| Class | JSON::Pure::Parser |
| In: |
lib/json/pure/parser.rb
|
| Parent: | StringScanner |
| STRING | = | /" ((?:[^\x0-\x1f"\\] | # escaped special characters: \\["\\\/bfnrt] | \\u[0-9a-fA-F]{4} | # match all but escaped special characters: \\[\x20-\x21\x23-\x2e\x30-\x5b\x5d-\x61\x63-\x65\x67-\x6d\x6f-\x71\x73\x75-\xff])*) "/nx | ||
| INTEGER | = | /(-?0|-?[1-9]\d*)/ | ||
| FLOAT | = | /(-? (?:0|[1-9]\d*) (?: \.\d+(?i:e[+-]?\d+) | \.\d+ | (?i:e[+-]?\d+) ) )/x | ||
| NAN | = | /NaN/ | ||
| INFINITY | = | /Infinity/ | ||
| MINUS_INFINITY | = | /-Infinity/ | ||
| OBJECT_OPEN | = | /\{/ | ||
| OBJECT_CLOSE | = | /\}/ | ||
| ARRAY_OPEN | = | /\[/ | ||
| ARRAY_CLOSE | = | /\]/ | ||
| PAIR_DELIMITER | = | /:/ | ||
| COLLECTION_DELIMITER | = | /,/ | ||
| TRUE | = | /true/ | ||
| FALSE | = | /false/ | ||
| NULL | = | /null/ | ||
| IGNORE | = | %r( (?: //[^\n\r]*[\n\r]| # line comments /\* # c-style comments (?: [^*/]| # normal chars /[^*]| # slashes that do not start a nested comment \*[^/]| # asterisks that do not end this comment /(?=\*/) # single slash before this comment's end )* \*/ # the End of this comment |[ \t\r\n]+ # whitespaces: space, horicontal tab, lf, cr )+ )mx | ||
| UNPARSED | = | Object.new | ||
| UNESCAPE_MAP | = | Hash.new { |h, k| h[k] = k.chr } | Unescape characters in strings. |
| string | -> | source |
Creates a new JSON::Pure::Parser instance for the string source.
It will be configured by the opts hash. opts can have the following keys:
# File lib/json/pure/parser.rb, line 66
66: def initialize(source, opts = {})
67: super
68: if !opts.key?(:max_nesting) # defaults to 19
69: @max_nesting = 19
70: elsif opts[:max_nesting]
71: @max_nesting = opts[:max_nesting]
72: else
73: @max_nesting = 0
74: end
75: @allow_nan = !!opts[:allow_nan]
76: ca = true
77: ca = opts[:create_additions] if opts.key?(:create_additions)
78: @create_id = ca ? JSON.create_id : nil
79: end
Parses the current JSON string source and returns the complete data structure as a result.
# File lib/json/pure/parser.rb, line 85
85: def parse
86: reset
87: obj = nil
88: until eos?
89: case
90: when scan(OBJECT_OPEN)
91: obj and raise ParserError, "source '#{peek(20)}' not in JSON!"
92: @current_nesting = 1
93: obj = parse_object
94: when scan(ARRAY_OPEN)
95: obj and raise ParserError, "source '#{peek(20)}' not in JSON!"
96: @current_nesting = 1
97: obj = parse_array
98: when skip(IGNORE)
99: ;
100: else
101: raise ParserError, "source '#{peek(20)}' not in JSON!"
102: end
103: end
104: obj or raise ParserError, "source did not contain any JSON!"
105: obj
106: end
# File lib/json/pure/parser.rb, line 182
182: def parse_array
183: raise NestingError, "nesting of #@current_nesting is to deep" if
184: @max_nesting.nonzero? && @current_nesting > @max_nesting
185: result = []
186: delim = false
187: until eos?
188: case
189: when (value = parse_value) != UNPARSED
190: delim = false
191: result << value
192: skip(IGNORE)
193: if scan(COLLECTION_DELIMITER)
194: delim = true
195: elsif match?(ARRAY_CLOSE)
196: ;
197: else
198: raise ParserError, "expected ',' or ']' in array at '#{peek(20)}'!"
199: end
200: when scan(ARRAY_CLOSE)
201: if delim
202: raise ParserError, "expected next element in array at '#{peek(20)}'!"
203: end
204: break
205: when skip(IGNORE)
206: ;
207: else
208: raise ParserError, "unexpected token in array at '#{peek(20)}'!"
209: end
210: end
211: result
212: end
# File lib/json/pure/parser.rb, line 214
214: def parse_object
215: raise NestingError, "nesting of #@current_nesting is to deep" if
216: @max_nesting.nonzero? && @current_nesting > @max_nesting
217: result = {}
218: delim = false
219: until eos?
220: case
221: when (string = parse_string) != UNPARSED
222: skip(IGNORE)
223: unless scan(PAIR_DELIMITER)
224: raise ParserError, "expected ':' in object at '#{peek(20)}'!"
225: end
226: skip(IGNORE)
227: unless (value = parse_value).equal? UNPARSED
228: result[string] = value
229: delim = false
230: skip(IGNORE)
231: if scan(COLLECTION_DELIMITER)
232: delim = true
233: elsif match?(OBJECT_CLOSE)
234: ;
235: else
236: raise ParserError, "expected ',' or '}' in object at '#{peek(20)}'!"
237: end
238: else
239: raise ParserError, "expected value in object at '#{peek(20)}'!"
240: end
241: when scan(OBJECT_CLOSE)
242: if delim
243: raise ParserError, "expected next name, value pair in object at '#{peek(20)}'!"
244: end
245: if @create_id and klassname = result[@create_id]
246: klass = JSON.deep_const_get klassname
247: break unless klass and klass.json_creatable?
248: result = klass.json_create(result)
249: end
250: break
251: when skip(IGNORE)
252: ;
253: else
254: raise ParserError, "unexpected token in object at '#{peek(20)}'!"
255: end
256: end
257: result
258: end
# File lib/json/pure/parser.rb, line 124
124: def parse_string
125: if scan(STRING)
126: return '' if self[1].empty?
127: self[1].gsub(%r((?:\\[\\bfnrt"/]|(?:\\u(?:[A-Fa-f\d]{4}))+|\\[\x20-\xff]))n) do |c|
128: if u = UNESCAPE_MAP[c[1]]
129: u
130: else # \uXXXX
131: bytes = ''
132: i = 0
133: while c[6 * i] == ?\\ && c[6 * i + 1] == ?u
134: bytes << c[6 * i + 2, 2].to_i(16) << c[6 * i + 4, 2].to_i(16)
135: i += 1
136: end
137: JSON::UTF16toUTF8.iconv(bytes)
138: end
139: end
140: else
141: UNPARSED
142: end
143: rescue Iconv::Failure => e
144: raise GeneratorError, "Caught #{e.class}: #{e}"
145: end
# File lib/json/pure/parser.rb, line 147
147: def parse_value
148: case
149: when scan(FLOAT)
150: Float(self[1])
151: when scan(INTEGER)
152: Integer(self[1])
153: when scan(TRUE)
154: true
155: when scan(FALSE)
156: false
157: when scan(NULL)
158: nil
159: when (string = parse_string) != UNPARSED
160: string
161: when scan(ARRAY_OPEN)
162: @current_nesting += 1
163: ary = parse_array
164: @current_nesting -= 1
165: ary
166: when scan(OBJECT_OPEN)
167: @current_nesting += 1
168: obj = parse_object
169: @current_nesting -= 1
170: obj
171: when @allow_nan && scan(NAN)
172: NaN
173: when @allow_nan && scan(INFINITY)
174: Infinity
175: when @allow_nan && scan(MINUS_INFINITY)
176: MinusInfinity
177: else
178: UNPARSED
179: end
180: end