From a50936f2644d809ee264aa7a44aa94b769789455 Mon Sep 17 00:00:00 2001 From: Soispha Date: Sun, 24 Mar 2024 19:57:32 +0100 Subject: [PATCH] feat(parser): Associate a vector of nasps with every struct, enum, nasp This feature makes it possible to generate these types actually in namespaces and not only in one toplevel. --- trixy-parser/src/command_spec/checked.rs | 18 +++++++--- trixy-parser/src/command_spec/unchecked.rs | 4 ++- trixy-parser/src/lexing/mod.rs | 16 +++------ trixy-parser/src/parsing/checked/error.rs | 14 ++++++++ trixy-parser/src/parsing/checked/mod.rs | 37 +++++++++++++------ trixy-parser/src/parsing/checked/test.rs | 22 ++++++------ trixy-parser/src/parsing/unchecked/mod.rs | 41 ++++++++++++++++------ 7 files changed, 104 insertions(+), 48 deletions(-) diff --git a/trixy-parser/src/command_spec/checked.rs b/trixy-parser/src/command_spec/checked.rs index 078e5dc..36ff31f 100644 --- a/trixy-parser/src/command_spec/checked.rs +++ b/trixy-parser/src/command_spec/checked.rs @@ -27,15 +27,23 @@ use crate::lexing::TokenKind; use super::unchecked::{self, DeriveValue}; -#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)] +#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)] pub enum Variant { - Structure, - Enumeration, + Structure { + namespace: Vec, + }, + Enumeration { + namespace: Vec, + }, Namespace, + /// The first (implicit) namespace, containing everything + RootNamespace, Function, - NamedType, Primitive, + NamedType, DocNamedType, + + /// Implicit default, this is not something that _should_ ever be exposed to the public API Void, } @@ -278,7 +286,7 @@ impl From<&DocIdentifier> for Identifier { fn from(value: &DocIdentifier) -> Self { Self { name: value.name.to_owned(), - variant: value.variant, + variant: value.variant.clone(), } } } diff --git a/trixy-parser/src/command_spec/unchecked.rs b/trixy-parser/src/command_spec/unchecked.rs index 648a670..4d45b4d 100644 --- a/trixy-parser/src/command_spec/unchecked.rs +++ b/trixy-parser/src/command_spec/unchecked.rs @@ -38,7 +38,7 @@ pub struct CommandSpec { impl From for Namespace { fn from(value: CommandSpec) -> Self { Self { - name: Token::get_dummy(), + name: Token::default(), functions: value.functions, structures: value.structures, enumerations: value.enumerations, @@ -144,6 +144,7 @@ pub struct Structure { pub identifier: Token, // Will later become an Identifier pub contents: Vec, pub attributes: Vec, + pub namespaces: Vec, // Will later become an Identifier } #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)] @@ -151,6 +152,7 @@ pub struct Enumeration { pub identifier: Token, // Will later become an Identifier pub states: Vec, // Will later become an Identifier pub attributes: Vec, + pub namespaces: Vec, // Will later become an Identifier } #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)] diff --git a/trixy-parser/src/lexing/mod.rs b/trixy-parser/src/lexing/mod.rs index febd2bc..1c84dd9 100644 --- a/trixy-parser/src/lexing/mod.rs +++ b/trixy-parser/src/lexing/mod.rs @@ -149,14 +149,6 @@ impl Token { pub fn span(&self) -> &TokenSpan { &self.span } - - /// Get a dummy token, this is intended for error handling - pub fn get_dummy() -> Token { - Self { - span: TokenSpan { start: 0, end: 0 }, - kind: TokenKind::Dummy, - } - } } /// Possibly kinds of tokens @@ -184,9 +176,10 @@ pub enum TokenKind { Comment(String), - /// This is not a real TokenKind, but only used for error handling #[default] - Dummy, + /// This tokenkind is here support usages of [`mem::take`], this should never be exposed in the + /// final parsed output. + DefaultTokenKind, } impl TokenKind { @@ -233,7 +226,6 @@ impl Display for TokenKind { TokenKind::Semicolon => f.write_str("SEMICOLON"), TokenKind::Comma => f.write_str("COMMA"), TokenKind::Arrow => f.write_str("ARROW"), - TokenKind::Dummy => f.write_str("DUMMY"), TokenKind::StringLiteral(text) => write!(f, r#"STRING_LITERAL("{}")"#, text), TokenKind::CurlyBracketOpen => f.write_str("CURLY_BRACKET_OPEN"), @@ -244,6 +236,8 @@ impl Display for TokenKind { TokenKind::AngledBracketClose => f.write_str("ANGLED_BRACKET_CLOSE"), TokenKind::SquareBracketOpen => f.write_str("SQUARE_BRACKET_OPEN"), TokenKind::SquareBracketClose => f.write_str("SQUARE_BRACKET_CLOSE"), + + TokenKind::DefaultTokenKind => f.write_str("DEFAULT_TOKEN_KIND"), TokenKind::Comment(text) => write!(f, "COMMENT({})", text), } } diff --git a/trixy-parser/src/parsing/checked/error.rs b/trixy-parser/src/parsing/checked/error.rs index 13a1e49..bb6bafc 100644 --- a/trixy-parser/src/parsing/checked/error.rs +++ b/trixy-parser/src/parsing/checked/error.rs @@ -68,6 +68,16 @@ pub enum ParsingError { specified: Attribute, span: TokenSpan, }, + #[error("The structure named: {structure} has been used multiple times")] + StructureCopied { + structure: Identifier, + span: TokenSpan, + }, + #[error("The enumeration named: {enumeration} has been used multiple times")] + EnumerationCopied { + enumeration: Identifier, + span: TokenSpan, + }, } impl ParsingError { @@ -80,6 +90,8 @@ impl ParsingError { ParsingError::NotEnoughGenericArgs { span, .. } => span, ParsingError::TooManyGenericArgs { span, .. } => span, ParsingError::WrongAttributeInPosition { span, .. } => span, + ParsingError::StructureCopied { span, .. } => span, + ParsingError::EnumerationCopied { span, .. } => span, } } } @@ -94,6 +106,8 @@ impl AdditionalHelp for ParsingError { ParsingError::NotEnoughGenericArgs { got, expected_min, .. } => format!("Add generic args until you have gone from {} to {}", got, expected_min), ParsingError::TooManyGenericArgs { got, expected_max, .. } => format!("Remove generic args until you have gone from {} to {}", got, expected_max), ParsingError::WrongAttributeInPosition { .. } => format!("Remove this attribute"), + ParsingError::StructureCopied {..} => format!("Change this name to be something else, or delete the struct"), + ParsingError::EnumerationCopied {..} => format!("Change this name to be something else, or delete the enum"), } } } diff --git a/trixy-parser/src/parsing/checked/mod.rs b/trixy-parser/src/parsing/checked/mod.rs index 8f35790..5a76b2c 100644 --- a/trixy-parser/src/parsing/checked/mod.rs +++ b/trixy-parser/src/parsing/checked/mod.rs @@ -106,7 +106,8 @@ impl Parser { fn parse(mut self) -> Result { let namespace: UncheckedNamespace = UncheckedNamespace::from(mem::take(&mut self.command_spec)); - let namespace = self.process_namespace(namespace).map_err(|err| { + + let namespace = self.process_namespace(namespace, vec![]).map_err(|err| { let span = *err.span(); SpannedParsingError { source: Box::new(err), @@ -119,6 +120,7 @@ impl Parser { fn process_namespace( &mut self, namespace: UncheckedNamespace, + previous_namespaces: Vec, ) -> Result { let namespace_span = namespace.name.span; let name = match namespace.name.kind { @@ -126,24 +128,33 @@ impl Parser { name: ident, variant: Variant::Namespace, }, - // This is not really used, so the value put here does not matter - TokenKind::Dummy => Identifier { - name: "".to_owned(), - variant: Variant::Void, + // This is the first (implicit) root namespace + TokenKind::DefaultTokenKind => Identifier { + name: "".to_owned(), + variant: Variant::RootNamespace, }, _ => unreachable!("This should never be more than these two enum veriants"), }; + let previous_namespaces = previous_namespaces + .into_iter() + .chain(iter::once(name.clone())) + .collect(); let mut enumerations = vec![]; let mut enumerations_counter = 0; for enumeration in namespace.enumerations { - enumerations.push(self.process_enumeration(enumeration, &name, namespace_span)?); + enumerations.push(self.process_enumeration( + enumeration, + &name, + namespace_span, + &previous_namespaces, + )?); enumerations_counter += 1; } let mut structures = vec![]; let mut structures_counter = 0; for structure in namespace.structures { - structures.push(self.process_structure(structure)?); + structures.push(self.process_structure(structure, &previous_namespaces)?); structures_counter += 1; } @@ -153,7 +164,7 @@ impl Parser { } let mut namespaces = vec![]; for namespace in namespace.namespaces { - namespaces.push(self.process_namespace(namespace)?); + namespaces.push(self.process_namespace(namespace, previous_namespaces.clone())?); } // Remove added enums and structs again @@ -202,12 +213,15 @@ impl Parser { mut enumeration: UncheckedEnumeration, namespace_name: &Identifier, namespace_span: TokenSpan, + parent_namespaces: &Vec, ) -> Result { self.enumerations.push(enumeration.clone()); let enum_span = enumeration.identifier.span; let identifier: Identifier = - mem::take(&mut enumeration.identifier.kind).to_identifier(Variant::Enumeration); + mem::take(&mut enumeration.identifier.kind).to_identifier(Variant::Enumeration { + namespace: parent_namespaces.clone(), + }); if &identifier == namespace_name { return Err(ParsingError::EnumWithNamespaceName { name: identifier.clone(), @@ -246,11 +260,14 @@ impl Parser { fn process_structure( &mut self, mut structure: UncheckedStructure, + parent_namespaces: &Vec, ) -> Result { self.structures.push(structure.clone()); let identifier: Identifier = - mem::take(&mut structure.identifier.kind).to_identifier(Variant::Structure); + mem::take(&mut structure.identifier.kind).to_identifier(Variant::Structure { + namespace: parent_namespaces.clone(), + }); let mut contents = vec![]; for named_type in structure.contents { contents.push(self.process_doc_named_type(named_type)?); diff --git a/trixy-parser/src/parsing/checked/test.rs b/trixy-parser/src/parsing/checked/test.rs index a0468cd..ef6e7a5 100644 --- a/trixy-parser/src/parsing/checked/test.rs +++ b/trixy-parser/src/parsing/checked/test.rs @@ -33,7 +33,7 @@ fn test_full() { let input = " mod trinitrix { struct Callback { - func: void, + func: u32, timeout: u8, } @@ -77,7 +77,7 @@ mod trinitrix { r#type: Type { identifier: Identifier { name: "Callback".to_owned(), - variant: Variant::Type, + variant: Variant::Structure, }, generic_args: vec![], }, @@ -90,7 +90,7 @@ mod trinitrix { r#type: Type { identifier: Identifier { name: "CallbackPriority".to_owned(), - variant: Variant::Type, + variant: Variant::Enumeration, }, generic_args: vec![], }, @@ -112,8 +112,8 @@ mod trinitrix { }, r#type: Type { identifier: Identifier { - name: "()".to_owned(), - variant: Variant::Type, + name: "u32".to_owned(), + variant: Variant::Primitive, }, generic_args: vec![], }, @@ -127,7 +127,7 @@ mod trinitrix { r#type: Type { identifier: Identifier { name: "u8".to_owned(), - variant: Variant::Type, + variant: Variant::Primitive, }, generic_args: vec![], }, @@ -188,8 +188,8 @@ fn execute_callback(callback: Name); assert_eq!( r#type, Identifier { - name: "Name".to_owned(), - variant: Variant::Type, + name: "void".to_owned(), + variant: Variant::Void, } ) } @@ -230,7 +230,7 @@ mod trinitrix { r#type: Type { identifier: Identifier { name: "String".to_owned(), - variant: Variant::Type, + variant: Variant::Primitive, }, generic_args: vec![], }, @@ -256,7 +256,7 @@ mod trinitrix { r#type: Type { identifier: Identifier { name: "String".to_owned(), - variant: Variant::Type, + variant: Variant::Primitive, }, generic_args: vec![], }, @@ -264,7 +264,7 @@ mod trinitrix { output: Some(Type { identifier: Identifier { name: "String".to_owned(), - variant: Variant::Type, + variant: Variant::Primitive, }, generic_args: vec![], }), diff --git a/trixy-parser/src/parsing/unchecked/mod.rs b/trixy-parser/src/parsing/unchecked/mod.rs index 43dcb7d..c362b1e 100644 --- a/trixy-parser/src/parsing/unchecked/mod.rs +++ b/trixy-parser/src/parsing/unchecked/mod.rs @@ -63,7 +63,7 @@ impl Parser { fn parse(&mut self) -> Result { let mut output = CommandSpec::default(); while !self.token_stream.is_empty() { - let next = self.parse_next().map_err(|err| { + let next = self.parse_next(&vec![]).map_err(|err| { let span = err.get_span(); SpannedParsingError { source: Box::new(err), @@ -81,14 +81,20 @@ impl Parser { Ok(output) } - fn parse_next(&mut self) -> Result { + fn parse_next(&mut self, current_namespaces: &Vec) -> Result { // Use of [peek_raw] here is fine, as we know that the function is only called, when // something should still be contained in the token stream match self.peek_raw().kind() { - token![mod] => Ok(Declaration::Namespace(self.parse_namespace()?)), + token![mod] => Ok(Declaration::Namespace( + self.parse_namespace(current_namespaces.to_owned())?, + )), token![fn] => Ok(Declaration::Function(self.parse_function()?)), - token![struct] => Ok(Declaration::Structure(self.parse_structure()?)), - token![enum] => Ok(Declaration::Enumeration(self.parse_enumeration()?)), + token![struct] => Ok(Declaration::Structure( + self.parse_structure(current_namespaces.clone())?, + )), + token![enum] => Ok(Declaration::Enumeration( + self.parse_enumeration(current_namespaces.to_owned())?, + )), token![#] => { let attributes = self.parse_attributes()?; self.current_attributes.extend(attributes); @@ -107,7 +113,7 @@ impl Parser { span, }) } else { - self.parse_next() + self.parse_next(current_namespaces) } } _ => { @@ -239,7 +245,10 @@ impl Parser { Ok(attrs) } - fn parse_namespace(&mut self) -> Result { + fn parse_namespace( + &mut self, + previous_namespaces: Vec, + ) -> Result { let attributes = self.parse_attributes()?; self.expect(token![mod])?; @@ -248,11 +257,15 @@ impl Parser { attributes, ..Default::default() }; + let current_namespaces: Vec<_> = previous_namespaces + .into_iter() + .chain(once(namespace.name.clone())) + .collect(); self.expect(token![CurlyBracketOpen])?; while !self.expect_peek(token![CurlyBracketClose]) { - let next = self.parse_next()?; + let next = self.parse_next(¤t_namespaces)?; match next { Declaration::Function(function) => namespace.functions.push(function), Declaration::Structure(structure) => namespace.structures.push(structure), @@ -267,7 +280,10 @@ impl Parser { Ok(namespace) } - fn parse_enumeration(&mut self) -> Result { + fn parse_enumeration( + &mut self, + current_namespaces: Vec, + ) -> Result { let attributes = self.parse_attributes()?; self.expect(token![enum])?; let identifier = self.expect(token![Ident])?; @@ -299,10 +315,14 @@ impl Parser { identifier, states, attributes, + namespaces: current_namespaces, }) } - fn parse_structure(&mut self) -> Result { + fn parse_structure( + &mut self, + current_namespaces: Vec, + ) -> Result { let attributes = self.parse_attributes()?; self.expect(token![struct])?; let name = self.expect(token![Ident])?; @@ -326,6 +346,7 @@ impl Parser { identifier: name, contents, attributes, + namespaces: current_namespaces, }) }