Pass all tests

This commit is contained in:
Jeff 2024-03-11 15:17:01 -04:00
parent bf72e779fe
commit 780ea0858b
8 changed files with 49 additions and 18 deletions

View File

@ -38,7 +38,7 @@ impl Assignment {
impl AbstractTree for Assignment { impl AbstractTree for Assignment {
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> {

View File

@ -63,10 +63,12 @@ mod tests {
#[test] #[test]
fn basic_loop() { fn basic_loop() {
let result = 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()); .run(&Context::new());
assert_eq!(result, Ok(Action::Break(Value::integer(42)))) assert_eq!(result, Ok(Action::Break(Some(Value::integer(42)))))
} }
} }

View File

@ -42,7 +42,7 @@ pub trait AbstractTree {
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord)] #[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord)]
pub enum Action { pub enum Action {
Break(Value), Break(Option<Value>),
Return(Value), Return(Value),
None, None,
} }
@ -50,7 +50,13 @@ pub enum Action {
impl Action { impl Action {
pub fn as_value(self) -> Result<Value, ValidationError> { pub fn as_value(self) -> Result<Value, ValidationError> {
match self { 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::Return(value) => Ok(value),
Action::None => Err(ValidationError::ExpectedValue), Action::None => Err(ValidationError::ExpectedValue),
} }

View File

@ -9,7 +9,7 @@ use super::{AbstractTree, Action, Assignment, Block, Expression, IfElse, Loop, T
pub enum Statement { pub enum Statement {
Assignment(Assignment), Assignment(Assignment),
Block(Block), Block(Block),
Break(Expression), Break(Option<Expression>),
Expression(Expression), Expression(Expression),
IfElse(IfElse), IfElse(IfElse),
Loop(Loop), Loop(Loop),
@ -20,7 +20,13 @@ impl AbstractTree for Statement {
match self { match self {
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(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::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),
@ -31,7 +37,13 @@ impl AbstractTree for Statement {
match self { match self {
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(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::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),
@ -43,9 +55,13 @@ 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(expression) => { 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::Expression(expression) => expression.run(_context),
Statement::IfElse(if_else) => if_else.run(_context), Statement::IfElse(if_else) => if_else.run(_context),

View File

@ -53,7 +53,13 @@ impl Interpreter {
for (statement, _span) in statements { for (statement, _span) in statements {
value = match statement.run(&self.context) { value = match statement.run(&self.context) {
Ok(action) => match action { 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::Return(value) => Some(value),
Action::None => continue, Action::None => continue,
}, },

View File

@ -305,7 +305,7 @@ pub fn parser<'src>() -> DustParser<'src> {
.boxed(); .boxed();
let r#break = just(Token::Keyword("break")) let r#break = just(Token::Keyword("break"))
.ignore_then(expression.clone()) .ignore_then(expression.clone().or_not())
.map(|expression| Statement::Break(expression)); .map(|expression| Statement::Break(expression));
let assignment = identifier let assignment = identifier

View File

@ -5,24 +5,25 @@ fn loops_and_breaks() {
assert_eq!( assert_eq!(
interpret( interpret(
" "
i = 0; i = 0
loop { loop {
if i == 3 { if i == 3 {
break 'foobar' break
} else { } else {
i += 1 i += 1
} }
} }
i
" "
), ),
Ok(Some(Value::string("foobar".to_string()))) Ok(Some(Value::integer(3)))
) )
} }
#[test] #[test]
fn r#if() { fn r#if() {
assert_eq!( assert_eq!(
interpret("if true 'foobar'"), interpret("if true { 'foobar' }"),
Ok(Some(Value::string("foobar".to_string()))) Ok(Some(Value::string("foobar".to_string())))
) )
} }
@ -30,7 +31,7 @@ fn r#if() {
#[test] #[test]
fn if_else() { fn if_else() {
assert_eq!( assert_eq!(
interpret("if false 'foo' else 'bar'"), interpret("if false { 'foo' } else { 'bar' }"),
Ok(Some(Value::string("bar".to_string()))) Ok(Some(Value::string("bar".to_string())))
) )
} }

View File

@ -37,7 +37,7 @@ fn set_variable_with_type_error() {
#[test] #[test]
fn function_variable() { fn function_variable() {
assert_eq!( assert_eq!(
interpret("foobar = (x: int): int x; foobar"), interpret("foobar = (x: int): int { x }; foobar"),
Ok(Some(Value::function( Ok(Some(Value::function(
vec![(Identifier::new("x"), Type::Integer)], vec![(Identifier::new("x"), Type::Integer)],
Type::Integer, Type::Integer,