Implement enum definition parsing
This commit is contained in:
parent
b7ae0f1b52
commit
77ded361ff
45
src/abstract_tree/enum_definition.rs
Normal file
45
src/abstract_tree/enum_definition.rs
Normal file
@ -0,0 +1,45 @@
|
||||
use super::{AbstractTree, Identifier, Type, WithPosition};
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
||||
pub struct EnumDefinition {
|
||||
name: Identifier,
|
||||
type_parameters: Vec<Identifier>,
|
||||
variants: Vec<(Identifier, Vec<WithPosition<Type>>)>,
|
||||
}
|
||||
|
||||
impl EnumDefinition {
|
||||
pub fn new(
|
||||
name: Identifier,
|
||||
type_parameters: Vec<Identifier>,
|
||||
variants: Vec<(Identifier, Vec<WithPosition<Type>>)>,
|
||||
) -> Self {
|
||||
Self {
|
||||
name,
|
||||
type_parameters,
|
||||
variants,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AbstractTree for EnumDefinition {
|
||||
fn expected_type(
|
||||
&self,
|
||||
_context: &crate::context::Context,
|
||||
) -> Result<Type, crate::error::ValidationError> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn validate(
|
||||
&self,
|
||||
_context: &crate::context::Context,
|
||||
) -> Result<(), crate::error::ValidationError> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn run(
|
||||
self,
|
||||
_context: &crate::context::Context,
|
||||
) -> Result<super::Action, crate::error::RuntimeError> {
|
||||
todo!()
|
||||
}
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
pub mod assignment;
|
||||
pub mod block;
|
||||
pub mod enum_definition;
|
||||
pub mod expression;
|
||||
pub mod function_call;
|
||||
pub mod identifier;
|
||||
@ -19,6 +20,7 @@ use chumsky::span::{SimpleSpan, Span};
|
||||
pub use self::{
|
||||
assignment::{Assignment, AssignmentOperator},
|
||||
block::Block,
|
||||
enum_definition::EnumDefinition,
|
||||
expression::Expression,
|
||||
function_call::FunctionCall,
|
||||
identifier::Identifier,
|
||||
|
@ -3,13 +3,16 @@ use crate::{
|
||||
error::{RuntimeError, ValidationError},
|
||||
};
|
||||
|
||||
use super::{AbstractTree, Action, Assignment, Block, Expression, IfElse, Loop, Type, While};
|
||||
use super::{
|
||||
AbstractTree, Action, Assignment, Block, EnumDefinition, Expression, IfElse, Loop, Type, While,
|
||||
};
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
||||
pub enum Statement {
|
||||
Assignment(Assignment),
|
||||
Block(Block),
|
||||
Break,
|
||||
EnumDefinition(EnumDefinition),
|
||||
Expression(Expression),
|
||||
IfElse(IfElse),
|
||||
Loop(Loop),
|
||||
@ -22,6 +25,7 @@ impl AbstractTree for Statement {
|
||||
Statement::Assignment(assignment) => assignment.expected_type(_context),
|
||||
Statement::Block(block) => block.expected_type(_context),
|
||||
Statement::Break => Ok(Type::None),
|
||||
Statement::EnumDefinition(_) => todo!(),
|
||||
Statement::Expression(expression) => expression.expected_type(_context),
|
||||
Statement::IfElse(if_else) => if_else.expected_type(_context),
|
||||
Statement::Loop(r#loop) => r#loop.expected_type(_context),
|
||||
@ -34,6 +38,7 @@ impl AbstractTree for Statement {
|
||||
Statement::Assignment(assignment) => assignment.validate(_context),
|
||||
Statement::Block(block) => block.validate(_context),
|
||||
Statement::Break => Ok(()),
|
||||
Statement::EnumDefinition(_) => todo!(),
|
||||
Statement::Expression(expression) => expression.validate(_context),
|
||||
Statement::IfElse(if_else) => if_else.validate(_context),
|
||||
Statement::Loop(r#loop) => r#loop.validate(_context),
|
||||
@ -46,6 +51,7 @@ impl AbstractTree for Statement {
|
||||
Statement::Assignment(assignment) => assignment.run(_context),
|
||||
Statement::Block(block) => block.run(_context),
|
||||
Statement::Break => Ok(Action::Break),
|
||||
Statement::EnumDefinition(_) => todo!(),
|
||||
Statement::Expression(expression) => expression.run(_context),
|
||||
Statement::IfElse(if_else) => if_else.run(_context),
|
||||
Statement::Loop(r#loop) => r#loop.run(_context),
|
||||
|
@ -1,6 +1,6 @@
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
|
||||
use chumsky::{prelude::*, text::whitespace};
|
||||
use chumsky::prelude::*;
|
||||
|
||||
use crate::error::Error;
|
||||
|
||||
@ -217,6 +217,7 @@ pub fn lexer<'src>() -> impl Parser<
|
||||
just("bool").padded(),
|
||||
just("break").padded(),
|
||||
just("else").padded(),
|
||||
just("enum").padded(),
|
||||
just("float").padded(),
|
||||
just("int").padded(),
|
||||
just("if").padded(),
|
||||
@ -228,11 +229,10 @@ pub fn lexer<'src>() -> impl Parser<
|
||||
just("loop").padded(),
|
||||
just("while").padded(),
|
||||
))
|
||||
.delimited_by(whitespace(), whitespace())
|
||||
.map(Token::Keyword);
|
||||
|
||||
choice((
|
||||
boolean, float, integer, string, identifier, keyword, control, operator,
|
||||
boolean, float, integer, string, keyword, identifier, control, operator,
|
||||
))
|
||||
.map_with(|token, state| (token, state.span()))
|
||||
.padded()
|
||||
@ -270,7 +270,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn keywords() {
|
||||
assert_eq!(lex("int").unwrap()[0].0, Token::Keyword("int"))
|
||||
assert_eq!(lex("int ").unwrap()[0].0, Token::Keyword("int"))
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -424,7 +424,48 @@ pub fn parser<'src>() -> DustParser<'src> {
|
||||
.with_position(state.span())
|
||||
});
|
||||
|
||||
let enum_variant = identifier.clone().then(
|
||||
r#type
|
||||
.clone()
|
||||
.separated_by(just(Token::Control(Control::Comma)))
|
||||
.allow_trailing()
|
||||
.collect()
|
||||
.delimited_by(
|
||||
just(Token::Control(Control::ParenOpen)),
|
||||
just(Token::Control(Control::ParenClose)),
|
||||
),
|
||||
);
|
||||
|
||||
let enum_definition = just(Token::Keyword("enum"))
|
||||
.ignore_then(identifier.clone())
|
||||
.then(
|
||||
identifier
|
||||
.clone()
|
||||
.separated_by(just(Token::Control(Control::Comma)))
|
||||
.allow_trailing()
|
||||
.collect()
|
||||
.delimited_by(
|
||||
just(Token::Control(Control::ParenOpen)),
|
||||
just(Token::Control(Control::ParenClose)),
|
||||
),
|
||||
)
|
||||
.then(
|
||||
enum_variant
|
||||
.separated_by(just(Token::Control(Control::Comma)))
|
||||
.allow_trailing()
|
||||
.collect()
|
||||
.delimited_by(
|
||||
just(Token::Control(Control::CurlyOpen)),
|
||||
just(Token::Control(Control::CurlyClose)),
|
||||
),
|
||||
)
|
||||
.map_with(|((name, type_parameters), variants), state| {
|
||||
Statement::EnumDefinition(EnumDefinition::new(name, type_parameters, variants))
|
||||
.with_position(state.span())
|
||||
});
|
||||
|
||||
choice((
|
||||
enum_definition,
|
||||
if_else,
|
||||
assignment,
|
||||
expression_statement,
|
||||
@ -445,6 +486,37 @@ mod tests {
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn enum_definition() {
|
||||
assert_eq!(
|
||||
parse(
|
||||
&lex("
|
||||
enum FooBar (F, B) {
|
||||
Foo(F),
|
||||
Bar(B),
|
||||
}
|
||||
")
|
||||
.unwrap()
|
||||
)
|
||||
.unwrap()[0]
|
||||
.node,
|
||||
Statement::EnumDefinition(EnumDefinition::new(
|
||||
Identifier::new("FooBar"),
|
||||
vec![Identifier::new("F"), Identifier::new("B")],
|
||||
vec![
|
||||
(
|
||||
Identifier::new("Foo"),
|
||||
vec![Type::Custom(Identifier::new("F")).with_position((0, 0))],
|
||||
),
|
||||
(
|
||||
Identifier::new("Bar"),
|
||||
vec![Type::Custom(Identifier::new("B")).with_position((0, 0))]
|
||||
)
|
||||
]
|
||||
))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn map_index() {
|
||||
assert_eq!(
|
||||
|
30
src/value.rs
30
src/value.rs
@ -3,7 +3,6 @@ use std::{
|
||||
collections::BTreeMap,
|
||||
fmt::{self, Display, Formatter},
|
||||
io::stdin,
|
||||
num::ParseIntError,
|
||||
ops::Range,
|
||||
sync::{Arc, OnceLock},
|
||||
};
|
||||
@ -18,7 +17,7 @@ use stanza::{
|
||||
use crate::{
|
||||
abstract_tree::{AbstractTree, Action, Block, Identifier, Type, WithPosition},
|
||||
context::Context,
|
||||
error::{RuntimeError, ValidationError},
|
||||
error::RuntimeError,
|
||||
};
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
@ -354,18 +353,15 @@ impl BuiltInFunction {
|
||||
let string = arguments.get(0).unwrap();
|
||||
|
||||
if let ValueInner::String(string) = string.inner().as_ref() {
|
||||
// let integer = string.parse();
|
||||
|
||||
todo!()
|
||||
|
||||
// Ok(Action::Return(Value::integer(integer)))
|
||||
let integer = if let Ok(integer) = string.parse() {
|
||||
integer
|
||||
} else {
|
||||
Err(RuntimeError::ValidationFailure(
|
||||
ValidationError::WrongArguments {
|
||||
expected: vec![Type::String],
|
||||
actual: arguments.iter().map(|value| value.r#type()).collect(),
|
||||
},
|
||||
))
|
||||
todo!()
|
||||
};
|
||||
|
||||
Ok(Action::Return(Value::integer(integer)))
|
||||
} else {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
BuiltInFunction::IntRandomRange => {
|
||||
@ -409,24 +405,24 @@ impl Display for BuiltInFunction {
|
||||
static INT: OnceLock<Value> = OnceLock::new();
|
||||
static IO: OnceLock<Value> = OnceLock::new();
|
||||
|
||||
pub const BUILT_IN_MODULES: [BuiltInModule; 2] = [BuiltInModule::Integer, BuiltInModule::Io];
|
||||
pub const BUILT_IN_MODULES: [BuiltInModule; 2] = [BuiltInModule::Int, BuiltInModule::Io];
|
||||
|
||||
pub enum BuiltInModule {
|
||||
Integer,
|
||||
Int,
|
||||
Io,
|
||||
}
|
||||
|
||||
impl BuiltInModule {
|
||||
pub fn name(&self) -> &'static str {
|
||||
match self {
|
||||
BuiltInModule::Integer => "int",
|
||||
BuiltInModule::Int => "int",
|
||||
BuiltInModule::Io => "io",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn value(self) -> Value {
|
||||
match self {
|
||||
BuiltInModule::Integer => {
|
||||
BuiltInModule::Int => {
|
||||
let mut properties = BTreeMap::new();
|
||||
|
||||
properties.insert(
|
||||
|
@ -47,7 +47,7 @@ fn callback() {
|
||||
|
||||
#[test]
|
||||
fn built_in_function_call() {
|
||||
assert_eq!(interpret("output('Hiya')"), Ok(None));
|
||||
assert_eq!(interpret("io.write_line('Hiya')"), Ok(None));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
Loading…
Reference in New Issue
Block a user