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.
This commit is contained in:
Benedikt Peetz 2024-03-24 19:57:32 +01:00
parent 4a32f0d2f4
commit 3c3ee23c2b
Signed by: bpeetz
GPG Key ID: A5E94010C3A642AD
7 changed files with 104 additions and 48 deletions

View File

@ -27,15 +27,23 @@ use crate::lexing::TokenKind;
use super::unchecked::{self, DeriveValue}; use super::unchecked::{self, DeriveValue};
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)] #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
pub enum Variant { pub enum Variant {
Structure, Structure {
Enumeration, namespace: Vec<Identifier>,
},
Enumeration {
namespace: Vec<Identifier>,
},
Namespace, Namespace,
/// The first (implicit) namespace, containing everything
RootNamespace,
Function, Function,
NamedType,
Primitive, Primitive,
NamedType,
DocNamedType, DocNamedType,
/// Implicit default, this is not something that _should_ ever be exposed to the public API
Void, Void,
} }
@ -278,7 +286,7 @@ impl From<&DocIdentifier> for Identifier {
fn from(value: &DocIdentifier) -> Self { fn from(value: &DocIdentifier) -> Self {
Self { Self {
name: value.name.to_owned(), name: value.name.to_owned(),
variant: value.variant, variant: value.variant.clone(),
} }
} }
} }

View File

@ -38,7 +38,7 @@ pub struct CommandSpec {
impl From<CommandSpec> for Namespace { impl From<CommandSpec> for Namespace {
fn from(value: CommandSpec) -> Self { fn from(value: CommandSpec) -> Self {
Self { Self {
name: Token::get_dummy(), name: Token::default(),
functions: value.functions, functions: value.functions,
structures: value.structures, structures: value.structures,
enumerations: value.enumerations, enumerations: value.enumerations,
@ -144,6 +144,7 @@ pub struct Structure {
pub identifier: Token, // Will later become an Identifier pub identifier: Token, // Will later become an Identifier
pub contents: Vec<DocNamedType>, pub contents: Vec<DocNamedType>,
pub attributes: Vec<Attribute>, pub attributes: Vec<Attribute>,
pub namespaces: Vec<Token>, // Will later become an Identifier
} }
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)] #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
@ -151,6 +152,7 @@ pub struct Enumeration {
pub identifier: Token, // Will later become an Identifier pub identifier: Token, // Will later become an Identifier
pub states: Vec<DocToken>, // Will later become an Identifier pub states: Vec<DocToken>, // Will later become an Identifier
pub attributes: Vec<Attribute>, pub attributes: Vec<Attribute>,
pub namespaces: Vec<Token>, // Will later become an Identifier
} }
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)] #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]

View File

@ -149,14 +149,6 @@ impl Token {
pub fn span(&self) -> &TokenSpan { pub fn span(&self) -> &TokenSpan {
&self.span &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 /// Possibly kinds of tokens
@ -184,9 +176,10 @@ pub enum TokenKind {
Comment(String), Comment(String),
/// This is not a real TokenKind, but only used for error handling
#[default] #[default]
Dummy, /// This tokenkind is here support usages of [`mem::take`], this should never be exposed in the
/// final parsed output.
DefaultTokenKind,
} }
impl TokenKind { impl TokenKind {
@ -233,7 +226,6 @@ impl Display for TokenKind {
TokenKind::Semicolon => f.write_str("SEMICOLON"), TokenKind::Semicolon => f.write_str("SEMICOLON"),
TokenKind::Comma => f.write_str("COMMA"), TokenKind::Comma => f.write_str("COMMA"),
TokenKind::Arrow => f.write_str("ARROW"), TokenKind::Arrow => f.write_str("ARROW"),
TokenKind::Dummy => f.write_str("DUMMY"),
TokenKind::StringLiteral(text) => write!(f, r#"STRING_LITERAL("{}")"#, text), TokenKind::StringLiteral(text) => write!(f, r#"STRING_LITERAL("{}")"#, text),
TokenKind::CurlyBracketOpen => f.write_str("CURLY_BRACKET_OPEN"), 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::AngledBracketClose => f.write_str("ANGLED_BRACKET_CLOSE"),
TokenKind::SquareBracketOpen => f.write_str("SQUARE_BRACKET_OPEN"), TokenKind::SquareBracketOpen => f.write_str("SQUARE_BRACKET_OPEN"),
TokenKind::SquareBracketClose => f.write_str("SQUARE_BRACKET_CLOSE"), TokenKind::SquareBracketClose => f.write_str("SQUARE_BRACKET_CLOSE"),
TokenKind::DefaultTokenKind => f.write_str("DEFAULT_TOKEN_KIND"),
TokenKind::Comment(text) => write!(f, "COMMENT({})", text), TokenKind::Comment(text) => write!(f, "COMMENT({})", text),
} }
} }

View File

@ -68,6 +68,16 @@ pub enum ParsingError {
specified: Attribute, specified: Attribute,
span: TokenSpan, 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 { impl ParsingError {
@ -80,6 +90,8 @@ impl ParsingError {
ParsingError::NotEnoughGenericArgs { span, .. } => span, ParsingError::NotEnoughGenericArgs { span, .. } => span,
ParsingError::TooManyGenericArgs { span, .. } => span, ParsingError::TooManyGenericArgs { span, .. } => span,
ParsingError::WrongAttributeInPosition { 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::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::TooManyGenericArgs { got, expected_max, .. } => format!("Remove generic args until you have gone from {} to {}", got, expected_max),
ParsingError::WrongAttributeInPosition { .. } => format!("Remove this attribute"), 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"),
} }
} }
} }

View File

@ -106,7 +106,8 @@ impl Parser {
fn parse(mut self) -> Result<CommandSpec, SpannedParsingError> { fn parse(mut self) -> Result<CommandSpec, SpannedParsingError> {
let namespace: UncheckedNamespace = let namespace: UncheckedNamespace =
UncheckedNamespace::from(mem::take(&mut self.command_spec)); 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(); let span = *err.span();
SpannedParsingError { SpannedParsingError {
source: Box::new(err), source: Box::new(err),
@ -119,6 +120,7 @@ impl Parser {
fn process_namespace( fn process_namespace(
&mut self, &mut self,
namespace: UncheckedNamespace, namespace: UncheckedNamespace,
previous_namespaces: Vec<Identifier>,
) -> Result<Namespace, ParsingError> { ) -> Result<Namespace, ParsingError> {
let namespace_span = namespace.name.span; let namespace_span = namespace.name.span;
let name = match namespace.name.kind { let name = match namespace.name.kind {
@ -126,24 +128,33 @@ impl Parser {
name: ident, name: ident,
variant: Variant::Namespace, variant: Variant::Namespace,
}, },
// This is not really used, so the value put here does not matter // This is the first (implicit) root namespace
TokenKind::Dummy => Identifier { TokenKind::DefaultTokenKind => Identifier {
name: "".to_owned(), name: "<root>".to_owned(),
variant: Variant::Void, variant: Variant::RootNamespace,
}, },
_ => unreachable!("This should never be more than these two enum veriants"), _ => 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 = vec![];
let mut enumerations_counter = 0; let mut enumerations_counter = 0;
for enumeration in namespace.enumerations { 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; enumerations_counter += 1;
} }
let mut structures = vec![]; let mut structures = vec![];
let mut structures_counter = 0; let mut structures_counter = 0;
for structure in namespace.structures { for structure in namespace.structures {
structures.push(self.process_structure(structure)?); structures.push(self.process_structure(structure, &previous_namespaces)?);
structures_counter += 1; structures_counter += 1;
} }
@ -153,7 +164,7 @@ impl Parser {
} }
let mut namespaces = vec![]; let mut namespaces = vec![];
for namespace in namespace.namespaces { 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 // Remove added enums and structs again
@ -202,12 +213,15 @@ impl Parser {
mut enumeration: UncheckedEnumeration, mut enumeration: UncheckedEnumeration,
namespace_name: &Identifier, namespace_name: &Identifier,
namespace_span: TokenSpan, namespace_span: TokenSpan,
parent_namespaces: &Vec<Identifier>,
) -> Result<Enumeration, ParsingError> { ) -> Result<Enumeration, ParsingError> {
self.enumerations.push(enumeration.clone()); self.enumerations.push(enumeration.clone());
let enum_span = enumeration.identifier.span; let enum_span = enumeration.identifier.span;
let identifier: Identifier = 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 { if &identifier == namespace_name {
return Err(ParsingError::EnumWithNamespaceName { return Err(ParsingError::EnumWithNamespaceName {
name: identifier.clone(), name: identifier.clone(),
@ -246,11 +260,14 @@ impl Parser {
fn process_structure( fn process_structure(
&mut self, &mut self,
mut structure: UncheckedStructure, mut structure: UncheckedStructure,
parent_namespaces: &Vec<Identifier>,
) -> Result<Structure, ParsingError> { ) -> Result<Structure, ParsingError> {
self.structures.push(structure.clone()); self.structures.push(structure.clone());
let identifier: Identifier = 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![]; let mut contents = vec![];
for named_type in structure.contents { for named_type in structure.contents {
contents.push(self.process_doc_named_type(named_type)?); contents.push(self.process_doc_named_type(named_type)?);

View File

@ -33,7 +33,7 @@ fn test_full() {
let input = " let input = "
mod trinitrix { mod trinitrix {
struct Callback { struct Callback {
func: void, func: u32,
timeout: u8, timeout: u8,
} }
@ -77,7 +77,7 @@ mod trinitrix {
r#type: Type { r#type: Type {
identifier: Identifier { identifier: Identifier {
name: "Callback".to_owned(), name: "Callback".to_owned(),
variant: Variant::Type, variant: Variant::Structure,
}, },
generic_args: vec![], generic_args: vec![],
}, },
@ -90,7 +90,7 @@ mod trinitrix {
r#type: Type { r#type: Type {
identifier: Identifier { identifier: Identifier {
name: "CallbackPriority".to_owned(), name: "CallbackPriority".to_owned(),
variant: Variant::Type, variant: Variant::Enumeration,
}, },
generic_args: vec![], generic_args: vec![],
}, },
@ -112,8 +112,8 @@ mod trinitrix {
}, },
r#type: Type { r#type: Type {
identifier: Identifier { identifier: Identifier {
name: "()".to_owned(), name: "u32".to_owned(),
variant: Variant::Type, variant: Variant::Primitive,
}, },
generic_args: vec![], generic_args: vec![],
}, },
@ -127,7 +127,7 @@ mod trinitrix {
r#type: Type { r#type: Type {
identifier: Identifier { identifier: Identifier {
name: "u8".to_owned(), name: "u8".to_owned(),
variant: Variant::Type, variant: Variant::Primitive,
}, },
generic_args: vec![], generic_args: vec![],
}, },
@ -188,8 +188,8 @@ fn execute_callback(callback: Name);
assert_eq!( assert_eq!(
r#type, r#type,
Identifier { Identifier {
name: "Name".to_owned(), name: "void".to_owned(),
variant: Variant::Type, variant: Variant::Void,
} }
) )
} }
@ -230,7 +230,7 @@ mod trinitrix {
r#type: Type { r#type: Type {
identifier: Identifier { identifier: Identifier {
name: "String".to_owned(), name: "String".to_owned(),
variant: Variant::Type, variant: Variant::Primitive,
}, },
generic_args: vec![], generic_args: vec![],
}, },
@ -256,7 +256,7 @@ mod trinitrix {
r#type: Type { r#type: Type {
identifier: Identifier { identifier: Identifier {
name: "String".to_owned(), name: "String".to_owned(),
variant: Variant::Type, variant: Variant::Primitive,
}, },
generic_args: vec![], generic_args: vec![],
}, },
@ -264,7 +264,7 @@ mod trinitrix {
output: Some(Type { output: Some(Type {
identifier: Identifier { identifier: Identifier {
name: "String".to_owned(), name: "String".to_owned(),
variant: Variant::Type, variant: Variant::Primitive,
}, },
generic_args: vec![], generic_args: vec![],
}), }),

View File

@ -63,7 +63,7 @@ impl Parser {
fn parse(&mut self) -> Result<CommandSpec, SpannedParsingError> { fn parse(&mut self) -> Result<CommandSpec, SpannedParsingError> {
let mut output = CommandSpec::default(); let mut output = CommandSpec::default();
while !self.token_stream.is_empty() { 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(); let span = err.get_span();
SpannedParsingError { SpannedParsingError {
source: Box::new(err), source: Box::new(err),
@ -81,14 +81,20 @@ impl Parser {
Ok(output) Ok(output)
} }
fn parse_next(&mut self) -> Result<Declaration, ParsingError> { fn parse_next(&mut self, current_namespaces: &Vec<Token>) -> Result<Declaration, ParsingError> {
// Use of [peek_raw] here is fine, as we know that the function is only called, when // 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 // something should still be contained in the token stream
match self.peek_raw().kind() { 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![fn] => Ok(Declaration::Function(self.parse_function()?)),
token![struct] => Ok(Declaration::Structure(self.parse_structure()?)), token![struct] => Ok(Declaration::Structure(
token![enum] => Ok(Declaration::Enumeration(self.parse_enumeration()?)), self.parse_structure(current_namespaces.clone())?,
)),
token![enum] => Ok(Declaration::Enumeration(
self.parse_enumeration(current_namespaces.to_owned())?,
)),
token![#] => { token![#] => {
let attributes = self.parse_attributes()?; let attributes = self.parse_attributes()?;
self.current_attributes.extend(attributes); self.current_attributes.extend(attributes);
@ -107,7 +113,7 @@ impl Parser {
span, span,
}) })
} else { } else {
self.parse_next() self.parse_next(current_namespaces)
} }
} }
_ => { _ => {
@ -239,7 +245,10 @@ impl Parser {
Ok(attrs) Ok(attrs)
} }
fn parse_namespace(&mut self) -> Result<Namespace, ParsingError> { fn parse_namespace(
&mut self,
previous_namespaces: Vec<Token>,
) -> Result<Namespace, ParsingError> {
let attributes = self.parse_attributes()?; let attributes = self.parse_attributes()?;
self.expect(token![mod])?; self.expect(token![mod])?;
@ -248,11 +257,15 @@ impl Parser {
attributes, attributes,
..Default::default() ..Default::default()
}; };
let current_namespaces: Vec<_> = previous_namespaces
.into_iter()
.chain(once(namespace.name.clone()))
.collect();
self.expect(token![CurlyBracketOpen])?; self.expect(token![CurlyBracketOpen])?;
while !self.expect_peek(token![CurlyBracketClose]) { while !self.expect_peek(token![CurlyBracketClose]) {
let next = self.parse_next()?; let next = self.parse_next(&current_namespaces)?;
match next { match next {
Declaration::Function(function) => namespace.functions.push(function), Declaration::Function(function) => namespace.functions.push(function),
Declaration::Structure(structure) => namespace.structures.push(structure), Declaration::Structure(structure) => namespace.structures.push(structure),
@ -267,7 +280,10 @@ impl Parser {
Ok(namespace) Ok(namespace)
} }
fn parse_enumeration(&mut self) -> Result<Enumeration, ParsingError> { fn parse_enumeration(
&mut self,
current_namespaces: Vec<Token>,
) -> Result<Enumeration, ParsingError> {
let attributes = self.parse_attributes()?; let attributes = self.parse_attributes()?;
self.expect(token![enum])?; self.expect(token![enum])?;
let identifier = self.expect(token![Ident])?; let identifier = self.expect(token![Ident])?;
@ -299,10 +315,14 @@ impl Parser {
identifier, identifier,
states, states,
attributes, attributes,
namespaces: current_namespaces,
}) })
} }
fn parse_structure(&mut self) -> Result<Structure, ParsingError> { fn parse_structure(
&mut self,
current_namespaces: Vec<Token>,
) -> Result<Structure, ParsingError> {
let attributes = self.parse_attributes()?; let attributes = self.parse_attributes()?;
self.expect(token![struct])?; self.expect(token![struct])?;
let name = self.expect(token![Ident])?; let name = self.expect(token![Ident])?;
@ -326,6 +346,7 @@ impl Parser {
identifier: name, identifier: name,
contents, contents,
attributes, attributes,
namespaces: current_namespaces,
}) })
} }