Class: CodeRay::Scanners::JSON

Inherits:
Scanner
  • Object
show all
Includes:
CodeRay::Streamable
Defined in:
vendor/plugins/coderay-0.9.2/lib/coderay/scanners/json.rb

Constant Summary

KINDS_NOT_LOC =
[
  :float, :char, :content, :delimiter,
  :error, :integer, :operator, :value,
]
CONSTANTS =
%w( true false null )
IDENT_KIND =
WordList.new(:key).add(CONSTANTS, :value)
ESCAPE =
/ [bfnrt\\"\/] /x
UNICODE_ESCAPE =
/ u[a-fA-F0-9]{4} /x

Constants inherited from Scanner

DEFAULT_OPTIONS, KINDS_NOT_LOC, ScanError

Instance Method Summary

Methods inherited from Scanner

#column, #each, file_extension, #initialize, #line, #marshal_dump, #marshal_load, normify, #reset, streamable?, #streaming?, #string=, #tokenize, #tokens

Methods included from CodeRay::Plugin

#helper, #included, #plugin_host, #plugin_id, #register_for, #title

Constructor Details

This class inherits a constructor from CodeRay::Scanners::Scanner

Instance Method Details

- (Object) scan_tokens(tokens, options)



22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
# File 'vendor/plugins/coderay-0.9.2/lib/coderay/scanners/json.rb', line 22

def scan_tokens tokens, options
  
  state = :initial
  stack = []
  string_delimiter = nil
  key_expected = false
  
  until eos?
    
    kind = nil
    match = nil
    
    case state
    
    when :initial
      if match = scan(/ \s+ | \\\n /x)
        tokens << [match, :space]
        next
      elsif match = scan(/ [:,\[{\]}] /x)
        kind = :operator
        case match
        when '{' then stack << :object; key_expected = true
        when '[' then stack << :array
        when ':' then key_expected = false
        when ',' then key_expected = true if stack.last == :object
        when '}', ']' then stack.pop  # no error recovery, but works for valid JSON
        end
      elsif match = scan(/ true | false | null /x)
        kind = IDENT_KIND[match]
      elsif match = scan(/-?(?:0|[1-9]\d*)/)
        kind = :integer
        if scan(/\.\d+(?:[eE][-+]?\d+)?|[eE][-+]?\d+/)
          match << matched
          kind = :float
        end
      elsif match = scan(/"/)
        state = key_expected ? :key : :string
        tokens << [:open, state]
        kind = :delimiter
      else
        getch
        kind = :error
      end
      
    when :string, :key
      if scan(/[^\\"]+/)
        kind = :content
      elsif scan(/"/)
        tokens << ['"', :delimiter]
        tokens << [:close, state]
        state = :initial
        next
      elsif scan(/ \\ (?: #{ESCAPE} | #{UNICODE_ESCAPE} ) /mox)
        kind = :char
      elsif scan(/\\./m)
        kind = :content
      elsif scan(/ \\ | $ /x)
        tokens << [:close, :delimiter]
        kind = :error
        state = :initial
      else
        raise_inspect "else case \" reached; %p not handled." % peek(1), tokens
      end
      
    else
      raise_inspect 'Unknown state', tokens
      
    end
    
    match ||= matched
    if $CODERAY_DEBUG and not kind
      raise_inspect 'Error token %p in line %d' %
        [[match, kind], line], tokens
    end
    raise_inspect 'Empty token', tokens unless match
    
    tokens << [match, kind]
    
  end
  
  if [:string, :key].include? state
    tokens << [:close, state]
  end
  
  tokens
end