annotate vendor/plugins/coderay-0.9.2/lib/coderay/scanners/json.rb @ 36:de76cd3e8c8e cc-branches

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