feat(trixy-lang_parser): Add support for structs and enums
This commit is contained in:
parent
3a65c33b15
commit
be066afe23
|
@ -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
|
||||
|
|
Binary file not shown.
|
@ -5,7 +5,7 @@ nasp trinitrix {
|
|||
}
|
||||
|
||||
nasp trinitrix {
|
||||
fn ho(name: String) -> String;
|
||||
fn ho(name: String, name2: String) -> String;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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
|
|
@ -17,7 +17,22 @@ pub struct Declaration {
|
|||
|
||||
impl Declaration {
|
||||
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,
|
||||
/// 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<FunctionInput>,
|
||||
pub inputs: Vec<NamedType>,
|
||||
pub output: Option<Token>, // Will later become an Type
|
||||
}
|
||||
|
||||
#[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 r#type: Token, // Will later become an Type
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()),
|
||||
};
|
||||
|
||||
|
|
|
@ -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<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> {
|
||||
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])?;
|
||||
|
|
Reference in New Issue