Mercurial > projects > ddmd
annotate dmd/Expression.d @ 178:e3afd1303184
Many small bugs fixed
Made all classes derive from TObject to detect memory leaks (functionality is disabled for now)
Began work on overriding backend memory allocations (to avoid memory leaks)
author | korDen |
---|---|
date | Sun, 17 Oct 2010 07:42:00 +0400 |
parents | 7171e6ea651d |
children | cd48cb899aee |
rev | line source |
---|---|
0 | 1 module dmd.Expression; |
2 | |
114 | 3 import dmd.common; |
0 | 4 import dmd.Loc; |
5 import dmd.TOK; | |
130
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
126
diff
changeset
|
6 import dmd.Parameter; |
12
832f71e6f96c
*Exp and *AssignExp arrayOp implementation added (might be a bit incomplete)
korDen
parents:
4
diff
changeset
|
7 import dmd.IdentifierExp; |
0 | 8 import dmd.Type; |
9 import dmd.WANT; | |
10 import dmd.Scope; | |
84
be2ab491772e
Expressions -> Vector!Expression
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
73
diff
changeset
|
11 import dmd.Array; |
0 | 12 import dmd.ArrayTypes; |
13 import dmd.OutBuffer; | |
14 import dmd.HdrGenState; | |
15 import dmd.MATCH; | |
16 import dmd.IntRange; | |
17 import dmd.Dsymbol; | |
18 import dmd.FuncDeclaration; | |
19 import dmd.InterState; | |
20 import dmd.InlineCostState; | |
21 import dmd.InlineDoState; | |
22 import dmd.InlineScanState; | |
23 import dmd.Identifier; | |
24 import dmd.IRState; | |
25 import dmd.DotIdExp; | |
26 import dmd.TypeExp; | |
27 import dmd.DYNCAST; | |
28 import dmd.TY; | |
29 import dmd.CallExp; | |
30 import dmd.VarExp; | |
31 import dmd.STC; | |
32 import dmd.TemplateInstance; | |
33 import dmd.CommaExp; | |
34 import dmd.NullExp; | |
35 import dmd.AddrExp; | |
55 | 36 import dmd.LINK; |
37 import dmd.FuncExp; | |
38 import dmd.ReturnStatement; | |
39 import dmd.Statement; | |
40 import dmd.FuncLiteralDeclaration; | |
41 import dmd.TypeFunction; | |
0 | 42 import dmd.ErrorExp; |
43 import dmd.TypeStruct; | |
44 import dmd.CastExp; | |
45 import dmd.Global; | |
93
df6d0f967680
implemented a whole bunch of methods to make phobos 2.035 compile
Trass3r
parents:
84
diff
changeset
|
46 import dmd.GlobalExpressions; |
0 | 47 import dmd.Token; |
48 import dmd.TypeClass; | |
49 import dmd.PtrExp; | |
50 import dmd.TypeSArray; | |
51 import dmd.TypeReference; | |
52 import dmd.Util; | |
53 import dmd.Complex; | |
54 | |
55 import dmd.backend.elem; | |
141 | 56 import dmd.backend.Util; |
0 | 57 import dmd.backend.dt_t; |
58 | |
4 | 59 import core.memory; |
2 | 60 |
0 | 61 import std.stdio : writef; |
62 | |
63 import std.conv; | |
64 | |
65 /* Things like: | |
66 * int.size | |
67 * foo.size | |
68 * (foo).size | |
69 * cast(foo).size | |
70 */ | |
71 | |
72 Expression typeDotIdExp(Loc loc, Type type, Identifier ident) | |
73 { | |
74 return new DotIdExp(loc, new TypeExp(loc, type), ident); | |
75 } | |
76 | |
77 /***************************************** | |
78 * Determine if 'this' is available. | |
79 * If it is, return the FuncDeclaration that has it. | |
80 */ | |
81 | |
82 FuncDeclaration hasThis(Scope sc) | |
83 { | |
84 FuncDeclaration fd; | |
85 FuncDeclaration fdthis; | |
86 | |
87 //printf("hasThis()\n"); | |
88 fdthis = sc.parent.isFuncDeclaration(); | |
89 //printf("fdthis = %p, '%s'\n", fdthis, fdthis ? fdthis.toChars() : ""); | |
90 | |
91 // Go upwards until we find the enclosing member function | |
92 fd = fdthis; | |
93 while (1) | |
94 { | |
95 if (!fd) | |
96 { | |
97 goto Lno; | |
98 } | |
99 if (!fd.isNested()) | |
100 break; | |
101 | |
102 Dsymbol parent = fd.parent; | |
103 while (parent) | |
104 { | |
105 TemplateInstance ti = parent.isTemplateInstance(); | |
106 if (ti) | |
107 parent = ti.parent; | |
108 else | |
109 break; | |
110 } | |
111 | |
112 fd = fd.parent.isFuncDeclaration(); | |
113 } | |
114 | |
115 if (!fd.isThis()) | |
116 { | |
117 //printf("test '%s'\n", fd.toChars()); | |
118 goto Lno; | |
119 } | |
120 | |
121 assert(fd.vthis); | |
122 return fd; | |
123 | |
124 Lno: | |
125 return null; // don't have 'this' available | |
126 } | |
127 | |
128 /*************************************** | |
129 * Pull out any properties. | |
130 */ | |
131 Expression resolveProperties(Scope sc, Expression e) | |
132 { | |
133 //printf("resolveProperties(%s)\n", e.toChars()); | |
134 if (e.type) | |
135 { | |
136 Type t = e.type.toBasetype(); | |
137 | |
138 if (t.ty == TY.Tfunction || e.op == TOK.TOKoverloadset) | |
139 { | |
109 | 140 static if(false) |
141 { | |
142 if (t.ty == Tfunction && !(cast(TypeFunction)t).isproperty) | |
143 error(e.loc, "not a property %s\n", e.toChars()); | |
144 } | |
0 | 145 e = new CallExp(e.loc, e); |
146 e = e.semantic(sc); | |
147 } | |
148 | |
149 /* Look for e being a lazy parameter; rewrite as delegate call | |
150 */ | |
151 else if (e.op == TOK.TOKvar) | |
152 { VarExp ve = cast(VarExp)e; | |
153 | |
154 if (ve.var.storage_class & STC.STClazy) | |
155 { | |
156 e = new CallExp(e.loc, e); | |
157 e = e.semantic(sc); | |
158 } | |
159 } | |
160 | |
161 else if (e.op == TOK.TOKdotexp) | |
162 { | |
163 e.error("expression has no value"); | |
164 } | |
165 } | |
166 else if (e.op == TOK.TOKdottd) | |
167 { | |
168 e = new CallExp(e.loc, e); | |
169 e = e.semantic(sc); | |
170 } | |
171 | |
172 return e; | |
173 } | |
174 | |
95 | 175 void indent(int indent) |
176 { | |
177 foreach (i; 0 .. indent) | |
178 writef(" "); | |
179 } | |
180 | |
181 string type_print(Type type) | |
182 { | |
183 return type ? type.toChars() : "null"; | |
184 } | |
185 | |
178 | 186 import dmd.TObject; |
187 | |
188 class Expression : TObject | |
0 | 189 { |
190 Loc loc; // file location | |
191 TOK op; // handy to minimize use of dynamic_cast | |
192 Type type; // !=null means that semantic() has been run | |
193 int size; // # of bytes in Expression so we can copy() it | |
194 | |
195 this(Loc loc, TOK op, int size) | |
196 { | |
178 | 197 register(); |
0 | 198 this.loc = loc; |
199 //writef("Expression.Expression(op = %d %s) this = %p\n", op, to!(string)(op), this); | |
200 this.op = op; | |
201 this.size = size; | |
202 type = null; | |
203 } | |
204 | |
45 | 205 bool equals(Object o) |
0 | 206 { |
207 return this is o; | |
208 } | |
209 | |
210 /********************************* | |
211 * Does *not* do a deep copy. | |
212 */ | |
178 | 213 Expression copy() |
0 | 214 { |
178 | 215 return cloneThis(this); |
0 | 216 } |
217 | |
218 Expression syntaxCopy() | |
219 { | |
220 //printf("Expression::syntaxCopy()\n"); | |
221 //dump(0); | |
222 return copy(); | |
223 } | |
224 | |
225 Expression semantic(Scope sc) | |
226 { | |
227 version (LOGSEMANTIC) { | |
228 printf("Expression.semantic() %s\n", toChars()); | |
229 } | |
230 if (type) | |
231 type = type.semantic(loc, sc); | |
232 else | |
233 type = Type.tvoid; | |
234 return this; | |
235 } | |
236 | |
237 Expression trySemantic(Scope sc) | |
238 { | |
239 uint errors = global.errors; | |
240 global.gag++; | |
241 Expression e = semantic(sc); | |
242 global.gag--; | |
243 if (errors != global.errors) | |
244 { | |
245 global.errors = errors; | |
246 e = null; | |
247 } | |
248 return e; | |
249 } | |
250 | |
251 DYNCAST dyncast() { return DYNCAST.DYNCAST_EXPRESSION; } // kludge for template.isExpression() | |
252 | |
253 void print() | |
254 { | |
255 assert(false); | |
256 } | |
257 | |
258 string toChars() | |
259 { | |
260 scope OutBuffer buf = new OutBuffer(); | |
261 HdrGenState hgs; | |
262 | |
263 toCBuffer(buf, &hgs); | |
264 return buf.toChars(); | |
265 } | |
266 | |
95 | 267 void dump(int i) |
0 | 268 { |
95 | 269 indent(i); |
270 writef("%p %s type=%s\n", this, Token.toChars(op), type_print(type)); | |
0 | 271 } |
272 | |
273 void error(T...)(string format, T t) | |
274 { | |
275 .error(loc, format, t); | |
276 } | |
277 | |
278 void warning(T...)(string formar, T t) | |
279 { | |
280 .warning(loc, format, t); | |
281 } | |
282 | |
283 void rvalue() | |
284 { | |
285 if (type && type.toBasetype().ty == TY.Tvoid) | |
286 { | |
287 error("expression %s is void and has no value", toChars()); | |
288 static if (false) { | |
289 dump(0); | |
290 halt(); | |
291 } | |
292 type = Type.terror; | |
293 } | |
294 } | |
295 | |
296 static Expression combine(Expression e1, Expression e2) | |
297 { | |
298 if (e1) | |
299 { | |
300 if (e2) | |
301 { | |
302 e1 = new CommaExp(e1.loc, e1, e2); | |
303 e1.type = e2.type; | |
304 } | |
305 } | |
306 else | |
307 { | |
308 e1 = e2; | |
309 } | |
310 | |
311 return e1; | |
312 } | |
313 | |
314 static Expressions arraySyntaxCopy(Expressions exps) | |
315 { | |
316 Expressions a = null; | |
317 | |
318 if (exps) | |
319 { | |
320 a = new Expressions(); | |
321 a.setDim(exps.dim); | |
84
be2ab491772e
Expressions -> Vector!Expression
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
73
diff
changeset
|
322 for (size_t i = 0; i < a.dim; i++) |
0 | 323 { |
84
be2ab491772e
Expressions -> Vector!Expression
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
73
diff
changeset
|
324 auto e = exps[i]; |
0 | 325 |
326 e = e.syntaxCopy(); | |
84
be2ab491772e
Expressions -> Vector!Expression
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
73
diff
changeset
|
327 a[i] = e; |
0 | 328 } |
329 } | |
330 return a; | |
331 } | |
332 | |
333 ulong toInteger() | |
334 { | |
93
df6d0f967680
implemented a whole bunch of methods to make phobos 2.035 compile
Trass3r
parents:
84
diff
changeset
|
335 //printf("Expression %s\n", Token.toChars(op)); |
df6d0f967680
implemented a whole bunch of methods to make phobos 2.035 compile
Trass3r
parents:
84
diff
changeset
|
336 error("Integer constant expression expected instead of %s", toChars()); |
df6d0f967680
implemented a whole bunch of methods to make phobos 2.035 compile
Trass3r
parents:
84
diff
changeset
|
337 return 0; |
0 | 338 } |
339 | |
340 ulong toUInteger() | |
341 { | |
342 //printf("Expression %s\n", Token.toChars(op)); | |
343 return cast(ulong)toInteger(); | |
344 } | |
345 | |
346 real toReal() | |
347 { | |
93
df6d0f967680
implemented a whole bunch of methods to make phobos 2.035 compile
Trass3r
parents:
84
diff
changeset
|
348 error("Floating point constant expression expected instead of %s", toChars()); |
df6d0f967680
implemented a whole bunch of methods to make phobos 2.035 compile
Trass3r
parents:
84
diff
changeset
|
349 return 0; |
0 | 350 } |
351 | |
352 real toImaginary() | |
353 { | |
93
df6d0f967680
implemented a whole bunch of methods to make phobos 2.035 compile
Trass3r
parents:
84
diff
changeset
|
354 error("Floating point constant expression expected instead of %s", toChars()); |
df6d0f967680
implemented a whole bunch of methods to make phobos 2.035 compile
Trass3r
parents:
84
diff
changeset
|
355 return 0; |
0 | 356 } |
357 | |
358 Complex!(real) toComplex() | |
359 { | |
93
df6d0f967680
implemented a whole bunch of methods to make phobos 2.035 compile
Trass3r
parents:
84
diff
changeset
|
360 error("Floating point constant expression expected instead of %s", toChars()); |
df6d0f967680
implemented a whole bunch of methods to make phobos 2.035 compile
Trass3r
parents:
84
diff
changeset
|
361 return Complex!real(0); |
0 | 362 } |
363 | |
364 void toCBuffer(OutBuffer buf, HdrGenState* hgs) | |
365 { | |
366 buf.writestring(Token.toChars(op)); | |
367 } | |
368 | |
369 void toMangleBuffer(OutBuffer buf) | |
370 { | |
55 | 371 error("expression %s is not a valid template value argument", toChars()); |
0 | 372 assert(false); |
55 | 373 version (DEBUG) { |
374 dump(0); | |
375 } | |
0 | 376 } |
377 | |
66 | 378 /*************************************** |
379 * Return !=0 if expression is an lvalue. | |
380 */ | |
0 | 381 int isLvalue() |
382 { | |
66 | 383 return 0; |
0 | 384 } |
93
df6d0f967680
implemented a whole bunch of methods to make phobos 2.035 compile
Trass3r
parents:
84
diff
changeset
|
385 |
df6d0f967680
implemented a whole bunch of methods to make phobos 2.035 compile
Trass3r
parents:
84
diff
changeset
|
386 /******************************* |
df6d0f967680
implemented a whole bunch of methods to make phobos 2.035 compile
Trass3r
parents:
84
diff
changeset
|
387 * Give error if we're not an lvalue. |
df6d0f967680
implemented a whole bunch of methods to make phobos 2.035 compile
Trass3r
parents:
84
diff
changeset
|
388 * If we can, convert expression to be an lvalue. |
df6d0f967680
implemented a whole bunch of methods to make phobos 2.035 compile
Trass3r
parents:
84
diff
changeset
|
389 */ |
df6d0f967680
implemented a whole bunch of methods to make phobos 2.035 compile
Trass3r
parents:
84
diff
changeset
|
390 Expression toLvalue(Scope sc, Expression e) |
0 | 391 { |
93
df6d0f967680
implemented a whole bunch of methods to make phobos 2.035 compile
Trass3r
parents:
84
diff
changeset
|
392 if (!e) |
df6d0f967680
implemented a whole bunch of methods to make phobos 2.035 compile
Trass3r
parents:
84
diff
changeset
|
393 e = this; |
df6d0f967680
implemented a whole bunch of methods to make phobos 2.035 compile
Trass3r
parents:
84
diff
changeset
|
394 else if (!loc.filename) |
df6d0f967680
implemented a whole bunch of methods to make phobos 2.035 compile
Trass3r
parents:
84
diff
changeset
|
395 loc = e.loc; |
df6d0f967680
implemented a whole bunch of methods to make phobos 2.035 compile
Trass3r
parents:
84
diff
changeset
|
396 error("%s is not an lvalue", e.toChars()); |
df6d0f967680
implemented a whole bunch of methods to make phobos 2.035 compile
Trass3r
parents:
84
diff
changeset
|
397 return this; |
0 | 398 } |
93
df6d0f967680
implemented a whole bunch of methods to make phobos 2.035 compile
Trass3r
parents:
84
diff
changeset
|
399 |
0 | 400 Expression modifiableLvalue(Scope sc, Expression e) |
401 { | |
402 //printf("Expression::modifiableLvalue() %s, type = %s\n", toChars(), type.toChars()); | |
403 | |
404 // See if this expression is a modifiable lvalue (i.e. not const) | |
405 version (DMDV2) { | |
406 if (type && (!type.isMutable() || !type.isAssignable())) | |
407 error("%s is not mutable", e.toChars()); | |
408 } | |
409 return toLvalue(sc, e); | |
410 } | |
411 | |
412 /************************************** | |
413 * Do an implicit cast. | |
414 * Issue error if it can't be done. | |
415 */ | |
416 Expression implicitCastTo(Scope sc, Type t) | |
417 { | |
418 //printf("Expression.implicitCastTo(%s of type %s) => %s\n", toChars(), type.toChars(), t.toChars()); | |
419 | |
420 MATCH match = implicitConvTo(t); | |
421 if (match) | |
422 { | |
423 TY tyfrom = type.toBasetype().ty; | |
424 TY tyto = t.toBasetype().ty; | |
425 | |
426 version (DMDV1) { | |
427 if (global.params.warnings && | |
428 Type.impcnvWarn[tyfrom][tyto] && | |
429 op != TOKint64) | |
430 { | |
431 Expression e = optimize(WANT.WANTflags | WANT.WANTvalue); | |
432 | |
433 if (e.op == TOK.TOKint64) | |
434 return e.implicitCastTo(sc, t); | |
435 if (tyfrom == Tint32 && (op == TOKadd || op == TOKmin || op == TOKand || op == TOKor || op == TOKxor)) | |
436 { | |
437 /* This is really only a semi-kludge fix, | |
438 * we really should look at the operands of op | |
439 * and see if they are narrower types. | |
440 * For example, b=b|b and b=b|7 and s=b+b should be allowed, | |
441 * but b=b|i should be an error. | |
442 */ | |
443 ; | |
444 } | |
445 else | |
446 { | |
447 warning("implicit conversion of expression (%s) of type %s to %s can cause loss of data", toChars(), type.toChars(), t.toChars()); | |
448 } | |
449 } | |
450 } | |
451 version (DMDV2) { | |
452 if (match == MATCH.MATCHconst && t == type.constOf()) | |
453 { | |
454 Expression e = copy(); | |
455 e.type = t; | |
456 return e; | |
457 } | |
458 } | |
459 return castTo(sc, t); | |
460 } | |
461 | |
462 Expression e = optimize(WANT.WANTflags | WANT.WANTvalue); | |
463 if (e != this) | |
464 return e.implicitCastTo(sc, t); | |
465 | |
466 static if (false) { | |
467 printf("ty = %d\n", type.ty); | |
468 print(); | |
469 type.print(); | |
470 printf("to:\n"); | |
471 t.print(); | |
472 printf("%p %p type: %s to: %s\n", type.deco, t.deco, type.deco, t.deco); | |
473 //printf("%p %p %p\n", type.nextOf().arrayOf(), type, t); | |
474 fflush(stdout); | |
475 } | |
476 if (!t.deco) { | |
477 /* Can happen with: | |
478 * enum E { One } | |
479 * class A | |
480 * { static void fork(EDG dg) { dg(E.One); } | |
481 * alias void delegate(E) EDG; | |
482 * } | |
483 * Should eventually make it work. | |
484 */ | |
485 error("forward reference to type %s", t.toChars()); | |
486 } else if (t.reliesOnTident()) { | |
487 error("forward reference to type %s", t.reliesOnTident().toChars()); | |
488 } | |
489 | |
490 error("cannot implicitly convert expression (%s) of type %s to %s", toChars(), type.toChars(), t.toChars()); | |
491 return castTo(sc, t); | |
492 } | |
493 | |
494 /******************************************* | |
495 * Return !=0 if we can implicitly convert this to type t. | |
496 * Don't do the actual cast. | |
497 */ | |
498 MATCH implicitConvTo(Type t) | |
499 { | |
500 static if (false) { | |
501 printf("Expression.implicitConvTo(this=%s, type=%s, t=%s)\n", | |
502 toChars(), type.toChars(), t.toChars()); | |
503 } | |
504 //static int nest; if (++nest == 10) halt(); | |
505 if (!type) | |
506 { | |
507 error("%s is not an expression", toChars()); | |
508 type = Type.terror; | |
509 } | |
510 Expression e = optimize(WANT.WANTvalue | WANT.WANTflags); | |
511 if (e.type == t) | |
512 return MATCH.MATCHexact; | |
513 if (e != this) | |
514 { | |
515 //printf("\toptimized to %s of type %s\n", e.toChars(), e.type.toChars()); | |
516 return e.implicitConvTo(t); | |
517 } | |
518 MATCH match = type.implicitConvTo(t); | |
519 if (match != MATCH.MATCHnomatch) | |
520 return match; | |
521 | |
522 /* See if we can do integral narrowing conversions | |
523 */ | |
524 if (type.isintegral() && t.isintegral() && | |
525 type.isTypeBasic() && t.isTypeBasic()) | |
526 { | |
527 IntRange ir = getIntRange(); | |
528 if (ir.imax <= t.sizemask()) | |
529 return MATCH.MATCHconvert; | |
530 } | |
531 | |
532 static if (false) { | |
533 Type tb = t.toBasetype(); | |
534 if (tb.ty == Tdelegate) | |
535 { | |
536 TypeDelegate td = cast(TypeDelegate)tb; | |
537 TypeFunction tf = cast(TypeFunction)td.nextOf(); | |
538 | |
539 if (!tf.varargs && !(tf.arguments && tf.arguments.dim)) | |
540 { | |
541 match = type.implicitConvTo(tf.nextOf()); | |
542 if (match) | |
543 return match; | |
544 if (tf.nextOf().toBasetype().ty == Tvoid) | |
545 return MATCH.MATCHconvert; | |
546 } | |
547 } | |
548 } | |
549 return MATCH.MATCHnomatch; | |
550 } | |
551 | |
552 IntRange getIntRange() | |
553 { | |
53 | 554 IntRange ir; |
555 ir.imin = 0; | |
73 | 556 if (type.isintegral()) |
557 ir.imax = type.sizemask(); | |
558 else | |
559 ir.imax = 0xFFFFFFFFFFFFFFFFUL; // assume the worst | |
560 | |
53 | 561 return ir; |
0 | 562 } |
563 | |
564 /************************************** | |
565 * Do an explicit cast. | |
566 */ | |
567 Expression castTo(Scope sc, Type t) | |
568 { | |
569 //printf("Expression.castTo(this=%s, t=%s)\n", toChars(), t.toChars()); | |
570 static if (false) { | |
571 writef("Expression.castTo(this=%s, type=%s, t=%s)\n", | |
572 toChars(), type.toChars(), t.toChars()); | |
573 } | |
574 if (type is t) | |
575 return this; | |
576 Expression e = this; | |
577 Type tb = t.toBasetype(); | |
578 Type typeb = type.toBasetype(); | |
579 if (tb != typeb) | |
580 { | |
581 // Do (type *) cast of (type [dim]) | |
582 if (tb.ty == TY.Tpointer && typeb.ty == TY.Tsarray | |
583 ) | |
584 { | |
585 //printf("Converting [dim] to *\n"); | |
586 | |
587 if (typeb.size(loc) == 0) | |
588 e = new NullExp(loc); | |
589 else | |
590 e = new AddrExp(loc, e); | |
591 } | |
592 else { | |
593 static if (false) { | |
594 if (tb.ty == Tdelegate && type.ty != Tdelegate) | |
595 { | |
596 TypeDelegate td = cast(TypeDelegate)tb; | |
597 TypeFunction tf = cast(TypeFunction)td.nextOf(); | |
598 return toDelegate(sc, tf.nextOf()); | |
599 } | |
600 } | |
601 if (typeb.ty == TY.Tstruct) | |
602 { | |
603 TypeStruct ts = cast(TypeStruct)typeb; | |
604 if (!(tb.ty == TY.Tstruct && ts.sym == (cast(TypeStruct)tb).sym) && | |
605 ts.sym.aliasthis) | |
606 { /* Forward the cast to our alias this member, rewrite to: | |
607 * cast(to)e1.aliasthis | |
608 */ | |
609 Expression e1 = new DotIdExp(loc, this, ts.sym.aliasthis.ident); | |
610 Expression e2 = new CastExp(loc, e1, tb); | |
611 e2 = e2.semantic(sc); | |
612 return e2; | |
613 } | |
614 } | |
615 else if (typeb.ty == TY.Tclass) | |
616 { | |
617 TypeClass ts = cast(TypeClass)typeb; | |
618 if (tb.ty != TY.Tclass && ts.sym.aliasthis) | |
619 { /* Forward the cast to our alias this member, rewrite to: | |
620 * cast(to)e1.aliasthis | |
621 */ | |
622 Expression e1 = new DotIdExp(loc, this, ts.sym.aliasthis.ident); | |
623 Expression e2 = new CastExp(loc, e1, tb); | |
624 e2 = e2.semantic(sc); | |
625 return e2; | |
626 } | |
627 } | |
628 e = new CastExp(loc, e, tb); | |
629 } | |
630 } | |
631 else | |
632 { | |
633 e = e.copy(); // because of COW for assignment to e.type | |
634 } | |
635 | |
636 assert(e != this); | |
637 e.type = t; | |
638 //printf("Returning: %s\n", e.toChars()); | |
639 return e; | |
640 } | |
641 | |
642 /************************************ | |
643 * Detect cases where pointers to the stack can 'escape' the | |
644 * lifetime of the stack frame. | |
645 */ | |
646 void checkEscape() | |
647 { | |
648 } | |
649 | |
135 | 650 void checkEscapeRef() |
651 { | |
652 } | |
653 | |
0 | 654 void checkScalar() |
655 { | |
656 if (!type.isscalar()) | |
657 error("'%s' is not a scalar, it is a %s", toChars(), type.toChars()); | |
658 | |
659 rvalue(); | |
660 } | |
661 | |
662 void checkNoBool() | |
663 { | |
664 if (type.toBasetype().ty == TY.Tbool) | |
665 error("operation not allowed on bool '%s'", toChars()); | |
666 } | |
667 | |
668 Expression checkIntegral() | |
669 { | |
670 if (!type.isintegral()) | |
671 { | |
672 error("'%s' is not of integral type, it is a %s", toChars(), type.toChars()); | |
673 return new ErrorExp(); | |
674 } | |
675 | |
676 rvalue(); | |
677 return this; | |
678 } | |
679 | |
680 Expression checkArithmetic() | |
681 { | |
682 if (!type.isintegral() && !type.isfloating()) | |
683 { | |
684 error("'%s' is not of arithmetic type, it is a %s", toChars(), type.toChars()); | |
685 return new ErrorExp(); | |
686 } | |
687 | |
688 rvalue(); | |
689 return this; | |
690 } | |
691 | |
692 void checkDeprecated(Scope sc, Dsymbol s) | |
693 { | |
694 s.checkDeprecated(loc, sc); | |
695 } | |
696 | |
697 void checkPurity(Scope sc, FuncDeclaration f) | |
698 { | |
699 static if (true) { | |
700 if (sc.func) | |
701 { | |
130
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
126
diff
changeset
|
702 /* Given: |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
126
diff
changeset
|
703 * void f() |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
126
diff
changeset
|
704 * { pure void g() |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
126
diff
changeset
|
705 * { |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
126
diff
changeset
|
706 * void h() |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
126
diff
changeset
|
707 * { |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
126
diff
changeset
|
708 * void i() { } |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
126
diff
changeset
|
709 * } |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
126
diff
changeset
|
710 * } |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
126
diff
changeset
|
711 * } |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
126
diff
changeset
|
712 * g() can call h() but not f() |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
126
diff
changeset
|
713 * i() can call h() and g() but not f() |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
126
diff
changeset
|
714 */ |
0 | 715 FuncDeclaration outerfunc = sc.func; |
716 while (outerfunc.toParent2() && outerfunc.toParent2().isFuncDeclaration()) | |
717 { | |
718 outerfunc = outerfunc.toParent2().isFuncDeclaration(); | |
719 } | |
130
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
126
diff
changeset
|
720 if (outerfunc.isPure() && !sc.intypeof && (!f.isNested() && !f.isPure())) |
0 | 721 error("pure function '%s' cannot call impure function '%s'\n", |
722 sc.func.toChars(), f.toChars()); | |
723 } | |
724 } else { | |
725 if (sc.func && sc.func.isPure() && !sc.intypeof && !f.isPure()) | |
726 error("pure function '%s' cannot call impure function '%s'\n", | |
727 sc.func.toChars(), .toChars()); | |
728 } | |
729 } | |
130
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
126
diff
changeset
|
730 |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
126
diff
changeset
|
731 void checkSafety(Scope sc, FuncDeclaration f) |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
126
diff
changeset
|
732 { |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
126
diff
changeset
|
733 if (sc.func && sc.func.isSafe() && !sc.intypeof && |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
126
diff
changeset
|
734 !f.isSafe() && !f.isTrusted()) |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
126
diff
changeset
|
735 error("safe function '%s' cannot call system function '%s'\n", |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
126
diff
changeset
|
736 sc.func.toChars(), f.toChars()); |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
126
diff
changeset
|
737 } |
0 | 738 |
739 /***************************** | |
740 * Check that expression can be tested for true or false. | |
741 */ | |
742 Expression checkToBoolean() | |
743 { | |
744 // Default is 'yes' - do nothing | |
745 | |
746 debug { | |
747 if (!type) | |
748 dump(0); | |
749 } | |
750 | |
751 if (!type.checkBoolean()) | |
752 { | |
753 error("expression %s of type %s does not have a boolean value", toChars(), type.toChars()); | |
754 } | |
755 | |
756 return this; | |
757 } | |
758 | |
759 Expression checkToPointer() | |
760 { | |
109 | 761 //writef("Expression::checkToPointer()\n"); |
762 Expression e = this; | |
0 | 763 |
109 | 764 version(SARRAYVALUE) {} else |
765 { | |
0 | 766 // If C static array, convert to pointer |
109 | 767 Type tb = type.toBasetype(); |
0 | 768 if (tb.ty == Tsarray) |
769 { | |
770 TypeSArray ts = cast(TypeSArray)tb; | |
771 if (ts.size(loc) == 0) | |
772 e = new NullExp(loc); | |
773 else | |
774 e = new AddrExp(loc, this); | |
775 e.type = ts.next.pointerTo(); | |
776 } | |
109 | 777 } |
0 | 778 return e; |
779 } | |
780 | |
781 Expression addressOf(Scope sc) | |
782 { | |
783 //printf("Expression::addressOf()\n"); | |
784 Expression e = toLvalue(sc, null); | |
785 e = new AddrExp(loc, e); | |
786 e.type = type.pointerTo(); | |
787 return e; | |
788 } | |
789 | |
790 /****************************** | |
791 * If this is a reference, dereference it. | |
792 */ | |
793 Expression deref() | |
794 { | |
795 //printf("Expression::deref()\n"); | |
73 | 796 // type could be null if forward referencing an 'auto' variable |
797 if (type && type.ty == Treference) | |
798 { | |
0 | 799 Expression e = new PtrExp(loc, this); |
800 e.type = (cast(TypeReference)type).next; | |
801 return e; | |
802 } | |
803 return this; | |
804 } | |
805 | |
806 /*********************************** | |
807 * Do integral promotions (convertchk). | |
808 * Don't convert <array of> to <pointer to> | |
809 */ | |
810 Expression integralPromotions(Scope sc) | |
811 { | |
812 Expression e = this; | |
813 | |
814 //printf("integralPromotions %s %s\n", e.toChars(), e.type.toChars()); | |
815 switch (type.toBasetype().ty) | |
816 { | |
817 case TY.Tvoid: | |
818 error("void has no value"); | |
819 break; | |
820 | |
821 case TY.Tint8: | |
822 case TY.Tuns8: | |
823 case TY.Tint16: | |
824 case TY.Tuns16: | |
825 case TY.Tbit: | |
826 case TY.Tbool: | |
827 case TY.Tchar: | |
828 case TY.Twchar: | |
829 e = e.castTo(sc, Type.tint32); | |
830 break; | |
831 | |
832 case TY.Tdchar: | |
833 e = e.castTo(sc, Type.tuns32); | |
834 break; | |
835 default: | |
836 break; /// | |
837 } | |
838 return e; | |
839 } | |
840 | |
55 | 841 /******************************************** |
842 * Convert from expression to delegate that returns the expression, | |
843 * i.e. convert: | |
844 * expr | |
845 * to: | |
846 * t delegate() { return expr; } | |
847 */ | |
0 | 848 Expression toDelegate(Scope sc, Type t) |
849 { | |
55 | 850 //printf("Expression.toDelegate(t = %s) %s\n", t.toChars(), toChars()); |
851 TypeFunction tf = new TypeFunction(null, t, 0, LINKd); | |
852 FuncLiteralDeclaration fld = new FuncLiteralDeclaration(loc, loc, tf, TOKdelegate, null); | |
853 Expression e; | |
854 static if (true) { | |
855 sc = sc.push(); | |
856 sc.parent = fld; // set current function to be the delegate | |
857 e = this; | |
858 e.scanForNestedRef(sc); | |
859 sc = sc.pop(); | |
860 } else { | |
861 e = this.syntaxCopy(); | |
862 } | |
863 Statement s = new ReturnStatement(loc, e); | |
864 fld.fbody = s; | |
865 e = new FuncExp(loc, fld); | |
866 e = e.semantic(sc); | |
867 return e; | |
0 | 868 } |
869 | |
870 void scanForNestedRef(Scope sc) | |
871 { | |
55 | 872 //printf("Expression.scanForNestedRef(%s)\n", toChars()); |
0 | 873 } |
874 | |
875 Expression optimize(int result) | |
876 { | |
877 //printf("Expression.optimize(result = x%x) %s\n", result, toChars()); | |
878 return this; | |
879 } | |
880 | |
93
df6d0f967680
implemented a whole bunch of methods to make phobos 2.035 compile
Trass3r
parents:
84
diff
changeset
|
881 Expression interpret(InterState istate) |
0 | 882 { |
93
df6d0f967680
implemented a whole bunch of methods to make phobos 2.035 compile
Trass3r
parents:
84
diff
changeset
|
883 version(LOG) |
df6d0f967680
implemented a whole bunch of methods to make phobos 2.035 compile
Trass3r
parents:
84
diff
changeset
|
884 { |
df6d0f967680
implemented a whole bunch of methods to make phobos 2.035 compile
Trass3r
parents:
84
diff
changeset
|
885 writef("Expression::interpret() %s\n", toChars()); |
df6d0f967680
implemented a whole bunch of methods to make phobos 2.035 compile
Trass3r
parents:
84
diff
changeset
|
886 writef("type = %s\n", type.toChars()); |
df6d0f967680
implemented a whole bunch of methods to make phobos 2.035 compile
Trass3r
parents:
84
diff
changeset
|
887 dump(0); |
df6d0f967680
implemented a whole bunch of methods to make phobos 2.035 compile
Trass3r
parents:
84
diff
changeset
|
888 } |
df6d0f967680
implemented a whole bunch of methods to make phobos 2.035 compile
Trass3r
parents:
84
diff
changeset
|
889 error("Cannot interpret %s at compile time", toChars()); |
df6d0f967680
implemented a whole bunch of methods to make phobos 2.035 compile
Trass3r
parents:
84
diff
changeset
|
890 return EXP_CANT_INTERPRET; |
0 | 891 } |
892 | |
893 int isConst() | |
894 { | |
895 //printf("Expression::isConst(): %s\n", toChars()); | |
896 return 0; | |
897 } | |
898 | |
899 /******************************** | |
900 * Does this expression statically evaluate to a boolean TRUE or FALSE? | |
901 */ | |
902 bool isBool(bool result) | |
903 { | |
904 return false; | |
905 } | |
906 | |
141 | 907 /******************************** |
908 * Does this expression result in either a 1 or a 0? | |
909 */ | |
910 int isBit() | |
0 | 911 { |
141 | 912 return false; |
0 | 913 } |
914 | |
915 /******************************** | |
916 * Check for expressions that have no use. | |
917 * Input: | |
918 * flag 0 not going to use the result, so issue error message if no | |
919 * side effects | |
920 * 1 the result of the expression is used, but still check | |
921 * for useless subexpressions | |
922 * 2 do not issue error messages, just return !=0 if expression | |
923 * has side effects | |
924 */ | |
925 bool checkSideEffect(int flag) | |
926 { | |
927 if (flag == 0) | |
928 { | |
73 | 929 if (op == TOKerror) |
930 { | |
931 // Error should have already been printed | |
932 } | |
933 else if (op == TOKimport) | |
0 | 934 error("%s has no effect", toChars()); |
935 else | |
936 error("%s has no effect in expression (%s)", | |
937 | |
938 Token.toChars(op), toChars()); | |
939 } | |
940 | |
941 return false; | |
942 } | |
943 | |
944 bool canThrow() | |
945 { | |
946 version (DMDV2) { | |
947 return false; | |
948 } else { | |
949 return true; | |
950 } | |
951 } | |
952 | |
130
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
126
diff
changeset
|
953 /**************************************** |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
126
diff
changeset
|
954 * Resolve __LINE__ and __FILE__ to loc. |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
126
diff
changeset
|
955 */ |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
126
diff
changeset
|
956 Expression resolveLoc(Loc loc, Scope sc) |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
126
diff
changeset
|
957 { |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
126
diff
changeset
|
958 return this; |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
126
diff
changeset
|
959 } |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
126
diff
changeset
|
960 |
0 | 961 int inlineCost(InlineCostState* ics) |
962 { | |
963 return 1; | |
964 } | |
965 | |
966 Expression doInline(InlineDoState ids) | |
967 { | |
968 //printf("Expression.doInline(%s): %s\n", Token.toChars(op), toChars()); | |
969 return copy(); | |
970 } | |
971 | |
972 Expression inlineScan(InlineScanState* iss) | |
973 { | |
974 return this; | |
975 } | |
976 | |
977 /*********************************** | |
978 * Determine if operands of binary op can be reversed | |
979 * to fit operator overload. | |
980 */ | |
981 | |
982 // For operator overloading | |
983 bool isCommutative() | |
984 { | |
985 return false; // default is no reverse | |
986 } | |
987 | |
988 /*********************************** | |
989 * Get Identifier for operator overload. | |
990 */ | |
991 Identifier opId() | |
992 { | |
993 assert(false); | |
994 } | |
995 | |
996 /*********************************** | |
997 * Get Identifier for reverse operator overload, | |
998 * null if not supported for this operator. | |
999 */ | |
1000 Identifier opId_r() | |
1001 { | |
1002 return null; | |
1003 } | |
1004 | |
1005 // For array ops | |
12
832f71e6f96c
*Exp and *AssignExp arrayOp implementation added (might be a bit incomplete)
korDen
parents:
4
diff
changeset
|
1006 /****************************************** |
832f71e6f96c
*Exp and *AssignExp arrayOp implementation added (might be a bit incomplete)
korDen
parents:
4
diff
changeset
|
1007 * Construct the identifier for the array operation function, |
832f71e6f96c
*Exp and *AssignExp arrayOp implementation added (might be a bit incomplete)
korDen
parents:
4
diff
changeset
|
1008 * and build the argument list to pass to it. |
832f71e6f96c
*Exp and *AssignExp arrayOp implementation added (might be a bit incomplete)
korDen
parents:
4
diff
changeset
|
1009 */ |
0 | 1010 void buildArrayIdent(OutBuffer buf, Expressions arguments) |
1011 { | |
12
832f71e6f96c
*Exp and *AssignExp arrayOp implementation added (might be a bit incomplete)
korDen
parents:
4
diff
changeset
|
1012 buf.writestring("Exp"); |
84
be2ab491772e
Expressions -> Vector!Expression
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
73
diff
changeset
|
1013 arguments.shift(this); |
0 | 1014 } |
1015 | |
130
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
126
diff
changeset
|
1016 Expression buildArrayLoop(Parameters fparams) |
0 | 1017 { |
12
832f71e6f96c
*Exp and *AssignExp arrayOp implementation added (might be a bit incomplete)
korDen
parents:
4
diff
changeset
|
1018 Identifier id = Identifier.generateId("c", fparams.dim); |
130
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
126
diff
changeset
|
1019 auto param = new Parameter(STC.STCundefined, type, id, null); |
126
1765f3ef917d
ClassDeclarations, Arguments -> Vector
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
1020 fparams.shift(param); |
12
832f71e6f96c
*Exp and *AssignExp arrayOp implementation added (might be a bit incomplete)
korDen
parents:
4
diff
changeset
|
1021 Expression e = new IdentifierExp(Loc(0), id); |
832f71e6f96c
*Exp and *AssignExp arrayOp implementation added (might be a bit incomplete)
korDen
parents:
4
diff
changeset
|
1022 return e; |
0 | 1023 } |
95 | 1024 |
1025 /*********************************************** | |
1026 * Test if operand is a valid array op operand. | |
1027 */ | |
1028 int isArrayOperand() | |
1029 { | |
1030 //writef("Expression::isArrayOperand() %s\n", toChars()); | |
1031 if (op == TOKslice) | |
1032 return 1; | |
1033 if (type.toBasetype().ty == TY.Tarray) | |
1034 { | |
1035 switch (op) | |
1036 { | |
1037 case TOKadd: | |
1038 case TOKmin: | |
1039 case TOKmul: | |
1040 case TOKdiv: | |
1041 case TOKmod: | |
1042 case TOKxor: | |
1043 case TOKand: | |
1044 case TOKor: | |
1045 case TOKneg: | |
1046 case TOKtilde: | |
1047 return 1; | |
1048 | |
1049 default: | |
1050 break; | |
1051 } | |
1052 } | |
1053 return 0; | |
1054 } | |
1055 | |
0 | 1056 // Back end |
1057 elem* toElem(IRState* irs) | |
1058 { | |
141 | 1059 print(); |
0 | 1060 assert(false); |
141 | 1061 return null; |
0 | 1062 } |
1063 | |
1064 dt_t** toDt(dt_t** pdt) | |
1065 { | |
141 | 1066 debug |
1067 { | |
1068 writef("Expression::toDt() %d\n", op); | |
1069 dump(0); | |
1070 } | |
1071 error("non-constant expression %s", toChars()); | |
1072 pdt = dtnzeros(pdt, 1); | |
1073 return pdt; | |
0 | 1074 } |
16
5c9b78899f5d
Implemented methods for Tuples, fixed some linking issues.
Robert Clipsham <robert@octarineparrot.com>
parents:
4
diff
changeset
|
1075 } |
84
be2ab491772e
Expressions -> Vector!Expression
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
73
diff
changeset
|
1076 |
be2ab491772e
Expressions -> Vector!Expression
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
73
diff
changeset
|
1077 alias Vector!Expression Expressions; |