From 780ea0858b515b52a945947fbdb80111c58b3402 Mon Sep 17 00:00:00 2001 From: Jeff Date: Mon, 11 Mar 2024 15:17:01 -0400 Subject: [PATCH] Pass all tests --- src/abstract_tree/assignment.rs | 2 +- src/abstract_tree/loop.rs | 6 ++++-- src/abstract_tree/mod.rs | 10 ++++++++-- src/abstract_tree/statement.rs | 26 +++++++++++++++++++++----- src/lib.rs | 8 +++++++- src/parser.rs | 2 +- tests/statements.rs | 11 ++++++----- tests/variables.rs | 2 +- 8 files changed, 49 insertions(+), 18 deletions(-) diff --git a/src/abstract_tree/assignment.rs b/src/abstract_tree/assignment.rs index 81b2803..2f5b642 100644 --- a/src/abstract_tree/assignment.rs +++ b/src/abstract_tree/assignment.rs @@ -38,7 +38,7 @@ impl Assignment { impl AbstractTree for Assignment { fn expected_type(&self, _context: &Context) -> Result { - todo!() + Ok(Type::None) } fn validate(&self, context: &Context) -> Result<(), ValidationError> { diff --git a/src/abstract_tree/loop.rs b/src/abstract_tree/loop.rs index ac199bb..a9bc7c2 100644 --- a/src/abstract_tree/loop.rs +++ b/src/abstract_tree/loop.rs @@ -63,10 +63,12 @@ mod tests { #[test] fn basic_loop() { let result = Loop { - statements: vec![Statement::Break(Expression::Value(ValueNode::Integer(42)))], + statements: vec![Statement::Break(Some(Expression::Value( + ValueNode::Integer(42), + )))], } .run(&Context::new()); - assert_eq!(result, Ok(Action::Break(Value::integer(42)))) + assert_eq!(result, Ok(Action::Break(Some(Value::integer(42))))) } } diff --git a/src/abstract_tree/mod.rs b/src/abstract_tree/mod.rs index 7017019..a488a4b 100644 --- a/src/abstract_tree/mod.rs +++ b/src/abstract_tree/mod.rs @@ -42,7 +42,7 @@ pub trait AbstractTree { #[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord)] pub enum Action { - Break(Value), + Break(Option), Return(Value), None, } @@ -50,7 +50,13 @@ pub enum Action { impl Action { pub fn as_value(self) -> Result { match self { - Action::Break(value) => Ok(value), + Action::Break(value) => { + if let Some(value) = value { + Ok(value) + } else { + Err(ValidationError::ExpectedValue) + } + } Action::Return(value) => Ok(value), Action::None => Err(ValidationError::ExpectedValue), } diff --git a/src/abstract_tree/statement.rs b/src/abstract_tree/statement.rs index 984ca09..03cad38 100644 --- a/src/abstract_tree/statement.rs +++ b/src/abstract_tree/statement.rs @@ -9,7 +9,7 @@ use super::{AbstractTree, Action, Assignment, Block, Expression, IfElse, Loop, T pub enum Statement { Assignment(Assignment), Block(Block), - Break(Expression), + Break(Option), Expression(Expression), IfElse(IfElse), Loop(Loop), @@ -20,7 +20,13 @@ impl AbstractTree for Statement { match self { Statement::Assignment(assignment) => assignment.expected_type(_context), Statement::Block(block) => block.expected_type(_context), - Statement::Break(expression) => expression.expected_type(_context), + Statement::Break(expression_option) => { + if let Some(expression) = expression_option { + expression.expected_type(_context) + } else { + Ok(Type::None) + } + } 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), @@ -31,7 +37,13 @@ impl AbstractTree for Statement { match self { Statement::Assignment(assignment) => assignment.validate(_context), Statement::Block(block) => block.validate(_context), - Statement::Break(expression) => expression.validate(_context), + Statement::Break(expression_option) => { + if let Some(expression) = expression_option { + expression.validate(_context) + } else { + Ok(()) + } + } Statement::Expression(expression) => expression.validate(_context), Statement::IfElse(if_else) => if_else.validate(_context), Statement::Loop(r#loop) => r#loop.validate(_context), @@ -43,9 +55,13 @@ impl AbstractTree for Statement { Statement::Assignment(assignment) => assignment.run(_context), Statement::Block(block) => block.run(_context), Statement::Break(expression) => { - let value = expression.run(_context)?.as_return_value()?; + if let Some(expression) = expression { + let value = expression.run(_context)?.as_return_value()?; - Ok(Action::Break(value)) + Ok(Action::Break(Some(value))) + } else { + Ok(Action::Break(None)) + } } Statement::Expression(expression) => expression.run(_context), Statement::IfElse(if_else) => if_else.run(_context), diff --git a/src/lib.rs b/src/lib.rs index 15ec7c6..fb9e924 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -53,7 +53,13 @@ impl Interpreter { for (statement, _span) in statements { value = match statement.run(&self.context) { Ok(action) => match action { - Action::Break(value) => Some(value), + Action::Break(value_option) => { + if let Some(value) = value_option { + Some(value) + } else { + None + } + } Action::Return(value) => Some(value), Action::None => continue, }, diff --git a/src/parser.rs b/src/parser.rs index 9bee5b2..95769af 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -305,7 +305,7 @@ pub fn parser<'src>() -> DustParser<'src> { .boxed(); let r#break = just(Token::Keyword("break")) - .ignore_then(expression.clone()) + .ignore_then(expression.clone().or_not()) .map(|expression| Statement::Break(expression)); let assignment = identifier diff --git a/tests/statements.rs b/tests/statements.rs index 14ce920..7c64367 100644 --- a/tests/statements.rs +++ b/tests/statements.rs @@ -5,24 +5,25 @@ fn loops_and_breaks() { assert_eq!( interpret( " - i = 0; + i = 0 loop { if i == 3 { - break 'foobar' + break } else { i += 1 } } + i " ), - Ok(Some(Value::string("foobar".to_string()))) + Ok(Some(Value::integer(3))) ) } #[test] fn r#if() { assert_eq!( - interpret("if true 'foobar'"), + interpret("if true { 'foobar' }"), Ok(Some(Value::string("foobar".to_string()))) ) } @@ -30,7 +31,7 @@ fn r#if() { #[test] fn if_else() { assert_eq!( - interpret("if false 'foo' else 'bar'"), + interpret("if false { 'foo' } else { 'bar' }"), Ok(Some(Value::string("bar".to_string()))) ) } diff --git a/tests/variables.rs b/tests/variables.rs index 5712c49..72c8f47 100644 --- a/tests/variables.rs +++ b/tests/variables.rs @@ -37,7 +37,7 @@ fn set_variable_with_type_error() { #[test] fn function_variable() { assert_eq!( - interpret("foobar = (x: int): int x; foobar"), + interpret("foobar = (x: int): int { x }; foobar"), Ok(Some(Value::function( vec![(Identifier::new("x"), Type::Integer)], Type::Integer,