1 /*****
2  * env.cc
3  * Andy Hammerlindl 2002/6/20
4  *
5  * Keeps track of the namespaces of variables and types when traversing
6  * the abstract syntax.
7  *****/
8 
9 #include "env.h"
10 #include "record.h"
11 #include "genv.h"
12 #include "builtin.h"
13 
14 using namespace types;
15 
16 namespace trans {
17 
18 // Instances of this class are passed to types::ty objects so that they can call
19 // back to env when checking casting of subtypes.
20 class envCaster : public caster {
21   protoenv &e;
22   symbol name;
23 public:
envCaster(protoenv & e,symbol name)24   envCaster(protoenv &e, symbol name)
25     : e(e), name(name) {}
26 
operator ()(ty * target,ty * source)27   access *operator() (ty *target, ty *source) {
28     return e.lookupCast(target, source, name);
29   }
30 
castable(ty * target,ty * source)31   bool castable(ty *target, ty *source) {
32     return e.castable(target, source, name);
33   }
34 };
35 
baseLookupCast(ty * target,ty * source,symbol name)36 access *protoenv::baseLookupCast(ty *target, ty *source, symbol name) {
37   static identAccess id;
38 
39   assert(target->kind != ty_overloaded &&
40          source->kind != ty_overloaded);
41 
42   // If errors already exist, don't report more.  This may, however, cause
43   // problems with resoving the signature of an overloaded function.  The
44   // abstract syntax should check if any of the parameters had an error before
45   // finding the signature.
46   if (target->kind == ty_error || source->kind == ty_error)
47     return &id;
48   else if (equivalent(target,source))
49     return &id;
50   else {
51     varEntry *v=lookupVarByType(name,new function(target,source));
52     return v ? v->getLocation() : 0;
53   }
54 }
55 
lookupCast(ty * target,ty * source,symbol name)56 access *protoenv::lookupCast(ty *target, ty *source, symbol name) {
57   access *a=baseLookupCast(target, source, name);
58   if (a)
59     return a;
60 
61   envCaster ec(*this, name);
62   return source->castTo(target, ec);
63 }
64 
castable(ty * target,ty * source,symbol name)65 bool protoenv::castable(ty *target, ty *source, symbol name) {
66   struct castTester : public tester {
67     protoenv &e;
68     symbol name;
69 
70     castTester(protoenv &e, symbol name)
71       : e(e), name(name) {}
72 
73     bool base(ty *t, ty *s) {
74       access *a=e.baseLookupCast(t, s, name);
75       if (a)
76         return true;
77 
78       envCaster ec(e, name);
79       return s->castable(t, ec);
80     }
81   };
82 
83   castTester ct(*this, name);
84   return ct.test(target,source);
85 }
86 
fastCastable(ty * target,ty * source)87 bool protoenv::fastCastable(ty *target, ty *source) {
88   assert(target->kind != types::ty_overloaded);
89   assert(target->kind != types::ty_error);
90   assert(source->kind != types::ty_error);
91 
92   // To avoid memory allocation, fill one static variable with new parameters
93   // in each call.
94   // Warning: This is not re-entrant if asy ever goes multi-threaded.
95   static types::function castFunc(primVoid(), primVoid());
96   castFunc.result = target;
97 
98   if (source->kind == types::ty_overloaded) {
99     bool result = false;
100     types::ty_vector& v = ((overloaded *)source)->sub;
101     for (size_t i = 0; i < v.size(); ++i) {
102       castFunc.sig.formals[0].t = v[i];
103       if (lookupVarByType(symbol::castsym, &castFunc)) {
104         result = true;
105         break;
106       }
107     }
108     //assert(result == castable(target, source, symbol::castsym));
109     //cout << "fc OVERLOADED " << (result ? "CAST" : "FAIL") << endl;
110     return result;
111   }
112   //else cout << "fc SIMPLE" << endl;
113 
114   // Don't test for equivalent, as that is already done by the castScore
115   // code.  Assert disabled for speed.
116 #if 0
117   assert(!equivalent(target, source));
118 #endif
119 
120   castFunc.sig.formals[0].t = source;
121 
122   if (lookupVarByType(symbol::castsym, &castFunc))
123     return true;
124 
125   // Test for generic casts of null.  This should be moved to a types.h
126   // routine.
127   return source->kind == ty_null && target->isReference();
128 }
129 
fastLookupCast(ty * target,ty * source)130 access *protoenv::fastLookupCast(ty *target, ty *source) {
131   assert(target->kind != types::ty_overloaded);
132   assert(target->kind != types::ty_error);
133   assert(source->kind != types::ty_overloaded);
134   assert(source->kind != types::ty_error);
135 
136   // Warning: This is not re-entrant.
137   static types::function castFunc(primVoid(), primVoid());
138   castFunc.result = target;
139   castFunc.sig.formals[0].t = source;
140 
141   varEntry *ve = lookupVarByType(symbol::castsym, &castFunc);
142   if (ve)
143     return ve->getLocation();
144 
145   // Fall back on slow routine.
146   return lookupCast(target, source, symbol::castsym);
147 }
148 
149 
castTarget(ty * target,ty * source,symbol name)150 ty *protoenv::castTarget(ty *target, ty *source, symbol name) {
151   struct resolver : public collector {
152     protoenv &e;
153     symbol name;
154 
155     resolver(protoenv &e, symbol name)
156       : e(e), name(name) {}
157 
158     types::ty *base(types::ty *target, types::ty *source) {
159       return e.castable(target, source, name) ? target : 0;
160     }
161   };
162 
163   resolver r(*this, name);
164   return r.collect(target, source);
165 }
166 
castSource(ty * target,ty * source,symbol name)167 ty *protoenv::castSource(ty *target, ty *source, symbol name) {
168   struct resolver : public collector {
169     protoenv &e;
170     symbol name;
171 
172     resolver(protoenv &e, symbol name)
173       : e(e), name(name) {}
174 
175     types::ty *base(types::ty *target, types::ty *source) {
176       return e.castable(target, source, name) ? source : 0;
177     }
178   };
179 
180   resolver r(*this, name);
181   return r.collect(target, source);
182 }
183 
addArrayOps(array * a)184 void protoenv::addArrayOps(array *a)
185 {
186   trans::addArrayOps(ve, a);
187 }
188 
addRecordOps(record * r)189 void protoenv::addRecordOps(record *r)
190 {
191   trans::addRecordOps(ve, r);
192 }
193 
addFunctionOps(function * f)194 void protoenv::addFunctionOps(function *f)
195 {
196   trans::addFunctionOps(ve, f);
197 }
198 
env(genv & ge)199 env::env(genv &ge)
200   : protoenv(venv::file_env_tag()), ge(ge)
201 {
202   // NOTE: May want to make this initial environment into a "builtin" module,
203   // and then import the builtin module.
204   base_tenv(te);
205   base_venv(ve);
206 }
207 
~env()208 env::~env()
209 {
210 }
211 
getModule(symbol id,string filename)212 record *env::getModule(symbol id, string filename)
213 {
214   return ge.getModule(id, filename);
215 }
216 
217 }
218