1 /* Digital Mars DMDScript source code.
2  * Copyright (c) 2000-2002 by Chromium Communications
3  * D version Copyright (c) 2004-2010 by Digital Mars
4  * Distributed under the Boost Software License, Version 1.0.
5  * (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6  * written by Walter Bright
7  * http://www.digitalmars.com
8  *
9  * D2 port by Dmitry Olshansky 
10  *
11  * DMDScript is implemented in the D Programming Language,
12  * http://www.digitalmars.com/d/
13  *
14  * For a C++ implementation of DMDScript, including COM support, see
15  * http://www.digitalmars.com/dscript/cppscript.html
16  */
17 
18 module dmdscript.expression;
19 
20 import std.string;
21 import std.algorithm;
22 import std.string;
23 import std.range;
24 import std.exception;
25 import std.stdio;
26 
27 import dmdscript.script;
28 import dmdscript.lexer;
29 import dmdscript.scopex;
30 import dmdscript.text;
31 import dmdscript.errmsgs;
32 import dmdscript.functiondefinition;
33 import dmdscript.irstate;
34 import dmdscript.ir;
35 import dmdscript.opcodes;
36 import dmdscript.identifier;
37 
38 /******************************** Expression **************************/
39 
40 class Expression
41 {
42     enum uint EXPRESSION_SIGNATURE = 0x3AF31E3F;
43     uint signature = EXPRESSION_SIGNATURE;
44 
45     Loc loc;                    // file location
46     TOK op;
47 
48     this(Loc loc, TOK op)
49     {
50         this.loc = loc;
51         this.op = op;
52         signature = EXPRESSION_SIGNATURE;
53     }
54 
55     invariant()
56     {
57         assert(signature == EXPRESSION_SIGNATURE);
58         assert(op != TOKreserved && op < TOKmax);
59     }
60 
61     /**************************
62      * Semantically analyze Expression.
63      * Determine types, fold constants, e
64      */
65 
66     Expression semantic(Scope *sc)
67     {
68         return this;
69     }
70 
71     override d_string toString()
72     {
73         char[] buf;
74 
75         toBuffer(buf);
76         return assumeUnique(buf);
77     }
78 
79     void toBuffer(ref char[] buf)
80     {
81         buf ~= toString();
82     }
83 
84     void checkLvalue(Scope *sc)
85     {
86         d_string buf;
87 
88         //writefln("checkLvalue(), op = %d", op);
89         if(sc.funcdef)
90         {
91             if(sc.funcdef.isAnonymous)
92                 buf = "anonymous";
93             else if(sc.funcdef.name)
94                 buf = sc.funcdef.name.toString();
95         }
96         buf ~= std..string.format("(%d) : Error: ", loc);
97         buf ~= std..string.format(errmsgtbl[ERR_CANNOT_ASSIGN_TO], toString());
98 
99         if(!sc.errinfo.message)
100         {
101             sc.errinfo.message = buf;
102             sc.errinfo.linnum = loc;
103             sc.errinfo.srcline = Lexer.locToSrcline(sc.getSource().ptr, loc);
104         }
105     }
106 
107     // Do we match for purposes of optimization?
108 
109     int match(Expression e)
110     {
111         return false;
112     }
113 
114     // Is the result of the expression guaranteed to be a boolean?
115 
116     int isBooleanResult()
117     {
118         return false;
119     }
120 
121     void toIR(IRstate *irs, uint ret)
122     {
123         writef("Expression::toIR('%s')\n", toString());
124     }
125 
126     void toLvalue(IRstate *irs, out uint base, IR *property, out int opoff)
127     {
128         base = irs.alloc(1);
129         toIR(irs, base);
130         property.index = 0;
131         opoff = 3;
132     }
133 }
134 
135 /******************************** RealExpression **************************/
136 
137 class RealExpression : Expression
138 {
139     real_t value;
140 
141     this(Loc loc, real_t value)
142     {
143         super(loc, TOKreal);
144         this.value = value;
145     }
146 
147     override d_string toString()
148     {
149         d_string buf;
150         long i;
151 
152         i = cast(long)value;
153         if(i == value)
154             buf = std..string.format("%d", i);
155         else
156             buf = std..string.format("%g", value);
157         return buf;
158     }
159 
160     override void toBuffer(ref tchar[] buf)
161     {
162         buf ~= std..string.format("%g", value);
163     }
164 
165     override void toIR(IRstate *irs, uint ret)
166     {
167         //writef("RealExpression::toIR(%g)\n", value);
168 
169         static assert(value.sizeof == 2 * uint.sizeof);
170         if(ret)
171             irs.genX(loc, IRnumber, ret, value);
172     }
173 }
174 
175 /******************************** IdentifierExpression **************************/
176 
177 class IdentifierExpression : Expression
178 {
179     Identifier *ident;
180 
181     this(Loc loc, Identifier * ident)
182     {
183         super(loc, TOKidentifier);
184         this.ident = ident;
185     }
186 
187     override Expression semantic(Scope *sc)
188     {
189         return this;
190     }
191 
192     override d_string toString()
193     {
194         return ident.toString();
195     }
196 
197     override void checkLvalue(Scope *sc)
198     {
199     }
200 
201     override int match(Expression e)
202     {
203         if(e.op != TOKidentifier)
204             return 0;
205 
206         IdentifierExpression ie = cast(IdentifierExpression)(e);
207 
208         return ident == ie.ident;
209     }
210 
211     override void toIR(IRstate *irs, uint ret)
212     {
213         Identifier* id = ident;
214 
215         assert(id.sizeof == IRstate.Op.sizeof);
216         if(ret)
217             irs.gen2(loc, IRgetscope, ret, cast(IRstate.Op)id);
218         else
219             irs.gen1(loc,IRcheckref, cast(IRstate.Op)id);
220     }
221 
222     override void toLvalue(IRstate *irs, out uint base, IR *property, out int opoff)
223     {
224         //irs.gen1(loc, IRthis, base);
225         property.id = ident;
226         opoff = 2;
227         base = ~0u;
228     }
229 }
230 
231 /******************************** ThisExpression **************************/
232 
233 class ThisExpression : Expression
234 {
235     this(Loc loc)
236     {
237         super(loc, TOKthis);
238     }
239 
240     override d_string toString()
241     {
242         return TEXT_this;
243     }
244 
245     override Expression semantic(Scope *sc)
246     {
247         return this;
248     }
249 
250     override void toIR(IRstate *irs, uint ret)
251     {
252         if(ret)
253             irs.gen1(loc, IRthis, ret);
254     }
255 }
256 
257 /******************************** NullExpression **************************/
258 
259 class NullExpression : Expression
260 {
261     this(Loc loc)
262     {
263         super(loc, TOKnull);
264     }
265 
266     override d_string toString()
267     {
268         return TEXT_null;
269     }
270 
271     override void toIR(IRstate *irs, uint ret)
272     {
273         if(ret)
274             irs.gen1(loc, IRnull, ret);
275     }
276 }
277 
278 /******************************** StringExpression **************************/
279 
280 class StringExpression : Expression
281 {
282     static import std.ascii;
283     import std.format : format;
284 
285     d_string string;
286 
287     this(Loc loc, d_string string)
288     {
289         //writefln("StringExpression('%s')", string);
290         super(loc, TOKstring);
291         this.string = string;
292     }
293 
294     override void toBuffer(ref tchar[] buf)
295     {
296         buf ~= '"';
297         foreach(dchar c; string)
298         {
299             switch(c)
300             {
301             case '"':
302                 buf ~= '\\';
303                 goto Ldefault;
304 
305             default:
306                 Ldefault:
307                 if(c & ~0xFF)
308                     buf ~= format("\\u%04x", c);
309                 else if(std.ascii.isPrintable(c))
310                     buf ~= cast(tchar)c;
311                 else
312                     buf ~= format("\\x%02x", c);
313                 break;
314             }
315         }
316         buf ~= '"';
317     }
318 
319     override void toIR(IRstate *irs, uint ret)
320     {
321         static assert((Identifier*).sizeof == IRstate.Op.sizeof);
322         if(ret)
323         {
324             auto u = cast(IRstate.Op)Identifier.build(string);
325             irs.gen2(loc, IRstring, ret, u);
326         }
327     }
328 }
329 
330 /******************************** RegExpLiteral **************************/
331 
332 class RegExpLiteral : Expression
333 {
334     d_string string;
335 
336     this(Loc loc, d_string string)
337     {
338         //writefln("RegExpLiteral('%s')", string);
339         super(loc, TOKregexp);
340         this.string = string;
341     }
342 
343     override void toBuffer(ref tchar[] buf)
344     {
345         buf ~= string;
346     }
347 
348     override void toIR(IRstate *irs, uint ret)
349     {
350         d_string pattern;
351         d_string attribute = null;
352         sizediff_t e;
353 
354         uint argc;
355         uint argv;
356         uint b;
357 
358         // Regular expression is of the form:
359         //	/pattern/attribute
360 
361         // Parse out pattern and attribute strings
362         assert(string[0] == '/');
363         e = std..string.lastIndexOf(string, '/');
364         assert(e != -1);
365         pattern = string[1 .. e];
366         argc = 1;
367         if(e + 1 < string.length)
368         {
369             attribute = string[e + 1 .. $];
370             argc++;
371         }
372 
373         // Generate new Regexp(pattern [, attribute])
374 
375         b = irs.alloc(1);
376         Identifier* re = Identifier.build(TEXT_RegExp);
377         irs.gen2(loc, IRgetscope, b, cast(IRstate.Op)re);
378         argv = irs.alloc(argc);
379         irs.gen2(loc, IRstring, argv, cast(IRstate.Op)Identifier.build(pattern));
380         if(argc == 2)
381             irs.gen2(loc, IRstring, argv + 1 * INDEX_FACTOR, cast(IRstate.Op)Identifier.build(attribute));
382         irs.gen4(loc, IRnew, ret, b, argc, argv);
383         irs.release(b, argc + 1);
384     }
385 }
386 
387 /******************************** BooleanExpression **************************/
388 
389 class BooleanExpression : Expression
390 {
391     int boolean;
392 
393     this(Loc loc, int boolean)
394     {
395         super(loc, TOKboolean);
396         this.boolean = boolean;
397     }
398 
399     override d_string toString()
400     {
401         return boolean ? "true" : "false";
402     }
403 
404     override void toBuffer(ref tchar[] buf)
405     {
406         buf ~= toString();
407     }
408 
409     override int isBooleanResult()
410     {
411         return true;
412     }
413 
414     override void toIR(IRstate *irs, uint ret)
415     {
416         if(ret)
417             irs.gen2(loc, IRboolean, ret, boolean);
418     }
419 }
420 
421 /******************************** ArrayLiteral **************************/
422 
423 class ArrayLiteral : Expression
424 {
425     Expression[] elements;
426 
427     this(Loc loc, Expression[] elements)
428     {
429         super(loc, TOKarraylit);
430         this.elements = elements;
431     }
432 
433     override Expression semantic(Scope *sc)
434     {
435         foreach(ref Expression e; elements)
436         {
437             if(e)
438                 e = e.semantic(sc);
439         }
440         return this;
441     }
442 
443     override void toBuffer(ref tchar[] buf)
444     {
445         uint i;
446 
447         buf ~= '[';
448         foreach(Expression e; elements)
449         {
450             if(i)
451                 buf ~= ',';
452             i = 1;
453             if(e)
454                 e.toBuffer(buf);
455         }
456         buf ~= ']';
457     }
458 
459     override void toIR(IRstate *irs, uint ret)
460     {
461         uint argc;
462         uint argv;
463         uint b;
464         uint v;
465 
466         b = irs.alloc(1);
467         static Identifier* ar;
468         if(!ar)
469             ar = Identifier.build(TEXT_Array);
470         irs.gen2(loc, IRgetscope, b, cast(IRstate.Op)ar);
471         if(elements.length)
472         {
473             Expression e;
474 
475             argc = cast(uint)elements.length;
476             argv = irs.alloc(argc);
477             if(argc > 1)
478             {
479                 uint i;
480 
481                 // array literal [a, b, c] is equivalent to:
482                 //	new Array(a,b,c)
483                 for(i = 0; i < argc; i++)
484                 {
485                     e = elements[i];
486                     if(e)
487                     {
488                         e.toIR(irs, argv + i * INDEX_FACTOR);
489                     }
490                     else
491                         irs.gen1(loc, IRundefined, argv + i * INDEX_FACTOR);
492                 }
493                 irs.gen4(loc, IRnew, ret, b, argc, argv);
494             }
495             else
496             {   //	[a] translates to:
497                 //	ret = new Array(1);
498                 //  ret[0] = a
499                 irs.genX(loc, IRnumber, argv, 1.0);
500                 irs.gen4(loc, IRnew, ret, b, argc, argv);
501 
502                 e = elements[0];
503                 v = irs.alloc(1);
504                 if(e)
505                     e.toIR(irs, v);
506                 else
507                     irs.gen1(loc, IRundefined, v);
508                 irs.gen3(loc, IRputs, v, ret, cast(IRstate.Op)Identifier.build(TEXT_0));
509                 irs.release(v, 1);
510             }
511             irs.release(argv, argc);
512         }
513         else
514         {
515             // Generate new Array()
516             irs.gen4(loc, IRnew, ret, b, 0, 0);
517         }
518         irs.release(b, 1);
519     }
520 }
521 
522 /******************************** FieldLiteral **************************/
523 
524 class Field
525 {
526     Identifier* ident;
527     Expression exp;
528 
529     this(Identifier * ident, Expression exp)
530     {
531         this.ident = ident;
532         this.exp = exp;
533     }
534 }
535 
536 /******************************** ObjectLiteral **************************/
537 
538 class ObjectLiteral : Expression
539 {
540     Field[] fields;
541 
542     this(Loc loc, Field[] fields)
543     {
544         super(loc, TOKobjectlit);
545         this.fields = fields;
546     }
547 
548     override Expression semantic(Scope *sc)
549     {
550         foreach(Field f; fields)
551         {
552             f.exp = f.exp.semantic(sc);
553         }
554         return this;
555     }
556 
557     override void toBuffer(ref tchar[] buf)
558     {
559         uint i;
560 
561         buf ~= '{';
562         foreach(Field f; fields)
563         {
564             if(i)
565                 buf ~= ',';
566             i = 1;
567             buf ~= f.ident.toString();
568             buf ~= ':';
569             f.exp.toBuffer(buf);
570         }
571         buf ~= '}';
572     }
573 
574     override void toIR(IRstate *irs, uint ret)
575     {
576         uint b;
577 
578         b = irs.alloc(1);
579         //irs.gen2(loc, IRstring, b, TEXT_Object);
580         Identifier* ob = Identifier.build(TEXT_Object);
581         irs.gen2(loc, IRgetscope, b, cast(IRstate.Op)ob);
582         // Generate new Object()
583         irs.gen4(loc, IRnew, ret, b, 0, 0);
584         if(fields.length)
585         {
586             uint x;
587 
588             x = irs.alloc(1);
589             foreach(Field f; fields)
590             {
591                 f.exp.toIR(irs, x);
592                 irs.gen3(loc, IRputs, x, ret, cast(IRstate.Op)(f.ident));
593             }
594         }
595     }
596 }
597 
598 /******************************** FunctionLiteral **************************/
599 
600 class FunctionLiteral : Expression
601 { FunctionDefinition func;
602 
603   this(Loc loc, FunctionDefinition func)
604   {
605       super(loc, TOKobjectlit);
606       this.func = func;
607   }
608 
609   override Expression semantic(Scope *sc)
610   {
611       func = cast(FunctionDefinition)(func.semantic(sc));
612       return this;
613   }
614 
615   override void toBuffer(ref tchar[] buf)
616   {
617       func.toBuffer(buf);
618   }
619 
620   override void toIR(IRstate *irs, uint ret)
621   {
622       func.toIR(null);
623       irs.gen2(loc, IRobject, ret, cast(IRstate.Op)cast(void*)func);
624   }
625 }
626 
627 /***************************** UnaExp *************************************/
628 
629 class UnaExp : Expression
630 {
631     Expression e1;
632 
633     this(Loc loc, TOK op, Expression e1)
634     {
635         super(loc, op);
636         this.e1 = e1;
637     }
638 
639     override Expression semantic(Scope *sc)
640     {
641         e1 = e1.semantic(sc);
642         return this;
643     }
644 
645     override void toBuffer(ref tchar[] buf)
646     {
647         buf ~= Token.toString(op);
648         buf ~= ' ';
649         e1.toBuffer(buf);
650     }
651 }
652 
653 /***************************** BinExp *************************************/
654 
655 class BinExp : Expression
656 {
657     Expression e1;
658     Expression e2;
659 
660     this(Loc loc, TOK op, Expression e1, Expression e2)
661     {
662         super(loc, op);
663         this.e1 = e1;
664         this.e2 = e2;
665     }
666 
667     override Expression semantic(Scope *sc)
668     {
669         e1 = e1.semantic(sc);
670         e2 = e2.semantic(sc);
671         return this;
672     }
673 
674     override void toBuffer(ref tchar[] buf)
675     {
676         e1.toBuffer(buf);
677         buf ~= ' ';
678         buf ~= Token.toString(op);
679         buf ~= ' ';
680         e2.toBuffer(buf);
681     }
682 
683     void binIR(IRstate *irs, uint ret, uint ircode)
684     {
685         uint b;
686         uint c;
687 
688         if(ret)
689         {
690             b = irs.alloc(1);
691             e1.toIR(irs, b);
692             if(e1.match(e2))
693             {
694                 irs.gen3(loc, ircode, ret, b, b);
695             }
696             else
697             {
698                 c = irs.alloc(1);
699                 e2.toIR(irs, c);
700                 irs.gen3(loc, ircode, ret, b, c);
701                 irs.release(c, 1);
702             }
703             irs.release(b, 1);
704         }
705         else
706         {
707             e1.toIR(irs, 0);
708             e2.toIR(irs, 0);
709         }
710     }
711 }
712 
713 /************************************************************/
714 
715 /* Handle ++e and --e
716  */
717 
718 class PreExp : UnaExp
719 {
720     uint ircode;
721 
722     this(Loc loc, uint ircode, Expression e)
723     {
724         super(loc, TOKplusplus, e);
725         this.ircode = ircode;
726     }
727 
728     override Expression semantic(Scope *sc)
729     {
730         super.semantic(sc);
731         e1.checkLvalue(sc);
732         return this;
733     }
734 
735     override void toBuffer(ref tchar[] buf)
736     {
737         e1.toBuffer(buf);
738         buf ~= Token.toString(op);
739     }
740 
741     override void toIR(IRstate *irs, uint ret)
742     {
743         uint base;
744         IR property;
745         int opoff;
746 
747         //writef("PreExp::toIR('%s')\n", toChars());
748         e1.toLvalue(irs, base, &property, opoff);
749         assert(opoff != 3);
750         if(opoff == 2)
751         {
752             //irs.gen2(loc, ircode + 2, ret, property.index);
753             irs.gen3(loc, ircode + 2, ret, property.index, property.id.toHash());
754         }
755         else
756             irs.gen3(loc, ircode + opoff, ret, base, property.index);
757     }
758 }
759 
760 /************************************************************/
761 
762 class PostIncExp : UnaExp
763 {
764     this(Loc loc, Expression e)
765     {
766         super(loc, TOKplusplus, e);
767     }
768 
769     override Expression semantic(Scope *sc)
770     {
771         super.semantic(sc);
772         e1.checkLvalue(sc);
773         return this;
774     }
775 
776     override void toBuffer(ref tchar[] buf)
777     {
778         e1.toBuffer(buf);
779         buf ~= Token.toString(op);
780     }
781 
782     override void toIR(IRstate *irs, uint ret)
783     {
784         uint base;
785         IR property;
786         int opoff;
787 
788         //writef("PostIncExp::toIR('%s')\n", toChars());
789         e1.toLvalue(irs, base, &property, opoff);
790         assert(opoff != 3);
791         if(opoff == 2)
792         {
793             if(ret)
794             {
795                 irs.gen2(loc, IRpostincscope, ret, property.index);
796             }
797             else
798             {
799                 //irs.gen2(loc, IRpreincscope, ret, property.index);
800                 irs.gen3(loc, IRpreincscope, ret, property.index, property.id.toHash());
801             }
802         }
803         else
804             irs.gen3(loc, (ret ? IRpostinc : IRpreinc) + opoff, ret, base, property.index);
805     }
806 }
807 
808 /****************************************************************/
809 
810 class PostDecExp : UnaExp
811 {
812     this(Loc loc, Expression e)
813     {
814         super(loc, TOKplusplus, e);
815     }
816 
817     override Expression semantic(Scope *sc)
818     {
819         super.semantic(sc);
820         e1.checkLvalue(sc);
821         return this;
822     }
823 
824     override void toBuffer(ref tchar[] buf)
825     {
826         e1.toBuffer(buf);
827         buf ~= Token.toString(op);
828     }
829 
830     override void toIR(IRstate *irs, uint ret)
831     {
832         uint base;
833         IR property;
834         int opoff;
835 
836         //writef("PostDecExp::toIR('%s')\n", toChars());
837         e1.toLvalue(irs, base, &property, opoff);
838         assert(opoff != 3);
839         if(opoff == 2)
840         {
841             if(ret)
842             {
843                 irs.gen2(loc, IRpostdecscope, ret, property.index);
844             }
845             else
846             {
847                 //irs.gen2(loc, IRpredecscope, ret, property.index);
848                 irs.gen3(loc, IRpredecscope, ret, property.index, property.id.toHash());
849             }
850         }
851         else
852             irs.gen3(loc, (ret ? IRpostdec : IRpredec) + opoff, ret, base, property.index);
853     }
854 }
855 
856 /************************************************************/
857 
858 class DotExp : UnaExp
859 {
860     Identifier *ident;
861 
862     this(Loc loc, Expression e, Identifier * ident)
863     {
864         super(loc, TOKdot, e);
865         this.ident = ident;
866     }
867 
868     override void checkLvalue(Scope *sc)
869     {
870     }
871 
872     override void toBuffer(ref tchar[] buf)
873     {
874         e1.toBuffer(buf);
875         buf ~= '.';
876         buf ~= ident.toString();
877     }
878 
879     override void toIR(IRstate *irs, uint ret)
880     {
881         uint base;
882 
883         //writef("DotExp::toIR('%s')\n", toChars());
884         version(all)
885         {
886             // Some test cases depend on things like:
887             //		foo.bar;
888             // generating a property get even if the result is thrown away.
889             base = irs.alloc(1);
890             e1.toIR(irs, base);
891             irs.gen3(loc, IRgets, ret, base, cast(IRstate.Op)ident);
892         }
893         else
894         {
895             if(ret)
896             {
897                 base = irs.alloc(1);
898                 e1.toIR(irs, base);
899                 irs.gen3(loc, IRgets, ret, base, cast(IRstate.Op)ident);
900             }
901             else
902                 e1.toIR(irs, 0);
903         }
904     }
905 
906     override void toLvalue(IRstate *irs, out uint base, IR *property, out int opoff)
907     {
908         base = irs.alloc(1);
909         e1.toIR(irs, base);
910         property.id = ident;
911         opoff = 1;
912     }
913 }
914 
915 /************************************************************/
916 
917 class CallExp : UnaExp
918 {
919     Expression[] arguments;
920 
921     this(Loc loc, Expression e, Expression[] arguments)
922     {
923         //writef("CallExp(e1 = %x)\n", e);
924         super(loc, TOKcall, e);
925         this.arguments = arguments;
926     }
927 
928     override Expression semantic(Scope *sc)
929     {
930         IdentifierExpression ie;
931 
932         //writef("CallExp(e1=%x, %d, vptr=%x)\n", e1, e1.op, *(uint *)e1);
933         //writef("CallExp(e1='%s')\n", e1.toString());
934         e1 = e1.semantic(sc);
935         /*if(e1.op != TOKcall)
936             e1.checkLvalue(sc);
937 */
938         foreach(ref Expression e; arguments)
939         {
940             e = e.semantic(sc);
941         }
942         if(arguments.length == 1)
943         {
944             if(e1.op == TOKidentifier)
945             {
946                 ie = cast(IdentifierExpression )e1;
947                 if(ie.ident.toString() == "assert")
948                 {
949                     return new AssertExp(loc, arguments[0]);
950                 }
951             }
952         }
953         return this;
954     }
955 
956     override void toBuffer(ref tchar[] buf)
957     {
958         e1.toBuffer(buf);
959         buf ~= '(';
960         for(size_t u = 0; u < arguments.length; u++)
961         {
962             if(u)
963                 buf ~= ", ";
964             arguments[u].toBuffer(buf);
965         }
966         buf ~= ')';
967     }
968 
969     override void toIR(IRstate *irs, uint ret)
970     {
971         // ret = base.property(argc, argv)
972         // CALL ret,base,property,argc,argv
973         uint base;
974         uint argc;
975         uint argv;
976         IR property;
977         int opoff;
978 
979         //writef("CallExp::toIR('%s')\n", toChars());
980         e1.toLvalue(irs, base, &property, opoff);
981 
982         if(arguments.length)
983         {
984             uint u;
985 
986             argc = cast(uint)arguments.length;
987             argv = irs.alloc(argc);
988             for(u = 0; u < argc; u++)
989             {
990                 Expression e;
991 
992                 e = arguments[u];
993                 e.toIR(irs, argv + u * INDEX_FACTOR);
994             }
995             arguments[] = null;         // release to GC
996             arguments = null;
997         }
998         else
999         {
1000             argc = 0;
1001             argv = 0;
1002         }
1003 
1004         if(opoff == 3)
1005             irs.gen4(loc, IRcallv, ret, base, argc, argv);
1006         else if(opoff == 2)
1007             irs.gen4(loc, IRcallscope, ret, property.index, argc, argv);
1008         else
1009             irs.genX(loc, IRcall + opoff, ret, base, property, argc, argv);
1010         irs.release(argv, argc);
1011     }
1012 }
1013 
1014 /************************************************************/
1015 
1016 class AssertExp : UnaExp
1017 {
1018     this(Loc loc, Expression e)
1019     {
1020         super(loc, TOKassert, e);
1021     }
1022 
1023     override void toBuffer(ref tchar[] buf)
1024     {
1025         buf ~= "assert(";
1026         e1.toBuffer(buf);
1027         buf ~= ')';
1028     }
1029 
1030     override void toIR(IRstate *irs, uint ret)
1031     {
1032         uint linnum;
1033         uint u;
1034         uint b;
1035 
1036         b = ret ? ret : irs.alloc(1);
1037 
1038         e1.toIR(irs, b);
1039         u = irs.getIP();
1040         irs.gen2(loc, IRjt, 0, b);
1041         linnum = cast(uint)loc;
1042         irs.gen1(loc, IRassert, linnum);
1043         irs.patchJmp(u, irs.getIP());
1044 
1045         if(!ret)
1046             irs.release(b, 1);
1047     }
1048 }
1049 
1050 /************************* NewExp ***********************************/
1051 
1052 class NewExp : UnaExp
1053 {
1054     Expression[] arguments;
1055 
1056     this(Loc loc, Expression e, Expression[] arguments)
1057     {
1058         super(loc, TOKnew, e);
1059         this.arguments = arguments;
1060     }
1061 
1062     override Expression semantic(Scope *sc)
1063     {
1064         e1 = e1.semantic(sc);
1065         for(size_t a = 0; a < arguments.length; a++)
1066         {
1067             arguments[a] = arguments[a].semantic(sc);
1068         }
1069         return this;
1070     }
1071 
1072     override void toBuffer(ref tchar[] buf)
1073     {
1074         buf ~= Token.toString(op);
1075         buf ~= ' ';
1076 
1077         e1.toBuffer(buf);
1078         buf ~= '(';
1079         for(size_t a = 0; a < arguments.length; a++)
1080         {
1081             arguments[a].toBuffer(buf);
1082         }
1083         buf ~= ')';
1084     }
1085 
1086     override void toIR(IRstate *irs, uint ret)
1087     {
1088         // ret = new b(argc, argv)
1089         // CALL ret,b,argc,argv
1090         uint b;
1091         uint argc;
1092         uint argv;
1093 
1094         //writef("NewExp::toIR('%s')\n", toChars());
1095         b = irs.alloc(1);
1096         e1.toIR(irs, b);
1097         if(arguments.length)
1098         {
1099             uint u;
1100 
1101             argc = cast(uint)arguments.length;
1102             argv = irs.alloc(argc);
1103             for(u = 0; u < argc; u++)
1104             {
1105                 Expression e;
1106 
1107                 e = arguments[u];
1108                 e.toIR(irs, argv + u * INDEX_FACTOR);
1109             }
1110         }
1111         else
1112         {
1113             argc = 0;
1114             argv = 0;
1115         }
1116 
1117         irs.gen4(loc, IRnew, ret, b, argc, argv);
1118         irs.release(argv, argc);
1119         irs.release(b, 1);
1120     }
1121 }
1122 
1123 /************************************************************/
1124 
1125 class XUnaExp : UnaExp
1126 {
1127     uint ircode;
1128 
1129     this(Loc loc, TOK op, uint ircode, Expression e)
1130     {
1131         super(loc, op, e);
1132         this.ircode = ircode;
1133     }
1134 
1135     override void toIR(IRstate *irs, uint ret)
1136     {
1137         e1.toIR(irs, ret);
1138         if(ret)
1139             irs.gen1(loc, ircode, ret);
1140     }
1141 }
1142 
1143 class NotExp : XUnaExp
1144 {
1145     this(Loc loc, Expression e)
1146     {
1147         super(loc, TOKnot, IRnot, e);
1148     }
1149 
1150     override int isBooleanResult()
1151     {
1152         return true;
1153     }
1154 }
1155 
1156 class DeleteExp : UnaExp
1157 {
1158     bool lval;
1159     this(Loc loc, Expression e)
1160     {
1161         super(loc, TOKdelete, e);
1162     }
1163 
1164     override Expression semantic(Scope *sc)
1165     {
1166         e1.checkLvalue(sc);
1167         lval = sc.errinfo.message == null;
1168         //delete don't have to operate on Lvalue, while slightly stupid but perfectly by the standard
1169         if(!lval)
1170                sc.errinfo.message = null;
1171         return this;
1172     }
1173 
1174     override void toIR(IRstate *irs, uint ret)
1175     {
1176         uint base;
1177         IR property;
1178         int opoff;
1179 
1180         if(lval){
1181             e1.toLvalue(irs, base, &property, opoff);
1182         
1183             assert(opoff != 3);
1184             if(opoff == 2)
1185                 irs.gen2(loc, IRdelscope, ret, property.index);
1186             else
1187                 irs.gen3(loc, IRdel + opoff, ret, base, property.index);
1188         }else{
1189             //e1.toIR(irs,ret);
1190             irs.gen2(loc,IRboolean,ret,true);
1191         }
1192     }
1193 }
1194 
1195 /************************* CommaExp ***********************************/
1196 
1197 class CommaExp : BinExp
1198 {
1199     this(Loc loc, Expression e1, Expression e2)
1200     {
1201         super(loc, TOKcomma, e1, e2);
1202     }
1203 
1204     override void checkLvalue(Scope *sc)
1205     {
1206         e2.checkLvalue(sc);
1207     }
1208 
1209     override void toIR(IRstate *irs, uint ret)
1210     {
1211         e1.toIR(irs, 0);
1212         e2.toIR(irs, ret);
1213     }
1214 }
1215 
1216 /************************* ArrayExp ***********************************/
1217 
1218 class ArrayExp : BinExp
1219 {
1220     this(Loc loc, Expression e1, Expression e2)
1221     {
1222         super(loc, TOKarray, e1, e2);
1223     }
1224 
1225     override Expression semantic(Scope *sc)
1226     {
1227         checkLvalue(sc);
1228         return this;
1229     }
1230 
1231     override void checkLvalue(Scope *sc)
1232     {
1233     }
1234 
1235     override void toBuffer(ref tchar[] buf)
1236     {
1237         e1.toBuffer(buf);
1238         buf ~= '[';
1239         e2.toBuffer(buf);
1240         buf ~= ']';
1241     }
1242 
1243     override void toIR(IRstate *irs, uint ret)
1244     {
1245         uint base;
1246         IR property;
1247         int opoff;
1248 
1249         if(ret)
1250         {
1251             toLvalue(irs, base, &property, opoff);
1252             assert(opoff != 3);
1253             if(opoff == 2)
1254                 irs.gen2(loc, IRgetscope, ret, property.index);
1255             else
1256                 irs.gen3(loc, IRget + opoff, ret, base, property.index);
1257         }
1258         else
1259         {
1260             e1.toIR(irs, 0);
1261             e2.toIR(irs, 0);
1262         }
1263     }
1264 
1265     override void toLvalue(IRstate *irs, out uint base, IR *property, out int opoff)
1266     {
1267         uint index;
1268 
1269         base = irs.alloc(1);
1270         e1.toIR(irs, base);
1271         index = irs.alloc(1);
1272         e2.toIR(irs, index);
1273         property.index = index;
1274         opoff = 0;
1275     }
1276 }
1277 
1278 /************************* AssignExp ***********************************/
1279 
1280 class AssignExp : BinExp
1281 {
1282     this(Loc loc, Expression e1, Expression e2)
1283     {
1284         super(loc, TOKassign, e1, e2);
1285     }
1286 
1287     override Expression semantic(Scope *sc)
1288     {
1289         //writefln("AssignExp.semantic()");
1290         super.semantic(sc);
1291         if(e1.op != TOKcall)            // special case for CallExp lvalue's
1292             e1.checkLvalue(sc);
1293         return this;
1294     }
1295 
1296     override void toIR(IRstate *irs, uint ret)
1297     {
1298         uint b;
1299 
1300         //writef("AssignExp::toIR('%s')\n", toChars());
1301         if(e1.op == TOKcall)            // if CallExp
1302         {
1303             assert(cast(CallExp)(e1));  // make sure we got it right
1304 
1305             // Special case a function call as an lvalue.
1306             // This can happen if:
1307             //	foo() = 3;
1308             // A Microsoft extension, it means to assign 3 to the default property of
1309             // the object returned by foo(). It only has meaning for com objects.
1310             // This functionality should be worked into toLvalue() if it gets used
1311             // elsewhere.
1312 
1313             uint base;
1314             uint argc;
1315             uint argv;
1316             IR property;
1317             int opoff;
1318             CallExp ec = cast(CallExp)e1;
1319 
1320             if(ec.arguments.length)
1321                 argc = cast(uint)ec.arguments.length + 1;
1322             else
1323                 argc = 1;
1324 
1325             argv = irs.alloc(argc);
1326 
1327             e2.toIR(irs, argv + (argc - 1) * INDEX_FACTOR);
1328 
1329             ec.e1.toLvalue(irs, base, &property, opoff);
1330 
1331             if(ec.arguments.length)
1332             {
1333                 uint u;
1334 
1335                 for(u = 0; u < ec.arguments.length; u++)
1336                 {
1337                     Expression e;
1338 
1339                     e = ec.arguments[u];
1340                     e.toIR(irs, argv + (u + 0) * INDEX_FACTOR);
1341                 }
1342                 ec.arguments[] = null;          // release to GC
1343                 ec.arguments = null;
1344             }
1345 
1346             if(opoff == 3)
1347                 irs.gen4(loc, IRputcallv, ret, base, argc, argv);
1348             else if(opoff == 2)
1349                 irs.gen4(loc, IRputcallscope, ret, property.index, argc, argv);
1350             else
1351                 irs.genX(loc, IRputcall + opoff, ret, base, property, argc, argv);
1352             irs.release(argv, argc);
1353         }
1354         else
1355         {
1356             uint base;
1357             IR property;
1358             int opoff;
1359 
1360             b = ret ? ret : irs.alloc(1);
1361             e2.toIR(irs, b);
1362 
1363             e1.toLvalue(irs, base, &property, opoff);
1364             assert(opoff != 3);
1365             if(opoff == 2)
1366                 irs.gen2(loc, IRputscope, b, property.index);
1367             else
1368                 irs.gen3(loc, IRput + opoff, b, base, property.index);
1369             if(!ret)
1370                 irs.release(b, 1);
1371         }
1372     }
1373 }
1374 
1375 /************************* AddAssignExp ***********************************/
1376 
1377 class AddAssignExp : BinExp
1378 {
1379     this(Loc loc, Expression e1, Expression e2)
1380     {
1381         super(loc, TOKplusass, e1, e2);
1382     }
1383 
1384     override Expression semantic(Scope *sc)
1385     {
1386         super.semantic(sc);
1387         e1.checkLvalue(sc);
1388         return this;
1389     }
1390 
1391     override void toIR(IRstate *irs, uint ret)
1392     {
1393         /*if(ret == 0 && e2.op == TOKreal &&
1394            (cast(RealExpression)e2).value == 1)//disabled for better standard conformance
1395         {
1396             uint base;
1397             IR property;
1398             int opoff;
1399 
1400             //writef("AddAssign to PostInc('%s')\n", toChars());
1401             e1.toLvalue(irs, base, &property, opoff);
1402             assert(opoff != 3);
1403             if(opoff == 2)
1404                 irs.gen2(loc, IRpostincscope, ret, property.index);
1405             else
1406                 irs.gen3(loc, IRpostinc + opoff, ret, base, property.index);
1407         }
1408         else*/
1409         {
1410             uint r;
1411             uint base;
1412             IR property;
1413             int opoff;
1414 
1415             //writef("AddAssignExp::toIR('%s')\n", toChars());
1416             e1.toLvalue(irs, base, &property, opoff);
1417             assert(opoff != 3);
1418             r = ret ? ret : irs.alloc(1);
1419             e2.toIR(irs, r);
1420             if(opoff == 2)
1421                 irs.gen3(loc, IRaddassscope, r, property.index, property.id.toHash());
1422             else
1423                 irs.gen3(loc, IRaddass + opoff, r, base, property.index);
1424             if(!ret)
1425                 irs.release(r, 1);
1426         }
1427     }
1428 }
1429 
1430 /************************* BinAssignExp ***********************************/
1431 
1432 class BinAssignExp : BinExp
1433 {
1434     uint ircode = IRerror;
1435 
1436     this(Loc loc, TOK op, uint ircode, Expression e1, Expression e2)
1437     {
1438         super(loc, op, e1, e2);
1439         this.ircode = ircode;
1440     }
1441 
1442     override Expression semantic(Scope *sc)
1443     {
1444         super.semantic(sc);
1445         e1.checkLvalue(sc);
1446         return this;
1447     }
1448 
1449     override void toIR(IRstate *irs, uint ret)
1450     {
1451         uint b;
1452         uint c;
1453         uint r;
1454         uint base;
1455         IR property;
1456         int opoff;
1457 
1458         //writef("BinExp::binAssignIR('%s')\n", toChars());
1459         e1.toLvalue(irs, base, &property, opoff);
1460         assert(opoff != 3);
1461         b = irs.alloc(1);
1462         if(opoff == 2)
1463             irs.gen2(loc, IRgetscope, b, property.index);
1464         else
1465             irs.gen3(loc, IRget + opoff, b, base, property.index);
1466         c = irs.alloc(1);
1467         e2.toIR(irs, c);
1468         r = ret ? ret : irs.alloc(1);
1469         irs.gen3(loc, ircode, r, b, c);
1470         if(opoff == 2)
1471             irs.gen2(loc, IRputscope, r, property.index);
1472         else
1473             irs.gen3(loc, IRput + opoff, r, base, property.index);
1474         if(!ret)
1475             irs.release(r, 1);
1476     }
1477 }
1478 
1479 /************************* AddExp *****************************/
1480 
1481 class AddExp : BinExp
1482 {
1483     this(Loc loc, Expression e1, Expression e2)
1484     {
1485         super(loc, TOKplus, e1, e2);
1486     }
1487 
1488     override Expression semantic(Scope *sc)
1489     {
1490         return this;
1491     }
1492 
1493     override void toIR(IRstate *irs, uint ret)
1494     {
1495         binIR(irs, ret, IRadd);
1496     }
1497 }
1498 
1499 /************************* XBinExp ***********************************/
1500 
1501 class XBinExp : BinExp
1502 {
1503     uint ircode = IRerror;
1504 
1505     this(Loc loc, TOK op, uint ircode, Expression e1, Expression e2)
1506     {
1507         super(loc, op, e1, e2);
1508         this.ircode = ircode;
1509     }
1510 
1511     override void toIR(IRstate *irs, uint ret)
1512     {
1513         binIR(irs, ret, ircode);
1514     }
1515 }
1516 
1517 /************************* OrOrExp ***********************************/
1518 
1519 class OrOrExp : BinExp
1520 {
1521     this(Loc loc, Expression e1, Expression e2)
1522     {
1523         super(loc, TOKoror, e1, e2);
1524     }
1525 
1526     override void toIR(IRstate *irs, uint ret)
1527     {
1528         uint u;
1529         uint b;
1530 
1531         if(ret)
1532             b = ret;
1533         else
1534             b = irs.alloc(1);
1535 
1536         e1.toIR(irs, b);
1537         u = irs.getIP();
1538         irs.gen2(loc, IRjt, 0, b);
1539         e2.toIR(irs, ret);
1540         irs.patchJmp(u, irs.getIP());
1541 
1542         if(!ret)
1543             irs.release(b, 1);
1544     }
1545 }
1546 
1547 /************************* AndAndExp ***********************************/
1548 
1549 class AndAndExp : BinExp
1550 {
1551     this(Loc loc, Expression e1, Expression e2)
1552     {
1553         super(loc, TOKandand, e1, e2);
1554     }
1555 
1556     override void toIR(IRstate *irs, uint ret)
1557     {
1558         uint u;
1559         uint b;
1560 
1561         if(ret)
1562             b = ret;
1563         else
1564             b = irs.alloc(1);
1565 
1566         e1.toIR(irs, b);
1567         u = irs.getIP();
1568         irs.gen2(loc, IRjf, 0, b);
1569         e2.toIR(irs, ret);
1570         irs.patchJmp(u, irs.getIP());
1571 
1572         if(!ret)
1573             irs.release(b, 1);
1574     }
1575 }
1576 
1577 /************************* CmpExp ***********************************/
1578 
1579 
1580 
1581 class CmpExp : BinExp
1582 {
1583     uint ircode = IRerror;
1584 
1585     this(Loc loc, TOK tok, uint ircode, Expression e1, Expression e2)
1586     {
1587         super(loc, tok, e1, e2);
1588         this.ircode = ircode;
1589     }
1590 
1591     override int isBooleanResult()
1592     {
1593         return true;
1594     }
1595 
1596     override void toIR(IRstate *irs, uint ret)
1597     {
1598         binIR(irs, ret, ircode);
1599     }
1600 }
1601 
1602 /*************************** InExp **************************/
1603 
1604 class InExp : BinExp
1605 {
1606     this(Loc loc, Expression e1, Expression e2)
1607     {
1608         super(loc, TOKin, e1, e2);
1609     }
1610 	override void toIR(IRstate *irs, uint ret)
1611     {
1612         binIR(irs, ret, IRin);
1613     }
1614 }
1615 
1616 /****************************************************************/
1617 
1618 class CondExp : BinExp
1619 {
1620     Expression econd;
1621 
1622     this(Loc loc, Expression econd, Expression e1, Expression e2)
1623     {
1624         super(loc, TOKquestion, e1, e2);
1625         this.econd = econd;
1626     }
1627 
1628     override void toIR(IRstate *irs, uint ret)
1629     {
1630         uint u1;
1631         uint u2;
1632         uint b;
1633 
1634         if(ret)
1635             b = ret;
1636         else
1637             b = irs.alloc(1);
1638 
1639         econd.toIR(irs, b);
1640         u1 = irs.getIP();
1641         irs.gen2(loc, IRjf, 0, b);
1642         e1.toIR(irs, ret);
1643         u2 = irs.getIP();
1644         irs.gen1(loc, IRjmp, 0);
1645         irs.patchJmp(u1, irs.getIP());
1646         e2.toIR(irs, ret);
1647         irs.patchJmp(u2, irs.getIP());
1648 
1649         if(!ret)
1650             irs.release(b, 1);
1651     }
1652 }
1653