More work on pattern-matching

This commit is contained in:
Greg Shuflin 2021-10-26 01:53:30 -07:00
parent e52d0bf515
commit 9e799c23ba
5 changed files with 49 additions and 18 deletions

View File

@ -4,6 +4,7 @@
* Get a test library for running many unit tests working
* Write a human-readable display of the AST
* Make an automatic (macro-based?) system for numbering compiler errors, this should be every type of error
## Symbols
@ -13,6 +14,8 @@
* dealing with variable lookup w/in functions/closures should probably happen in AST -> ReducedAST
* b/c that's where we go from a string name to a canonical ID (for e.g. 2nd param in 3rd enclosing scope)
* In fact to prove this works, the symbol table shoudl _parallelize_ the process of checking subscopes for local items
* Old notes on a plan of attack:
1. modify visitor so it can handle scopes

View File

@ -308,14 +308,15 @@ impl<'a> Reducer<'a> {
impl ast::Pattern {
fn reduce(&self, symbol_table: &SymbolTable) -> Result<Pattern, PatternError> {
Ok(match self {
ast::Pattern::Ignored => {
Pattern::Ignored
},
ast::Pattern::Ignored => Pattern::Ignored,
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)
let items: Vec<_> = subpatterns.iter().map(|pat| pat.reduce(symbol_table)).collect();
let items: Result<Vec<Pattern>, PatternError> = items.into_iter().collect();
let items = items?;
Pattern::Tuple {
tag: None,
subpatterns: items,
}
},
ast::Pattern::Literal(lit) => Pattern::Literal(match lit {
ast::PatternLiteral::NumPattern { neg, num } => match (neg, num) {
@ -328,15 +329,31 @@ impl ast::Pattern {
ast::PatternLiteral::StringPattern(s) => Literal::StringLit(s.clone()),
ast::PatternLiteral::BoolPattern(b) => Literal::Bool(*b),
}),
ast::Pattern::TupleStruct(_name, _subpatterns) => {
unimplemented!()
ast::Pattern::TupleStruct(name, subpatterns) => {
let symbol = symbol_table.lookup_symbol(&name.id).unwrap();
if let SymbolSpec::DataConstructor { index: tag, type_id, arity } = symbol.spec() {
let items: Vec<_> = subpatterns.iter().map(|pat| pat.reduce(symbol_table)).collect();
let items: Result<Vec<Pattern>, PatternError> = items.into_iter().collect();
let items = items?;
Pattern::Tuple {
tag: Some(tag as u32),
subpatterns: items,
}
} else {
return Err("Internal error, trying to match something that's not a DataConstructor".into());
}
},
ast::Pattern::VarOrName(name) => {
//TODO fix this symbol not existing
let symbol = symbol_table.lookup_symbol(&name.id).unwrap();
println!("VarOrName symbol: {:?}", symbol);
Pattern::Ignored
},
ast::Pattern::Record(name, /*Vec<(Rc<String>, Pattern)>*/ _) => {
unimplemented!()
},
ast::Pattern::VarOrName(_name) => {
unimplemented!()
},
})
}
}

View File

@ -125,7 +125,10 @@ pub struct Alternative {
#[derive(Debug, Clone)]
pub enum Pattern {
Tuple(Vec<Pattern>),
Tuple {
subpatterns: Vec<Pattern>,
tag: Option<u32>,
},
Literal(Literal),
Ignored,
}

View File

@ -284,10 +284,19 @@ impl<'a> State<'a> {
} else {
false
},
Pattern::Tuple(subpatterns) => match scrut {
Pattern::Tuple { subpatterns, tag } => match tag {
None => 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
},
Some(pattern_tag) => match scrut {
//TODO should test type_ids for runtime type checking, once those work
Primitive::Object { tag, items, .. } if tag == pattern_tag && items.len() == subpatterns.len() => {
items.iter().zip(subpatterns.iter()).all(|(item, subpat)| matches(item, subpat))
}
_ => false
}
}
}
}

View File

@ -6,7 +6,6 @@ use crate::tree_walk_eval::State;
fn evaluate_input(input: &str) -> Result<String, String> {
let ast = crate::util::quick_ast(input);
println!("AST: {:?}", ast);
let mut symbol_table = SymbolTable::new();
symbol_table.process_ast(&ast).unwrap();
let reduced_ir = crate::reduced_ir::reduce(&ast, &symbol_table);