Fix bug with pattern matching

This commit is contained in:
Greg Shuflin 2021-10-26 13:02:40 -07:00
parent df173a0096
commit b9767d0d7d
4 changed files with 59 additions and 54 deletions

View File

@ -27,47 +27,6 @@ macro_rules! test_in_fresh_env {
}
}
#[test]
fn if_is_patterns() {
let source = r#"
type Option<T> = Some(T) | None
let x = Option::Some(9); if x is Option::Some(q) then { q } else { 0 }"#;
test_in_fresh_env!(source, "9");
let source = r#"
type Option<T> = Some(T) | None
let x = Option::None; if x is Option::Some(q) then { q } else { 0 }"#;
test_in_fresh_env!(source, "0");
}
#[test]
fn full_if_matching() {
let source = r#"
type Option<T> = Some(T) | None
let a = Option::None
if a { is Option::None then 4, is Option::Some(x) then x }
"#;
test_in_fresh_env!(source, "4");
let source = r#"
type Option<T> = Some(T) | None
let a = Option::Some(99)
if a { is Option::None then 4, is Option::Some(x) then x }
"#;
test_in_fresh_env!(source, "99");
let source = r#"
let a = 10
if a { is 10 then "x", is 4 then "y" }
"#;
test_in_fresh_env!(source, "\"x\"");
let source = r#"
let a = 10
if a { is 15 then "x", is 10 then "y" }
"#;
test_in_fresh_env!(source, "\"y\"");
}
#[test]
fn string_pattern() {

View File

@ -344,11 +344,20 @@ impl ast::Pattern {
}
},
ast::Pattern::VarOrName(name) => {
//TODO fix this symbol not existing
let symbol = symbol_table.lookup_symbol(&name.id).unwrap();
println!("VarOrName symbol: {:?}", symbol);
let def_id = symbol.def_id().unwrap().clone();
Pattern::Binding(def_id)
match symbol.spec() {
SymbolSpec::DataConstructor { index: tag, type_id, arity } => {
Pattern::Tuple {
tag: Some(tag as u32),
subpatterns: vec![]
}
},
SymbolSpec::LocalVariable => {
let def_id = symbol.def_id().unwrap().clone();
Pattern::Binding(def_id)
},
spec => return Err(format!("Unexpected VarOrName symbol: {:?}", spec).into())
}
},
ast::Pattern::Record(name, /*Vec<(Rc<String>, Pattern)>*/ _) => {
unimplemented!()

View File

@ -72,7 +72,8 @@ impl<'a> ScopeResolver<'a> {
/// mappings.
fn lookup_name_in_scope(&mut self, name: &QualifiedName) {
let QualifiedName { id, components } = name;
//TODO handle a "partial" qualified name
//TODO handle a "partial" qualified name, and also handle it down in the pattern-matching
//section
//TODO some of these if lets that look into the fqsn_to_symbol table should probaby fail
//with an error
if components.len() == 1 {
@ -298,13 +299,21 @@ impl<'a> ASTVisitor for ScopeResolver<'a> {
}
//TODO this isn't really the right syntax for a VarOrName
VarOrName(ref name @ QualifiedName { id, components }) => {
//TODO need a better way to construct a FQSN from a QualifiedName
let local_name: Rc<String> = components[0].clone();
let lscope = Scope::Name(Rc::new("<local-case-match>".to_string()));
let fqsn = Fqsn { scopes: vec![lscope, Scope::Name(local_name.clone())] };
//let local_name = fqsn.local_name();
self.symbol_table.add_symbol(id, fqsn, SymbolSpec::LocalVariable);
self.lexical_scopes.insert(local_name.clone(), NameType::LocalVariable(id.clone()));
if components.len() == 1 {
//TODO need a better way to construct a FQSN from a QualifiedName
let local_name: Rc<String> = components[0].clone();
let lscope = Scope::Name(Rc::new("<local-case-match>".to_string()));
let fqsn = Fqsn { scopes: vec![lscope, Scope::Name(local_name.clone())] };
//let local_name = fqsn.local_name();
self.symbol_table.add_symbol(id, fqsn, SymbolSpec::LocalVariable);
self.lexical_scopes.insert(local_name.clone(), NameType::LocalVariable(id.clone()));
} else {
let fqsn = Fqsn { scopes: components.iter().map(|name| Scope::Name(name.clone())).collect() };
let symbol = self.symbol_table.fqsn_to_symbol.get(&fqsn);
if let Some(symbol) = symbol {
self.symbol_table.id_to_symbol.insert(id.clone(), symbol.clone());
}
}
},
};
Recursion::Continue

View File

@ -127,7 +127,6 @@ if x {
is (_, "panda", _, 2.2) then "yes"
is _ then "maybe"
}"#);
println!("{}", source);
eval_assert(&source, expected);
}
@ -149,6 +148,35 @@ let x = Option::None; if x is Option::Some(q) then { q } else { -2 + outer }"#;
eval_assert(source, "0");
}
#[test]
fn full_if_matching() {
let source = r#"
type Option<T> = Some(T) | None
let a = Option::None
if a { is Option::None then 4, is Option::Some(x) then x }
"#;
eval_assert(source, "4");
let source = r#"
type Option<T> = Some(T) | None
let sara = Option::Some(99)
if sara { is Option::None then 1 + 3, is Option::Some(x) then x }
"#;
eval_assert(source, "99");
let source = r#"
let a = 10
if a { is 10 then "x", is 4 then "y" }
"#;
eval_assert(source, "\"x\"");
let source = r#"
let a = 10
if a { is 15 then "x", is 10 then "y" }
"#;
eval_assert(source, "\"y\"");
}
#[test]
fn basic_lambda_evaluation_1() {