/*****
* name.cc
* Andy Hammerlindl2002/07/14
*
* Qualified names (such as x, f, builtin.sin, a.b.c.d, etc.) can be used
* either as variables or a type names. This class stores qualified
* names used in nameExp and nameTy in the abstract syntax, and
* implements the exp and type functions.
*****/
namespace absyntax {
using namespace types;
using trans::access;
using trans::qualifiedAccess;
using trans::action;
using trans::READ;
using trans::WRITE;
using trans::CALL;
using vm::inst;
types::ty *signatureless(types::ty *t) {
if (overloaded *o=dynamic_cast<overloaded *>(t))
return o->signatureless();
else
return (t && !t->getSignature()) ? t : 0;
}
void name::forceEquivalency(action act, coenv &e,
types::ty *target, types::ty *source)
{
if (act == READ)
e.implicitCast(getPos(), target, source);
else if (!equivalent(target, source)) {
em.compiler(getPos());
em << "type mismatch in variable: "
<< *target
<< " vs " << *source;
}
}
frame *name::frameTrans(coenv &e)
{
if (types::ty *t=signatureless(varGetType(e))) {
if (t->kind == types::ty_record) {
varTrans(READ, e, t);
return ((record *)t)->getLevel();
}
else
return 0;
}
else
return tyFrameTrans(e);
}
types::ty *name::getType(coenv &e, bool tacit)
{
types::ty *t=signatureless(varGetType(e));
if (!tacit && t && t->kind == ty_error)
// Report errors associated with regarding the name as a variable.
varTrans(trans::READ, e, t);
return t ? t : typeTrans(e, tacit);
}
varEntry *simpleName::getVarEntry(coenv &e)
{
// If the name refers to a signatureless variable,
// return its varEntry.
types::ty *t=signatureless(varGetType(e));
if (t)
return e.e.lookupVarByType(id, t);
// Otherwise, the name refers to a type.
// Return its varEntry.
tyEntry *ent = e.e.lookupTyEntry(id);
return ent ? ent->v : 0;
}
if (v) {
v->encode(act, getPos(), e.c);
forceEquivalency(act, e, target, v->getType());
}
else {
em.error(getPos());
em << "no matching variable of name \'" << id << "\'";
}
}
types::ty *simpleName::typeTrans(coenv &e, bool tacit)
{
types::ty *t = e.e.lookupType(id);
if (t) {
return t;
}
else {
if (!tacit) {
em.error(getPos());
em << "no type of name \'" << id << "\'";
}
return primError();
}
}
tyEntry *simpleName::tyEntryTrans(coenv &e)
{
tyEntry *ent = e.e.lookupTyEntry(id);
if (!ent) {
em.error(getPos());
em << "no type of name \'" << id << "\'";
return new tyEntry(primError(), nullptr, nullptr, nullPos);
}
return ent;
}
record *qualifiedName::castToRecord(types::ty *t, bool tacit)
{
switch (t->kind) {
case ty_overloaded:
if (!tacit) {
em.compiler(qualifier->getPos());
em << "name::getType returned overloaded";
}
return 0;
case ty_record:
return (record *)t;
case ty_error:
return 0;
default:
if (!tacit) {
em.error(qualifier->getPos());
em << "type \'" << *t << "\' is not a structure";
}
return 0;
}
}
if (v) {
frame *f = qualifier->frameTrans(e);
if (f)
v->encode(act, getPos(), e.c, f);
else
v->encode(act, getPos(), e.c);
forceEquivalency(act, e, target, v->getType());
}
else {
em.error(getPos());
em << "no matching field of name \'" << id << "\' in \'" << *r << "\'";
}
}
// Look for virtual fields.
types::ty *t = qt->virtualFieldGetType(id);
if (t)
return t;
record *r = castToRecord(qt, true);
return r ? r->e.varGetType(id) : 0;
}
trans::varEntry *qualifiedName::getCallee(coenv &e, signature *sig)
{
// getTypeAsCallee is an optimization attempt. We don't try optimizing the
// rarer qualifiedName call case.
// TODO: See if this is worth implementing.
//cout << "FAIL BY QUALIFIED NAME" << endl;
return 0;
}
record *r = castToRecord(rt, tacit);
if (!r)
return primError();
tyEntry *ent = r->e.lookupTyEntry(id);
if (ent) {
if (!tacit)
ent->reportPerm(READ, getPos(), e.c);
return ent->t;
}
else {
if (!tacit) {
em.error(getPos());
em << "no matching field or type of name \'" << id << "\' in \'"
<< *r << "\'";
}
return primError();
}
}
record *r = castToRecord(rt, false);
if (!r)
return new tyEntry(primError(), nullptr, nullptr, nullPos);
tyEntry *ent = r->e.lookupTyEntry(id);
if (!ent) {
em.error(getPos());
em << "no matching type of name \'" << id << "\' in \'"
<< *r << "\'";
return new tyEntry(primError(), nullptr, nullptr, nullPos);
}
ent->reportPerm(READ, getPos(), e.c);