diff --git a/trixy/trixy-lang_parser/docs/grammar.ebnf b/trixy/trixy-lang_parser/docs/grammar.ebnf index 749149c..05ffca8 100644 --- a/trixy/trixy-lang_parser/docs/grammar.ebnf +++ b/trixy/trixy-lang_parser/docs/grammar.ebnf @@ -6,11 +6,13 @@ # - Block comments (`/* */`). # *) -CommandSpec = { Function | Namespace } ; -Function = "fn" Identifier "(" {Identifier ":" Type} ")" [ "->" Type ] ";" ; -Namespace = "nasp" Identifier "{" {Function | Namespace} "}" ; -Type = "String" | "Integer" ; # (* This corresponds to the CommandTransferValue *) +CommandSpec = { Function | Namespace | Enumeration | Structure } ; +Function = "fn" Identifier "(" [NamedType {"," NamedType }] ")" [ "->" Type ] ";" ; +Namespace = "nasp" Identifier "{" {Function | Namespace | Enumeration | Structure} "}" ; +Structure = "struct" Identifier "{" [NamedType {"," NamedType } [","]] "}" ";"; +Enumeration = "enum" Identifier "{" [Identifier {"," Identifier} [","]] "}" ";"; Identifier = CHARACTER { NUMBER | CHARACTER } ; +NamedType = Identifier ":" Type; # (* # vim: ft=ebnf diff --git a/trixy/trixy-lang_parser/docs/grammar.pdf b/trixy/trixy-lang_parser/docs/grammar.pdf index 54cad09..bf84bb0 100644 Binary files a/trixy/trixy-lang_parser/docs/grammar.pdf and b/trixy/trixy-lang_parser/docs/grammar.pdf differ diff --git a/trixy/trixy-lang_parser/example/multiple.tri b/trixy/trixy-lang_parser/example/multiple.tri index a0d01ad..0fca007 100644 --- a/trixy/trixy-lang_parser/example/multiple.tri +++ b/trixy/trixy-lang_parser/example/multiple.tri @@ -5,7 +5,7 @@ nasp trinitrix { } nasp trinitrix { - fn ho(name: String) -> String; + fn ho(name: String, name2: String) -> String; } diff --git a/trixy/trixy-lang_parser/example/types.tri b/trixy/trixy-lang_parser/example/types.tri new file mode 100644 index 0000000..b599445 --- /dev/null +++ b/trixy/trixy-lang_parser/example/types.tri @@ -0,0 +1,18 @@ +nasp trinitrix { + struct Callback { + func: Function, + timeout: Integer, + }; + + enum CallbackPriority { + High, + Medium, + Low, + }; + + fn execute_callback(callback: Callback, priority: CallbackPriority); +} + + +// That's a flat out lie, but it results in a rather nice syntax highlight compared to nothing: +// vim: syntax=rust diff --git a/trixy/trixy-lang_parser/src/command_spec/unchecked.rs b/trixy/trixy-lang_parser/src/command_spec/unchecked.rs index ec2fa66..c7d2dc5 100644 --- a/trixy/trixy-lang_parser/src/command_spec/unchecked.rs +++ b/trixy/trixy-lang_parser/src/command_spec/unchecked.rs @@ -17,7 +17,22 @@ pub struct Declaration { impl Declaration { pub fn new_function(function: Function, namespace: Vec) -> Self { - Declaration { namespace, genus: Genus::Function(function) } + Declaration { + namespace, + genus: Genus::Function(function), + } + } + pub fn new_structure(structure: Structure, namespace: Vec) -> Self { + Declaration { + namespace, + genus: Genus::Structure(structure), + } + } + pub fn new_enumeration(r#enum: Enumeration, namespace: Vec) -> Self { + Declaration { + namespace, + genus: Genus::Enumeration(r#enum), + } } } @@ -32,17 +47,31 @@ pub enum Genus { Dummy, /// A function Function(Function), + Structure(Structure), + Enumeration(Enumeration), } #[derive(Debug, PartialEq, Eq, PartialOrd, Ord)] pub struct Function { pub identifier: Token, // Will later become an Identifier - pub inputs: Vec, + pub inputs: Vec, pub output: Option, // Will later become an Type } #[derive(Debug, PartialEq, Eq, PartialOrd, Ord)] -pub struct FunctionInput { - pub name: Token, // Will later become an Identifier +pub struct Structure { + pub identifier: Token, // Will later become an Identifier + pub contents: Vec, +} + +#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)] +pub struct Enumeration { + pub identifier: Token, // Will later become an Identifier + pub states: Vec, // Will later become an Identifier +} + +#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)] +pub struct NamedType { + pub name: Token, // Will later become an Identifier pub r#type: Token, // Will later become an Type } diff --git a/trixy/trixy-lang_parser/src/lexing/mod.rs b/trixy/trixy-lang_parser/src/lexing/mod.rs index 989ec8b..a8ecd6c 100644 --- a/trixy/trixy-lang_parser/src/lexing/mod.rs +++ b/trixy/trixy-lang_parser/src/lexing/mod.rs @@ -169,6 +169,12 @@ pub enum Keyword { /// Start a function declaration #[allow(non_camel_case_types)] r#fn, + /// Start a structure declaration + #[allow(non_camel_case_types)] + r#struct, + /// Start a enum declaration + #[allow(non_camel_case_types)] + r#enum, } impl Display for Keyword { @@ -176,6 +182,8 @@ impl Display for Keyword { match self { Keyword::nasp => f.write_str("nasp"), Keyword::r#fn => f.write_str("fn"), + Keyword::r#struct => f.write_str("struct"), + Keyword::r#enum => f.write_str("enum"), } } } @@ -214,6 +222,8 @@ macro_rules! token { [nasp] => { $crate::lexing::TokenKind::Keyword($crate::lexing::Keyword::nasp) }; [fn] => { $crate::lexing::TokenKind::Keyword($crate::lexing::Keyword::r#fn) }; + [struct] => { $crate::lexing::TokenKind::Keyword($crate::lexing::Keyword::r#struct) }; + [enum] => { $crate::lexing::TokenKind::Keyword($crate::lexing::Keyword::r#enum) }; // This is only works for checking for a identifier // see the `same_kind` method on TokenKind diff --git a/trixy/trixy-lang_parser/src/lexing/tokenizer.rs b/trixy/trixy-lang_parser/src/lexing/tokenizer.rs index af46d43..3e78ed7 100644 --- a/trixy/trixy-lang_parser/src/lexing/tokenizer.rs +++ b/trixy/trixy-lang_parser/src/lexing/tokenizer.rs @@ -91,8 +91,6 @@ impl<'a> Tokenizer<'a> { remaining = &remaining[ws..]; ws }; - // let comments = skip_comments(remaining); - // remaining = &remaining[comments..]; let skip = self.remaining_text.len() - remaining.len(); self.chomp(skip); @@ -128,6 +126,8 @@ fn tokenize_ident(text: &str) -> Result<(TokenKind, usize), LexingError> { let tokenkind = match got { "nasp" => TokenKind::Keyword(Keyword::nasp), "fn" => TokenKind::Keyword(Keyword::r#fn), + "struct" => TokenKind::Keyword(Keyword::r#struct), + "enum" => TokenKind::Keyword(Keyword::r#enum), other => TokenKind::Identifier(other.to_string()), }; diff --git a/trixy/trixy-lang_parser/src/parsing/unchecked.rs b/trixy/trixy-lang_parser/src/parsing/unchecked.rs index 9d12a9e..07f9423 100644 --- a/trixy/trixy-lang_parser/src/parsing/unchecked.rs +++ b/trixy/trixy-lang_parser/src/parsing/unchecked.rs @@ -1,5 +1,7 @@ use crate::{ - command_spec::unchecked::{CommandSpec, Declaration, Function, FunctionInput}, + command_spec::unchecked::{ + CommandSpec, Declaration, Enumeration, Function, NamedType, Structure, + }, error::ErrorContext, lexing::{Token, TokenKind, TokenStream}, token, @@ -52,6 +54,14 @@ impl Parser { self.parse_function()?, self.current_namespaces.clone(), )]), + token![struct] => Ok(vec![Declaration::new_structure( + self.parse_structure()?, + self.current_namespaces.clone(), + )]), + token![enum] => Ok(vec![Declaration::new_enumeration( + self.parse_enumeration()?, + self.current_namespaces.clone(), + )]), _ => { let err = ParsingError::ExpectedKeyword { span: *self.peek().span(), @@ -79,20 +89,73 @@ impl Parser { Ok(declarations) } + fn parse_enumeration(&mut self) -> Result { + self.expect(token![enum])?; + let identifier = self.expect(token![Ident])?; + self.expect(token![BraceOpen])?; + + let mut states = vec![]; + if self.expect_peek(token![Ident]) { + states.push(self.expect(token![Ident])?); + } + while self.expect_peek(token![Comma]) { + self.expect(token![Comma])?; + if self.expect_peek(token![Ident]) { + states.push(self.expect(token![Ident])?); + } else { + break; + } + } + self.expect(token![BraceClose])?; + self.expect(token![;])?; + Ok(Enumeration { identifier, states }) + } + + fn parse_structure(&mut self) -> Result { + self.expect(token![struct])?; + let name = self.expect(token![Ident])?; + self.expect(token![BraceOpen])?; + + let mut contents = vec![]; + if self.expect_peek(token![Ident]) { + contents.push(self.parse_named_type()?); + } + while self.expect_peek(token![Comma]) { + self.expect(token![Comma])?; + if self.expect_peek(token![Ident]) { + contents.push(self.parse_named_type()?); + } else { + break; + } + } + self.expect(token![BraceClose])?; + self.expect(token![;])?; + + Ok(Structure { + identifier: name, + contents, + }) + } + + fn parse_named_type(&mut self) -> Result { + let name = self.expect(token![Ident])?; + self.expect(token![Colon])?; + let r#type = self.expect(token![Ident])?; + Ok(NamedType { name, r#type }) + } + fn parse_function(&mut self) -> Result { self.expect(token![fn])?; let name = self.expect(token![Ident])?; self.expect(token![ParenOpen])?; let mut inputs = vec![]; - while self.expect_peek(token![Ident]) { - let input_name = self.expect(token![Ident])?; - self.expect(token![Colon])?; - let input_type = self.expect(token![Ident])?; - inputs.push(FunctionInput { - name: input_name, - r#type: input_type, - }) + if self.expect_peek(token![Ident]) { + inputs.push(self.parse_named_type()?); + } + while self.expect_peek(token![Comma]) { + self.expect(token![Comma])?; + inputs.push(self.parse_named_type()?); } self.expect(token![ParenClose])?;