diff --git a/TODO.md b/TODO.md index ba412e1..71a63cb 100644 --- a/TODO.md +++ b/TODO.md @@ -3,6 +3,7 @@ ## Testing * Get a test library for running many unit tests working +* Write a human-readable display of the AST ## Symbols diff --git a/schala-lang/language/src/parsing/test.rs b/schala-lang/language/src/parsing/test.rs index 5ec8826..68c390f 100644 --- a/schala-lang/language/src/parsing/test.rs +++ b/schala-lang/language/src/parsing/test.rs @@ -830,6 +830,55 @@ fn if_expr() { } } +#[test] +fn advanced_if_expr() { + + parse_test_wrap_ast! { + r#" +if (45, "panda", false, 2.2) { + is (49, "pablo", _, 28.4) then "no" + is (_, "panda", _, -2.2) then "yes" + is _ then "maybe" +}"#, + exst!( + IfExpression { + discriminator: Some(bx!(ex!(s r#"(45, "panda", false, 2.2)"#))), + body: bx!(IfExpressionBody::CondList(vec![ + ConditionArm { + condition: Condition::Pattern(Pattern::TuplePattern( + vec![ + Pattern::Literal(PatternLiteral::NumPattern { neg: false, num: NatLiteral(49) }), + Pattern::Literal(PatternLiteral::StringPattern(rc!(pablo))), + Pattern::Ignored, + Pattern::Literal(PatternLiteral::NumPattern { neg: false, num: FloatLiteral(28.4) }), + ] + )), + guard: None, + body: vec![exst!(s r#""no""#)], + }, + ConditionArm { + condition: Condition::Pattern(Pattern::TuplePattern( + vec![ + Pattern::Ignored, + Pattern::Literal(PatternLiteral::StringPattern(rc!(panda))), + Pattern::Ignored, + Pattern::Literal(PatternLiteral::NumPattern { neg: true, num: FloatLiteral(2.2) }), + ] + )), + guard: None, + body: vec![exst!(s r#""yes""#)], + }, + ConditionArm { + condition: Condition::Pattern(Pattern::Ignored), + guard: None, + body: vec![exst!(s r#""maybe""#)], + }, + ])) + } + ) + } +} + #[test] fn modules() { parse_test_wrap_ast! { @@ -890,4 +939,3 @@ fn annotations() { } }; } - diff --git a/schala-lang/language/src/reduced_ir/mod.rs b/schala-lang/language/src/reduced_ir/mod.rs index 68e3641..fbf76ae 100644 --- a/schala-lang/language/src/reduced_ir/mod.rs +++ b/schala-lang/language/src/reduced_ir/mod.rs @@ -311,8 +311,11 @@ impl ast::Pattern { ast::Pattern::Ignored => { Pattern::Ignored }, - ast::Pattern::TuplePattern(/*Vec*/..) => { - unimplemented!() + ast::Pattern::TuplePattern(subpatterns) => { + let pats: Vec<_> = subpatterns.iter().map(|pat| pat.reduce(symbol_table)).collect(); + let pats: Result, PatternError> = pats.into_iter().collect(); + let pats = pats?; + Pattern::Tuple(pats) }, ast::Pattern::Literal(lit) => Pattern::Literal(match lit { ast::PatternLiteral::NumPattern { neg, num } => match (neg, num) { diff --git a/schala-lang/language/src/reduced_ir/types.rs b/schala-lang/language/src/reduced_ir/types.rs index bf52baa..55bf303 100644 --- a/schala-lang/language/src/reduced_ir/types.rs +++ b/schala-lang/language/src/reduced_ir/types.rs @@ -125,6 +125,7 @@ pub struct Alternative { #[derive(Debug, Clone)] pub enum Pattern { + Tuple(Vec), Literal(Literal), Ignored, } diff --git a/schala-lang/language/src/tree_walk_eval/mod.rs b/schala-lang/language/src/tree_walk_eval/mod.rs index a673ba6..c1d7fb9 100644 --- a/schala-lang/language/src/tree_walk_eval/mod.rs +++ b/schala-lang/language/src/tree_walk_eval/mod.rs @@ -284,6 +284,11 @@ impl<'a> State<'a> { } else { false }, + Pattern::Tuple(subpatterns) => match scrut { + Primitive::Tuple(items) if items.len() == subpatterns.len() => + items.iter().zip(subpatterns.iter()).all(|(item, subpat)| matches(item, subpat)), + _ => false //TODO should be a type error + } } } let cond = self.expression(cond)?; @@ -413,6 +418,7 @@ impl<'a> State<'a> { (BooleanNot, Lit(Bool(false))) => Bool(true), (Negate, Lit(Nat(n))) => Int(-(*n as i64)), (Negate, Lit(Int(n))) => Int(-(*n as i64)), + (Negate, Lit(Float(f))) => Float(-(*f as f64)), (Increment, Lit(Int(n))) => Int(*n), (Increment, Lit(Nat(n))) => Nat(*n), _ => return Err("No valid prefix op".into()) diff --git a/schala-lang/language/src/tree_walk_eval/test.rs b/schala-lang/language/src/tree_walk_eval/test.rs index 82cea92..99e02c7 100644 --- a/schala-lang/language/src/tree_walk_eval/test.rs +++ b/schala-lang/language/src/tree_walk_eval/test.rs @@ -116,6 +116,21 @@ if x { eval_assert(&source, expected); } +#[test_case(r#"(45, "panda", false, 2.2)"#, r#""yes""#)] +#[test_case(r#"(99, "panda", false, -2.45)"#, r#""maybe""#)] +fn tuple_patterns(input: &str, expected: &str) { + let mut source = format!("let x = {}", input); + source.push_str(r#" +if x { + is (45, "pablo", _, 28.4) then "no" + is (_, "panda", _, 2.2) then "yes" + is _ then "maybe" +}"#); +println!("{}", source); + + eval_assert(&source, expected); +} + #[test] fn if_is_patterns() { let source = r#"