feat(trixy-lang_parser): Add support for structs and enums

This commit is contained in:
Benedikt Peetz 2023-12-18 20:50:58 +01:00
parent 3a65c33b15
commit be066afe23
Signed by: bpeetz
GPG Key ID: A5E94010C3A642AD
8 changed files with 142 additions and 20 deletions

View File

@ -6,11 +6,13 @@
# - Block comments (`/* */`). # - Block comments (`/* */`).
# *) # *)
CommandSpec = { Function | Namespace } ; CommandSpec = { Function | Namespace | Enumeration | Structure } ;
Function = "fn" Identifier "(" {Identifier ":" Type} ")" [ "->" Type ] ";" ; Function = "fn" Identifier "(" [NamedType {"," NamedType }] ")" [ "->" Type ] ";" ;
Namespace = "nasp" Identifier "{" {Function | Namespace} "}" ; Namespace = "nasp" Identifier "{" {Function | Namespace | Enumeration | Structure} "}" ;
Type = "String" | "Integer" ; # (* This corresponds to the CommandTransferValue *) Structure = "struct" Identifier "{" [NamedType {"," NamedType } [","]] "}" ";";
Enumeration = "enum" Identifier "{" [Identifier {"," Identifier} [","]] "}" ";";
Identifier = CHARACTER { NUMBER | CHARACTER } ; Identifier = CHARACTER { NUMBER | CHARACTER } ;
NamedType = Identifier ":" Type;
# (* # (*
# vim: ft=ebnf # vim: ft=ebnf

View File

@ -5,7 +5,7 @@ nasp trinitrix {
} }
nasp trinitrix { nasp trinitrix {
fn ho(name: String) -> String; fn ho(name: String, name2: String) -> String;
} }

View File

@ -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

View File

@ -17,7 +17,22 @@ pub struct Declaration {
impl Declaration { impl Declaration {
pub fn new_function(function: Function, namespace: Vec<Token>) -> Self { pub fn new_function(function: Function, namespace: Vec<Token>) -> Self {
Declaration { namespace, genus: Genus::Function(function) } Declaration {
namespace,
genus: Genus::Function(function),
}
}
pub fn new_structure(structure: Structure, namespace: Vec<Token>) -> Self {
Declaration {
namespace,
genus: Genus::Structure(structure),
}
}
pub fn new_enumeration(r#enum: Enumeration, namespace: Vec<Token>) -> Self {
Declaration {
namespace,
genus: Genus::Enumeration(r#enum),
}
} }
} }
@ -32,17 +47,31 @@ pub enum Genus {
Dummy, Dummy,
/// A function /// A function
Function(Function), Function(Function),
Structure(Structure),
Enumeration(Enumeration),
} }
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)] #[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct Function { pub struct Function {
pub identifier: Token, // Will later become an Identifier pub identifier: Token, // Will later become an Identifier
pub inputs: Vec<FunctionInput>, pub inputs: Vec<NamedType>,
pub output: Option<Token>, // Will later become an Type pub output: Option<Token>, // Will later become an Type
} }
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)] #[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct FunctionInput { pub struct Structure {
pub identifier: Token, // Will later become an Identifier
pub contents: Vec<NamedType>,
}
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct Enumeration {
pub identifier: Token, // Will later become an Identifier
pub states: Vec<Token>, // Will later become an Identifier
}
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct NamedType {
pub name: Token, // Will later become an Identifier pub name: Token, // Will later become an Identifier
pub r#type: Token, // Will later become an Type pub r#type: Token, // Will later become an Type
} }

View File

@ -169,6 +169,12 @@ pub enum Keyword {
/// Start a function declaration /// Start a function declaration
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
r#fn, 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 { impl Display for Keyword {
@ -176,6 +182,8 @@ impl Display for Keyword {
match self { match self {
Keyword::nasp => f.write_str("nasp"), Keyword::nasp => f.write_str("nasp"),
Keyword::r#fn => f.write_str("fn"), 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) }; [nasp] => { $crate::lexing::TokenKind::Keyword($crate::lexing::Keyword::nasp) };
[fn] => { $crate::lexing::TokenKind::Keyword($crate::lexing::Keyword::r#fn) }; [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 // This is only works for checking for a identifier
// see the `same_kind` method on TokenKind // see the `same_kind` method on TokenKind

View File

@ -91,8 +91,6 @@ impl<'a> Tokenizer<'a> {
remaining = &remaining[ws..]; remaining = &remaining[ws..];
ws ws
}; };
// let comments = skip_comments(remaining);
// remaining = &remaining[comments..];
let skip = self.remaining_text.len() - remaining.len(); let skip = self.remaining_text.len() - remaining.len();
self.chomp(skip); self.chomp(skip);
@ -128,6 +126,8 @@ fn tokenize_ident(text: &str) -> Result<(TokenKind, usize), LexingError> {
let tokenkind = match got { let tokenkind = match got {
"nasp" => TokenKind::Keyword(Keyword::nasp), "nasp" => TokenKind::Keyword(Keyword::nasp),
"fn" => TokenKind::Keyword(Keyword::r#fn), "fn" => TokenKind::Keyword(Keyword::r#fn),
"struct" => TokenKind::Keyword(Keyword::r#struct),
"enum" => TokenKind::Keyword(Keyword::r#enum),
other => TokenKind::Identifier(other.to_string()), other => TokenKind::Identifier(other.to_string()),
}; };

View File

@ -1,5 +1,7 @@
use crate::{ use crate::{
command_spec::unchecked::{CommandSpec, Declaration, Function, FunctionInput}, command_spec::unchecked::{
CommandSpec, Declaration, Enumeration, Function, NamedType, Structure,
},
error::ErrorContext, error::ErrorContext,
lexing::{Token, TokenKind, TokenStream}, lexing::{Token, TokenKind, TokenStream},
token, token,
@ -52,6 +54,14 @@ impl Parser {
self.parse_function()?, self.parse_function()?,
self.current_namespaces.clone(), 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 { let err = ParsingError::ExpectedKeyword {
span: *self.peek().span(), span: *self.peek().span(),
@ -79,20 +89,73 @@ impl Parser {
Ok(declarations) Ok(declarations)
} }
fn parse_enumeration(&mut self) -> Result<Enumeration, ParsingError> {
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<Structure, ParsingError> {
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<NamedType, ParsingError> {
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<Function, ParsingError> { fn parse_function(&mut self) -> Result<Function, ParsingError> {
self.expect(token![fn])?; self.expect(token![fn])?;
let name = self.expect(token![Ident])?; let name = self.expect(token![Ident])?;
self.expect(token![ParenOpen])?; self.expect(token![ParenOpen])?;
let mut inputs = vec![]; let mut inputs = vec![];
while self.expect_peek(token![Ident]) { if self.expect_peek(token![Ident]) {
let input_name = self.expect(token![Ident])?; inputs.push(self.parse_named_type()?);
self.expect(token![Colon])?; }
let input_type = self.expect(token![Ident])?; while self.expect_peek(token![Comma]) {
inputs.push(FunctionInput { self.expect(token![Comma])?;
name: input_name, inputs.push(self.parse_named_type()?);
r#type: input_type,
})
} }
self.expect(token![ParenClose])?; self.expect(token![ParenClose])?;