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