summaryrefslogtreecommitdiff
path: root/Build/source/utils/asymptote/types.h
diff options
context:
space:
mode:
Diffstat (limited to 'Build/source/utils/asymptote/types.h')
-rw-r--r--Build/source/utils/asymptote/types.h655
1 files changed, 655 insertions, 0 deletions
diff --git a/Build/source/utils/asymptote/types.h b/Build/source/utils/asymptote/types.h
new file mode 100644
index 00000000000..9492890bd20
--- /dev/null
+++ b/Build/source/utils/asymptote/types.h
@@ -0,0 +1,655 @@
+/*****
+ * types.h
+ * Andy Hammerlindl 2002/06/20
+ *
+ * Used by the compiler as a way to keep track of the type of a variable
+ * or expression.
+ *
+ *****/
+
+#ifndef TYPES_H
+#define TYPES_H
+
+#include <iostream>
+#include <cstdio>
+#include <cassert>
+
+#include "errormsg.h"
+#include "symbol.h"
+#include "common.h"
+#include "util.h"
+
+using std::ostream;
+
+using sym::symbol;
+
+// Forward declaration.
+namespace trans {
+class access;
+class varEntry;
+}
+namespace absyntax {
+class varinit;
+extern varinit *Default;
+}
+
+namespace types {
+
+enum ty_kind {
+ ty_null,
+ ty_record, // "struct" in Asymptote language
+ ty_function,
+ ty_overloaded,
+
+#define PRIMITIVE(name,Name,asyName) ty_##name,
+#define PRIMERROR
+#include "primitives.h"
+#undef PRIMERROR
+#undef PRIMITIVE
+
+ ty_array
+};
+
+// Forward declarations.
+class ty;
+struct signature;
+typedef mem::vector<ty *> ty_vector;
+typedef ty_vector::iterator ty_iterator;
+
+// Checks if two types are equal in the sense of the language.
+// That is primitive types are equal if they are the same kind.
+// Structures are equal if they come from the same struct definition.
+// Arrays are equal if their cell types are equal.
+bool equivalent(const ty *t1, const ty *t2);
+
+// If special is true, this is the same as above. If special is false, just the
+// signatures are compared.
+bool equivalent(const ty *t1, const ty *t2, bool special);
+
+class caster {
+public:
+ virtual ~caster() {}
+ virtual trans::access *operator() (ty *target, ty *source) = 0;
+ virtual bool castable(ty *target, ty *source) = 0;
+};
+
+class ty : public gc {
+public:
+ const ty_kind kind;
+ ty(ty_kind kind)
+ : kind(kind) {}
+ virtual ~ty();
+
+ virtual void print (ostream& out) const;
+ virtual void printVar (ostream& out, string name) const {
+ print(out);
+ out << " " << name;
+ }
+
+
+ // Returns true if the type is a user-defined type or the null type.
+ // While the pair, path, etc. are stored by reference, this is
+ // transparent to the user.
+ virtual bool isReference() {
+ return true;
+ }
+
+ virtual signature *getSignature() {
+ return 0;
+ }
+
+ virtual const signature *getSignature() const {
+ return 0;
+ }
+
+ virtual bool primitive() {
+ return false;
+ }
+
+ bool isError() const { return kind == ty_error; }
+ bool isNotError() const { return !isError(); }
+
+ // The following are only used by the overloaded type, but it is so common
+ // to test for an overloaded type then iterate over its types, that this
+ // allows the code:
+ // if (t->isOverloaded()) {
+ // for (ty_iterator i = t->begin(); i != t->end(); ++i) {
+ // ...
+ // }
+ // }
+ // For speed reasons, only begin has an assert to test if t is overloaded.
+ bool isOverloaded() const {
+ return kind == ty_overloaded;
+ }
+ bool isNotOverloaded() const { return !isOverloaded(); }
+ ty_iterator begin();
+ ty_iterator end();
+
+ // If a default initializer is not stored in the environment, the abstract
+ // syntax asks the type if it has a "default" default initializer, by calling
+ // this method.
+ virtual trans::access *initializer() {
+ return 0;
+ }
+
+ // If a cast function is not stored in the environment, ask the type itself.
+ // This handles null->record casting, and the like. The caster is used as a
+ // callback to the environment for casts of subtypes.
+ virtual trans::access *castTo(ty *, caster &) {
+ return 0;
+ }
+
+ // Just checks if a cast is possible.
+ virtual bool castable(ty *target, caster &c) {
+ return castTo(target, c);
+ }
+
+ // For pair's x and y, and array's length, this is a special type of
+ // "field".
+ // In actually, it returns a function which takes the object as its
+ // parameter and returns the necessary result.
+ // These should not have public permission, as modifying them would
+ // have strange results.
+ virtual trans::varEntry *virtualField(symbol, signature *) {
+ return 0;
+ }
+
+ // varGetType for virtual fields.
+ // Unless you are using functions for virtual fields, the base implementation
+ // should work fine.
+ virtual ty *virtualFieldGetType(symbol id);
+
+#if 0
+ // Returns the type. In case of functions, return the equivalent type
+ // but with no default values for parameters.
+ virtual ty *stripDefaults()
+ {
+ return this;
+ }
+#endif
+
+ // Returns true if the other type is equivalent to this one.
+ // The general function equivalent should be preferably used, as it properly
+ // handles overloaded type comparisons.
+ virtual bool equiv(const ty *other) const
+ {
+ return this==other;
+ }
+
+
+ // Returns a number for the type for use in a hash table. Equivalent types
+ // must yield the same number.
+ virtual size_t hash() const = 0;
+};
+
+class primitiveTy : public ty {
+public:
+ primitiveTy(ty_kind kind)
+ : ty(kind) {}
+
+ bool primitive() {
+ return true;
+ }
+
+ bool isReference() {
+ return false;
+ }
+
+ ty *virtualFieldGetType(symbol );
+ trans::varEntry *virtualField(symbol, signature *);
+
+ bool equiv(const ty *other) const
+ {
+ return this->kind==other->kind;
+ }
+
+ size_t hash() const {
+ return (size_t)kind + 47;
+ }
+};
+
+class nullTy : public primitiveTy {
+public:
+ nullTy()
+ : primitiveTy(ty_null) {}
+
+ bool isReference() {
+ return true;
+ }
+
+ trans::access *castTo(ty *target, caster &);
+
+ size_t hash() const {
+ return (size_t)kind + 47;
+ }
+};
+
+// Ostream output, just defer to print.
+inline ostream& operator<< (ostream& out, const ty& t)
+{ t.print(out); return out; }
+
+struct array : public ty {
+ ty *celltype;
+ ty *pushtype;
+ ty *poptype;
+ ty *appendtype;
+ ty *inserttype;
+ ty *deletetype;
+
+ array(ty *celltype)
+ : ty(ty_array), celltype(celltype), pushtype(0), poptype(0),
+ appendtype(0), inserttype(0), deletetype(0) {}
+
+ virtual bool isReference() {
+ return true;
+ }
+
+ bool equiv(const ty *other) const {
+ return other->kind==ty_array &&
+ equivalent(this->celltype,((array *)other)->celltype);
+ }
+
+ size_t hash() const {
+ return 1007 * celltype->hash();
+ }
+
+ Int depth() {
+ if (array *cell=dynamic_cast<array *>(celltype))
+ return cell->depth() + 1;
+ else
+ return 1;
+ }
+
+ void print(ostream& out) const
+ { out << *celltype << "[]"; }
+
+ ty *pushType();
+ ty *popType();
+ ty *appendType();
+ ty *insertType();
+ ty *deleteType();
+
+ // Initialize to an empty array by default.
+ trans::access *initializer();
+
+ // NOTE: General vectorization of casts would be here.
+
+ // Add length and push as virtual fields.
+ ty *virtualFieldGetType(symbol id);
+ trans::varEntry *virtualField(symbol id, signature *sig);
+};
+
+/* Base types */
+#define PRIMITIVE(name,Name,asyName) \
+ ty *prim##Name(); \
+ ty *name##Array(); \
+ ty *name##Array2(); \
+ ty *name##Array3();
+#define PRIMERROR
+#include "primitives.h"
+#undef PRIMERROR
+#undef PRIMITIVE
+
+ty *primNull();
+
+
+struct formal {
+ ty *t;
+ symbol name;
+ bool defval;
+ bool Explicit;
+
+ formal(ty *t,
+ symbol name=symbol::nullsym,
+ bool optional=false,
+ bool Explicit=false)
+ : t(t), name(name),
+ defval(optional), Explicit(Explicit) {}
+
+ // string->symbol translation is costly if done too many times. This
+ // constructor has been disabled to make this cost more visible to the
+ // programmer.
+#if 0
+ formal(ty *t,
+ const char *name,
+ bool optional=false,
+ bool Explicit=false)
+ : t(t), name(symbol::trans(name)),
+ defval(optional ? absyntax::Default : 0), Explicit(Explicit) {}
+#endif
+
+ friend ostream& operator<< (ostream& out, const formal& f);
+};
+
+bool equivalent(const formal& f1, const formal& f2);
+bool argumentEquivalent(const formal &f1, const formal& f2);
+
+typedef mem::vector<formal> formal_vector;
+
+// Holds the parameters of a function and if they have default values
+// (only applicable in some cases).
+struct signature : public gc {
+ formal_vector formals;
+
+ // The number of keyword-only formals. These formals always come after the
+ // regular formals.
+ size_t numKeywordOnly;
+
+ // Formal for the rest parameter. If there is no rest parameter, then the
+ // type is null.
+ formal rest;
+
+ bool isOpen;
+
+ signature()
+ : numKeywordOnly(0), rest(0), isOpen(false)
+ {}
+
+ static const struct OPEN_t {} OPEN;
+
+ explicit signature(OPEN_t) : numKeywordOnly(0), rest(0), isOpen(true) {}
+
+ signature(signature &sig)
+ : formals(sig.formals), numKeywordOnly(sig.numKeywordOnly),
+ rest(sig.rest), isOpen(sig.isOpen)
+ {}
+
+ virtual ~signature() {}
+
+ void add(formal f) {
+ formals.push_back(f);
+ }
+
+ void addKeywordOnly(formal f) {
+ add(f);
+ ++numKeywordOnly;
+ }
+
+ void addRest(formal f) {
+ rest=f;
+ }
+
+ bool hasRest() const {
+ return rest.t;
+ }
+ size_t getNumFormals() const {
+ return rest.t ? formals.size() + 1 : formals.size();
+ }
+
+ formal& getFormal(size_t n) {
+ assert(n < formals.size());
+ return formals[n];
+ }
+ const formal& getFormal(size_t n) const {
+ assert(n < formals.size());
+ return formals[n];
+ }
+
+ formal& getRest() {
+ return rest;
+ }
+ const formal& getRest() const {
+ return rest;
+ }
+
+ bool formalIsKeywordOnly(size_t n) const
+ {
+ assert(n < formals.size());
+ return n >= formals.size() - numKeywordOnly;
+ }
+
+ friend ostream& operator<< (ostream& out, const signature& s);
+
+ friend bool equivalent(const signature *s1, const signature *s2);
+
+ // Check if a signature of argument types (as opposed to formal parameters)
+ // are equivalent. Here, the arguments, if named, must have the same names,
+ // and (for simplicity) no overloaded arguments are allowed.
+ friend bool argumentEquivalent(const signature *s1, const signature *s2);
+#if 0
+ friend bool castable(signature *target, signature *source);
+ friend Int numFormalsMatch(signature *s1, signature *s2);
+#endif
+
+ size_t hash() const;
+};
+
+struct function : public ty {
+ ty *result;
+ signature sig;
+
+ function(ty *result)
+ : ty(ty_function), result(result) {}
+ function(ty *result, signature::OPEN_t)
+ : ty(ty_function), result(result), sig(signature::OPEN) {}
+ function(ty *result, signature *sig)
+ : ty(ty_function), result(result), sig(*sig) {}
+ function(ty *result, formal f1)
+ : ty(ty_function), result(result) {
+ add(f1);
+ }
+ function(ty *result, formal f1, formal f2)
+ : ty(ty_function), result(result) {
+ add(f1);
+ add(f2);
+ }
+ function(ty *result, formal f1, formal f2, formal f3)
+ : ty(ty_function), result(result) {
+ add(f1);
+ add(f2);
+ add(f3);
+ }
+ function(ty *result, formal f1, formal f2, formal f3, formal f4)
+ : ty(ty_function), result(result) {
+ add(f1);
+ add(f2);
+ add(f3);
+ add(f4);
+ }
+ virtual ~function() {}
+
+ void add(formal f) {
+ sig.add(f);
+ }
+
+ void addRest(formal f) {
+ sig.addRest(f);
+ }
+
+ virtual bool isReference() {
+ return true;
+ }
+
+ bool equiv(const ty *other) const
+ {
+ if (other->kind==ty_function) {
+ function *that=(function *)other;
+ return equivalent(this->result,that->result) &&
+ equivalent(&this->sig,&that->sig);
+ }
+ else return false;
+ }
+
+ size_t hash() const {
+ return sig.hash()*0x1231+result->hash();
+ }
+
+ void print(ostream& out) const
+ { out << *result << sig; }
+
+ void printVar (ostream& out, string name) const {
+ result->printVar(out,name);
+ out << sig;
+ }
+
+ ty *getResult() {
+ return result;
+ }
+
+ signature *getSignature() {
+ return &sig;
+ }
+
+ const signature *getSignature() const {
+ return &sig;
+ }
+
+#if 0
+ ty *stripDefaults();
+#endif
+
+ // Initialized to null.
+ trans::access *initializer();
+};
+
+// This is used in getType expressions when an overloaded variable is accessed.
+class overloaded : public ty {
+public:
+ ty_vector sub;
+
+ // Warning: The venv endScope routine relies heavily on the current
+ // implementation of overloaded.
+public:
+ overloaded()
+ : ty(ty_overloaded) {}
+ overloaded(ty *t)
+ : ty(ty_overloaded) { add(t); }
+ virtual ~overloaded() {}
+
+ bool equiv(const ty *other) const
+ {
+ for(ty_vector::const_iterator i=sub.begin();i!=sub.end();++i)
+ if (equivalent(*i,other))
+ return true;
+ return false;
+ }
+
+ size_t hash() const {
+ // Overloaded types should not be hashed.
+ assert(False);
+ return 0;
+ }
+
+ void add(ty *t) {
+ if (t->kind == ty_overloaded) {
+ overloaded *ot = (overloaded *)t;
+ copy(ot->sub.begin(), ot->sub.end(),
+ inserter(this->sub, this->sub.end()));
+ }
+ else
+ sub.push_back(t);
+ }
+
+ // Only add a type distinct from the ones currently in the overloaded type.
+ // If special is false, just the distinct signatures are added.
+ void addDistinct(ty *t, bool special=false);
+
+ // If there are less than two overloaded types, the type isn't really
+ // overloaded. This gives a more appropriate type in this case.
+ ty *simplify() {
+ switch (sub.size()) {
+ case 0:
+ return 0;
+ case 1: {
+ return sub.front();
+ }
+ default:
+ return new overloaded(*this);
+ }
+ }
+
+ // Returns the signature-less type of the set.
+ ty *signatureless();
+
+ // True if one of the subtypes is castable.
+ bool castable(ty *target, caster &c);
+
+ size_t size() const { return sub.size(); }
+
+ // Use default printing for now.
+};
+
+inline ty_iterator ty::begin() {
+ assert(this->isOverloaded());
+ return ((overloaded *)this)->sub.begin();
+}
+inline ty_iterator ty::end() {
+ return ((overloaded *)this)->sub.end();
+}
+
+// This is used to encapsulate iteration over the subtypes of an overloaded
+// type. The base method need only be implemented to handle non-overloaded
+// types.
+class collector {
+public:
+ virtual ~collector() {}
+ virtual ty *base(ty *target, ty *source) = 0;
+
+ virtual ty *collect(ty *target, ty *source) {
+ if (overloaded *o=dynamic_cast<overloaded *>(target)) {
+ ty_vector &sub=o->sub;
+
+ overloaded *oo=new overloaded;
+ for(ty_vector::iterator x = sub.begin(); x != sub.end(); ++x) {
+ types::ty *t=collect(*x, source);
+ if (t)
+ oo->add(t);
+ }
+
+ return oo->simplify();
+ }
+ else if (overloaded *o=dynamic_cast<overloaded *>(source)) {
+ ty_vector &sub=o->sub;
+
+ overloaded *oo=new overloaded;
+ for(ty_vector::iterator y = sub.begin(); y != sub.end(); ++y) {
+ // NOTE: A possible speed optimization would be to replace this with a
+ // call to base(), but this is only correct if we can guarantee that an
+ // overloaded type has no overloaded sub-types.
+ types::ty *t=collect(target, *y);
+ if (t)
+ oo->add(t);
+ }
+
+ return oo->simplify();
+ }
+ else
+ return base(target, source);
+ }
+};
+
+class tester {
+public:
+ virtual ~tester() {}
+ virtual bool base(ty *target, ty *source) = 0;
+
+ virtual bool test(ty *target, ty *source) {
+ if (overloaded *o=dynamic_cast<overloaded *>(target)) {
+ ty_vector &sub=o->sub;
+
+ for(ty_vector::iterator x = sub.begin(); x != sub.end(); ++x)
+ if (test(*x, source))
+ return true;
+
+ return false;
+ }
+ else if (overloaded *o=dynamic_cast<overloaded *>(source)) {
+ ty_vector &sub=o->sub;
+
+ for(ty_vector::iterator y = sub.begin(); y != sub.end(); ++y)
+ if (base(target, *y))
+ return true;
+
+ return false;
+ }
+ else
+ return base(target, source);
+ }
+};
+
+} // namespace types
+
+GC_DECLARE_PTRFREE(types::primitiveTy);
+GC_DECLARE_PTRFREE(types::nullTy);
+
+#endif