annotate vendor/gems/coderay-0.9.7/lib/coderay/scanners/json.rb @ 855:7294e8db2515 bug_162

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