/*****
* fundec.h
* Andy Hammerlindl 2002/8/29
*
* Defines the semantics for defining functions. Both the newexp syntax, and
* the abbreviated C-style function definition.
*****/
types::ty *formal::getType(coenv &e, bool tacit) {
types::ty *bt = base->trans(e, tacit);
types::ty *t = start ? start->getType(bt, e, tacit) : bt;
if (t->kind == ty_void && !tacit) {
em.error(getPos());
em << "cannot declare parameters of type void";
return primError();
}
return t;
}
void formal::addOps(coenv &e, record *r) {
base->addOps(e, r);
if (start)
start->addOps(base->trans(e, true), e, r);
}
void formals::prettyprint(ostream &out, Int indent)
{
prettyname(out, "formals",indent, getPos());
for (list<formal *>::iterator p = fields.begin(); p != fields.end(); ++p)
(*p)->prettyprint(out, indent+1);
}
void formals::addToSignature(signature& sig,
coenv &e, bool encodeDefVal, bool tacit)
{
for (list<formal *>::iterator p = fields.begin(); p != fields.end(); ++p) {
formal& f=**p;
types::formal tf = f.trans(e, encodeDefVal, tacit);
if (f.isKeywordOnly())
sig.addKeywordOnly(tf);
else
sig.add(tf);
}
if (rest) {
if (!tacit && rest->getDefaultValue()) {
em.error(rest->getPos());
em << "rest parameters cannot have default values";
}
sig.addRest(rest->trans(e, encodeDefVal, tacit));
}
}
// Returns the types of each parameter as a signature.
// encodeDefVal means that it will also encode information regarding
// the default values into the signature
signature *formals::getSignature(coenv &e, bool encodeDefVal, bool tacit)
{
signature *sig = new signature;
addToSignature(*sig,e,encodeDefVal,tacit);
return sig;
}
// Returns the corresponding function type, assuming it has a return
// value of types::ty *result.
function *formals::getType(types::ty *result, coenv &e,
bool encodeDefVal,
bool tacit)
{
function *ft = new function(result);
addToSignature(ft->sig,e,encodeDefVal,tacit);
return ft;
}
void formals::addOps(coenv &e, record *r)
{
for(list<formal *>::iterator p = fields.begin(); p != fields.end(); ++p)
(*p)->addOps(e, r);
if (rest)
rest->addOps(e, r);
}
mem::vector<tySymbolPair> *formals::getFields() {
auto *lst = new mem::vector<tySymbolPair>();
for (auto frml : fields) {
lst->emplace_back(frml->getAbsyntaxType(), frml->getName());
}
return lst;
}
// Another helper class. Does an assignment, but relying only on the
// destination for the type.
class basicAssignExp : public exp {
varEntry *dest;
varinit *value;
public:
basicAssignExp(position pos, varEntry *dest, varinit *value)
: exp(pos), dest(dest), value(value) {}
types::ty *trans(coenv &e) {
// This doesn't handle overloaded types for the destination.
value->transToType(e, getType(e));
dest->encode(WRITE, pos, e.c);
return getType(e);
}
};
void transDefault(coenv &e, position pos, varEntry *v, varinit *init) {
// This roughly translates into the statement
// if (isDefault(x))
// x=init;
// where x is the variable in v and isDefault is a function that tests
// whether x is the default argument token.
v->encode(READ, pos, e.c);
label end = e.c.fwdLabel();
e.c.useLabel(inst::jump_if_not_default, end);
void formal::transAsVar(coenv &e, Int index) {
symbol name = getName();
if (name) {
trans::access *a = e.c.accessFormal(index);
assert(a);
// Suppress error messages because they will already be reported
// when the formals are translated to yield the type earlier.
types::ty *t = getType(e, true);
varEntry *v = new varEntry(t, a, 0, getPos());
// Translate the default argument before adding the formal to the
// environment, consistent with the initializers of variables.
if (defval)
transDefault(e, getPos(), v, defval);
void fundef::baseTrans(coenv &e, types::function *ft)
{
string name = id ? string(id) : string("<anonymous function>");
// Create a new function environment.
coder fc = e.c.newFunction(getPos(), name, ft);
coenv fe(fc,e.e);
// Translate the function.
fe.e.beginScope();
params->trans(fe);
body->trans(fe);
types::ty *rt = ft->result;
if (rt->kind != ty_void &&
rt->kind != ty_error &&
!body->returns()) {
em.error(body->getPos());
em << "function must return a value";
}
fe.e.endScope();
// Put an instance of the new function on the stack.
vm::lambda *l = fe.c.close();
e.c.encode(inst::pushclosure);
e.c.encode(inst::makefunc, l);
}
types::ty *fundef::trans(coenv &e) {
// We must addOps for the return type and formals. ex:
//
// new guide[] (guide f(int)) {
// return sequence(f, 10);
// };
function *ft=transTypeAndAddOps(e, (record *)0, false);
assert(ft);
baseTrans(e, ft);
return ft;
}
void fundec::prettyprint(ostream &out, Int indent)
{
prettyindent(out, indent);
out << "fundec '" << id << "'\n";