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