70 lines
2.8 KiB
Plaintext
70 lines
2.8 KiB
Plaintext
|
WHITESPACE = _{ " " | "," | "\t" | "\u{feff}" | line_terminator }
|
||
|
COMMENT = _{ "#" ~ (!line_terminator ~ ANY)* }
|
||
|
line_terminator = @{ "\r\n" | "\r" | "\n" }
|
||
|
|
||
|
document = { SOI ~ definition+ ~ EOI }
|
||
|
definition = { operation_definition | fragment_definition }
|
||
|
|
||
|
operation_definition = { named_operation_definition | selection_set }
|
||
|
named_operation_definition = { operation_type ~ name? ~ variable_definitions? ~ directives? ~ selection_set }
|
||
|
operation_type = { "query" | "mutation" | "subscription" }
|
||
|
variable_definitions = { "(" ~ variable_definition* ~ ")" }
|
||
|
variable_definition = { variable ~ ":" ~ type_ ~ default_value? }
|
||
|
variable = { "$" ~ name }
|
||
|
default_value = { "=" ~ value }
|
||
|
|
||
|
type_ = @{ (name | "[" ~ type_ ~ "]") ~ "!"? }
|
||
|
|
||
|
// float must come before int; other than that order does not matter
|
||
|
value = { variable | float | int | string | boolean | null | enum_ | list | object }
|
||
|
|
||
|
float = @{ int ~ ((fractional ~ exponent) | fractional | exponent) }
|
||
|
fractional = { "." ~ ASCII_DIGIT+ }
|
||
|
exponent = { ("E" | "e") ~ ("+" | "-")? ~ ASCII_DIGIT+ }
|
||
|
|
||
|
int = @{ "-"? ~ ("0" | (ASCII_NONZERO_DIGIT ~ ASCII_DIGIT*)) }
|
||
|
boolean = { "true" | "false" }
|
||
|
|
||
|
string = ${ ("\"\"\"" ~ block_string_content ~ "\"\"\"") | ("\"" ~ string_content ~ "\"") }
|
||
|
block_string_content = @{ block_string_character* }
|
||
|
block_string_character = {
|
||
|
(!("\"\"\"" | "\\\"\"\"") ~ ANY)
|
||
|
| "\\\"\"\""
|
||
|
}
|
||
|
string_content = @{ string_character* }
|
||
|
string_character = {
|
||
|
(!("\"" | "\\" | line_terminator) ~ ANY)
|
||
|
| ("\\" ~ ("\"" | "\\" | "/" | "b" | "f" | "n" | "r" | "t"))
|
||
|
| ("\\u" ~ unicode_scalar_value_hex)
|
||
|
}
|
||
|
// Spec inconsistency:
|
||
|
// In GraphQL, strings can contain any Unicode code point. However in Rust strings can only contain
|
||
|
// Unicode Scalar Values. To avoid having to use Vec<u8> everywhere we deviate from the spec
|
||
|
// slightly and disallow non-scalar value code points at the parsing level.
|
||
|
unicode_scalar_value_hex = { !(^"d" ~ ('8'..'9' | 'a'..'f' | 'A'..'F')) ~ ASCII_HEX_DIGIT{4} }
|
||
|
|
||
|
null = { "null" }
|
||
|
|
||
|
enum_ = ${ !(boolean | null) ~ name }
|
||
|
|
||
|
list = { "[" ~ value* ~ "]" }
|
||
|
|
||
|
name_value = { name ~ ":" ~ value }
|
||
|
object = { "{" ~ name_value* ~ "}" }
|
||
|
|
||
|
selection_set = { "{" ~ selection+ ~ "}" }
|
||
|
selection = { field | inline_fragment | fragment_spread }
|
||
|
field = { alias? ~ name ~ arguments? ~ directives? ~ selection_set? }
|
||
|
alias = { name ~ ":" }
|
||
|
arguments = { "(" ~ name_value* ~ ")" }
|
||
|
fragment_spread = { "..." ~ name ~ directives? }
|
||
|
inline_fragment = { "..." ~ type_condition? ~ directives? ~ selection_set }
|
||
|
|
||
|
fragment_definition = { "fragment" ~ name ~ type_condition ~ directives? ~ selection_set }
|
||
|
type_condition = { "on" ~ name }
|
||
|
|
||
|
directives = { directive* }
|
||
|
directive = { "@" ~ name ~ arguments? }
|
||
|
|
||
|
name = @{ (ASCII_ALPHA | "_") ~ (ASCII_ALPHA | ASCII_DIGIT | "_")* }
|