Implement if/else, loops and breaks

This commit is contained in:
Jeff 2024-03-08 14:29:53 -05:00
parent 5571418d44
commit b7288ceed8
5 changed files with 57 additions and 17 deletions

View File

@ -28,11 +28,15 @@ impl<'src> IfElse<'src> {
impl<'src> AbstractTree for IfElse<'src> { impl<'src> AbstractTree for IfElse<'src> {
fn expected_type(&self, _context: &Context) -> Result<Type, ValidationError> { fn expected_type(&self, _context: &Context) -> Result<Type, ValidationError> {
todo!() Ok(Type::None)
} }
fn validate(&self, _context: &Context) -> Result<(), ValidationError> { fn validate(&self, _context: &Context) -> Result<(), ValidationError> {
todo!() if let Type::Boolean = self.if_expression.expected_type(_context)? {
Ok(())
} else {
Err(ValidationError::ExpectedBoolean)
}
} }
fn run(self, _context: &Context) -> Result<Action, RuntimeError> { fn run(self, _context: &Context) -> Result<Action, RuntimeError> {

View File

@ -40,11 +40,12 @@ impl<'src> AbstractTree for Loop<'src> {
} }
let statement = self.statements[index].clone(); let statement = self.statements[index].clone();
let action = statement.run(_context)?;
if let Statement::Break(expression) = statement { match action {
break expression.run(_context); Action::Return(_) => {}
} else { Action::None => {}
statement.run(_context)?; r#break => return Ok(r#break),
} }
} }
} }
@ -66,6 +67,6 @@ mod tests {
} }
.run(&Context::new()); .run(&Context::new());
assert_eq!(result, Ok(Action::Return(Value::integer(42)))) assert_eq!(result, Ok(Action::Break(Value::integer(42))))
} }
} }

View File

@ -22,7 +22,7 @@ impl<'src> AbstractTree for Statement<'src> {
Statement::Block(block) => block.expected_type(_context), Statement::Block(block) => block.expected_type(_context),
Statement::Break(expression) => expression.expected_type(_context), Statement::Break(expression) => expression.expected_type(_context),
Statement::Expression(expression) => expression.expected_type(_context), Statement::Expression(expression) => expression.expected_type(_context),
Statement::IfElse(_) => todo!(), 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),
} }
} }
@ -30,10 +30,10 @@ impl<'src> AbstractTree for Statement<'src> {
fn validate(&self, _context: &Context) -> Result<(), ValidationError> { fn validate(&self, _context: &Context) -> Result<(), ValidationError> {
match self { match self {
Statement::Assignment(assignment) => assignment.validate(_context), Statement::Assignment(assignment) => assignment.validate(_context),
Statement::Block(_) => todo!(), Statement::Block(block) => block.validate(_context),
Statement::Break(expression) => expression.validate(_context), Statement::Break(expression) => expression.validate(_context),
Statement::Expression(expression) => expression.validate(_context), Statement::Expression(expression) => expression.validate(_context),
Statement::IfElse(_) => todo!(), Statement::IfElse(if_else) => if_else.validate(_context),
Statement::Loop(r#loop) => r#loop.validate(_context), Statement::Loop(r#loop) => r#loop.validate(_context),
} }
} }
@ -41,10 +41,14 @@ impl<'src> AbstractTree for Statement<'src> {
fn run(self, _context: &Context) -> Result<Action, RuntimeError> { fn run(self, _context: &Context) -> Result<Action, RuntimeError> {
match self { match self {
Statement::Assignment(assignment) => assignment.run(_context), Statement::Assignment(assignment) => assignment.run(_context),
Statement::Block(_) => todo!(), Statement::Block(block) => block.run(_context),
Statement::Break(expression) => expression.run(_context), Statement::Break(expression) => {
let value = expression.run(_context)?.as_return_value()?;
Ok(Action::Break(value))
}
Statement::Expression(expression) => expression.run(_context), Statement::Expression(expression) => expression.run(_context),
Statement::IfElse(_) => todo!(), Statement::IfElse(if_else) => if_else.run(_context),
Statement::Loop(r#loop) => r#loop.run(_context), Statement::Loop(r#loop) => r#loop.run(_context),
} }
} }

View File

@ -259,10 +259,13 @@ 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(statement.clone())
.then_ignore(just(Token::Keyword("else"))) .then(
.then(statement.clone().or_not()) just(Token::Keyword("else"))
.map(|((if_expression, if_block), else_block)| { .ignore_then(statement.clone())
Statement::IfElse(IfElse::new(if_expression, if_block, else_block)) .or_not(),
)
.map(|((if_expression, if_statement), else_statement)| {
Statement::IfElse(IfElse::new(if_expression, if_statement, else_statement))
}) })
.boxed(); .boxed();
@ -290,6 +293,18 @@ mod tests {
use super::*; use super::*;
#[test]
fn r#if() {
assert_eq!(
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"))),
None
))
)
}
#[test] #[test]
fn if_else() { fn if_else() {
assert_eq!( assert_eq!(

View File

@ -18,3 +18,19 @@ fn loops_and_breaks() {
Ok(Some(Value::string("foobar"))) Ok(Some(Value::string("foobar")))
) )
} }
#[test]
fn r#if() {
assert_eq!(
interpret("if true 'foobar'"),
Ok(Some(Value::string("foobar")))
)
}
#[test]
fn if_else() {
assert_eq!(
interpret("if false 'foo' else 'bar'"),
Ok(Some(Value::string("bar")))
)
}