Bunch of messing-around with case matching

This commit is contained in:
Greg Shuflin 2021-10-25 22:39:29 -07:00
parent 6162d05b60
commit 284d7ce383
5 changed files with 207 additions and 29 deletions

View File

@ -3,7 +3,7 @@ use std::fmt::Write;
use std::io; use std::io;
use crate::util::ScopeStack; 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; use crate::builtin::Builtin;
mod test; mod test;

View File

@ -177,15 +177,14 @@ impl<'a> Reducer<'a> {
} => { } => {
let alternatives = vec![ let alternatives = vec![
Alternative { 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), item: self.function_internal_block(then_case),
}, },
Alternative { Alternative {
matchable: Subpattern { pattern: Pattern::Ignored,
tag: None,
subpatterns: vec![],
guard: None,
},
item: match else_case.as_ref() { item: match else_case.as_ref() {
Some(else_case) => self.function_internal_block(else_case), Some(else_case) => self.function_internal_block(else_case),
None => vec![], None => vec![],
@ -289,33 +288,44 @@ impl<'a> Reducer<'a> {
} }
impl ast::Pattern { impl ast::Pattern {
fn reduce(&self, symbol_table: &SymbolTable) -> Result<Pattern, PatternError> {
Ok(Pattern::Ignored)
}
}
/*
impl ast::Pattern {
fn to_subpattern(&self, symbol_table: &SymbolTable) -> Subpattern { fn to_subpattern(&self, symbol_table: &SymbolTable) -> Subpattern {
Subpattern { use ast::Pattern::*;
use Expression::ReductionError;
match self {
Ignored => Subpattern {
tag: None, tag: None,
subpatterns: vec![], subpatterns: vec![],
guard: None, guard: None,
} },
Literal(lit) => lit.to_subpattern(symbol_table),
/* /*
use self::Pattern::*;
match self {
TupleStruct(QualifiedName { components, id }, inner_patterns) => { TupleStruct(QualifiedName { components, id }, inner_patterns) => {
match symbol_table.lookup_symbol(id) { match symbol_table.lookup_symbol(id) {
Some(symbol) => handle_symbol(Some(symbol), inner_patterns, symbol_table), Some(symbol) => handle_symbol(Some(symbol), inner_patterns, symbol_table),
None => panic!("Symbol {:?} not found", components), None => panic!("Symbol {:?} not found", components),
} }
} }
*/
_ => Subpattern {
tag: None,
subpatterns: vec![],
guard: None,
}
}
/*
TuplePattern(inner_patterns) => handle_symbol(None, inner_patterns, symbol_table), TuplePattern(inner_patterns) => handle_symbol(None, inner_patterns, symbol_table),
Record(_name, _pairs) => { Record(_name, _pairs) => {
unimplemented!() unimplemented!()
} }
Ignored => Subpattern {
tag: None,
subpatterns: vec![],
guard: None,
bound_vars: vec![],
},
Literal(lit) => lit.to_subpattern(symbol_table),
VarOrName(QualifiedName { components, id }) => { VarOrName(QualifiedName { components, id }) => {
// if symbol is Some, treat this as a symbol pattern. If it's None, treat it // if symbol is Some, treat this as a symbol pattern. If it's None, treat it
// as a variable. // 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<Expr> = 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![],
}
} }
*/ */
} }
} }
}
*/

View File

@ -1,5 +1,6 @@
use std::collections::HashMap; use std::collections::HashMap;
use std::rc::Rc; use std::rc::Rc;
use std::convert::From;
use crate::builtin::Builtin; use crate::builtin::Builtin;
use crate::symbol_table::{DefId, SymbolTable}; use crate::symbol_table::{DefId, SymbolTable};
@ -118,10 +119,17 @@ pub enum Literal {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Alternative { pub struct Alternative {
pub matchable: Subpattern, pub pattern: Pattern,
pub item: Vec<Statement>, pub item: Vec<Statement>,
} }
#[derive(Debug, Clone)]
pub enum Pattern {
Literal(Literal),
Ignored,
}
/*
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Subpattern { pub struct Subpattern {
pub tag: Option<usize>, pub tag: Option<usize>,
@ -129,3 +137,15 @@ pub struct Subpattern {
//pub bound_vars: BoundVars, //pub bound_vars: BoundVars,
pub guard: Option<Expression>, pub guard: Option<Expression>,
} }
*/
#[derive(Debug)]
pub struct PatternError {
msg: String,
}
impl From<&str> for PatternError {
fn from(s: &str) -> Self {
Self { msg: s.to_string() }
}
}

View File

@ -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::symbol_table::{DefId};
use crate::util::ScopeStack; use crate::util::ScopeStack;
use crate::builtin::Builtin; use crate::builtin::Builtin;
@ -270,13 +270,29 @@ impl<'a> State<'a> {
v => return Err(format!("Non-boolean value {:?} in if-statement", v).into()) v => return Err(format!("Non-boolean value {:?} in if-statement", v).into())
} }
}, },
Expression::CaseMatch { cond, alternatives } => { Expression::CaseMatch { box cond, alternatives } => self.case_match_expression(cond, alternatives)?,
panic!()
},
Expression::ReductionError(e) => return Err(e.into()), Expression::ReductionError(e) => return Err(e.into()),
}) })
} }
fn case_match_expression(&mut self, cond: Expression, alternatives: Vec<Alternative>) -> EvalResult<Primitive> {
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<Expression>) -> EvalResult<Primitive> { fn call_expression(&mut self, f: Expression, args: Vec<Expression>) -> EvalResult<Primitive> {
let func = match self.expression(f)? { let func = match self.expression(f)? {
Primitive::Callable(func) => func, Primitive::Callable(func) => func,

View File

@ -87,13 +87,13 @@ fn basic_if_statement() {
#[test] #[test]
fn if_is_patterns() { fn if_is_patterns() {
/*
let source = r#" let source = r#"
type Option<T> = Some(T) | None type Option<T> = Some(T) | None
let x = Option::Some(9); if x is Option::Some(q) then { q } else { 0 }"#; let x = Option::Some(9); if x is Option::Some(q) then { q } else { 0 }"#;
eval_assert(source, "9"); eval_assert(source, "9");
/*
let source = r#" let source = r#"
type Option<T> = Some(T) | None type Option<T> = Some(T) | None
let x = Option::None; if x is Option::Some(q) then { q } else { 0 }"#; let x = Option::None; if x is Option::Some(q) then { q } else { 0 }"#;