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