Class: Platform::IEL::SexpParser::Lexer

Inherits:
Object
  • Object
show all
Defined in:
lib/introhive_expression_language/iel/sexp_parser.rb

Constant Summary collapse

SYMBOL_LEADING_CHAR_SE =
%q{[\w@+*\/=!<>-]}
SYMBOL_LEADING_CHAR =
Regexp.new(SYMBOL_LEADING_CHAR_SE)
SYMBOL_TRAILING_CHAR_SE =
'[\w:@=.()#+*\/!<>?-]'
SYMBOL_TRAILING_CHAR =
Regexp.new(SYMBOL_TRAILING_CHAR_SE)
SYMBOL =
Regexp.new("#{SYMBOL_LEADING_CHAR_SE}#{SYMBOL_TRAILING_CHAR_SE}*")

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.tokenize(chars, pos, context, &block) ⇒ Object



170
171
172
# File 'lib/introhive_expression_language/iel/sexp_parser.rb', line 170

def self.tokenize(chars, pos, context, &block)
  self.new.tokenize(chars, pos, context, &block)
end

Instance Method Details

#cnextObject



331
332
333
334
335
# File 'lib/introhive_expression_language/iel/sexp_parser.rb', line 331

def cnext
  c = @chars[@pos]
  @pos += 1
  c
end

#comment(s = '') ⇒ Object



270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
# File 'lib/introhive_expression_language/iel/sexp_parser.rb', line 270

def comment(s = '')
  pos = @pos
  maybe_ending = false
  while true
    case cpeek
    when '*'
      maybe_ending = true
      s += cnext
    when '/'
      s += cnext
      if maybe_ending
        @block.call(Node.new(:comment, pos, s, @context))
        break
      end
    else
      maybe_ending = false
      next_c = cnext
      raise ParseError, "Unexpected EOF in comment at #{@pos}" if next_c.nil?
      s += next_c
    end
  end
end

#cpeekObject



327
328
329
# File 'lib/introhive_expression_language/iel/sexp_parser.rb', line 327

def cpeek
  @chars[@pos]
end

#expect(c) ⇒ Object

Raises:



322
323
324
325
# File 'lib/introhive_expression_language/iel/sexp_parser.rb', line 322

def expect(c)
  raise ParseError, "'#{c}' expected at #{@pos}" if cpeek != c
  cnext
end

#next_tokenObject



183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
# File 'lib/introhive_expression_language/iel/sexp_parser.rb', line 183

def next_token
  case cpeek
  when nil
    return false
  when /\s/
    cnext
  when '['
    @block.call(Node.new(:list_start, @pos, nil, @context))
    cnext
  when ']'
    @block.call(Node.new(:list_end, @pos, nil, @context))
    cnext
  when '"'
    string_literal
  when "'"
    quote_symbol
  when '-'
    numeric_literal_or_symbol
  when /[-\d]/
    numeric_literal
  when SYMBOL_LEADING_CHAR
    symbol_or_comment
  else
    raise ParseError, "'#{cpeek}' unexpected at #{@pos}"
  end
  true
end

#numeric_literal(s = '') ⇒ Object



242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
# File 'lib/introhive_expression_language/iel/sexp_parser.rb', line 242

def numeric_literal(s = '')
  pos = @pos - s.length
  dot_count = 0
  while true
    case cpeek
    when /[\d]/
      s += cnext
    when /[.]/
      dot_count += 1
      raise ParseError, "Unexpected '.' in numeric literal at #{@pos}" if dot_count > 1
      s += cnext
    else
      @block.call(Node.new(:numeric_literal, pos, s.include?('.') ? s.to_f : s.to_i, @context))
      break
    end
  end
end

#numeric_literal_or_symbolObject



211
212
213
214
215
216
217
218
# File 'lib/introhive_expression_language/iel/sexp_parser.rb', line 211

def numeric_literal_or_symbol
  cnext # consume the minus
  if cpeek =~ /[\d]/
    numeric_literal('-')
  else
    symbol('-')
  end
end

#quote_symbolObject



317
318
319
320
# File 'lib/introhive_expression_language/iel/sexp_parser.rb', line 317

def quote_symbol
  cnext
  @block.call(Node.new(:symbol, @pos, "'", @context))
end

#string_literalObject



220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
# File 'lib/introhive_expression_language/iel/sexp_parser.rb', line 220

def string_literal
  pos = @pos
  expect('"')
  s = ''
  while true
    case cpeek
    when nil
      raise ParseError, "Unexpected end of string literal at #{@pos}"
    when '"'
      cnext
      if cpeek == '"'
        s += cnext
      else
        @block.call(Node.new(:string_literal, pos, s, @context))
        break
      end
    else
      s += cnext
    end
  end
end

#symbol(s = '') ⇒ Object



293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
# File 'lib/introhive_expression_language/iel/sexp_parser.rb', line 293

def symbol(s = '')
  pos = @pos - s.length
  while true
    case cpeek
    when SYMBOL_TRAILING_CHAR
      s += cnext
    else
      case s
      when 'true'
        @block.call(Node.new(:boolean, pos, true, @context))
      when 'false'
        @block.call(Node.new(:boolean, pos, false, @context))
      when 'nan'
        @block.call(Node.new(:nan, pos, nil, @context))
      when 'nil'
        @block.call(Node.new(:nil, pos, nil, @context))
      else
        @block.call(Node.new(:symbol, pos, s, @context))
      end
      break
    end
  end
end

#symbol_or_comment(s = '') ⇒ Object



260
261
262
263
264
265
266
267
268
# File 'lib/introhive_expression_language/iel/sexp_parser.rb', line 260

def symbol_or_comment(s = '')
  s += cnext
  if cpeek == '*'
    s += cnext
    comment(s)
  else
    symbol(s)
  end
end

#tokenize(chars, pos, context, &block) ⇒ Object



174
175
176
177
178
179
180
181
# File 'lib/introhive_expression_language/iel/sexp_parser.rb', line 174

def tokenize(chars, pos, context, &block)
  @chars = chars
  @pos = pos
  @context = context
  @block = block
  while next_token
  end
end