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