aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/compile.cpp156
-rw-r--r--src/constrain.cpp228
-rw-r--r--src/lift.cpp80
3 files changed, 233 insertions, 231 deletions
diff --git a/src/compile.cpp b/src/compile.cpp
index 127a981..a696836 100644
--- a/src/compile.cpp
+++ b/src/compile.cpp
@@ -34,63 +34,27 @@ compile_symbol(CEnv& cenv, const ASymbol* sym) throw()
}
static CVal
-compile_fn(CEnv& cenv, const ATuple* fn) throw()
-{
- assert(!cenv.currentFn);
-
- const AType* type = cenv.type(fn);
- CFunc f = cenv.findImpl(fn, type);
- if (f)
- return f;
-
- // Write function declaration and push stack frame
- f = cenv.engine()->startFn(cenv, cenv.name(fn), fn->prot(), type);
- cenv.engine()->pushFnArgs(cenv, fn->prot(), type, f);
- cenv.currentFn = f;
-
- // Write function body
- CVal retVal = NULL;
- for (ATuple::const_iterator i = fn->iter_at(2); i != fn->end(); ++i)
- retVal = resp_compile(cenv, *i);
-
- // Write function conclusion and pop stack frame
- cenv.engine()->finishFn(cenv, f, retVal);
- cenv.pop();
- cenv.currentFn = NULL;
-
- cenv.vals.def(cenv.penv.sym(cenv.name(fn)), f);
- cenv.addImpl(fn, f);
- return f;
-}
-
-static CVal
-compile_type(CEnv& cenv, const AType* type) throw()
+compile_cons(CEnv& cenv, const ATuple* cons) throw()
{
- const ASymbol* sym = type->head()->as_symbol();
- CVal* existing = cenv.vals.ref(sym);
- if (existing) {
- return *existing;
- } else {
- CVal compiled = cenv.engine()->compileString(
- cenv, (string("__T_") + type->head()->str()).c_str());
- cenv.vals.def(sym, compiled);
- return compiled;
+ AType* type = new AType(cons->head()->as_symbol(), NULL, Cursor());
+ TList tlist(type);
+ vector<CVal> fields;
+ for (ATuple::const_iterator i = cons->iter_at(1); i != cons->end(); ++i) {
+ tlist.push_back(cenv.type(*i));
+ fields.push_back(resp_compile(cenv, *i));
}
+ return cenv.engine()->compileCons(cenv, type, resp_compile(cenv, type), fields);
}
static CVal
-compile_call(CEnv& cenv, const ATuple* call) throw()
+compile_dot(CEnv& cenv, const ATuple* dot) throw()
{
- CFunc f = resp_compile(cenv, call->head());
-
- if (!f)
- f = cenv.currentFn; // Recursive call (callee defined as a stub)
-
- vector<CVal> args;
- for (ATuple::const_iterator e = call->iter_at(1); e != call->end(); ++e)
- args.push_back(resp_compile(cenv, *e));
-
- return cenv.engine()->compileCall(cenv, f, cenv.type(call->head()), args);
+ ATuple::const_iterator i = dot->begin();
+ const AST* tup = *++i;
+ const ALiteral<int32_t>* index = (ALiteral<int32_t>*)(*++i);
+ assert(index->tag() == T_INT32);
+ CVal tupVal = resp_compile(cenv, tup);
+ return cenv.engine()->compileDot(cenv, tupVal, index->val + 1); // + 1 to skip RTTI
}
static CVal
@@ -110,27 +74,33 @@ compile_def(CEnv& cenv, const ATuple* def) throw()
}
static CVal
-compile_cons(CEnv& cenv, const ATuple* cons) throw()
+compile_fn(CEnv& cenv, const ATuple* fn) throw()
{
- AType* type = new AType(cons->head()->as_symbol(), NULL, Cursor());
- TList tlist(type);
- vector<CVal> fields;
- for (ATuple::const_iterator i = cons->iter_at(1); i != cons->end(); ++i) {
- tlist.push_back(cenv.type(*i));
- fields.push_back(resp_compile(cenv, *i));
- }
- return cenv.engine()->compileCons(cenv, type, resp_compile(cenv, type), fields);
-}
+ assert(!cenv.currentFn);
+
+ const AType* type = cenv.type(fn);
+ CFunc f = cenv.findImpl(fn, type);
+ if (f)
+ return f;
-static CVal
-compile_dot(CEnv& cenv, const ATuple* dot) throw()
-{
- ATuple::const_iterator i = dot->begin();
- const AST* tup = *++i;
- const ALiteral<int32_t>* index = (ALiteral<int32_t>*)(*++i);
- assert(index->tag() == T_INT32);
- CVal tupVal = resp_compile(cenv, tup);
- return cenv.engine()->compileDot(cenv, tupVal, index->val + 1); // + 1 to skip RTTI
+ // Write function declaration and push stack frame
+ f = cenv.engine()->startFn(cenv, cenv.name(fn), fn->prot(), type);
+ cenv.engine()->pushFnArgs(cenv, fn->prot(), type, f);
+ cenv.currentFn = f;
+
+ // Write function body
+ CVal retVal = NULL;
+ for (ATuple::const_iterator i = fn->iter_at(2); i != fn->end(); ++i)
+ retVal = resp_compile(cenv, *i);
+
+ // Write function conclusion and pop stack frame
+ cenv.engine()->finishFn(cenv, f, retVal);
+ cenv.pop();
+ cenv.currentFn = NULL;
+
+ cenv.vals.def(cenv.penv.sym(cenv.name(fn)), f);
+ cenv.addImpl(fn, f);
+ return f;
}
static CVal
@@ -173,6 +143,36 @@ compile_match(CEnv& cenv, const ATuple* match) throw()
return cenv.engine()->compileIfEnd(cenv, state, NULL, type);
}
+static CVal
+compile_type(CEnv& cenv, const AType* type) throw()
+{
+ const ASymbol* sym = type->head()->as_symbol();
+ CVal* existing = cenv.vals.ref(sym);
+ if (existing) {
+ return *existing;
+ } else {
+ CVal compiled = cenv.engine()->compileString(
+ cenv, (string("__T_") + type->head()->str()).c_str());
+ cenv.vals.def(sym, compiled);
+ return compiled;
+ }
+}
+
+static CVal
+compile_call(CEnv& cenv, const ATuple* call) throw()
+{
+ CFunc f = resp_compile(cenv, call->head());
+
+ if (!f)
+ f = cenv.currentFn; // Recursive call (callee defined as a stub)
+
+ vector<CVal> args;
+ for (ATuple::const_iterator e = call->iter_at(1); e != call->end(); ++e)
+ args.push_back(resp_compile(cenv, *e));
+
+ return cenv.engine()->compileCall(cenv, f, cenv.type(call->head()), args);
+}
+
CVal
resp_compile(CEnv& cenv, const AST* ast) throw()
{
@@ -196,20 +196,20 @@ resp_compile(CEnv& cenv, const AST* ast) throw()
const std::string form = sym ? sym->sym() : "";
if (is_primitive(cenv.penv, call))
return cenv.engine()->compilePrimitive(cenv, ast->as_tuple());
- else if (form == "fn")
- return compile_fn(cenv, call);
- else if (form == "def")
- return compile_def(cenv, call);
- else if (form == "if")
- return compile_if(cenv, call);
else if (form == "cons" || isupper(form[0]))
return compile_cons(cenv, call);
else if (form == ".")
return compile_dot(cenv, call);
+ else if (form == "def")
+ return compile_def(cenv, call);
+ else if (form == "def-type")
+ return NULL; // FIXME
+ else if (form == "fn")
+ return compile_fn(cenv, call);
+ else if (form == "if")
+ return compile_if(cenv, call);
else if (form == "match")
return compile_match(cenv, call);
- else if (form == "def-type")
- return NULL;
else
return compile_call(cenv, call);
}
diff --git a/src/constrain.cpp b/src/constrain.cpp
index 7b437c8..c4a08ec 100644
--- a/src/constrain.cpp
+++ b/src/constrain.cpp
@@ -31,58 +31,51 @@ constrain_symbol(TEnv& tenv, Constraints& c, const ASymbol* sym) throw(Error)
}
static void
-constrain_fn(TEnv& tenv, Constraints& c, const ATuple* call) throw(Error)
+constrain_cons(TEnv& tenv, Constraints& c, const ATuple* call) throw(Error)
{
- set<const ASymbol*> defs;
- TEnv::Frame frame;
-
- const ATuple* const prot = call->prot();
-
- // Add parameters to environment frame
- TList protT;
- for (ATuple::const_iterator i = prot->begin(); i != prot->end(); ++i) {
- const ASymbol* sym = (*i)->to_symbol();
- THROW_IF(!sym, (*i)->loc, "parameter name is not a symbol");
- THROW_IF(defs.count(sym) != 0, sym->loc,
- (format("duplicate parameter `%1%'") % sym->str()).str());
- defs.insert(sym);
- const AType* tvar = tenv.fresh(sym);
- frame.push_back(make_pair(sym->sym(), tvar));
- protT.push_back(tvar);
- }
- protT.head->loc = call->loc;
+ const ASymbol* sym = (*call->begin())->as_symbol();
+ const AType* type = NULL;
- ATuple::const_iterator i = call->iter_at(1);
- c.constrain(tenv, *i, protT);
+ for (ATuple::const_iterator i = call->iter_at(1); i != call->end(); ++i)
+ resp_constrain(tenv, c, *i);
- // Add internal definitions to environment frame
- for (++i; i != call->end(); ++i) {
- const AST* exp = *i;
- const ATuple* call = exp->to_tuple();
- if (call && is_form(call, "def")) {
- const ASymbol* sym = call->list_ref(1)->as_symbol();
- THROW_IF(defs.count(sym) != 0, call->loc,
- (format("`%1%' defined twice") % sym->str()).str());
- defs.insert(sym);
- frame.push_back(make_pair(sym->sym(), (AType*)NULL));
+ if (!strcmp(sym->sym(), "Tup")) {
+ TList tupT(new AType(tenv.Tup, NULL, call->loc));
+ for (ATuple::const_iterator i = call->iter_at(1); i != call->end(); ++i) {
+ tupT.push_back(tenv.var(*i));
}
+ type = tupT;
+ } else {
+ const AType** consTRef = tenv.ref(sym);
+ THROW_IF(!consTRef, call->loc,
+ (format("call to undefined constructor `%1%'") % sym->sym()).str());
+ const AType* consT = *consTRef;
+ type = new AType(consT->head()->as_type(), 0, call->loc);
}
+ c.constrain(tenv, call, type);
+}
- tenv.push(frame);
-
- const AST* exp = NULL;
- for (i = call->iter_at(2); i != call->end(); ++i) {
- exp = *i;
- resp_constrain(tenv, c, exp);
- }
+static void
+constrain_dot(TEnv& tenv, Constraints& c, const ATuple* call) throw(Error)
+{
+ THROW_IF(call->list_len() != 3, call->loc, "`.' requires exactly 2 arguments");
+ ATuple::const_iterator i = call->begin();
+ const AST* obj = *++i;
+ const AST* idx_ast = *++i;
+ THROW_IF(idx_ast->tag() != T_INT32, call->loc, "the 2nd argument to `.' must be a literal integer");
+ const ALiteral<int32_t>* idx = (ALiteral<int32_t>*)idx_ast;
- const AType* bodyT = tenv.var(exp);
- const AType* fnT = tup<const AType>(call->loc, tenv.Fn, protT.head, bodyT, 0);
- Object::pool.addRoot(fnT);
+ resp_constrain(tenv, c, obj);
- tenv.pop();
+ const AType* retT = tenv.var(call);
+ c.constrain(tenv, call, retT);
- c.constrain(tenv, call, fnT);
+ TList objT(new AType(tenv.Tup, NULL, call->loc));
+ for (int i = 0; i < idx->val; ++i)
+ objT.push_back(tenv.var());
+ objT.push_back(retT);
+ objT.push_back(tenv.Dots);
+ c.constrain(tenv, obj, objT);
}
static void
@@ -129,34 +122,58 @@ constrain_def_type(TEnv& tenv, Constraints& c, const ATuple* call) throw(Error)
}
static void
-constrain_match(TEnv& tenv, Constraints& c, const ATuple* call) throw(Error)
+constrain_fn(TEnv& tenv, Constraints& c, const ATuple* call) throw(Error)
{
- THROW_IF(call->list_len() < 5, call->loc, "`match' requires at least 4 arguments");
- const AST* matchee = call->list_ref(1);
- const AType* retT = tenv.var();
- const AType* matcheeT = NULL;// = tup<AType>(loc, tenv.U, 0);
- resp_constrain(tenv, c, matchee);
- for (ATuple::const_iterator i = call->iter_at(2); i != call->end();) {
- const AST* exp = *i++;
- const ATuple* pattern = exp->to_tuple();
- THROW_IF(!pattern, exp->loc, "pattern expression expected");
- const ASymbol* name = (*pattern->begin())->to_symbol();
- THROW_IF(!name, (*pattern->begin())->loc, "pattern does not start with a symbol");
+ set<const ASymbol*> defs;
+ TEnv::Frame frame;
- const AType* consT = *tenv.ref(name);
+ const ATuple* const prot = call->prot();
+
+ // Add parameters to environment frame
+ TList protT;
+ for (ATuple::const_iterator i = prot->begin(); i != prot->end(); ++i) {
+ const ASymbol* sym = (*i)->to_symbol();
+ THROW_IF(!sym, (*i)->loc, "parameter name is not a symbol");
+ THROW_IF(defs.count(sym) != 0, sym->loc,
+ (format("duplicate parameter `%1%'") % sym->str()).str());
+ defs.insert(sym);
+ const AType* tvar = tenv.fresh(sym);
+ frame.push_back(make_pair(sym->sym(), tvar));
+ protT.push_back(tvar);
+ }
+ protT.head->loc = call->loc;
- if (!matcheeT) {
- const AType* headT = consT->head()->as_type();
- matcheeT = new AType(headT, 0, call->loc);
+ ATuple::const_iterator i = call->iter_at(1);
+ c.constrain(tenv, *i, protT);
+
+ // Add internal definitions to environment frame
+ for (++i; i != call->end(); ++i) {
+ const AST* exp = *i;
+ const ATuple* call = exp->to_tuple();
+ if (call && is_form(call, "def")) {
+ const ASymbol* sym = call->list_ref(1)->as_symbol();
+ THROW_IF(defs.count(sym) != 0, call->loc,
+ (format("`%1%' defined twice") % sym->str()).str());
+ defs.insert(sym);
+ frame.push_back(make_pair(sym->sym(), (AType*)NULL));
}
+ }
- THROW_IF(i == call->end(), pattern->loc, "missing pattern body");
- const AST* body = *i++;
- resp_constrain(tenv, c, body);
- c.constrain(tenv, body, retT);
+ tenv.push(frame);
+
+ const AST* exp = NULL;
+ for (i = call->iter_at(2); i != call->end(); ++i) {
+ exp = *i;
+ resp_constrain(tenv, c, exp);
}
- c.constrain(tenv, call, retT);
- c.constrain(tenv, matchee, matcheeT);
+
+ const AType* bodyT = tenv.var(exp);
+ const AType* fnT = tup<const AType>(call->loc, tenv.Fn, protT.head, bodyT, 0);
+ Object::pool.addRoot(fnT);
+
+ tenv.pop();
+
+ c.constrain(tenv, call, fnT);
}
static void
@@ -182,51 +199,34 @@ constrain_if(TEnv& tenv, Constraints& c, const ATuple* call) throw(Error)
}
static void
-constrain_cons(TEnv& tenv, Constraints& c, const ATuple* call) throw(Error)
+constrain_match(TEnv& tenv, Constraints& c, const ATuple* call) throw(Error)
{
- const ASymbol* sym = (*call->begin())->as_symbol();
- const AType* type = NULL;
+ THROW_IF(call->list_len() < 5, call->loc, "`match' requires at least 4 arguments");
+ const AST* matchee = call->list_ref(1);
+ const AType* retT = tenv.var();
+ const AType* matcheeT = NULL;// = tup<AType>(loc, tenv.U, 0);
+ resp_constrain(tenv, c, matchee);
+ for (ATuple::const_iterator i = call->iter_at(2); i != call->end();) {
+ const AST* exp = *i++;
+ const ATuple* pattern = exp->to_tuple();
+ THROW_IF(!pattern, exp->loc, "pattern expression expected");
+ const ASymbol* name = (*pattern->begin())->to_symbol();
+ THROW_IF(!name, (*pattern->begin())->loc, "pattern does not start with a symbol");
- for (ATuple::const_iterator i = call->iter_at(1); i != call->end(); ++i)
- resp_constrain(tenv, c, *i);
+ const AType* consT = *tenv.ref(name);
- if (!strcmp(sym->sym(), "Tup")) {
- TList tupT(new AType(tenv.Tup, NULL, call->loc));
- for (ATuple::const_iterator i = call->iter_at(1); i != call->end(); ++i) {
- tupT.push_back(tenv.var(*i));
+ if (!matcheeT) {
+ const AType* headT = consT->head()->as_type();
+ matcheeT = new AType(headT, 0, call->loc);
}
- type = tupT;
- } else {
- const AType** consTRef = tenv.ref(sym);
- THROW_IF(!consTRef, call->loc,
- (format("call to undefined constructor `%1%'") % sym->sym()).str());
- const AType* consT = *consTRef;
- type = new AType(consT->head()->as_type(), 0, call->loc);
- }
- c.constrain(tenv, call, type);
-}
-static void
-constrain_dot(TEnv& tenv, Constraints& c, const ATuple* call) throw(Error)
-{
- THROW_IF(call->list_len() != 3, call->loc, "`.' requires exactly 2 arguments");
- ATuple::const_iterator i = call->begin();
- const AST* obj = *++i;
- const AST* idx_ast = *++i;
- THROW_IF(idx_ast->tag() != T_INT32, call->loc, "the 2nd argument to `.' must be a literal integer");
- const ALiteral<int32_t>* idx = (ALiteral<int32_t>*)idx_ast;
-
- resp_constrain(tenv, c, obj);
-
- const AType* retT = tenv.var(call);
+ THROW_IF(i == call->end(), pattern->loc, "missing pattern body");
+ const AST* body = *i++;
+ resp_constrain(tenv, c, body);
+ c.constrain(tenv, body, retT);
+ }
c.constrain(tenv, call, retT);
-
- TList objT(new AType(tenv.Tup, NULL, call->loc));
- for (int i = 0; i < idx->val; ++i)
- objT.push_back(tenv.var());
- objT.push_back(retT);
- objT.push_back(tenv.Dots);
- c.constrain(tenv, obj, objT);
+ c.constrain(tenv, matchee, matcheeT);
}
static void
@@ -315,7 +315,7 @@ constrain_primitive(TEnv& tenv, Constraints& c, const ATuple* call) throw(Error)
}
static void
-constrain_tuple(TEnv& tenv, Constraints& c, const ATuple* tup) throw(Error)
+constrain_list(TEnv& tenv, Constraints& c, const ATuple* tup) throw(Error)
{
const ASymbol* const sym = tup->head()->to_symbol();
if (!sym) {
@@ -326,20 +326,20 @@ constrain_tuple(TEnv& tenv, Constraints& c, const ATuple* tup) throw(Error)
const std::string form = sym->sym();
if (is_primitive(tenv.penv, tup))
constrain_primitive(tenv, c, tup);
- else if (form == "fn")
- constrain_fn(tenv, c, tup);
+ else if (form == "cons" || isupper(form[0]))
+ constrain_cons(tenv, c, tup);
+ else if (form == ".")
+ constrain_dot(tenv, c, tup);
else if (form == "def")
constrain_def(tenv, c, tup);
else if (form == "def-type")
constrain_def_type(tenv, c, tup);
- else if (form == "match")
- constrain_match(tenv, c, tup);
+ else if (form == "fn")
+ constrain_fn(tenv, c, tup);
else if (form == "if")
constrain_if(tenv, c, tup);
- else if (form == "cons" || isupper(form[0]))
- constrain_cons(tenv, c, tup);
- else if (form == ".")
- constrain_dot(tenv, c, tup);
+ else if (form == "match")
+ constrain_match(tenv, c, tup);
else
constrain_call(tenv, c, tup);
}
@@ -367,7 +367,7 @@ resp_constrain(TEnv& tenv, Constraints& c, const AST* ast) throw(Error)
constrain_symbol(tenv, c, ast->as_symbol());
break;
case T_TUPLE:
- constrain_tuple(tenv, c, ast->as_tuple());
+ constrain_list(tenv, c, ast->as_tuple());
break;
}
}
diff --git a/src/lift.cpp b/src/lift.cpp
index 5ac3816..4e2159b 100644
--- a/src/lift.cpp
+++ b/src/lift.cpp
@@ -47,6 +47,35 @@ lift_symbol(CEnv& cenv, Code& code, const ASymbol* sym) throw()
}
static const AST*
+lift_def(CEnv& cenv, Code& code, const ATuple* def) throw()
+{
+ // Define stub first for recursion
+ const ASymbol* const sym = def->list_ref(1)->as_symbol();
+ const AST* const body = def->list_ref(2);
+ cenv.def(sym, body, cenv.type(body), NULL);
+ if (is_form(body, "fn"))
+ cenv.setName(body->as_tuple(), sym->str());
+
+ assert(def->list_ref(1)->to_symbol());
+ List<ATuple, const AST> copy;
+ copy.push_back(def->head());
+ copy.push_back(resp_lift(cenv, code, def->list_ref(1)));
+ for (ATuple::const_iterator t = def->iter_at(2); t != def->end(); ++t)
+ copy.push_back(resp_lift(cenv, code, *t));
+
+ cenv.setTypeSameAs(copy.head, def);
+
+ if (copy.head->list_ref(1) == copy.head->list_ref(2))
+ return NULL; // Definition created by lift_fn when body was lifted
+
+ cenv.def(copy.head->list_ref(1)->as_symbol(),
+ copy.head->list_ref(2),
+ cenv.type(copy.head->list_ref(2)),
+ NULL);
+ return copy;
+}
+
+static const AST*
lift_fn(CEnv& cenv, Code& code, const ATuple* fn) throw()
{
List<ATuple, const AST> impl;
@@ -180,36 +209,7 @@ lift_call(CEnv& cenv, Code& code, const ATuple* call) throw()
}
static const AST*
-lift_def(CEnv& cenv, Code& code, const ATuple* def) throw()
-{
- // Define stub first for recursion
- const ASymbol* const sym = def->list_ref(1)->as_symbol();
- const AST* const body = def->list_ref(2);
- cenv.def(sym, body, cenv.type(body), NULL);
- if (is_form(body, "fn"))
- cenv.setName(body->as_tuple(), sym->str());
-
- assert(def->list_ref(1)->to_symbol());
- List<ATuple, const AST> copy;
- copy.push_back(def->head());
- copy.push_back(resp_lift(cenv, code, def->list_ref(1)));
- for (ATuple::const_iterator t = def->iter_at(2); t != def->end(); ++t)
- copy.push_back(resp_lift(cenv, code, *t));
-
- cenv.setTypeSameAs(copy.head, def);
-
- if (copy.head->list_ref(1) == copy.head->list_ref(2))
- return NULL; // Definition created by lift_fn when body was lifted
-
- cenv.def(copy.head->list_ref(1)->as_symbol(),
- copy.head->list_ref(2),
- cenv.type(copy.head->list_ref(2)),
- NULL);
- return copy;
-}
-
-static const AST*
-lift_builtin_call(CEnv& cenv, Code& code, const ATuple* call) throw()
+lift_args(CEnv& cenv, Code& code, const ATuple* call) throw()
{
List<ATuple, const AST> copy;
copy.push_back(call->head());
@@ -235,18 +235,20 @@ resp_lift(CEnv& cenv, Code& code, const AST* ast) throw()
const ASymbol* const sym = call->head()->to_symbol();
const std::string form = sym ? sym->sym() : "";
if (is_primitive(cenv.penv, call))
- return lift_builtin_call(cenv, code, call);
- else if (form == "fn")
- return lift_fn(cenv, code, call);
+ return lift_args(cenv, code, call);
+ else if (form == "cons" || isupper(form[0]))
+ return lift_args(cenv, code, call);
+ else if (form == ".")
+ return lift_args(cenv, code, call);
else if (form == "def")
return lift_def(cenv, code, call);
+ else if (form == "def-type")
+ return call; // FIXME
+ else if (form == "fn")
+ return lift_fn(cenv, code, call);
else if (form == "if")
- return lift_builtin_call(cenv, code, call);
- else if (form == "cons" || isupper(form[0]))
- return lift_builtin_call(cenv, code, call);
- else if (form == ".")
- return lift_builtin_call(cenv, code, call);
- else if (form == "match" || form == "def-type")
+ return lift_args(cenv, code, call);
+ else if (form == "match")
return call; // FIXME
else
return lift_call(cenv, code, call);