diff --git a/dust-lang/src/abstract_tree/if_else.rs b/dust-lang/src/abstract_tree/if_else.rs index a9f4166..449afeb 100644 --- a/dust-lang/src/abstract_tree/if_else.rs +++ b/dust-lang/src/abstract_tree/if_else.rs @@ -39,16 +39,16 @@ impl AbstractNode for IfElse { self.if_expression.validate(context)?; self.if_block.node.validate(context)?; + let expected_type = self.if_block.node.expected_type(context)?; let if_expression_type = self.if_expression.expected_type(context)?; if let Type::Boolean = if_expression_type { if let Some(else_block) = &self.else_block { else_block.node.validate(context)?; - let expected = self.if_block.node.expected_type(context)?; let actual = else_block.node.expected_type(context)?; - expected + expected_type .check(&actual) .map_err(|conflict| ValidationError::TypeCheck { conflict, @@ -56,14 +56,37 @@ impl AbstractNode for IfElse { expected_position: self.if_expression.position(), })?; } - - Ok(()) } else { - Err(ValidationError::ExpectedBoolean { + return Err(ValidationError::ExpectedBoolean { actual: if_expression_type, position: self.if_expression.position(), - }) + }); } + + for (expression, block) in &self.else_ifs { + let expression_type = expression.expected_type(context)?; + + if let Type::Boolean = expression_type { + block.node.validate(context)?; + + let actual = block.node.expected_type(context)?; + + expected_type + .check(&actual) + .map_err(|conflict| ValidationError::TypeCheck { + conflict, + actual_position: self.if_block.node.last_statement().position(), + expected_position: self.if_expression.position(), + })?; + } else { + return Err(ValidationError::ExpectedBoolean { + actual: if_expression_type, + position: self.if_expression.position(), + }); + } + } + + Ok(()) } fn run(self, context: &Context) -> Result { @@ -80,10 +103,37 @@ impl AbstractNode for IfElse { if let ValueInner::Boolean(if_boolean) = value.inner().as_ref() { if *if_boolean { self.if_block.node.run(context) - } else if let Some(else_statement) = self.else_block { - else_statement.node.run(context) } else { - Ok(Action::None) + for (expression, block) in self.else_ifs { + let expression_position = expression.position(); + let action = expression.run(context)?; + let value = if let Action::Return(value) = action { + value + } else { + return Err(RuntimeError::ValidationFailure( + ValidationError::InterpreterExpectedReturn(expression_position), + )); + }; + + if let ValueInner::Boolean(else_if_boolean) = value.inner().as_ref() { + if *else_if_boolean { + return block.node.run(context); + } + } else { + return Err(RuntimeError::ValidationFailure( + ValidationError::ExpectedBoolean { + actual: value.r#type(context)?, + position: expression_position, + }, + )); + } + } + + if let Some(else_statement) = self.else_block { + else_statement.node.run(context) + } else { + Ok(Action::None) + } } } else { Err(RuntimeError::ValidationFailure( diff --git a/dust-lang/src/abstract_tree/while.rs b/dust-lang/src/abstract_tree/while.rs index 8783531..602bc8e 100644 --- a/dust-lang/src/abstract_tree/while.rs +++ b/dust-lang/src/abstract_tree/while.rs @@ -40,7 +40,7 @@ impl AbstractNode for While { fn run(self, _context: &Context) -> Result { let get_boolean = || -> Result { let expression_position = self.expression.position(); - let action = self.expression.run(_context)?; + let action = self.expression.clone().run(_context)?; if let Action::Return(value) = action { Ok(value) @@ -51,16 +51,14 @@ impl AbstractNode for While { } }; - if let ValueInner::Boolean(boolean) = get_boolean()?.inner().as_ref() { - while *boolean { - for statement in &self.statements { - let action = statement.clone().run(_context)?; + while let ValueInner::Boolean(true) = get_boolean()?.inner().as_ref() { + for statement in &self.statements { + let action = statement.clone().run(_context)?; - match action { - Action::Return(_) => {} - Action::None => {} - Action::Break => return Ok(Action::Break), - } + match action { + Action::Return(_) => {} + Action::None => {} + Action::Break => return Ok(Action::Break), } } } diff --git a/examples/fizzbuzz.ds b/examples/fizzbuzz.ds index 28211cc..37b4017 100644 --- a/examples/fizzbuzz.ds +++ b/examples/fizzbuzz.ds @@ -5,13 +5,13 @@ while count <= 15 { divides_by_5 = count % 5 == 0 if divides_by_3 && divides_by_5 { - output('fizzbuzz') + io.write_line('fizzbuzz') } else if divides_by_3 { - output('fizz') + io.write_line('fizz') } else if divides_by_5 { - output('buzz') + io.write_line('buzz') } else { - output(count) + io.write_line(count) } count += 1 diff --git a/std/io.ds b/std/io.ds index b47d873..953a7b7 100644 --- a/std/io.ds +++ b/std/io.ds @@ -3,7 +3,7 @@ io = { __READ_LINE__() } - write_line = (output: str) none { + write_line = (output: any) none { __WRITE_LINE__(output) } }