diff options
Diffstat (limited to 'Build/source/utils/asymptote/types.cc')
-rw-r--r-- | Build/source/utils/asymptote/types.cc | 556 |
1 files changed, 556 insertions, 0 deletions
diff --git a/Build/source/utils/asymptote/types.cc b/Build/source/utils/asymptote/types.cc new file mode 100644 index 00000000000..dee660c3cad --- /dev/null +++ b/Build/source/utils/asymptote/types.cc @@ -0,0 +1,556 @@ +/***** + * types.cc + * Andy Hammerlindl 2002/06/24 + * + * Used by the compiler as a way to keep track of the type of a variable + * or expression. + *****/ + +#include <cstdio> +#include <algorithm> + +#include "entry.h" +#include "types.h" +#include "runtime.h" +#include "runarray.h" +#include "runfile.h" +#include "runpair.h" +#include "runtriple.h" +#include "access.h" +#include "virtualfieldaccess.h" + +namespace run { +void arrayDeleteHelper(vm::stack *Stack); +} + +// For pre-translated symbols. +#ifndef NOSYM +#include "types.symbols.h" +#endif + +namespace types { + +/* Base types */ +#define PRIMITIVE(name,Name,asyName) \ + primitiveTy p##Name(ty_##name); \ + ty *prim##Name() { return &p##Name; } \ + array name##Array_(prim##Name()); \ + ty *name##Array() { return &name##Array_; } \ + array name##Array2_(name##Array()); \ + ty *name##Array2() { return &name##Array2_; } \ + array name##Array3_(name##Array2()); \ + ty *name##Array3() { return &name##Array3_; } +#define PRIMERROR +#include "primitives.h" +#undef PRIMERROR +#undef PRIMITIVE + +nullTy pNull; +ty *primNull() { return &pNull; } + +const char *names[] = { + "null", + "<structure>", "<function>", "<overloaded>", + +#define PRIMITIVE(name,Name,asyName) #asyName, +#define PRIMERROR +#include "primitives.h" +#undef PRIMERROR +#undef PRIMITIVE + + "<array>" +}; + +ty::~ty() +{} + +void ty::print(ostream& out) const +{ + out << names[kind]; +} + +// Used for primitive virtual fields and array virtual fields. +#define FIELD(Type, name, func) \ + if (sig == 0 && id == name) { \ + static trans::virtualFieldAccess a(run::func); \ + static trans::varEntry v(Type(), &a, 0, position()); \ + return &v; \ + } + +#define RWFIELD(Type, name, getter, setter) \ + if (sig == 0 && id == name) { \ + static trans::virtualFieldAccess a(run::getter, run::setter); \ + static trans::varEntry v(Type(), &a, 0, position()); \ + return &v; \ + } + +#define SIGFIELD(Type, name, func) \ + if (id == name && \ + equivalent(sig, Type()->getSignature())) \ + { \ + static trans::virtualFieldAccess a(run::func, 0, run::func##Helper); \ + static trans::varEntry v(Type(), &a, 0, position()); \ + return &v; \ + } + +#define DSIGFIELD(name, sym, func) \ + if (id == sym && \ + equivalent(sig, name##Type()->getSignature())) \ + { \ + static trans::virtualFieldAccess a(run::func, 0, run::func##Helper); \ + /* for some fields, v needs to be dynamic */ \ + /* e.g. when the function type depends on an array type. */ \ + trans::varEntry *v = \ + new trans::varEntry(name##Type(), &a, 0, position()); \ + return v; \ + } + +#define FILEFIELD(GetType, SetType, name, sym) \ + FIELD(GetType,sym,name##Part); \ + SIGFIELD(SetType,sym,name##Set); + + +ty *dimensionType() { + return new function(primFile(), + formal(primInt(),SYM(nx),true), + formal(primInt(),SYM(ny),true), + formal(primInt(),SYM(nz),true)); +} + +ty *modeType() { + return new function(primFile(),formal(primBoolean(),SYM(b), true)); +} + +ty *readType() { + return new function(primFile(), formal(primInt(), SYM(i))); +} + +trans::varEntry *primitiveTy::virtualField(symbol id, signature *sig) +{ + switch (kind) { + case ty_pair: + FIELD(primReal,SYM(x),pairXPart); + FIELD(primReal,SYM(y),pairYPart); + break; + case ty_triple: + FIELD(primReal,SYM(x),tripleXPart); + FIELD(primReal,SYM(y),tripleYPart); + FIELD(primReal,SYM(z),tripleZPart); + break; + case ty_transform: + FIELD(primReal,SYM(x),transformXPart); + FIELD(primReal,SYM(y),transformYPart); + FIELD(primReal,SYM(xx),transformXXPart); + FIELD(primReal,SYM(xy),transformXYPart); + FIELD(primReal,SYM(yx),transformYXPart); + FIELD(primReal,SYM(yy),transformYYPart); + break; + case ty_tensionSpecifier: + FIELD(primReal,SYM(out),tensionSpecifierOutPart); + FIELD(primReal,SYM(in),tensionSpecifierInPart); + FIELD(primBoolean,SYM(atLeast),tensionSpecifierAtleastPart); + break; + case ty_curlSpecifier: + FIELD(primReal,SYM(value),curlSpecifierValuePart); + FIELD(primInt,SYM(side),curlSpecifierSidePart); + break; + case ty_file: + FIELD(primString,SYM(name),namePart); + FIELD(primString,SYM(mode),modePart); + FILEFIELD(IntArray,dimensionType,dimension,SYM(dimension)); + FILEFIELD(primBoolean,modeType,line,SYM(line)); + FILEFIELD(primBoolean,modeType,csv,SYM(csv)); + FILEFIELD(primBoolean,modeType,word,SYM(word)); + FILEFIELD(primBoolean,modeType,singlereal,SYM(singlereal)); + FILEFIELD(primBoolean,modeType,singleint,SYM(singleint)); + FILEFIELD(primBoolean,modeType,signedint,SYM(signedint)); + SIGFIELD(readType,SYM(read),readSet); + break; + default: + break; + } + return 0; +} + +ty *overloadedDimensionType() { + overloaded *o=new overloaded; + o->add(dimensionType()); + o->add(IntArray()); + return o; +} + +ty *overloadedModeType() { + overloaded *o=new overloaded; + o->add(modeType()); + o->add(primBoolean()); + return o; +} + +ty *ty::virtualFieldGetType(symbol id) +{ + trans::varEntry *v = virtualField(id, 0); + return v ? v->getType() : 0; +} + +ty *primitiveTy::virtualFieldGetType(symbol id) +{ + if(kind == ty_file) { + if (id == SYM(dimension)) + return overloadedDimensionType(); + + if (id == SYM(line) || id == SYM(csv) || + id == SYM(word) || id == SYM(singlereal) || + id == SYM(singleint) || id == SYM(signedint)) + return overloadedModeType(); + + if (id == SYM(read)) + return readType(); + } + + trans::varEntry *v = virtualField(id, 0); + + return v ? v->getType() : 0; +} + +#define RETURN_STATIC_BLTIN(func) \ + { \ + static trans::bltinAccess a(run::func); \ + return &a; \ + } + +trans::access *nullTy::castTo(ty *target, caster &) { + switch (target->kind) { + case ty_array: { + RETURN_STATIC_BLTIN(pushNullArray); + } + case ty_record: { + RETURN_STATIC_BLTIN(pushNullRecord); + } + case ty_function: { + RETURN_STATIC_BLTIN(pushNullFunction); + } + default: + return 0; + } +} + +trans::access *array::initializer() +{ + RETURN_STATIC_BLTIN(emptyArray) + } + +ty *array::pushType() +{ + if (pushtype == 0) + pushtype = new function(celltype,formal(celltype,SYM(x))); + + return pushtype; +} + +ty *array::popType() +{ + if (poptype == 0) + poptype = new function(celltype); + + return poptype; +} + +ty *array::appendType() +{ + if (appendtype == 0) + appendtype = new function(primVoid(),formal(this,SYM(a))); + + return appendtype; +} + +ty *array::insertType() +{ + if (inserttype == 0) { + function *f=new function(primVoid(),formal(primInt(),SYM(i))); + f->addRest(this); + inserttype = f; + } + + return inserttype; +} + +ty *array::deleteType() +{ + if (deletetype == 0) + deletetype = new function(primVoid(),formal(primInt(),SYM(i),true), + formal(primInt(),SYM(j),true)); + + return deletetype; +} + +ty *initializedType() { + return new function(primBoolean(),formal(primInt(),SYM(i))); +} + +#define SIGFIELDLIST \ + ASIGFIELD(initialized, SYM(initialized), arrayInitialized); \ + ASIGFIELD(push, SYM(push), arrayPush); \ + ASIGFIELD(pop, SYM(pop), arrayPop); \ + ASIGFIELD(append, SYM(append), arrayAppend); \ + ASIGFIELD(insert, SYM(insert), arrayInsert); \ + ASIGFIELD(delete, SYM(delete), arrayDelete); \ + +ty *array::virtualFieldGetType(symbol id) +{ +#define ASIGFIELD(name, sym, func) \ + if (id == sym) \ + return name##Type(); + + SIGFIELDLIST + +#undef ASIGFIELD + + return ty::virtualFieldGetType(id); +} + +trans::varEntry *array::virtualField(symbol id, signature *sig) +{ + FIELD(primInt, SYM(length), arrayLength); + FIELD(IntArray, SYM(keys), arrayKeys); + RWFIELD(primBoolean, SYM(cyclic), arrayCyclicFlag, arraySetCyclicFlag); + +#define ASIGFIELD(name, sym, func) DSIGFIELD(name, sym, func) + + SIGFIELDLIST + +#undef ASIGFIELD + + // Fall back on base class to handle no match. + return ty::virtualField(id, sig); +} + +#undef SIGFIELDLIST + +void printFormal(ostream& out, const formal& f, bool keywordOnly) +{ + if (f.Explicit) + out << "explicit "; + if (f.name) + f.t->printVar(out, keywordOnly ? "keyword "+(string)(f.name) : f.name); + else + f.t->print(out); + if (f.defval) + out << "=<default>"; +} + +ostream& operator<< (ostream& out, const formal& f) +{ +#if 0 + if (f.Explicit) + out << "explicit "; + if (f.name) + f.t->printVar(out,f.name); + else + f.t->print(out); + if (f.defval) + out << "=<default>"; +#endif + printFormal(out, f, false); + return out; +} + +bool equivalent(const formal& f1, const formal& f2) { + // Just test the types. + // This cannot be used on rest formal with types equal to NULL. + return equivalent(f1.t,f2.t); +} + +bool argumentEquivalent(const formal &f1, const formal& f2) { + if (f1.name == f2.name) { + if (f1.t == 0) + return f2.t == 0; + else if (f2.t == 0) + return false; + + return f1.t->kind != ty_overloaded && + f2.t->kind != ty_overloaded && + equivalent(f1.t, f2.t); + } + else + return false; +} + +ostream& operator<< (ostream& out, const signature& s) +{ + if (s.isOpen) { + out << "(<open>)"; + return out; + } + + out << "("; + + for (size_t i = 0; i < s.formals.size(); ++i) + { + if (i > 0) + out << ", "; + printFormal(out, s.getFormal(i), s.formalIsKeywordOnly(i)); + } + + if (s.rest.t) { + if (!s.formals.empty()) + out << " "; + out << "... " << s.rest; + } + + out << ")"; + + return out; +} + + +// Equivalence by design does not look at the presence of default values. +bool equivalent(const signature *s1, const signature *s2) +{ + if (s1 == s2) + return true; + + // Handle null signature + if (s1 == 0 || s2 == 0) + return false; + + // Two open signatures are always equivalent, as the formals are ignored. + if (s1->isOpen) + return s2->isOpen; + else if (s2->isOpen) + return false; + + if (s1->formals.size() != s2->formals.size()) + return false; + + if (!std::equal(s1->formals.begin(),s1->formals.end(),s2->formals.begin(), + (bool (*)(const formal&,const formal&)) equivalent)) + return false; + + if (s1->rest.t) + return s2->rest.t && equivalent(s1->rest, s2->rest); + else + return s2->rest.t == 0; +} + +bool argumentEquivalent(const signature *s1, const signature *s2) +{ + // Handle null signature + if (s1 == 0) + return s2 == 0; + else if (s2 == 0) + return false; + + if (s1->formals.size() != s2->formals.size()) + return false; + + return std::equal(s1->formals.begin(),s1->formals.end(),s2->formals.begin(), + (bool (*)(const formal&,const formal&)) + argumentEquivalent) && + argumentEquivalent(s1->rest, s2->rest); +} + +size_t signature::hash() const { + size_t x=2038; + for (formal_vector::const_iterator i=formals.begin(); i!=formals.end(); ++i) + x=x*0xFAEC+i->t->hash(); + + if (rest.t) + x=x*0xACED +rest.t->hash(); + + return x; +} + +trans::access *function::initializer() { + RETURN_STATIC_BLTIN(pushNullFunction); +} + +#if 0 +ty *function::stripDefaults() +{ + function *f = new function(result); + + Int n = sig.getNumFormals(); + for (Int i = 0; i < n; ++i) + f->add(sig.getFormal(i), 0); + + return f; +} +#endif + +// Only add a type with a signature distinct from the ones currently +// in the overloaded type. +void overloaded::addDistinct(ty *t, bool special) +{ + if (t->kind == ty_overloaded) { + overloaded *ot = (overloaded *)t; + for (ty_vector::iterator st = ot->sub.begin(); + st != ot->sub.end(); + ++st) + { + this->addDistinct(*st, special); + } + } + else { + for (ty_vector::iterator st = this->sub.begin(); + st != this->sub.end(); + ++st) + { + if (equivalent(t, *st, special)) + return; + } + + // Nonequivalent in signature - add it. + this->add(t); + } +} + + +ty *overloaded::signatureless() +{ + for(ty_vector::iterator t = sub.begin(); t != sub.end(); ++t) + if ((*t)->getSignature()==0) + return *t; + + return 0; +} + +bool overloaded::castable(ty *target, caster &c) +{ + for(ty_vector::iterator s = sub.begin(); s != sub.end(); ++s) + if (c.castable(target,*s)) + return true; + return false; +} + +bool equivalent(const ty *t1, const ty *t2) +{ + // The same pointer must point to the same type. + if (t1 == t2) + return true; + + // Ensure if an overloaded type is compared to a non-overloaded one, that the + // overloaded type's method is called. + if (t2->kind == ty_overloaded) + return t2->equiv(t1); + if (t1->kind == ty_overloaded) + return t1->equiv(t2); + + // Outside of overloaded types, different kinds mean different types. + if (t1->kind != t2->kind) + return false; + + return t1->equiv(t2); +} + + +bool equivalent(const ty *t1, const ty *t2, bool special) { + return special ? equivalent(t1, t2) : + equivalent(t1->getSignature(), t2->getSignature()); +} + +#undef FIELD +#undef RWFIELD +#undef SIGFIELD +#undef DSIGFIELD + +} // namespace types |