Module: LangScan::OCaml

Defined in:
lib/langscan/ocaml.rb

Defined Under Namespace

Classes: Eof, Tokenizer

Constant Summary collapse

CAMLEXER_PATH =
$LOAD_PATH.map{|path|
  File.join(path, "langscan/ocaml/camlexer")
}.find {|path| File.file?(path) }

Class Method Summary collapse

Class Method Details

.abbrevObject



73
74
75
# File 'lib/langscan/ocaml.rb', line 73

def abbrev
  "ocaml"
end

.check_token(tkns, index, type, name = nil) ⇒ Object

Raises:



81
82
83
84
85
# File 'lib/langscan/ocaml.rb', line 81

def check_token(tkns, index, type, name = nil)
  t = tkns[index]
  raise Eof.new if !t
  return t.type == type && (!name || t.text == name)
end

.check_token_next(tkns, index, step, type, name = nil) ⇒ Object



95
96
97
98
# File 'lib/langscan/ocaml.rb', line 95

def check_token_next(tkns, index, step, type, name = nil)
  index = go_next(tkns, index, step)
  check_token(tkns, index, type, name)
end

.check_token_prev(tkns, index, step, type, name = nil) ⇒ Object



108
109
110
111
# File 'lib/langscan/ocaml.rb', line 108

def check_token_prev(tkns, index, step, type, name = nil)
  index = go_prev(tkns, index, step)
  check_token(tkns, index, type, name)
end

.convert_fun(tkns, i, max) ⇒ Object



194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
# File 'lib/langscan/ocaml.rb', line 194

def convert_fun(tkns, i, max)
  begin
    while (i < max)
      t = tkns[i]
      if (t.type == :ident)
        if (check_token_prev(tkns, i, 1, :keyword, 'fun'))
          while (!check_token(tkns, i, :punct, '->'))
            i = go_next(tkns, i, 1)
          end
        elsif (check_token_prev(tkns, i, 1, :keyword, 'let') ||
               (check_token_prev(tkns, i, 1, :keyword, 'rec') &&
                check_token_prev(tkns, i, 2, :keyword, 'let')))
          if (!check_token_next(tkns, i, 1, :punct, '='))
            t.type = :fundef
            i += 1 while (!check_token(tkns, i, :punct, '='))
          end
        elsif (check_token_prev(tkns, i, 1, :keyword, 'val') ||
               (check_token_prev(tkns, i, 1, :keyword, 'mutable') &&
                check_token_prev(tkns, i, 2, :keyword, 'val')) ||
               check_token_prev(tkns, i, 1, :keyword, 'external'))
          if (check_token_next(tkns, i, 1, :punct, ':'))
            # not strict
            i = go_next(tkns, i, 2)
            while (!check_token(tkns, i, :keyword))
              if (check_token(tkns, i, :punct, '->'))
                t.type = :fundecl
                i = skip_type(tkns, i+1)
                break
              end
              i = go_next(tkns, i, 1)
            end
          else
            # what?
          end
        elsif (is_method?(tkns, i))
          if (check_token_next(tkns, i, 1, :punct, ':'))
            t.type = :fundecl
            i = go_next(tkns, i, 2)
            i = skip_type(tkns, i)
          else
            t.type = :fundef
            i += 1 while (!check_token(tkns, i, :punct, '='))
          end
        elsif (!check_token_prev(tkns, i, 1, :punct, ':') &&
               !check_token_prev(tkns, i, 1, :punct, '*') &&
               !check_token_prev(tkns, i, 1, :punct, '\'') &&
               !check_token_prev(tkns, i, 1, :punct, '~') &&
               !check_token_prev(tkns, i, 1, :punct, '?') &&
               !check_token_prev(tkns, i, 1, :punct, '|') &&
               !check_token_prev(tkns, i, 1, :keyword, 'with'))
          # is it call?
          i = go_next(tkns, i, 1)
          if (check_token_prev(tkns, i, 2, :punct, '#') ||
              is_first_parameter?(tkns, i))
            t.type = :funcall
            i = skip_parameter(tkns, i)
            while (is_parameter?(tkns, i))
              i = skip_parameter(tkns, i)
            end
          end
        end
      elsif (check_token(tkns, i, :keyword, 'of') ||
#                 check_token(tkns, i, :punct, '|') ||  # overrun ->
             check_token(tkns, i, :punct, ':>'))
        # is it needed?
        i = skip_type(tkns, i+1)
        i = go_prev(tkns, i, 1)
      elsif (check_token(tkns, i, :keyword, 'class'))
        i = go_next(tkns, i, 1) while (!check_token(tkns, i, :punct, '='))
      end

      i += 1
    end
  rescue Eof
  end
end

.extnamesObject



77
78
79
# File 'lib/langscan/ocaml.rb', line 77

def extnames
  [".ml", ".mli", ".mll", ".mly"]
end

.go_next(tkns, index, step) ⇒ Object



87
88
89
90
91
92
93
# File 'lib/langscan/ocaml.rb', line 87

def go_next(tkns, index, step)
  for i in 0...step
    index += 1
    index += 1 while (check_token(tkns, index, :comment))
  end
  index
end

.go_prev(tkns, index, step) ⇒ Object



100
101
102
103
104
105
106
# File 'lib/langscan/ocaml.rb', line 100

def go_prev(tkns, index, step)
  for i in 0...step
    index -= 1
    index -= 1 while (check_token(tkns, index, :comment))
  end
  index
end

.is_first_parameter?(tkns, index) ⇒ Boolean

Returns:

  • (Boolean)


142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
# File 'lib/langscan/ocaml.rb', line 142

def is_first_parameter?(tkns, index)
  t = tkns[index]
  return false if !t

  if (t.type == :string || t.type == :character)
    return true
  end

  if (t.type == :keyword)
    return (t.text == '()')
  end

  if (t.type == :integer || t.type == :float)
    return (t.text !~ /^-/)
  end

  if (t.type == :ident)
    return (t.text != 'array' && t.text != 'list' && t.text != 'option')
  end

  if (t.type == :punct)
    return (t.text == '(' || t.text =~ /^\[\|?/)
  end

  return false
end

.is_method?(tkns, i) ⇒ Boolean

Returns:

  • (Boolean)


169
170
171
172
173
174
175
176
177
# File 'lib/langscan/ocaml.rb', line 169

def is_method?(tkns, i)
  if (check_token_prev(tkns, i, 1, :keyword, 'virtual'))
    i = go_prev(tkns, i, 1)
  end
  if (check_token_prev(tkns, i, 1, :keyword, 'private'))
    i = go_prev(tkns, i, 1)
  end
  check_token_prev(tkns, i, 1, :keyword, 'method')
end

.is_parameter?(tkns, index) ⇒ Boolean

Returns:

  • (Boolean)


179
180
181
182
183
184
185
186
187
188
189
190
191
192
# File 'lib/langscan/ocaml.rb', line 179

def is_parameter?(tkns, index)
  return true if (is_first_parameter?(tkns, index))

  t = tkns[index]
  return false if !t

  if (t.type == :punct)
    if (t.text == '.' || t.text == '#')
      return true
    end
  end

  return false
end

.nameObject



69
70
71
# File 'lib/langscan/ocaml.rb', line 69

def name
  "Objective Caml"
end

.scan(input, &block) ⇒ Object

LangScan::OCaml.scan iterates over Objective Caml program. It yields for each Fragment.



273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
# File 'lib/langscan/ocaml.rb', line 273

def scan(input, &block)
  tokenizer = Tokenizer.new(input)

  tkns = Array.new
  while (tkn = tokenizer.get_token())
    # is it ok?
    if (tkn.type == :ident && tkn.text =~ /^\W/)
      tkn.type = :punct
    end
    tkns << tkn
  end

  convert_fun(tkns, 0, tkns.size)

  tkns.each do |tkn|
    yield tkn
  end
  
  tokenizer.dispose()
end

.skip_parameter(tkns, i) ⇒ Object



127
128
129
130
131
132
133
134
135
136
137
138
139
140
# File 'lib/langscan/ocaml.rb', line 127

def skip_parameter(tkns, i)
  t = tkns[i]
  return i if !t
  if (t.type == :punct && (t.text == '(' || t.text =~ /^\[\|?/))
    i = go_next(tkns, i, 1)
    first = i
    del = { '(' => ')', '[' => ']', '[|' => '|]' }[t.text]
    while (!check_token(tkns, i, :punct, del))
      i = go_next(tkns, i, 1)
    end
    convert_fun(tkns, first, i)
  end
  i = go_next(tkns, i, 1)
end

.skip_type(tkns, i) ⇒ Object



113
114
115
116
117
118
119
120
121
122
123
124
125
# File 'lib/langscan/ocaml.rb', line 113

def skip_type(tkns, i)
  while (check_token(tkns, i, :punct, '->') ||
         check_token(tkns, i, :punct, '.') ||
         check_token(tkns, i, :punct, ':') ||
         check_token(tkns, i, :punct, '(') ||
         check_token(tkns, i, :punct, ')') ||
         check_token(tkns, i, :punct, '*') ||
         check_token(tkns, i, :comment) ||
         check_token(tkns, i, :ident))
    i += 1
  end
  i
end