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