More tuple-matching
Also discovered parser bug
This commit is contained in:
parent
62043ac2d1
commit
ec29077247
@ -7,7 +7,7 @@ use std::io;
|
|||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
|
|
||||||
use util::ScopeStack;
|
use util::ScopeStack;
|
||||||
use reduced_ast::{ReducedAST, Stmt, Expr, Lit, Func, Alternative};
|
use reduced_ast::{BoundVars, ReducedAST, Stmt, Expr, Lit, Func, Alternative, Subpattern};
|
||||||
use symbol_table::{SymbolSpec, Symbol, SymbolTable};
|
use symbol_table::{SymbolSpec, Symbol, SymbolTable};
|
||||||
|
|
||||||
pub struct State<'a> {
|
pub struct State<'a> {
|
||||||
@ -21,7 +21,6 @@ macro_rules! builtin_binding {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO add a more concise way of getting a new frame
|
|
||||||
impl<'a> State<'a> {
|
impl<'a> State<'a> {
|
||||||
pub fn new(symbol_table_handle: Rc<RefCell<SymbolTable>>) -> State<'a> {
|
pub fn new(symbol_table_handle: Rc<RefCell<SymbolTable>>) -> State<'a> {
|
||||||
let mut values = ScopeStack::new(Some(format!("global")));
|
let mut values = ScopeStack::new(Some(format!("global")));
|
||||||
@ -34,6 +33,19 @@ impl<'a> State<'a> {
|
|||||||
pub fn debug_print(&self) -> String {
|
pub fn debug_print(&self) -> String {
|
||||||
format!("Values: {:?}", self.values)
|
format!("Values: {:?}", self.values)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn new_frame(&'a self, items: &'a Vec<Node>, bound_vars: &BoundVars) -> State<'a> {
|
||||||
|
let mut inner_state = State {
|
||||||
|
values: self.values.new_scope(None),
|
||||||
|
symbol_table_handle: self.symbol_table_handle.clone(),
|
||||||
|
};
|
||||||
|
for (bound_var, val) in bound_vars.iter().zip(items.iter()) {
|
||||||
|
if let Some(bv) = bound_var.as_ref() {
|
||||||
|
inner_state.values.insert(bv.clone(), ValueEntry::Binding { constant: true, val: val.clone() });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
inner_state
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
@ -391,19 +403,27 @@ impl<'a> State<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn all_subpatterns_pass(state: &mut State, subpatterns: &Vec<Option<Subpattern>>, items: &Vec<Node>) -> EvalResult<bool> {
|
||||||
|
for (maybe_subp, cond) in subpatterns.iter().zip(items.iter()) {
|
||||||
|
if let Some(subp) = maybe_subp {
|
||||||
|
if let Some(ref guard) = subp.guard {
|
||||||
|
let guard_expr = match &cond {
|
||||||
|
Node::Expr(ref e) => guard.clone().replace_conditional_target_sigil(e),
|
||||||
|
_ => guard.clone()
|
||||||
|
};
|
||||||
|
if !state.expression(guard_expr.to_node())?.is_true() {
|
||||||
|
return Ok(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(true)
|
||||||
|
}
|
||||||
|
|
||||||
match cond {
|
match cond {
|
||||||
Node::PrimObject { ref tag, ref items, .. } => {
|
Node::PrimObject { ref tag, ref items, .. } => {
|
||||||
if alt.tag.map(|t| t == *tag).unwrap_or(true) {
|
if alt.tag.map(|t| t == *tag).unwrap_or(true) {
|
||||||
let mut inner_state = State {
|
let mut inner_state = self.new_frame(items, &alt.bound_vars);
|
||||||
values: self.values.new_scope(None),
|
|
||||||
symbol_table_handle: self.symbol_table_handle.clone(),
|
|
||||||
};
|
|
||||||
for (bound_var, val) in alt.bound_vars.iter().zip(items.iter()) {
|
|
||||||
if let Some(bv) = bound_var.as_ref() {
|
|
||||||
inner_state.values.insert(bv.clone(), ValueEntry::Binding { constant: true, val: val.clone() });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return inner_state.block(alt.item)
|
return inner_state.block(alt.item)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -412,32 +432,8 @@ impl<'a> State<'a> {
|
|||||||
return Err(format!("Subpattern length isn't correct"));
|
return Err(format!("Subpattern length isn't correct"));
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut inner_state = State {
|
let mut inner_state = self.new_frame(items, &alt.bound_vars);
|
||||||
values: self.values.new_scope(None),
|
if !all_subpatterns_pass(&mut inner_state, &alt.subpatterns, items)? {
|
||||||
symbol_table_handle: self.symbol_table_handle.clone(),
|
|
||||||
};
|
|
||||||
for (bound_var, val) in alt.bound_vars.iter().zip(items.iter()) {
|
|
||||||
if let Some(bv) = bound_var.as_ref() {
|
|
||||||
inner_state.values.insert(bv.clone(), ValueEntry::Binding { constant: true, val: val.clone() });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut passes = true;
|
|
||||||
for (maybe_subp, cond) in alt.subpatterns.iter().zip(items.iter()) {
|
|
||||||
if let Some(subp) = maybe_subp {
|
|
||||||
if let Some(ref guard) = subp.guard {
|
|
||||||
let guard_expr = match &cond {
|
|
||||||
Node::Expr(ref e) => guard.clone().replace_conditional_target_sigil(e),
|
|
||||||
_ => guard.clone()
|
|
||||||
};
|
|
||||||
if !inner_state.expression(guard_expr.to_node())?.is_true() {
|
|
||||||
passes = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !passes {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
return inner_state.block(alt.item)
|
return inner_state.block(alt.item)
|
||||||
@ -644,4 +640,49 @@ if Some(10) {
|
|||||||
"#;
|
"#;
|
||||||
test_in_fresh_env!(source, "\"hella\"");
|
test_in_fresh_env!(source, "\"hella\"");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn tuple_pattern() {
|
||||||
|
let source = r#"
|
||||||
|
if (1, 2) {
|
||||||
|
is (1, x) -> x,
|
||||||
|
is _ -> 99
|
||||||
|
}
|
||||||
|
"#;
|
||||||
|
test_in_fresh_env!(source, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn tuple_pattern_2() {
|
||||||
|
let source = r#"
|
||||||
|
if (1, 2) {
|
||||||
|
is (10, x) -> x,
|
||||||
|
is (y, x) -> x + y
|
||||||
|
}
|
||||||
|
"#;
|
||||||
|
test_in_fresh_env!(source, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn tuple_pattern_3() {
|
||||||
|
let source = r#"
|
||||||
|
if (1, 5) {
|
||||||
|
is (10, x) -> x,
|
||||||
|
is (1, x) -> x
|
||||||
|
}
|
||||||
|
"#;
|
||||||
|
test_in_fresh_env!(source, 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn need_to_fix_parser_to_make_work() {
|
||||||
|
let source = r#"
|
||||||
|
if (1, 5) {
|
||||||
|
is (10, x) -> x,
|
||||||
|
is (1, x) -> x,
|
||||||
|
}
|
||||||
|
"#;
|
||||||
|
test_in_fresh_env!(source, 5);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -56,12 +56,14 @@ pub enum Expr {
|
|||||||
UnimplementedSigilValue
|
UnimplementedSigilValue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub type BoundVars = Vec<Option<Rc<String>>>; //remember that order matters here
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Alternative {
|
pub struct Alternative {
|
||||||
pub tag: Option<usize>,
|
pub tag: Option<usize>,
|
||||||
pub subpatterns: Vec<Option<Subpattern>>,
|
pub subpatterns: Vec<Option<Subpattern>>,
|
||||||
pub guard: Option<Expr>,
|
pub guard: Option<Expr>,
|
||||||
pub bound_vars: Vec<Option<Rc<String>>>, //remember that order matters here
|
pub bound_vars: BoundVars,
|
||||||
pub item: Vec<Stmt>,
|
pub item: Vec<Stmt>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -69,7 +71,7 @@ pub struct Alternative {
|
|||||||
pub struct Subpattern {
|
pub struct Subpattern {
|
||||||
pub tag: Option<usize>,
|
pub tag: Option<usize>,
|
||||||
pub subpatterns: Vec<Option<Subpattern>>,
|
pub subpatterns: Vec<Option<Subpattern>>,
|
||||||
pub bound_vars: Vec<Option<Rc<String>>>,
|
pub bound_vars: BoundVars,
|
||||||
pub guard: Option<Expr>,
|
pub guard: Option<Expr>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user