72
|
1 module dmd.DotIdExp;
|
|
2
|
|
3 import dmd.Expression;
|
|
4 import dmd.Identifier;
|
|
5 import dmd.IntegerExp;
|
|
6 import dmd.Type;
|
|
7 import dmd.TY;
|
|
8 import dmd.ScopeExp;
|
|
9 import dmd.StringExp;
|
|
10 import dmd.PtrExp;
|
|
11 import dmd.TypePointer;
|
|
12 import dmd.Dsymbol;
|
|
13 import dmd.EnumMember;
|
|
14 import dmd.VarDeclaration;
|
|
15 import dmd.ThisExp;
|
|
16 import dmd.DotVarExp;
|
|
17 import dmd.VarExp;
|
|
18 import dmd.CommaExp;
|
|
19 import dmd.FuncDeclaration;
|
|
20 import dmd.OverloadSet;
|
|
21 import dmd.OverExp;
|
|
22 import dmd.TypeExp;
|
|
23 import dmd.TupleDeclaration;
|
|
24 import dmd.ScopeDsymbol;
|
|
25 import dmd.Import;
|
|
26 import dmd.Id;
|
|
27 import dmd.TupleExp;
|
|
28 import dmd.ArrayTypes;
|
|
29 import dmd.UnaExp;
|
|
30 import dmd.OutBuffer;
|
|
31 import dmd.Loc;
|
|
32 import dmd.Scope;
|
|
33 import dmd.TOK;
|
|
34 import dmd.HdrGenState;
|
|
35 import dmd.ClassDeclaration;
|
|
36 import dmd.StructDeclaration;
|
|
37 import dmd.AggregateDeclaration;
|
|
38 import dmd.DotExp;
|
|
39 import dmd.Global;
|
|
40 import dmd.IdentifierExp;
|
|
41 import dmd.CallExp;
|
|
42 import dmd.PREC;
|
|
43
|
|
44 import dmd.expression.Util;
|
|
45
|
0
|
46 class DotIdExp : UnaExp
|
|
47 {
|
|
48 Identifier ident;
|
|
49
|
|
50 this(Loc loc, Expression e, Identifier ident)
|
|
51 {
|
72
|
52 super(loc, TOK.TOKdot, DotIdExp.sizeof, e);
|
0
|
53 this.ident = ident;
|
|
54 }
|
|
55
|
72
|
56 override Expression semantic(Scope sc)
|
0
|
57 {
|
72
|
58 Expression e;
|
|
59 Expression eleft;
|
|
60 Expression eright;
|
|
61
|
|
62 version (LOGSEMANTIC) {
|
|
63 printf("DotIdExp.semantic(this = %p, '%s')\n", this, toChars());
|
|
64 //printf("e1.op = %d, '%s'\n", e1.op, Token.toChars(e1.op));
|
|
65 }
|
|
66
|
|
67 //{ static int z; fflush(stdout); if (++z == 10) *(char*)0=0; }
|
|
68
|
|
69 static if (false) {
|
|
70 /* Don't do semantic analysis if we'll be converting
|
|
71 * it to a string.
|
|
72 */
|
|
73 if (ident == Id.stringof)
|
|
74 {
|
|
75 char *s = e1.toChars();
|
|
76 e = new StringExp(loc, s, strlen(s), 'c');
|
|
77 e = e.semantic(sc);
|
|
78 return e;
|
|
79 }
|
|
80 }
|
|
81
|
|
82 /* Special case: rewrite this.id and super.id
|
|
83 * to be classtype.id and baseclasstype.id
|
|
84 * if we have no this pointer.
|
|
85 */
|
|
86 if ((e1.op == TOK.TOKthis || e1.op == TOK.TOKsuper) && !hasThis(sc))
|
|
87 {
|
|
88 ClassDeclaration cd;
|
|
89 StructDeclaration sd;
|
|
90 AggregateDeclaration ad;
|
|
91
|
|
92 ad = sc.getStructClassScope();
|
|
93 if (ad)
|
|
94 {
|
|
95 cd = ad.isClassDeclaration();
|
|
96 if (cd)
|
|
97 {
|
|
98 if (e1.op == TOK.TOKthis)
|
|
99 {
|
|
100 e = typeDotIdExp(loc, cd.type, ident);
|
|
101 return e.semantic(sc);
|
|
102 }
|
|
103 else if (cd.baseClass && e1.op == TOK.TOKsuper)
|
|
104 {
|
|
105 e = typeDotIdExp(loc, cd.baseClass.type, ident);
|
|
106 return e.semantic(sc);
|
|
107 }
|
|
108 }
|
|
109 else
|
|
110 {
|
|
111 sd = ad.isStructDeclaration();
|
|
112 if (sd)
|
|
113 {
|
|
114 if (e1.op == TOK.TOKthis)
|
|
115 {
|
|
116 e = typeDotIdExp(loc, sd.type, ident);
|
|
117 return e.semantic(sc);
|
|
118 }
|
|
119 }
|
|
120 }
|
|
121 }
|
|
122 }
|
|
123
|
|
124 UnaExp.semantic(sc);
|
|
125
|
|
126 if (e1.op == TOK.TOKdotexp)
|
|
127 {
|
|
128 DotExp de = cast(DotExp)e1;
|
|
129 eleft = de.e1;
|
|
130 eright = de.e2;
|
|
131 }
|
|
132 else
|
|
133 {
|
|
134 e1 = resolveProperties(sc, e1);
|
|
135 eleft = null;
|
|
136 eright = e1;
|
|
137 }
|
|
138
|
|
139 version (DMDV2) {
|
|
140 if (e1.op == TOK.TOKtuple && ident == Id.offsetof)
|
|
141 {
|
|
142 /* 'distribute' the .offsetof to each of the tuple elements.
|
|
143 */
|
|
144 TupleExp te = cast(TupleExp)e1;
|
|
145 Expressions exps = new Expressions();
|
|
146 exps.setDim(te.exps.dim);
|
|
147 for (int i = 0; i < exps.dim; i++)
|
|
148 {
|
|
149 Expression ee = cast(Expression)te.exps.data[i];
|
|
150 ee = ee.semantic(sc);
|
|
151 ee = new DotIdExp(e.loc, ee, Id.offsetof);
|
|
152 exps.data[i] = cast(void*)ee;
|
|
153 }
|
|
154 e = new TupleExp(loc, exps);
|
|
155 e = e.semantic(sc);
|
|
156 return e;
|
|
157 }
|
|
158 }
|
|
159
|
|
160 if (e1.op == TOK.TOKtuple && ident == Id.length)
|
|
161 {
|
|
162 TupleExp te = cast(TupleExp)e1;
|
|
163 e = new IntegerExp(loc, te.exps.dim, Type.tsize_t);
|
|
164 return e;
|
|
165 }
|
|
166
|
|
167 if (e1.op == TOK.TOKdottd)
|
|
168 {
|
|
169 error("template %s does not have property %s", e1.toChars(), ident.toChars());
|
|
170 return e1;
|
|
171 }
|
|
172
|
|
173 if (!e1.type)
|
|
174 {
|
|
175 error("expression %s does not have property %s", e1.toChars(), ident.toChars());
|
|
176 return e1;
|
|
177 }
|
|
178
|
|
179 Type t1b = e1.type.toBasetype();
|
|
180
|
|
181 if (eright.op == TOK.TOKimport) // also used for template alias's
|
|
182 {
|
|
183 ScopeExp ie = cast(ScopeExp)eright;
|
|
184
|
|
185 /* Disable access to another module's private imports.
|
|
186 * The check for 'is sds our current module' is because
|
|
187 * the current module should have access to its own imports.
|
|
188 */
|
|
189 Dsymbol s = ie.sds.search(loc, ident,
|
|
190 (ie.sds.isModule() && ie.sds != sc.module_) ? 1 : 0);
|
|
191 if (s)
|
|
192 {
|
|
193 s = s.toAlias();
|
|
194 checkDeprecated(sc, s);
|
|
195
|
|
196 EnumMember em = s.isEnumMember();
|
|
197 if (em)
|
|
198 {
|
|
199 e = em.value;
|
|
200 e = e.semantic(sc);
|
|
201 return e;
|
|
202 }
|
|
203
|
|
204 VarDeclaration v = s.isVarDeclaration();
|
|
205 if (v)
|
|
206 {
|
|
207 //printf("DotIdExp. Identifier '%s' is a variable, type '%s'\n", toChars(), v.type.toChars());
|
|
208 if (v.inuse)
|
|
209 {
|
|
210 error("circular reference to '%s'", v.toChars());
|
|
211 type = Type.tint32;
|
|
212 return this;
|
|
213 }
|
|
214 type = v.type;
|
|
215 if (v.needThis())
|
|
216 {
|
|
217 if (!eleft)
|
|
218 eleft = new ThisExp(loc);
|
|
219 e = new DotVarExp(loc, eleft, v);
|
|
220 e = e.semantic(sc);
|
|
221 }
|
|
222 else
|
|
223 {
|
|
224 e = new VarExp(loc, v);
|
|
225 if (eleft)
|
|
226 {
|
|
227 e = new CommaExp(loc, eleft, e);
|
|
228 e.type = v.type;
|
|
229 }
|
|
230 }
|
|
231 return e.deref();
|
|
232 }
|
|
233
|
|
234 FuncDeclaration f = s.isFuncDeclaration();
|
|
235 if (f)
|
|
236 {
|
|
237 //printf("it's a function\n");
|
|
238 if (f.needThis())
|
|
239 {
|
|
240 if (!eleft)
|
|
241 eleft = new ThisExp(loc);
|
|
242 e = new DotVarExp(loc, eleft, f);
|
|
243 e = e.semantic(sc);
|
|
244 }
|
|
245 else
|
|
246 {
|
|
247 e = new VarExp(loc, f, 1);
|
|
248 if (eleft)
|
|
249 { e = new CommaExp(loc, eleft, e);
|
|
250 e.type = f.type;
|
|
251 }
|
|
252 }
|
|
253 return e;
|
|
254 }
|
|
255 version (DMDV2) {
|
|
256 OverloadSet o = s.isOverloadSet();
|
|
257 if (o)
|
|
258 {
|
|
259 //printf("'%s' is an overload set\n", o.toChars());
|
|
260 return new OverExp(o);
|
|
261 }
|
|
262 }
|
|
263
|
|
264 Type t = s.getType();
|
|
265 if (t)
|
|
266 {
|
|
267 return new TypeExp(loc, t);
|
|
268 }
|
|
269
|
|
270 TupleDeclaration tup = s.isTupleDeclaration();
|
|
271 if (tup)
|
|
272 {
|
|
273 if (eleft)
|
|
274 error("cannot have e.tuple");
|
|
275 e = new TupleExp(loc, tup);
|
|
276 e = e.semantic(sc);
|
|
277 return e;
|
|
278 }
|
|
279
|
|
280 ScopeDsymbol sds = s.isScopeDsymbol();
|
|
281 if (sds)
|
|
282 {
|
|
283 //printf("it's a ScopeDsymbol\n");
|
|
284 e = new ScopeExp(loc, sds);
|
|
285 e = e.semantic(sc);
|
|
286 if (eleft)
|
|
287 e = new DotExp(loc, eleft, e);
|
|
288 return e;
|
|
289 }
|
|
290
|
|
291 Import imp = s.isImport();
|
|
292 if (imp)
|
|
293 {
|
|
294 ScopeExp iee = new ScopeExp(loc, imp.pkg);
|
|
295 return iee.semantic(sc);
|
|
296 }
|
|
297
|
|
298 // BUG: handle other cases like in IdentifierExp.semantic()
|
|
299 version (DEBUG) {
|
|
300 printf("s = '%s', kind = '%s'\n", s.toChars(), s.kind());
|
|
301 }
|
|
302 assert(0);
|
|
303 }
|
|
304 else if (ident is Id.stringof_)
|
|
305 {
|
|
306 string ss = ie.toChars();
|
|
307 e = new StringExp(loc, ss, 'c');
|
|
308 e = e.semantic(sc);
|
|
309 return e;
|
|
310 }
|
|
311 error("undefined identifier %s", toChars());
|
|
312 type = Type.tvoid;
|
|
313 return this;
|
|
314 }
|
|
315 else if (t1b.ty == TY.Tpointer &&
|
|
316 ident !is Id.init_ && ident !is Id.__sizeof &&
|
|
317 ident !is Id.alignof_ && ident !is Id.offsetof &&
|
|
318 ident !is Id.mangleof_ && ident !is Id.stringof_)
|
|
319 { /* Rewrite:
|
|
320 * p.ident
|
|
321 * as:
|
|
322 * (*p).ident
|
|
323 */
|
|
324 e = new PtrExp(loc, e1);
|
|
325 e.type = (cast(TypePointer)t1b).next;
|
|
326 return e.type.dotExp(sc, e, ident);
|
|
327 }
|
|
328 ///version (DMDV2) {
|
|
329 else if (t1b.ty == TY.Tarray ||
|
|
330 t1b.ty == TY.Tsarray ||
|
|
331 t1b.ty == TY.Taarray)
|
|
332 {
|
|
333 /* If ident is not a valid property, rewrite:
|
|
334 * e1.ident
|
|
335 * as:
|
|
336 * .ident(e1)
|
|
337 */
|
|
338 uint errors = global.errors;
|
|
339 global.gag++;
|
|
340 e = e1.type.dotExp(sc, e1, ident);
|
|
341 global.gag--;
|
|
342 if (errors != global.errors) // if failed to find the property
|
|
343 {
|
|
344 global.errors = errors;
|
|
345 e = new DotIdExp(loc, new IdentifierExp(loc, Id.empty), ident);
|
|
346 e = new CallExp(loc, e, e1);
|
|
347 }
|
|
348 e = e.semantic(sc);
|
|
349 return e;
|
|
350 }
|
|
351 ///}
|
|
352 else
|
|
353 {
|
|
354 e = e1.type.dotExp(sc, e1, ident);
|
|
355 e = e.semantic(sc);
|
|
356 return e;
|
0
|
357 }
|
|
358 }
|
|
359
|
72
|
360 override void toCBuffer(OutBuffer buf, HdrGenState* hgs)
|
0
|
361 {
|
72
|
362 //printf("DotIdExp.toCBuffer()\n");
|
|
363 expToCBuffer(buf, hgs, e1, PREC.PREC_primary);
|
|
364 buf.writeByte('.');
|
0
|
365 buf.writestring(ident.toChars());
|
|
366 }
|
|
367
|
72
|
368 override void dump(int i)
|
0
|
369 {
|
|
370 assert(false);
|
|
371 }
|
|
372 }
|
|
373
|