diff options
author | Karl Berry <karl@freefriends.org> | 2021-02-25 19:22:25 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2021-02-25 19:22:25 +0000 |
commit | ad547a6b5986815fda458221149728d9d9ab1d87 (patch) | |
tree | 16296910eb3eca724371474ea9aea3994dc69614 /Build/source/utils/asymptote/exp.cc | |
parent | 947b43de3dd21d58ccc2ffadefc4441ea1c2a813 (diff) |
restore Build,TODO from r57911
git-svn-id: svn://tug.org/texlive/trunk@57915 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Build/source/utils/asymptote/exp.cc')
-rw-r--r-- | Build/source/utils/asymptote/exp.cc | 1496 |
1 files changed, 1496 insertions, 0 deletions
diff --git a/Build/source/utils/asymptote/exp.cc b/Build/source/utils/asymptote/exp.cc new file mode 100644 index 00000000000..dbf6886ecb5 --- /dev/null +++ b/Build/source/utils/asymptote/exp.cc @@ -0,0 +1,1496 @@ +/***** + * exp.cc + * andy hammerlindl 2002/8/19 + * + * represents the abstract syntax tree for the expressions in the + * language. this is translated into virtual machine code using trans() + * and with the aid of the environment class. + *****/ + +#include "exp.h" +#include "errormsg.h" +#include "runtime.h" +#include "runmath.h" +#include "runpicture.h" +#include "runarray.h" +#include "runpair.h" +#include "runtriple.h" +#include "runpath.h" +#include "coenv.h" +#include "application.h" +#include "dec.h" +#include "stm.h" +#include "inst.h" +#include "opsymbols.h" +#include "process.h" + +//void runCode(absyntax::block *code); + +namespace absyntax { + +using namespace types; +using namespace trans; +using vm::inst; +using mem::vector; + + +#if 0 +void exp::prettyprint(ostream &out, Int indent) +{ + prettyname(out, "exp",indent); +} +#endif + +void exp::transAsType(coenv &e, types::ty *target) { + trans(e); +// types::ty *t=trans(e); +// assert(t->kind==ty_error || equivalent(t,target)); +} + +void exp::transToType(coenv &e, types::ty *target) +{ + types::ty *ct=cgetType(e); + + if (equivalent(target, ct)) { + transAsType(e, target); + return; + } + + // See if the cast can be handled by the fastLookupCast method, which does + // less memory allocation. + if (ct->kind != ty_overloaded && + ct->kind != ty_error && + target->kind != ty_error) { + access *a = e.e.fastLookupCast(target, ct); + if (a) { + transAsType(e, ct); + a->encode(trans::CALL, getPos(), e.c); + return; + } + } + + types::ty *source = e.e.castSource(target, ct, symbol::castsym); + if (source==0) { + if (target->kind != ty_error) { + types::ty *sources=cgetType(e); + em.error(getPos()); + + em << "cannot cast "; + if (sources->kind==ty_overloaded) + em << "expression"; + else + em << "'" << *sources << "'"; + em << " to '" << *target << "'"; + } + } + else if (source->kind==ty_overloaded) { + if (target->kind != ty_error) { + em.error(getPos()); + em << "expression is ambiguous in cast to '" << *target << "'"; + } + } + else { + transAsType(e, source); + e.implicitCast(getPos(), target, source); + } +} + +void exp::testCachedType(coenv &e) { + if (ct != 0) { + types::ty *t = getType(e); + if (!equivalent(t, ct)) { + em.compiler(getPos()); + em << "cached type '" << *ct + << "' doesn't match actual type '" << *t << "'"; + em.sync(); + } + } +} + +void exp::transCall(coenv &e, types::ty *target) +{ + transAsType(e, target); + e.c.encode(inst::popcall); +} + +void exp::transConditionalJump(coenv &e, bool cond, label dest) { + transToType(e, primBoolean()); + e.c.useLabel(cond ? inst::cjmp : inst::njmp, dest); +} + +exp *exp::evaluate(coenv &e, types::ty *target) { + return new tempExp(e, this, target); +} + + +tempExp::tempExp(coenv &e, varinit *v, types::ty *t) + : exp(v->getPos()), a(e.c.allocLocal()), t(t) +{ + v->transToType(e, t); + a->encode(WRITE, getPos(), e.c); + e.c.encodePop(); +} + +void tempExp::prettyprint(ostream &out, Int indent) { + prettyname(out, "tempExp", indent); +} + +types::ty *tempExp::trans(coenv &e) { + a->encode(READ, getPos(), e.c); + return t; +} + + +varEntryExp::varEntryExp(position pos, types::ty *t, access *a) + : exp(pos), v(new trans::varEntry(t, a, 0, position())) {} +varEntryExp::varEntryExp(position pos, types::ty *t, vm::bltin f) + : exp(pos), v(new trans::varEntry(t, new bltinAccess(f), 0, position())) {} + +void varEntryExp::prettyprint(ostream &out, Int indent) { + prettyname(out, "varEntryExp", indent); +} + +types::ty *varEntryExp::getType(coenv &) { + return v->getType(); +} + +types::ty *varEntryExp::trans(coenv &e) { + v->encode(READ, getPos(), e.c); + return getType(e); +} + +trans::varEntry *varEntryExp::getCallee(coenv &e, types::signature *sig) { + return equivalent(sig, v->getType()->getSignature()) ? v : 0; +} + +void varEntryExp::transAct(action act, coenv &e, types::ty *target) { + assert(equivalent(getType(e),target)); + v->encode(act, getPos(), e.c); +} +void varEntryExp::transAsType(coenv &e, types::ty *target) { + transAct(READ, e, target); +} +void varEntryExp::transWrite(coenv &e, types::ty *target, exp *value) { + value->transToType(e, target); + transAct(WRITE, e, target); +} +void varEntryExp::transCall(coenv &e, types::ty *target) { + transAct(trans::CALL, e, target); +} + + +void nameExp::prettyprint(ostream &out, Int indent) +{ + prettyname(out, "nameExp",indent); + + value->prettyprint(out, indent+1); +} + + +void fieldExp::pseudoName::prettyprint(ostream &out, Int indent) +{ + // This should never be called. + prettyindent(out, indent); + out << "pseudoName" << "\n"; + + object->prettyprint(out, indent+1); +} + +void fieldExp::prettyprint(ostream &out, Int indent) +{ + prettyindent(out, indent); + out << "fieldExp '" << field << "'\n"; + + object->prettyprint(out, indent+1); +} + +types::ty *fieldExp::getObject(coenv& e) +{ + types::ty *t = object->cgetType(e); + if (t->kind == ty_overloaded) { + t=((overloaded *)t)->signatureless(); + if(!t) return primError(); + } + return t; +} + + +array *arrayExp::getArrayType(coenv &e) +{ + types::ty *a = set->cgetType(e); + if (a->kind == ty_overloaded) { + a = ((overloaded *)a)->signatureless(); + if (!a) + return 0; + } + + switch (a->kind) { + case ty_array: + return (array *)a; + case ty_error: + return 0; + default: + return 0; + } +} + +array *arrayExp::transArray(coenv &e) +{ + types::ty *a = set->cgetType(e); + if (a->kind == ty_overloaded) { + a = ((overloaded *)a)->signatureless(); + if (!a) { + em.error(set->getPos()); + em << "expression is not an array"; + return 0; + } + } + + set->transAsType(e, a); + + switch (a->kind) { + case ty_array: + return (array *)a; + case ty_error: + return 0; + default: + em.error(set->getPos()); + em << "expression is not an array"; + return 0; + } +} + +// Checks if the expression can be translated as an array. +bool isAnArray(coenv &e, exp *x) +{ + types::ty *t=x->cgetType(e); + if (t->kind == ty_overloaded) + t=dynamic_cast<overloaded *>(t)->signatureless(); + return t && t->kind==ty_array; +} + + +void subscriptExp::prettyprint(ostream &out, Int indent) +{ + prettyindent(out, indent); + out << "subscriptExp\n"; + + set->prettyprint(out, indent+1); + index->prettyprint(out, indent+1); +} + +types::ty *subscriptExp::trans(coenv &e) +{ + array *a = transArray(e); + if (!a) + return primError(); + + if (isAnArray(e, index)) { + index->transToType(e, types::IntArray()); + e.c.encode(inst::builtin, run::arrayIntArray); + return getArrayType(e); + } + else { + index->transToType(e, types::primInt()); + e.c.encode(inst::builtin, + a->celltype->kind==ty_array ? run::arrayArrayRead : + run::arrayRead); + return a->celltype; + } +} + +types::ty *subscriptExp::getType(coenv &e) +{ + array *a = getArrayType(e); + return a ? (isAnArray(e, index) ? a : a->celltype) : + primError(); +} + +void subscriptExp::transWrite(coenv &e, types::ty *t, exp *value) +{ + // Put array, index, and value on the stack in that order, then call + // arrayWrite. + array *a = transArray(e); + if (!a) + return; + + if (!equivalent(a->celltype, t)) + { + em.error(getPos()); + em << "array expression cannot be used as an address"; + + // Translate the value for errors. + value->transToType(e, t); + return; + } + + index->transToType(e, types::primInt()); + + value->transToType(e, t); + + e.c.encode(inst::builtin, run::arrayWrite); +} + + +void slice::prettyprint(ostream &out, Int indent) +{ + prettyname(out, "slice", indent); + if (left) + left->prettyprint(out, indent+1); + else + prettyname(out, "left omitted", indent+1); + if (right) + right->prettyprint(out, indent+1); + else + prettyname(out, "right omitted", indent+1); +} + +void slice::trans(coenv &e) +{ + if (left) + left->transToType(e, types::primInt()); + else + // If the left index is omitted it can be assumed to be zero. + e.c.encode(inst::intpush, (Int)0); + + if (right) + right->transToType(e, types::primInt()); +} + + +void sliceExp::prettyprint(ostream &out, Int indent) +{ + prettyname(out, "sliceExp", indent); + set->prettyprint(out, indent+1); + index->prettyprint(out, indent+1); +} + +types::ty *sliceExp::trans(coenv &e) +{ + array *a = transArray(e); + if (!a) + return primError(); + + index->trans(e); + + e.c.encode(inst::builtin, index->getRight() ? run::arraySliceRead : + run::arraySliceReadToEnd); + + return a; +} + +types::ty *sliceExp::getType(coenv &e) +{ + array *a = getArrayType(e); + return a ? a : primError(); +} + +void sliceExp::transWrite(coenv &e, types::ty *t, exp *value) +{ + array *a = transArray(e); + if (!a) + return; + assert(equivalent(a, t)); + + index->trans(e); + + value->transToType(e, t); + + e.c.encode(inst::builtin, index->getRight() ? run::arraySliceWrite : + run::arraySliceWriteToEnd); +} + +void thisExp::prettyprint(ostream &out, Int indent) +{ + prettyname(out, "thisExp", indent); +} + +types::ty *thisExp::trans(coenv &e) +{ + if (!e.c.encodeThis()) { + em.error(getPos()); + em << "static use of 'this' expression"; + } + return cgetType(e); +} + +types::ty *thisExp::getType(coenv &e) +{ + return e.c.thisType(); +} + +void equalityExp::prettyprint(ostream &out, Int indent) +{ + prettyname(out, "equalityExp", indent); + callExp::prettyprint(out, indent+1); +} + +types::ty *equalityExp::getType(coenv &e) { + // Try to the resolve the expression as a function call first. + types::ty *t = callExp::getType(e); + assert(t); + if (t->kind != ty_error) + return t; + else + // Either an error or handled by the function equality methods. In the + // first case, we may return whatever we like, and the second case always + // returns bool. In either case, it is safe to return bool. + return primBoolean(); +} + +// From a possibly overloaded type, if there is a unique function type, return +// it, otherwise 0. +types::ty *uniqueFunction(types::ty *t) { + if (t->kind == types::ty_function) + return t; + + if (t->isOverloaded()) { + types::ty *ft = 0; + for (ty_iterator i = t->begin(); i != t->end(); ++i) + { + if ((*i)->kind != types::ty_function) + continue; + + if (ft) { + // Multiple function types. + return 0; + } + + ft = *i; + } + + return ft; + } + + // Not a function. + return 0; +} + +// From two possibly overloaded types, if there is a unique function type +// common to both, return it, otherwise 0. +types::ty *uniqueFunction(types::ty *t1, types::ty *t2) { + if (t1->kind == types::ty_function) + return equivalent(t1, t2) ? t1 : 0; + + if (t1->isOverloaded()) { + types::ty *ft = 0; + for (ty_iterator i = t1->begin(); i != t1->end(); ++i) + { + if ((*i)->kind != types::ty_function) + continue; + + if (!equivalent(*i, t2)) + continue; + + if (ft) { + // Multiple function types. + return 0; + } + + ft = *i; + } + + return ft; + } + + // Not a function. + return 0; +} + +bltin bltinFromName(symbol name) { + if (name == SYM_EQ) + return run::boolFuncEq; + assert(name == SYM_NEQ); + return run::boolFuncNeq; +} + +types::ty *equalityExp::trans(coenv &e) { + // First, try to handle by normal function resolution. + types::ty *t = callExp::getType(e); + assert(t); + if (t->kind != ty_error) + return callExp::trans(e); + + // Then, check for the function equality case. + exp *left = (*this->args)[0].val; + exp *right = (*this->args)[1].val; + + types::ty *lt = left->getType(e); + types::ty *rt = right->getType(e); + + // TODO: decide what null == null should do. + + // Check for function == null and null == function + types::ty *ft = 0; + if (rt->kind == types::ty_null) + ft = uniqueFunction(lt); + else if (lt->kind == types::ty_null) + ft = uniqueFunction(rt); + else + ft = uniqueFunction(lt, rt); + + + if (ft) { + assert(ft->kind == ty_function); + + left->transToType(e, ft); + right->transToType(e, ft); + e.c.encode(inst::builtin, bltinFromName(callee->getName())); + + return primBoolean(); + } else { + // Let callExp report a "no such function" error. + types::ty *t = callExp::trans(e); + assert(t->kind == ty_error); + return t; + } +} + +void scaleExp::prettyprint(ostream &out, Int indent) +{ + exp *left=getLeft(); exp *right=getRight(); + + prettyname(out, "scaleExp",indent); + left->prettyprint(out, indent+1); + right->prettyprint(out, indent+1); +} + +types::ty *scaleExp::trans(coenv &e) +{ + exp *left=getLeft(); exp *right=getRight(); + + types::ty *lt = left->cgetType(e); + if (lt->kind != types::ty_Int && lt->kind != types::ty_real) { + if (lt->kind != types::ty_error) { + em.error(left->getPos()); + em << "only numeric constants can do implicit scaling"; + } + right->trans(e); + return types::primError(); + } + + if (!right->scalable()) { + em.warning(right->getPos()); + em << "implicit scaling may be unintentional"; + } + + // Defer to the binaryExp for multiplication. + return binaryExp::trans(e); +} + + +void intExp::prettyprint(ostream &out, Int indent) +{ + prettyindent(out,indent); + out << "intExp: " << value << "\n"; +} + +types::ty *intExp::trans(coenv &e) +{ + e.c.encode(inst::intpush,value); + + return types::primInt(); +} + + +void realExp::prettyprint(ostream &out, Int indent) +{ + prettyindent(out, indent); + out << "realExp: " << value << "\n"; +} + +types::ty *realExp::trans(coenv &e) +{ + e.c.encode(inst::constpush,(item)value); + + return types::primReal(); +} + +void stringExp::prettyprint(ostream &out, Int indent) +{ + prettyindent(out, indent); + out << "stringExp '" << str << "'\n"; +} + +types::ty *stringExp::trans(coenv &e) +{ + e.c.encode(inst::constpush,(item) string(str)); + + return types::primString(); +} + + +void booleanExp::prettyprint(ostream &out, Int indent) +{ + prettyindent(out, indent); + out << "booleanExp: " << value << "\n"; +} + +types::ty *booleanExp::trans(coenv &e) +{ + e.c.encode(inst::constpush,(item)value); + + return types::primBoolean(); +} + +void newPictureExp::prettyprint(ostream &out, Int indent) +{ + prettyname(out, "newPictureExp",indent); +} + +types::ty *newPictureExp::trans(coenv &e) +{ + e.c.encode(inst::builtin, run::newPicture); + + return types::primPicture(); +} + +void cycleExp::prettyprint(ostream &out, Int indent) +{ + prettyname(out, "cycleExp",indent); +} + +types::ty *cycleExp::trans(coenv &e) +{ + e.c.encode(inst::builtin, run::newCycleToken); + + return types::primCycleToken(); +} + +void nullPathExp::prettyprint(ostream &out, Int indent) +{ + prettyname(out, "nullPathExp",indent); +} + +types::ty *nullPathExp::trans(coenv &e) +{ + e.c.encode(inst::builtin, run::nullPath); + + return types::primPath(); +} + +void nullExp::prettyprint(ostream &out, Int indent) +{ + prettyname(out, "nullExp",indent); +} + +types::ty *nullExp::trans(coenv &) +{ + // Things get put on the stack when ty_null + // is cast to an appropriate type + return types::primNull(); +} + + +void quoteExp::prettyprint(ostream &out, Int indent) +{ + prettyname(out, "quoteExp", indent); + value->prettyprint(out, indent+1); +} + +types::ty *quoteExp::trans(coenv &e) +{ + e.c.encode(inst::constpush,(item)value); + + return types::primCode(); +} + +void explist::prettyprint(ostream &out, Int indent) +{ + prettyname(out, "explist",indent); + for (expvector::iterator p = exps.begin(); + p != exps.end(); ++p) + (*p)->prettyprint(out, indent+1); +} + + +void argument::prettyprint(ostream &out, Int indent) +{ + prettyindent(out, indent); + out << "explist"; + if (name) + out << " '" << name << "'"; + out << '\n'; + + val->prettyprint(out, indent+1); +} + +void arglist::prettyprint(ostream &out, Int indent) +{ + prettyname(out, "arglist",indent); + for (argvector::iterator p = args.begin(); + p != args.end(); ++p) + p->prettyprint(out, indent+1); +} + +void callExp::prettyprint(ostream &out, Int indent) +{ + prettyname(out, "callExp",indent); + + callee->prettyprint(out, indent+1); + args->prettyprint(out, indent+1); +} + +signature *callExp::argTypes(coenv &e, bool *searchable) +{ + signature *source=new signature; + + // The signature is searchable unless one of the arguments is overloaded or + // named. + *searchable = true; + + size_t n = args->size(); + + for (size_t i = 0; i < n; i++) { + if(string(args->args[i].name) == "KEY") { + stringExp *s=dynamic_cast<stringExp*>(args->args[i].val); + if(s) { + if(getPos().filename() == processData().fileName) + processData().xkey[getPos().LineColumn()]=Strdup(s->getString()); + args->args.erase(args->args.begin()+i); + --n; + if(i == n) break; + } + } + + argument a=(*args)[i]; + types::ty *t = a.val->cgetType(e); + if (t->kind == types::ty_error) + return 0; + if (t->kind == types::ty_overloaded || a.name) + *searchable = false; + source->add(types::formal(t,a.name)); + } + + if (args->rest.val) { + argument a=args->rest; + types::ty *t = a.val->cgetType(e); + if (t->kind == types::ty_error) + return 0; + if (t->kind == types::ty_overloaded || a.name) + *searchable = false; + source->addRest(types::formal(t,a.name)); + } + + return source; +} + +application *callExp::resolve(coenv &e, overloaded *o, signature *source, + bool tacit) { + app_list l=multimatch(e.e, o, source, *args); + + if (l.empty()) { + //cerr << "l is empty\n"; + if (!tacit) { + em.error(getPos()); + + symbol s = callee->getName(); + if (s) + em << "no matching function \'" << s; + else + em << "no matching function for signature \'"; + em << *source << "\'"; + } + + return 0; + } + else if (l.size() > 1) { // This may take O(n) time. + //cerr << "l is full\n"; + if (!tacit) { + em.error(getPos()); + + symbol s = callee->getName(); + if(s) + em << "call of function \'" << s; + else + em << "call with signature \'"; + em << *source << "\' is ambiguous"; + } + + return 0; + } + else { + //cerr << "l is singleton\n"; + return l.front(); + } +} + +bool hasNamedParameters(signature *sig) { + for (size_t i=0; i < sig->getNumFormals(); ++i) + if (sig->getFormal(i).name) + return true; + return false; +} + +void callExp::reportMismatch(function *ft, signature *source) +{ + symbol s = callee->getName(); + const char *separator=ft->getSignature()->getNumFormals() > 1 ? "\n" : " "; + + em.error(getPos()); + em << "cannot call" << separator << "'" << *ft->getResult() << " "; + if(s) + em << s; + em << *ft->getSignature() << "'" << separator; + + if (ft->getSignature()->isOpen && hasNamedParameters(source)) + em << "with named parameters"; + else + switch(source->getNumFormals()) { + case 0: + em << "without parameters"; + break; + case 1: + em << "with parameter '" << *source << "'"; + break; + default: + em << "with parameters\n'" << *source << "'"; + } +} + +void callExp::reportArgErrors(coenv &e) +{ + // Cycle through the parameters to report all errors. + // NOTE: This may report inappropriate ambiguity errors. + for (size_t i = 0; i < args->size(); i++) { + (*args)[i].val->trans(e); + } + if (args->rest.val) + args->rest.val->trans(e); +} + +void callExp::reportNonFunction() { + em.error(getPos()); + symbol s = callee->getName(); + if (s) + em << "\'" << s << "\' is not a function"; + else + em << "called expression is not a function"; +} + +types::ty *callExp::cacheAppOrVarEntry(coenv &e, bool tacit) +{ + assert(cachedVarEntry == 0 && cachedApp == 0); + + // First figure out the signature of what we want to call. + bool searchable; + signature *source=argTypes(e, &searchable); + +#ifdef DEBUG_GETAPP /* {{{ */ + cout << "getApp for "; + if (callee->getName()) + cout << *callee->getName(); + else + cout << "unnamed"; + cout << " at " << getPos() << endl; + cout << "searchable: " << searchable << endl; +#endif /* }}} */ + + if (!source) { + return primError(); + } + + // An attempt at speeding up compilation: See if the source arguments match + // the (possibly overloaded) function exactly. + if (searchable) { + varEntry *ve = callee->getCallee(e, source); + +#ifdef DEBUG_GETAPP + cout << "guessed: " << (ve!=0) << endl; +#endif + + if (ve) { + cachedVarEntry = ve; +#ifndef DEBUG_CACHE + // Normally DEBUG_CACHE is not defined and we return here for efficiency + // reasons. If DEBUG_CACHE is defined, we instead proceed to resolve + // the function by the normal techniques and make sure we get the same + // result. + return ((function *)ve->getType())->getResult(); +#endif + } + } + + // Figure out what function types we can call. + types::ty *ft = callee->cgetType(e); + +#ifdef DEBUG_GETAPP + string name = callee->getName() ? string(*callee->getName()) : + string("unnamed"); + if (!callee->getName()) + cout << getPos() << endl; +#endif + + switch (ft->kind) { + case ty_error: + if (!tacit) + // Report callee errors. + callee->trans(e); + break; + + case ty_function: + //cout << "name " << name << endl; + cachedApp = application::match(e.e, (function *)ft, source, *args); + if (!cachedApp && !tacit) + reportMismatch((function *)ft, source); + break; + + case ty_overloaded: { +#ifdef DEBUG_GETAPP + int size = ((overloaded *)ft)->sub.size(); + for (int i = 0; i < size; ++i) cout << "name " << name << endl; +#endif + cachedApp = resolve(e, (overloaded *)ft, source, tacit); + break; + } + + default: + if (!tacit) + reportNonFunction(); + break; + } + +#ifdef DEBUG_GETAPP + cout << name << " " << *source << " --> " + << *cachedApp->getType()->getSignature() << endl; +#endif + +#if DEBUG_CACHE + // Make sure cachedVarEntry is giving us the right function. + if (cachedVarEntry) + assert(equivalent(cachedVarEntry->getType(), cachedApp->getType())); +#endif + + // getType relies on this method for the type. + return cachedApp ? cachedApp->getType()->getResult() : primError(); +} + +types::ty *callExp::transPerfectMatch(coenv &e) { + // The varEntry of the callee. (No longer needed after translation.) + varEntry *ve = cachedVarEntry; + cachedVarEntry = 0; + assert(ve); + + // Translate the arguments in turn. + for (size_t i = 0; i < args->size(); ++i) + (*args)[i].val->trans(e); + if (args->rest.val) + args->rest.val->trans(e); + + // Call the function. + ve->encode(trans::CALL, getPos(), e.c); + + // That's it. Return the return type of the function. + return ct ? ct : dynamic_cast<function *>(ve->getType())->getResult(); +} + +types::ty *callExp::trans(coenv &e) +{ + if (cachedVarEntry == 0 && cachedApp == 0) + cacheAppOrVarEntry(e, false); + + if (cachedVarEntry) + return transPerfectMatch(e); + + // The cached data is no longer needed after translation, so let it be + // garbage collected. + application *a = cachedApp; + cachedApp=0; + + if (!a) { + reportArgErrors(e); + return primError(); + } + + // To simulate left-to-right order of evaluation, produce the + // side-effects for the callee. + assert(a); + function *t=a->getType(); + assert(t); + exp *temp=callee->evaluate(e, t); + + // Let the application handle the argument translation. + a->transArgs(e); + + // Translate the call. + temp->transCall(e, t); + + return t->result; +} + +types::ty *callExp::getType(coenv &e) +{ + if (cachedApp) + return cachedApp->getType()->getResult(); + if (cachedVarEntry) { + function *ft = dynamic_cast<function *>(cachedVarEntry->getType()); + assert(ft); + return ft->getResult(); + } + return cacheAppOrVarEntry(e, true); +} + +bool callExp::resolved(coenv &e) { + if (cachedApp == 0 && cachedVarEntry == 0) + cacheAppOrVarEntry(e, true); + return cachedApp || cachedVarEntry; +} + + +void pairExp::prettyprint(ostream &out, Int indent) +{ + prettyname(out, "pairExp",indent); + + x->prettyprint(out, indent+1); + y->prettyprint(out, indent+1); +} + +types::ty *pairExp::trans(coenv &e) +{ + x->transToType(e, types::primReal()); + y->transToType(e, types::primReal()); + + e.c.encode(inst::builtin, run::realRealToPair); + + return types::primPair(); +} + +void tripleExp::prettyprint(ostream &out, Int indent) +{ + prettyname(out, "tripleExp",indent); + + x->prettyprint(out, indent+1); + y->prettyprint(out, indent+1); + z->prettyprint(out, indent+1); +} + +types::ty *tripleExp::trans(coenv &e) +{ + x->transToType(e, types::primReal()); + y->transToType(e, types::primReal()); + z->transToType(e, types::primReal()); + + e.c.encode(inst::builtin, run::realRealRealToTriple); + + return types::primTriple(); +} + +void transformExp::prettyprint(ostream &out, Int indent) +{ + prettyname(out, "transformExp",indent); + + x->prettyprint(out, indent+1); + y->prettyprint(out, indent+1); + xx->prettyprint(out, indent+1); + xy->prettyprint(out, indent+1); + yx->prettyprint(out, indent+1); + yy->prettyprint(out, indent+1); +} + +types::ty *transformExp::trans(coenv &e) +{ + x->transToType(e, types::primReal()); + y->transToType(e, types::primReal()); + xx->transToType(e, types::primReal()); + xy->transToType(e, types::primReal()); + yx->transToType(e, types::primReal()); + yy->transToType(e, types::primReal()); + + e.c.encode(inst::builtin, run::real6ToTransform); + + return types::primTransform(); +} + +void castExp::prettyprint(ostream &out, Int indent) +{ + prettyname(out, "castExp",indent); + + target->prettyprint(out, indent+1); + castee->prettyprint(out, indent+1); +} + +types::ty *castExp::tryCast(coenv &e, types::ty *t, types::ty *s, + symbol csym) +{ + types::ty *ss=e.e.castSource(t, s, csym); + if (ss == 0) { + return 0; + } + if (ss->kind == ty_overloaded) { + em.error(getPos()); + em << "cast is ambiguous"; + return primError(); + } + else { + castee->transAsType(e, ss); + + access *a=e.e.lookupCast(t, ss, csym); + assert(a); + a->encode(trans::CALL, getPos(), e.c); + return ss; + } +} + +types::ty *castExp::trans(coenv &e) +{ + target->addOps(e, (record *)0); + types::ty *t=target->trans(e); + + types::ty *s=castee->cgetType(e); + + if (!tryCast(e, t, s, symbol::ecastsym)) + if (!tryCast(e, t, s, symbol::castsym)) { + em.error(getPos()); + em << "cannot cast '" << *s << "' to '" << *t << "'"; + } + + return t; +} + +types::ty *castExp::getType(coenv &e) +{ + return target->trans(e, true); +} + + +void conditionalExp::prettyprint(ostream &out, Int indent) +{ + prettyname(out, "conditionalExp",indent); + + test->prettyprint(out, indent+1); + onTrue->prettyprint(out, indent+1); + onFalse->prettyprint(out, indent+1); +} + +void conditionalExp::baseTransToType(coenv &e, types::ty *target) { + test->transToType(e, types::primBoolean()); + + label tlabel = e.c.fwdLabel(); + e.c.useLabel(inst::cjmp,tlabel); + + onFalse->transToType(e, target); + + label end = e.c.fwdLabel(); + e.c.useLabel(inst::jmp,end); + + e.c.defLabel(tlabel); + onTrue->transToType(e, target); + + e.c.defLabel(end); +} + +void conditionalExp::transToType(coenv &e, types::ty *target) +{ + if (isAnArray(e, test)) { + if (target->kind != ty_array) { + em.error(getPos()); + em << "cannot cast vectorized conditional to '" << *target << "'"; + } + test->transToType(e, types::booleanArray()); + onTrue->transToType(e, target); + onFalse->transToType(e, target); + e.c.encode(inst::builtin, run::arrayConditional); + } + else { + baseTransToType(e, target); + } +} + +types::ty *promote(coenv &e, types::ty *x, types::ty *y) +{ + struct promoter : public collector { + env &e; + + promoter(env &e) + : e(e) {} + + types::ty *both (types::ty *x, types::ty *y) { + overloaded *o=new overloaded; + o->add(x); o->add(y); + return o; + } + + types::ty *base (types::ty *x, types::ty *y) { + if (equivalent(x,y)) + return x; + else { + bool castToFirst=e.castable(x, y, symbol::castsym); + bool castToSecond=e.castable(y, x, symbol::castsym); + + return (castToFirst && castToSecond) ? both(x,y) : + castToFirst ? x : + castToSecond ? y : + 0; + } + } + }; + + promoter p(e.e); + return p.collect(x,y); +} + +types::ty *conditionalExp::trans(coenv &e) +{ + types::ty *tt=onTrue->cgetType(e); + types::ty *ft=onFalse->cgetType(e); + + if (tt->kind==ty_error) + return onTrue->trans(e); + if (ft->kind==ty_error) + return onFalse->trans(e); + + types::ty *t=promote(e, tt, ft); + if (!t) { + em.error(getPos()); + em << "types in conditional expression do not match"; + return primError(); + } + else if (t->kind == ty_overloaded) { + em.error(getPos()); + em << "type of conditional expression is ambiguous"; + return primError(); + } + + transToType(e,t); + return t; +} + +types::ty *conditionalExp::getType(coenv &e) +{ + types::ty *tt=onTrue->cgetType(e); + types::ty *ft=onFalse->cgetType(e); + if (tt->kind==ty_error || ft->kind==ty_error) + return primError(); + + types::ty *t = promote(e, tt, ft); + return t ? t : primError(); +} + + +void orExp::prettyprint(ostream &out, Int indent) +{ + prettyname(out, "orExp", indent); + + left->prettyprint(out, indent+1); + right->prettyprint(out, indent+1); +} + +types::ty *orExp::trans(coenv &e) +{ + // a || b + // translates into + // a ? true : b + booleanExp be(pos, true); + conditionalExp ce(pos, left, &be, right); + ce.baseTransToType(e, primBoolean()); + + return getType(e); +} + +void orExp::transConditionalJump(coenv &e, bool cond, label dest) +{ + if (cond == true) { + left->transConditionalJump(e, true, dest); + right->transConditionalJump(e, true, dest); + } else { /* cond == false */ + label end = e.c.fwdLabel(); + + left->transConditionalJump(e, true, end); + right->transConditionalJump(e, false, dest); + + e.c.defLabel(end); + } +} + + +void andExp::prettyprint(ostream &out, Int indent) +{ + prettyname(out, "andExp", indent); + + left->prettyprint(out, indent+1); + right->prettyprint(out, indent+1); +} + +types::ty *andExp::trans(coenv &e) +{ + // a && b + // translates into + // a ? b : false + booleanExp be(pos, false); + conditionalExp ce(pos, left, right, &be); + ce.baseTransToType(e, primBoolean()); + + return getType(e); +} + +void andExp::transConditionalJump(coenv &e, bool cond, label dest) +{ + if (cond == true) { + label end = e.c.fwdLabel(); + + left->transConditionalJump(e, false, end); + right->transConditionalJump(e, true, dest); + + e.c.defLabel(end); + } else { /* cond == false */ + left->transConditionalJump(e, false, dest); + right->transConditionalJump(e, false, dest); + } +} + +void joinExp::prettyprint(ostream &out, Int indent) +{ + prettyname(out, "joinExp",indent); + + callee->prettyprint(out, indent+1); + args->prettyprint(out, indent+1); +} + + +void specExp::prettyprint(ostream &out, Int indent) +{ + prettyindent(out,indent); + out << "specExp '" << op << "' " + << (s==camp::OUT ? "out" : + s==camp::IN ? "in" : + "invalid side") << '\n'; + + arg->prettyprint(out, indent+1); +} + +types::ty *specExp::trans(coenv &e) +{ + intExp ie(getPos(), (Int)s); + binaryExp be(getPos(), arg, op, &ie); + return be.trans(e); +} + +types::ty *specExp::getType(coenv &e) +{ + intExp ie(getPos(), (Int)s); + binaryExp be(getPos(), arg, op, &ie); + return be.cgetType(e); +} + +void assignExp::prettyprint(ostream &out, Int indent) +{ + prettyname(out, "assignExp",indent); + + dest->prettyprint(out, indent+1); + value->prettyprint(out, indent+1); +} + +void assignExp::transAsType(coenv &e, types::ty *target) +{ +#if 0 + // For left-to-right order, we have to evaluate the side-effects of the + // destination first. + exp *temp=dest->evaluate(e, target); + ultimateValue(temp)->transToType(e, target); + temp->transWrite(e, target); +#endif + + // All of the heavy work is handled by transWrite. + dest->transWrite(e, target, value); +} + +types::ty *assignExp::trans(coenv &e) +{ + exp *uvalue=ultimateValue(dest); + types::ty *lt = dest->cgetType(e), *rt = uvalue->cgetType(e); + + if (lt->kind == ty_error) + return dest->trans(e); + if (rt->kind == ty_error) + return uvalue->trans(e); + + types::ty *t = e.e.castTarget(lt, rt, symbol::castsym); + if (!t) { + em.error(getPos()); + em << "cannot convert '" << *rt << "' to '" << *lt << "' in assignment"; + return primError(); + } + else if (t->kind == ty_overloaded) { + em.error(getPos()); + em << "assignment is ambiguous"; + return primError(); + } + else { + transAsType(e, t); + return t; + } +} + +types::ty *assignExp::getType(coenv &e) +{ + types::ty *lt = dest->cgetType(e), *rt = ultimateValue(dest)->cgetType(e); + if (lt->kind==ty_error || rt->kind==ty_error) + return primError(); + types::ty *t = e.e.castTarget(lt, rt, symbol::castsym); + + return t ? t : primError(); +} + + +void selfExp::prettyprint(ostream &out, Int indent) +{ + prettyindent(out, indent); + out << "selfExp '" << op << "'\n"; + + dest->prettyprint(out, indent+1); + value->prettyprint(out, indent+1); +} + +void selfExp::transAsType(coenv &e, types::ty *target) +{ + // Create a temp expression for the destination, so it is not evaluated + // twice. + exp *temp=dest->evaluate(e, target); + temp->transWrite(e, target, ultimateValue(temp)); +} + +void prefixExp::prettyprint(ostream &out, Int indent) +{ + prettyindent(out, indent); + out << "prefixExp '" << op << "'\n"; + + dest->prettyprint(out, indent+1); +} + +types::ty *prefixExp::trans(coenv &e) +{ + // Convert into the operation and the assign. + // NOTE: This can cause multiple evaluations. + intExp ie(getPos(), 1); + selfExp se(getPos(), dest, op, &ie); + + return se.trans(e); +} + +types::ty *prefixExp::getType(coenv &e) +{ + // Convert into the operation and the assign. + intExp ie(getPos(), 1); + selfExp se(getPos(), dest, op, &ie); + + return se.getType(e); +} + +void postfixExp::prettyprint(ostream &out, Int indent) +{ + prettyindent(out, indent); + out << "postfixExp <illegal> '" << op << "'\n"; + + dest->prettyprint(out, indent+1); +} + +types::ty *postfixExp::trans(coenv &) +{ + em.error(getPos()); + em << "postfix expressions are not allowed"; + return primError(); +} + + +} // namespace absyntax + |