From ad547a6b5986815fda458221149728d9d9ab1d87 Mon Sep 17 00:00:00 2001 From: Karl Berry Date: Thu, 25 Feb 2021 19:22:25 +0000 Subject: restore Build,TODO from r57911 git-svn-id: svn://tug.org/texlive/trunk@57915 c570f23f-e606-0410-a88d-b1316a301751 --- Build/source/utils/asymptote/entry.cc | 787 ++++++++++++++++++++++++++++++++++ 1 file changed, 787 insertions(+) create mode 100644 Build/source/utils/asymptote/entry.cc (limited to 'Build/source/utils/asymptote/entry.cc') diff --git a/Build/source/utils/asymptote/entry.cc b/Build/source/utils/asymptote/entry.cc new file mode 100644 index 00000000000..7a780fdd56b --- /dev/null +++ b/Build/source/utils/asymptote/entry.cc @@ -0,0 +1,787 @@ +/***** + * 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. + *****/ + +#include + +#include +#include +#include +#include "entry.h" +#include "coder.h" + +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"; + } + } +} + +entry::entry(entry &e1, entry &e2) : where(e2.where), pos(e2.pos) { + perms.insert(perms.end(), e1.perms.begin(), e1.perms.end()); + perms.insert(perms.end(), e2.perms.begin(), e2.perms.end()); +} + +entry::entry(entry &base, permission perm, record *r) + : where(base.where), pos(base.pos) { + perms.insert(perms.end(), base.perms.begin(), base.perms.end()); + addPerm(perm, r); +} + +bool entry::checkPerm(action act, coder &c) { + for (mem::list::iterator p=perms.begin(); p != perms.end(); ++p) + if (!p->check(act, c)) + return false; + return true; +} + +void entry::reportPerm(action act, position pos, coder &c) { + for (mem::list::iterator p=perms.begin(); p != perms.end(); ++p) + p->report(act, pos, c); +} + + +varEntry::varEntry(varEntry &qv, varEntry &v) + : entry(qv,v), t(v.t), + location(new qualifiedAccess(qv.location, qv.getLevel(), v.location)) {} + +frame *varEntry::getLevel() { + record *r=dynamic_cast(t); + assert(r); + return r->getLevel(); +} + +void varEntry::encode(action act, position pos, coder &c) { + reportPerm(act, pos, c); + getLocation()->encode(act, pos, c); +} + +void varEntry::encode(action act, position pos, coder &c, frame *top) { + reportPerm(act, pos, c); + getLocation()->encode(act, pos, c, top); +} + +varEntry *qualifyVarEntry(varEntry *qv, varEntry *v) +{ + return qv ? (v ? new varEntry(*qv,*v) : qv) : v; +} + + +bool tenv::add(symbol dest, + names_t::value_type &x, varEntry *qualifier, coder &c) +{ + if (!x.second.empty()) { + tyEntry *ent=x.second.front(); + if (ent->checkPerm(READ, c)) { + enter(dest, qualifyTyEntry(qualifier, ent)); + return true; + } + } + return false; +} + +void tenv::add(tenv& source, varEntry *qualifier, coder &c) { + // Enter each distinct (unshadowed) name,type pair. + for(names_t::iterator p = source.names.begin(); p != source.names.end(); ++p) + add(p->first, *p, qualifier, c); +} + +bool tenv::add(symbol src, symbol dest, + tenv& source, varEntry *qualifier, coder &c) { + names_t::iterator p = source.names.find(src); + if (p != source.names.end()) + return add(dest, *p, qualifier, c); + else + return false; +} + +// To avoid writing qualifiers everywhere. +typedef core_venv::cell cell; + +void core_venv::initTable(size_t capacity) { + // Assert that capacity is a power of two. + assert((capacity & (capacity-1)) == 0); + + this->capacity = capacity; + size = 0; + mask = capacity - 1; + table = new (UseGC) cell[capacity]; + memset(table, 0, sizeof(cell) * capacity); +} + +void core_venv::clear() { + if (size != 0) { + memset(table, 0, sizeof(cell) * capacity); + size = 0; + } +} + +void core_venv::resize() { + size_t oldCapacity = capacity; + size_t oldSize = size; + cell *oldTable = table; + + initTable(capacity * 4); + + for (size_t i = 0; i < oldCapacity; ++i) { + cell& b = oldTable[i]; + if (!b.empty() && !b.isATomb()) { + varEntry *old = store(b.name, b.ent); + + // We should not be shadowing anything when reconstructing the table. + DEBUG_CACHE_ASSERT(old == 0); + } + } + + assert(size == oldSize); + +#if DEBUG_CACHE + confirm_size(); + + for (size_t i = 0; i < oldCapacity; ++i) { + cell& b = oldTable[i]; + if (!b.empty() && !b.isATomb()) { + assert(lookup(b.name, b.ent->getType()) == b.ent); + } + } +#endif + + //cout << "resized from " << oldCapacity << " to " << capacity << endl; +} + +cell& core_venv::cellByIndex(size_t i) { + return table[i & mask]; +} + +const cell& core_venv::cellByIndex(size_t i) const { + return table[i & mask]; +} + +void core_venv::confirm_size() { + size_t sum = 0; + for (size_t i = 0; i < capacity; ++i) { + cell& b = table[i]; + if (!b.empty() && !b.isATomb()) + ++sum; + } + assert(sum == size); +} + +varEntry *core_venv::storeNew(cell& cell, symbol name, varEntry *ent) { + // Store the value into the cell. + cell.storeNew(name, ent); + + // We now have a new entry. Update the size. + ++size; + + // Check if the hash table has grown too big and needs to be expanded. + if (2*size > capacity) + resize(); + + // Nothing is shadowed. + return 0; +} + + +varEntry *core_venv::storeNonSpecialAfterTomb(size_t tombIndex, + symbol name, varEntry *ent) { + DEBUG_CACHE_ASSERT(name.notSpecial()); + DEBUG_CACHE_ASSERT(ent); + DEBUG_CACHE_ASSERT(ent->getType()); + + signature *sig = ent->getSignature(); + + for (size_t i = tombIndex+1; ; ++i) + { + cell& b = cellByIndex(i); + + if (b.empty()) + return storeNew(cellByIndex(tombIndex), name, ent); + + if (b.matches(name, sig)) + return b.replaceWith(name, ent); + } +} + +varEntry *core_venv::storeSpecialAfterTomb(size_t tombIndex, + symbol name, varEntry *ent) { + DEBUG_CACHE_ASSERT(name.special()); + DEBUG_CACHE_ASSERT(ent); + DEBUG_CACHE_ASSERT(ent->getType()); + + ty *t = ent->getType(); + + for (size_t i = tombIndex+1; ; ++i) + { + cell& b = cellByIndex(i); + + if (b.empty()) + return storeNew(cellByIndex(tombIndex), name, ent); + + if (b.matches(name, t)) + return b.replaceWith(name, ent); + } +} + +size_t hashSig(const signature *sig) { + return sig ? sig->hash() : 0; +} +size_t nonSpecialHash(symbol name, const signature *sig) { + return name.hash() * 107 + hashSig(sig); +} +size_t nonSpecialHash(symbol name, const ty *t) { + DEBUG_CACHE_ASSERT(t); + return nonSpecialHash(name, t->getSignature()); +} +size_t specialHash(symbol name, const ty *t) { + DEBUG_CACHE_ASSERT(t); + return name.hash() * 107 + t->hash(); +} + +varEntry *core_venv::storeNonSpecial(symbol name, varEntry *ent) { + DEBUG_CACHE_ASSERT(name.notSpecial()); + DEBUG_CACHE_ASSERT(ent); + DEBUG_CACHE_ASSERT(ent->getType()); + + signature *sig = ent->getSignature(); + + for (size_t i = nonSpecialHash(name, sig); ; ++i) + { + cell& b = cellByIndex(i); + + if (b.empty()) + return storeNew(b, name, ent); + + if (b.matches(name, sig)) + return b.replaceWith(name, ent); + + if (b.isATomb()) + return storeNonSpecialAfterTomb(i, name, ent); + } +} + +varEntry *core_venv::storeSpecial(symbol name, varEntry *ent) { + DEBUG_CACHE_ASSERT(name.special()); + DEBUG_CACHE_ASSERT(ent); + DEBUG_CACHE_ASSERT(ent->getType()); + + ty *t = ent->getType(); + + for (size_t i = specialHash(name, t); ; ++i) + { + cell& b = cellByIndex(i); + + if (b.empty()) + return storeNew(b, name, ent); + + if (b.matches(name, t)) + return b.replaceWith(name, ent); + + if (b.isATomb()) + return storeSpecialAfterTomb(i, name, ent); + } +} + +varEntry *core_venv::store(symbol name, varEntry *ent) { + DEBUG_CACHE_ASSERT(ent); + DEBUG_CACHE_ASSERT(ent->getType()); + + return name.special() ? storeSpecial(name, ent) : + storeNonSpecial(name, ent); +} + +varEntry *core_venv::lookupSpecial(symbol name, const ty *t) { + DEBUG_CACHE_ASSERT(name.special()); + DEBUG_CACHE_ASSERT(t); + + for (size_t i = specialHash(name, t); ; ++i) + { + cell& b = cellByIndex(i); + + if (b.matches(name, t)) + return b.ent; + + if (b.empty()) + return 0; + } +} + +varEntry *core_venv::lookupNonSpecial(symbol name, const signature *sig) { + DEBUG_CACHE_ASSERT(name.notSpecial()); + + for (size_t i = nonSpecialHash(name, sig); ; ++i) + { + cell& b = cellByIndex(i); + + if (b.matches(name, sig)) + return b.ent; + + if (b.empty()) + return 0; + } +} + +varEntry *core_venv::lookup(symbol name, const ty *t) { + DEBUG_CACHE_ASSERT(t); + + return name.special() ? lookupSpecial(name, t) : + lookupNonSpecial(name, t->getSignature()); +} + +void core_venv::removeNonSpecial(symbol name, const signature *sig) { + DEBUG_CACHE_ASSERT(name.notSpecial()); + + for (size_t i = nonSpecialHash(name, sig); ; ++i) + { + cell& b = cellByIndex(i); + + if (b.matches(name, sig)) { + b.remove(); + --size; + return; + } + + DEBUG_CACHE_ASSERT(!b.empty()); + } +} + +void core_venv::removeSpecial(symbol name, const ty *t) { + DEBUG_CACHE_ASSERT(name.special()); + DEBUG_CACHE_ASSERT(t); + + for (size_t i = specialHash(name, t); ; ++i) + { + cell& b = cellByIndex(i); + + if (b.matches(name, t)) { + b.remove(); + --size; + return; + } + + DEBUG_CACHE_ASSERT(!b.empty()); + } +} + +void core_venv::remove(symbol name, const ty *t) { + DEBUG_CACHE_ASSERT(t); + + if (name.special()) + removeSpecial(name, t); + else + removeNonSpecial(name, t->getSignature()); +} + + +size_t numFormals(ty *t) { + signature *sig = t->getSignature(); + return sig ? sig->getNumFormals() : 0; +} + +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; + + varEntry *v=p->ent; + assert(v); + assert(equivalent(t, v->getType())); + } + } + assert(matches == size); +} + +void rightKind(ty *t) { + if (t && t->isOverloaded()) { + ty_vector& set=((overloaded *)t)->sub; + assert(set.size() > 1); + } +} + +#ifdef DEBUG_CACHE +#define RIGHTKIND(t) (rightKind(t)) +#define CHECKNAME(name) (checkName(name)) +#else +#define RIGHTKIND(t) (void)(t) +#define CHECKNAME(name) (void)(name) +#endif + +void venv::namevalue::addType(ty *s) { + RIGHTKIND(t); + +#ifdef DEBUG_CACHE + assert(!s->isOverloaded()); +#endif + + if (t == 0) { + maxFormals = numFormals(s); + t = s; + } else { + if (!t->isOverloaded()) + t = new overloaded(t); + +#ifdef DEBUG_CACHE + assert(t->isOverloaded()); + assert(!equivalent(t, s)); +#endif + + ((overloaded *)t)->add(s); + + size_t n = numFormals(s); + if (n > maxFormals) + maxFormals = n; + } + + RIGHTKIND(t); +} + +void venv::namevalue::replaceType(ty *new_t, ty *old_t) { +#ifdef DEBUG_CACHE + assert(t != 0); + RIGHTKIND(t); +#endif + + // TODO: Test for equivalence. + + if (t->isOverloaded()) { + for (ty_iterator i = t->begin(); i != t->end(); ++i) { + if (equivalent(old_t, *i)) { + *i = new_t; + return; + } + } + + // An error, the type was not found. + assert("unreachable code" == 0); + + } else { +#ifdef DEBUG_CACHE + assert(equivalent(old_t, t)); +#endif + t = new_t; + } + +#ifdef DEBUG_CACHE + assert(t != 0); + RIGHTKIND(t); +#endif +} + +#ifdef DEBUG_CACHE +void venv::namevalue::popType(ty *s) +#else + void venv::namevalue::popType() +#endif +{ +#ifdef DEBUG_CACHE + assert(t); + RIGHTKIND(t); + assert(!s->isOverloaded()); +#endif + + if (t->isOverloaded()) { + ty_vector& set=((overloaded *)t)->sub; + +#ifdef DEBUG_CACHE + assert(set.size() > 0); + assert(equivalent(set.back(), s)); +#endif + + // 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); + + DEBUG_CACHE_ASSERT(popEnt); + + // Unshadow the previously shadowed varEntry. + names[a.name].replaceType(a.shadowed->getType(), popEnt->getType()); + } + else { + // Remove the (name,sig) key completely. +#if DEBUG_CACHE + varEntry *popEnt = core.lookup(a.name, a.t); + assert(popEnt); + names[a.name].popType(popEnt->getType()); +#else + names[a.name].popType(); +#endif + + core.remove(a.name, a.t); + } + + CHECKNAME(a.name); +} + +void venv::beginScope() { + if (core.empty()) { + assert(scopesizes.empty()); + ++empty_scopes; + } else { + scopesizes.push(additions.size()); + } +} + +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(); + + assert(empty_scopes > 0); + --empty_scopes; + } else { + size_t scopesize = scopesizes.top(); + assert(additions.size() >= scopesize); + while (additions.size() > scopesize) { + remove(additions.top()); + additions.pop(); + } + scopesizes.pop(); + } +} + +// 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(); + } +} + + +void venv::enter(symbol name, varEntry *v) +{ + CHECKNAME(name); + + // 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; +} + +void venv::add(venv& source, varEntry *qualifier, coder &c) +{ + core_venv::const_iterator end = source.core.end(); + for (core_venv::const_iterator p = source.core.begin(); p != end; ++p) + { + DEBUG_CACHE_ASSERT(p->filled()); + + varEntry *v=p->ent; + if (v->checkPerm(READ, c)) { + enter(p->name, qualifyVarEntry(qualifier, v)); + } + } +} + +bool venv::add(symbol src, symbol dest, + venv& source, varEntry *qualifier, coder &c) +{ + 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)) { + enter(dest, qualifyVarEntry(qualifier, v)); + added=true; + } + } + return added; + } + else { + varEntry *v=source.lookByType(src, t); + if (v->checkPerm(READ, c)) { + enter(dest, qualifyVarEntry(qualifier, v)); + return true; + } + return false; + } +} + + +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("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& 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); +} + +} // namespace trans -- cgit v1.2.3