Clean up type parsing

This commit is contained in:
Jeff 2024-03-09 15:17:19 -05:00
parent 2dd1628bca
commit a3591d19af
2 changed files with 85 additions and 61 deletions

View File

@ -3,25 +3,21 @@ use crate::{
error::{RuntimeError, ValidationError},
};
use super::{AbstractTree, Action, Expression, Statement, Type};
use super::{AbstractTree, Action, Block, Expression, Type};
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
pub struct IfElse {
if_expression: Expression,
if_statement: Box<Statement>,
else_statement: Option<Box<Statement>>,
if_block: Block,
else_block: Option<Block>,
}
impl IfElse {
pub fn new(
if_expression: Expression,
if_statement: Statement,
else_statement: Option<Statement>,
) -> Self {
pub fn new(if_expression: Expression, if_block: Block, else_block: Option<Block>) -> Self {
Self {
if_expression,
if_statement: Box::new(if_statement),
else_statement: else_statement.map(|statement| Box::new(statement)),
if_block,
else_block,
}
}
}
@ -47,8 +43,8 @@ impl AbstractTree for IfElse {
.as_boolean()?;
if if_boolean {
self.if_statement.run(_context)
} else if let Some(else_statement) = self.else_statement {
self.if_block.run(_context)
} else if let Some(else_statement) = self.else_block {
else_statement.run(_context)
} else {
Ok(Action::None)
@ -59,7 +55,7 @@ impl AbstractTree for IfElse {
#[cfg(test)]
mod tests {
use crate::{
abstract_tree::{Action, ValueNode},
abstract_tree::{Action, Statement, ValueNode},
context::Context,
Value,
};
@ -71,7 +67,9 @@ mod tests {
assert_eq!(
IfElse::new(
Expression::Value(ValueNode::Boolean(true)),
Statement::Expression(Expression::Value(ValueNode::String("foo".to_string()))),
Block::new(vec![Statement::Expression(Expression::Value(
ValueNode::String("foo".to_string())
)),]),
None
)
.run(&Context::new()),
@ -84,10 +82,12 @@ mod tests {
assert_eq!(
IfElse::new(
Expression::Value(ValueNode::Boolean(false)),
Statement::Expression(Expression::Value(ValueNode::String("foo".to_string()))),
Some(Statement::Expression(Expression::Value(ValueNode::String(
"bar".to_string()
))))
Block::new(vec![Statement::Expression(Expression::Value(
ValueNode::String("foo".to_string())
)),]),
Some(Block::new(vec![Statement::Expression(Expression::Value(
ValueNode::String("bar".to_string())
))]))
)
.run(&Context::new()),
Ok(Action::Return(Value::string("bar".to_string())))

View File

@ -56,7 +56,25 @@ pub fn parser<'src>() -> DustParser<'src> {
.map(|value| Expression::Value(value))
.boxed();
let basic_type = choice((
let type_specification = recursive(|type_specification| {
let r#type = recursive(|r#type| {
let function_type = type_specification
.clone()
.separated_by(just(Token::Control(Control::Comma)))
.collect()
.delimited_by(
just(Token::Control(Control::ParenOpen)),
just(Token::Control(Control::ParenClose)),
)
.then_ignore(just(Token::Control(Control::Colon)))
.then(r#type.clone())
.map(|(parameter_types, return_type)| Type::Function {
parameter_types,
return_type: Box::new(return_type),
});
choice((
function_type,
just(Token::Keyword("any")).to(Type::Any),
just(Token::Keyword("bool")).to(Type::Boolean),
just(Token::Keyword("float")).to(Type::Float),
@ -65,15 +83,16 @@ pub fn parser<'src>() -> DustParser<'src> {
just(Token::Keyword("range")).to(Type::Range),
just(Token::Keyword("str")).to(Type::String),
just(Token::Keyword("list")).to(Type::List),
));
))
});
let type_arguments = basic_type.clone().delimited_by(
let type_arguments = r#type.clone().delimited_by(
just(Token::Control(Control::ParenOpen)),
just(Token::Control(Control::ParenClose)),
);
let type_specification = just(Token::Control(Control::Colon)).ignore_then(choice((
basic_type
just(Token::Control(Control::Colon)).ignore_then(choice((
r#type
.clone()
.separated_by(just(Token::Control(Control::Comma)))
.collect()
@ -85,11 +104,12 @@ pub fn parser<'src>() -> DustParser<'src> {
just(Token::Keyword("list"))
.then(type_arguments)
.map(|(_, item_type)| Type::ListOf(Box::new(item_type))),
basic_type.clone(),
r#type.clone(),
identifier
.clone()
.map(|identifier| Type::Custom(identifier)),
)));
)))
});
let statement = recursive(|statement| {
let block = statement
@ -318,14 +338,14 @@ pub fn parser<'src>() -> DustParser<'src> {
let if_else = just(Token::Keyword("if"))
.ignore_then(expression.clone())
.then(statement.clone())
.then(block.clone())
.then(
just(Token::Keyword("else"))
.ignore_then(statement.clone())
.ignore_then(block.clone())
.or_not(),
)
.map(|((if_expression, if_statement), else_statement)| {
Statement::IfElse(IfElse::new(if_expression, if_statement, else_statement))
.map(|((if_expression, if_block), else_block)| {
Statement::IfElse(IfElse::new(if_expression, if_block, else_block))
})
.boxed();
@ -390,10 +410,12 @@ mod tests {
#[test]
fn r#if() {
assert_eq!(
parse(&lex("if true 'foo'").unwrap()).unwrap()[0].0,
parse(&lex("if true { 'foo' }").unwrap()).unwrap()[0].0,
Statement::IfElse(IfElse::new(
Expression::Value(ValueNode::Boolean(true)),
Statement::Expression(Expression::Value(ValueNode::String("foo".to_string()))),
Block::new(vec![Statement::Expression(Expression::Value(
ValueNode::String("foo".to_string())
))]),
None
))
)
@ -402,13 +424,15 @@ mod tests {
#[test]
fn if_else() {
assert_eq!(
parse(&lex("if true 'foo' else 'bar'").unwrap()).unwrap()[0].0,
parse(&lex("if true {'foo' } else { 'bar' }").unwrap()).unwrap()[0].0,
Statement::IfElse(IfElse::new(
Expression::Value(ValueNode::Boolean(true)),
Statement::Expression(Expression::Value(ValueNode::String("foo".to_string()))),
Some(Statement::Expression(Expression::Value(ValueNode::String(
"bar".to_string()
))))
Block::new(vec![Statement::Expression(Expression::Value(
ValueNode::String("foo".to_string())
))]),
Some(Block::new(vec![Statement::Expression(Expression::Value(
ValueNode::String("bar".to_string())
))]))
))
)
}