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