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