To check out this repository please hg clone the following URL, or open the URL using EasyMercurial or your preferred Mercurial client.

Statistics Download as Zip
| Branch: | Tag: | Revision:

root / vendor / gems / coderay-0.9.7 / lib / coderay / scanners / json.rb @ 442:753f1380d6bc

History | View | Annotate | Download (2.73 KB)

1
module CodeRay
2
module Scanners
3
  
4
  class JSON < Scanner
5
    
6
    include Streamable
7
    
8
    register_for :json
9
    file_extension 'json'
10
    
11
    KINDS_NOT_LOC = [
12
      :float, :char, :content, :delimiter,
13
      :error, :integer, :operator, :value,
14
    ]
15
    
16
    ESCAPE = / [bfnrt\\"\/] /x
17
    UNICODE_ESCAPE =  / u[a-fA-F0-9]{4} /x
18
    
19
    def scan_tokens tokens, options
20
      
21
      state = :initial
22
      stack = []
23
      key_expected = false
24
      
25
      until eos?
26
        
27
        kind = nil
28
        match = nil
29
        
30
        case state
31
        
32
        when :initial
33
          if match = scan(/ \s+ | \\\n /x)
34
            tokens << [match, :space]
35
            next
36
          elsif match = scan(/ [:,\[{\]}] /x)
37
            kind = :operator
38
            case match
39
            when '{' then stack << :object; key_expected = true
40
            when '[' then stack << :array
41
            when ':' then key_expected = false
42
            when ',' then key_expected = true if stack.last == :object
43
            when '}', ']' then stack.pop  # no error recovery, but works for valid JSON
44
            end
45
          elsif match = scan(/ true | false | null /x)
46
            kind = :value
47
          elsif match = scan(/-?(?:0|[1-9]\d*)/)
48
            kind = :integer
49
            if scan(/\.\d+(?:[eE][-+]?\d+)?|[eE][-+]?\d+/)
50
              match << matched
51
              kind = :float
52
            end
53
          elsif match = scan(/"/)
54
            state = key_expected ? :key : :string
55
            tokens << [:open, state]
56
            kind = :delimiter
57
          else
58
            getch
59
            kind = :error
60
          end
61
          
62
        when :string, :key
63
          if scan(/[^\\"]+/)
64
            kind = :content
65
          elsif scan(/"/)
66
            tokens << ['"', :delimiter]
67
            tokens << [:close, state]
68
            state = :initial
69
            next
70
          elsif scan(/ \\ (?: #{ESCAPE} | #{UNICODE_ESCAPE} ) /mox)
71
            kind = :char
72
          elsif scan(/\\./m)
73
            kind = :content
74
          elsif scan(/ \\ | $ /x)
75
            tokens << [:close, state]
76
            kind = :error
77
            state = :initial
78
          else
79
            raise_inspect "else case \" reached; %p not handled." % peek(1), tokens
80
          end
81
          
82
        else
83
          raise_inspect 'Unknown state', tokens
84
          
85
        end
86
        
87
        match ||= matched
88
        if $CODERAY_DEBUG and not kind
89
          raise_inspect 'Error token %p in line %d' %
90
            [[match, kind], line], tokens
91
        end
92
        raise_inspect 'Empty token', tokens unless match
93
        
94
        tokens << [match, kind]
95
        
96
      end
97
      
98
      if [:string, :key].include? state
99
        tokens << [:close, state]
100
      end
101
      
102
      tokens
103
    end
104
    
105
  end
106
  
107
end
108
end