fson 1.0.0

Flexible Serialized Object Notation
Documentation
WHITESPACE = _{ " " | "\t" | "\r" | "\n" }
COMMENT    = _{ ("/*" ~ (!"*/" ~ ANY)* ~ "*/") | ("//" ~ (!NEWLINE ~ ANY)*) }

// Identifier
identifier = @{ LETTER+ ~ (ASCII_ALPHANUMERIC | "_" | LETTER+)* }

colon      = _{ ":" }
semicolon  = _{ ";" }
comma      = _{ "," }
ref_symbol = _{ "#" }

// Array [..., ...]
array = { "[" ~ value ~ (comma ~ value)* ~ comma? ~ "]" | "[" ~ "]" }

// Object { "x": 1, y: 1 }
object_pair = { (string | identifier) ~ colon ~ value }
object      = { "{" ~ object_pair ~ (comma ~ object_pair)* ~ comma? ~ "}" | "{" ~ "}" }

// Dobule quotes string
db_quotes_str = _{ ("\"" ~ double_quotes_string ~ "\"") }
// Single quotes string
si_quotes_str = _{ ("'" ~ single_quotes_string ~ "'") }

string = ${ db_quotes_str | si_quotes_str | ("`" ~ template_string ~ "`") }

// Normal strings (" ... ", ' ... ')
double_quotes_string = @{
    (!("\"" | "\\") ~ ANY | escape_and_unicode)*
}
single_quotes_string = @{
    (!("\'" | "\\") ~ ANY | escape_and_unicode)*
}

// Template string (` ${...} `)
template_char          = @{
    (!("`" | "\\") ~ ANY | escape_and_unicode)
}
template_string        =  { ((string_interpolation? ~ template_char ~ string_interpolation?) | string_interpolation)* }
interpolation_template =  { "${" ~ value ~ "}" }
string_interpolation   = _{ interpolation_template+ }

// Escape (\...) and unicode (\u....)
escape_and_unicode = {
    "\\" ~ ("\"" | "\'" | "`" | "\\" | "/" | "b" | "f" | "n" | "r" | "t")
  | "\\" ~ ("u" ~ ASCII_HEX_DIGIT{4})
}

// Number (1, +1, -1, 0.1)
number = @{ ("-" | "+")? ~ (hexadecimal | (int ~ ("." ~ ASCII_DIGIT+ ~ exp? | exp)?) | infinity) }
int    = @{ "0" | ASCII_NONZERO_DIGIT ~ ASCII_DIGIT* }
exp    = @{ ("E" | "e") ~ ("+" | "-")? ~ ASCII_DIGIT+ }

infinity    = { "Infinity" }
hexadecimal = { "0x" ~ HEX_DIGIT+ }

// Not a Number
not_a_number = { "NaN" }

// Boolean (true, false)
boolean = { "true" | "false" }

// Null
null = { "null" }

// Reference
ref_str        = _{ (string | identifier) }
ref_path_slash = _{ "/" }
ref_path       =  { ref_path_slash ~ (ref_str ~ (ref_path_slash ~ ref_str)* | "") }
reference      =  { ref_symbol ~ (ref_str | ref_path) }

ref_value_id  = { ref_symbol ~ "id" ~ colon ~ (db_quotes_str | si_quotes_str) ~ semicolon }
ref_value_val = { ref_symbol ~ "value" ~ colon ~ value ~ semicolon }
ref_value     = { ref_symbol ~ "{" ~ ((ref_value_id ~ ref_value_val) | (ref_value_val ~ ref_value_id)) ~ "}" }

value = _{ string | array | ref_value | object | boolean | number | null | reference | not_a_number }

// JSON Document
document = _{ SOI ~ value ~ EOI }