json_p3 0.2.1 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
data/lib/json_p3/lexer.rb CHANGED
@@ -15,7 +15,7 @@ module JSONP3 # rubocop:disable Style/Documentation
15
15
  lexer.run
16
16
  tokens = lexer.tokens
17
17
 
18
- if !tokens.empty? && tokens.last.type == Token::ERROR
18
+ if !tokens.empty? && tokens.last.type == :token_error
19
19
  raise JSONPathSyntaxError.new(tokens.last.message || raise,
20
20
  tokens.last)
21
21
  end
@@ -26,7 +26,7 @@ module JSONP3 # rubocop:disable Style/Documentation
26
26
  # JSONPath query expression lexical scanner.
27
27
  #
28
28
  # @see tokenize
29
- class Lexer # rubocop:disable Metrics/ClassLength
29
+ class Lexer
30
30
  RE_INT = /-?[0-9]+/
31
31
  RE_NAME = /[\u0080-\uFFFFa-zA-Z_][\u0080-\uFFFFa-zA-Z0-9_-]*/
32
32
  RE_WHITESPACE = /[ \n\r\t]+/
@@ -46,7 +46,7 @@ module JSONP3 # rubocop:disable Style/Documentation
46
46
 
47
47
  def run
48
48
  state = :lex_root
49
- state = method(state).call until state.nil?
49
+ state = send(state) until state.nil?
50
50
  end
51
51
 
52
52
  protected
@@ -56,12 +56,12 @@ module JSONP3 # rubocop:disable Style/Documentation
56
56
  # @param value [String | nil] a the token's value, if it is known, otherwise the
57
57
  # value will be sliced from @query. This is a performance optimization.
58
58
  def emit(token_type, value = nil)
59
- @tokens << Token.new(token_type, value || @query[@start...@scanner.charpos], @start, @query)
59
+ @tokens << Token.new(token_type, value || @query[@start, @scanner.charpos - @start], @start, @query)
60
60
  @start = @scanner.charpos
61
61
  end
62
62
 
63
63
  def next
64
- @scanner.getch || ""
64
+ @scanner.get_byte || ""
65
65
  end
66
66
 
67
67
  def ignore
@@ -69,7 +69,6 @@ module JSONP3 # rubocop:disable Style/Documentation
69
69
  end
70
70
 
71
71
  def backup
72
- # Assumes we're backing-up from a single byte character.
73
72
  @scanner.pos -= 1
74
73
  end
75
74
 
@@ -78,7 +77,7 @@ module JSONP3 # rubocop:disable Style/Documentation
78
77
  @scanner.peek(1)
79
78
  end
80
79
 
81
- # Advance the lexer if the next character is equal to _char_.
80
+ # Advance the lexer if _pattern_ matches from the current position.
82
81
  def accept?(pattern)
83
82
  !@scanner.scan(pattern).nil?
84
83
  end
@@ -100,7 +99,7 @@ module JSONP3 # rubocop:disable Style/Documentation
100
99
 
101
100
  def error(message)
102
101
  @tokens << Token.new(
103
- Token::ERROR, @query[@start...@scanner.charpos] || "", @start, @query, message: message
102
+ :token_error, @query[@start, @scanner.charpos - @start] || "", @start, @query, message: message
104
103
  )
105
104
  end
106
105
 
@@ -112,11 +111,11 @@ module JSONP3 # rubocop:disable Style/Documentation
112
111
  return nil
113
112
  end
114
113
 
115
- emit(Token::ROOT, "$")
114
+ emit(:token_root, "$")
116
115
  :lex_segment
117
116
  end
118
117
 
119
- def lex_segment # rubocop:disable Metrics/MethodLength, Metrics/CyclomaticComplexity
118
+ def lex_segment
120
119
  if accept?(RE_WHITESPACE) && peek.empty?
121
120
  error "unexpected trailing whitespace"
122
121
  return nil
@@ -127,16 +126,16 @@ module JSONP3 # rubocop:disable Style/Documentation
127
126
 
128
127
  case c
129
128
  when ""
130
- emit(Token::EOI, "")
129
+ emit(:token_eoi, "")
131
130
  nil
132
131
  when "."
133
132
  return :lex_shorthand_selector unless peek == "."
134
133
 
135
134
  self.next
136
- emit(Token::DOUBLE_DOT, "..")
135
+ emit(:token_double_dot, "..")
137
136
  :lex_descendant_segment
138
137
  when "["
139
- emit(Token::LBRACKET, "[")
138
+ emit(:token_lbracket, "[")
140
139
  :lex_inside_bracketed_segment
141
140
  else
142
141
  if @filter_depth.positive?
@@ -149,21 +148,21 @@ module JSONP3 # rubocop:disable Style/Documentation
149
148
  end
150
149
  end
151
150
 
152
- def lex_descendant_segment # rubocop:disable Metrics/MethodLength
151
+ def lex_descendant_segment
153
152
  case self.next
154
153
  when ""
155
154
  error "bald descendant segment"
156
155
  nil
157
156
  when "*"
158
- emit(Token::WILD, "*")
157
+ emit(:token_wild, "*")
159
158
  :lex_segment
160
159
  when "["
161
- emit(Token::LBRACKET, "[")
160
+ emit(:token_lbracket, "[")
162
161
  :lex_inside_bracketed_segment
163
162
  else
164
163
  backup
165
164
  if accept?(RE_NAME)
166
- emit(Token::NAME)
165
+ emit(:token_name)
167
166
  :lex_segment
168
167
  else
169
168
  c = self.next
@@ -173,7 +172,7 @@ module JSONP3 # rubocop:disable Style/Documentation
173
172
  end
174
173
  end
175
174
 
176
- def lex_shorthand_selector # rubocop:disable Metrics/MethodLength
175
+ def lex_shorthand_selector
177
176
  if peek == ""
178
177
  error "unexpected trailing dot"
179
178
  return nil
@@ -188,12 +187,12 @@ module JSONP3 # rubocop:disable Style/Documentation
188
187
 
189
188
  if peek == "*"
190
189
  self.next
191
- emit(Token::WILD, "*")
190
+ emit(:token_wild, "*")
192
191
  return :lex_segment
193
192
  end
194
193
 
195
194
  if accept?(RE_NAME)
196
- emit(Token::NAME)
195
+ emit(:token_name)
197
196
  return :lex_segment
198
197
  end
199
198
 
@@ -202,28 +201,28 @@ module JSONP3 # rubocop:disable Style/Documentation
202
201
  nil
203
202
  end
204
203
 
205
- def lex_inside_bracketed_segment # rubocop:disable Metrics/MethodLength, Metrics/AbcSize, Metrics/CyclomaticComplexity
204
+ def lex_inside_bracketed_segment
206
205
  loop do # rubocop:disable Metrics/BlockLength
207
206
  ignore_whitespace?
208
207
  c = self.next
209
208
 
210
209
  case c
211
210
  when "]"
212
- emit(Token::RBRACKET, "]")
211
+ emit(:token_rbracket, "]")
213
212
  return @filter_depth.positive? ? :lex_inside_filter : :lex_segment
214
213
  when ""
215
214
  error "unclosed bracketed selection"
216
215
  return nil
217
216
  when "*"
218
- emit(Token::WILD, "*")
217
+ emit(:token_wild, "*")
219
218
  when "?"
220
- emit(Token::FILTER, "?")
219
+ emit(:token_filter, "?")
221
220
  @filter_depth += 1
222
221
  return :lex_inside_filter
223
222
  when ","
224
- emit(Token::COMMA, ",")
223
+ emit(:token_comma, ",")
225
224
  when ":"
226
- emit(Token::COLON, ":")
225
+ emit(:token_colon, ":")
227
226
  when "'"
228
227
  return :lex_single_quoted_string_inside_bracketed_segment
229
228
  when '"'
@@ -232,7 +231,7 @@ module JSONP3 # rubocop:disable Style/Documentation
232
231
  backup
233
232
  if accept_int?
234
233
  # Index selector or part of a slice selector.
235
- emit Token::INDEX
234
+ emit(:token_index)
236
235
  else
237
236
  error "unexpected token '#{c}' in bracketed selection"
238
237
  return nil
@@ -259,7 +258,7 @@ module JSONP3 # rubocop:disable Style/Documentation
259
258
  backup
260
259
  return :lex_inside_bracketed_segment
261
260
  when ","
262
- emit(Token::COMMA, ",")
261
+ emit(:token_comma, ",")
263
262
  # If we have unbalanced parens, we are inside a function call and a
264
263
  # comma separates arguments. Otherwise a comma separates selectors.
265
264
  next if @paren_stack.length.positive?
@@ -271,11 +270,11 @@ module JSONP3 # rubocop:disable Style/Documentation
271
270
  when '"'
272
271
  return :lex_double_quoted_string_inside_filter_expression
273
272
  when "("
274
- emit(Token::LPAREN, "(")
273
+ emit(:token_lparen, "(")
275
274
  # Are we in a function call? If so, a function argument contains parens.
276
275
  @paren_stack[-1] += 1 if @paren_stack.length.positive?
277
276
  when ")"
278
- emit(Token::RPAREN, ")")
277
+ emit(:token_rparen, ")")
279
278
  # Are we closing a function call or a parenthesized expression?
280
279
  if @paren_stack.length.positive?
281
280
  if @paren_stack[-1] == 1
@@ -285,10 +284,10 @@ module JSONP3 # rubocop:disable Style/Documentation
285
284
  end
286
285
  end
287
286
  when "$"
288
- emit(Token::ROOT, "$")
287
+ emit(:token_root, "$")
289
288
  return :lex_segment
290
289
  when "@"
291
- emit(Token::CURRENT, "@")
290
+ emit(:token_current, "@")
292
291
  return :lex_segment
293
292
  when "."
294
293
  backup
@@ -296,32 +295,32 @@ module JSONP3 # rubocop:disable Style/Documentation
296
295
  when "!"
297
296
  if peek == "="
298
297
  self.next
299
- emit(Token::NE, "!=")
298
+ emit(:token_ne, "!=")
300
299
  else
301
- emit(Token::NOT, "!")
300
+ emit(:token_not, "!")
302
301
  end
303
302
  when "="
304
303
  if peek == "="
305
304
  self.next
306
- emit(Token::EQ, "==")
305
+ emit(:token_eq, "==")
307
306
  else
308
307
  backup
309
- error "unexpected filter selector token '#{c}'"
308
+ error "found '=', did you mean '==', '!=', '<=' or '>='?"
310
309
  return nil
311
310
  end
312
311
  when "<"
313
312
  if peek == "="
314
313
  self.next
315
- emit(Token::LE, "<=")
314
+ emit(:token_le, "<=")
316
315
  else
317
- emit(Token::LT, "<")
316
+ emit(:token_lt, "<")
318
317
  end
319
318
  when ">"
320
319
  if peek == "="
321
320
  self.next
322
- emit(Token::GE, ">=")
321
+ emit(:token_ge, ">=")
323
322
  else
324
- emit(Token::GT, ">")
323
+ emit(:token_gt, ">")
325
324
  end
326
325
  else
327
326
  backup
@@ -335,24 +334,24 @@ module JSONP3 # rubocop:disable Style/Documentation
335
334
  end
336
335
 
337
336
  accept?(/[eE][+-]?[0-9]+/)
338
- emit Token::FLOAT
337
+ emit :token_float
339
338
  # An int, or float if exponent is negative
340
339
  elsif accept?(/[eE]-[0-9]+/)
341
- emit Token::FLOAT
340
+ emit :token_float
342
341
  else
343
342
  accept?(/[eE][+-]?[0-9]+/)
344
- emit Token::INT
343
+ emit :token_int
345
344
  end
346
345
  elsif accept?("&&")
347
- emit(Token::AND, "&&")
346
+ emit(:token_and, "&&")
348
347
  elsif accept?("||")
349
- emit(Token::OR, "||")
348
+ emit(:token_or, "||")
350
349
  elsif accept?("true")
351
- emit(Token::TRUE, "true")
350
+ emit(:token_true, "true")
352
351
  elsif accept?("false")
353
- emit(Token::FALSE, "false")
352
+ emit(:token_false, "false")
354
353
  elsif accept?("null")
355
- emit(Token::NULL, "null")
354
+ emit(:token_null, "null")
356
355
  elsif accept?(/[a-z][a-z_0-9]*/)
357
356
  unless peek == "("
358
357
  error "unexpected filter selector token"
@@ -361,7 +360,7 @@ module JSONP3 # rubocop:disable Style/Documentation
361
360
  # Function name
362
361
  # Keep track of parentheses for this function call.
363
362
  @paren_stack << 1
364
- emit Token::FUNCTION
363
+ emit :token_function
365
364
  self.next
366
365
  ignore # move past LPAREN
367
366
  else
@@ -373,20 +372,20 @@ module JSONP3 # rubocop:disable Style/Documentation
373
372
  end
374
373
 
375
374
  class << self
376
- def lex_string_factory(quote, state, token) # rubocop:disable Metrics/MethodLength
375
+ def lex_string_factory(quote, state, token)
377
376
  proc {
378
377
  # @type self: Lexer
379
378
  ignore # move past opening quote
380
379
 
381
380
  loop do
382
381
  c = self.next
383
- peeked = peek
384
382
 
385
383
  case c
386
384
  when ""
387
385
  error "unclosed string starting at index #{@start}"
388
386
  return nil
389
387
  when "\\"
388
+ peeked = peek
390
389
  if S_ESCAPES.member?(peeked) || peeked == quote
391
390
  self.next
392
391
  else
@@ -406,15 +405,15 @@ module JSONP3 # rubocop:disable Style/Documentation
406
405
  end
407
406
 
408
407
  define_method(:lex_double_quoted_string_inside_bracketed_segment,
409
- lex_string_factory('"', :lex_inside_bracketed_segment, Token::DOUBLE_QUOTE_STRING))
408
+ lex_string_factory('"', :lex_inside_bracketed_segment, :token_double_quote_string))
410
409
 
411
410
  define_method(:lex_single_quoted_string_inside_bracketed_segment,
412
- lex_string_factory("'", :lex_inside_bracketed_segment, Token::SINGLE_QUOTE_STRING))
411
+ lex_string_factory("'", :lex_inside_bracketed_segment, :token_single_quote_string))
413
412
 
414
413
  define_method(:lex_double_quoted_string_inside_filter_expression,
415
- lex_string_factory('"', :lex_inside_filter, Token::DOUBLE_QUOTE_STRING))
414
+ lex_string_factory('"', :lex_inside_filter, :token_double_quote_string))
416
415
 
417
416
  define_method(:lex_single_quoted_string_inside_filter_expression,
418
- lex_string_factory("'", :lex_inside_filter, Token::SINGLE_QUOTE_STRING))
417
+ lex_string_factory("'", :lex_inside_filter, :token_single_quote_string))
419
418
  end
420
419
  end