From 284d7ce383b72bc41654091400ba2bff5f69bc8b Mon Sep 17 00:00:00 2001 From: Greg Shuflin Date: Mon, 25 Oct 2021 22:39:29 -0700 Subject: [PATCH] Bunch of messing-around with case matching --- schala-lang/language/src/eval/mod.rs | 2 +- schala-lang/language/src/reduced_ir/mod.rs | 186 +++++++++++++++--- schala-lang/language/src/reduced_ir/types.rs | 22 ++- .../language/src/tree_walk_eval/mod.rs | 24 ++- .../language/src/tree_walk_eval/test.rs | 2 +- 5 files changed, 207 insertions(+), 29 deletions(-) diff --git a/schala-lang/language/src/eval/mod.rs b/schala-lang/language/src/eval/mod.rs index 1464178..16d537d 100644 --- a/schala-lang/language/src/eval/mod.rs +++ b/schala-lang/language/src/eval/mod.rs @@ -3,7 +3,7 @@ use std::fmt::Write; use std::io; use crate::util::ScopeStack; -use crate::reduced_ast::{BoundVars, ReducedAST, Stmt, Expr, Lit, Func, Alternative, Subpattern}; +use crate::reduced_ast::{BoundVars, ReducedAST, Stmt, Expr, Lit, Func, Alternative, Pattern}; use crate::builtin::Builtin; mod test; diff --git a/schala-lang/language/src/reduced_ir/mod.rs b/schala-lang/language/src/reduced_ir/mod.rs index 13f0333..c46572f 100644 --- a/schala-lang/language/src/reduced_ir/mod.rs +++ b/schala-lang/language/src/reduced_ir/mod.rs @@ -177,15 +177,14 @@ impl<'a> Reducer<'a> { } => { let alternatives = vec![ Alternative { - matchable: pattern.to_subpattern(self.symbol_table), + pattern: match pattern.reduce(self.symbol_table) { + Ok(p) => p, + Err(e) => return Expression::ReductionError(format!("Bad pattern: {:?}", e)), + }, item: self.function_internal_block(then_case), }, Alternative { - matchable: Subpattern { - tag: None, - subpatterns: vec![], - guard: None, - }, + pattern: Pattern::Ignored, item: match else_case.as_ref() { Some(else_case) => self.function_internal_block(else_case), None => vec![], @@ -289,33 +288,44 @@ impl<'a> Reducer<'a> { } impl ast::Pattern { + fn reduce(&self, symbol_table: &SymbolTable) -> Result { + Ok(Pattern::Ignored) + } +} + +/* +impl ast::Pattern { fn to_subpattern(&self, symbol_table: &SymbolTable) -> Subpattern { - Subpattern { - tag: None, - subpatterns: vec![], - guard: None, - } - /* - use self::Pattern::*; + use ast::Pattern::*; + use Expression::ReductionError; + match self { + Ignored => Subpattern { + tag: None, + subpatterns: vec![], + guard: None, + }, + Literal(lit) => lit.to_subpattern(symbol_table), + /* TupleStruct(QualifiedName { components, id }, inner_patterns) => { match symbol_table.lookup_symbol(id) { Some(symbol) => handle_symbol(Some(symbol), inner_patterns, symbol_table), None => panic!("Symbol {:?} not found", components), } } + */ + _ => Subpattern { + tag: None, + subpatterns: vec![], + guard: None, + } + } + /* TuplePattern(inner_patterns) => handle_symbol(None, inner_patterns, symbol_table), Record(_name, _pairs) => { unimplemented!() } - Ignored => Subpattern { - tag: None, - subpatterns: vec![], - guard: None, - bound_vars: vec![], - }, - Literal(lit) => lit.to_subpattern(symbol_table), VarOrName(QualifiedName { components, id }) => { // if symbol is Some, treat this as a symbol pattern. If it's None, treat it // as a variable. @@ -337,7 +347,139 @@ impl ast::Pattern { } } } - } - */ + */ } } +*/ + +/* +fn handle_symbol( + symbol: Option<&Symbol>, + inner_patterns: &[Pattern], + symbol_table: &SymbolTable, +) -> Subpattern { + use ast::Pattern::*; + + let tag = symbol.map(|symbol| match symbol.spec { + SymbolSpec::DataConstructor { index, .. } => index, + _ => { + panic!("Symbol is not a data constructor - this should've been caught in type-checking") + } + }); + let bound_vars = inner_patterns + .iter() + .map(|p| match p { + VarOrName(qualified_name) => { + let symbol_exists = symbol_table.lookup_symbol(&qualified_name.id).is_some(); + if symbol_exists { + None + } else { + let QualifiedName { components, .. } = qualified_name; + if components.len() == 1 { + Some(components[0].clone()) + } else { + panic!("Bad variable name in pattern"); + } + } + } + _ => None, + }) + .collect(); + + let subpatterns = inner_patterns + .iter() + .map(|p| match p { + Ignored => None, + VarOrName(_) => None, + Literal(other) => Some(other.to_subpattern(symbol_table)), + tp @ TuplePattern(_) => Some(tp.to_subpattern(symbol_table)), + ts @ TupleStruct(_, _) => Some(ts.to_subpattern(symbol_table)), + Record(..) => unimplemented!(), + }) + .collect(); + + let guard = None; + /* + let guard_equality_exprs: Vec = subpatterns.iter().map(|p| match p { + Literal(lit) => match lit { + _ => unimplemented!() + }, + _ => unimplemented!() + }).collect(); + */ + + Subpattern { + tag, + subpatterns, + guard, + bound_vars, + } +} +*/ + +/* +impl ast::PatternLiteral { + fn to_subpattern(&self, _symbol_table: &SymbolTable) -> Subpattern { + use ast::PatternLiteral::*; + + match self { + NumPattern { neg, num } => { + let comparison = Expression::Literal(match (neg, num) { + (false, ast::ExpressionKind::NatLiteral(n)) => Literal::Nat(*n), + (false, ast::ExpressionKind::FloatLiteral(f)) => Literal::Float(*f), + (true, ast::ExpressionKind::NatLiteral(n)) => Literal::Int(-(*n as i64)), + (true, ast::ExpressionKind::FloatLiteral(f)) => Literal::Float(-f), + _ => panic!("This should never happen"), + }); + unimplemented!() + /* + let guard = Some(Expr::Call { + f: Box::new(Expr::Func(Func::BuiltIn(Builtin::Equality))), + args: vec![comparison, Expr::ConditionalTargetSigilValue], + }); + Subpattern { + tag: None, + subpatterns: vec![], + guard, + } + */ + } + _ => unimplemented!() + /* + StringPattern(s) => { + let guard = Some(Expr::Call { + f: Box::new(Expr::Func(Func::BuiltIn(Builtin::Equality))), + args: vec![ + Expr::Lit(Lit::StringLit(s.clone())), + Expr::ConditionalTargetSigilValue, + ], + }); + + Subpattern { + tag: None, + subpatterns: vec![], + guard, + bound_vars: vec![], + } + } + BoolPattern(b) => { + let guard = Some(if *b { + Expr::ConditionalTargetSigilValue + } else { + Expr::Call { + f: Box::new(Expr::Func(Func::BuiltIn(Builtin::BooleanNot))), + args: vec![Expr::ConditionalTargetSigilValue], + } + }); + Subpattern { + tag: None, + subpatterns: vec![], + guard, + bound_vars: vec![], + } + } + */ + } + } +} +*/ diff --git a/schala-lang/language/src/reduced_ir/types.rs b/schala-lang/language/src/reduced_ir/types.rs index f046971..b384134 100644 --- a/schala-lang/language/src/reduced_ir/types.rs +++ b/schala-lang/language/src/reduced_ir/types.rs @@ -1,5 +1,6 @@ use std::collections::HashMap; use std::rc::Rc; +use std::convert::From; use crate::builtin::Builtin; use crate::symbol_table::{DefId, SymbolTable}; @@ -118,10 +119,17 @@ pub enum Literal { #[derive(Debug, Clone)] pub struct Alternative { - pub matchable: Subpattern, + pub pattern: Pattern, pub item: Vec, } +#[derive(Debug, Clone)] +pub enum Pattern { + Literal(Literal), + Ignored, +} + +/* #[derive(Debug, Clone)] pub struct Subpattern { pub tag: Option, @@ -129,3 +137,15 @@ pub struct Subpattern { //pub bound_vars: BoundVars, pub guard: Option, } +*/ + +#[derive(Debug)] +pub struct PatternError { + msg: String, +} + +impl From<&str> for PatternError { + fn from(s: &str) -> Self { + Self { msg: s.to_string() } + } +} diff --git a/schala-lang/language/src/tree_walk_eval/mod.rs b/schala-lang/language/src/tree_walk_eval/mod.rs index 7afe402..f3f7152 100644 --- a/schala-lang/language/src/tree_walk_eval/mod.rs +++ b/schala-lang/language/src/tree_walk_eval/mod.rs @@ -1,4 +1,4 @@ -use crate::reduced_ir::{ReducedIR, Expression, Lookup, Callable, FunctionDefinition, Statement, Literal}; +use crate::reduced_ir::{ReducedIR, Expression, Lookup, Callable, FunctionDefinition, Statement, Literal, Alternative, Pattern}; use crate::symbol_table::{DefId}; use crate::util::ScopeStack; use crate::builtin::Builtin; @@ -270,13 +270,29 @@ impl<'a> State<'a> { v => return Err(format!("Non-boolean value {:?} in if-statement", v).into()) } }, - Expression::CaseMatch { cond, alternatives } => { - panic!() - }, + Expression::CaseMatch { box cond, alternatives } => self.case_match_expression(cond, alternatives)?, Expression::ReductionError(e) => return Err(e.into()), }) } + fn case_match_expression(&mut self, cond: Expression, alternatives: Vec) -> EvalResult { + + fn matches(cond: &Expression, matcher: &Pattern) -> bool { + + + + false + } + + for alt in alternatives.into_iter() { + if matches(&cond, &alt.pattern) { + // Set up local vars + return self.block(alt.item) + } + } + Err("No valid match in match expression".into()) + } + fn call_expression(&mut self, f: Expression, args: Vec) -> EvalResult { let func = match self.expression(f)? { Primitive::Callable(func) => func, diff --git a/schala-lang/language/src/tree_walk_eval/test.rs b/schala-lang/language/src/tree_walk_eval/test.rs index 6af16a4..40a1646 100644 --- a/schala-lang/language/src/tree_walk_eval/test.rs +++ b/schala-lang/language/src/tree_walk_eval/test.rs @@ -87,13 +87,13 @@ fn basic_if_statement() { #[test] fn if_is_patterns() { -/* let source = r#" type Option = Some(T) | None let x = Option::Some(9); if x is Option::Some(q) then { q } else { 0 }"#; eval_assert(source, "9"); +/* let source = r#" type Option = Some(T) | None let x = Option::None; if x is Option::Some(q) then { q } else { 0 }"#;