annotate vendor/gems/coderay-1.0.0/lib/coderay/scanners/json.rb @ 1472:f0b798dad2d6 feature_526

Close obsolete branch feature_526
author Chris Cannam
date Tue, 20 Nov 2012 19:45:51 +0000
parents cbb26bc654de
children
rev   line source
Chris@909 1 module CodeRay
Chris@909 2 module Scanners
Chris@909 3
Chris@909 4 # Scanner for JSON (JavaScript Object Notation).
Chris@909 5 class JSON < Scanner
Chris@909 6
Chris@909 7 register_for :json
Chris@909 8 file_extension 'json'
Chris@909 9
Chris@909 10 KINDS_NOT_LOC = [
Chris@909 11 :float, :char, :content, :delimiter,
Chris@909 12 :error, :integer, :operator, :value,
Chris@909 13 ] # :nodoc:
Chris@909 14
Chris@909 15 ESCAPE = / [bfnrt\\"\/] /x # :nodoc:
Chris@909 16 UNICODE_ESCAPE = / u[a-fA-F0-9]{4} /x # :nodoc:
Chris@909 17
Chris@909 18 protected
Chris@909 19
Chris@909 20 # See http://json.org/ for a definition of the JSON lexic/grammar.
Chris@909 21 def scan_tokens encoder, options
Chris@909 22
Chris@909 23 state = :initial
Chris@909 24 stack = []
Chris@909 25 key_expected = false
Chris@909 26
Chris@909 27 until eos?
Chris@909 28
Chris@909 29 case state
Chris@909 30
Chris@909 31 when :initial
Chris@909 32 if match = scan(/ \s+ /x)
Chris@909 33 encoder.text_token match, :space
Chris@909 34 elsif match = scan(/"/)
Chris@909 35 state = key_expected ? :key : :string
Chris@909 36 encoder.begin_group state
Chris@909 37 encoder.text_token match, :delimiter
Chris@909 38 elsif match = scan(/ [:,\[{\]}] /x)
Chris@909 39 encoder.text_token match, :operator
Chris@909 40 case match
Chris@909 41 when ':' then key_expected = false
Chris@909 42 when ',' then key_expected = true if stack.last == :object
Chris@909 43 when '{' then stack << :object; key_expected = true
Chris@909 44 when '[' then stack << :array
Chris@909 45 when '}', ']' then stack.pop # no error recovery, but works for valid JSON
Chris@909 46 end
Chris@909 47 elsif match = scan(/ true | false | null /x)
Chris@909 48 encoder.text_token match, :value
Chris@909 49 elsif match = scan(/ -? (?: 0 | [1-9]\d* ) /x)
Chris@909 50 if scan(/ \.\d+ (?:[eE][-+]?\d+)? | [eE][-+]? \d+ /x)
Chris@909 51 match << matched
Chris@909 52 encoder.text_token match, :float
Chris@909 53 else
Chris@909 54 encoder.text_token match, :integer
Chris@909 55 end
Chris@909 56 else
Chris@909 57 encoder.text_token getch, :error
Chris@909 58 end
Chris@909 59
Chris@909 60 when :string, :key
Chris@909 61 if match = scan(/[^\\"]+/)
Chris@909 62 encoder.text_token match, :content
Chris@909 63 elsif match = scan(/"/)
Chris@909 64 encoder.text_token match, :delimiter
Chris@909 65 encoder.end_group state
Chris@909 66 state = :initial
Chris@909 67 elsif match = scan(/ \\ (?: #{ESCAPE} | #{UNICODE_ESCAPE} ) /mox)
Chris@909 68 encoder.text_token match, :char
Chris@909 69 elsif match = scan(/\\./m)
Chris@909 70 encoder.text_token match, :content
Chris@909 71 elsif match = scan(/ \\ | $ /x)
Chris@909 72 encoder.end_group state
Chris@909 73 encoder.text_token match, :error
Chris@909 74 state = :initial
Chris@909 75 else
Chris@909 76 raise_inspect "else case \" reached; %p not handled." % peek(1), encoder
Chris@909 77 end
Chris@909 78
Chris@909 79 else
Chris@909 80 raise_inspect 'Unknown state: %p' % [state], encoder
Chris@909 81
Chris@909 82 end
Chris@909 83 end
Chris@909 84
Chris@909 85 if [:string, :key].include? state
Chris@909 86 encoder.end_group state
Chris@909 87 end
Chris@909 88
Chris@909 89 encoder
Chris@909 90 end
Chris@909 91
Chris@909 92 end
Chris@909 93
Chris@909 94 end
Chris@909 95 end