forked from trinitrix/core
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 (`/* */`).
|
# - 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
|
||||||
|
|
Binary file not shown.
|
@ -5,7 +5,7 @@ nasp trinitrix {
|
||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
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 name: Token, // Will later become an Identifier
|
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
|
pub r#type: Token, // Will later become an Type
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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()),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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])?;
|
||||||
|
|
Loading…
Reference in New Issue