aboutsummaryrefslogtreecommitdiffstats
path: root/src/simplify.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/simplify.cpp')
-rw-r--r--src/simplify.cpp48
1 files changed, 42 insertions, 6 deletions
diff --git a/src/simplify.cpp b/src/simplify.cpp
index c5b2566..d6188ad 100644
--- a/src/simplify.cpp
+++ b/src/simplify.cpp
@@ -56,12 +56,12 @@ simplify_if(CEnv& cenv, const ATuple* aif) throw()
static const AST*
simplify_match(CEnv& cenv, const ATuple* match) throw()
{
+ const AST* const obj = resp_simplify(cenv, match->list_ref(1));
+
// Dot expression to get tag. Note index is -1 to compensate for the lift phase
// which adds 1 to skip the RTTI, which we don't want here (FIXME: ick...)
- List tval;
- tval.push_back(cenv.penv.sym("."));
- tval.push_back(resp_simplify(cenv, match->list_ref(1)));
- tval.push_back(new ALiteral<int32_t>(T_INT32, -1, Cursor()));
+ const AST* index = new ALiteral<int32_t>(T_INT32, -1, Cursor());
+ List tval(Cursor(), cenv.penv.sym("."), obj, index, 0);
const ASymbol* tsym = cenv.penv.gensym("__tag");
@@ -78,11 +78,47 @@ simplify_match(CEnv& cenv, const ATuple* match) throw()
const_cast<ASymbol*>(consTag)->tag(T_LITSYM);
cenv.setType(consTag, cenv.tenv.named("Symbol"));
+ const ATuple* texp = cenv.tenv.named(consTag->sym())->as_tuple();
+
+ // Append condition for this case
List cond(Cursor(), cenv.penv.sym("="), tsym, consTag, 0);
cenv.setType(cond, cenv.tenv.named("Bool"));
-
copyIf.push_back(cond);
- copyIf.push_back(resp_simplify(cenv, body));
+
+ // If constructor has no variables, append body and continue
+ // (don't generate pointless fn)
+ if (texp->list_len() == 2) {
+ copyIf.push_back(body);
+ continue;
+ }
+
+ // Build fn for the body of this case
+ const ASymbol* osym = cenv.penv.gensym("__obj");
+ const ATuple* prot = new ATuple(osym, 0, Cursor());
+ const ATuple* protT = new ATuple(texp->rst(), 0, Cursor());
+
+ List fn(Cursor(), cenv.penv.sym("fn"), prot, 0);
+ int idx = 0;
+ ATuple::const_iterator ti = texp->iter_at(2);
+ for (ATuple::const_iterator j = pat->iter_at(1); j != pat->end(); ++j, ++ti, ++idx) {
+ const AST* index = new ALiteral<int32_t>(T_INT32, idx, Cursor());
+ const AST* dot = tup(Cursor(), cenv.penv.sym("."), osym, index, 0);
+ const AST* def = tup(Cursor(), cenv.penv.sym("def"), *j, dot);
+ fn.push_back(def);
+ }
+
+ fn.push_back(resp_simplify(cenv, body));
+
+ List fnT(Cursor(), cenv.tenv.Fn, protT, cenv.type(match), 0);
+ assert(fnT.head->list_ref(1));
+ cenv.setType(fn, fnT);
+
+ const ATuple* cast = tup(Cursor(), cenv.penv.sym("cast"), obj, 0);
+ cenv.setType(cast, texp->rst());
+
+ List call(Cursor(), fn, cast, 0);
+ cenv.setTypeSameAs(call, match);
+ copyIf.push_back(call);
}
copyIf.push_back(cenv.penv.sym("__unreachable"));
cenv.setTypeSameAs(copyIf, match);