Commit 96fee995 by Jeff Smits

Added ConsMatch which does a wide match on the current term constructor using a…

Added ConsMatch which does a wide match on the current term constructor using a hashmap. This patterns happens a lot in overloaded rules, which get compiled to guarded choice chains.
parent b840180e
......@@ -225,6 +225,14 @@ impl<'d, 'f : 'd> Eval<'d, 'f> for preprocess::Strategy {
context.drop_overlay();
s_else.eval(context, current)
}
ConsMatch(ref map, ref s_else) => {
let matching_arm = current.get_application().and_then(|(cons, _)| map.get(cons));
if let Option::Some(s_match) = matching_arm {
s_match.eval(context, current.clone())
} else {
s_else.eval(context, current)
}
}
PrimT(ref name, ref sargs, ref targs) => {
let sargs = sargs
.into_iter()
......
......@@ -8,7 +8,10 @@ use aterm::{ATerm as A, ATermFactory as ATF};
use try_from::{TryInto, TryFrom};
use fnv::FnvHashMap;
use std::result;
use std::rc::Rc;
pub fn preprocess<'a>(program: ctree::Module) -> Result<Vec<Def>> {
let decls = match program {
......@@ -27,7 +30,7 @@ pub fn preprocess<'a>(program: ctree::Module) -> Result<Vec<Def>> {
.collect()
}
#[derive(Debug, PartialEq, Eq, Hash, Clone)]
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum StrategyDef<'a> {
TopLevel(&'a Def),
Predefined {
......@@ -112,7 +115,7 @@ impl<'a> StrategyDef<'a> {
}
}
#[derive(Debug, PartialEq, Eq, Hash, Clone)]
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct Def {
pub name: String,
pub sargs: Vec<String>,
......@@ -151,7 +154,7 @@ impl TryFrom<ctree::Def> for Def {
}
}
#[derive(Debug, PartialEq, Eq, Hash, Clone)]
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum Strategy {
Let(Vec<Def>, Box<Strategy>),
CallT(String, Vec<Strategy>, Vec<BuildTerm>),
......@@ -162,7 +165,8 @@ pub enum Strategy {
Build(BuildTerm),
Scope(Vec<String>, Box<Strategy>),
Seq(Box<[Strategy]>),
GuardedLChoice(Box<[(Strategy, Strategy)]>, Box<Strategy>),
GuardedLChoice(Box<[(Strategy, Strategy)]>, Rc<Strategy>),
ConsMatch(FnvHashMap<String, Strategy>, Rc<Strategy>),
PrimT(String, Vec<Strategy>, Vec<BuildTerm>),
Some(Box<Strategy>),
One(Box<Strategy>),
......@@ -170,6 +174,66 @@ pub enum Strategy {
ImportTerm(ctree::ModName),
}
impl Strategy {
fn matches_cons(str: &ctree::Strategy) -> Option<String> {
use ctree::Strategy::*;
match *str {
Seq(ref s, _) |
Scope(_, ref s) |
Let(_, ref s) => Self::matches_cons(s),
Match(ref t) => Self::matches_cons_term(t),
_ => None,
}
}
fn matches_cons_term(trm: &ctree::Term) -> Option<String> {
use ctree::Term::*;
match *trm {
Anno(ref t, _) => Self::matches_cons_preterm(t),
As(_, ref t) => Self::matches_cons_term(t),
_ => None,
}
}
fn matches_cons_preterm(trm: &ctree::PreTerm) -> Option<String> {
use ctree::PreTerm::*;
use ctree::Term::Anno;
match *trm {
As(_, ref t) => Self::matches_cons_preterm(&**t),
Op(ref s, _) => Some(s.clone()),
Explode(Anno(ref pt,_), _) => match **pt {
Str(ref s) => Some(s.clone()),
_ => None,
},
_ => None,
}
}
fn build_cons_match(s_if: Box<ctree::Strategy>, s_then: Box<ctree::Strategy>, s_else: Box<ctree::Strategy>, cons: String) -> Result<Strategy> {
use ctree::Strategy as I;
use self::Strategy as O;
let mut map: FnvHashMap<String, Vec<(Strategy, Strategy)>> = FnvHashMap::default();
map.insert(cons, vec![((*s_if).try_into()?, (*s_then).try_into()?)]);
let mut value = *s_else;
while let I::GuardedLChoice(s_if, s_then, s_else) = value {
if let Some(cons) = Self::matches_cons(&s_if) {
map.entry(cons).or_insert_with(Vec::new).push(((*s_if).try_into()?, (*s_then).try_into()?));
value = *s_else;
} else {
value = I::GuardedLChoice(s_if, s_then, s_else);
break;
}
}
let s_else: Rc<Strategy> = Rc::new(value.try_into()?);
if map.len() == 1 {
Ok(map.into_iter().map(|(_,v)| O::GuardedLChoice(v.into_boxed_slice(), s_else.clone())).next().expect("build_cons_match: Map should have had at least one item"))
} else {
let map: FnvHashMap<String, Strategy> = map.into_iter().map(|(k, v)| (k, O::GuardedLChoice(v.into_boxed_slice(), s_else.clone()))).collect();
Ok(O::ConsMatch(map, s_else))
}
}
}
impl TryFrom<ctree::Strategy> for Strategy {
type Err = Error;
......@@ -215,15 +279,19 @@ impl TryFrom<ctree::Strategy> for Strategy {
Ok(O::Seq(children.into_boxed_slice()))
}
I::GuardedLChoice(s_if, s_then, s_else) => {
let mut children = Vec::new();
children.push(((*s_if).try_into()?, (*s_then).try_into()?));
let mut value = *s_else;
while let I::GuardedLChoice(s_if, s_then, s_else) = value {
if let Some(cons) = Self::matches_cons(&s_if) {
Self::build_cons_match(s_if, s_then, s_else, cons)
} else {
let mut children = Vec::new();
children.push(((*s_if).try_into()?, (*s_then).try_into()?));
value = *s_else;
let mut value = *s_else;
while let I::GuardedLChoice(s_if, s_then, s_else) = value {
children.push(((*s_if).try_into()?, (*s_then).try_into()?));
value = *s_else;
}
let s_else = Rc::new(value.try_into()?);
Ok(O::GuardedLChoice(children.into_boxed_slice(), s_else))
}
let s_else = Box::new(value.try_into()?);
Ok(O::GuardedLChoice(children.into_boxed_slice(), s_else))
}
I::PrimT(prim_name, sargs, targs) => {
let t = try_into_vec(targs)?;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment