namespace vm {
// Defined in stack.cc
extern vm::vmFrame *make_dummyframe(string name);
}
using namespace types;
using namespace camp;
using namespace vm;
namespace trans {
using camp::transform;
using camp::pair;
using vm::bltin;
using run::divide;
using run::less;
using run::greater;
using run::plus;
using run::minus;
if (f1.t) fun->add(f1);
if (f2.t) fun->add(f2);
if (f3.t) fun->add(f3);
if (f4.t) fun->add(f4);
if (f5.t) fun->add(f5);
if (f6.t) fun->add(f6);
if (f7.t) fun->add(f7);
if (f8.t) fun->add(f8);
if (f9.t) fun->add(f9);
if (fA.t) fun->add(fA);
if (fB.t) fun->add(fB);
if (fC.t) fun->add(fC);
if (fD.t) fun->add(fD);
if (fE.t) fun->add(fE);
if (fF.t) fun->add(fF);
if (fG.t) fun->add(fG);
if (fH.t) fun->add(fH);
if (fI.t) fun->add(fI);
// NOTE: If the function is a field, we should encode the defining record in
// the entry
varEntry *ent = new varEntry(fun, a, 0, nullPos);
ve.enter(id, ent);
return ent;
}
// Add a function with one or more default arguments.
varEntry *addFunc(venv &ve, bltin f, ty *result, symbol name,
formal f1, formal f2, formal f3, formal f4, formal f5, formal f6,
formal f7, formal f8, formal f9, formal fA, formal fB, formal fC,
formal fD, formal fE, formal fF, formal fG, formal fH, formal fI)
{
#ifdef DEBUG_BLTIN
// If the function is an operator, print out the whole signature with the
// types, as operators are heavily overloaded. min and max are also heavily
// overloaded, so we check for them too. Many builtin functions have so
// many arguments that it is noise to print out their full signatures.
string s = name;
if (s.find("operator ", 0) == 0 || s == "min" || s == "max")
{
function *fun = functionFromFormals(result,f1,f2,f3,f4,f5,f6,f7,f8,f9,
fA,fB,fC,fD,fE,fF,fG,fH,fI);
ostringstream out;
fun->printVar(out, name);
REGISTER_BLTIN(f, out.str());
}
else {
REGISTER_BLTIN(f, name);
}
#endif
access *a = new bltinAccess(f);
return addFunc(ve,a,result,name,f1,f2,f3,f4,f5,f6,f7,f8,f9,
fA,fB,fC,fD,fE,fF,fG,fH,fI);
}
void addOpenFunc(venv &ve, bltin f, ty *result, symbol name)
{
function *fun = new function(result, signature::OPEN);
REGISTER_BLTIN(f, name);
access *a= new bltinAccess(f);
varEntry *ent = new varEntry(fun, a, 0, nullPos);
ve.enter(name, ent);
}
// Add a rest function with zero or more default/explicit arguments.
void addRestFunc(venv &ve, bltin f, ty *result, symbol name, formal frest,
formal f1=noformal, formal f2=noformal, formal f3=noformal,
formal f4=noformal, formal f5=noformal, formal f6=noformal,
formal f7=noformal, formal f8=noformal, formal f9=noformal)
{
REGISTER_BLTIN(f, name);
access *a = new bltinAccess(f);
function *fun = new function(result);
if (f1.t) fun->add(f1);
if (f2.t) fun->add(f2);
if (f3.t) fun->add(f3);
if (f4.t) fun->add(f4);
if (f5.t) fun->add(f5);
if (f6.t) fun->add(f6);
if (f7.t) fun->add(f7);
if (f8.t) fun->add(f8);
if (f9.t) fun->add(f9);
template <double (*func)(double, int)>
void realRealInt(vm::stack *s) {
Int n = pop<Int>(s);
double x = pop<double>(s);
s->push(func(x, intcast(n)));
}
template<double (*fcn)(double, int)>
void addRealIntFunc(venv& ve, symbol name, symbol arg1,
symbol arg2) {
addFunc(ve, realRealInt<fcn>, primReal(), name, formal(primReal(), arg1),
formal(primInt(), arg2));
}
void addInitializer(venv &ve, ty *t, access *a)
{
addFunc(ve, a, t, symbol::initsym);
}
void addInitializer(venv &ve, ty *t, bltin f)
{
#ifdef DEBUG_BLTIN
ostringstream s;
s << "initializer for " << *t;
REGISTER_BLTIN(f, s.str());
#endif
access *a = new bltinAccess(f);
addInitializer(ve, t, a);
}
// Specifies that source may be cast to target, but only if an explicit
// cast expression is used.
void addExplicitCast(venv &ve, ty *target, ty *source, access *a) {
addFunc(ve, a, target, symbol::ecastsym, source);
}
// Specifies that source may be implicitly cast to target by the
// function or instruction stores at a.
void addCast(venv &ve, ty *target, ty *source, access *a) {
//addExplicitCast(target,source,a);
addFunc(ve, a, target, symbol::castsym, source);
}
void addExplicitCast(venv &ve, ty *target, ty *source, bltin f) {
#ifdef DEBUG_BLTIN
ostringstream s;
s << "explicit cast from " << *source << " to " << *target;
REGISTER_BLTIN(f, s.str());
#endif
addExplicitCast(ve, target, source, new bltinAccess(f));
}
void addCast(venv &ve, ty *target, ty *source, bltin f) {
#ifdef DEBUG_BLTIN
ostringstream s;
s << "cast from " << *source << " to " << *target;
REGISTER_BLTIN(f, s.str());
#endif
addCast(ve, target, source, new bltinAccess(f));
}
template<class T>
void addVariable(venv &ve, T *ref, ty *t, symbol name,
record *module=settings::getSettingsModule()) {
access *a = new refAccess<T>(ref);
varEntry *ent = new varEntry(t, a, PUBLIC, module, 0, nullPos);
ve.enter(name, ent);
}
template<class T>
void addVariable(venv &ve, T value, ty *t, symbol name,
record *module=settings::getSettingsModule(),
permission perm=PUBLIC) {
item* ref=new item;
*ref=value;
access *a = new itemRefAccess(ref);
varEntry *ent = new varEntry(t, a, perm, module, 0, nullPos);
ve.enter(name, ent);
}
template<class T>
void addConstant(venv &ve, T value, ty *t, symbol name,
record *module=settings::getSettingsModule()) {
addVariable(ve,value,t,name,module,RESTRICTED);
}
// The identity access, i.e. no instructions are encoded for a cast or
// operation, and no functions are called.
identAccess id;
function *IntRealFunction()
{
return new function(primInt(),primReal());
}
function *realPairFunction()
{
return new function(primReal(),primPair());
}
function *voidFileFunction()
{
return new function(primVoid(),primFile());
}
void addGuideOperators(venv &ve)
{
// The guide operators .. and -- take an array of guides, and turn them
// into a single guide.
addRestFunc(ve, dotsGuide, primGuide(), SYM_DOTS, guideArray());
addRestFunc(ve, dashesGuide, primGuide(), SYM_DASHES, guideArray());
}
/* Avoid typing the same type three times. */
void addSimpleOperator(venv &ve, bltin f, ty *t, symbol name)
{
addFunc(ve,f,t,name,formal(t,SYM(a)),formal(t,SYM(b)));
}
void addBooleanOperator(venv &ve, bltin f, ty *t, symbol name)
{
addFunc(ve,f,primBoolean(),name,formal(t,SYM(a)),formal(t,SYM(b)));
}
template<class T, template <class S> class op>
void addArray2Array2Op(venv &ve, ty *t3, symbol name)
{
addFunc(ve,array2Array2Op<T,op>,t3,name,formal(t3,SYM(a)),formal(t3,SYM(b)));
}
template<class T, template <class S> class op>
void addOpArray2(venv &ve, ty *t1, symbol name, ty *t3)
{
addFunc(ve,opArray2<T,T,op>,t3,name,formal(t1,SYM(a)),formal(t3,SYM(b)));
}
template<class T, template <class S> class op>
void addArray2Op(venv &ve, ty *t1, symbol name, ty *t3)
{
addFunc(ve,array2Op<T,T,op>,t3,name,formal(t3,SYM(a)),formal(t1,SYM(b)));
}
template<class T, template <class S> class op>
void addOps(venv &ve, ty *t1, symbol name, ty *t2)
{
addSimpleOperator(ve,binaryOp<T,op>,t1,name);
addFunc(ve,opArray<T,T,op>,t2,name,formal(t1,SYM(a)),formal(t2,SYM(b)));
addFunc(ve,arrayOp<T,T,op>,t2,name,formal(t2,SYM(a)),formal(t1,SYM(b)));
addSimpleOperator(ve,arrayArrayOp<T,op>,t2,name);
}
template<class T, template <class S> class op>
void addBooleanOps(venv &ve, ty *t1, symbol name, ty *t2)
{
addBooleanOperator(ve,binaryOp<T,op>,t1,name);
addFunc(ve,opArray<T,T,op>,
booleanArray(),name,formal(t1,SYM(a)),formal(t2,SYM(b)));
addFunc(ve,arrayOp<T,T,op>,
booleanArray(),name,formal(t2,SYM(a)),formal(t1,SYM(b)));
addFunc(ve,arrayArrayOp<T,op>,booleanArray(),name,formal(t2,SYM(a)),
formal(t2,SYM(b)));
}
void addWrite(venv &ve, bltin f, ty *t1, ty *t2)
{
addRestFunc(ve,f,primVoid(),SYM(write),t2,
formal(primFile(),SYM(file),true),
formal(primString(),SYM(s),true),
formal(t1,SYM(x)),formal(voidFileFunction(),SYM(suffix),true));
}
template<class T>
void addUnorderedOps(venv &ve, ty *t1, ty *t2, ty *t3, ty *t4)
{
addBooleanOps<T,equals>(ve,t1,SYM_EQ,t2);
addBooleanOps<T,notequals>(ve,t1,SYM_NEQ,t2);
template<class T>
inline T negate(T x) {
return -x;
}
template<class T, template <class S> class op>
void addBinOps(venv &ve, ty *t1, ty *t2, ty *t3, ty *t4, symbol name)
{
addFunc(ve,binopArray<T,op>,t1,name,formal(t2,SYM(a)));
addFunc(ve,binopArray2<T,op>,t1,name,formal(t3,SYM(a)));
addFunc(ve,binopArray3<T,op>,t1,name,formal(t4,SYM(a)));
}
template<class T>
void addOrderedOps(venv &ve, ty *t1, ty *t2, ty *t3, ty *t4)
{
addBooleanOps<T,less>(ve,t1,SYM_LT,t2);
addBooleanOps<T,lessequals>(ve,t1,SYM_LE,t2);
addBooleanOps<T,greaterequals>(ve,t1,SYM_GE,t2);
addBooleanOps<T,greater>(ve,t1,SYM_GT,t2);
template<class T>
void addOps(venv &ve, ty *t1, ty *t2, ty *t3, ty *t4, bool integer=false,
bool Explicit=false)
{
addBasicOps<T>(ve,t1,t2,t3,t4,integer,Explicit);
// Adds standard functions for a newly added array type.
void addArrayOps(venv &ve, types::array *t)
{
ty *ct = t->celltype;
// Check for the alias function to see if these operation have already been
// added, if they have, don't add them again.
static types::function aliasType(primBoolean(), primVoid(), primVoid());
aliasType.sig.formals[0].t = t;
aliasType.sig.formals[1].t = t;
if (ve.lookByType(SYM(alias), &aliasType))
return;
// Define an array constructor. This needs to know the depth of the array,
// which may not be known at runtime. Therefore, the depth, which is known
// here at compile-time, is pushed on the stack beforehand by use of a
// thunk.
callable *copyValueFunc = new thunk(new vm::bfunc(run::copyArrayValue),(Int) depth-1);
addFunc(ve, new callableAccess(copyValueFunc),
t, SYM(array), formal(primInt(), SYM(n)),
formal(ct, SYM(value)),
formal(primInt(), SYM(depth), true));
callable *copyFunc = new thunk(new vm::bfunc(run::copyArray),(Int) depth);
addFunc(ve, new callableAccess(copyFunc),
t, SYM(copy), formal(t, SYM(a)), formal(primInt(), SYM(depth), true));
// An example of an open function.
#ifdef OPENFUNCEXAMPLE
void openFunc(stack *Stack)
{
vm::array *a=vm::pop<vm::array *>(Stack);
size_t numArgs=checkArray(a);
for (size_t k=0; k<numArgs; ++k)
cout << k << ": " << (*a)[k];
Stack->push<Int>((Int)numArgs);
}
#endif
// A function accessible in asy code print the bytecode of a function.
void printBytecode(stack *Stack)
{
// As arbitrary addresses can be sent to printBytecode, it should not be run
// in safe mode.
if (settings::safe) {
cerr << "use -nosafe flag to enable printBytecode" << endl;
return;
}
vm::array *a=vm::pop<vm::array *>(Stack);
size_t numArgs=checkArray(a);
if (numArgs != 1)
cerr << "printBytecode takes one argument" << endl;
// TODO: Add a reliable test for the object being a func.
callable *c = a->read<callable *>(0);
if (func *f = dynamic_cast<func *>(c))
print(cout, f->body->code);
else
cout << "callable is not a standard function";
}
// NOTE: We should move all of these into a "builtin" module.
void base_venv(venv &ve)
{
// Register the name of arrayDeleteHelper for debugging in "asy -s" mode.
// This is done automatically for other function, but because
// arrayDeleteHelper is not defined in the usual way, it must be done
// explicitly, and here is as good a place as any.
REGISTER_BLTIN(arrayDeleteHelper, "arrayDeleteHelper");