diff --git a/schala-lang/language/src/reduced_ir/mod.rs b/schala-lang/language/src/reduced_ir/mod.rs index 79a29ec..c203563 100644 --- a/schala-lang/language/src/reduced_ir/mod.rs +++ b/schala-lang/language/src/reduced_ir/mod.rs @@ -108,7 +108,7 @@ impl<'a> Reducer<'a> { let symbol = self.symbol_table.lookup_symbol(item_id).unwrap(); let def_id = symbol.def_id().unwrap(); let function_def = FunctionDefinition { - body: self.function(statements) + body: self.function_internal_block(statements) }; self.functions.insert(def_id, function_def); } @@ -136,7 +136,7 @@ impl<'a> Reducer<'a> { Lambda { params, body, .. } => { Expression::Callable(Callable::Lambda { arity: params.len() as u8, - body: self.function(body), + body: self.function_internal_block(body), }) }, NamedStruct { .. } => Expression::ReductionError("NamedStruct not implemented".to_string()), //self.reduce_named_struct(name, fields), @@ -147,8 +147,29 @@ impl<'a> Reducer<'a> { } } - fn reduce_if_expression(&mut self, _discriminator: Option<&ast::Expression>, _body: &ast::IfExpressionBody) -> Expression { - Expression::ReductionError("if expr".to_string()) + fn reduce_if_expression(&mut self, discriminator: Option<&ast::Expression>, body: &ast::IfExpressionBody) -> Expression { + let cond = Box::new(match discriminator { + Some(expr) => self.expression(expr), + None => return Expression::ReductionError("blank cond if-expr not supported".to_string()), + }); + match body { + ast::IfExpressionBody::SimpleConditional { + then_case, + else_case, + } => { + let then_clause = self.function_internal_block(then_case); + let else_clause = match else_case.as_ref() { + None => vec![], + Some(stmts) => self.function_internal_block(stmts), + }; + Expression::Conditional { + cond, + then_clause, + else_clause, + } + }, + _ => Expression::ReductionError("if expr".to_string()) + } } fn invocation_argument(&mut self, invoc: &ast::InvocationArgument) -> Expression { @@ -160,7 +181,7 @@ impl<'a> Reducer<'a> { } } - fn function(&mut self, statements: &ast::Block) -> Vec { + fn function_internal_block(&mut self, statements: &ast::Block) -> Vec { statements.iter().filter_map(|stmt| self.function_internal_statement(stmt)).collect() } diff --git a/schala-lang/language/src/reduced_ir/types.rs b/schala-lang/language/src/reduced_ir/types.rs index cad89ff..9e0dca7 100644 --- a/schala-lang/language/src/reduced_ir/types.rs +++ b/schala-lang/language/src/reduced_ir/types.rs @@ -61,6 +61,11 @@ pub enum Expression { f: Box, args: Vec }, + Conditional { + cond: Box, + then_clause: Vec, + else_clause: Vec, + }, ReductionError(String), } diff --git a/schala-lang/language/src/tree_walk_eval/mod.rs b/schala-lang/language/src/tree_walk_eval/mod.rs index 16f0cc7..3d59b9c 100644 --- a/schala-lang/language/src/tree_walk_eval/mod.rs +++ b/schala-lang/language/src/tree_walk_eval/mod.rs @@ -262,6 +262,14 @@ impl<'a> State<'a> { type_id, tag, items: vec![] }, Expression::Callable(func) => Primitive::Callable(func), + Expression::Conditional { box cond, then_clause, else_clause } => { + let cond = self.expression(cond)?; + match cond { + Primitive::Literal(Literal::Bool(true)) => self.block(then_clause)?, + Primitive::Literal(Literal::Bool(false)) => self.block(else_clause)?, + v => return Err(format!("Non-boolean value {:?} in if-statement", v).into()) + } + }, Expression::ReductionError(e) => return Err(e.into()), }) } diff --git a/schala-lang/language/src/tree_walk_eval/test.rs b/schala-lang/language/src/tree_walk_eval/test.rs index 80e4a9c..6af16a4 100644 --- a/schala-lang/language/src/tree_walk_eval/test.rs +++ b/schala-lang/language/src/tree_walk_eval/test.rs @@ -75,9 +75,19 @@ let b = Option::Some(10) eval_assert(source, "(Some(10), None)"); } -/* +#[test] +fn basic_if_statement() { + let source = r#" + let a = 10 + let b = 10 + if a == b then { 69 } else { 420 } + "#; + eval_assert(source, "69"); +} + #[test] fn if_is_patterns() { +/* let source = r#" type Option = Some(T) | None let x = Option::Some(9); if x is Option::Some(q) then { q } else { 0 }"#; @@ -88,8 +98,8 @@ let x = Option::Some(9); if x is Option::Some(q) then { q } else { 0 }"#; type Option = Some(T) | None let x = Option::None; if x is Option::Some(q) then { q } else { 0 }"#; eval_assert(source, "0"); -} */ +} #[test]