diff --git a/src/abstract_tree/if_else.rs b/src/abstract_tree/if_else.rs index 987afb6..352e0ef 100644 --- a/src/abstract_tree/if_else.rs +++ b/src/abstract_tree/if_else.rs @@ -7,29 +7,52 @@ use crate::{AbstractTree, Expression, Result, Statement, Value, VariableMap}; pub struct IfElse { if_expression: Expression, then_statement: Statement, + else_if_expressions: Vec, + else_if_statements: Vec, else_statement: Option, } impl AbstractTree for IfElse { fn from_syntax_node(node: Node, source: &str) -> Result { - let if_node = node.child(1).unwrap(); + let if_node = node.child(0).unwrap().child(1).unwrap(); let if_expression = Expression::from_syntax_node(if_node, source)?; - let then_node = node.child(3).unwrap(); + let then_node = node.child(0).unwrap().child(3).unwrap(); let then_statement = Statement::from_syntax_node(then_node, source)?; - let else_node = node.child(5); - let else_statement = if let Some(node) = else_node { - Some(Statement::from_syntax_node(node, source)?) - } else { - None - }; + let child_count = node.child_count(); + let mut else_if_expressions = Vec::new(); + let mut else_if_statements = Vec::new(); + let mut else_statement = None; - println!("{if_node:?} {then_node:?} {else_node:?}"); + for index in 1..child_count { + let child = node.child(index); + + if let Some(node) = child { + if node.kind() == "else_if" { + let expression_node = node.child(1).unwrap(); + let expression = Expression::from_syntax_node(expression_node, source)?; + + else_if_expressions.push(expression); + + let statement_node = node.child(3).unwrap(); + let statement = Statement::from_syntax_node(statement_node, source)?; + + else_if_statements.push(statement); + } + + if node.kind() == "else" { + let else_node = node.child(2).unwrap(); + else_statement = Some(Statement::from_syntax_node(else_node, source)?); + } + } + } Ok(IfElse { if_expression, then_statement, + else_if_expressions, + else_if_statements, else_statement, }) } @@ -39,10 +62,24 @@ impl AbstractTree for IfElse { if if_boolean { self.then_statement.run(context) - } else if let Some(statement) = &self.else_statement { - statement.run(context) } else { - Ok(Value::Empty) + let expressions = &self.else_if_expressions; + + for (index, expression) in expressions.into_iter().enumerate() { + let if_boolean = expression.run(context)?.as_boolean()?; + + if if_boolean { + let statement = self.else_if_statements.get(index).unwrap(); + + return statement.run(context); + } + } + + if let Some(statement) = &self.else_statement { + statement.run(context) + } else { + Ok(Value::Empty) + } } } } diff --git a/src/evaluator.rs b/src/evaluator.rs index a640fa0..884f62a 100644 --- a/src/evaluator.rs +++ b/src/evaluator.rs @@ -85,6 +85,8 @@ impl<'context, 'code> Evaluator<'context, 'code> { let root_node = cursor.node(); let mut prev_result = Ok(Value::Empty); + println!("{}", root_node.to_sexp()); + for item_node in root_node.children(&mut cursor) { let item = Item::from_syntax_node(item_node, self.source)?; prev_result = item.run(self.context); @@ -188,18 +190,18 @@ mod tests { } #[test] - fn evaluate_if_then() { + fn evaluate_if() { assert_eq!( - evaluate("if true then 'true'"), + evaluate("if true { 'true' }"), Ok(Value::String("true".to_string())) ); } #[test] - fn evaluate_if_then_else() { - assert_eq!(evaluate("if false then 1 else 2"), Ok(Value::Integer(2))); + fn evaluate_if_else() { + assert_eq!(evaluate("if false { 1 } else { 2 }"), Ok(Value::Integer(2))); assert_eq!( - evaluate("if true then 1.0 else 42.0"), + evaluate("if true { 1.0 } else { 42.0 }"), Ok(Value::Float(1.0)) ); } @@ -209,12 +211,13 @@ mod tests { assert_eq!( evaluate( " - if false - then 'no' - else if 1 + 1 == 3 - then 'nope' - else + if false { + 'no' + } else if 1 + 1 == 3 { + 'nope' + } else { 'ok' + } " ), Ok(Value::String("ok".to_string())) @@ -226,15 +229,17 @@ mod tests { assert_eq!( evaluate( " - if false - then 'no' - else if 1 + 1 == 1 - then 'nope' - else if 9 / 2 == 4 - then 'nope' - else if 'foo' == 'bar' - then 'nope' - else 'ok' + if false { + 'no' + } else if 1 + 1 == 1 { + 'nope' + } else if 9 / 2 == 4 { + 'nope' + } else if 'foo' == 'bar' { + 'nope' + } else { + 'ok' + } " ), Ok(Value::String("ok".to_string()))