Skip to content

Commit 8ad948a

Browse files
committed
parser: generalize parsing of lists with delimiters
Replicates graphql/graphql-js@388cc9a
1 parent f5615b2 commit 8ad948a

File tree

1 file changed

+38
-34
lines changed

1 file changed

+38
-34
lines changed

src/graphql/language/parser.py

Lines changed: 38 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -659,16 +659,10 @@ def parse_object_type_definition(self) -> ObjectTypeDefinitionNode:
659659

660660
def parse_implements_interfaces(self) -> List[NamedTypeNode]:
661661
"""ImplementsInterfaces"""
662-
types: List[NamedTypeNode] = []
663-
if self.expect_optional_keyword("implements"):
664-
# optional leading ampersand
665-
self.expect_optional_token(TokenKind.AMP)
666-
append = types.append
667-
while True:
668-
append(self.parse_named_type())
669-
if not self.expect_optional_token(TokenKind.AMP):
670-
break
671-
return types
662+
if not self.expect_optional_keyword("implements"):
663+
return []
664+
665+
return self.delimited_many(TokenKind.AMP, self.parse_named_type)
672666

673667
def parse_fields_definition(self) -> List[FieldDefinitionNode]:
674668
"""FieldsDefinition: {FieldDefinition+}"""
@@ -758,16 +752,11 @@ def parse_union_type_definition(self) -> UnionTypeDefinitionNode:
758752

759753
def parse_union_member_types(self) -> List[NamedTypeNode]:
760754
"""UnionMemberTypes"""
761-
types: List[NamedTypeNode] = []
762-
if self.expect_optional_token(TokenKind.EQUALS):
763-
# optional leading pipe
764-
self.expect_optional_token(TokenKind.PIPE)
765-
append = types.append
766-
while True:
767-
append(self.parse_named_type())
768-
if not self.expect_optional_token(TokenKind.PIPE):
769-
break
770-
return types
755+
return (
756+
self.delimited_many(TokenKind.PIPE, self.parse_named_type)
757+
if self.expect_optional_token(TokenKind.EQUALS)
758+
else []
759+
)
771760

772761
def parse_enum_type_definition(self) -> EnumTypeDefinitionNode:
773762
"""UnionTypeDefinition"""
@@ -956,15 +945,7 @@ def parse_directive_definition(self) -> DirectiveDefinitionNode:
956945

957946
def parse_directive_locations(self) -> List[NameNode]:
958947
"""DirectiveLocations"""
959-
# optional leading pipe
960-
self.expect_optional_token(TokenKind.PIPE)
961-
locations: List[NameNode] = []
962-
append = locations.append
963-
while True:
964-
append(self.parse_directive_location())
965-
if not self.expect_optional_token(TokenKind.PIPE):
966-
break
967-
return locations
948+
return self.delimited_many(TokenKind.PIPE, self.parse_directive_location)
968949

969950
def parse_directive_location(self) -> NameNode:
970951
"""DirectiveLocation"""
@@ -1070,7 +1051,8 @@ def any(
10701051
self.expect_token(open_kind)
10711052
nodes: List[T] = []
10721053
append = nodes.append
1073-
while not self.expect_optional_token(close_kind):
1054+
expect_optional_token = partial(self.expect_optional_token, close_kind)
1055+
while not expect_optional_token():
10741056
append(parse_fn())
10751057
return nodes
10761058

@@ -1088,7 +1070,8 @@ def optional_many(
10881070
if self.expect_optional_token(open_kind):
10891071
nodes = [parse_fn()]
10901072
append = nodes.append
1091-
while not self.expect_optional_token(close_kind):
1073+
expect_optional_token = partial(self.expect_optional_token, close_kind)
1074+
while not expect_optional_token():
10921075
append(parse_fn())
10931076
return nodes
10941077
return []
@@ -1098,18 +1081,39 @@ def many(
10981081
) -> List[T]:
10991082
"""Fetch matching nodes, at least one.
11001083
1101-
Returns a non-empty list of parse nodes, determined by the ``parse_fn``.
1102-
This list begins with a lex token of ``open_kind`` and ends with a lex token of
1084+
Returns a non-empty list of parse nodes, determined by the ``parse_fn``. This
1085+
list begins with a lex token of ``open_kind`` and ends with a lex token of
11031086
``close_kind``. Advances the parser to the next lex token after the closing
11041087
token.
11051088
"""
11061089
self.expect_token(open_kind)
11071090
nodes = [parse_fn()]
11081091
append = nodes.append
1109-
while not self.expect_optional_token(close_kind):
1092+
expect_optional_token = partial(self.expect_optional_token, close_kind)
1093+
while not expect_optional_token():
11101094
append(parse_fn())
11111095
return nodes
11121096

1097+
def delimited_many(
1098+
self, delimiter_kind: TokenKind, parse_fn: Callable[[], T]
1099+
) -> List[T]:
1100+
"""Fetch many delimited nodes.
1101+
1102+
Returns a non-empty list of parse nodes, determined by the ``parse_fn``. This
1103+
list may begin with a lex token of ``delimiter_kind`` followed by items
1104+
separated by lex tokens of ``delimiter_kind``. Advances the parser to the next
1105+
lex token after the last item in the list.
1106+
"""
1107+
expect_optional_token = partial(self.expect_optional_token, delimiter_kind)
1108+
expect_optional_token()
1109+
nodes: List[T] = []
1110+
append = nodes.append
1111+
while True:
1112+
append(parse_fn())
1113+
if not expect_optional_token():
1114+
break
1115+
return nodes
1116+
11131117

11141118
def get_token_desc(token: Token) -> str:
11151119
"""Describe a token as a string for debugging."""

0 commit comments

Comments
 (0)