1WHITESPACE = _{ " " | "\t" | "\n" | "\r" }
2COMMENT = _{ "#" ~ (!("\n" | "\r") ~ ANY)* }
3
4uson_text = { SOI ~ expr* ~ EOI }
5
6expr = { value }
7
8// Values
9value = {
10 typed
11 | false_val
12 | null_val
13 | true_val
14 | assign
15 | object
16 | array
17 | number
18 | string
19}
20
21false_val = { "false" }
22null_val = { "null" }
23true_val = { "true" }
24
25// Objects - support optional commas like arrays
26object = {
27 "{" ~ (member ~ (","? ~ member)* ~ ","?)? ~ "}"
28}
29
30member = { string ~ ":" ~ value }
31
32// Arrays
33array = {
34 "[" ~ (value ~ (","? ~ value)* ~ ","?)? ~ "]"
35}
36
37// Numbers - must not be followed by alphanumeric to avoid matching "1ab" as number
38number = @{
39 "-"? ~ int ~ ("." ~ ASCII_DIGIT+)? ~ (^"e" ~ ("+" | "-")? ~ ASCII_DIGIT+)? ~ !ASCII_ALPHANUMERIC
40}
41
42int = { "0" | (ASCII_NONZERO_DIGIT ~ ASCII_DIGIT*) }
43
44// Strings
45string = {
46 double_quoted_string
47 | single_quoted_string
48 | unquoted_string
49}
50
51double_quoted_string = @{
52 "\"" ~ (escape_sequence | (!("\"" | "\\") ~ ANY))* ~ "\""
53}
54
55single_quoted_string = @{
56 "'" ~ (escape_sequence | (!("'" | "\\") ~ ANY))* ~ "'"
57}
58
59unquoted_string = @{
60 simple_char+
61}
62
63simple_char = {
64 !("\"" | "#" | "," | ":" | "[" | "\\" | "]" | "{" | "}" | WHITESPACE) ~ ANY
65}
66
67escape_sequence = @{
68 "\\" ~ (
69 "\"" | "'" | "\\" | "/" | "#"
70 | "b" | "f" | "n" | "r" | "t"
71 | ("u" ~ ASCII_HEX_DIGIT{4})
72 )
73}
74
75// Assignments
76assign = { string ~ ":" ~ value }
77
78// Typed literals
79typed = { type_name ~ "!" ~ value }
80type_name = @{ (ASCII_ALPHA | ASCII_DIGIT | "_" | "-")+ }