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