-
Notifications
You must be signed in to change notification settings - Fork 180
/
Copy pathparser.py
889 lines (677 loc) · 24.4 KB
/
parser.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
from six import string_types
from . import ast
from ..error import GraphQLSyntaxError
from .lexer import Lexer, TokenKind, get_token_desc, get_token_kind_desc
from .source import Source
from ..utils.undefined import Undefined
# Necessary for static type checking
if False: # flake8: noqa
from typing import Dict, Union, Any, Optional, Callable, List
from ..error.syntax_error import GraphQLSyntaxError
from .source import Source
from .lexer import Token
from .ast import (
Document,
Name,
OperationDefinition,
VariableDefinition,
Variable,
SelectionSet,
Field,
FragmentSpread,
Argument,
InlineFragment,
FragmentDefinition,
IntValue,
StringValue,
BooleanValue,
ObjectValue,
ListValue,
ObjectField,
Directive,
NamedType,
NonNullType,
ListType,
SchemaDefinition,
OperationTypeDefinition,
ScalarTypeDefinition,
ObjectTypeDefinition,
FieldDefinition,
InputValueDefinition,
InterfaceTypeDefinition,
UnionTypeDefinition,
EnumTypeDefinition,
EnumValueDefinition,
InputObjectTypeDefinition,
TypeExtensionDefinition,
DirectiveDefinition,
)
__all__ = ["parse"]
def parse(source, **kwargs):
# type: (Union[Source, str], **Any) -> Document
"""Given a GraphQL source, parses it into a Document."""
options = {"no_location": False, "no_source": False}
options.update(kwargs)
if isinstance(source, string_types):
source_obj = Source(source) # type: Source
else:
source_obj = source # type: ignore
parser = Parser(source_obj, options)
return parse_document(parser)
def parse_value(source, **kwargs):
if source is None:
return ast.NullValue()
if source is Undefined:
return ast.UndefinedValue()
options = {"no_location": False, "no_source": False}
options.update(kwargs)
source_obj = source
if isinstance(source, string_types):
source_obj = Source(source)
parser = Parser(source_obj, options)
return parse_value_literal(parser, False)
class Parser(object):
__slots__ = "lexer", "source", "options", "prev_end", "token"
def __init__(self, source, options):
# type: (Source, Dict[str, bool]) -> None
self.lexer = Lexer(source)
self.source = source
self.options = options
self.prev_end = 0
self.token = self.lexer.next_token()
class Loc(object):
__slots__ = "start", "end", "source"
def __init__(self, start, end, source=None):
# type: (int, int, Union[Source, str]) -> None
self.start = start
self.end = end
self.source = source
def __repr__(self):
# type: () -> str
source = " source={}".format(self.source) if self.source else ""
return "<Loc start={} end={}{}>".format(self.start, self.end, source)
def __eq__(self, other):
return (
isinstance(other, Loc)
and self.start == other.start
and self.end == other.end
and self.source == other.source
)
def loc(parser, start):
# type: (Parser, int) -> Optional[Loc]
"""Returns a location object, used to identify the place in
the source that created a given parsed object."""
if parser.options["no_location"]:
return None
if parser.options["no_source"]:
return Loc(start, parser.prev_end)
return Loc(start, parser.prev_end, parser.source)
def advance(parser):
# type: (Parser) -> None
"""Moves the internal parser object to the next lexed token."""
prev_end = parser.token.end
parser.prev_end = prev_end
parser.token = parser.lexer.next_token(prev_end)
def peek(parser, kind):
# type: (Parser, int) -> bool
"""Determines if the next token is of a given kind"""
return parser.token.kind == kind
def skip(parser, kind):
# type: (Parser, int) -> bool
"""If the next token is of the given kind, return true after advancing
the parser. Otherwise, do not change the parser state
and throw an error."""
match = parser.token.kind == kind
if match:
advance(parser)
return match
def expect(parser, kind):
# type: (Parser, int) -> Token
"""If the next token is of the given kind, return that token after
advancing the parser. Otherwise, do not change the parser state and
return False."""
token = parser.token
if token.kind == kind:
advance(parser)
return token
raise GraphQLSyntaxError(
parser.source,
token.start,
u"Expected {}, found {}".format(
get_token_kind_desc(kind), get_token_desc(token)
),
)
def expect_keyword(parser, value):
# type: (Parser, str) -> Token
"""If the next token is a keyword with the given value, return that
token after advancing the parser. Otherwise, do not change the parser
state and return False."""
token = parser.token
if token.kind == TokenKind.NAME and token.value == value:
advance(parser)
return token
raise GraphQLSyntaxError(
parser.source,
token.start,
u'Expected "{}", found {}'.format(value, get_token_desc(token)),
)
def unexpected(parser, at_token=None):
# type: (Parser, Optional[Any]) -> GraphQLSyntaxError
"""Helper function for creating an error when an unexpected lexed token
is encountered."""
token = at_token or parser.token
return GraphQLSyntaxError(
parser.source, token.start, u"Unexpected {}".format(get_token_desc(token))
)
def any(parser, open_kind, parse_fn, close_kind):
# type: (Parser, int, Callable, int) -> Any
"""Returns a possibly empty list of parse nodes, determined by
the parse_fn. This list begins with a lex token of openKind
and ends with a lex token of closeKind. Advances the parser
to the next lex token after the closing token."""
expect(parser, open_kind)
nodes = []
while not skip(parser, close_kind):
nodes.append(parse_fn(parser))
return nodes
def many(parser, open_kind, parse_fn, close_kind):
# type: (Parser, int, Callable, int) -> Any
"""Returns a non-empty list of parse nodes, determined by
the parse_fn. This list begins with a lex token of openKind
and ends with a lex token of closeKind. Advances the parser
to the next lex token after the closing token."""
expect(parser, open_kind)
nodes = [parse_fn(parser)]
while not skip(parser, close_kind):
nodes.append(parse_fn(parser))
return nodes
def parse_name(parser):
# type: (Parser) -> Name
"""Converts a name lex token into a name parse node."""
token = expect(parser, TokenKind.NAME)
return ast.Name(value=token.value, loc=loc(parser, token.start)) # type: ignore
# Implements the parsing rules in the Document section.
def parse_document(parser):
# type: (Parser) -> Document
start = parser.token.start
definitions = []
while True:
definitions.append(parse_definition(parser))
if skip(parser, TokenKind.EOF):
break
return ast.Document(definitions=definitions, loc=loc(parser, start))
def parse_definition(parser):
# type: (Parser) -> Any
if peek(parser, TokenKind.BRACE_L):
return parse_operation_definition(parser)
if peek(parser, TokenKind.NAME):
name = parser.token.value
if name in ("query", "mutation", "subscription"):
return parse_operation_definition(parser)
elif name == "fragment":
return parse_fragment_definition(parser)
elif name in (
"schema",
"scalar",
"type",
"interface",
"union",
"enum",
"input",
"extend",
"directive",
):
return parse_type_system_definition(parser)
raise unexpected(parser)
# Implements the parsing rules in the Operations section.
def parse_operation_definition(parser):
# type: (Parser) -> OperationDefinition
start = parser.token.start
if peek(parser, TokenKind.BRACE_L):
return ast.OperationDefinition(
operation="query",
name=None,
variable_definitions=None,
directives=[],
selection_set=parse_selection_set(parser),
loc=loc(parser, start),
)
operation = parse_operation_type(parser)
name = None
if peek(parser, TokenKind.NAME):
name = parse_name(parser)
return ast.OperationDefinition(
operation=operation,
name=name,
variable_definitions=parse_variable_definitions(parser),
directives=parse_directives(parser),
selection_set=parse_selection_set(parser),
loc=loc(parser, start),
)
def parse_operation_type(parser):
# type: (Parser) -> str
operation_token = expect(parser, TokenKind.NAME)
operation = operation_token.value
if operation == "query":
return "query"
elif operation == "mutation":
return "mutation"
elif operation == "subscription":
return "subscription"
raise unexpected(parser, operation_token)
def parse_variable_definitions(parser):
# type: (Parser) -> List[VariableDefinition]
if peek(parser, TokenKind.PAREN_L):
return many(
parser, TokenKind.PAREN_L, parse_variable_definition, TokenKind.PAREN_R
)
return []
def parse_variable_definition(parser):
# type: (Parser) -> VariableDefinition
start = parser.token.start
return ast.VariableDefinition(
variable=parse_variable(parser),
type=expect(parser, TokenKind.COLON) and parse_type(parser),
default_value=parse_value_literal(parser, True)
if skip(parser, TokenKind.EQUALS)
else Undefined,
loc=loc(parser, start),
)
def parse_variable(parser):
# type: (Parser) -> Variable
start = parser.token.start
expect(parser, TokenKind.DOLLAR)
return ast.Variable(name=parse_name(parser), loc=loc(parser, start))
def parse_selection_set(parser):
# type: (Parser) -> SelectionSet
start = parser.token.start
return ast.SelectionSet(
selections=many(parser, TokenKind.BRACE_L, parse_selection, TokenKind.BRACE_R),
loc=loc(parser, start),
)
def parse_selection(parser):
# type: (Parser) -> Union[Field, FragmentSpread, InlineFragment]
if peek(parser, TokenKind.SPREAD):
return parse_fragment(parser)
else:
return parse_field(parser)
def parse_field(parser):
# type: (Parser) -> Field
# Corresponds to both Field and Alias in the spec
start = parser.token.start
name_or_alias = parse_name(parser)
if skip(parser, TokenKind.COLON):
alias = name_or_alias
name = parse_name(parser)
else:
alias = None # type: ignore
name = name_or_alias
return ast.Field(
alias=alias,
name=name,
arguments=parse_arguments(parser),
directives=parse_directives(parser),
selection_set=parse_selection_set(parser)
if peek(parser, TokenKind.BRACE_L)
else None,
loc=loc(parser, start),
)
def parse_arguments(parser):
# type: (Parser) -> List[Argument]
if peek(parser, TokenKind.PAREN_L):
return many(parser, TokenKind.PAREN_L, parse_argument, TokenKind.PAREN_R)
return []
def parse_argument(parser):
# type: (Parser) -> Argument
start = parser.token.start
return ast.Argument(
name=parse_name(parser),
value=expect(parser, TokenKind.COLON) and parse_value_literal(parser, False),
loc=loc(parser, start),
)
# Implements the parsing rules in the Fragments section.
def parse_fragment(parser):
# type: (Parser) -> Union[FragmentSpread, InlineFragment]
# Corresponds to both FragmentSpread and InlineFragment in the spec
start = parser.token.start
expect(parser, TokenKind.SPREAD)
if peek(parser, TokenKind.NAME) and parser.token.value != "on":
return ast.FragmentSpread(
name=parse_fragment_name(parser),
directives=parse_directives(parser),
loc=loc(parser, start),
)
type_condition = None
if parser.token.value == "on":
advance(parser)
type_condition = parse_named_type(parser)
return ast.InlineFragment(
type_condition=type_condition,
directives=parse_directives(parser),
selection_set=parse_selection_set(parser),
loc=loc(parser, start),
)
def parse_fragment_definition(parser):
# type: (Parser) -> FragmentDefinition
start = parser.token.start
expect_keyword(parser, "fragment")
return ast.FragmentDefinition(
name=parse_fragment_name(parser),
type_condition=parse_named_type(parser)
if expect_keyword(parser, "on")
else None,
directives=parse_directives(parser),
selection_set=parse_selection_set(parser),
loc=loc(parser, start),
)
def parse_fragment_name(parser):
# type: (Parser) -> Name
if parser.token.value == "on":
raise unexpected(parser)
return parse_name(parser)
def parse_value_literal(parser, is_const):
# type: (Parser, bool) -> Any
token = parser.token
if token.kind == TokenKind.BRACKET_L:
return parse_list(parser, is_const)
elif token.kind == TokenKind.BRACE_L:
return parse_object(parser, is_const)
elif token.kind == TokenKind.INT:
advance(parser)
return ast.IntValue( # type: ignore
value=token.value, loc=loc(parser, token.start)
)
elif token.kind == TokenKind.FLOAT:
advance(parser)
return ast.FloatValue( # type: ignore
value=token.value, loc=loc(parser, token.start)
)
elif token.kind == TokenKind.STRING:
advance(parser)
return ast.StringValue( # type: ignore
value=token.value, loc=loc(parser, token.start)
)
elif token.kind == TokenKind.NAME:
advance(parser)
if token.value in ("true", "false"):
return ast.BooleanValue( # type: ignore
value=token.value == "true", loc=loc(parser, token.start)
)
if token.value == "null":
return ast.NullValue(loc=loc(parser, token.start)) # type: ignore
return ast.EnumValue( # type: ignore
value=token.value, loc=loc(parser, token.start)
)
elif token.kind == TokenKind.DOLLAR:
if not is_const:
return parse_variable(parser)
raise unexpected(parser)
# Implements the parsing rules in the Values section.
def parse_variable_value(parser):
# type: (Parser) -> Union[IntValue, StringValue, Variable]
return parse_value_literal(parser, False)
def parse_const_value(parser):
# type: (Parser) -> Union[BooleanValue, ObjectValue, StringValue]
return parse_value_literal(parser, True)
def parse_list(parser, is_const):
# type: (Parser, bool) -> ListValue
start = parser.token.start
item = parse_const_value if is_const else parse_variable_value
return ast.ListValue(
values=any(parser, TokenKind.BRACKET_L, item, TokenKind.BRACKET_R),
loc=loc(parser, start),
)
def parse_object(parser, is_const):
# type: (Parser, bool) -> ObjectValue
start = parser.token.start
expect(parser, TokenKind.BRACE_L)
fields = []
while not skip(parser, TokenKind.BRACE_R):
fields.append(parse_object_field(parser, is_const))
return ast.ObjectValue(fields=fields, loc=loc(parser, start))
def parse_object_field(parser, is_const):
# type: (Parser, bool) -> ObjectField
start = parser.token.start
return ast.ObjectField(
name=parse_name(parser),
value=expect(parser, TokenKind.COLON) and parse_value_literal(parser, is_const),
loc=loc(parser, start),
)
# Implements the parsing rules in the Directives section.
def parse_directives(parser):
# type: (Parser) -> List[Directive]
directives = []
while peek(parser, TokenKind.AT):
directives.append(parse_directive(parser))
return directives
def parse_directive(parser):
# type: (Parser) -> Directive
start = parser.token.start
expect(parser, TokenKind.AT)
return ast.Directive(
name=parse_name(parser),
arguments=parse_arguments(parser),
loc=loc(parser, start),
)
# Implements the parsing rules in the Types section.
def parse_type(parser):
# type: (Parser) -> Union[NamedType, NonNullType, ListType]
"""Handles the 'Type': TypeName, ListType, and NonNullType
parsing rules."""
start = parser.token.start
if skip(parser, TokenKind.BRACKET_L):
ast_type = parse_type(parser)
expect(parser, TokenKind.BRACKET_R)
ast_type = ast.ListType(type=ast_type, loc=loc(parser, start)) # type: ignore
else:
ast_type = parse_named_type(parser)
if skip(parser, TokenKind.BANG):
return ast.NonNullType(type=ast_type, loc=loc(parser, start))
return ast_type
def parse_named_type(parser):
# type: (Parser) -> NamedType
start = parser.token.start
return ast.NamedType(name=parse_name(parser), loc=loc(parser, start))
def parse_type_system_definition(parser):
# type: (Parser) -> Any
"""
TypeSystemDefinition :
- SchemaDefinition
- TypeDefinition
- TypeExtensionDefinition
- DirectiveDefinition
TypeDefinition :
- ScalarTypeDefinition
- ObjectTypeDefinition
- InterfaceTypeDefinition
- UnionTypeDefinition
- EnumTypeDefinition
- InputObjectTypeDefinition
"""
if not peek(parser, TokenKind.NAME):
raise unexpected(parser)
name = parser.token.value
if name == "schema":
return parse_schema_definition(parser)
elif name == "scalar":
return parse_scalar_type_definition(parser)
elif name == "type":
return parse_object_type_definition(parser)
elif name == "interface":
return parse_interface_type_definition(parser)
elif name == "union":
return parse_union_type_definition(parser)
elif name == "enum":
return parse_enum_type_definition(parser)
elif name == "input":
return parse_input_object_type_definition(parser)
elif name == "extend":
return parse_type_extension_definition(parser)
elif name == "directive":
return parse_directive_definition(parser)
raise unexpected(parser)
def parse_schema_definition(parser):
# type: (Parser) -> SchemaDefinition
start = parser.token.start
expect_keyword(parser, "schema")
directives = parse_directives(parser)
operation_types = many(
parser, TokenKind.BRACE_L, parse_operation_type_definition, TokenKind.BRACE_R
)
return ast.SchemaDefinition(
directives=directives, operation_types=operation_types, loc=loc(parser, start)
)
def parse_operation_type_definition(parser):
# type: (Parser) -> OperationTypeDefinition
start = parser.token.start
operation = parse_operation_type(parser)
expect(parser, TokenKind.COLON)
return ast.OperationTypeDefinition(
operation=operation, type=parse_named_type(parser), loc=loc(parser, start)
)
def parse_scalar_type_definition(parser):
# type: (Parser) -> ScalarTypeDefinition
start = parser.token.start
expect_keyword(parser, "scalar")
return ast.ScalarTypeDefinition(
name=parse_name(parser),
directives=parse_directives(parser),
loc=loc(parser, start),
)
def parse_object_type_definition(parser):
# type: (Parser) -> ObjectTypeDefinition
start = parser.token.start
expect_keyword(parser, "type")
return ast.ObjectTypeDefinition(
name=parse_name(parser),
interfaces=parse_implements_interfaces(parser),
directives=parse_directives(parser),
fields=any(
parser, TokenKind.BRACE_L, parse_field_definition, TokenKind.BRACE_R
),
loc=loc(parser, start),
)
def parse_implements_interfaces(parser):
# type: (Parser) -> List[NamedType]
types = []
if parser.token.value == "implements":
advance(parser)
while True:
types.append(parse_named_type(parser))
if not peek(parser, TokenKind.NAME):
break
return types
def parse_field_definition(parser):
# type: (Parser) -> FieldDefinition
start = parser.token.start
return ast.FieldDefinition( # type: ignore
name=parse_name(parser),
arguments=parse_argument_defs(parser),
type=expect(parser, TokenKind.COLON) and parse_type(parser),
directives=parse_directives(parser),
loc=loc(parser, start),
)
def parse_argument_defs(parser):
# type: (Parser) -> List[InputValueDefinition]
if not peek(parser, TokenKind.PAREN_L):
return []
return many(parser, TokenKind.PAREN_L, parse_input_value_def, TokenKind.PAREN_R)
def parse_input_value_def(parser):
# type: (Parser) -> InputValueDefinition
start = parser.token.start
return ast.InputValueDefinition( # type: ignore
name=parse_name(parser),
type=expect(parser, TokenKind.COLON) and parse_type(parser),
default_value=parse_const_value(parser)
if skip(parser, TokenKind.EQUALS)
else Undefined,
directives=parse_directives(parser),
loc=loc(parser, start),
)
def parse_interface_type_definition(parser):
# type: (Parser) -> InterfaceTypeDefinition
start = parser.token.start
expect_keyword(parser, "interface")
return ast.InterfaceTypeDefinition(
name=parse_name(parser),
directives=parse_directives(parser),
fields=any(
parser, TokenKind.BRACE_L, parse_field_definition, TokenKind.BRACE_R
),
loc=loc(parser, start),
)
def parse_union_type_definition(parser):
# type: (Parser) -> UnionTypeDefinition
start = parser.token.start
expect_keyword(parser, "union")
return ast.UnionTypeDefinition( # type: ignore
name=parse_name(parser),
directives=parse_directives(parser),
types=expect(parser, TokenKind.EQUALS) and parse_union_members(parser),
loc=loc(parser, start),
)
def parse_union_members(parser):
# type: (Parser) -> List[NamedType]
members = []
while True:
members.append(parse_named_type(parser))
if not skip(parser, TokenKind.PIPE):
break
return members
def parse_enum_type_definition(parser):
# type: (Parser) -> EnumTypeDefinition
start = parser.token.start
expect_keyword(parser, "enum")
return ast.EnumTypeDefinition(
name=parse_name(parser),
directives=parse_directives(parser),
values=many(
parser, TokenKind.BRACE_L, parse_enum_value_definition, TokenKind.BRACE_R
),
loc=loc(parser, start),
)
def parse_enum_value_definition(parser):
# type: (Parser) -> EnumValueDefinition
start = parser.token.start
return ast.EnumValueDefinition(
name=parse_name(parser),
directives=parse_directives(parser),
loc=loc(parser, start),
)
def parse_input_object_type_definition(parser):
# type: (Parser) -> InputObjectTypeDefinition
start = parser.token.start
expect_keyword(parser, "input")
return ast.InputObjectTypeDefinition(
name=parse_name(parser),
directives=parse_directives(parser),
fields=any(parser, TokenKind.BRACE_L, parse_input_value_def, TokenKind.BRACE_R),
loc=loc(parser, start),
)
def parse_type_extension_definition(parser):
# type: (Parser) -> TypeExtensionDefinition
start = parser.token.start
expect_keyword(parser, "extend")
return ast.TypeExtensionDefinition(
definition=parse_object_type_definition(parser), loc=loc(parser, start)
)
def parse_directive_definition(parser):
# type: (Parser) -> DirectiveDefinition
start = parser.token.start
expect_keyword(parser, "directive")
expect(parser, TokenKind.AT)
name = parse_name(parser)
args = parse_argument_defs(parser)
expect_keyword(parser, "on")
locations = parse_directive_locations(parser)
return ast.DirectiveDefinition(
name=name, locations=locations, arguments=args, loc=loc(parser, start)
)
def parse_directive_locations(parser):
# type: (Parser) -> List[Name]
locations = []
while True:
locations.append(parse_name(parser))
if not skip(parser, TokenKind.PIPE):
break
return locations