Skip to content

Commit

Permalink
Parse interfaces in cynic-parser
Browse files Browse the repository at this point in the history
  • Loading branch information
obmarg committed Jan 7, 2024
1 parent 7660feb commit f5f9c9a
Show file tree
Hide file tree
Showing 7 changed files with 153 additions and 7 deletions.
20 changes: 20 additions & 0 deletions cynic-parser/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ pub struct Ast {

schema_definitions: Vec<SchemaDefinition>,
object_definitions: Vec<ObjectDefinition>,
interface_definitions: Vec<InterfaceDefinition>,
input_object_definitions: Vec<InputObjectDefinition>,

field_definitions: Vec<FieldDefinition>,
Expand All @@ -38,6 +39,7 @@ pub struct Ast {
pub enum AstDefinition {
Schema(SchemaDefinitionId),
Object(ObjectDefinitionId),
Interface(InterfaceDefinitionId),
InputObject(InputObjectDefinitionId),
}

Expand All @@ -62,6 +64,14 @@ pub struct FieldDefinition {
pub span: Span,
}

pub struct InterfaceDefinition {
pub name: StringId,
pub fields: Vec<FieldDefinitionId>,
pub directives: Vec<DirectiveId>,
pub implements: Vec<StringId>,
pub span: Span,
}

pub struct InputObjectDefinition {
pub name: StringId,
pub fields: Vec<InputValueDefinitionId>,
Expand Down Expand Up @@ -190,6 +200,16 @@ impl AstBuilder {
definition_id
}

pub fn interface_definition(&mut self, definition: InterfaceDefinition) -> DefinitionId {
let id = InterfaceDefinitionId(self.ast.interface_definitions.len());
self.ast.interface_definitions.push(definition);

let definition_id = DefinitionId(self.ast.definitions.len());
self.ast.definitions.push(AstDefinition::Interface(id));

definition_id
}

pub fn input_object_definition(&mut self, definition: InputObjectDefinition) -> DefinitionId {
let id = InputObjectDefinitionId(self.ast.input_object_definitions.len());
self.ast.input_object_definitions.push(definition);
Expand Down
17 changes: 16 additions & 1 deletion cynic-parser/src/ast/ids.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use crate::Ast;

use super::{
Argument, AstDefinition, Directive, FieldDefinition, InputObjectDefinition,
InputValueDefinition, ObjectDefinition, SchemaDefinition, Type, Value,
InputValueDefinition, InterfaceDefinition, ObjectDefinition, SchemaDefinition, Type, Value,
};

pub trait AstId {}
Expand Down Expand Up @@ -71,6 +71,21 @@ impl AstLookup<ObjectDefinitionId> for Ast {
}
}

#[derive(Clone, Copy)]
pub struct InterfaceDefinitionId(pub(super) usize);

impl AstId for InterfaceDefinitionId {}

impl AstLookup<InterfaceDefinitionId> for Ast {
type Output = InterfaceDefinition;

fn lookup(&self, index: InterfaceDefinitionId) -> &Self::Output {
self.interface_definitions
.get(index.0)
.expect("objects to be present")
}
}

#[derive(Clone, Copy)]
pub struct InputObjectDefinitionId(pub(super) usize);
impl AstId for InputObjectDefinitionId {}
Expand Down
37 changes: 36 additions & 1 deletion cynic-parser/src/ast/reader.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
use crate::{ast, Ast};

use super::{
ids::{ArgumentId, AstId, AstLookup, DirectiveId, InputValueDefinitionId, TypeId, ValueId},
ids::{
ArgumentId, AstId, AstLookup, DirectiveId, InputValueDefinitionId, InterfaceDefinitionId,
TypeId, ValueId,
},
FieldDefinitionId, InputObjectDefinitionId, ObjectDefinitionId, OperationType,
SchemaDefinitionId, Type, WrappingType,
};
Expand All @@ -25,6 +28,7 @@ impl Ast {
self.definitions.iter().map(|definition| match definition {
ast::AstDefinition::Schema(id) => Definition::Schema(self.read(*id)),
ast::AstDefinition::Object(id) => Definition::Object(self.read(*id)),
ast::AstDefinition::Interface(id) => Definition::Interface(self.read(*id)),
ast::AstDefinition::InputObject(id) => Definition::InputObject(self.read(*id)),
})
}
Expand All @@ -33,6 +37,7 @@ impl Ast {
pub enum Definition<'a> {
Schema(AstReader<'a, SchemaDefinitionId>),
Object(AstReader<'a, ObjectDefinitionId>),
Interface(AstReader<'a, InterfaceDefinitionId>),
InputObject(AstReader<'a, InputObjectDefinitionId>),
}

Expand Down Expand Up @@ -76,6 +81,36 @@ impl<'a> AstReader<'a, ObjectDefinitionId> {
}
}

impl<'a> AstReader<'a, InterfaceDefinitionId> {
pub fn name(&self) -> &str {
self.ast.lookup(self.ast.lookup(self.id).name)
}

pub fn implements_interfaces(&self) -> impl Iterator<Item = &'a str> + 'a {
self.ast
.lookup(self.id)
.implements
.iter()
.map(|id| self.ast.lookup(*id))
}

pub fn fields(&self) -> impl Iterator<Item = AstReader<'a, FieldDefinitionId>> + 'a {
self.ast
.lookup(self.id)
.fields
.iter()
.map(|id| self.ast.read(*id))
}

pub fn directives(&self) -> impl Iterator<Item = AstReader<'a, DirectiveId>> + 'a {
self.ast
.lookup(self.id)
.directives
.iter()
.map(|id| self.ast.read(*id))
}
}

impl<'a> AstReader<'a, InputObjectDefinitionId> {
pub fn name(&self) -> &str {
self.ast.lookup(self.ast.lookup(self.id).name)
Expand Down
4 changes: 4 additions & 0 deletions cynic-parser/src/lexer/tokens.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,9 @@ pub enum Token<'a> {
#[token("implements")]
Implements,

#[token("interface")]
Interface,

// IntegerPart: -?(0|[1-9][0-9]*)
// FractionalPart: \\.[0-9]+
// ExponentPart: [eE][+-]?[0-9]+
Expand Down Expand Up @@ -266,6 +269,7 @@ impl fmt::Display for Token<'_> {
Token::False => "false",
Token::Null => "null,",
Token::Implements => "implements",
Token::Interface => "interface",
};
f.write_str(message)
}
Expand Down
18 changes: 18 additions & 0 deletions cynic-parser/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,24 @@ mod tests {
);
}

#[test]
fn test_basic_interface() {
insta::assert_snapshot!(
parse_type_system_document(r#"
interface MyType implements Blah & Bloo @hello {
field: Whatever @hello(name: ["string"]),
other: [[Int!]]!
}"#
).to_sdl(),
@r###"
interface MyType implements Blah & Bloo @hello {
field: Whatever@hello(name: ("string"))
other: [[Int!]]!
}
"###
);
}

#[test]
fn test_schema_field() {
// Use a keyword as a field name and make sure it's fine
Expand Down
42 changes: 38 additions & 4 deletions cynic-parser/src/printer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ use pretty::{Arena, BoxAllocator, DocAllocator, Pretty};
use crate::ast::{
ids::{
ArgumentId, DirectiveId, FieldDefinitionId, InputObjectDefinitionId,
InputValueDefinitionId, ObjectDefinitionId, SchemaDefinitionId, TypeId, ValueId,
InputValueDefinitionId, InterfaceDefinitionId, ObjectDefinitionId, SchemaDefinitionId,
TypeId, ValueId,
},
AstDefinition, AstReader, Definition,
};
Expand All @@ -16,9 +17,10 @@ impl crate::Ast {

let builder = allocator
.concat(self.definitions().map(|definition| match definition {
Definition::Schema(schema) => NodeDisplay(schema).pretty(&allocator),
Definition::Object(object) => NodeDisplay(object).pretty(&allocator),
Definition::InputObject(object) => NodeDisplay(object).pretty(&allocator),
Definition::Schema(reader) => NodeDisplay(reader).pretty(&allocator),
Definition::Object(reader) => NodeDisplay(reader).pretty(&allocator),
Definition::Interface(reader) => NodeDisplay(reader).pretty(&allocator),
Definition::InputObject(reader) => NodeDisplay(reader).pretty(&allocator),
}))
.pretty(&allocator);

Expand Down Expand Up @@ -103,6 +105,38 @@ impl<'a> Pretty<'a, BoxAllocator> for NodeDisplay<'a, FieldDefinitionId> {
}
}

impl<'a> Pretty<'a, BoxAllocator> for NodeDisplay<'a, InterfaceDefinitionId> {
fn pretty(self, allocator: &'a BoxAllocator) -> pretty::DocBuilder<'a, BoxAllocator, ()> {
let mut builder = allocator
.text(format!("interface {}", self.0.name()))
.append(allocator.space());

let interfaces = self.0.implements_interfaces().collect::<Vec<_>>();

if !interfaces.is_empty() {
builder = builder
.append(allocator.text("implements"))
.append(allocator.space())
.append(allocator.intersperse(interfaces, " & "))
.append(allocator.space());
}

builder
.append(allocator.intersperse(self.0.directives().map(NodeDisplay), allocator.line()))
.append(allocator.space())
.append(allocator.text("{"))
.append(allocator.hardline())
.append(allocator.text(" "))
.append(
allocator
.intersperse(self.0.fields().map(NodeDisplay), allocator.hardline())
.align(),
)
.append(allocator.hardline())
.append(allocator.text("}"))
}
}

impl<'a> Pretty<'a, BoxAllocator> for NodeDisplay<'a, InputObjectDefinitionId> {
fn pretty(self, allocator: &'a BoxAllocator) -> pretty::DocBuilder<'a, BoxAllocator, ()> {
allocator
Expand Down
22 changes: 21 additions & 1 deletion cynic-parser/src/schema.lalrpop
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ pub DefinitionAndDescription: (Option<StringId>, DefinitionId) = {
pub TypeSystemDefinition: DefinitionId = {
<def:SchemaDefinition> => ast.schema_definition(def),
<def:ObjectDefinition> => ast.object_definition(def),
<def:InputObjectDefinition> => ast.input_object_definition(def)
<def:InterfaceDefinition> => ast.interface_definition(def),
<def:InputObjectDefinition> => ast.input_object_definition(def),
}

pub SchemaDefinition: SchemaDefinition = {
Expand Down Expand Up @@ -88,6 +89,23 @@ ArgumentsDefinition: Vec<InputValueDefinitionId> = {
"(" <arguments:InputValueDefinition+> ")" => arguments,
};

pub InterfaceDefinition: InterfaceDefinition = {
<start:@L> interface
<name:Name>
<implements:ImplementsInterfaces?>
<directives:Directive*>
<fields:FieldsDefinition?>
<end:@R>
=> InterfaceDefinition {
name,
directives,
implements: implements.unwrap_or_default(),
fields: fields.unwrap_or_default(),
span: Span::new(start,end)
}
};


pub InputObjectDefinition: InputObjectDefinition = {
<start:@L> input
<name:Name>
Expand Down Expand Up @@ -206,6 +224,7 @@ Ident: &'input str = {
false => "false",
null => "null",
implements => "implements",
interface => "interface",
}

extern {
Expand Down Expand Up @@ -248,5 +267,6 @@ extern {
false => lexer::Token::False,
null => lexer::Token::Null,
implements => lexer::Token::Implements,
interface => lexer::Token::Interface,
}
}

0 comments on commit f5f9c9a

Please sign in to comment.