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