# Predicated Recursive Descent grammar for JSON
# Simpler, slightly slower version
# Passes all of the parsing tests in https://github.com/nst/JSONTestSuite
json ::= element $become EOF
EOF ::= @eof
element ::=
@peek(0, "{") object | @peek(0, "[") array
# A``r regex strings match any token that starts with the contained regex
| @peekr(0, A`"`r) string
| @auto "true" | @auto "false" | @auto "null"
| number
object ::= @peek(1, "}") "{" "}" | "{" members "}"
members ::= member $become memberlist
memberlist ::= @auto "," member $become memberlist | #empty
member ::= string ":" element
array ::= @peek(1, "]") "[" "]" | "[" elements "]"
# Lookahead/predicates are necessary for any non-final alternation. Alternations are attempted in order, and never backtracked/memoized.
# Example: this would never attempt to match the "elements" production: array ::= "[" "]" | "[" elements "]"
elements ::= element $become elementlist
elementlist ::= @auto "," element $become elementlist | #empty
# NOTE: #empty is just a comment. It's not a magical way of writing epsilons.
# r``r regex strings both perform a match test at parse time (cached) and Also register themselves with the tokenizer.
# R``r do the same, but WITHOUT registering themselves with the tokenizer. A``r also do not register with the tokenizer.
string ::= r`"(?:[ !#-\[\]-\u{10ffff}]|\\["\\\/bfnrt]|\\u[a-fA-F0-9]{4})*"`r
number ::= r`[-]?(?:[1-9][0-9]+|[0-9])(?:\.[0-9]+)?(?:[eE][-+]?[0-9]+)?`r