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

View File

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