| /* JSON parser based on the grammar described at http://json.org/. */ |
| |
| /* ===== Syntactical Elements ===== */ |
| |
| start |
| = _ object:object { return object; } |
| |
| object |
| = "{" _ "}" _ { return {}; } |
| / "{" _ members:members "}" _ { return members; } |
| |
| members |
| = head:pair tail:("," _ pair)* { |
| var result = {}; |
| result[head[0]] = head[1]; |
| for (var i = 0; i < tail.length; i++) { |
| result[tail[i][2][0]] = tail[i][2][1]; |
| } |
| return result; |
| } |
| |
| pair |
| = name:string ":" _ value:value { return [name, value]; } |
| |
| array |
| = "[" _ "]" _ { return []; } |
| / "[" _ elements:elements "]" _ { return elements; } |
| |
| elements |
| = head:value tail:("," _ value)* { |
| var result = [head]; |
| for (var i = 0; i < tail.length; i++) { |
| result.push(tail[i][2]); |
| } |
| return result; |
| } |
| |
| value |
| = string |
| / number |
| / object |
| / array |
| / "true" _ { return true; } |
| / "false" _ { return false; } |
| // FIXME: We can't return null here because that would mean parse failure. |
| / "null" _ { return "null"; } |
| |
| /* ===== Lexical Elements ===== */ |
| |
| string "string" |
| = '"' '"' _ { return ""; } |
| / '"' chars:chars '"' _ { return chars; } |
| |
| chars |
| = chars:char+ { return chars.join(""); } |
| |
| char |
| // In the original JSON grammar: "any-Unicode-character-except-"-or-\-or-control-character" |
| = [^"\\\0-\x1F\x7f] |
| / '\\"' { return '"'; } |
| / "\\\\" { return "\\"; } |
| / "\\/" { return "/"; } |
| / "\\b" { return "\b"; } |
| / "\\f" { return "\f"; } |
| / "\\n" { return "\n"; } |
| / "\\r" { return "\r"; } |
| / "\\t" { return "\t"; } |
| / "\\u" h1:hexDigit h2:hexDigit h3:hexDigit h4:hexDigit { |
| return String.fromCharCode(parseInt("0x" + h1 + h2 + h3 + h4)); |
| } |
| |
| number "number" |
| = int_:int frac:frac exp:exp _ { return parseFloat(int_ + frac + exp); } |
| / int_:int frac:frac _ { return parseFloat(int_ + frac); } |
| / int_:int exp:exp _ { return parseFloat(int_ + exp); } |
| / int_:int _ { return parseFloat(int_); } |
| |
| int |
| = digit19:digit19 digits:digits { return digit19 + digits; } |
| / digit:digit |
| / "-" digit19:digit19 digits:digits { return "-" + digit19 + digits; } |
| / "-" digit:digit { return "-" + digit; } |
| |
| frac |
| = "." digits:digits { return "." + digits; } |
| |
| exp |
| = e:e digits:digits { return e + digits; } |
| |
| digits |
| = digits:digit+ { return digits.join(""); } |
| |
| e |
| = e:[eE] sign:[+-]? { return e + sign; } |
| |
| /* |
| * The following rules are not present in the original JSON gramar, but they are |
| * assumed to exist implicitly. |
| * |
| * FIXME: Define them according to ECMA-262, 5th ed. |
| */ |
| |
| digit |
| = [0-9] |
| |
| digit19 |
| = [1-9] |
| |
| hexDigit |
| = [0-9a-fA-F] |
| |
| /* ===== Whitespace ===== */ |
| |
| _ "whitespace" |
| = whitespace* |
| |
| // Whitespace is undefined in the original JSON grammar, so I assume a simple |
| // conventional definition consistent with ECMA-262, 5th ed. |
| whitespace |
| = [ \t\n\r] |