summaryrefslogtreecommitdiff
path: root/Build/source/utils/asymptote/entry.h
diff options
context:
space:
mode:
authorKarl Berry <karl@freefriends.org>2009-05-16 00:19:13 +0000
committerKarl Berry <karl@freefriends.org>2009-05-16 00:19:13 +0000
commitbab45528d65eaafe68a705dbb2a57075c7b7cbd8 (patch)
tree10b4ae2b5195c8dede153ab89359ec00f55f325f /Build/source/utils/asymptote/entry.h
parent8643d90372e9c31e0f461c15c596b60a545bd7d3 (diff)
asymptote 1.72 sources (not integrated into build yet)
git-svn-id: svn://tug.org/texlive/trunk@13110 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Build/source/utils/asymptote/entry.h')
-rw-r--r--Build/source/utils/asymptote/entry.h392
1 files changed, 392 insertions, 0 deletions
diff --git a/Build/source/utils/asymptote/entry.h b/Build/source/utils/asymptote/entry.h
new file mode 100644
index 00000000000..c4ad2bef451
--- /dev/null
+++ b/Build/source/utils/asymptote/entry.h
@@ -0,0 +1,392 @@
+/*****
+ * entry.h
+ * 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, a table of
+ * "entries" is used.
+ *****/
+
+#ifndef ENTRY_H
+#define ENTRY_H
+
+#include <iostream>
+
+#include "common.h"
+#include "frame.h"
+#include "table.h"
+#include "types.h"
+#include "modifier.h"
+
+using sym::symbol;
+using types::ty;
+using types::signature;
+
+// Forward declaration.
+namespace types {
+class record;
+}
+using types::record;
+
+namespace trans {
+
+// An entry is associated to a name in the (variable or type) environment, and
+// has permission based on the enclosing records where it was defined or
+// imported.
+class entry : public gc {
+ struct pr {
+ permission perm;
+ record *r;
+
+ pr(permission perm, record *r)
+ : perm(perm), r(r) {}
+
+ // Returns true if the permission allows access in this context.
+ bool check(action act, coder &c);
+
+ // Reports an error if permission is not allowed.
+ void report(action act, position pos, coder &c);
+ };
+
+ mem::list<pr> perms;
+
+ void addPerm(permission perm, record *r) {
+ // Only store restrictive permissions.
+ if (perm != PUBLIC && r)
+ perms.push_back(pr(perm,r));
+ }
+
+ // The record where the variable or type is defined, or 0 if the entry is
+ // not a field.
+ record *where;
+
+ // The location (file and line number) where the entry was defined.
+ position pos;
+
+public:
+ entry(record *where, position pos) : where(where), pos(pos) {}
+ entry(permission perm, record *r, record *where, position pos)
+ : where(where), pos(pos) {
+ addPerm(perm, r);
+ }
+
+ // (Non-destructively) merges two entries, appending permission lists.
+ // The 'where' member is taken from the second entry.
+ entry(entry &e1, entry &e2);
+
+ // Create an entry with one more permission in the list.
+ entry(entry &base, permission perm, record *r);
+
+ bool checkPerm(action act, coder &c);
+ void reportPerm(action act, position pos, coder &c);
+
+ record *whereDefined() {
+ return where;
+ }
+
+ position getPos() {
+ return pos;
+ }
+};
+
+class varEntry : public entry {
+ ty *t;
+ access *location;
+
+public:
+ varEntry(ty *t, access *location, record *where, position pos)
+ : entry(where, pos), t(t), location(location) {}
+
+ varEntry(ty *t, access *location, permission perm, record *r,
+ record *where, position pos)
+ : entry(perm, r, where, pos), t(t), location(location) {}
+
+ // (Non-destructively) merges two varEntries, creating a qualified varEntry.
+ varEntry(varEntry &qv, varEntry &v);
+
+ ty *getType()
+ { return t; }
+
+ signature *getSignature()
+ {
+ return t->getSignature();
+ }
+
+ access *getLocation()
+ { return location; }
+
+ frame *getLevel();
+
+ // Encodes the access, but also checks permissions.
+ void encode(action act, position pos, coder &c);
+ void encode(action act, position pos, coder &c, frame *top);
+};
+
+varEntry *qualifyVarEntry(varEntry *qv, varEntry *v);
+
+// As looked-up types can be allocated in a new expression, we need to know
+// what frame they should be allocated on. Type entries store this extra
+// information along with the type.
+class tyEntry : public entry {
+public:
+ ty *t;
+ varEntry *v; // NOTE: Name isn't very descriptive.
+
+ tyEntry(ty *t, varEntry *v, record *where, position pos)
+ : entry(where, pos), t(t), v(v) {}
+
+ tyEntry(tyEntry *base, permission perm, record *r)
+ : entry(*base, perm, r), t(base->t), v(base->v) {}
+
+ // Records need a varEntry that refers back to the qualifier qv; i.e. in
+ // the last new of the code
+ // struct A {
+ // struct B {}
+ // }
+ // A a=new A;
+ // unravel a;
+ // new B;
+ // we need to put a's frame on the stack before allocating an instance of B.
+ // NOTE: A possible optimization could be to only qualify the varEntry if
+ // the type is a record, as other types don't use the varEntry.
+private:
+ tyEntry(tyEntry *base, varEntry *qv)
+ : entry(*base, *qv), t(base->t), v(qualifyVarEntry(qv, base->v)) {}
+
+public:
+ // Since the constructor can only be used when qv is non-null it is private
+ // for safety reasons, and we provide this method instead.
+ friend tyEntry *qualifyTyEntry(varEntry *qv, tyEntry *ent);
+};
+
+inline tyEntry *qualifyTyEntry(varEntry *qv, tyEntry *ent) {
+ return qv ? new tyEntry(ent, qv) : ent;
+}
+
+// The type environment.
+class tenv : public sym::table<tyEntry *> {
+ bool add(symbol *dest, names_t::value_type &x, varEntry *qualifier,
+ coder &c);
+public:
+ // Add the entries in one environment to another, if qualifier is
+ // non-null, it is a record and the source environment is its types. The
+ // coder is used to see which entries are accessible and should be added.
+ void add(tenv& source, varEntry *qualifier, coder &c);
+
+ // Adds entries of the name src in source as the name dest, returning true if
+ // any were added.
+ bool add(symbol *src, symbol *dest,
+ tenv& source, varEntry *qualifier, coder &c);
+};
+
+#ifdef NOHASH //{{{
+class venv : public sym::table<varEntry*> {
+public:
+ venv() {}
+
+ // This is an optimization in the hashtable version that is duplicated here
+ // for compatibility. It is identical to venv().
+ struct file_env_tag {};
+ venv(file_env_tag) {}
+
+#if 0
+ // Look for a function that exactly matches the signature given.
+ varEntry *lookExact(symbol *name, signature *key);
+#endif
+
+ // Add the entries in one environment to another, if qualifier is
+ // non-null, it is a record and the source environment are its fields.
+ // The coder is necessary to check which variables are accessible and
+ // should be added.
+ void add(venv& source, varEntry *qualifier, coder &c);
+
+ // Add all unshadowed variables from source of the name src as variables
+ // named dest. Returns true if at least one was added.
+ bool add(symbol *src, symbol *dest,
+ venv& source, varEntry *qualifier, coder &c);
+
+ // Look for a function that exactly matches the type given.
+ varEntry *lookByType(symbol *name, ty *t);
+
+ // Checks if a function was added in the top scope as two identical
+ // functions cannot be defined in one scope.
+ varEntry *lookInTopScope(symbol *name, ty *t);
+
+ // Return the type of the variable, if name is overloaded, return an
+ // overloaded type.
+ ty *getType(symbol *name);
+
+ friend std::ostream& operator<< (std::ostream& out, const venv& ve);
+
+ // Prints a list of the variables to the standard output.
+ void list(record *module=0);
+};
+
+//}}}
+#else //{{{
+
+// venv implemented with a hash table.
+class venv {
+ struct key : public gc {
+ symbol *name;
+ ty *t;
+
+ key(symbol *name, ty *t)
+ : name(name), t(t) {}
+
+ key(symbol *name, varEntry *v)
+ : name(name), t(v->getType()) {}
+ };
+ friend ostream& operator<< (ostream& out, const venv::key &k);
+
+ struct value : public gc {
+ varEntry *v;
+ bool shadowed;
+ value *next; // The entry (of the same key) that this one shadows.
+
+ value(varEntry *v)
+ : v(v), shadowed(false), next(0) {}
+ };
+ struct namehash {
+ size_t operator()(const symbol *name) const {
+ return (size_t)name;
+ }
+ };
+ struct nameeq {
+ bool operator()(const symbol *s, const symbol *t) const {
+ return s==t;
+ }
+ };
+ struct keyhash {
+ size_t hashSig(ty *t) const {
+ signature *sig=t->getSignature();
+ return sig ? sig->hash() : 0;
+ }
+ size_t operator()(const key k) const {
+ return (size_t)(k.name) * 107 +
+ (k.name->special ? k.t->hash() : hashSig(k.t));
+ }
+ };
+ struct keyeq {
+#define TEST_COLLISION 0
+#if TEST_COLLISION
+ bool base(const key k, const key l) const {
+ return k.name==l.name &&
+ (k.name->special ? equivalent(k.t, l.t) :
+ equivalent(k.t->getSignature(),
+ l.t->getSignature()));
+ }
+ bool operator()(const key k, const key l) const;
+#else
+ bool operator()(const key k, const key l) const;
+#endif
+ };
+
+
+ // A hash table used to quickly look up a variable once its name and type are
+ // known. Includes all scopes.
+ typedef mem::unordered_map<key, value *, keyhash, keyeq> keymap;
+ keymap all;
+
+ // Similar hashes, one for each scope level.
+ typedef mem::unordered_multimap<key, value *, keyhash, keyeq> keymultimap;
+ typedef mem::stack<keymultimap> mapstack;
+ mapstack scopes;
+
+ // A hash table indexed solely on the name, storing for each name the list of
+ // all values of that name. Used to get the (possibly overloaded) type
+ // of the name.
+ typedef mem::list<value *> values;
+ typedef mem::unordered_map<symbol *, values, namehash, nameeq> namemap;
+ namemap names;
+
+ void listValues(symbol *name, values &vals, record *module);
+
+ // Helper function for endScope.
+ void remove(key k);
+
+ // These are roughly the size the hashtables will be after loading the
+ // builtin functions and plain module.
+ static const size_t fileAllSize=2000;
+ static const size_t namesAllSize=1000;
+public:
+ venv() {
+ beginScope();
+ }
+
+ // Most file level modules automatically import plain, so allocate hashtables
+ // big enough to hold it in advance.
+ struct file_env_tag {};
+ venv(file_env_tag)
+ : all(fileAllSize), names(namesAllSize)
+ {
+ beginScope();
+ }
+
+ void enter(symbol *name, varEntry *v);
+
+ // Add the entries in one environment to another, if qualifier is
+ // non-null, it is a record and entries of the source environment are its
+ // fields. The coder is necessary to check which variables are accessible and
+ // should be added.
+ void add(venv& source, varEntry *qualifier, coder &c);
+
+ // Add all unshadowed variables from source of the name src as variables
+ // named dest. Returns true if at least one was added.
+ bool add(symbol *src, symbol *dest,
+ venv& source, varEntry *qualifier, coder &c);
+
+ bool lookInTopScope(key k) {
+ return scopes.top().find(k)!=scopes.top().end();
+ }
+
+ // Look for a function that exactly matches the type given.
+ bool lookInTopScope(symbol *name, ty *t) {
+ return lookInTopScope(key(name, t));
+ }
+
+ varEntry *lookByType(key k) {
+ keymap::const_iterator p=all.find(k);
+ return p!=all.end() ? p->second->v : 0;
+ }
+
+ // Look for a function that exactly matches the type given.
+ varEntry *lookByType(symbol *name, ty *t) {
+ return lookByType(key(name, t));
+ }
+
+ ty *getType(symbol *name);
+
+ void beginScope() {
+ scopes.push(keymultimap());
+ }
+ void endScope() {
+ keymultimap &scope=scopes.top();
+ for (keymultimap::iterator p=scope.begin(); p!=scope.end(); ++p) {
+ remove(p->first);
+ }
+ scopes.pop();
+ }
+
+ // Adds the definitions of the top-level scope to the level underneath,
+ // and then removes the top scope.
+ void collapseScope() {
+ // NOTE: May be expensively copying a large hash table.
+ keymultimap top=scopes.top();
+ scopes.pop();
+
+ keymultimap& underneath=scopes.top();
+ underneath.insert(top.begin(), top.end());
+ }
+
+ // Prints a list of the variables to the standard output.
+ void list(record *module=0);
+
+ // Adds to l, all names prefixed by start.
+ void completions(mem::list<symbol *>& l, string start);
+};
+#endif
+
+} // namespace trans
+
+#endif //ENTRY_H