Skip to content

Instantly share code, notes, and snippets.

@wreulicke
Last active August 30, 2017 13:56
Show Gist options
  • Save wreulicke/ebf7f55cc523515779490e826a4c0d36 to your computer and use it in GitHub Desktop.
Save wreulicke/ebf7f55cc523515779490e826a4c0d36 to your computer and use it in GitHub Desktop.
謎のjson template ast parser
{
"test": "string",
"vvvv": "{{{vvvv}}}",
"v": 2,
"d": {{{number}}},
"{{{hogehoge}}}":[
{{{template}}},
"{{{edge}}}"
],
"test": bool(h)
}
// 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
= booleanTemplate
/ false
/ null
/ true
/ numberTemplate
/ object
/ array
/ number
/ string
booleanTemplate = "bool(" id:$[a-zA-Z]* ")" {return {type: "boolean_template", id}}
numberTemplate = "{{{" id:$[a-zA-Z]* "}}}" { return {type:"number_template", id: id}}
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; })*
{
return {type: "object", members: [head].concat(tail)};
}
)?
end_object
{ return members !== null ? members: {}; }
member
= name:key 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 {type: "array", value: [head].concat(tail)}; }
)?
end_array
{ return values !== null ? values : []; }
// ----- 6. Numbers -----
number "number"
= minus? int frac? exp? { return {type: "number", exp:text(), value: 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 -----
key = e:string {return e}
string "string"
= quotation_mark "{{{" chars:$[a-zA-Z]* "}}}" quotation_mark {
return {type:"string_template", id: chars }
}
/ quotation_mark chars:$char* quotation_mark {
return {type:"string", value: chars };
}
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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment