More tuple pattern work

This commit is contained in:
Greg Shuflin 2021-10-26 00:39:24 -07:00
parent 48e2d9a683
commit a03f570266
6 changed files with 77 additions and 3 deletions

View File

@ -3,6 +3,7 @@
## Testing
* Get a test library for running many unit tests working
* Write a human-readable display of the AST
## Symbols

View File

@ -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() {
}
};
}

View File

@ -311,8 +311,11 @@ impl ast::Pattern {
ast::Pattern::Ignored => {
Pattern::Ignored
},
ast::Pattern::TuplePattern(/*Vec<Pattern>*/..) => {
unimplemented!()
ast::Pattern::TuplePattern(subpatterns) => {
let pats: Vec<_> = subpatterns.iter().map(|pat| pat.reduce(symbol_table)).collect();
let pats: Result<Vec<Pattern>, 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) {

View File

@ -125,6 +125,7 @@ pub struct Alternative {
#[derive(Debug, Clone)]
pub enum Pattern {
Tuple(Vec<Pattern>),
Literal(Literal),
Ignored,
}

View File

@ -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())

View File

@ -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#"