diff options
Diffstat (limited to 'Build/source/utils/asymptote/fundec.cc')
-rw-r--r-- | Build/source/utils/asymptote/fundec.cc | 305 |
1 files changed, 305 insertions, 0 deletions
diff --git a/Build/source/utils/asymptote/fundec.cc b/Build/source/utils/asymptote/fundec.cc new file mode 100644 index 00000000000..016e300321e --- /dev/null +++ b/Build/source/utils/asymptote/fundec.cc @@ -0,0 +1,305 @@ +/***** + * fundec.h + * Andy Hammerlindl 2002/8/29 + * + * Defines the semantics for defining functions. Both the newexp syntax, and + * the abbreviated C-style function definition. + *****/ + +#include "fundec.h" +#include "errormsg.h" +#include "coenv.h" +#include "stm.h" +#include "runtime.h" + +namespace absyntax { + +using namespace trans; +using namespace types; +using mem::list; + +varinit *Default=new definit(nullPos); + +void formal::prettyprint(ostream &out, Int indent) +{ + prettyname(out, "formal",indent); + + base->prettyprint(out, indent+1); + if (start) start->prettyprint(out, indent+1); + if (defval) defval->prettyprint(out, indent+1); +} + +types::formal formal::trans(coenv &e, bool encodeDefVal, bool tacit) { + return types::formal(getType(e,tacit), + getName(), + encodeDefVal ? (bool) getDefaultValue() : 0, + getExplicit()); +} + +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); + + 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) + sig.add((*p)->trans(e, encodeDefVal, tacit)); + + 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); +} + +// Another helper class. Does an assignment, but relying only on the +// destination for the type. +class basicAssignExp : public exp { + exp *dest; + varinit *value; +public: + basicAssignExp(position pos, exp *dest, varinit *value) + : exp(pos), dest(dest), value(value) {} + + types::ty *getType(coenv &e) { + return dest->getType(e); + } + + types::ty *trans(coenv &e) { + // This doesn't handle overloaded types for the destination. + value->transToType(e, getType(e)); + dest->transWrite(e, getType(e)); + return getType(e); + } +}; + +void transDefault(coenv &e, position pos, varEntry *v, varinit *init) { + // This roughly translates into the expression + // 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. + varEntryExp vee(pos, v); + ifStm is(pos, + new callExp(pos, + new varEntryExp(pos, + new function(primBoolean(), v->getType()), + run::isDefault), + &vee), + new expStm(pos, + new basicAssignExp(pos, + &vee, + init))); + is.trans(e); +} + +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); + + e.e.addVar(name, v); + } +} + +void formals::trans(coenv &e) +{ + Int index = 0; + + for (list<formal *>::iterator p=fields.begin(); p!=fields.end(); ++p) { + (*p)->transAsVar(e, index); + ++index; + } + + if (rest) { + rest->transAsVar(e, index); + ++index; + } +} + +void fundef::prettyprint(ostream &out, Int indent) +{ + result->prettyprint(out, indent+1); + params->prettyprint(out, indent+1); + body->prettyprint(out, indent+1); +} + +function *fundef::transType(coenv &e, bool tacit) { + bool encodeDefVal=true; + return params->getType(result->trans(e, tacit), e, encodeDefVal, tacit); +} + +function *fundef::transTypeAndAddOps(coenv &e, record *r, bool tacit) { + result->addOps(e,r); + params->addOps(e,r); + + function *ft=transType(e, tacit); + e.e.addFunctionOps(ft); + if (r) + r->e.addFunctionOps(ft); + + return ft; +} + +varinit *fundef::makeVarInit(function *ft) { + struct initializer : public varinit { + fundef *f; + function *ft; + + initializer(fundef *f, function *ft) + : varinit(f->getPos()), f(f), ft(ft) {} + + void prettyprint(ostream &out, Int indent) { + prettyname(out, "initializer", indent); + } + + void transToType(coenv &e, types::ty *target) { + assert(ft==target); + f->baseTrans(e, ft); + } + }; + + return new initializer(this, ft); +} + +void fundef::baseTrans(coenv &e, types::function *ft) +{ + // Create a new function environment. + coder fc = e.c.newFunction(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) { + // I don't see how addFunctionOps can be useful here. + // For instance, in + // + // new void() {} == null + // + // callExp has to search for == before translating either argument, and the + // operator cannot be added before translation. (getType() is not allowed to + // manipulate the environment.) + // A new function expression is assigned to a variable, given as a return + // value, or used as an argument to a function. In any of these + // + // We must still addOps though, 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"; + + fun.prettyprint(out, indent); +} + +void fundec::trans(coenv &e) +{ + transAsField(e,0); +} + +void fundec::transAsField(coenv &e, record *r) +{ + function *ft = fun.transTypeAndAddOps(e, r, false); + assert(ft); + + createVar(getPos(), e, r, id, ft, fun.makeVarInit(ft)); +} + +} // namespace absyntax |