// JSON Grammar // ============ // // Based on the grammar from RFC 7159 [1]. // // Note that JSON is also specified in ECMA-262 [2], ECMA-404 [3], and on the // JSON website [4] (somewhat informally). The RFC seems the most authoritative // source, which is confirmed e.g. by [5]. // // [1] http://tools.ietf.org/html/rfc7159 // [2] http://www.ecma-international.org/publications/standards/Ecma-262.htm // [3] http://www.ecma-international.org/publications/standards/Ecma-404.htm // [4] http://json.org/ // [5] https://www.tbray.org/ongoing/When/201x/2014/03/05/RFC7159-JSON // ----- 2. JSON Grammar ----- JSON_text = ws value:value ws { return value; } begin_array = ws "[" ws begin_object = ws "{" ws end_array = ws "]" ws end_object = ws "}" ws name_separator = ws ":" ws value_separator = ws "," ws ws "whitespace" = [ \t\n\r]* // ----- 3. Values ----- value = false / null / true / object / array / number / string false = "false" { return false; } null = "null" { return null; } true = "true" { return true; } // ----- 4. Objects ----- object = begin_object members:( head:member tail:(value_separator m:member { return m; })* { var result = {}; [head].concat(tail).forEach(function(element) { result[element.name] = element.value; }); return result; } )? end_object { return members !== null ? members: {}; } member = name:string name_separator value:value { return { name: name, value: value }; } // ----- 5. Arrays ----- array = begin_array values:( head:value tail:(value_separator v:value { return v; })* { return [head].concat(tail); } )? end_array { return values !== null ? values : []; } // ----- 6. Numbers ----- number "number" = minus? int frac? exp? { return parseFloat(text()); } decimal_point = "." digit1_9 = [1-9] e = [eE] exp = e (minus / plus)? DIGIT+ frac = decimal_point DIGIT+ int = zero / (digit1_9 DIGIT*) minus = "-" plus = "+" zero = "0" // ----- 7. Strings ----- string "string" = quotation_mark chars:char* quotation_mark { return chars.join(""); } char = unescaped / escape sequence:( '"' / "\\" / "/" / "b" { return "\b"; } / "f" { return "\f"; } / "n" { return "\n"; } / "r" { return "\r"; } / "t" { return "\t"; } / "u" digits:$(HEXDIG HEXDIG HEXDIG HEXDIG) { return String.fromCharCode(parseInt(digits, 16)); } ) { return sequence; } escape = "\\" quotation_mark = '"' unescaped = [^\0-\x1F\x22\x5C] // ----- Core ABNF Rules ----- // See RFC 4234, Appendix B (http://tools.ietf.org/html/rfc4234). DIGIT = [0-9] HEXDIG = [0-9a-f]i