#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, nullPos); \
return v; \
}
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 *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();
// 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;
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 << "(<open>)";
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;
#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