Skip to content

Commit 3bc2b08

Browse files
committed
Avoid parse ambiguity on type extensions
Partial fix to #564, adds lookahead constraints to type system extensions to remove ambiguity or inefficiency from the grammar. The GraphQL grammar should be parsed in linear type with at most one lookahead. Since extensions have an optional `{ }` body, finding the token `{` should always attempt to parse the relevant portion of the type extension rather than completing the type extension and attempting to parse the query shorthand SelectionSet.
1 parent 439cacf commit 3bc2b08

File tree

2 files changed

+40
-20
lines changed

2 files changed

+40
-20
lines changed

spec/Appendix B -- Grammar Summary.md

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ SchemaDefinition : schema Directives[Const]? { RootOperationTypeDefinition+ }
198198

199199
SchemaExtension :
200200
- extend schema Directives[Const]? { RootOperationTypeDefinition+ }
201-
- extend schema Directives[Const]
201+
- extend schema Directives[Const] [lookahead != `{`]
202202

203203
RootOperationTypeDefinition : OperationType : NamedType
204204

@@ -225,12 +225,14 @@ ScalarTypeDefinition : Description? scalar Name Directives[Const]?
225225
ScalarTypeExtension :
226226
- extend scalar Name Directives[Const]
227227

228-
ObjectTypeDefinition : Description? type Name ImplementsInterfaces? Directives[Const]? FieldsDefinition?
228+
ObjectTypeDefinition :
229+
- Description? type Name ImplementsInterfaces? Directives[Const]? FieldsDefinition
230+
- Description? type Name ImplementsInterfaces? Directives[Const]? [lookahead != `{`]
229231

230232
ObjectTypeExtension :
231233
- extend type Name ImplementsInterfaces? Directives[Const]? FieldsDefinition
232-
- extend type Name ImplementsInterfaces? Directives[Const]
233-
- extend type Name ImplementsInterfaces
234+
- extend type Name ImplementsInterfaces? Directives[Const] [lookahead != `{`]
235+
- extend type Name ImplementsInterfaces [lookahead != `{`]
234236

235237
ImplementsInterfaces :
236238
- ImplementsInterfaces & NamedType
@@ -244,11 +246,13 @@ ArgumentsDefinition : ( InputValueDefinition+ )
244246

245247
InputValueDefinition : Description? Name : Type DefaultValue? Directives[Const]?
246248

247-
InterfaceTypeDefinition : Description? interface Name Directives[Const]? FieldsDefinition?
249+
InterfaceTypeDefinition :
250+
- Description? interface Name Directives[Const]? FieldsDefinition
251+
- Description? interface Name Directives[Const]? [lookahead != `{`]
248252

249253
InterfaceTypeExtension :
250254
- extend interface Name Directives[Const]? FieldsDefinition
251-
- extend interface Name Directives[Const]
255+
- extend interface Name Directives[Const] [lookahead != `{`]
252256

253257
UnionTypeDefinition : Description? union Name Directives[Const]? UnionMemberTypes?
254258

@@ -260,23 +264,27 @@ UnionTypeExtension :
260264
- extend union Name Directives[Const]? UnionMemberTypes
261265
- extend union Name Directives[Const]
262266

263-
EnumTypeDefinition : Description? enum Name Directives[Const]? EnumValuesDefinition?
267+
EnumTypeDefinition :
268+
- Description? enum Name Directives[Const]? EnumValuesDefinition
269+
- Description? enum Name Directives[Const]? [lookahead != `{`]
264270

265271
EnumValuesDefinition : { EnumValueDefinition+ }
266272

267273
EnumValueDefinition : Description? EnumValue Directives[Const]?
268274

269275
EnumTypeExtension :
270276
- extend enum Name Directives[Const]? EnumValuesDefinition
271-
- extend enum Name Directives[Const]
277+
- extend enum Name Directives[Const] [lookahead != `{`]
272278

273-
InputObjectTypeDefinition : Description? input Name Directives[Const]? InputFieldsDefinition?
279+
InputObjectTypeDefinition :
280+
- Description? input Name Directives[Const]? InputFieldsDefinition
281+
- Description? input Name Directives[Const]? [lookahead != `{`]
274282

275283
InputFieldsDefinition : { InputValueDefinition+ }
276284

277285
InputObjectTypeExtension :
278286
- extend input Name Directives[Const]? InputFieldsDefinition
279-
- extend input Name Directives[Const]
287+
- extend input Name Directives[Const] [lookahead != `{`]
280288

281289
DirectiveDefinition : Description? directive @ Name ArgumentsDefinition? on DirectiveLocations
282290

spec/Section 3 -- Type System.md

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -154,12 +154,16 @@ type Query {
154154

155155
SchemaExtension :
156156
- extend schema Directives[Const]? { RootOperationTypeDefinition+ }
157-
- extend schema Directives[Const]
157+
- extend schema Directives[Const] [lookahead != `{`]
158158

159159
Schema extensions are used to represent a schema which has been extended from
160160
an original schema. For example, this might be used by a GraphQL service which
161161
adds additional operation types, or additional directives to an existing schema.
162162

163+
Note: Schema extensions without additional operation type definitions must not
164+
be followed by a {`{`} (such as a query shorthand) to avoid parsing ambiguity.
165+
This same limitation applies to the type definitions and extensions below.
166+
163167
**Schema Validation**
164168

165169
Schema extensions have the potential to be invalid if incorrectly defined.
@@ -550,7 +554,9 @@ Scalar type extensions have the potential to be invalid if incorrectly defined.
550554

551555
## Objects
552556

553-
ObjectTypeDefinition : Description? type Name ImplementsInterfaces? Directives[Const]? FieldsDefinition?
557+
ObjectTypeDefinition :
558+
- Description? type Name ImplementsInterfaces? Directives[Const]? FieldsDefinition
559+
- Description? type Name ImplementsInterfaces? Directives[Const]? [lookahead != `{`]
554560

555561
ImplementsInterfaces :
556562
- ImplementsInterfaces & NamedType
@@ -902,8 +908,8 @@ type ExampleType {
902908

903909
ObjectTypeExtension :
904910
- extend type Name ImplementsInterfaces? Directives[Const]? FieldsDefinition
905-
- extend type Name ImplementsInterfaces? Directives[Const]
906-
- extend type Name ImplementsInterfaces
911+
- extend type Name ImplementsInterfaces? Directives[Const] [lookahead != `{`]
912+
- extend type Name ImplementsInterfaces [lookahead != `{`]
907913

908914
Object type extensions are used to represent a type which has been extended from
909915
some original type. For example, this might be used to represent local data, or
@@ -944,7 +950,9 @@ Object type extensions have the potential to be invalid if incorrectly defined.
944950

945951
## Interfaces
946952

947-
InterfaceTypeDefinition : Description? interface Name Directives[Const]? FieldsDefinition?
953+
InterfaceTypeDefinition :
954+
- Description? interface Name Directives[Const]? FieldsDefinition
955+
- Description? interface Name Directives[Const]? [lookahead != `{`]
948956

949957
GraphQL interfaces represent a list of named fields and their arguments. GraphQL
950958
objects can then implement these interfaces which requires that the object type
@@ -1071,7 +1079,7 @@ Interface types have the potential to be invalid if incorrectly defined.
10711079

10721080
InterfaceTypeExtension :
10731081
- extend interface Name Directives[Const]? FieldsDefinition
1074-
- extend interface Name Directives[Const]
1082+
- extend interface Name Directives[Const] [lookahead != `{`]
10751083

10761084
Interface type extensions are used to represent an interface which has been
10771085
extended from some original interface. For example, this might be used to
@@ -1244,7 +1252,9 @@ Union type extensions have the potential to be invalid if incorrectly defined.
12441252

12451253
## Enums
12461254

1247-
EnumTypeDefinition : Description? enum Name Directives[Const]? EnumValuesDefinition?
1255+
EnumTypeDefinition :
1256+
- Description? enum Name Directives[Const]? EnumValuesDefinition
1257+
- Description? enum Name Directives[Const]? [lookahead != `{`]
12481258

12491259
EnumValuesDefinition : { EnumValueDefinition+ }
12501260

@@ -1294,7 +1304,7 @@ Enum types have the potential to be invalid if incorrectly defined.
12941304

12951305
EnumTypeExtension :
12961306
- extend enum Name Directives[Const]? EnumValuesDefinition
1297-
- extend enum Name Directives[Const]
1307+
- extend enum Name Directives[Const] [lookahead != `{`]
12981308

12991309
Enum type extensions are used to represent an enum type which has been
13001310
extended from some original enum type. For example, this might be used to
@@ -1314,7 +1324,9 @@ Enum type extensions have the potential to be invalid if incorrectly defined.
13141324

13151325
## Input Objects
13161326

1317-
InputObjectTypeDefinition : Description? input Name Directives[Const]? InputFieldsDefinition?
1327+
InputObjectTypeDefinition :
1328+
- Description? input Name Directives[Const]? InputFieldsDefinition
1329+
- Description? input Name Directives[Const]? [lookahead != `{`]
13181330

13191331
InputFieldsDefinition : { InputValueDefinition+ }
13201332

@@ -1424,7 +1436,7 @@ Literal Value | Variables | Coerced Value
14241436

14251437
InputObjectTypeExtension :
14261438
- extend input Name Directives[Const]? InputFieldsDefinition
1427-
- extend input Name Directives[Const]
1439+
- extend input Name Directives[Const] [lookahead != `{`]
14281440

14291441
Input object type extensions are used to represent an input object type which
14301442
has been extended from some original input object type. For example, this might

0 commit comments

Comments
 (0)