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