| Class | JSON::Pure::Parser |
| In: |
lib/json/pure/parser.rb
|
| Parent: | StringScanner |
| STRING | = | /" ((?:[^\x0-\x1f"\\] | \\["\\\/bfnrt] | \\u[0-9a-fA-F]{4} | \\[\x20-\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: @object_class = opts[:object_class] || Hash
80: @array_class = opts[:array_class] || Array
81: end
Parses the current JSON string source and returns the complete data structure as a result.
# File lib/json/pure/parser.rb, line 87
87: def parse
88: reset
89: obj = nil
90: until eos?
91: case
92: when scan(OBJECT_OPEN)
93: obj and raise ParserError, "source '#{peek(20)}' not in JSON!"
94: @current_nesting = 1
95: obj = parse_object
96: when scan(ARRAY_OPEN)
97: obj and raise ParserError, "source '#{peek(20)}' not in JSON!"
98: @current_nesting = 1
99: obj = parse_array
100: when skip(IGNORE)
101: ;
102: else
103: raise ParserError, "source '#{peek(20)}' not in JSON!"
104: end
105: end
106: obj or raise ParserError, "source did not contain any JSON!"
107: obj
108: end
# File lib/json/pure/parser.rb, line 188
188: def parse_array
189: raise NestingError, "nesting of #@current_nesting is to deep" if
190: @max_nesting.nonzero? && @current_nesting > @max_nesting
191: result = @array_class.new
192: delim = false
193: until eos?
194: case
195: when (value = parse_value) != UNPARSED
196: delim = false
197: result << value
198: skip(IGNORE)
199: if scan(COLLECTION_DELIMITER)
200: delim = true
201: elsif match?(ARRAY_CLOSE)
202: ;
203: else
204: raise ParserError, "expected ',' or ']' in array at '#{peek(20)}'!"
205: end
206: when scan(ARRAY_CLOSE)
207: if delim
208: raise ParserError, "expected next element in array at '#{peek(20)}'!"
209: end
210: break
211: when skip(IGNORE)
212: ;
213: else
214: raise ParserError, "unexpected token in array at '#{peek(20)}'!"
215: end
216: end
217: result
218: end
# File lib/json/pure/parser.rb, line 220
220: def parse_object
221: raise NestingError, "nesting of #@current_nesting is to deep" if
222: @max_nesting.nonzero? && @current_nesting > @max_nesting
223: result = @object_class.new
224: delim = false
225: until eos?
226: case
227: when (string = parse_string) != UNPARSED
228: skip(IGNORE)
229: unless scan(PAIR_DELIMITER)
230: raise ParserError, "expected ':' in object at '#{peek(20)}'!"
231: end
232: skip(IGNORE)
233: unless (value = parse_value).equal? UNPARSED
234: result[string] = value
235: delim = false
236: skip(IGNORE)
237: if scan(COLLECTION_DELIMITER)
238: delim = true
239: elsif match?(OBJECT_CLOSE)
240: ;
241: else
242: raise ParserError, "expected ',' or '}' in object at '#{peek(20)}'!"
243: end
244: else
245: raise ParserError, "expected value in object at '#{peek(20)}'!"
246: end
247: when scan(OBJECT_CLOSE)
248: if delim
249: raise ParserError, "expected next name, value pair in object at '#{peek(20)}'!"
250: end
251: if @create_id and klassname = result[@create_id]
252: klass = JSON.deep_const_get klassname
253: break unless klass and klass.json_creatable?
254: result = klass.json_create(result)
255: end
256: break
257: when skip(IGNORE)
258: ;
259: else
260: raise ParserError, "unexpected token in object at '#{peek(20)}'!"
261: end
262: end
263: result
264: end
# File lib/json/pure/parser.rb, line 126
126: def parse_string
127: if scan(STRING)
128: return '' if self[1].empty?
129: string = self[1].gsub(%r((?:\\[\\bfnrt"/]|(?:\\u(?:[A-Fa-f\d]{4}))+|\\[\x20-\xff]))n) do |c|
130: if u = UNESCAPE_MAP[$&[1]]
131: u
132: else # \uXXXX
133: bytes = ''
134: i = 0
135: while c[6 * i] == ?\\ && c[6 * i + 1] == ?u
136: bytes << c[6 * i + 2, 2].to_i(16) << c[6 * i + 4, 2].to_i(16)
137: i += 1
138: end
139: JSON::UTF16toUTF8.iconv(bytes)
140: end
141: end
142: if string.respond_to?(:force_encoding)
143: string.force_encoding(Encoding::UTF_8)
144: end
145: string
146: else
147: UNPARSED
148: end
149: rescue Iconv::Failure => e
150: raise GeneratorError, "Caught #{e.class}: #{e}"
151: end
# File lib/json/pure/parser.rb, line 153
153: def parse_value
154: case
155: when scan(FLOAT)
156: Float(self[1])
157: when scan(INTEGER)
158: Integer(self[1])
159: when scan(TRUE)
160: true
161: when scan(FALSE)
162: false
163: when scan(NULL)
164: nil
165: when (string = parse_string) != UNPARSED
166: string
167: when scan(ARRAY_OPEN)
168: @current_nesting += 1
169: ary = parse_array
170: @current_nesting -= 1
171: ary
172: when scan(OBJECT_OPEN)
173: @current_nesting += 1
174: obj = parse_object
175: @current_nesting -= 1
176: obj
177: when @allow_nan && scan(NAN)
178: NaN
179: when @allow_nan && scan(INFINITY)
180: Infinity
181: when @allow_nan && scan(MINUS_INFINITY)
182: MinusInfinity
183: else
184: UNPARSED
185: end
186: end