Skip to content

Commit

Permalink
feat: support extend keyword
Browse files Browse the repository at this point in the history
  • Loading branch information
gabotechs committed Oct 12, 2023
1 parent a835ede commit 9c81b2a
Show file tree
Hide file tree
Showing 29 changed files with 732 additions and 464 deletions.
556 changes: 321 additions & 235 deletions Cargo.lock

Large diffs are not rendered by default.

5 changes: 2 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,10 @@ categories = ["language", "compilers"]
license = "MIT"
readme = "README.md"
repository = "https://github.com/gabotechs/graphqxl"
keywords = ["graphql", "graphqxl", "schemas", "server", "api", "language"]
keywords = ["graphql", "schemas", "server", "api", "language"]

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html


[workspace]
members = [
"graphqxl_parser",
Expand All @@ -22,7 +21,7 @@ members = [
[dependencies]
clap = { version = "4.0.22", features = ["derive"] }
anyhow = "1.0.63"
apollo-compiler = "0.3.0"
apollo-compiler = "0.11.3"
graphqxl_parser = { path = "graphqxl_parser" }
graphqxl_transpiler = { path = "graphqxl_transpiler" }
graphqxl_synthesizer = { path = "graphqxl_synthesizer" }
Expand Down
5 changes: 3 additions & 2 deletions graphqxl_parser/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
pest = "2.3.1"
pest_derive = "2.3.1"
pest = "2.7.4"
pest_derive = "2.7.4"
indexmap = "1.9.1"
uuid = { version = "1.4.1", features = ["v4"]}

2 changes: 1 addition & 1 deletion graphqxl_parser/src/ast_arguments.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ fn parse_argument(pair: Pair<Rule>, file: &str) -> Result<Argument, Box<RuleErro
let DescriptionAndNext(description, next) =
parse_description_and_continue(&mut childs, file);
// at this moment we are on [identifier, value]
let name = parse_identifier(next, file)?;
let name = parse_identifier(next.unwrap(), file)?;
let value = parse_value_type(childs.next().unwrap(), file)?;
let mut default = None;
let mut directives = Vec::new();
Expand Down
34 changes: 18 additions & 16 deletions graphqxl_parser/src/ast_block_def.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ pub enum BlockEntry {

#[derive(Debug, Clone, PartialEq)]
pub struct BlockDef {
pub extend: bool,
pub span: OwnedSpan,
pub name: Identifier,
pub generic: Option<Generic>,
Expand All @@ -55,6 +56,7 @@ pub struct BlockDef {
impl BlockDef {
fn build(name: &str, kind: BlockDefType) -> Self {
Self {
extend: false,
span: OwnedSpan::default(),
name: Identifier::from(name),
generic: None,
Expand Down Expand Up @@ -120,11 +122,17 @@ impl BlockDef {
self.directives.push(directive);
self.clone()
}

pub fn extend(&mut self) -> Self {
self.extend = true;
self.clone()
}
}

fn _parse_block_def(
pair: Pair<Rule>,
kind: BlockDefType,
extend: bool,
file: &str,
) -> Result<BlockDef, Box<RuleError>> {
let span = OwnedSpan::from(pair.as_span(), file);
Expand Down Expand Up @@ -179,6 +187,7 @@ fn _parse_block_def(
}
}
Ok(BlockDef {
extend,
span,
name,
generic,
Expand All @@ -193,10 +202,14 @@ fn _parse_block_def(

pub(crate) fn parse_block_def(pair: Pair<Rule>, file: &str) -> Result<BlockDef, Box<RuleError>> {
match pair.as_rule() {
Rule::type_def => _parse_block_def(pair, BlockDefType::Type, file),
Rule::input_def => _parse_block_def(pair, BlockDefType::Input, file),
Rule::enum_def => _parse_block_def(pair, BlockDefType::Enum, file),
Rule::interface_def => _parse_block_def(pair, BlockDefType::Interface, file),
Rule::type_def => _parse_block_def(pair, BlockDefType::Type, false, file),
Rule::type_ext => _parse_block_def(pair, BlockDefType::Type, true, file),
Rule::input_def => _parse_block_def(pair, BlockDefType::Input, false, file),
Rule::input_ext => _parse_block_def(pair, BlockDefType::Input, true, file),
Rule::enum_def => _parse_block_def(pair, BlockDefType::Enum, false, file),
Rule::enum_ext => _parse_block_def(pair, BlockDefType::Enum, true, file),
Rule::interface_def => _parse_block_def(pair, BlockDefType::Interface, false, file),
Rule::interface_ext => _parse_block_def(pair, BlockDefType::Interface, true, file),
_unknown => Err(unknown_rule_error(
pair,
"type_def, input_def, enum_def or interface_def",
Expand All @@ -211,18 +224,7 @@ mod tests {
use crate::ValueType;

fn parse_input(input: &str) -> Result<BlockDef, Box<RuleError>> {
let rule = if input.contains("input ") {
Rule::input_def
} else if input.contains("type ") {
Rule::type_def
} else if input.contains("enum ") {
Rule::enum_def
} else if input.contains("interface ") {
Rule::interface_def
} else {
Rule::type_def
};
parse_full_input(input, rule, parse_block_def)
parse_full_input(input, Rule::def, parse_block_def)
}

#[test]
Expand Down
2 changes: 1 addition & 1 deletion graphqxl_parser/src/ast_block_field.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ fn _parse_block_field(pair: Pair<Rule>, file: &str) -> Result<BlockField, Box<Ru
let mut pairs = pair.into_inner();
// at this moment we are on [description?, identifier, args?, value?]
let DescriptionAndNext(description, next) = parse_description_and_continue(&mut pairs, file);
let name = parse_identifier(next, file)?;
let name = parse_identifier(next.unwrap(), file)?;
let mut block_field = BlockField {
span,
name,
Expand Down
16 changes: 10 additions & 6 deletions graphqxl_parser/src/ast_description.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,19 +18,23 @@ pub(crate) fn parse_description(pair: Pair<Rule>, _file: &str) -> Result<String,
}

#[derive(Debug, Clone, PartialEq)]
pub(crate) struct DescriptionAndNext<'a>(pub(crate) String, pub(crate) Pair<'a, Rule>);
pub(crate) struct DescriptionAndNext<'a>(pub(crate) String, pub(crate) Option<Pair<'a, Rule>>);

pub(crate) fn parse_description_and_continue<'a>(
pairs: &mut Pairs<'a, Rule>,
file: &str,
) -> DescriptionAndNext<'a> {
let mut pair = pairs.next().unwrap();
let mut pair_opt = pairs.next();
let mut description = "".to_string();
if let Rule::description = pair.as_rule() {
description = parse_description(pair, file).unwrap();
pair = pairs.next().unwrap();
if let Some(pair) = pair_opt {
if let Rule::description = pair.as_rule() {
description = parse_description(pair, file).unwrap();
pair_opt = pairs.next();
} else {
pair_opt = Some(pair)
}
}
DescriptionAndNext(description, pair)
DescriptionAndNext(description, pair_opt)
}

#[cfg(test)]
Expand Down
2 changes: 1 addition & 1 deletion graphqxl_parser/src/ast_directive_def.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ pub(crate) fn parse_directive_def(
let mut childs = pair.into_inner();
let DescriptionAndNext(description, next) =
parse_description_and_continue(&mut childs, file);
let name = parse_identifier(next, file)?;
let name = parse_identifier(next.unwrap(), file)?;
let mut next = childs.next().unwrap();
let mut arguments = Vec::new();
if let Rule::arguments = next.as_rule() {
Expand Down
6 changes: 6 additions & 0 deletions graphqxl_parser/src/ast_identifier.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@ impl Identifier {
span: OwnedSpan::default(),
}
}

pub fn extend(id: &Self) -> Self {
let mut clone = id.clone();
clone.id = format!("{}__extend__{}", clone.id, uuid::Uuid::new_v4());
clone
}
}

pub(crate) fn parse_identifier(pair: Pair<Rule>, file: &str) -> Result<Identifier, Box<RuleError>> {
Expand Down
30 changes: 24 additions & 6 deletions graphqxl_parser/src/ast_scalar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use pest::iterators::Pair;

#[derive(Debug, Clone, PartialEq, Default)]
pub struct Scalar {
pub extend: bool,
pub span: OwnedSpan,
pub name: Identifier,
pub description: String,
Expand All @@ -30,27 +31,36 @@ impl Scalar {
self.directives.push(directive);
self.clone()
}

pub fn extend(&mut self) -> Self {
self.extend = true;
self.clone()
}
}

pub(crate) fn parse_scalar(pair: Pair<Rule>, file: &str) -> Result<Scalar, Box<RuleError>> {
match pair.as_rule() {
Rule::scalar_def => {
fn _parse_scalar(pair: Pair<Rule>, file: &str, extend: bool) -> Result<Scalar, Box<RuleError>> {
let span = OwnedSpan::from(pair.as_span(), file);
let mut childs = pair.into_inner();
let DescriptionAndNext(description, next) =
parse_description_and_continue(&mut childs, file);
let name = parse_identifier(next, file)?;
let name = parse_identifier(next.unwrap(), file)?;
let mut directives = Vec::new();
for child in childs {
directives.push(parse_directive(child, file)?);
}
Ok(Scalar {
extend,
span,
name,
description,
directives,
})
}
}

pub(crate) fn parse_scalar(pair: Pair<Rule>, file: &str) -> Result<Scalar, Box<RuleError>> {
match pair.as_rule() {
Rule::scalar_def => _parse_scalar(pair, file, false),
Rule::scalar_ext => _parse_scalar(pair, file, true),
_unknown => Err(unknown_rule_error(pair, "scalar_def")),
}
}
Expand All @@ -61,7 +71,7 @@ mod tests {
use crate::utils::parse_full_input;

fn parse_input(input: &str) -> Result<Scalar, Box<RuleError>> {
parse_full_input(input, Rule::scalar_def, parse_scalar)
parse_full_input(input, Rule::def, parse_scalar)
}

#[test]
Expand All @@ -80,6 +90,14 @@ mod tests {
);
}

#[test]
fn test_parses_scalar_extension() {
assert_eq!(
parse_input("extend scalar MyScalar"),
Ok(Scalar::build("MyScalar").extend())
);
}

#[test]
fn test_accepts_directives() {
assert_eq!(
Expand Down
88 changes: 55 additions & 33 deletions graphqxl_parser/src/ast_schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use pest::iterators::Pair;

#[derive(Debug, Clone, PartialEq, Default)]
pub struct Schema {
pub extend: bool,
pub span: OwnedSpan,
pub description: String,
pub directives: Vec<Directive>,
Expand Down Expand Up @@ -45,6 +46,11 @@ impl Schema {
self.directives.push(directive);
self.clone()
}

pub fn extend(&mut self) -> Self {
self.extend = true;
self.clone()
}
}

enum SchemaKey {
Expand All @@ -67,40 +73,51 @@ fn parse_schema_key(pair: Pair<Rule>, _file: &str) -> Result<SchemaKey, Box<Rule
}
}

pub(crate) fn parse_schema(pair: Pair<Rule>, file: &str) -> Result<Schema, Box<RuleError>> {
match pair.as_rule() {
Rule::schema_def => {
let span = OwnedSpan::from(pair.as_span(), file);
let mut childs = pair.into_inner();
let DescriptionAndNext(description, mut next) =
parse_description_and_continue(&mut childs, file);
let mut query = Identifier::from("");
let mut mutation = Identifier::from("");
let mut subscription = Identifier::from("");
let mut directives = vec![];
while let Rule::directive = next.as_rule() {
directives.push(parse_directive(next, file)?);
next = childs.next().unwrap();
}
for field in next.into_inner() {
let mut field_parts = field.into_inner();
let key = parse_schema_key(field_parts.next().unwrap(), file)?;
let value = parse_identifier(field_parts.next().unwrap(), file)?;
match key {
SchemaKey::Query => query = value,
SchemaKey::Mutation => mutation = value,
SchemaKey::Subscription => subscription = value,
}
fn _parse_schema(pair: Pair<Rule>, file: &str, extend: bool) -> Result<Schema, Box<RuleError>> {
let span = OwnedSpan::from(pair.as_span(), file);
let mut query = Identifier::from("");
let mut mutation = Identifier::from("");
let mut subscription = Identifier::from("");
let mut directives = vec![];
let mut childs = pair.into_inner();
let DescriptionAndNext(description, mut next_opt) =
parse_description_and_continue(&mut childs, file);

while let Some(next) = next_opt.clone() {
if Rule::directive != next.as_rule() {
break;
}
directives.push(parse_directive(next, file)?);
next_opt = childs.next();
}

if let Some(next) = next_opt {
for field in next.into_inner() {
let mut field_parts = field.into_inner();
let key = parse_schema_key(field_parts.next().unwrap(), file)?;
let value = parse_identifier(field_parts.next().unwrap(), file)?;
match key {
SchemaKey::Query => query = value,
SchemaKey::Mutation => mutation = value,
SchemaKey::Subscription => subscription = value,
}
Ok(Schema {
span,
directives,
description,
query,
mutation,
subscription,
})
}
}
Ok(Schema {
extend,
span,
directives,
description,
query,
mutation,
subscription,
})
}

pub(crate) fn parse_schema(pair: Pair<Rule>, file: &str) -> Result<Schema, Box<RuleError>> {
match pair.as_rule() {
Rule::schema_def => _parse_schema(pair, file, false),
Rule::schema_ext => _parse_schema(pair, file, true),
_unknown => Err(unknown_rule_error(pair, "schema")),
}
}
Expand All @@ -111,7 +128,7 @@ mod tests {
use crate::utils::parse_full_input;

fn parse_input(input: &str) -> Result<Schema, Box<RuleError>> {
parse_full_input(input, Rule::schema_def, parse_schema)
parse_full_input(input, Rule::def, parse_schema)
}

#[test]
Expand All @@ -122,6 +139,11 @@ mod tests {
)
}

#[test]
fn test_empty_schema_extension() {
assert_eq!(parse_input("extend schema"), Ok(Schema::build().extend()))
}

#[test]
fn test_accepts_directive() {
assert_eq!(
Expand Down
Loading

0 comments on commit 9c81b2a

Please sign in to comment.