/***** * 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 #include #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" #include "asyprocess.h" namespace run { void arrayDeleteHelper(vm::stack *Stack); } // For pre-translated symbols. #ifndef NOSYM #include "types.symbols.h" #endif namespace types { const signature::OPEN_t signature::OPEN; /* 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", "", "", "", #define PRIMITIVE(name,Name,asyName) #asyName, #define PRIMERROR #include "primitives.h" #undef PRIMERROR #undef PRIMITIVE "" }; 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 << "="; } 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 << "="; #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; } string toString(const signature& s) { ostringstream 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; } return out.str(); } ostream& operator<< (ostream& out, const signature& s) { if (s.isOpen) { out << "()"; return out; } out << "("; out << toString(s); 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; } size_t signature::handle() { processDataStruct *P=&processData(); size_t h=hash(); for(;;) { auto p=P->sigMap.find(h); if(p == P->sigMap.end()) { P->sigMap[h]=this; return h; } if(equivalent(p->second,this)) return h; ++h; } } 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