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