/*****
* entry.cc
* Andy Hammerlindl 2002/08/29
*
* All variables, built-in functions and user-defined functions reside
* within the same namespace. To keep track of all these, table of
* "entries" is used.
*****/
using std::memset;
using types::ty;
using types::signature;
using types::overloaded;
using types::ty_vector;
using types::ty_iterator;
namespace trans {
bool entry::pr::check(action act, coder &c) {
// We assume PUBLIC permissions and one's without an associated record are not
// stored.
assert(perm!=PUBLIC && r!=0);
return c.inTranslation(r->getLevel()) ||
(perm == RESTRICTED && act != WRITE);
}
void entry::pr::report(action act, position pos, coder &c) {
if (!c.inTranslation(r->getLevel())) {
if (perm == PRIVATE) {
em.error(pos);
em << "accessing private field outside of structure";
}
else if (perm == RESTRICTED && act == WRITE) {
em.error(pos);
em << "modifying non-public field outside of structure";
}
}
}
void venv::checkName(symbol name)
{
#if 0
// This size test is too slow, even for DEBUG_CACHE.
core.confirm_size();
#endif
// Get the type, and make it overloaded if it is not (for uniformity).
overloaded o;
ty *t = getType(name);
if (!t)
t = &o;
if (!t->isOverloaded()) {
o.add(t);
t = &o;
}
assert(t->isOverloaded());
size_t maxFormals = names[name].maxFormals;
size_t size = 0;
for (ty_iterator i = t->begin(); i != t->end(); ++i) {
assert(numFormals(*i) <= maxFormals);
varEntry *v = lookByType(name, *i);
assert(v);
assert(equivalent(v->getType(), *i));
++size;
}
size_t matches = 0;
core_venv::const_iterator end = core.end();
for (core_venv::const_iterator p = core.begin(); p != end; ++p) {
if (p->name == name) {
++matches;
// We are relying on the fact that this was the last type added to t, and
// that type are added by pushing them on the end of the vector.
set.pop_back();
if (set.size() == 1)
t = set.front();
} else {
#ifdef DEBUG_CACHE
assert(equivalent(t, s));
#endif
t = 0;
}
RIGHTKIND(t);
// Don't try to reduce numFormals as I doubt it is worth the cost of
// recalculating.
}
void venv::remove(const addition& a) {
CHECKNAME(a.name);
if (a.shadowed) {
varEntry *popEnt = core.store(a.name, a.shadowed);
void venv::endScope() {
if (scopesizes.empty()) {
// The corresponding beginScope happened when the venv was empty, so
// clear the hash tables to return to that state.
core.clear();
names.clear();
// Adds the definitions of the top-level scope to the level underneath,
// and then removes the top scope.
void venv::collapseScope() {
if (scopesizes.empty()) {
// Collapsing an empty scope.
assert(empty_scopes > 0);
--empty_scopes;
} else {
// As scopes are stored solely by the number of entries at the beginning
// of the scope, popping the top size will put all of the entries into the
// next scope down.
scopesizes.pop();
}
}
// Store the new variable. If it shadows an older variable, that varEntry
// will be returned.
varEntry *shadowed = core.store(name, v);
ty *t = v->getType();
// Record the addition, so it can be undone during endScope.
if (!scopesizes.empty())
additions.push(addition(name, t, shadowed));
if (shadowed)
// The new value shadows an old value. They have the same signature, but
// possibly different return types. If necessary, update the type stored
// by name.
names[name].replaceType(t, shadowed->getType());
else
// Add to the names hash table.
names[name].addType(t);
CHECKNAME(name);
}
varEntry *venv::lookBySignature(symbol name, signature *sig) {
// Rest arguments are complicated and rare. Don't handle them here.
if (sig->hasRest())
return 0;
// Likewise with the special operators.
if (name.special())
return 0;
namevalue& nv = names[name];
// Avoid ambiguities with default parameters.
if (nv.maxFormals != sig->getNumFormals())
return 0;
// See if this exactly matches a function in the table.
varEntry *ve = core.lookupNonSpecial(name, sig);
if (!ve)
return 0;
// Keyword-only arguments may cause matching to fail.
if (ve->getSignature()->numKeywordOnly > 0)
return 0;
// At this point, any function with an equivalent signature will be equal
// to the result of the normal overloaded function resolution. We may
// safely return it.
return ve;
}
varEntry *v=p.ent;
if (v->checkPerm(READ, c)) {
if (permission perm = c.getPermission(); perm != PUBLIC) {
// Add an additional restriction to v based on c.getPermission().
v = new varEntry(*v, perm, c.thisType());
}
varEntry *qve=qualifyVarEntry(qualifier, v);
enter(p.name, qve);
if (isAutoUnravel) {
registerAutoUnravel(p.name, qve);
}
}
}
}
bool venv::add(
symbol src, symbol dest, venv& source, varEntry *qualifier, coder &c,
mem::vector<varEntry*> *addedVec
) {
ty *t=source.getType(src);
if (!t)
return false;
if (t->isOverloaded()) {
bool added=false;
for (ty_iterator i = t->begin(); i != t->end(); ++i)
{
varEntry *v=source.lookByType(src, *i);
if (v->checkPerm(READ, c)) {
if (permission perm = c.getPermission(); perm != PUBLIC) {
// Add an additional restriction to v based on c.getPermission().
v = new varEntry(*v, perm, c.thisType());
}
varEntry *qve=qualifyVarEntry(qualifier, v);
enter(dest, qve);
if (addedVec != nullptr) {
addedVec->push_back(qve);
}
added=true;
}
}
return added;
}
else {
varEntry *v=source.lookByType(src, t);
if (!v->checkPerm(READ, c)) {
return false;
}
if (permission perm = c.getPermission(); perm != PUBLIC) {
// Add an additional restriction to v based on c.getPermission().
v = new varEntry(*v, perm, c.thisType());
}
varEntry *qve=qualifyVarEntry(qualifier, v);
enter(dest, qve);
if (addedVec != nullptr) {
addedVec->push_back(qve);
}
return true;
}
}
ty *venv::getType(symbol name)
{
return names[name].t;
}
void listValue(symbol name, varEntry *v, record *module)
{
if (!module || v->whereDefined() == module)
{
if (settings::getSetting<bool>("where"))
cout << v->getPos();
v->getType()->printVar(cout, name);
cout << ";\n";
}
}
void venv::listValues(symbol name, record *module)
{
ty *t=getType(name);
if (t->isOverloaded())
for (ty_iterator i = t->begin(); i != t->end(); ++i)
listValue(name, lookByType(name, *i), module);
else
listValue(name, lookByType(name, t), module);
flush(cout);
}
void venv::list(record *module)
{
// List all functions and variables.
for (namemap::iterator N = names.begin(); N != names.end(); ++N)
listValues(N->first, module);
}
void venv::completions(mem::list<symbol >& l, string start)
{
for(namemap::iterator N = names.begin(); N != names.end(); ++N)
if (prefix(start, N->first) && N->second.t)
l.push_back(N->first);
}
void venv::registerAutoUnravel(symbol name, varEntry *v,
AutounravelPriority priority)
{
mem::pair<symbol, ty*> p = {name, v->getType()};
if (nonShadowableAutoUnravels.find(p) != nonShadowableAutoUnravels.end()) {
if (priority == AutounravelPriority::FORCE) {
em.error(v->getPos());
em << "cannot shadow autounravel " << name;
}
return;
}
autoUnravels.emplace_front(name, v);
if (priority == AutounravelPriority::FORCE) {
// The value doesn't matter, we just need to know that the key exists.
nonShadowableAutoUnravels[p] = nullptr;
}
}