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