// see https://spec.json5.org/#syntactic-grammar and
// https://spec.json5.org/#lexical-grammar

COMMENT = _{ "/*" ~ (!"*/" ~ ANY)* ~ "*/" | "//" ~ (!line_terminator ~ ANY)* }

WHITESPACE = _{
  "\u{0009}" |
  "\u{000B}" |
  "\u{000C}" |
  "\u{0020}" |
  "\u{00A0}" |
  "\u{FEFF}" |
  SPACE_SEPARATOR |
  line_terminator
}

array = { "[" ~ "]" | "[" ~ value ~ ("," ~ value)* ~ ","? ~ "]" }

boolean = @{ "true" | "false" }

char_escape_sequence = @{ single_escape_char | non_escape_char }

char_literal = @{ !("\\" | line_terminator) ~ ANY }

decimal_integer_literal = _{ "0" | ASCII_NONZERO_DIGIT ~ ASCII_DIGIT* }

decimal_literal = _{
  decimal_integer_literal ~ "." ~ ASCII_DIGIT* ~ exponent_part? |
  "." ~ ASCII_DIGIT+~ exponent_part? |
  decimal_integer_literal ~ exponent_part?
}

double_quote_char = _{
  "\\" ~ escape_sequence |
  line_continuation |
  !"\"" ~ char_literal
}

escape_char = _{ single_escape_char | ASCII_DIGIT | "x" | "u" }

escape_sequence = _{
  char_escape_sequence |
  nul_escape_sequence |
  "x" ~ hex_escape_sequence |
  "u" ~ unicode_escape_sequence
}

exponent_part = _{ ^"e" ~ ("+" | "-")? ~ ASCII_DIGIT+ }

hex_escape_sequence = @{ ASCII_HEX_DIGIT{2} }

hex_integer_literal = _{ ("+" | "-")? ~ ^"0x" ~ ASCII_HEX_DIGIT+ }

identifier = ${ identifier_start ~ identifier_part* }

identifier_part = _{
  identifier_start |
  &(
    NONSPACING_MARK |
    DIACRITIC | // not sure about this, spec says "Combining spacing mark (Mc)"
    DECIMAL_NUMBER |
    CONNECTOR_PUNCTUATION |
    "\u{200C}" |
    "\u{200D}"
  ) ~ char_literal
}

identifier_start = _{
  &(unicode_letter | "$" | "_") ~ char_literal |
  "\\u" ~ unicode_escape_sequence
}

key = _{ identifier | string }

line_continuation = _{ "\\" ~ line_terminator_sequence }

line_terminator = _{ "\u{000A}" | "\u{000D}" | "\u{2028}" | "\u{2029}" }

line_terminator_sequence = _{ "\u{000D}" ~ "\u{000A}" | line_terminator }

non_escape_char = _{ !(escape_char | line_terminator) ~ ANY }

nul_escape_sequence = @{ "0" }

null = @{ "null" }

number = @{ ("+" | "-")? ~ numeric_literal }

numeric_literal = _{
  hex_integer_literal |
  decimal_literal |
  "Infinity" |
  "NaN"
}

object = { "{" ~ "}" | "{" ~ pair ~ ("," ~ pair)* ~ ","? ~ "}" }

pair = _{ key ~ ":" ~ value }

single_escape_char = _{ "'" | "\"" | "\\" | "b" | "f" | "n" | "r" | "t" | "v" }

single_quote_char = _{
  "\\" ~ escape_sequence |
  line_continuation |
  !"'" ~ char_literal
}

double_single_quote_char = _{
  "\\" ~ escape_sequence |
  line_continuation |
  !("''") ~ char_literal
}

string = ${ "\"" ~ double_quote_char* ~ "\"" | "''" ~ double_single_quote_char* ~ "''" | "'" ~ single_quote_char* ~ "'" }

text = _{ SOI ~ value ~ EOI }

unicode_escape_sequence = @{ ASCII_HEX_DIGIT{4} }

unicode_letter = _{
  UPPERCASE_LETTER |
  LOWERCASE_LETTER |
  TITLECASE_LETTER |
  MODIFIER_LETTER |
  OTHER_LETTER |
  LETTER_NUMBER
}

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