1# A simple grammar for GraphQL
2%grammar graphql
3%version 0.01
4%include pegex-atoms
5
6# canonical: https://github.com/facebook/graphql/blob/master/spec/Appendix%20B%20--%20Grammar%20Summary.md
7# IDL RFC: https://github.com/facebook/graphql/pull/90
8# inspiration drawn from the slightly obsolete https://github.com/antlr/grammars-v4/blob/master/graphql/GraphQL.g4
9# string and number from https://github.com/ingydotnet/json-pgx/blob/master/json.pgx
10
11# in order to capture comments *before* a given rule-group *into* it,
12# can't suck up whitespace *after* rule-groups as part of them
13graphql: definition+
14
15definition: (operationDefinition | fragment | typeSystemDefinition | .ws2)
16
17operationDefinition: selectionSet | operationType .(-) name? .(-) variableDefinitions? .(-) directives? selectionSet
18
19operationType: /(query|mutation|subscription)/
20
21selectionSet: .(/- LCURLY -/) ( selection+ | `Expected name` ) .(/- RCURLY -/)
22
23selection: (field | inline_fragment | fragment_spread) .(-)
24
25field: alias? name .(-) arguments? .(-) directives? selectionSet?
26
27alias: name .(/- COLON -/)
28
29arguments: .(/- LPAREN -/) argument+ .(/- RPAREN -/)
30
31argument: name .(/- COLON -/) value
32
33fragment_spread: .spread fragmentName .(-) directives?
34
35inline_fragment: .spread typeCondition? .(-) directives? selectionSet
36
37fragment: .(/- 'fragment' -/) fragmentName .(-) (typeCondition | `Expected "on"`) .(-) directives? selectionSet
38
39fragmentName: ('on' `Unexpected Name "on"` | name)
40
41typeCondition: .(/'on' -/) namedType
42
43value: (variable | float | int | string | boolean | null | enumValue | listValue | objectValue) .(-)
44
45value_const: (float | int | string | boolean | null | enumValue | listValue_const | objectValue_const) .(-)
46
47boolean: /(true|false)/
48
49null: /(null)/
50
51enumValue: (/(true|false|null)/ `Invalid enum value` | name)
52
53listValue: .(/- LSQUARE -/) value* .(/- RSQUARE -/)
54
55listValue_const: .(/- LSQUARE -/) value_const* .(/- RSQUARE -/)
56
57objectValue: .(/- LCURLY -/) ( objectField+ | `Expected name` ) .(/- RCURLY -/)
58
59objectValue_const: .(/- LCURLY -/) ( objectField_const+ | `Expected name or constant` ) .(/- RCURLY -/)
60
61objectField: name .(/- COLON -/) value .(-)
62
63objectField_const: name .(/- COLON -/) value_const
64
65variableDefinitions: .(/- LPAREN -/) ( variableDefinition+ | `Expected $argument: Type` ) .(/- RPAREN -/)
66
67variableDefinition: variable .(/- COLON -/) typedef defaultValue? .(-)
68
69variable: .(/- DOLLAR/) name
70
71defaultValue: .(/- EQUAL -/) value_const
72
73# not "type" as using that for "objectTypeDefinition"
74typedef: nonNullType | namedType | listType
75
76namedType: name .(-)
77
78listType: LSQUARE typedef RSQUARE
79
80nonNullType: namedType /- BANG/ | listType /- BANG/
81
82directives: directiveactual+
83
84directiveactual: .(/- AT/) name arguments?
85
86string: blockStringValue | stringValue
87
88stringValue: /
89  DOUBLE
90    (
91      (:
92        BACK (:     # Backslash escapes
93          [
94            DOUBLE    # Double Quote
95            BACK    # Back Slash
96            SLASH     # Foreward Slash
97            'b'     # Back Space
98            'f'     # Form Feed
99            'n'     # New Line
100            'r'     # Carriage Return
101            't'     # Horizontal Tab
102          ]
103        |
104          'u' HEX{4}    # Unicode octet pair
105        )
106      |
107        [^ DOUBLE CONTROLS BACK ]  # Anything else
108      )*
109    )
110  DOUBLE
111/
112
113blockStringValue: /
114  DOUBLE DOUBLE DOUBLE
115    (
116      (:
117        (: BACK DOUBLE DOUBLE DOUBLE ) |
118        [^ CONTROLS DOUBLE ] |
119        [ TAB NL CR ] |
120	(: DOUBLE (?!"") )
121      )*
122    )
123  DOUBLE DOUBLE DOUBLE
124/
125
126float: /(
127  DASH?
128  (: 0 | [1-9] DIGIT* )
129  (:
130    # one or other or both. not neither
131    (: DOT DIGIT+ ) (: [eE] [ DASH PLUS ]? DIGIT+ ) |
132    (: DOT DIGIT+ ) |
133    (: [eE] [ DASH PLUS ]? DIGIT+ )
134  )
135)/
136
137int: /(
138  DASH?
139  (: 0 | [1-9] DIGIT* )
140)/
141
142name: /([ UNDER ALPHAS ] [ WORDS ]*)/
143
144spread: /\.{3}/ .(-)
145
146ws: / (: WS | \x{FEFF} | COMMA | comment ) /
147
148comment: / BLANK* HASH BLANK* [^\r\n]* (: EOL | CR !NL | EOS ) / # CR is because MacOS 9
149
150description: .(/ [ WS NL ]* /) string .(/ [ WS NL ]* /) | .(-)
151
152typeSystemDefinition: description? (schema | typeDefinition | typeExtensionDefinition | directive)
153
154schema: .(/'schema' -/) directives? ( .(/- LCURLY -/) operationTypeDefinition+ .(/- RCURLY /) )?
155
156operationTypeDefinition: operationType .(/- COLON -/) namedType .(-)
157
158typeDefinition: scalar | type | interface | union | enumTypeDefinition | input
159
160# aka scalarTypeDefinition
161scalar: .(/'scalar' -/) name .(-) directives?
162
163# aka objectTypeDefinition
164type: .(/'type' -/) name .(-) implementsInterfaces? .(-) directives? ( .(/- LCURLY /) fieldDefinition+ .(/- RCURLY /) )?
165
166implementsInterfaces: .(/'implements' -/) .(/- AMP -/)? (namedType+ % .(/- AMP -/))
167
168fieldDefinition: description? name .(-) argumentsDefinition? .(/- COLON -/) typedef .(-) directives?
169
170argumentsDefinition: .(/- LPAREN /) inputValueDefinition+ .(/- RPAREN /)
171
172inputValueDefinition: description? name .(/- COLON -/) typedef .(-) defaultValue? .(-) directives? .(-)
173
174interface: .(/'interface' -/) name .(-) directives? ( .(/- LCURLY /) fieldDefinition+ .(/- RCURLY /) )?
175
176union: .(/'union' -/) name .(-) directives? ( .(/- EQUAL -/) unionMembers )?
177
178unionMembers: .(/- PIPE -/)? namedType+ % .(/- PIPE -/)
179
180enumTypeDefinition: .(/'enum' -/) name .(-) directives? ( .(/- LCURLY /) enumValueDefinition+ .(/- RCURLY /) )?
181
182enumValueDefinition: description? enumValue (.(-) directives)?
183
184input: .(/'input' -/) name .(-) directives? ( .(/- LCURLY /) inputValueDefinition+ .(/- RCURLY /) )?
185
186typeExtensionDefinition: .(/'extend' -/) (schema | typeDefinition)
187
188directive: .(/'directive' - AT -/) name .(-) argumentsDefinition? .(/- 'on' -/) directiveLocations
189
190directiveLocations: .(/- PIPE -/)? name+ % .(/- PIPE -/)
191