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 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 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 self.next();
72
73 if self.peek() == &Token::Ampersand {
75 self.next();
76 }
77
78 match self.next() {
80 Token::Name(interface) => interfaces.push(interface),
81 t => return syntax_err!("Expected interface name, got {:?}", t),
82 }
83
84 while self.peek() == &Token::Ampersand {
86 self.next();
88
89 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 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
110pub trait ParseSdl<'a>: private::ParseFromCtx<'a> {
115 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 loop {
155 match ctx.peek() {
156 Token::End => break,
157 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 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 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 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 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 }
279 }
280 }
281
282 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 ctx.next();
501
502 if ctx.peek() == &Token::Pipe {
504 ctx.next();
505 }
506
507 match ctx.next() {
509 Token::Name(t) => types.push(t),
510 t => return syntax_err!("Expected type name, got {:?}", t),
511 }
512
513 while ctx.peek() == &Token::Pipe {
515 ctx.next();
517
518 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(); 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(); 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(); 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 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}