Skip to content

Commit

Permalink
Parse more directives & implements in cynic-parser (#804)
Browse files Browse the repository at this point in the history
  • Loading branch information
obmarg authored Jan 7, 2024
1 parent dab97cb commit 2f4f6ad
Show file tree
Hide file tree
Showing 6 changed files with 85 additions and 15 deletions.
3 changes: 3 additions & 0 deletions cynic-parser/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,13 +58,15 @@ pub struct ObjectDefinition {
pub name: StringId,
pub fields: Vec<NodeId>,
pub directives: Vec<DirectiveId>,
pub implements: Vec<StringId>,
}

pub struct FieldDefinition {
pub name: StringId,
pub ty: TypeId,
pub arguments: Vec<NodeId>,
pub description: Option<NodeId>,
pub directives: Vec<DirectiveId>,
}

pub struct InputObjectDefinition {
Expand All @@ -78,6 +80,7 @@ pub struct InputValueDefinition {
pub ty: TypeId,
pub description: Option<NodeId>,
pub default: Option<ValueId>,
pub directives: Vec<DirectiveId>,
}

pub struct RootOperationTypeDefinition {
Expand Down
24 changes: 24 additions & 0 deletions cynic-parser/src/ast/reader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,14 @@ impl<'a> AstReader<'a, ObjectDefinitionId> {
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)
Expand Down Expand Up @@ -129,6 +137,14 @@ impl<'a> AstReader<'a, FieldDefinitionId> {
}
})
}

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, InputValueDefinitionId> {
Expand All @@ -143,6 +159,14 @@ impl<'a> AstReader<'a, InputValueDefinitionId> {
pub fn default_value(&self) -> Option<AstReader<'a, ValueId>> {
self.ast.lookup(self.id).default.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, DirectiveId> {
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 @@ -98,6 +98,9 @@ pub enum Token<'a> {
#[token("null")]
Null,

#[token("implements")]
Implements,

// IntegerPart: -?(0|[1-9][0-9]*)
// FractionalPart: \\.[0-9]+
// ExponentPart: [eE][+-]?[0-9]+
Expand Down Expand Up @@ -262,6 +265,7 @@ impl fmt::Display for Token<'_> {
Token::True => "true",
Token::False => "false",
Token::Null => "null,",
Token::Implements => "implements",
};
f.write_str(message)
}
Expand Down
11 changes: 8 additions & 3 deletions cynic-parser/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,15 @@ mod tests {
#[test]
fn test_basic_object() {
insta::assert_snapshot!(
parse_type_system_document("type MyType @hello { field: Whatever, other: [[Int!]]! }").to_sdl(),
parse_type_system_document(r#"
type MyType implements Blah & Bloo @hello {
field: Whatever @hello(name: ["string"]),
other: [[Int!]]!
}"#
).to_sdl(),
@r###"
type MyType @hello {
field: Whatever
type MyType implements Blah & Bloo @hello {
field: Whatever@hello(name: ("string"))
other: [[Int!]]!
}
"###
Expand Down
19 changes: 16 additions & 3 deletions cynic-parser/src/printer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,21 @@ impl<'a> Pretty<'a, BoxAllocator> for NodeDisplay<'a, SchemaDefinitionId> {

impl<'a> Pretty<'a, BoxAllocator> for NodeDisplay<'a, ObjectDefinitionId> {
fn pretty(self, allocator: &'a BoxAllocator) -> pretty::DocBuilder<'a, BoxAllocator, ()> {
allocator
let mut builder = allocator
.text(format!("type {}", self.0.name()))
.append(allocator.space())
.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("{"))
Expand All @@ -91,6 +103,7 @@ impl<'a> Pretty<'a, BoxAllocator> for NodeDisplay<'a, FieldDefinitionId> {
.append(allocator.text(":"))
.append(allocator.space())
.append(NodeDisplay(self.0.ty()))
.append(allocator.intersperse(self.0.directives().map(NodeDisplay), " "))
}
}

Expand Down Expand Up @@ -130,7 +143,7 @@ impl<'a> Pretty<'a, BoxAllocator> for NodeDisplay<'a, InputValueDefinitionId> {
.append(NodeDisplay(value));
}

builder
builder.append(allocator.intersperse(self.0.directives().map(NodeDisplay), " "))
}
}

Expand Down
39 changes: 30 additions & 9 deletions cynic-parser/src/schema.lalrpop
Original file line number Diff line number Diff line change
Expand Up @@ -32,24 +32,42 @@ pub RootOperationTypeDefinition: RootOperationTypeDefinition = {
}

pub ObjectDefinition: ObjectDefinition = {
ty <name:Name> <directives:Directive*> <fields:FieldsDefinition?> => ObjectDefinition {
ty <name:Name> <implements:ImplementsInterfaces?> <directives:Directive*> <fields:FieldsDefinition?> => ObjectDefinition {
name,
directives,
implements: implements.unwrap_or_default(),
fields: fields.unwrap_or_default ()
}
};

ImplementsInterfaces: Vec<StringId> = {
<interfaces:ImplementsInterfaces> "&" <name:NamedType> => {
let mut interfaces = interfaces;
interfaces.push(name);
interfaces
},
implements "&"? <name:NamedType> => {
vec![name]
}
}

ImplementItem: StringId = {
"&" <name:NamedType> => name,
}

FieldsDefinition: Vec<NodeId> = {
"{" <fields:FieldDefinition+> "}" => fields
};

FieldDefinition: NodeId = {
<description:StringValue?> <name:Name> <arguments:ArgumentsDefinition?> ":" <ty:Type> => ast.field_definition(FieldDefinition {
name,
ty,
arguments: arguments.unwrap_or_default(),
description,
})
<description:StringValue?> <name:Name> <arguments:ArgumentsDefinition?> ":" <ty:Type> <directives:Directive*> =>
ast.field_definition(FieldDefinition {
name,
ty,
arguments: arguments.unwrap_or_default(),
description,
directives
})
};

ArgumentsDefinition: Vec<NodeId> = {
Expand All @@ -68,9 +86,9 @@ InputFieldsDefinition: Vec<NodeId> = {
"{" <fields:InputValueDefinition+> "}" => fields
};

// TODO: Add directives
InputValueDefinition: NodeId =
<description:StringValue?> <name:Name> ":" <ty:Type> <default:DefaultValue?> => ast.input_value_definition(InputValueDefinition { <> });
<description:StringValue?> <name:Name> ":" <ty:Type> <default:DefaultValue?> <directives:Directive*> =>
ast.input_value_definition(InputValueDefinition { <> });

DefaultValue: ValueId = {
"=" <v:Value> => v
Expand Down Expand Up @@ -158,6 +176,7 @@ Ident: &'input str = {
true => "true",
false => "false",
null => "null",
implements => "implements",
}

extern {
Expand All @@ -181,6 +200,7 @@ extern {
"!" => lexer::Token::Exclamation,
"=" => lexer::Token::Equals,
"@" => lexer::Token::At,
"&" => lexer::Token::Ampersand,

RawIdent => lexer::Token::Identifier(<&'input str>),

Expand All @@ -198,5 +218,6 @@ extern {
true => lexer::Token::True,
false => lexer::Token::False,
null => lexer::Token::Null,
implements => lexer::Token::Implements,
}
}

0 comments on commit 2f4f6ad

Please sign in to comment.