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