Skip to main content

graphql_query/schema/sdl/
parser.rs

1use super::{
2  error::{syntax, syntax_err, validation, SchemaError}, finalizers::initialize_type_definition, parse_ast::*
3};
4use crate::{
5  ast::{ASTContext, DefaultIn},
6  error::{get_location, print_span, Error, ErrorType, Result},
7  schema::{
8      sdl::lexer::{Extras, Token}, Schema, SchemaEnum, SchemaPossibleTypes, SchemaScalar
9  },
10};
11use bumpalo::collections::Vec;
12use hashbrown::{HashMap, HashSet};
13use logos::{Lexer, Logos, Span};
14
15pub type ParseResult<T> = std::result::Result<T, SchemaError>;
16
17pub(crate) mod private {
18  use bumpalo::collections::Vec;
19
20use super::*;
21
22  /// Private Parser context state that's kept to keep track of the current parser's progress and
23  /// state. This contains the AST context and a [Lexer].
24  pub struct ParserContext<'a> {
25      pub(crate) ast_ctx: &'a ASTContext,
26      pub(crate) peek: Option<Token<'a>>,
27      pub(crate) iter: Lexer<'a, Token<'a>>,
28  }
29
30  impl<'a> ParserContext<'a> {
31      /// Create a new Parser context for a given AST context and initialize it with an input source
32      /// string to parse from.
33      pub(crate) fn new(ctx: &'a ASTContext, source: &'a str) -> Self {
34          let extras = Extras { arena: &ctx.arena };
35          ParserContext {
36              ast_ctx: ctx,
37              peek: None,
38              iter: Token::lexer_with_extras(source, extras),
39          }
40      }
41
42      #[inline]
43      pub(crate) fn next(&mut self) -> Token<'a> {
44          match self.peek.take() {
45              Some(token) => token,
46              None => self.iter.next().unwrap_or(Token::End),
47          }
48      }
49
50      #[inline]
51      pub(crate) fn peek(&mut self) -> &Token<'a> {
52          let iter = &mut self.iter;
53          self.peek
54              .get_or_insert_with(|| iter.next().unwrap_or(Token::End))
55      }
56
57      #[inline]
58      pub(crate) fn source(&self) -> &str {
59          self.iter.source()
60      }
61
62      #[inline]
63      pub(crate) fn span(&self) -> Span {
64          self.iter.span()
65      }
66
67      pub(crate) fn get_implements_interfaces(&mut self) -> ParseResult<Vec<'a, &'a str>> {
68          let mut interfaces = Vec::new_in(&self.ast_ctx.arena);
69          if self.peek() == &Token::Name("implements") {
70              // Skip `implements`
71              self.next();
72
73              // Skip optional leading `&`
74              if self.peek() == &Token::Ampersand {
75                  self.next();
76              }
77
78              // Get name of first interface
79              match self.next() {
80                  Token::Name(interface) => interfaces.push(interface),
81                  t => return syntax_err!("Expected interface name, got {:?}", t),
82              }
83
84              // Get any remaining interfaces
85              while self.peek() == &Token::Ampersand {
86                  // Skip `&`
87                  self.next();
88
89                  // Get name of next interface
90                  match self.next() {
91                      Token::Name(interface) => interfaces.push(interface),
92                      t => return syntax_err!("Expected interface name, got {:?}", t),
93                  }
94              }
95          }
96
97          Ok(interfaces)
98      }
99  }
100
101  /// (Private) Trait for parsing AST Nodes from a Parser Context.
102  /// The [`super::ParseNode`] trait implements the public `parse` method instead.
103  pub trait ParseFromCtx<'a>: Sized {
104      fn parse_from_ctx(ctx: &mut ParserContext<'a>) -> ParseResult<Self>;
105  }
106}
107
108impl<'a, T: private::ParseFromCtx<'a>> ParseSdl<'a> for T {}
109
110/// Trait for parsing SDL AST nodes from source text using recursive descent and a lexer.
111///
112/// This trait is implemented by all AST nodes and can hence be used to granularly parse GraphQL SDL.
113/// However, mostly this will be used via `Schema::parse`.
114pub trait ParseSdl<'a>: private::ParseFromCtx<'a> {
115  /// Parse an input source text into the implementor's AST node structure and allocate the
116  /// resulting AST into the context arena.
117  fn parse<T: ToString>(ctx: &'a ASTContext, source: T) -> Result<&'a Self> {
118      let source = ctx.alloc_string(source.to_string());
119      let mut parser_ctx = private::ParserContext::new(ctx, source);
120      match Self::parse_from_ctx(&mut parser_ctx) {
121          Ok(value) => Ok(ctx.alloc(value)),
122          Err(error) => {
123              let span = print_span(parser_ctx.source(), parser_ctx.span());
124              let location = get_location(parser_ctx.source(), parser_ctx.span());
125              let message = error.to_string();
126
127              Err(Error::new_with_context(
128                  message,
129                  Some(location),
130                  span,
131                  Some(ErrorType::Syntax),
132              ))
133          }
134      }
135  }
136}
137
138const DEFAULT_SCALARS: [&str; 5] = [
139  "String",
140  "Int",
141  "Float",
142  "Boolean",
143  "ID",
144];
145
146impl<'a> private::ParseFromCtx<'a> for Schema<'a> {
147  #[inline]
148  fn parse_from_ctx(ctx: &mut private::ParserContext<'a>) -> ParseResult<Self> {
149      let mut schema = Schema::default_in(&ctx.ast_ctx.arena);
150      let mut schema_def = None;
151      let mut type_defs = HashMap::new_in(&ctx.ast_ctx.arena);
152      // TODO: store schema extensions here and merge after first loop
153      // let mut schema_extensions = HashMap::new_in(&ctx.ast_ctx.arena);
154      loop {
155          match ctx.peek() {
156              Token::End => break,
157              // TODO: add support for directives
158              Token::Name("schema") => {
159                  if schema_def.is_none() {
160                      schema_def = Some(SchemaDefinition::parse_from_ctx(ctx)?)
161                  } else {
162                      return syntax_err!("Must not specify more than one Schema Definition.");
163                  }
164              }
165              _ => {
166                let type_def = TypeDefinition::parse_from_ctx(ctx)?;
167                type_defs.insert(type_def.name(), type_def);
168              },
169          }
170      }
171
172      for (name, typ) in type_defs.clone().iter() {
173        match typ {
174            TypeDefinition::InterfaceTypeDefinition(i) => {
175                for interface in i.interfaces.iter() {
176                    if let Some(TypeDefinition::InterfaceTypeDefinition(implemented_interface)) = type_defs.get_mut(interface) {
177                        // TODO: check whether this is the right way to go about it, might be an existing bug in
178                        // the client-schema
179                        implemented_interface.add_possible_interface(name);
180                    }
181                }
182            },
183            TypeDefinition::ObjectTypeDefinition(obj) => {
184                for interface in obj.interfaces.iter() {
185                    if let Some(TypeDefinition::InterfaceTypeDefinition(i)) = type_defs.get_mut(interface) {
186                        i.add_possible_type(name);
187                    }
188                }
189            }
190            _ => (),
191        }
192      }
193
194      for scalar in DEFAULT_SCALARS.iter() {
195          schema.types.insert(
196              *scalar,
197              ctx.ast_ctx.alloc(crate::schema::SchemaType::Scalar(ctx.ast_ctx.alloc(SchemaScalar { name: scalar }))),
198          );
199      }
200
201      // Build type skeletons in a first pass.
202      // We need to create all type definitions first to avoid circular evaluation of types.
203      for typ in type_defs.into_iter() {
204          schema.types.insert(
205              typ.0,
206              initialize_type_definition(ctx.ast_ctx, ctx.ast_ctx.alloc(typ.1)),
207          );
208      }
209
210      for (name, typ) in schema.types.iter() {
211        match typ {
212            crate::schema::SchemaType::Object(schema_obj) => {
213                for field in schema_obj.fields.iter() {
214                    // TODO: check field-arguments
215
216                    field.1.output_type.of_type(&schema).output_type().ok_or_else(|| validation!(
217                        "Field `{}` of type `{}` has an invalid type.",
218                        field.0,
219                        name
220                    ))?;
221                }
222
223                for type_name in schema_obj.interfaces.iter() {
224                    schema.get_type(type_name).ok_or_else(|| validation!(
225                        "Interface `{}` on object `{}` does not exist.",
226                        type_name,
227                        schema_obj.name
228                    ))?;
229                }
230            }
231            crate::schema::SchemaType::InputObject(schema_input) => {
232                for field in schema_input.fields.iter() {
233                    field.1.input_type.of_type(&schema).input_type().ok_or_else(|| validation!(
234                        "Field `{}` of type `{}` has an invalid type.",
235                        field.0,
236                        name
237                    ))?;
238                }
239            }
240            crate::schema::SchemaType::Union(schema_union) => {
241                for type_name in schema_union.get_possible_types().iter() {
242                    schema.get_type(type_name).ok_or_else(|| validation!(
243                        "Type `{}` on union `{}` is not a valid type.",
244                        type_name,
245                        schema_union.name
246                    ))?;
247                }
248            }
249            crate::schema::SchemaType::Interface(schema_interface) => {
250                for field in schema_interface.fields.iter() {
251                    // TODO: Check whether each argument refers to a valid type
252
253                    field.1.output_type.of_type(&schema).output_type().ok_or_else(|| validation!(
254                        "Field `{}` of type `{}` has an invalid type.",
255                        field.0,
256                        name
257                    ))?;
258                }
259
260                for type_name in schema_interface.get_possible_types().iter() {
261                    schema.get_type(type_name).ok_or_else(|| validation!(
262                        "Type `{}` on interface `{}` is not a valid type.",
263                        type_name,
264                        schema_interface.name
265                    ))?;
266                }
267
268                for type_name in schema_interface.interfaces.iter() {
269                    schema.get_type(type_name).ok_or_else(|| validation!(
270                        "Interface `{}` on object `{}` does not exist.",
271                        type_name,
272                        schema_interface.name
273                    ))?;
274                }
275            }
276            _ => {
277                // Other types have no issues
278            }
279        }
280      } 
281
282      // fill in the root types
283      if let Some(query_type) = schema_def
284          .map_or(Some("Query"), |def| def.query_root_type_name)
285          .and_then(|name| schema.types.get(name))
286      {
287          schema.query_type = match query_type.object() {
288              Some(obj_type) => Some(obj_type),
289              None => {
290                  return syntax_err!(
291                      "Query root type `{}` must be an object type.",
292                      query_type.name()
293                  )
294              }
295          }
296      }
297
298      if let Some(mutation_type) = schema_def
299          .map_or(Some("Mutation"), |def| def.mutation_root_type_name)
300          .and_then(|name| schema.types.get(name))
301      {
302          schema.mutation_type = match mutation_type.object() {
303              Some(obj_type) => Some(obj_type),
304              None => {
305                  return syntax_err!(
306                      "Mutation root type `{}` must be an object type.",
307                      mutation_type.name()
308                  )
309              }
310          }
311      }
312
313      if let Some(subscription_type) = schema_def
314          .map_or(Some("Subscription"), |def| def.subscription_root_type_name)
315          .and_then(|name| schema.types.get(name))
316      {
317          schema.subscription_type = match subscription_type.object() {
318              Some(obj_type) => Some(obj_type),
319              None => {
320                  return syntax_err!(
321                      "Subscription root type `{}` must be an object type.",
322                      subscription_type.name()
323                  )
324              }
325          }
326      }
327
328      Ok(schema)
329  }
330}
331
332impl<'a> private::ParseFromCtx<'a> for SchemaDefinition<'a> {
333  #[inline]
334  fn parse_from_ctx(ctx: &mut private::ParserContext<'a>) -> ParseResult<Self> {
335      if ctx.next() != Token::Name("schema") {
336          return syntax_err!("Schema definition must start with the `schema` keyword.");
337      }
338
339      if Token::BraceOpen != ctx.next() {
340          return syntax_err!("Expected `{{`");
341      }
342
343      let mut defs = Self {
344          query_root_type_name: None,
345          mutation_root_type_name: None,
346          subscription_root_type_name: None,
347      };
348
349      while !matches!(ctx.peek(), Token::BraceClose | Token::End) {
350          let operation_type = match ctx.next() {
351              Token::Name(op @ ("query" | "mutation" | "subscription")) => op,
352              t => return syntax_err!("Expected operation type, got {:?}", t),
353          };
354
355          if Token::Colon != ctx.next() {
356              return syntax_err!("Expected `:`");
357          }
358
359          let type_name = if let Token::Name(n) = ctx.next() {
360              n
361          } else {
362              return syntax_err!("Expected named type");
363          };
364
365          match operation_type {
366              "query" => defs.query_root_type_name = Some(type_name),
367              "mutation" => defs.mutation_root_type_name = Some(type_name),
368              "subscription" => defs.subscription_root_type_name = Some(type_name),
369              _ => unreachable!("Invalid operation type {operation_type}"),
370          }
371      }
372
373      if Token::BraceClose != ctx.next() {
374          return syntax_err!("Expected `}}`");
375      }
376
377      Ok(defs)
378  }
379}
380
381impl<'a> private::ParseFromCtx<'a> for TypeDefinition<'a> {
382  #[inline]
383  fn parse_from_ctx(ctx: &mut private::ParserContext<'a>) -> ParseResult<Self> {
384      match ctx.peek() {
385          Token::Name("type") => SchemaObjectPlaceholder::parse_from_ctx(ctx)
386              .map(TypeDefinition::ObjectTypeDefinition),
387          Token::Name("input") => SchemaInputObjectPlaceholder::parse_from_ctx(ctx)
388              .map(TypeDefinition::InputObjectTypeDefinition),
389          Token::Name("enum") => {
390              SchemaEnum::parse_from_ctx(ctx).map(TypeDefinition::EnumTypeDefinition)
391          }
392          Token::Name("scalar") => {
393              SchemaScalar::parse_from_ctx(ctx).map(TypeDefinition::ScalarTypeDefinition)
394          }
395          Token::Name("interface") => SchemaInterfacePlaceholder::parse_from_ctx(ctx)
396              .map(TypeDefinition::InterfaceTypeDefinition),
397          Token::Name("union") => {
398              SchemaUnionPlaceholder::parse_from_ctx(ctx).map(TypeDefinition::UnionTypeDefinition)
399          }
400
401          t => {
402              syntax_err!("Expected valid type definition, got {:?}.", t)
403          }
404      }
405  }
406}
407
408impl<'a> private::ParseFromCtx<'a> for SchemaObjectPlaceholder<'a> {
409  #[inline]
410  fn parse_from_ctx(ctx: &mut private::ParserContext<'a>) -> ParseResult<Self> {
411      if ctx.next() != Token::Name("type") {
412          return syntax_err!("Object type must start with the `type` keyword.");
413      }
414
415      let name = match ctx.next() {
416          Token::Name(name) => name,
417          t => return syntax_err!("Expected type name, got {:?}", t),
418      };
419
420      let interfaces = ctx.get_implements_interfaces()?;
421
422      let fields = match ctx.peek() {
423          Token::BraceOpen => FieldDefinitions::parse_from_ctx(ctx)?,
424          t => return syntax_err!("Expected `{{`, got {:?}", t),
425      };
426
427      Ok(SchemaObjectPlaceholder {
428          name,
429          fields,
430          interfaces,
431      })
432  }
433}
434
435impl<'a> private::ParseFromCtx<'a> for SchemaInputObjectPlaceholder<'a> {
436  #[inline]
437  fn parse_from_ctx(ctx: &mut private::ParserContext<'a>) -> ParseResult<Self> {
438      if ctx.next() != Token::Name("input") {
439          return syntax_err!("Input object type must start with the `input` keyword.");
440      }
441
442      let name = match ctx.next() {
443          Token::Name(name) => name,
444          t => return syntax_err!("Expected input type name, got {:?}", t),
445      };
446
447      let fields = match ctx.peek() {
448          Token::BraceOpen => InputFieldDefinitions::parse_from_ctx(ctx)?,
449          t => return syntax_err!("Expected `{{`, got {:?}", t),
450      };
451
452      Ok(SchemaInputObjectPlaceholder { name, fields })
453  }
454}
455
456impl<'a> private::ParseFromCtx<'a> for SchemaInterfacePlaceholder<'a> {
457  #[inline]
458  fn parse_from_ctx(ctx: &mut private::ParserContext<'a>) -> ParseResult<Self> {
459      if ctx.next() != Token::Name("interface") {
460          return syntax_err!("Interface type must start with the `interface` keyword.");
461      }
462
463      let name = match ctx.next() {
464          Token::Name(name) => name,
465          t => return syntax_err!("Expected type name, got {:?}", t),
466      };
467
468      let interfaces = ctx.get_implements_interfaces()?;
469
470      let fields = match ctx.peek() {
471          Token::BraceOpen => FieldDefinitions::parse_from_ctx(ctx)?,
472          t => return syntax_err!("Expected `{{`, got {:?}", t),
473      };
474
475      Ok(SchemaInterfacePlaceholder {
476          name,
477          fields,
478          interfaces,
479          possible_types: Vec::new_in(&ctx.ast_ctx.arena),
480          possible_interfaces: Vec::new_in(&ctx.ast_ctx.arena),
481      })
482  }
483}
484
485impl<'a> private::ParseFromCtx<'a> for SchemaUnionPlaceholder<'a> {
486  #[inline]
487  fn parse_from_ctx(ctx: &mut private::ParserContext<'a>) -> ParseResult<Self> {
488      if ctx.next() != Token::Name("union") {
489          return syntax_err!("Union type must start with the `union` keyword.");
490      }
491
492      let name = match ctx.next() {
493          Token::Name(name) => name,
494          t => return syntax_err!("Expected type name, got {:?}", t),
495      };
496
497      let mut types = Vec::new_in(&ctx.ast_ctx.arena);
498      if ctx.peek() == &Token::Equal {
499          // Skip `=`
500          ctx.next();
501
502          // Skip optional leading `|`
503          if ctx.peek() == &Token::Pipe {
504              ctx.next();
505          }
506
507          // Get name of first type
508          match ctx.next() {
509              Token::Name(t) => types.push(t),
510              t => return syntax_err!("Expected type name, got {:?}", t),
511          }
512
513          // Get any remaining types
514          while ctx.peek() == &Token::Pipe {
515              // Skip `|`
516              ctx.next();
517
518              // Get name of next type
519              match ctx.next() {
520                  Token::Name(t) => types.push(t),
521                  t => return syntax_err!("Expected interface name, got {:?}", t),
522              }
523          }
524      }
525
526      Ok(SchemaUnionPlaceholder {
527          name,
528          types,
529      })
530  }
531}
532
533impl<'a> private::ParseFromCtx<'a> for FieldDefinitions<'a> {
534  #[inline]
535  fn parse_from_ctx(ctx: &mut private::ParserContext<'a>) -> ParseResult<Self> {
536      if let Token::BraceOpen = ctx.peek() {
537          ctx.next(); // Skip brace open
538
539          let mut fields = HashMap::new_in(&ctx.ast_ctx.arena);
540          while !matches!(ctx.peek(), Token::BraceClose | Token::End) {
541              let field = SchemaFieldPlaceholder::parse_from_ctx(ctx)?;
542              fields.insert(field.name, field);
543          }
544
545          match ctx.peek() {
546              Token::BraceClose => {
547                  ctx.next();
548                  Ok(FieldDefinitions { fields })
549              }
550
551              t => syntax_err!("Expected `}}`, got {:?}", t),
552          }
553      } else {
554          Ok(FieldDefinitions::default_in(&ctx.ast_ctx.arena))
555      }
556  }
557}
558
559impl<'a> private::ParseFromCtx<'a> for InputFieldDefinitions<'a> {
560  #[inline]
561  fn parse_from_ctx(ctx: &mut private::ParserContext<'a>) -> ParseResult<Self> {
562      if let Token::BraceOpen = ctx.peek() {
563          ctx.next(); // Skip brace open
564
565          let mut fields = HashMap::new_in(&ctx.ast_ctx.arena);
566          while !matches!(ctx.peek(), Token::BraceClose | Token::End) {
567              let field = SchemaInputFieldPlaceholder::parse_from_ctx(ctx)?;
568              fields.insert(field.name, field);
569          }
570
571          match ctx.peek() {
572              Token::BraceClose => {
573                  ctx.next();
574                  Ok(InputFieldDefinitions { fields })
575              }
576
577              t => syntax_err!("Expected `}}`, got {:?}", t),
578          }
579      } else {
580          Ok(InputFieldDefinitions::default_in(&ctx.ast_ctx.arena))
581      }
582  }
583}
584
585impl<'a> private::ParseFromCtx<'a> for SchemaFieldPlaceholder<'a> {
586  #[inline]
587  fn parse_from_ctx(ctx: &mut private::ParserContext<'a>) -> ParseResult<Self> {
588      let name = match ctx.next() {
589          Token::Name(name) => name,
590          t => return syntax_err!("Expected field name, got {:?}", t),
591      };
592
593      let arguments = match ctx.peek() {
594          Token::Colon => ArgumentList::default_in(&ctx.ast_ctx.arena),
595          Token::ParenOpen => ArgumentList::parse_from_ctx(ctx)?,
596          t => return syntax_err!("Expected `(` or `:`, got {:?}", t),
597      };
598
599      if Token::Colon != ctx.next() {
600          return syntax_err!("Expected `:`");
601      }
602
603      let output_type = ctx.ast_ctx.arena.alloc(TypeWrapper::parse_from_ctx(ctx)?);
604      Ok(SchemaFieldPlaceholder {
605          name,
606          arguments,
607          output_type,
608      })
609  }
610}
611
612impl<'a> private::ParseFromCtx<'a> for ArgumentList<'a> {
613  #[inline]
614  fn parse_from_ctx(ctx: &mut private::ParserContext<'a>) -> ParseResult<Self> {
615      if let Token::ParenOpen = ctx.peek() {
616          ctx.next(); // Skip parens open
617
618          let mut arguments = HashMap::new_in(&ctx.ast_ctx.arena);
619          while !matches!(ctx.peek(), Token::ParenClose | Token::End) {
620              let argument = SchemaInputFieldPlaceholder::parse_from_ctx(ctx)?;
621              arguments.insert(argument.name, argument);
622          }
623
624          match ctx.peek() {
625              Token::ParenClose => {
626                  ctx.next();
627                  Ok(ArgumentList { arguments })
628              }
629
630              t => syntax_err!("Expected `)`, got {:?}", t),
631          }
632      } else {
633          Ok(ArgumentList::default_in(&ctx.ast_ctx.arena))
634      }
635  }
636}
637
638impl<'a> private::ParseFromCtx<'a> for SchemaInputFieldPlaceholder<'a> {
639  #[inline]
640  fn parse_from_ctx(ctx: &mut private::ParserContext<'a>) -> ParseResult<Self> {
641      // Skip leading comma
642      if let Token::Comma = ctx.peek() {
643          ctx.next();
644      }
645
646      let name = match ctx.next() {
647          Token::Name(name) => name,
648          t => return syntax_err!("Expected input field name, got {:?}", t),
649      };
650
651      if Token::Colon != ctx.next() {
652          return syntax_err!("Expected `:`");
653      }
654
655      let input_type = ctx.ast_ctx.arena.alloc(TypeWrapper::parse_from_ctx(ctx)?);
656      Ok(SchemaInputFieldPlaceholder { name, input_type })
657  }
658}
659
660impl<'a> private::ParseFromCtx<'a> for TypeWrapper<'a> {
661  #[inline]
662  fn parse_from_ctx(ctx: &mut private::ParserContext<'a>) -> ParseResult<Self> {
663      let typ = match ctx.next() {
664          Token::Name(name) => TypeWrapper::Named(name),
665          Token::BracketOpen => {
666              let typ =
667                  TypeWrapper::List(ctx.ast_ctx.arena.alloc(TypeWrapper::parse_from_ctx(ctx)?));
668              if ctx.next() != Token::BracketClose {
669                  return syntax_err!("Unterminated list");
670              }
671
672              typ
673          }
674
675          t => return syntax_err!("Expected type name or list type start `[`, got {:?}", t),
676      };
677
678      match ctx.peek() {
679          Token::Exclam => {
680              ctx.next();
681              Ok(TypeWrapper::NonNull(ctx.ast_ctx.arena.alloc(typ)))
682          }
683          _ => Ok(typ),
684      }
685  }
686}
687
688impl<'a> private::ParseFromCtx<'a> for SchemaEnum<'a> {
689  #[inline]
690  fn parse_from_ctx(ctx: &mut private::ParserContext<'a>) -> ParseResult<Self> {
691      if ctx.next() != Token::Name("enum") {
692          return syntax_err!("Enum definition must start with the `enum` keyword.");
693      }
694
695      let name = match ctx.next() {
696          Token::Name(name) => name,
697          t => return syntax_err!("Expected type name, got {:?}", t),
698      };
699
700      let mut values = HashSet::new_in(&ctx.ast_ctx.arena);
701      match ctx.next() {
702          Token::BraceOpen => loop {
703              match ctx.next() {
704                  Token::BraceClose => break,
705                  Token::Name(name) => {
706                    values.insert(name);
707                  },
708                  t => {
709                      return syntax_err!(
710                          "Expected either closing brace or value name, got {:?}",
711                          t
712                      )
713                  }
714              }
715          },
716
717          t => {
718              return syntax_err!(
719                  "Enum definition must include values starting with `{{`, got {:?}",
720                  t
721              )
722          }
723      };
724
725      Ok(SchemaEnum { name, values })
726  }
727}
728
729impl<'a> private::ParseFromCtx<'a> for SchemaScalar<'a> {
730  #[inline]
731  fn parse_from_ctx(ctx: &mut private::ParserContext<'a>) -> ParseResult<Self> {
732      if ctx.next() != Token::Name("scalar") {
733          return syntax_err!("Scalar definition must start with the `scalar` keyword.");
734      }
735
736      let name = match ctx.next() {
737          Token::Name(name) => name,
738          t => return syntax_err!("Expected type name, got {:?}", t),
739      };
740
741      Ok(SchemaScalar { name })
742  }
743}