From 9e799c23ba47fe726ae7d3a5cfc20407bcf71bef Mon Sep 17 00:00:00 2001 From: Greg Shuflin Date: Tue, 26 Oct 2021 01:53:30 -0700 Subject: [PATCH] More work on pattern-matching --- TODO.md | 3 ++ schala-lang/language/src/reduced_ir/mod.rs | 41 +++++++++++++------ schala-lang/language/src/reduced_ir/types.rs | 5 ++- .../language/src/tree_walk_eval/mod.rs | 17 ++++++-- .../language/src/tree_walk_eval/test.rs | 1 - 5 files changed, 49 insertions(+), 18 deletions(-) diff --git a/TODO.md b/TODO.md index 71a63cb..0ef3f02 100644 --- a/TODO.md +++ b/TODO.md @@ -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 diff --git a/schala-lang/language/src/reduced_ir/mod.rs b/schala-lang/language/src/reduced_ir/mod.rs index fbf76ae..a678830 100644 --- a/schala-lang/language/src/reduced_ir/mod.rs +++ b/schala-lang/language/src/reduced_ir/mod.rs @@ -308,14 +308,15 @@ impl<'a> Reducer<'a> { impl ast::Pattern { fn reduce(&self, symbol_table: &SymbolTable) -> Result { 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, 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, 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, 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, Pattern)>*/ _) => { unimplemented!() }, - ast::Pattern::VarOrName(_name) => { - unimplemented!() - }, }) } } diff --git a/schala-lang/language/src/reduced_ir/types.rs b/schala-lang/language/src/reduced_ir/types.rs index 55bf303..03b7e8b 100644 --- a/schala-lang/language/src/reduced_ir/types.rs +++ b/schala-lang/language/src/reduced_ir/types.rs @@ -125,7 +125,10 @@ pub struct Alternative { #[derive(Debug, Clone)] pub enum Pattern { - Tuple(Vec), + Tuple { + subpatterns: Vec, + tag: Option, + }, 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 c1d7fb9..5a1aed4 100644 --- a/schala-lang/language/src/tree_walk_eval/mod.rs +++ b/schala-lang/language/src/tree_walk_eval/mod.rs @@ -284,10 +284,19 @@ 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 + 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 + } } } } diff --git a/schala-lang/language/src/tree_walk_eval/test.rs b/schala-lang/language/src/tree_walk_eval/test.rs index 99e02c7..5deddff 100644 --- a/schala-lang/language/src/tree_walk_eval/test.rs +++ b/schala-lang/language/src/tree_walk_eval/test.rs @@ -6,7 +6,6 @@ use crate::tree_walk_eval::State; fn evaluate_input(input: &str) -> Result { 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);