Module: JsonCompleter::Scanners

Defined in:
lib/json_completer/scanners.rb

Defined Under Namespace

Classes: CompletionStringToken, KeywordToken, NumberToken, ParsedStringToken

Class Method Summary collapse

Class Method Details

.digit_byte?(byte) ⇒ Boolean

Returns:

  • (Boolean)


431
432
433
# File 'lib/json_completer/scanners.rb', line 431

def digit_byte?(byte)
  byte.between?(48, 57)
end

.exponent_byte?(byte) ⇒ Boolean

Returns:

  • (Boolean)


435
436
437
438
439
440
441
442
# File 'lib/json_completer/scanners.rb', line 435

def exponent_byte?(byte)
  case byte
  when 69, 101
    true
  else
    false
  end
end

.hex_digit_byte?(byte) ⇒ Boolean

Returns:

  • (Boolean)


444
445
446
# File 'lib/json_completer/scanners.rb', line 444

def hex_digit_byte?(byte)
  digit_byte?(byte) || byte.between?(65, 70) || byte.between?(97, 102)
end

.scan_keyword_literal(input, index, target_keyword) ⇒ Object



417
418
419
420
421
422
423
424
425
426
427
428
429
# File 'lib/json_completer/scanners.rb', line 417

def scan_keyword_literal(input, index, target_keyword)
  start_index = index
  token = KeywordToken.new(target: target_keyword)
  length = input.bytesize

  while index < length && token.append_byte(input.getbyte(index))
    index += 1
  end

  return [input.byteslice(start_index, 1), 1] if token.matched.zero?

  [target_keyword, index - start_index]
end

.scan_number_literal(input, index) ⇒ Object



405
406
407
408
409
410
411
412
413
414
415
# File 'lib/json_completer/scanners.rb', line 405

def scan_number_literal(input, index)
  start_index = index
  token = NumberToken.new
  length = input.bytesize

  while index < length && token.append_byte(input.getbyte(index))
    index += 1
  end

  [token.completed_literal, index - start_index]
end

.scan_string(input, index, token) ⇒ Object



318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
# File 'lib/json_completer/scanners.rb', line 318

def scan_string(input, index, token)
  strict = token.is_a?(ParsedStringToken)
  # JSON string syntax is ASCII, so scanning bytes is safe here: multibyte UTF-8 content is
  # treated as opaque payload and copied via byteslice until we hit an ASCII delimiter/escape.
  length = input.bytesize
  segment_start = index

  while index < length
    byte = input.getbyte(index)

    if token.unicode_digits
      if hex_digit_byte?(byte)
        token.append_unicode_digit(byte)
        index += 1

        if token.unicode_digits.length == 4
          status = token.finish_unicode_escape!
          token.escape_state = nil
          token.unicode_digits = nil
          return [index, :invalid_unicode] if status == :invalid_unicode
        end

        segment_start = index
        next
      end

      token.invalid_unicode!
      token.terminate!
      return [index, :invalid_unicode]
    end

    if token.escape_state == :backslash
      if strict && token.pending_high_surrogate && byte != 117
        return [index, :invalid_unicode]
      end

      if byte == 117
        token.start_unicode_escape!
        index += 1
        segment_start = index
        next
      end

      return [index, :invalid_escape] unless token.valid_simple_escape?(byte)

      token.append_simple_escape(byte)
      token.escape_state = nil
      index += 1
      segment_start = index
      next
    end

    if strict && token.pending_high_surrogate && byte != 92
      return [index, :invalid_unicode]
    end

    if byte == 34
      token.append_slice(input, segment_start, index - segment_start) if index > segment_start

      if strict && token.pending_high_surrogate
        return [index, :invalid_unicode]
      end

      token.terminate!
      return [index + 1, :terminated]
    end

    if byte == 92
      token.append_slice(input, segment_start, index - segment_start) if index > segment_start
      token.start_escape!
      index += 1
      segment_start = index
      next
    end

    if strict && byte < 0x20
      token.append_slice(input, segment_start, index - segment_start) if index > segment_start
      return [index, :invalid_control_character]
    end

    index += 1
  end

  token.append_slice(input, segment_start, index - segment_start) if index > segment_start
  [index, :incomplete]
end