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