Skip to content

Commit 020ec1f

Browse files
authored
Fix parser type safety for stricter AST types (#255)
Fixes a number of type-safety issues which would be revealed when we make the AST nodes strictly typed.
1 parent a4b38e2 commit 020ec1f

File tree

1 file changed

+23
-15
lines changed

1 file changed

+23
-15
lines changed

src/graphql/language/parser.py

Lines changed: 23 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,8 @@ def __init__(
269269
def parse_name(self) -> NameNode:
270270
"""Convert a name lex token into a name parse node."""
271271
token = self.expect_token(TokenKind.NAME)
272-
return NameNode(value=token.value, loc=self.loc(token))
272+
# NAME tokens always have a value
273+
return NameNode(value=cast("str", token.value), loc=self.loc(token))
273274

274275
# Implement the parsing rules in the Document section.
275276

@@ -382,9 +383,12 @@ def parse_variable_definitions(self) -> tuple[VariableDefinitionNode, ...]:
382383
def parse_variable_definition(self) -> VariableDefinitionNode:
383384
"""VariableDefinition: Variable: Type DefaultValue? Directives[Const]?"""
384385
start = self._lexer.token
386+
variable = self.parse_variable()
387+
self.expect_token(TokenKind.COLON)
388+
type_ = self.parse_type_reference()
385389
return VariableDefinitionNode(
386-
variable=self.parse_variable(),
387-
type=self.expect_token(TokenKind.COLON) and self.parse_type_reference(),
390+
variable=variable,
391+
type=type_,
388392
default_value=self.parse_const_value_literal()
389393
if self.expect_optional_token(TokenKind.EQUALS)
390394
else None,
@@ -448,25 +452,25 @@ def parse_nullability_assertion(self) -> NullabilityAssertionNode | None:
448452
return None
449453

450454
start = self._lexer.token
451-
nullability_assertion: NullabilityAssertionNode | None = None
455+
list_nullability: ListNullabilityOperatorNode | None = None
452456

453457
if self.expect_optional_token(TokenKind.BRACKET_L):
454458
inner_modifier = self.parse_nullability_assertion()
455459
self.expect_token(TokenKind.BRACKET_R)
456-
nullability_assertion = ListNullabilityOperatorNode(
460+
list_nullability = ListNullabilityOperatorNode(
457461
nullability_assertion=inner_modifier, loc=self.loc(start)
458462
)
459463

460464
if self.expect_optional_token(TokenKind.BANG):
461-
nullability_assertion = NonNullAssertionNode(
462-
nullability_assertion=nullability_assertion, loc=self.loc(start)
465+
return NonNullAssertionNode(
466+
nullability_assertion=list_nullability, loc=self.loc(start)
463467
)
464-
elif self.expect_optional_token(TokenKind.QUESTION_MARK):
465-
nullability_assertion = ErrorBoundaryNode(
466-
nullability_assertion=nullability_assertion, loc=self.loc(start)
468+
if self.expect_optional_token(TokenKind.QUESTION_MARK):
469+
return ErrorBoundaryNode(
470+
nullability_assertion=list_nullability, loc=self.loc(start)
467471
)
468472

469-
return nullability_assertion
473+
return list_nullability
470474

471475
def parse_arguments(self, is_const: bool) -> tuple[ArgumentNode, ...]:
472476
"""Arguments[Const]: (Argument[?Const]+)"""
@@ -573,8 +577,9 @@ def parse_value_literal(self, is_const: bool) -> ValueNode:
573577
def parse_string_literal(self, _is_const: bool = False) -> StringValueNode:
574578
token = self._lexer.token
575579
self.advance_lexer()
580+
# STRING and BLOCK_STRING tokens always have a value
576581
return StringValueNode(
577-
value=token.value,
582+
value=token.value or "",
578583
block=token.kind == TokenKind.BLOCK_STRING,
579584
loc=self.loc(token),
580585
)
@@ -609,16 +614,19 @@ def parse_object(self, is_const: bool) -> ObjectValueNode:
609614
def parse_int(self, _is_const: bool = False) -> IntValueNode:
610615
token = self._lexer.token
611616
self.advance_lexer()
612-
return IntValueNode(value=token.value, loc=self.loc(token))
617+
# INT tokens always have a value
618+
return IntValueNode(value=token.value or "", loc=self.loc(token))
613619

614620
def parse_float(self, _is_const: bool = False) -> FloatValueNode:
615621
token = self._lexer.token
616622
self.advance_lexer()
617-
return FloatValueNode(value=token.value, loc=self.loc(token))
623+
# FLOAT tokens always have a value
624+
return FloatValueNode(value=token.value or "", loc=self.loc(token))
618625

619626
def parse_named_values(self, _is_const: bool = False) -> ValueNode:
620627
token = self._lexer.token
621-
value = token.value
628+
# NAME tokens always have a value
629+
value = token.value or ""
622630
self.advance_lexer()
623631
if value == "true":
624632
return BooleanValueNode(value=True, loc=self.loc(token))

0 commit comments

Comments
 (0)