1use crate::ast;
24use crate::DefinitionKind;
25use crate::DocumentKind;
26use crate::GraphQLParseError;
27use crate::GraphQLParseErrorKind;
28use crate::GraphQLSourceSpan;
29use crate::GraphQLTokenStream;
30use crate::ParseResult;
31use crate::ReservedNameContext;
32use crate::SourcePosition;
33use crate::ValueParsingError;
34use crate::token::GraphQLToken;
35use crate::token::GraphQLTokenKind;
36use crate::token_source::GraphQLTokenSource;
37use crate::token_source::StrGraphQLTokenSource;
38use smallvec::SmallVec;
39use std::borrow::Cow;
40
41#[derive(Debug, Clone, Copy)]
47enum DelimiterContext {
48 SchemaDefinition,
50 ObjectTypeDefinition,
52 InterfaceDefinition,
54 EnumDefinition,
56 InputObjectDefinition,
58 SelectionSet,
60 FieldArguments,
62 DirectiveArguments,
64 VariableDefinitions,
66 ListType,
68 ListValue,
70 ObjectValue,
72 ArgumentDefinitions,
74}
75
76impl DelimiterContext {
77 fn description(&self) -> &'static str {
79 match self {
80 DelimiterContext::SchemaDefinition => "schema definition",
81 DelimiterContext::ObjectTypeDefinition => "object type definition",
82 DelimiterContext::InterfaceDefinition => "interface definition",
83 DelimiterContext::EnumDefinition => "enum definition",
84 DelimiterContext::InputObjectDefinition => "input object definition",
85 DelimiterContext::SelectionSet => "selection set",
86 DelimiterContext::FieldArguments => "field arguments",
87 DelimiterContext::DirectiveArguments => "directive arguments",
88 DelimiterContext::VariableDefinitions => "variable definitions",
89 DelimiterContext::ListType => "list type annotation",
90 DelimiterContext::ListValue => "list value",
91 DelimiterContext::ObjectValue => "object value",
92 DelimiterContext::ArgumentDefinitions => "argument definitions",
93 }
94 }
95}
96
97#[derive(Debug, Clone)]
99struct OpenDelimiter {
100 span: GraphQLSourceSpan,
102 context: DelimiterContext,
104}
105
106enum RecoveryAction {
108 Stop,
110 Skip,
112 CheckKeyword(String),
114 CheckDescription,
116}
117
118#[derive(Clone, Copy, Debug)]
123enum ConstContext {
124 AllowVariables,
126 VariableDefaultValue,
128 DirectiveArgument,
130 InputDefaultValue,
132}
133
134impl ConstContext {
135 fn description(&self) -> &'static str {
140 match self {
141 ConstContext::AllowVariables => {
142 unreachable!("description() called on AllowVariables")
143 }
144 ConstContext::VariableDefaultValue => "variable default values",
145 ConstContext::DirectiveArgument => "directive arguments",
146 ConstContext::InputDefaultValue => "input field default values",
147 }
148 }
149}
150
151pub struct GraphQLParser<'src, TTokenSource: GraphQLTokenSource<'src>> {
180 token_stream: GraphQLTokenStream<'src, TTokenSource>,
182
183 errors: Vec<GraphQLParseError>,
185
186 delimiter_stack: SmallVec<[OpenDelimiter; 8]>,
191
192 recursion_depth: usize,
201
202 last_end_position: Option<SourcePosition>,
206}
207
208impl<'src> GraphQLParser<'src, StrGraphQLTokenSource<'src>> {
209 pub fn new<S: AsRef<str> + ?Sized>(
225 source: &'src S,
226 ) -> Self {
227 let token_source =
228 StrGraphQLTokenSource::new(source.as_ref());
229 Self::from_token_source(token_source)
230 }
231}
232
233impl<'src, TTokenSource: GraphQLTokenSource<'src>> GraphQLParser<'src, TTokenSource> {
234 const MAX_RECURSION_DEPTH: usize = 64;
243
244 pub fn from_token_source(
246 token_source: TTokenSource,
247 ) -> Self {
248 Self {
249 token_stream: GraphQLTokenStream::new(token_source),
250 errors: Vec::new(),
251 delimiter_stack: SmallVec::new(),
252 recursion_depth: 0,
253 last_end_position: None,
254 }
255 }
256
257 fn record_error(&mut self, error: GraphQLParseError) {
263 self.errors.push(error);
264 }
265
266 fn push_delimiter(
268 &mut self,
269 span: GraphQLSourceSpan,
270 context: DelimiterContext,
271 ) {
272 self.delimiter_stack.push(OpenDelimiter { span, context });
273 }
274
275 fn pop_delimiter(&mut self) -> Option<OpenDelimiter> {
277 self.delimiter_stack.pop()
278 }
279
280 fn recover_to_next_definition(&mut self) {
286 loop {
287 let action = match self.token_stream.peek() {
289 None => RecoveryAction::Stop,
290 Some(token) => match &token.kind {
291 GraphQLTokenKind::Eof => RecoveryAction::Stop,
292 GraphQLTokenKind::CurlyBraceOpen => RecoveryAction::Stop,
293 GraphQLTokenKind::Name(name) => {
294 let name_owned = name.to_string();
295 RecoveryAction::CheckKeyword(name_owned)
296 }
297 GraphQLTokenKind::StringValue(_) => {
298 RecoveryAction::CheckDescription
299 }
300 _ => RecoveryAction::Skip,
301 },
302 };
303
304 match action {
305 RecoveryAction::Stop => break,
306 RecoveryAction::Skip => {
307 self.consume_token();
308 }
309 RecoveryAction::CheckKeyword(keyword) => {
310 if self.looks_like_definition_start(&keyword) {
311 break;
312 }
313 self.consume_token();
314 }
315 RecoveryAction::CheckDescription => {
316 let is_description_for_def =
318 if let Some(next) = self.token_stream.peek_nth(1)
319 && let GraphQLTokenKind::Name(name) = &next.kind {
320 matches!(
321 name.as_ref(),
322 "type"
323 | "interface"
324 | "union"
325 | "enum"
326 | "scalar"
327 | "input"
328 | "directive"
329 | "schema"
330 | "extend"
331 )
332 } else {
333 false
334 };
335 if is_description_for_def {
336 break;
337 }
338 self.consume_token();
339 }
340 }
341 }
342 self.delimiter_stack.clear();
344 }
345
346 fn looks_like_definition_start(&mut self, keyword: &str) -> bool {
352 let next = self.token_stream.peek_nth(1);
353
354 match keyword {
355 "type" | "interface" | "union" | "enum" | "scalar" | "input" => {
358 matches!(
359 next.map(|t| &t.kind),
360 Some(
361 GraphQLTokenKind::Name(_)
362 | GraphQLTokenKind::True
363 | GraphQLTokenKind::False
364 | GraphQLTokenKind::Null
365 )
366 )
367 }
368
369 "directive" => {
371 matches!(next.map(|t| &t.kind), Some(GraphQLTokenKind::At))
372 }
373
374 "schema" => {
376 matches!(
377 next.map(|t| &t.kind),
378 Some(GraphQLTokenKind::CurlyBraceOpen | GraphQLTokenKind::At)
379 )
380 }
381
382 "extend" => {
384 if let Some(next_token) = next {
385 if let GraphQLTokenKind::Name(n) = &next_token.kind {
386 matches!(
387 n.as_ref(),
388 "type"
389 | "interface"
390 | "union"
391 | "enum"
392 | "scalar"
393 | "input"
394 | "schema"
395 )
396 } else {
397 false
398 }
399 } else {
400 false
401 }
402 }
403
404 "query" | "mutation" | "subscription" => {
406 matches!(
407 next.map(|t| &t.kind),
408 Some(
409 GraphQLTokenKind::Name(_)
410 | GraphQLTokenKind::True
411 | GraphQLTokenKind::False
412 | GraphQLTokenKind::Null
413 | GraphQLTokenKind::CurlyBraceOpen
414 | GraphQLTokenKind::ParenOpen
415 | GraphQLTokenKind::At
416 )
417 ) || next.is_none() }
419
420 "fragment" => {
422 if let Some(next_token) = next {
423 if let GraphQLTokenKind::Name(n) = &next_token.kind {
424 n.as_ref() != "on"
426 } else {
427 matches!(
428 &next_token.kind,
429 GraphQLTokenKind::True
430 | GraphQLTokenKind::False
431 | GraphQLTokenKind::Null
432 )
433 }
434 } else {
435 false
436 }
437 }
438
439 _ => false,
440 }
441 }
442
443 fn expect(
452 &mut self,
453 expected_kind: &GraphQLTokenKind,
454 ) -> Result<GraphQLToken<'src>, ()> {
455 let mismatch_info = match self.token_stream.peek() {
460 None => {
461 let span = self.eof_span();
462 self.record_error(GraphQLParseError::new(
463 format!(
464 "expected `{}`",
465 Self::token_kind_display(expected_kind),
466 ),
467 span,
468 GraphQLParseErrorKind::UnexpectedEof {
469 expected: vec![
470 Self::token_kind_display(
471 expected_kind,
472 ),
473 ],
474 },
475 ));
476 return Err(());
477 },
478 Some(token) => {
479 if Self::token_kinds_match(
480 &token.kind,
481 expected_kind,
482 ) {
483 None
484 } else {
485 Some((
486 token.span.clone(),
487 Self::token_kind_display(&token.kind),
488 ))
489 }
490 },
491 };
492 if let Some((span, found)) = mismatch_info {
494 self.record_error(GraphQLParseError::new(
495 format!(
496 "expected `{}`, found `{}`",
497 Self::token_kind_display(expected_kind),
498 found,
499 ),
500 span,
501 GraphQLParseErrorKind::UnexpectedToken {
502 expected: vec![
503 Self::token_kind_display(expected_kind),
504 ],
505 found,
506 },
507 ));
508 Err(())
509 } else {
510 Ok(self.consume_token().unwrap())
511 }
512 }
513
514 fn expect_name(&mut self) -> Result<(Cow<'src, str>, GraphQLSourceSpan), ()> {
525 let span = self
527 .token_stream
528 .peek()
529 .map(|t| t.span.clone())
530 .unwrap_or_else(|| self.eof_span());
531 let name = self.expect_name_only()?;
532 Ok((name, span))
533 }
534
535 fn expect_name_only(
551 &mut self,
552 ) -> Result<Cow<'src, str>, ()> {
553 let mismatch = match self.token_stream.peek() {
554 None => {
555 let span = self.eof_span();
556 self.record_error(GraphQLParseError::new(
557 "expected name",
558 span,
559 GraphQLParseErrorKind::UnexpectedEof {
560 expected: vec!["name".to_string()],
561 },
562 ));
563 return Err(());
564 },
565 Some(token) => match &token.kind {
566 GraphQLTokenKind::Name(_)
567 | GraphQLTokenKind::True
568 | GraphQLTokenKind::False
569 | GraphQLTokenKind::Null => None,
570 _ => Some((
571 token.span.clone(),
572 Self::token_kind_display(&token.kind),
573 )),
574 },
575 };
576 if let Some((span, found)) = mismatch {
577 self.record_error(GraphQLParseError::new(
578 format!("expected name, found `{found}`"),
579 span,
580 GraphQLParseErrorKind::UnexpectedToken {
581 expected: vec!["name".to_string()],
582 found,
583 },
584 ));
585 return Err(());
586 }
587 let token = self.consume_token().unwrap();
588 match token.kind {
589 GraphQLTokenKind::Name(s) => Ok(s),
590 GraphQLTokenKind::True => {
591 Ok(Cow::Borrowed("true"))
592 },
593 GraphQLTokenKind::False => {
594 Ok(Cow::Borrowed("false"))
595 },
596 GraphQLTokenKind::Null => {
597 Ok(Cow::Borrowed("null"))
598 },
599 _ => unreachable!(),
600 }
601 }
602
603 fn expect_keyword(
618 &mut self,
619 keyword: &str,
620 ) -> Result<GraphQLSourceSpan, ()> {
621 let mismatch = match self.token_stream.peek() {
622 None => {
623 let span = self.eof_span();
624 self.record_error(GraphQLParseError::new(
625 format!("expected `{keyword}`"),
626 span,
627 GraphQLParseErrorKind::UnexpectedEof {
628 expected: vec![keyword.to_string()],
629 },
630 ));
631 return Err(());
632 },
633 Some(token) => {
634 if let GraphQLTokenKind::Name(name) = &token.kind
635 && name.as_ref() == keyword {
636 None
637 } else {
638 Some((
639 token.span.clone(),
640 Self::token_kind_display(
641 &token.kind,
642 ),
643 ))
644 }
645 },
646 };
647 if let Some((span, found)) = mismatch {
648 self.record_error(GraphQLParseError::new(
649 format!(
650 "expected `{keyword}`, found `{found}`"
651 ),
652 span,
653 GraphQLParseErrorKind::UnexpectedToken {
654 expected: vec![keyword.to_string()],
655 found,
656 },
657 ));
658 return Err(());
659 }
660 Ok(self.consume_token().unwrap().span)
661 }
662
663 fn peek_is_keyword(&mut self, keyword: &str) -> bool {
678 match self.token_stream.peek() {
679 Some(token) => {
680 if let GraphQLTokenKind::Name(name) = &token.kind {
681 name.as_ref() == keyword
682 } else {
683 false
684 }
685 }
686 None => false,
687 }
688 }
689
690 fn peek_is(&mut self, kind: &GraphQLTokenKind) -> bool {
692 match self.token_stream.peek() {
693 Some(token) => Self::token_kinds_match(&token.kind, kind),
694 None => false,
695 }
696 }
697
698 fn consume_token(
705 &mut self,
706 ) -> Option<GraphQLToken<'src>> {
707 let token = self.token_stream.consume();
708 if let Some(ref t) = token {
709 self.last_end_position =
710 Some(t.span.end_exclusive.clone());
711 }
712 token
713 }
714
715 fn eof_span(&self) -> GraphQLSourceSpan {
718 if let Some(ref pos) = self.last_end_position {
719 GraphQLSourceSpan::new(pos.clone(), pos.clone())
720 } else {
721 let zero = SourcePosition::new(0, 0, Some(0), 0);
722 GraphQLSourceSpan::new(zero.clone(), zero)
723 }
724 }
725
726 fn token_kind_display(kind: &GraphQLTokenKind) -> String {
728 match kind {
729 GraphQLTokenKind::Ampersand => "&".to_string(),
730 GraphQLTokenKind::At => "@".to_string(),
731 GraphQLTokenKind::Bang => "!".to_string(),
732 GraphQLTokenKind::Colon => ":".to_string(),
733 GraphQLTokenKind::CurlyBraceClose => "}".to_string(),
734 GraphQLTokenKind::CurlyBraceOpen => "{".to_string(),
735 GraphQLTokenKind::Dollar => "$".to_string(),
736 GraphQLTokenKind::Ellipsis => "...".to_string(),
737 GraphQLTokenKind::Equals => "=".to_string(),
738 GraphQLTokenKind::ParenClose => ")".to_string(),
739 GraphQLTokenKind::ParenOpen => "(".to_string(),
740 GraphQLTokenKind::Pipe => "|".to_string(),
741 GraphQLTokenKind::SquareBracketClose => "]".to_string(),
742 GraphQLTokenKind::SquareBracketOpen => "[".to_string(),
743 GraphQLTokenKind::Name(s) => s.to_string(),
744 GraphQLTokenKind::IntValue(s) => s.to_string(),
745 GraphQLTokenKind::FloatValue(s) => s.to_string(),
746 GraphQLTokenKind::StringValue(_) => "string".to_string(),
747 GraphQLTokenKind::True => "true".to_string(),
748 GraphQLTokenKind::False => "false".to_string(),
749 GraphQLTokenKind::Null => "null".to_string(),
750 GraphQLTokenKind::Eof => "end of input".to_string(),
751 GraphQLTokenKind::Error { message, .. } => {
752 format!("tokenization error: {message}")
753 }
754 }
755 }
756
757 fn token_kinds_match(
768 actual: &GraphQLTokenKind,
769 expected: &GraphQLTokenKind,
770 ) -> bool {
771 match actual {
772 GraphQLTokenKind::Name(_) => matches!(expected, GraphQLTokenKind::Name(_)),
776 GraphQLTokenKind::IntValue(_) => {
777 matches!(expected, GraphQLTokenKind::IntValue(_))
778 }
779 GraphQLTokenKind::FloatValue(_) => {
780 matches!(expected, GraphQLTokenKind::FloatValue(_))
781 }
782 GraphQLTokenKind::StringValue(_) => {
783 matches!(expected, GraphQLTokenKind::StringValue(_))
784 }
785 GraphQLTokenKind::Error { .. } => {
786 matches!(expected, GraphQLTokenKind::Error { .. })
787 }
788 GraphQLTokenKind::Ampersand => actual == expected,
790 GraphQLTokenKind::At => actual == expected,
791 GraphQLTokenKind::Bang => actual == expected,
792 GraphQLTokenKind::Colon => actual == expected,
793 GraphQLTokenKind::CurlyBraceClose => actual == expected,
794 GraphQLTokenKind::CurlyBraceOpen => actual == expected,
795 GraphQLTokenKind::Dollar => actual == expected,
796 GraphQLTokenKind::Ellipsis => actual == expected,
797 GraphQLTokenKind::Equals => actual == expected,
798 GraphQLTokenKind::ParenClose => actual == expected,
799 GraphQLTokenKind::ParenOpen => actual == expected,
800 GraphQLTokenKind::Pipe => actual == expected,
801 GraphQLTokenKind::SquareBracketClose => actual == expected,
802 GraphQLTokenKind::SquareBracketOpen => actual == expected,
803 GraphQLTokenKind::True => actual == expected,
804 GraphQLTokenKind::False => actual == expected,
805 GraphQLTokenKind::Null => actual == expected,
806 GraphQLTokenKind::Eof => actual == expected,
807 }
808 }
809
810 fn handle_lexer_error(&mut self, token: &GraphQLToken<'src>) {
812 if let GraphQLTokenKind::Error {
813 message,
814 error_notes,
815 } = &token.kind {
816 self.record_error(GraphQLParseError::from_lexer_error(
817 message.clone(),
818 token.span.clone(),
819 error_notes.clone(),
820 ));
821 }
822 }
823
824 fn enter_recursion(&mut self) -> Result<(), ()> {
833 self.recursion_depth += 1;
834 if self.recursion_depth > Self::MAX_RECURSION_DEPTH {
835 let span = self
836 .token_stream.peek()
837 .map(|t| t.span.clone())
838 .unwrap_or_else(|| self.eof_span());
839 self.consume_token();
840 self.record_error(GraphQLParseError::new(
841 "maximum nesting depth exceeded",
842 span,
843 GraphQLParseErrorKind::InvalidSyntax,
844 ));
845 self.recursion_depth -= 1;
846 return Err(());
847 }
848 Ok(())
849 }
850
851 fn exit_recursion(&mut self) {
853 self.recursion_depth -= 1;
854 }
855
856 fn parse_value(
861 &mut self,
862 context: ConstContext,
863 ) -> Result<ast::Value, ()> {
864 self.enter_recursion()?;
865 let result = self.parse_value_impl(context);
866 self.exit_recursion();
867 result
868 }
869
870 fn parse_value_impl(
872 &mut self,
873 context: ConstContext,
874 ) -> Result<ast::Value, ()> {
875 match self.token_stream.peek() {
876 None => {
877 let span = self.eof_span();
878 self.record_error(GraphQLParseError::new(
879 "expected value",
880 span,
881 GraphQLParseErrorKind::UnexpectedEof {
882 expected: vec!["value".to_string()],
883 },
884 ));
885 Err(())
886 }
887 Some(token) => {
888 let span = token.span.clone();
889 match &token.kind {
890 GraphQLTokenKind::Dollar => {
892 if !matches!(context, ConstContext::AllowVariables) {
893 self.consume_token();
894 self.record_error(GraphQLParseError::new(
895 format!(
896 "variables are not allowed in {}",
897 context.description()
898 ),
899 span,
900 GraphQLParseErrorKind::InvalidSyntax,
901 ));
902 return Err(());
903 }
904 self.consume_token(); let name = self.expect_name_only()?;
906 Ok(ast::Value::Variable(name.into_owned()))
907 }
908
909 GraphQLTokenKind::IntValue(raw) => {
911 let parse_result = token.kind.parse_int_value();
913 match parse_result {
914 Some(Ok(val)) => {
915 if val > i32::MAX as i64 || val < i32::MIN as i64 {
917 let raw_str = raw.clone().into_owned();
919 self.consume_token();
920 self.record_error(GraphQLParseError::new(
921 format!(
922 "integer `{raw_str}` overflows 32-bit integer"
923 ),
924 span,
925 GraphQLParseErrorKind::InvalidValue(
926 ValueParsingError::Int(raw_str),
927 ),
928 ));
929 Err(())
930 } else {
931 self.consume_token();
932 Ok(ast::Value::Int(ast::Number::from(val as i32)))
933 }
934 }
935 Some(Err(_)) => {
936 let raw_str = raw.clone().into_owned();
938 self.consume_token();
939 self.record_error(GraphQLParseError::new(
940 format!("invalid integer `{raw_str}`"),
941 span,
942 GraphQLParseErrorKind::InvalidValue(
943 ValueParsingError::Int(raw_str),
944 ),
945 ));
946 Err(())
947 }
948 None => unreachable!(
949 "parse_int_value returned None for IntValue token"
950 ),
951 }
952 }
953
954 GraphQLTokenKind::FloatValue(raw) => {
956 let parse_result = token.kind.parse_float_value();
958 match parse_result {
959 Some(Ok(val)) => {
960 if val.is_infinite() || val.is_nan() {
961 let raw_str = raw.clone().into_owned();
963 self.consume_token();
964 self.record_error(GraphQLParseError::new(
965 format!(
966 "float `{raw_str}` is not a finite number"
967 ),
968 span,
969 GraphQLParseErrorKind::InvalidValue(
970 ValueParsingError::Float(raw_str),
971 ),
972 ));
973 Err(())
974 } else {
975 self.consume_token();
976 Ok(ast::Value::Float(val))
977 }
978 }
979 Some(Err(_)) => {
980 let raw_str = raw.clone().into_owned();
982 self.consume_token();
983 self.record_error(GraphQLParseError::new(
984 format!("invalid float `{raw_str}`"),
985 span,
986 GraphQLParseErrorKind::InvalidValue(
987 ValueParsingError::Float(raw_str),
988 ),
989 ));
990 Err(())
991 }
992 None => unreachable!(
993 "parse_float_value returned None for FloatValue token"
994 ),
995 }
996 }
997
998 GraphQLTokenKind::StringValue(_) => {
1000 let token_clone = token.clone();
1002 self.consume_token();
1003 match token_clone.kind.parse_string_value() {
1004 Some(Ok(parsed)) => Ok(ast::Value::String(parsed)),
1005 Some(Err(e)) => {
1006 self.record_error(GraphQLParseError::new(
1007 format!("invalid string: {e}"),
1008 span,
1009 GraphQLParseErrorKind::InvalidValue(
1010 ValueParsingError::String(e),
1011 ),
1012 ));
1013 Err(())
1014 }
1015 None => {
1016 self.record_error(GraphQLParseError::new(
1018 "invalid string",
1019 span,
1020 GraphQLParseErrorKind::InvalidSyntax,
1021 ));
1022 Err(())
1023 }
1024 }
1025 }
1026
1027 GraphQLTokenKind::True => {
1029 self.consume_token();
1030 Ok(ast::Value::Boolean(true))
1031 }
1032 GraphQLTokenKind::False => {
1033 self.consume_token();
1034 Ok(ast::Value::Boolean(false))
1035 }
1036
1037 GraphQLTokenKind::Null => {
1039 self.consume_token();
1040 Ok(ast::Value::Null)
1041 }
1042
1043 GraphQLTokenKind::SquareBracketOpen => self.parse_list_value(context),
1045
1046 GraphQLTokenKind::CurlyBraceOpen => self.parse_object_value(context),
1048
1049 GraphQLTokenKind::Name(name) => {
1051 let enum_value = name.to_string();
1052 self.consume_token();
1053 Ok(ast::Value::Enum(enum_value))
1054 }
1055
1056 GraphQLTokenKind::Error { .. } => {
1058 let token = token.clone();
1062 self.handle_lexer_error(&token);
1063 self.consume_token();
1064 Err(())
1065 }
1066
1067 _ => {
1069 let found = Self::token_kind_display(&token.kind);
1070 self.record_error(GraphQLParseError::new(
1071 format!("expected value, found `{found}`"),
1072 span,
1073 GraphQLParseErrorKind::UnexpectedToken {
1074 expected: vec!["value".to_string()],
1075 found,
1076 },
1077 ));
1078 Err(())
1079 }
1080 }
1081 }
1082 }
1083 }
1084
1085 fn parse_list_value(&mut self, context: ConstContext) -> Result<ast::Value, ()> {
1087 let open_token = self.expect(&GraphQLTokenKind::SquareBracketOpen)?;
1088 self.push_delimiter(open_token.span.clone(), DelimiterContext::ListValue);
1089
1090 let mut values = Vec::new();
1091
1092 loop {
1093 if self.peek_is(&GraphQLTokenKind::SquareBracketClose) {
1094 break;
1095 }
1096 if self.token_stream.is_at_end() {
1097 let span = self.eof_span();
1098 let open_delim = self.pop_delimiter();
1099 let mut error = GraphQLParseError::new(
1100 "unclosed `[`",
1101 span,
1102 GraphQLParseErrorKind::UnclosedDelimiter {
1103 delimiter: "[".to_string(),
1104 },
1105 );
1106 if let Some(delim) = open_delim {
1107 error.add_note_with_span("opening `[` here", delim.span);
1108 }
1109 self.record_error(error);
1110 return Err(());
1111 }
1112
1113 match self.parse_value(context) {
1114 Ok(value) => values.push(value),
1115 Err(()) => {
1116 self.skip_to_list_recovery_point();
1118 if self.peek_is(&GraphQLTokenKind::SquareBracketClose) {
1119 break;
1120 }
1121 }
1122 }
1123 }
1124
1125 self.expect(&GraphQLTokenKind::SquareBracketClose)?;
1126 self.pop_delimiter();
1127
1128 Ok(ast::Value::List(values))
1129 }
1130
1131 fn parse_object_value(&mut self, context: ConstContext) -> Result<ast::Value, ()> {
1133 let open_token = self.expect(&GraphQLTokenKind::CurlyBraceOpen)?;
1134 self.push_delimiter(open_token.span.clone(), DelimiterContext::ObjectValue);
1135
1136 let mut fields = Vec::new();
1137
1138 loop {
1139 if self.peek_is(&GraphQLTokenKind::CurlyBraceClose) {
1140 break;
1141 }
1142 if self.token_stream.is_at_end() {
1143 let span = self.eof_span();
1144 let open_delim = self.pop_delimiter();
1145 let mut error = GraphQLParseError::new(
1146 "unclosed `{`",
1147 span,
1148 GraphQLParseErrorKind::UnclosedDelimiter {
1149 delimiter: "{".to_string(),
1150 },
1151 );
1152 if let Some(delim) = open_delim {
1153 error.add_note_with_span(
1154 format!(
1155 "opening `{{` in {} here",
1156 delim.context.description()
1157 ),
1158 delim.span,
1159 );
1160 }
1161 self.record_error(error);
1162 return Err(());
1163 }
1164
1165 let field_name = self.expect_name_only()?;
1167 self.expect(&GraphQLTokenKind::Colon)?;
1168 let value = self.parse_value(context)?;
1169
1170 fields.push((field_name.into_owned(), value));
1171 }
1172
1173 self.expect(&GraphQLTokenKind::CurlyBraceClose)?;
1174 self.pop_delimiter();
1175
1176 Ok(ast::Value::Object(fields.into_iter().collect()))
1177 }
1178
1179 fn skip_to_list_recovery_point(&mut self) {
1189 loop {
1190 match self.token_stream.peek() {
1191 None => break,
1192 Some(token) => match &token.kind {
1193 GraphQLTokenKind::SquareBracketClose | GraphQLTokenKind::Eof => break,
1195 GraphQLTokenKind::Dollar
1197 | GraphQLTokenKind::IntValue(_)
1198 | GraphQLTokenKind::FloatValue(_)
1199 | GraphQLTokenKind::StringValue(_)
1200 | GraphQLTokenKind::True
1201 | GraphQLTokenKind::False
1202 | GraphQLTokenKind::Null
1203 | GraphQLTokenKind::SquareBracketOpen
1204 | GraphQLTokenKind::CurlyBraceOpen
1205 | GraphQLTokenKind::Name(_) => break,
1206 GraphQLTokenKind::Ampersand
1208 | GraphQLTokenKind::At
1209 | GraphQLTokenKind::Bang
1210 | GraphQLTokenKind::Colon
1211 | GraphQLTokenKind::CurlyBraceClose
1212 | GraphQLTokenKind::Ellipsis
1213 | GraphQLTokenKind::Equals
1214 | GraphQLTokenKind::ParenClose
1215 | GraphQLTokenKind::ParenOpen
1216 | GraphQLTokenKind::Pipe
1217 | GraphQLTokenKind::Error { .. } => {
1218 self.consume_token();
1219 }
1220 },
1221 }
1222 }
1223 }
1224
1225 fn parse_executable_type_annotation(
1232 &mut self,
1233 ) -> Result<ast::operation::Type, ()> {
1234 self.enter_recursion()?;
1235 let result = self.parse_executable_type_annotation_impl();
1236 self.exit_recursion();
1237 result
1238 }
1239
1240 fn parse_executable_type_annotation_impl(
1242 &mut self,
1243 ) -> Result<ast::operation::Type, ()> {
1244 let base_type = if self.peek_is(&GraphQLTokenKind::SquareBracketOpen) {
1245 self.parse_executable_list_type()?
1247 } else {
1248 self.parse_executable_named_type()?
1250 };
1251
1252 if self.peek_is(&GraphQLTokenKind::Bang) {
1254 self.consume_token();
1255 Ok(ast::operation::Type::NonNullType(Box::new(base_type)))
1256 } else {
1257 Ok(base_type)
1258 }
1259 }
1260
1261 fn parse_executable_named_type(&mut self) -> Result<ast::operation::Type, ()> {
1263 let name = self.expect_name_only()?;
1264 Ok(ast::operation::Type::NamedType(name.into_owned()))
1265 }
1266
1267 fn parse_executable_list_type(&mut self) -> Result<ast::operation::Type, ()> {
1269 let open_token = self.expect(&GraphQLTokenKind::SquareBracketOpen)?;
1270 self.push_delimiter(open_token.span.clone(), DelimiterContext::ListType);
1271
1272 let inner = self.parse_executable_type_annotation()?;
1273
1274 self.expect(&GraphQLTokenKind::SquareBracketClose)?;
1275 self.pop_delimiter();
1276
1277 Ok(ast::operation::Type::ListType(Box::new(inner)))
1278 }
1279
1280 fn parse_directive_annotations(
1286 &mut self,
1287 ) -> Result<Vec<ast::operation::Directive>, ()> {
1288 let mut directives = Vec::new();
1289 while self.peek_is(&GraphQLTokenKind::At) {
1290 directives.push(self.parse_directive_annotation()?);
1291 }
1292 Ok(directives)
1293 }
1294
1295 fn parse_directive_annotation(&mut self) -> Result<ast::operation::Directive, ()> {
1297 let position = self
1302 .expect(&GraphQLTokenKind::At)?
1303 .span
1304 .start_inclusive
1305 .to_ast_pos();
1306 let name = self.expect_name_only()?;
1307
1308 let arguments = if self.peek_is(&GraphQLTokenKind::ParenOpen) {
1309 self.parse_arguments(DelimiterContext::DirectiveArguments)?
1310 } else {
1311 Vec::new()
1312 };
1313
1314 Ok(ast::operation::Directive {
1315 position,
1316 name: name.into_owned(),
1317 arguments,
1318 })
1319 }
1320
1321 fn parse_const_directive_annotations(
1324 &mut self,
1325 ) -> Result<Vec<ast::operation::Directive>, ()> {
1326 let mut directives = Vec::new();
1327 while self.peek_is(&GraphQLTokenKind::At) {
1328 directives.push(self.parse_const_directive_annotation()?);
1329 }
1330 Ok(directives)
1331 }
1332
1333 fn parse_const_directive_annotation(
1335 &mut self,
1336 ) -> Result<ast::operation::Directive, ()> {
1337 let position = self
1342 .expect(&GraphQLTokenKind::At)?
1343 .span
1344 .start_inclusive
1345 .to_ast_pos();
1346 let name = self.expect_name_only()?;
1347
1348 let arguments = if self.peek_is(&GraphQLTokenKind::ParenOpen) {
1349 self.parse_const_arguments(DelimiterContext::DirectiveArguments)?
1350 } else {
1351 Vec::new()
1352 };
1353
1354 Ok(ast::operation::Directive {
1355 position,
1356 name: name.into_owned(),
1357 arguments,
1358 })
1359 }
1360
1361 fn parse_arguments(
1367 &mut self,
1368 context: DelimiterContext,
1369 ) -> Result<Vec<(String, ast::Value)>, ()> {
1370 let open_token = self.expect(&GraphQLTokenKind::ParenOpen)?;
1371 self.push_delimiter(open_token.span.clone(), context);
1372
1373 let mut arguments = Vec::new();
1374
1375 if self.peek_is(&GraphQLTokenKind::ParenClose) {
1377 let span = open_token.span.clone();
1378 self.record_error(GraphQLParseError::new(
1379 "argument list cannot be empty; omit the parentheses instead",
1380 span,
1381 GraphQLParseErrorKind::InvalidEmptyConstruct {
1382 construct: "argument list".to_string(),
1383 },
1384 ));
1385 }
1386
1387 loop {
1388 if self.peek_is(&GraphQLTokenKind::ParenClose) {
1389 break;
1390 }
1391 if self.token_stream.is_at_end() {
1392 self.handle_unclosed_paren();
1393 return Err(());
1394 }
1395
1396 let arg_name = self.expect_name_only()?;
1397 self.expect(&GraphQLTokenKind::Colon)?;
1398 let value = self.parse_value(ConstContext::AllowVariables)?;
1399
1400 arguments.push((arg_name.into_owned(), value));
1401 }
1402
1403 self.expect(&GraphQLTokenKind::ParenClose)?;
1404 self.pop_delimiter();
1405
1406 Ok(arguments)
1407 }
1408
1409 fn parse_const_arguments(
1411 &mut self,
1412 context: DelimiterContext,
1413 ) -> Result<Vec<(String, ast::Value)>, ()> {
1414 let open_token = self.expect(&GraphQLTokenKind::ParenOpen)?;
1415 self.push_delimiter(open_token.span.clone(), context);
1416
1417 let mut arguments = Vec::new();
1418
1419 if self.peek_is(&GraphQLTokenKind::ParenClose) {
1420 let span = open_token.span.clone();
1421 self.record_error(GraphQLParseError::new(
1422 "argument list cannot be empty; omit the parentheses instead",
1423 span,
1424 GraphQLParseErrorKind::InvalidEmptyConstruct {
1425 construct: "argument list".to_string(),
1426 },
1427 ));
1428 }
1429
1430 loop {
1431 if self.peek_is(&GraphQLTokenKind::ParenClose) {
1432 break;
1433 }
1434 if self.token_stream.is_at_end() {
1435 self.handle_unclosed_paren();
1436 return Err(());
1437 }
1438
1439 let arg_name = self.expect_name_only()?;
1440 self.expect(&GraphQLTokenKind::Colon)?;
1441 let value = self.parse_value(ConstContext::DirectiveArgument)?;
1442
1443 arguments.push((arg_name.into_owned(), value));
1444 }
1445
1446 self.expect(&GraphQLTokenKind::ParenClose)?;
1447 self.pop_delimiter();
1448
1449 Ok(arguments)
1450 }
1451
1452 fn handle_unclosed_paren(&mut self) {
1454 let span = self.eof_span();
1455 let open_delim = self.pop_delimiter();
1456 let mut error = GraphQLParseError::new(
1457 "unclosed `(`",
1458 span,
1459 GraphQLParseErrorKind::UnclosedDelimiter {
1460 delimiter: "(".to_string(),
1461 },
1462 );
1463 if let Some(delim) = open_delim {
1464 error.add_note_with_span(
1465 format!("opening `(` in {} here", delim.context.description()),
1466 delim.span,
1467 );
1468 }
1469 self.record_error(error);
1470 }
1471
1472 fn parse_selection_set(
1478 &mut self,
1479 ) -> Result<ast::operation::SelectionSet, ()> {
1480 self.enter_recursion()?;
1481 let result = self.parse_selection_set_impl();
1482 self.exit_recursion();
1483 result
1484 }
1485
1486 fn parse_selection_set_impl(
1488 &mut self,
1489 ) -> Result<ast::operation::SelectionSet, ()> {
1490 let open_token = self.expect(&GraphQLTokenKind::CurlyBraceOpen)?;
1491 let open_pos = open_token.span.start_inclusive.to_ast_pos();
1495 self.push_delimiter(open_token.span.clone(), DelimiterContext::SelectionSet);
1496
1497 let mut selections = Vec::new();
1498
1499 if self.peek_is(&GraphQLTokenKind::CurlyBraceClose) {
1501 let span = open_token.span.clone();
1502 self.record_error(GraphQLParseError::new(
1503 "selection set cannot be empty",
1504 span,
1505 GraphQLParseErrorKind::InvalidEmptyConstruct {
1506 construct: "selection set".to_string(),
1507 },
1508 ));
1509 }
1510
1511 loop {
1512 if self.peek_is(&GraphQLTokenKind::CurlyBraceClose) {
1513 break;
1514 }
1515 if self.token_stream.is_at_end() {
1516 self.handle_unclosed_brace();
1517 return Err(());
1518 }
1519
1520 match self.parse_selection() {
1521 Ok(selection) => selections.push(selection),
1522 Err(()) => {
1523 self.skip_to_selection_recovery_point();
1525 }
1526 }
1527 }
1528
1529 let close_token = self.expect(&GraphQLTokenKind::CurlyBraceClose)?;
1532 let close_pos = close_token.span.start_inclusive.to_ast_pos();
1533 self.pop_delimiter();
1534
1535 Ok(ast::operation::SelectionSet {
1536 span: (open_pos, close_pos),
1537 items: selections,
1538 })
1539 }
1540
1541 fn parse_selection(&mut self) -> Result<ast::operation::Selection, ()> {
1543 if self.peek_is(&GraphQLTokenKind::Ellipsis) {
1544 let ellipsis_pos = self
1549 .expect(&GraphQLTokenKind::Ellipsis)?
1550 .span
1551 .start_inclusive
1552 .to_ast_pos();
1553
1554 if self.peek_is_keyword("on")
1555 || self.peek_is(&GraphQLTokenKind::At)
1556 || self.peek_is(&GraphQLTokenKind::CurlyBraceOpen) {
1557 self.parse_inline_fragment(ellipsis_pos)
1562 } else {
1563 self.parse_fragment_spread(ellipsis_pos)
1568 }
1569 } else {
1570 self.parse_field().map(ast::operation::Selection::Field)
1572 }
1573 }
1574
1575 fn parse_field(&mut self) -> Result<ast::operation::Field, ()> {
1577 let (first_name, first_span) = self.expect_name()?;
1585 let position = first_span.start_inclusive.to_ast_pos();
1586
1587 let (alias, name) = if self.peek_is(&GraphQLTokenKind::Colon) {
1589 self.consume_token();
1590 let field_name = self.expect_name_only()?;
1591 (Some(first_name), field_name)
1592 } else {
1593 (None, first_name)
1594 };
1595
1596 let arguments = if self.peek_is(&GraphQLTokenKind::ParenOpen) {
1598 self.parse_arguments(DelimiterContext::FieldArguments)?
1599 } else {
1600 Vec::new()
1601 };
1602
1603 let directives = self.parse_directive_annotations()?;
1605
1606 let selection_set = if self.peek_is(&GraphQLTokenKind::CurlyBraceOpen) {
1608 self.parse_selection_set()?
1609 } else {
1610 ast::operation::SelectionSet {
1615 span: (position, position),
1616 items: Vec::new(),
1617 }
1618 };
1619
1620 Ok(ast::operation::Field {
1621 position,
1622 alias: alias.map(|a| a.into_owned()),
1623 name: name.into_owned(),
1624 arguments,
1625 directives,
1626 selection_set,
1627 })
1628 }
1629
1630 fn parse_fragment_spread(
1639 &mut self,
1640 position: ast::AstPos,
1641 ) -> Result<ast::operation::Selection, ()> {
1642 let fragment_name = self.expect_name_only()?;
1643 let directives = self.parse_directive_annotations()?;
1644
1645 Ok(ast::operation::Selection::FragmentSpread(
1646 ast::operation::FragmentSpread {
1647 position,
1648 fragment_name: fragment_name.into_owned(),
1649 directives,
1650 },
1651 ))
1652 }
1653
1654 fn parse_inline_fragment(
1663 &mut self,
1664 position: ast::AstPos,
1665 ) -> Result<ast::operation::Selection, ()> {
1666 let type_condition = if self.peek_is_keyword("on") {
1668 self.consume_token(); let type_name = self.expect_name_only()?;
1670 Some(ast::operation::TypeCondition::On(type_name.into_owned()))
1671 } else {
1672 None
1673 };
1674
1675 let directives = self.parse_directive_annotations()?;
1676 let selection_set = self.parse_selection_set()?;
1677
1678 Ok(ast::operation::Selection::InlineFragment(
1679 ast::operation::InlineFragment {
1680 position,
1681 type_condition,
1682 directives,
1683 selection_set,
1684 },
1685 ))
1686 }
1687
1688 fn skip_to_selection_recovery_point(&mut self) {
1690 loop {
1691 match self.token_stream.peek() {
1692 None => break,
1693 Some(token) => match &token.kind {
1694 GraphQLTokenKind::CurlyBraceClose | GraphQLTokenKind::Eof => break,
1695 GraphQLTokenKind::Ellipsis | GraphQLTokenKind::Name(_) => break,
1697 GraphQLTokenKind::True
1699 | GraphQLTokenKind::False
1700 | GraphQLTokenKind::Null => break,
1701 _ => {
1702 self.consume_token();
1703 }
1704 },
1705 }
1706 }
1707 }
1708
1709 fn handle_unclosed_brace(&mut self) {
1711 let span = self.eof_span();
1712 let open_delim = self.pop_delimiter();
1713 let mut error = GraphQLParseError::new(
1714 "unclosed `{`",
1715 span,
1716 GraphQLParseErrorKind::UnclosedDelimiter {
1717 delimiter: "{".to_string(),
1718 },
1719 );
1720 if let Some(delim) = open_delim {
1721 error.add_note_with_span(
1722 format!(
1723 "opening `{{` in {} here",
1724 delim.context.description()
1725 ),
1726 delim.span,
1727 );
1728 }
1729 self.record_error(error);
1730 }
1731
1732 fn parse_operation_definition(
1738 &mut self,
1739 ) -> Result<ast::operation::OperationDefinition, ()> {
1740 if self.peek_is(&GraphQLTokenKind::CurlyBraceOpen) {
1742 let selection_set = self.parse_selection_set()?;
1743 return Ok(ast::operation::OperationDefinition::SelectionSet(
1744 selection_set,
1745 ));
1746 }
1747
1748 let (op_type, position) = if self.peek_is_keyword("query") {
1754 (
1755 "query",
1756 self.expect_keyword("query")?.start_inclusive.to_ast_pos(),
1757 )
1758 } else if self.peek_is_keyword("mutation") {
1759 (
1760 "mutation",
1761 self.expect_keyword("mutation")?
1762 .start_inclusive
1763 .to_ast_pos(),
1764 )
1765 } else if self.peek_is_keyword("subscription") {
1766 (
1767 "subscription",
1768 self.expect_keyword("subscription")?
1769 .start_inclusive
1770 .to_ast_pos(),
1771 )
1772 } else {
1773 let span = self
1774 .token_stream.peek()
1775 .map(|t| t.span.clone())
1776 .unwrap_or_else(|| self.eof_span());
1777 let found = self
1778 .token_stream.peek()
1779 .map(|t| Self::token_kind_display(&t.kind))
1780 .unwrap_or_else(|| "end of input".to_string());
1781 self.record_error(GraphQLParseError::new(
1782 format!(
1783 "expected operation type (`query`, `mutation`, or \
1784 `subscription`), found `{found}`"
1785 ),
1786 span,
1787 GraphQLParseErrorKind::UnexpectedToken {
1788 expected: vec![
1789 "query".to_string(),
1790 "mutation".to_string(),
1791 "subscription".to_string(),
1792 ],
1793 found,
1794 },
1795 ));
1796 return Err(());
1797 };
1798
1799 let name = if !self.peek_is(&GraphQLTokenKind::ParenOpen)
1801 && !self.peek_is(&GraphQLTokenKind::At)
1802 && !self.peek_is(&GraphQLTokenKind::CurlyBraceOpen) {
1803 if let Some(token) = self.token_stream.peek() {
1804 match &token.kind {
1805 GraphQLTokenKind::Name(_)
1806 | GraphQLTokenKind::True
1807 | GraphQLTokenKind::False
1808 | GraphQLTokenKind::Null => {
1809 let n = self.expect_name_only()?;
1810 Some(n)
1811 }
1812 _ => None,
1813 }
1814 } else {
1815 None
1816 }
1817 } else {
1818 None
1819 };
1820
1821 let variable_definitions = if self.peek_is(&GraphQLTokenKind::ParenOpen) {
1823 self.parse_variable_definitions()?
1824 } else {
1825 Vec::new()
1826 };
1827
1828 let directives = self.parse_directive_annotations()?;
1830
1831 let selection_set = self.parse_selection_set()?;
1833
1834 let name = name.map(|n| n.into_owned());
1836 match op_type {
1837 "query" => Ok(ast::operation::OperationDefinition::Query(
1838 ast::operation::Query {
1839 position,
1840 name,
1841 variable_definitions,
1842 directives,
1843 selection_set,
1844 },
1845 )),
1846 "mutation" => Ok(ast::operation::OperationDefinition::Mutation(
1847 ast::operation::Mutation {
1848 position,
1849 name,
1850 variable_definitions,
1851 directives,
1852 selection_set,
1853 },
1854 )),
1855 "subscription" => Ok(ast::operation::OperationDefinition::Subscription(
1856 ast::operation::Subscription {
1857 position,
1858 name,
1859 variable_definitions,
1860 directives,
1861 selection_set,
1862 },
1863 )),
1864 _ => unreachable!(),
1865 }
1866 }
1867
1868 fn parse_variable_definitions(
1870 &mut self,
1871 ) -> Result<Vec<ast::operation::VariableDefinition>, ()> {
1872 let open_token = self.expect(&GraphQLTokenKind::ParenOpen)?;
1873 self.push_delimiter(
1874 open_token.span.clone(),
1875 DelimiterContext::VariableDefinitions,
1876 );
1877
1878 let mut definitions = Vec::new();
1879
1880 if self.peek_is(&GraphQLTokenKind::ParenClose) {
1881 let span = open_token.span.clone();
1882 self.record_error(GraphQLParseError::new(
1883 "variable definitions cannot be empty; omit the parentheses \
1884 instead",
1885 span,
1886 GraphQLParseErrorKind::InvalidEmptyConstruct {
1887 construct: "variable definitions".to_string(),
1888 },
1889 ));
1890 }
1891
1892 loop {
1893 if self.peek_is(&GraphQLTokenKind::ParenClose) {
1894 break;
1895 }
1896 if self.token_stream.is_at_end() {
1897 self.handle_unclosed_paren();
1898 return Err(());
1899 }
1900
1901 definitions.push(self.parse_variable_definition()?);
1902 }
1903
1904 self.expect(&GraphQLTokenKind::ParenClose)?;
1905 self.pop_delimiter();
1906
1907 Ok(definitions)
1908 }
1909
1910 fn parse_variable_definition(
1912 &mut self,
1913 ) -> Result<ast::operation::VariableDefinition, ()> {
1914 let position = self
1919 .expect(&GraphQLTokenKind::Dollar)?
1920 .span
1921 .start_inclusive
1922 .to_ast_pos();
1923 let name = self.expect_name_only()?;
1924 self.expect(&GraphQLTokenKind::Colon)?;
1925 let var_type = self.parse_executable_type_annotation()?;
1926
1927 let default_value = if self.peek_is(&GraphQLTokenKind::Equals) {
1929 self.consume_token();
1930 Some(self.parse_value(ConstContext::VariableDefaultValue)?)
1931 } else {
1932 None
1933 };
1934
1935 let _directives = self.parse_const_directive_annotations()?;
1939
1940 Ok(ast::operation::VariableDefinition {
1941 position,
1942 name: name.into_owned(),
1943 var_type,
1944 default_value,
1945 })
1946 }
1947
1948 fn parse_fragment_definition(
1955 &mut self,
1956 ) -> Result<ast::operation::FragmentDefinition, ()> {
1957 let position = self
1962 .expect_keyword("fragment")?
1963 .start_inclusive
1964 .to_ast_pos();
1965
1966 let (name, name_span) = self.expect_name()?;
1968 if name == "on" {
1969 let mut error = GraphQLParseError::new(
1971 "fragment name cannot be `on`",
1972 name_span.clone(),
1973 GraphQLParseErrorKind::ReservedName {
1974 name: "on".to_string(),
1975 context: ReservedNameContext::FragmentName,
1976 },
1977 );
1978 error.add_spec(
1979 "https://spec.graphql.org/October2021/#sec-Fragment-Name-Uniqueness",
1980 );
1981 self.record_error(error);
1982 }
1983
1984 let type_condition = self.parse_type_condition()?;
1986
1987 let directives = self.parse_directive_annotations()?;
1989
1990 let selection_set = self.parse_selection_set()?;
1992
1993 Ok(ast::operation::FragmentDefinition {
1994 position,
1995 name: name.into_owned(),
1996 type_condition,
1997 directives,
1998 selection_set,
1999 })
2000 }
2001
2002 fn parse_type_condition(&mut self) -> Result<ast::operation::TypeCondition, ()> {
2004 self.expect_keyword("on")?;
2005 let type_name = self.expect_name_only()?;
2006 Ok(ast::operation::TypeCondition::On(type_name.into_owned()))
2007 }
2008
2009 fn parse_description(&mut self) -> Option<String> {
2015 if let Some(token) = self.token_stream.peek()
2016 && matches!(&token.kind, GraphQLTokenKind::StringValue(_)) {
2017 let token = self.consume_token().unwrap();
2018 match token.kind.parse_string_value() {
2019 Some(Ok(parsed)) => return Some(parsed),
2020 Some(Err(err)) => {
2021 self.record_error(GraphQLParseError::new(
2022 format!(
2023 "invalid string in description: {err}"
2024 ),
2025 token.span,
2026 GraphQLParseErrorKind::InvalidSyntax,
2027 ));
2028 },
2029 None => unreachable!(),
2030 }
2031 }
2032 None
2033 }
2034
2035 fn parse_schema_definition(&mut self) -> Result<ast::schema::SchemaDefinition, ()> {
2037 let position = self
2042 .expect_keyword("schema")?
2043 .start_inclusive
2044 .to_ast_pos();
2045
2046 let directives = self.parse_const_directive_annotations()?;
2047
2048 let open_token = self.expect(&GraphQLTokenKind::CurlyBraceOpen)?;
2049 self.push_delimiter(
2050 open_token.span.clone(),
2051 DelimiterContext::SchemaDefinition,
2052 );
2053
2054 let mut query = None;
2055 let mut mutation = None;
2056 let mut subscription = None;
2057
2058 loop {
2059 if self.peek_is(&GraphQLTokenKind::CurlyBraceClose) {
2060 break;
2061 }
2062 if self.token_stream.is_at_end() {
2063 self.handle_unclosed_brace();
2064 return Err(());
2065 }
2066
2067 let (operation_type, operation_type_span) =
2068 self.expect_name()?;
2069 self.expect(&GraphQLTokenKind::Colon)?;
2070 let type_name = self.expect_name_only()?;
2071
2072 match &*operation_type {
2073 "query" => query = Some(type_name.into_owned()),
2074 "mutation" => {
2075 mutation = Some(type_name.into_owned())
2076 },
2077 "subscription" => {
2078 subscription = Some(type_name.into_owned())
2079 },
2080 _ => {
2081 self.record_error(GraphQLParseError::new(
2082 format!(
2083 "unknown operation type \
2084 `{operation_type}`; expected \
2085 `query`, `mutation`, or \
2086 `subscription`"
2087 ),
2088 operation_type_span,
2089 GraphQLParseErrorKind::InvalidSyntax,
2090 ));
2091 }
2092 }
2093 }
2094
2095 self.expect(&GraphQLTokenKind::CurlyBraceClose)?;
2096 self.pop_delimiter();
2097
2098 let schema_directives = self.convert_directives_to_schema(directives);
2100
2101 Ok(ast::schema::SchemaDefinition {
2102 position,
2103 directives: schema_directives,
2104 query,
2105 mutation,
2106 subscription,
2107 })
2108 }
2109
2110 fn parse_scalar_type_definition(
2112 &mut self,
2113 description: Option<String>,
2114 ) -> Result<ast::schema::TypeDefinition, ()> {
2115 let position = self.expect_keyword("scalar")?.start_inclusive.to_ast_pos();
2120 let name = self.expect_name_only()?;
2121 let directives = self.parse_const_directive_annotations()?;
2122
2123 let schema_directives = self.convert_directives_to_schema(directives);
2124
2125 Ok(ast::schema::TypeDefinition::Scalar(ast::schema::ScalarType {
2126 position,
2127 description,
2128 name: name.into_owned(),
2129 directives: schema_directives,
2130 }))
2131 }
2132
2133 fn parse_object_type_definition(
2136 &mut self,
2137 description: Option<String>,
2138 ) -> Result<ast::schema::TypeDefinition, ()> {
2139 let position = self.expect_keyword("type")?.start_inclusive.to_ast_pos();
2144 let name = self.expect_name_only()?;
2145
2146 let implements_interfaces = if self.peek_is_keyword("implements") {
2147 self.parse_implements_interfaces()?
2148 } else {
2149 Vec::new()
2150 };
2151
2152 let directives = self.parse_const_directive_annotations()?;
2153 let schema_directives = self.convert_directives_to_schema(directives);
2154
2155 let fields = if self.peek_is(&GraphQLTokenKind::CurlyBraceOpen) {
2156 self.parse_fields_definition(DelimiterContext::ObjectTypeDefinition)?
2157 } else {
2158 Vec::new()
2159 };
2160
2161 Ok(ast::schema::TypeDefinition::Object(ast::schema::ObjectType {
2162 position,
2163 description,
2164 name: name.into_owned(),
2165 implements_interfaces,
2166 directives: schema_directives,
2167 fields,
2168 }))
2169 }
2170
2171 fn parse_interface_type_definition(
2173 &mut self,
2174 description: Option<String>,
2175 ) -> Result<ast::schema::TypeDefinition, ()> {
2176 let position = self
2181 .expect_keyword("interface")?
2182 .start_inclusive
2183 .to_ast_pos();
2184 let name = self.expect_name_only()?;
2185
2186 let implements_interfaces = if self.peek_is_keyword("implements") {
2187 self.parse_implements_interfaces()?
2188 } else {
2189 Vec::new()
2190 };
2191
2192 let directives = self.parse_const_directive_annotations()?;
2193 let schema_directives = self.convert_directives_to_schema(directives);
2194
2195 let fields = if self.peek_is(&GraphQLTokenKind::CurlyBraceOpen) {
2196 self.parse_fields_definition(DelimiterContext::InterfaceDefinition)?
2197 } else {
2198 Vec::new()
2199 };
2200
2201 Ok(ast::schema::TypeDefinition::Interface(
2202 ast::schema::InterfaceType {
2203 position,
2204 description,
2205 name: name.into_owned(),
2206 implements_interfaces,
2207 directives: schema_directives,
2208 fields,
2209 },
2210 ))
2211 }
2212
2213 fn parse_union_type_definition(
2215 &mut self,
2216 description: Option<String>,
2217 ) -> Result<ast::schema::TypeDefinition, ()> {
2218 let position = self.expect_keyword("union")?.start_inclusive.to_ast_pos();
2223 let name = self.expect_name_only()?;
2224
2225 let directives = self.parse_const_directive_annotations()?;
2226 let schema_directives = self.convert_directives_to_schema(directives);
2227
2228 let mut types = Vec::new();
2229 if self.peek_is(&GraphQLTokenKind::Equals) {
2230 self.consume_token();
2231
2232 if self.peek_is(&GraphQLTokenKind::Pipe) {
2234 self.consume_token();
2235 }
2236
2237 let first_type = self.expect_name_only()?;
2238 types.push(first_type.into_owned());
2239
2240 while self.peek_is(&GraphQLTokenKind::Pipe) {
2241 self.consume_token();
2242 let member_type = self.expect_name_only()?;
2243 types.push(member_type.into_owned());
2244 }
2245 }
2246
2247 Ok(ast::schema::TypeDefinition::Union(ast::schema::UnionType {
2248 position,
2249 description,
2250 name: name.into_owned(),
2251 directives: schema_directives,
2252 types,
2253 }))
2254 }
2255
2256 fn parse_enum_type_definition(
2258 &mut self,
2259 description: Option<String>,
2260 ) -> Result<ast::schema::TypeDefinition, ()> {
2261 let position = self.expect_keyword("enum")?.start_inclusive.to_ast_pos();
2266 let name = self.expect_name_only()?;
2267
2268 let directives = self.parse_const_directive_annotations()?;
2269 let schema_directives = self.convert_directives_to_schema(directives);
2270
2271 let values = if self.peek_is(&GraphQLTokenKind::CurlyBraceOpen) {
2272 self.parse_enum_values_definition()?
2273 } else {
2274 Vec::new()
2275 };
2276
2277 Ok(ast::schema::TypeDefinition::Enum(ast::schema::EnumType {
2278 position,
2279 description,
2280 name: name.into_owned(),
2281 directives: schema_directives,
2282 values,
2283 }))
2284 }
2285
2286 fn parse_input_object_type_definition(
2288 &mut self,
2289 description: Option<String>,
2290 ) -> Result<ast::schema::TypeDefinition, ()> {
2291 let position = self.expect_keyword("input")?.start_inclusive.to_ast_pos();
2296 let name = self.expect_name_only()?;
2297
2298 let directives = self.parse_const_directive_annotations()?;
2299 let schema_directives = self.convert_directives_to_schema(directives);
2300
2301 let fields = if self.peek_is(&GraphQLTokenKind::CurlyBraceOpen) {
2302 self.parse_input_fields_definition()?
2303 } else {
2304 Vec::new()
2305 };
2306
2307 Ok(ast::schema::TypeDefinition::InputObject(
2308 ast::schema::InputObjectType {
2309 position,
2310 description,
2311 name: name.into_owned(),
2312 directives: schema_directives,
2313 fields,
2314 },
2315 ))
2316 }
2317
2318 fn parse_directive_definition(
2320 &mut self,
2321 description: Option<String>,
2322 ) -> Result<ast::schema::DirectiveDefinition, ()> {
2323 let position = self
2328 .expect_keyword("directive")?
2329 .start_inclusive
2330 .to_ast_pos();
2331 self.expect(&GraphQLTokenKind::At)?;
2332 let name = self.expect_name_only()?;
2333
2334 let arguments = if self.peek_is(&GraphQLTokenKind::ParenOpen) {
2335 self.parse_arguments_definition()?
2336 } else {
2337 Vec::new()
2338 };
2339
2340 let repeatable = if self.peek_is_keyword("repeatable") {
2341 self.consume_token();
2342 true
2343 } else {
2344 false
2345 };
2346
2347 self.expect_keyword("on")?;
2348
2349 let locations = self.parse_directive_locations()?;
2351
2352 Ok(ast::schema::DirectiveDefinition {
2353 position,
2354 description,
2355 name: name.into_owned(),
2356 arguments,
2357 repeatable,
2358 locations,
2359 })
2360 }
2361
2362 fn parse_implements_interfaces(&mut self) -> Result<Vec<String>, ()> {
2364 self.expect_keyword("implements")?;
2365
2366 if self.peek_is(&GraphQLTokenKind::Ampersand) {
2368 self.consume_token();
2369 }
2370
2371 let mut interfaces = Vec::new();
2372 let first = self.expect_name_only()?;
2373 interfaces.push(first.into_owned());
2374
2375 while self.peek_is(&GraphQLTokenKind::Ampersand) {
2376 self.consume_token();
2377 let iface = self.expect_name_only()?;
2378 interfaces.push(iface.into_owned());
2379 }
2380
2381 Ok(interfaces)
2382 }
2383
2384 fn parse_fields_definition(
2386 &mut self,
2387 context: DelimiterContext,
2388 ) -> Result<Vec<ast::schema::Field>, ()> {
2389 let open_token = self.expect(&GraphQLTokenKind::CurlyBraceOpen)?;
2390 self.push_delimiter(open_token.span.clone(), context);
2391
2392 let mut fields = Vec::new();
2393
2394 loop {
2395 if self.peek_is(&GraphQLTokenKind::CurlyBraceClose) {
2396 break;
2397 }
2398 if self.token_stream.is_at_end() {
2399 self.handle_unclosed_brace();
2400 return Err(());
2401 }
2402
2403 fields.push(self.parse_field_definition()?);
2404 }
2405
2406 self.expect(&GraphQLTokenKind::CurlyBraceClose)?;
2407 self.pop_delimiter();
2408
2409 Ok(fields)
2410 }
2411
2412 fn parse_field_definition(&mut self) -> Result<ast::schema::Field, ()> {
2414 let description = self.parse_description();
2415 let (name, name_span) = self.expect_name()?;
2422 let position = name_span.start_inclusive.to_ast_pos();
2423
2424 let arguments = if self.peek_is(&GraphQLTokenKind::ParenOpen) {
2425 self.parse_arguments_definition()?
2426 } else {
2427 Vec::new()
2428 };
2429
2430 self.expect(&GraphQLTokenKind::Colon)?;
2431 let field_type = self.parse_schema_type_annotation()?;
2432
2433 let directives = self.parse_const_directive_annotations()?;
2434 let schema_directives = self.convert_directives_to_schema(directives);
2435
2436 Ok(ast::schema::Field {
2437 position,
2438 description,
2439 name: name.into_owned(),
2440 arguments,
2441 field_type,
2442 directives: schema_directives,
2443 })
2444 }
2445
2446 fn parse_arguments_definition(&mut self) -> Result<Vec<ast::schema::InputValue>, ()> {
2448 let open_token = self.expect(&GraphQLTokenKind::ParenOpen)?;
2449 self.push_delimiter(
2450 open_token.span.clone(),
2451 DelimiterContext::ArgumentDefinitions,
2452 );
2453
2454 let mut arguments = Vec::new();
2455
2456 loop {
2457 if self.peek_is(&GraphQLTokenKind::ParenClose) {
2458 break;
2459 }
2460 if self.token_stream.is_at_end() {
2461 self.handle_unclosed_paren();
2462 return Err(());
2463 }
2464
2465 arguments.push(self.parse_input_value_definition()?);
2466 }
2467
2468 self.expect(&GraphQLTokenKind::ParenClose)?;
2469 self.pop_delimiter();
2470
2471 Ok(arguments)
2472 }
2473
2474 fn parse_input_fields_definition(
2476 &mut self,
2477 ) -> Result<Vec<ast::schema::InputValue>, ()> {
2478 let open_token = self.expect(&GraphQLTokenKind::CurlyBraceOpen)?;
2479 self.push_delimiter(
2480 open_token.span.clone(),
2481 DelimiterContext::InputObjectDefinition,
2482 );
2483
2484 let mut fields = Vec::new();
2485
2486 loop {
2487 if self.peek_is(&GraphQLTokenKind::CurlyBraceClose) {
2488 break;
2489 }
2490 if self.token_stream.is_at_end() {
2491 self.handle_unclosed_brace();
2492 return Err(());
2493 }
2494
2495 fields.push(self.parse_input_value_definition()?);
2496 }
2497
2498 self.expect(&GraphQLTokenKind::CurlyBraceClose)?;
2499 self.pop_delimiter();
2500
2501 Ok(fields)
2502 }
2503
2504 fn parse_input_value_definition(&mut self) -> Result<ast::schema::InputValue, ()> {
2506 let description = self.parse_description();
2507 let (name, name_span) = self.expect_name()?;
2514 let position = name_span.start_inclusive.to_ast_pos();
2515 self.expect(&GraphQLTokenKind::Colon)?;
2516 let value_type = self.parse_schema_type_annotation()?;
2517
2518 let default_value = if self.peek_is(&GraphQLTokenKind::Equals) {
2519 self.consume_token();
2520 Some(self.parse_value(ConstContext::InputDefaultValue)?)
2521 } else {
2522 None
2523 };
2524
2525 let directives = self.parse_const_directive_annotations()?;
2526 let schema_directives = self.convert_directives_to_schema(directives);
2527
2528 Ok(ast::schema::InputValue {
2529 position,
2530 description,
2531 name: name.into_owned(),
2532 value_type,
2533 default_value,
2534 directives: schema_directives,
2535 })
2536 }
2537
2538 fn parse_enum_values_definition(
2540 &mut self,
2541 ) -> Result<Vec<ast::schema::EnumValue>, ()> {
2542 let open_token = self.expect(&GraphQLTokenKind::CurlyBraceOpen)?;
2543 self.push_delimiter(
2544 open_token.span.clone(),
2545 DelimiterContext::EnumDefinition,
2546 );
2547
2548 let mut values = Vec::new();
2549
2550 loop {
2551 if self.peek_is(&GraphQLTokenKind::CurlyBraceClose) {
2552 break;
2553 }
2554 if self.token_stream.is_at_end() {
2555 self.handle_unclosed_brace();
2556 return Err(());
2557 }
2558
2559 values.push(self.parse_enum_value_definition()?);
2560 }
2561
2562 self.expect(&GraphQLTokenKind::CurlyBraceClose)?;
2563 self.pop_delimiter();
2564
2565 Ok(values)
2566 }
2567
2568 fn parse_enum_value_definition(&mut self) -> Result<ast::schema::EnumValue, ()> {
2570 let description = self.parse_description();
2571
2572 let (name, name_span) = self.expect_name()?;
2578 let position = name_span.start_inclusive.to_ast_pos();
2579 if matches!(&*name, "true" | "false" | "null") {
2580 let mut error = GraphQLParseError::new(
2581 format!("enum value cannot be `{name}`"),
2582 name_span,
2583 GraphQLParseErrorKind::ReservedName {
2584 name: name.clone().into_owned(),
2585 context: ReservedNameContext::EnumValue,
2586 },
2587 );
2588 error.add_spec(
2589 "https://spec.graphql.org/October2021/#sec-Enum-Value-Uniqueness",
2590 );
2591 self.record_error(error);
2592 }
2594
2595 let directives = self.parse_const_directive_annotations()?;
2596 let schema_directives = self.convert_directives_to_schema(directives);
2597
2598 Ok(ast::schema::EnumValue {
2599 position,
2600 description,
2601 name: name.into_owned(),
2602 directives: schema_directives,
2603 })
2604 }
2605
2606 fn parse_directive_locations(
2608 &mut self,
2609 ) -> Result<Vec<ast::schema::DirectiveLocation>, ()> {
2610 if self.peek_is(&GraphQLTokenKind::Pipe) {
2612 self.consume_token();
2613 }
2614
2615 let mut locations = Vec::new();
2616 locations.push(self.parse_directive_location()?);
2617
2618 while self.peek_is(&GraphQLTokenKind::Pipe) {
2619 self.consume_token();
2620 locations.push(self.parse_directive_location()?);
2621 }
2622
2623 Ok(locations)
2624 }
2625
2626 fn parse_directive_location(
2628 &mut self,
2629 ) -> Result<ast::schema::DirectiveLocation, ()> {
2630 let (name, span) = self.expect_name()?;
2631
2632 match &*name {
2634 "QUERY" => Ok(ast::schema::DirectiveLocation::Query),
2636 "MUTATION" => Ok(ast::schema::DirectiveLocation::Mutation),
2637 "SUBSCRIPTION" => Ok(ast::schema::DirectiveLocation::Subscription),
2638 "FIELD" => Ok(ast::schema::DirectiveLocation::Field),
2639 "FRAGMENT_DEFINITION" => {
2640 Ok(ast::schema::DirectiveLocation::FragmentDefinition)
2641 }
2642 "FRAGMENT_SPREAD" => Ok(ast::schema::DirectiveLocation::FragmentSpread),
2643 "INLINE_FRAGMENT" => Ok(ast::schema::DirectiveLocation::InlineFragment),
2644 "VARIABLE_DEFINITION" => {
2645 Ok(ast::schema::DirectiveLocation::VariableDefinition)
2646 }
2647
2648 "SCHEMA" => Ok(ast::schema::DirectiveLocation::Schema),
2650 "SCALAR" => Ok(ast::schema::DirectiveLocation::Scalar),
2651 "OBJECT" => Ok(ast::schema::DirectiveLocation::Object),
2652 "FIELD_DEFINITION" => Ok(ast::schema::DirectiveLocation::FieldDefinition),
2653 "ARGUMENT_DEFINITION" => {
2654 Ok(ast::schema::DirectiveLocation::ArgumentDefinition)
2655 }
2656 "INTERFACE" => Ok(ast::schema::DirectiveLocation::Interface),
2657 "UNION" => Ok(ast::schema::DirectiveLocation::Union),
2658 "ENUM" => Ok(ast::schema::DirectiveLocation::Enum),
2659 "ENUM_VALUE" => Ok(ast::schema::DirectiveLocation::EnumValue),
2660 "INPUT_OBJECT" => Ok(ast::schema::DirectiveLocation::InputObject),
2661 "INPUT_FIELD_DEFINITION" => {
2662 Ok(ast::schema::DirectiveLocation::InputFieldDefinition)
2663 }
2664
2665 _ => {
2666 let mut error = GraphQLParseError::new(
2668 format!("unknown directive location `{name}`"),
2669 span,
2670 GraphQLParseErrorKind::InvalidSyntax,
2671 );
2672
2673 if let Some(suggestion) = Self::suggest_directive_location(&name) {
2674 error.add_help(format!("did you mean `{suggestion}`?"));
2675 }
2676
2677 self.record_error(error);
2678 Err(())
2679 }
2680 }
2681 }
2682
2683 fn suggest_directive_location(input: &str) -> Option<&'static str> {
2685 const LOCATIONS: &[&str] = &[
2686 "QUERY",
2687 "MUTATION",
2688 "SUBSCRIPTION",
2689 "FIELD",
2690 "FRAGMENT_DEFINITION",
2691 "FRAGMENT_SPREAD",
2692 "INLINE_FRAGMENT",
2693 "VARIABLE_DEFINITION",
2694 "SCHEMA",
2695 "SCALAR",
2696 "OBJECT",
2697 "FIELD_DEFINITION",
2698 "ARGUMENT_DEFINITION",
2699 "INTERFACE",
2700 "UNION",
2701 "ENUM",
2702 "ENUM_VALUE",
2703 "INPUT_OBJECT",
2704 "INPUT_FIELD_DEFINITION",
2705 ];
2706
2707 let input_upper = input.to_uppercase();
2709 let mut best_match: Option<&'static str> = None;
2710 let mut best_distance = usize::MAX;
2711
2712 for &location in LOCATIONS {
2713 let distance = Self::edit_distance(&input_upper, location);
2714 if distance < best_distance && distance <= 3 {
2715 best_distance = distance;
2716 best_match = Some(location);
2717 }
2718 }
2719
2720 best_match
2721 }
2722
2723 fn edit_distance(a: &str, b: &str) -> usize {
2725 let a_chars: Vec<char> = a.chars().collect();
2726 let b_chars: Vec<char> = b.chars().collect();
2727 let m = a_chars.len();
2728 let n = b_chars.len();
2729
2730 if m == 0 {
2731 return n;
2732 }
2733 if n == 0 {
2734 return m;
2735 }
2736
2737 let mut prev: Vec<usize> = (0..=n).collect();
2738 let mut curr = vec![0; n + 1];
2739
2740 for i in 1..=m {
2741 curr[0] = i;
2742 for j in 1..=n {
2743 let cost = if a_chars[i - 1] == b_chars[j - 1] {
2744 0
2745 } else {
2746 1
2747 };
2748 curr[j] = (prev[j] + 1)
2749 .min(curr[j - 1] + 1)
2750 .min(prev[j - 1] + cost);
2751 }
2752 std::mem::swap(&mut prev, &mut curr);
2753 }
2754
2755 prev[n]
2756 }
2757
2758 fn parse_schema_type_annotation(
2760 &mut self,
2761 ) -> Result<ast::schema::Type, ()> {
2762 self.enter_recursion()?;
2763 let result = self.parse_schema_type_annotation_impl();
2764 self.exit_recursion();
2765 result
2766 }
2767
2768 fn parse_schema_type_annotation_impl(
2770 &mut self,
2771 ) -> Result<ast::schema::Type, ()> {
2772 let base_type = if self.peek_is(&GraphQLTokenKind::SquareBracketOpen) {
2773 self.parse_schema_list_type()?
2774 } else {
2775 let name = self.expect_name_only()?;
2776 ast::schema::Type::NamedType(name.into_owned())
2777 };
2778
2779 if self.peek_is(&GraphQLTokenKind::Bang) {
2780 self.consume_token();
2781 Ok(ast::schema::Type::NonNullType(Box::new(base_type)))
2782 } else {
2783 Ok(base_type)
2784 }
2785 }
2786
2787 fn parse_schema_list_type(&mut self) -> Result<ast::schema::Type, ()> {
2789 let open_token = self.expect(&GraphQLTokenKind::SquareBracketOpen)?;
2790 self.push_delimiter(open_token.span.clone(), DelimiterContext::ListType);
2791
2792 let inner = self.parse_schema_type_annotation()?;
2793
2794 self.expect(&GraphQLTokenKind::SquareBracketClose)?;
2795 self.pop_delimiter();
2796
2797 Ok(ast::schema::Type::ListType(Box::new(inner)))
2798 }
2799
2800 fn convert_directives_to_schema(
2802 &self,
2803 directives: Vec<ast::operation::Directive>,
2804 ) -> Vec<ast::schema::Directive> {
2805 directives
2806 .into_iter()
2807 .map(|d| ast::schema::Directive {
2808 position: d.position,
2809 name: d.name,
2810 arguments: d.arguments,
2811 })
2812 .collect()
2813 }
2814
2815 fn parse_type_extension(&mut self) -> Result<ast::schema::TypeExtension, ()> {
2825 let extend_pos = self
2829 .expect_keyword("extend")?
2830 .start_inclusive
2831 .to_ast_pos();
2832
2833 if self.peek_is_keyword("schema") {
2834 self.skip_schema_extension()?;
2838 Err(())
2839 } else if self.peek_is_keyword("scalar") {
2840 self.parse_scalar_type_extension(extend_pos)
2844 } else if self.peek_is_keyword("type") {
2845 self.parse_object_type_extension(extend_pos)
2846 } else if self.peek_is_keyword("interface") {
2847 self.parse_interface_type_extension(extend_pos)
2848 } else if self.peek_is_keyword("union") {
2849 self.parse_union_type_extension(extend_pos)
2850 } else if self.peek_is_keyword("enum") {
2851 self.parse_enum_type_extension(extend_pos)
2852 } else if self.peek_is_keyword("input") {
2853 self.parse_input_object_type_extension(extend_pos)
2854 } else {
2855 let span = self
2856 .token_stream.peek()
2857 .map(|t| t.span.clone())
2858 .unwrap_or_else(|| self.eof_span());
2859 let found = self
2860 .token_stream.peek()
2861 .map(|t| Self::token_kind_display(&t.kind))
2862 .unwrap_or_else(|| "end of input".to_string());
2863 self.record_error(GraphQLParseError::new(
2864 format!(
2865 "expected type extension keyword (`schema`, `scalar`, `type`, \
2866 `interface`, `union`, `enum`, `input`), found `{found}`"
2867 ),
2868 span,
2869 GraphQLParseErrorKind::UnexpectedToken {
2870 expected: vec![
2871 "schema".to_string(),
2872 "scalar".to_string(),
2873 "type".to_string(),
2874 "interface".to_string(),
2875 "union".to_string(),
2876 "enum".to_string(),
2877 "input".to_string(),
2878 ],
2879 found,
2880 },
2881 ));
2882 Err(())
2883 }
2884 }
2885
2886 fn skip_schema_extension(&mut self) -> Result<(), ()> {
2892 let start_span = self
2893 .token_stream.peek()
2894 .map(|t| t.span.clone())
2895 .unwrap_or_else(|| self.eof_span());
2896
2897 self.expect_keyword("schema")?;
2898
2899 self.record_error(GraphQLParseError::new(
2901 "schema extensions (`extend schema`) are not yet supported".to_string(),
2902 start_span,
2903 GraphQLParseErrorKind::InvalidSyntax,
2904 ));
2905
2906 let _ = self.parse_const_directive_annotations();
2908
2909 if self.peek_is(&GraphQLTokenKind::CurlyBraceOpen) {
2911 let open_token = self.expect(&GraphQLTokenKind::CurlyBraceOpen)?;
2912 self.push_delimiter(
2913 open_token.span.clone(),
2914 DelimiterContext::SchemaDefinition,
2915 );
2916
2917 loop {
2918 if self.peek_is(&GraphQLTokenKind::CurlyBraceClose) {
2919 break;
2920 }
2921 if self.token_stream.is_at_end() {
2922 self.handle_unclosed_brace();
2923 return Err(());
2924 }
2925
2926 let _ = self.expect_name();
2928 let _ = self.expect(&GraphQLTokenKind::Colon);
2929 let _ = self.expect_name();
2930 }
2931
2932 self.expect(&GraphQLTokenKind::CurlyBraceClose)?;
2933 self.pop_delimiter();
2934 }
2935
2936 Ok(())
2937 }
2938
2939 fn parse_scalar_type_extension(
2947 &mut self,
2948 position: ast::AstPos,
2949 ) -> Result<ast::schema::TypeExtension, ()> {
2950 self.expect_keyword("scalar")?;
2951 let name = self.expect_name_only()?;
2952 let directives = self.parse_const_directive_annotations()?;
2953 let schema_directives = self.convert_directives_to_schema(directives);
2954
2955 Ok(ast::schema::TypeExtension::Scalar(
2956 ast::schema::ScalarTypeExtension {
2957 position,
2958 name: name.into_owned(),
2959 directives: schema_directives,
2960 },
2961 ))
2962 }
2963
2964 fn parse_object_type_extension(
2973 &mut self,
2974 position: ast::AstPos,
2975 ) -> Result<ast::schema::TypeExtension, ()> {
2976 self.expect_keyword("type")?;
2977 let name = self.expect_name_only()?;
2978
2979 let implements_interfaces = if self.peek_is_keyword("implements") {
2980 self.parse_implements_interfaces()?
2981 } else {
2982 Vec::new()
2983 };
2984
2985 let directives = self.parse_const_directive_annotations()?;
2986 let schema_directives = self.convert_directives_to_schema(directives);
2987
2988 let fields = if self.peek_is(&GraphQLTokenKind::CurlyBraceOpen) {
2989 self.parse_fields_definition(DelimiterContext::ObjectTypeDefinition)?
2990 } else {
2991 Vec::new()
2992 };
2993
2994 Ok(ast::schema::TypeExtension::Object(
2995 ast::schema::ObjectTypeExtension {
2996 position,
2997 name: name.into_owned(),
2998 implements_interfaces,
2999 directives: schema_directives,
3000 fields,
3001 },
3002 ))
3003 }
3004
3005 fn parse_interface_type_extension(
3013 &mut self,
3014 position: ast::AstPos,
3015 ) -> Result<ast::schema::TypeExtension, ()> {
3016 self.expect_keyword("interface")?;
3017 let name = self.expect_name_only()?;
3018
3019 let implements_interfaces = if self.peek_is_keyword("implements") {
3020 self.parse_implements_interfaces()?
3021 } else {
3022 Vec::new()
3023 };
3024
3025 let directives = self.parse_const_directive_annotations()?;
3026 let schema_directives = self.convert_directives_to_schema(directives);
3027
3028 let fields = if self.peek_is(&GraphQLTokenKind::CurlyBraceOpen) {
3029 self.parse_fields_definition(DelimiterContext::InterfaceDefinition)?
3030 } else {
3031 Vec::new()
3032 };
3033
3034 Ok(ast::schema::TypeExtension::Interface(
3035 ast::schema::InterfaceTypeExtension {
3036 position,
3037 name: name.into_owned(),
3038 implements_interfaces,
3039 directives: schema_directives,
3040 fields,
3041 },
3042 ))
3043 }
3044
3045 fn parse_union_type_extension(
3053 &mut self,
3054 position: ast::AstPos,
3055 ) -> Result<ast::schema::TypeExtension, ()> {
3056 self.expect_keyword("union")?;
3057 let name = self.expect_name_only()?;
3058
3059 let directives = self.parse_const_directive_annotations()?;
3060 let schema_directives = self.convert_directives_to_schema(directives);
3061
3062 let mut types = Vec::new();
3063 if self.peek_is(&GraphQLTokenKind::Equals) {
3064 self.consume_token();
3065
3066 if self.peek_is(&GraphQLTokenKind::Pipe) {
3067 self.consume_token();
3068 }
3069
3070 let first_type = self.expect_name_only()?;
3071 types.push(first_type.into_owned());
3072
3073 while self.peek_is(&GraphQLTokenKind::Pipe) {
3074 self.consume_token();
3075 let member_type = self.expect_name_only()?;
3076 types.push(member_type.into_owned());
3077 }
3078 }
3079
3080 Ok(ast::schema::TypeExtension::Union(
3081 ast::schema::UnionTypeExtension {
3082 position,
3083 name: name.into_owned(),
3084 directives: schema_directives,
3085 types,
3086 },
3087 ))
3088 }
3089
3090 fn parse_enum_type_extension(
3098 &mut self,
3099 position: ast::AstPos,
3100 ) -> Result<ast::schema::TypeExtension, ()> {
3101 self.expect_keyword("enum")?;
3102 let name = self.expect_name_only()?;
3103
3104 let directives = self.parse_const_directive_annotations()?;
3105 let schema_directives = self.convert_directives_to_schema(directives);
3106
3107 let values = if self.peek_is(&GraphQLTokenKind::CurlyBraceOpen) {
3108 self.parse_enum_values_definition()?
3109 } else {
3110 Vec::new()
3111 };
3112
3113 Ok(ast::schema::TypeExtension::Enum(
3114 ast::schema::EnumTypeExtension {
3115 position,
3116 name: name.into_owned(),
3117 directives: schema_directives,
3118 values,
3119 },
3120 ))
3121 }
3122
3123 fn parse_input_object_type_extension(
3131 &mut self,
3132 position: ast::AstPos,
3133 ) -> Result<ast::schema::TypeExtension, ()> {
3134 self.expect_keyword("input")?;
3135 let name = self.expect_name_only()?;
3136
3137 let directives = self.parse_const_directive_annotations()?;
3138 let schema_directives = self.convert_directives_to_schema(directives);
3139
3140 let fields = if self.peek_is(&GraphQLTokenKind::CurlyBraceOpen) {
3141 self.parse_input_fields_definition()?
3142 } else {
3143 Vec::new()
3144 };
3145
3146 Ok(ast::schema::TypeExtension::InputObject(
3147 ast::schema::InputObjectTypeExtension {
3148 position,
3149 name: name.into_owned(),
3150 directives: schema_directives,
3151 fields,
3152 },
3153 ))
3154 }
3155
3156 pub fn parse_schema_document(mut self) -> ParseResult<ast::schema::Document> {
3162 let mut definitions = Vec::new();
3163
3164 while !self.token_stream.is_at_end() {
3165 match self.parse_schema_definition_item() {
3166 Ok(def) => definitions.push(def),
3167 Err(()) => {
3168 self.recover_to_next_definition();
3169 }
3170 }
3171 }
3172
3173 let document = ast::schema::Document { definitions };
3174
3175 if self.errors.is_empty() {
3176 ParseResult::ok(document)
3177 } else {
3178 ParseResult::recovered(document, self.errors)
3179 }
3180 }
3181
3182 pub fn parse_executable_document(
3184 mut self,
3185 ) -> ParseResult<ast::operation::Document> {
3186 let mut definitions = Vec::new();
3187
3188 while !self.token_stream.is_at_end() {
3189 match self.parse_executable_definition_item() {
3190 Ok(def) => definitions.push(def),
3191 Err(()) => {
3192 self.recover_to_next_definition();
3193 }
3194 }
3195 }
3196
3197 let document = ast::operation::Document { definitions };
3198
3199 if self.errors.is_empty() {
3200 ParseResult::ok(document)
3201 } else {
3202 ParseResult::recovered(document, self.errors)
3203 }
3204 }
3205
3206 pub fn parse_mixed_document(mut self) -> ParseResult<ast::MixedDocument> {
3208 let mut definitions = Vec::new();
3209
3210 while !self.token_stream.is_at_end() {
3211 match self.parse_mixed_definition_item() {
3212 Ok(def) => definitions.push(def),
3213 Err(()) => {
3214 self.recover_to_next_definition();
3215 }
3216 }
3217 }
3218
3219 let document = ast::MixedDocument { definitions };
3220
3221 if self.errors.is_empty() {
3222 ParseResult::ok(document)
3223 } else {
3224 ParseResult::recovered(document, self.errors)
3225 }
3226 }
3227
3228 fn parse_schema_definition_item(&mut self) -> Result<ast::schema::Definition, ()> {
3230 if let Some(token) = self.token_stream.peek()
3232 && let GraphQLTokenKind::Error { .. } = &token.kind {
3233 let token = token.clone();
3234 self.handle_lexer_error(&token);
3235 self.consume_token();
3236 return Err(());
3237 }
3238
3239 let description = self.parse_description();
3240
3241 if self.peek_is_keyword("schema") {
3242 Ok(ast::schema::Definition::SchemaDefinition(
3243 self.parse_schema_definition()?,
3244 ))
3245 } else if self.peek_is_keyword("scalar") {
3246 Ok(ast::schema::Definition::TypeDefinition(
3247 self.parse_scalar_type_definition(description)?,
3248 ))
3249 } else if self.peek_is_keyword("type") {
3250 Ok(ast::schema::Definition::TypeDefinition(
3251 self.parse_object_type_definition(description)?,
3252 ))
3253 } else if self.peek_is_keyword("interface") {
3254 Ok(ast::schema::Definition::TypeDefinition(
3255 self.parse_interface_type_definition(description)?,
3256 ))
3257 } else if self.peek_is_keyword("union") {
3258 Ok(ast::schema::Definition::TypeDefinition(
3259 self.parse_union_type_definition(description)?,
3260 ))
3261 } else if self.peek_is_keyword("enum") {
3262 Ok(ast::schema::Definition::TypeDefinition(
3263 self.parse_enum_type_definition(description)?,
3264 ))
3265 } else if self.peek_is_keyword("input") {
3266 Ok(ast::schema::Definition::TypeDefinition(
3267 self.parse_input_object_type_definition(description)?,
3268 ))
3269 } else if self.peek_is_keyword("directive") {
3270 Ok(ast::schema::Definition::DirectiveDefinition(
3271 self.parse_directive_definition(description)?,
3272 ))
3273 } else if self.peek_is_keyword("extend") {
3274 Ok(ast::schema::Definition::TypeExtension(
3275 self.parse_type_extension()?,
3276 ))
3277 } else if self.peek_is_keyword("query")
3278 || self.peek_is_keyword("mutation")
3279 || self.peek_is_keyword("subscription")
3280 || self.peek_is_keyword("fragment")
3281 || self.peek_is(&GraphQLTokenKind::CurlyBraceOpen) {
3282 let span = self
3284 .token_stream.peek()
3285 .map(|t| t.span.clone())
3286 .unwrap_or_else(|| self.eof_span());
3287 let kind = if self.peek_is_keyword("fragment") {
3288 DefinitionKind::Fragment
3289 } else {
3290 DefinitionKind::Operation
3291 };
3292 self.record_error(GraphQLParseError::new(
3293 format!(
3294 "{} not allowed in schema document",
3295 match kind {
3296 DefinitionKind::Fragment => "fragment definition",
3297 DefinitionKind::Operation => "operation definition",
3298 _ => "definition",
3299 }
3300 ),
3301 span,
3302 GraphQLParseErrorKind::WrongDocumentKind {
3303 found: kind,
3304 document_kind: DocumentKind::Schema,
3305 },
3306 ));
3307 self.consume_token();
3312 Err(())
3313 } else {
3314 let span = self
3315 .token_stream.peek()
3316 .map(|t| t.span.clone())
3317 .unwrap_or_else(|| self.eof_span());
3318 let found = self
3319 .token_stream.peek()
3320 .map(|t| Self::token_kind_display(&t.kind))
3321 .unwrap_or_else(|| "end of input".to_string());
3322 self.consume_token();
3327 self.record_error(GraphQLParseError::new(
3328 format!("expected schema definition, found `{found}`"),
3329 span,
3330 GraphQLParseErrorKind::UnexpectedToken {
3331 expected: vec![
3332 "type".to_string(),
3333 "interface".to_string(),
3334 "union".to_string(),
3335 "enum".to_string(),
3336 "scalar".to_string(),
3337 "input".to_string(),
3338 "directive".to_string(),
3339 "schema".to_string(),
3340 "extend".to_string(),
3341 ],
3342 found,
3343 },
3344 ));
3345 Err(())
3346 }
3347 }
3348
3349 fn parse_executable_definition_item(
3351 &mut self,
3352 ) -> Result<ast::operation::Definition, ()> {
3353 if let Some(token) = self.token_stream.peek()
3355 && let GraphQLTokenKind::Error { .. } = &token.kind {
3356 let token = token.clone();
3357 self.handle_lexer_error(&token);
3358 self.consume_token();
3359 return Err(());
3360 }
3361
3362 if self.peek_is_keyword("query")
3363 || self.peek_is_keyword("mutation")
3364 || self.peek_is_keyword("subscription")
3365 || self.peek_is(&GraphQLTokenKind::CurlyBraceOpen) {
3366 Ok(ast::operation::Definition::Operation(
3367 self.parse_operation_definition()?,
3368 ))
3369 } else if self.peek_is_keyword("fragment") {
3370 Ok(ast::operation::Definition::Fragment(
3371 self.parse_fragment_definition()?,
3372 ))
3373 } else if self.peek_is_keyword("type")
3374 || self.peek_is_keyword("interface")
3375 || self.peek_is_keyword("union")
3376 || self.peek_is_keyword("enum")
3377 || self.peek_is_keyword("scalar")
3378 || self.peek_is_keyword("input")
3379 || self.peek_is_keyword("directive")
3380 || self.peek_is_keyword("schema")
3381 || self.peek_is_keyword("extend") {
3382 let span = self
3384 .token_stream.peek()
3385 .map(|t| t.span.clone())
3386 .unwrap_or_else(|| self.eof_span());
3387 let kind = if self.peek_is_keyword("directive") {
3388 DefinitionKind::DirectiveDefinition
3389 } else if self.peek_is_keyword("schema") || self.peek_is_keyword("extend") {
3390 DefinitionKind::Schema
3391 } else {
3392 DefinitionKind::TypeDefinition
3393 };
3394 self.consume_token();
3395 self.record_error(GraphQLParseError::new(
3396 format!(
3397 "{} not allowed in executable document",
3398 match kind {
3399 DefinitionKind::TypeDefinition => "type definition",
3400 DefinitionKind::DirectiveDefinition => "directive definition",
3401 DefinitionKind::Schema => "schema definition",
3402 _ => "definition",
3403 }
3404 ),
3405 span,
3406 GraphQLParseErrorKind::WrongDocumentKind {
3407 found: kind,
3408 document_kind: DocumentKind::Executable,
3409 },
3410 ));
3411 Err(())
3412 } else {
3413 let first_is_string = self
3417 .token_stream.peek()
3418 .map(|t| matches!(&t.kind, GraphQLTokenKind::StringValue(_)))
3419 .unwrap_or(false);
3420
3421 if first_is_string {
3422 let is_type_def = self.token_stream.peek_nth(1).is_some_and(|next| {
3424 if let GraphQLTokenKind::Name(name) = &next.kind {
3425 matches!(
3426 name.as_ref(),
3427 "type"
3428 | "interface"
3429 | "union"
3430 | "enum"
3431 | "scalar"
3432 | "input"
3433 | "directive"
3434 | "schema"
3435 | "extend"
3436 )
3437 } else {
3438 false
3439 }
3440 });
3441
3442 if is_type_def {
3443 let span = self
3444 .token_stream.peek()
3445 .map(|t| t.span.clone())
3446 .unwrap_or_else(|| self.eof_span());
3447 self.consume_token();
3448 self.record_error(GraphQLParseError::new(
3449 "type definition not allowed in executable document",
3450 span,
3451 GraphQLParseErrorKind::WrongDocumentKind {
3452 found: DefinitionKind::TypeDefinition,
3453 document_kind: DocumentKind::Executable,
3454 },
3455 ));
3456 return Err(());
3457 }
3458 }
3459
3460 let span = self
3461 .token_stream.peek()
3462 .map(|t| t.span.clone())
3463 .unwrap_or_else(|| self.eof_span());
3464 let found = self
3465 .token_stream.peek()
3466 .map(|t| Self::token_kind_display(&t.kind))
3467 .unwrap_or_else(|| "end of input".to_string());
3468 self.consume_token();
3473 self.record_error(GraphQLParseError::new(
3474 format!(
3475 "expected operation or fragment definition, found `{found}`"
3476 ),
3477 span,
3478 GraphQLParseErrorKind::UnexpectedToken {
3479 expected: vec![
3480 "query".to_string(),
3481 "mutation".to_string(),
3482 "subscription".to_string(),
3483 "fragment".to_string(),
3484 "{".to_string(),
3485 ],
3486 found,
3487 },
3488 ));
3489 Err(())
3490 }
3491 }
3492
3493 fn parse_mixed_definition_item(&mut self) -> Result<ast::MixedDefinition, ()> {
3495 if let Some(token) = self.token_stream.peek()
3497 && let GraphQLTokenKind::Error { .. } = &token.kind {
3498 let token = token.clone();
3499 self.handle_lexer_error(&token);
3500 self.consume_token();
3501 return Err(());
3502 }
3503
3504 let description = self.parse_description();
3505
3506 if self.peek_is_keyword("schema") {
3508 return Ok(ast::MixedDefinition::Schema(
3509 ast::schema::Definition::SchemaDefinition(self.parse_schema_definition()?),
3510 ));
3511 }
3512 if self.peek_is_keyword("scalar") {
3513 return Ok(ast::MixedDefinition::Schema(
3514 ast::schema::Definition::TypeDefinition(
3515 self.parse_scalar_type_definition(description)?,
3516 ),
3517 ));
3518 }
3519 if self.peek_is_keyword("type") {
3520 return Ok(ast::MixedDefinition::Schema(
3521 ast::schema::Definition::TypeDefinition(
3522 self.parse_object_type_definition(description)?,
3523 ),
3524 ));
3525 }
3526 if self.peek_is_keyword("interface") {
3527 return Ok(ast::MixedDefinition::Schema(
3528 ast::schema::Definition::TypeDefinition(
3529 self.parse_interface_type_definition(description)?,
3530 ),
3531 ));
3532 }
3533 if self.peek_is_keyword("union") {
3534 return Ok(ast::MixedDefinition::Schema(
3535 ast::schema::Definition::TypeDefinition(
3536 self.parse_union_type_definition(description)?,
3537 ),
3538 ));
3539 }
3540 if self.peek_is_keyword("enum") {
3541 return Ok(ast::MixedDefinition::Schema(
3542 ast::schema::Definition::TypeDefinition(
3543 self.parse_enum_type_definition(description)?,
3544 ),
3545 ));
3546 }
3547 if self.peek_is_keyword("input") {
3548 return Ok(ast::MixedDefinition::Schema(
3549 ast::schema::Definition::TypeDefinition(
3550 self.parse_input_object_type_definition(description)?,
3551 ),
3552 ));
3553 }
3554 if self.peek_is_keyword("directive") {
3555 return Ok(ast::MixedDefinition::Schema(
3556 ast::schema::Definition::DirectiveDefinition(
3557 self.parse_directive_definition(description)?,
3558 ),
3559 ));
3560 }
3561 if self.peek_is_keyword("extend") {
3562 return Ok(ast::MixedDefinition::Schema(
3563 ast::schema::Definition::TypeExtension(self.parse_type_extension()?),
3564 ));
3565 }
3566
3567 if self.peek_is_keyword("query")
3569 || self.peek_is_keyword("mutation")
3570 || self.peek_is_keyword("subscription")
3571 || self.peek_is(&GraphQLTokenKind::CurlyBraceOpen) {
3572 return Ok(ast::MixedDefinition::Executable(
3573 ast::operation::Definition::Operation(self.parse_operation_definition()?),
3574 ));
3575 }
3576 if self.peek_is_keyword("fragment") {
3577 return Ok(ast::MixedDefinition::Executable(
3578 ast::operation::Definition::Fragment(self.parse_fragment_definition()?),
3579 ));
3580 }
3581
3582 let span = self
3583 .token_stream.peek()
3584 .map(|t| t.span.clone())
3585 .unwrap_or_else(|| self.eof_span());
3586 let found = self
3587 .token_stream.peek()
3588 .map(|t| Self::token_kind_display(&t.kind))
3589 .unwrap_or_else(|| "end of input".to_string());
3590 self.consume_token();
3595 self.record_error(GraphQLParseError::new(
3596 format!("expected definition, found `{found}`"),
3597 span,
3598 GraphQLParseErrorKind::UnexpectedToken {
3599 expected: vec![
3600 "type".to_string(),
3601 "query".to_string(),
3602 "fragment".to_string(),
3603 ],
3604 found,
3605 },
3606 ));
3607 Err(())
3608 }
3609}