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.statement;
19 
20 import std.stdio;
21 import std..string;
22 import std.math;
23 
24 import dmdscript.script;
25 import dmdscript.value;
26 import dmdscript.scopex;
27 import dmdscript.expression;
28 import dmdscript.irstate;
29 import dmdscript.symbol;
30 import dmdscript.identifier;
31 import dmdscript.ir;
32 import dmdscript.lexer;
33 import dmdscript.errmsgs;
34 import dmdscript.functiondefinition;
35 import dmdscript.opcodes;
36 
37 enum
38 {
39     TOPSTATEMENT,
40     FUNCTIONDEFINITION,
41     EXPSTATEMENT,
42     VARSTATEMENT,
43 }
44 
45 
46 /******************************** TopStatement ***************************/
47 
48 class TopStatement
49 {
50     enum uint TOPSTATEMENT_SIGNATURE = 0xBA3FE1F3;
51     uint signature = TOPSTATEMENT_SIGNATURE;
52 
53     Loc loc;
54     int done;           // 0: parsed
55                         // 1: semantic
56                         // 2: toIR
57     int st;
58 
59     this(Loc loc)
60     {
61         this.loc = loc;
62         this.done = 0;
63         this.st = TOPSTATEMENT;
64     }
65 
66     invariant()
67     {
68         assert(signature == TOPSTATEMENT_SIGNATURE);
69     }
70 
71     void toBuffer(ref tchar[] buf)
72     {
73         buf ~= "TopStatement.toBuffer()\n";
74     }
75 
76     Statement semantic(Scope *sc)
77     {
78         writefln("TopStatement.semantic(%p)", this);
79         return null;
80     }
81 
82     void toIR(IRstate *irs)
83     {
84         writefln("TopStatement.toIR(%p)", this);
85     }
86 
87     void error(Scope *sc, int msgnum)
88     {
89         error(sc, errmsgtbl[msgnum]);
90     }
91 
92     void error(Scope *sc, ...)
93     {
94         d_string buf;
95         d_string sourcename;
96 
97         if(sc.funcdef)
98         {
99             if(sc.funcdef.isAnonymous)
100                 sourcename = "anonymous";
101             else if(sc.funcdef.name)
102                 sourcename ~= sc.funcdef.name.toString();
103         }
104         buf = std..string.format("%s(%d) : Error: ", sourcename, loc);
105 
106         void putc(dchar c)
107         {
108             dmdscript.utf.encode(buf, c);
109         }
110 
111         std.format.doFormat(&putc, _arguments, _argptr);
112 
113 
114         if(!sc.errinfo.message)
115         {
116             sc.errinfo.message = buf;
117             sc.errinfo.linnum = loc;
118             sc.errinfo.srcline = Lexer.locToSrcline(sc.getSource().ptr, loc);
119         }
120     }
121 
122     TopStatement ImpliedReturn()
123     {
124         return this;
125     }
126 }
127 
128 /******************************** Statement ***************************/
129 
130 class Statement : TopStatement
131 {
132     LabelSymbol *label;
133 
134     this(Loc loc)
135     {
136         super(loc);
137         this.loc = loc;
138     }
139 
140     override void toBuffer(ref tchar[] buf)
141     {
142         buf ~= "Statement.toBuffer()\n";
143     }
144 
145     override Statement semantic(Scope *sc)
146     {
147         writef("Statement.semantic(%p)\n", this);
148         return this;
149     }
150 
151     override void toIR(IRstate *irs)
152     {
153         writef("Statement.toIR(%p)\n", this);
154     }
155 
156     uint getBreak()
157     {
158         assert(0);
159     }
160 
161     uint getContinue()
162     {
163         assert(0);
164     }
165 
166     uint getGoto()
167     {
168         assert(0);
169     }
170 
171     uint getTarget()
172     {
173         assert(0);
174     }
175 
176     ScopeStatement getScope()
177     {
178         return null;
179     }
180 }
181 
182 /******************************** EmptyStatement ***************************/
183 
184 class EmptyStatement : Statement
185 {
186     this(Loc loc)
187     {
188         super(loc);
189         this.loc = loc;
190     }
191 
192     override void toBuffer(ref tchar[] buf)
193     {
194         buf ~= ";\n";
195     }
196 
197     override Statement semantic(Scope *sc)
198     {
199         //writef("EmptyStatement.semantic(%p)\n", this);
200         return this;
201     }
202 
203     override void toIR(IRstate *irs)
204     {
205     }
206 }
207 
208 /******************************** ExpStatement ***************************/
209 
210 class ExpStatement : Statement
211 {
212     Expression exp;
213 
214     this(Loc loc, Expression exp)
215     {
216         //writef("ExpStatement.ExpStatement(this = %x, exp = %x)\n", this, exp);
217         super(loc);
218         st = EXPSTATEMENT;
219         this.exp = exp;
220     }
221 
222     override void toBuffer(ref tchar[] buf)
223     {
224         if(exp)
225             exp.toBuffer(buf);
226         buf ~= ";\n";
227     }
228 
229     override Statement semantic(Scope *sc)
230     {
231         //writef("exp = '%s'\n", exp.toString());
232         //writef("ExpStatement.semantic(this = %x, exp = %x, exp.vptr = %x, %x, %x)\n", this, exp, ((uint *)exp)[0], /*(*(uint **)exp)[12],*/ *(uint *)(*(uint **)exp)[12]);
233         if(exp)
234             exp = exp.semantic(sc);
235         //writef("-semantic()\n");
236         return this;
237     }
238 
239     override TopStatement ImpliedReturn()
240     {
241         return new ImpliedReturnStatement(loc, exp);
242     }
243 
244     override void toIR(IRstate *irs)
245     {
246         //writef("ExpStatement.toIR(%p)\n", exp);
247         if(exp)
248         {
249             uint marksave = irs.mark();
250 
251             assert(exp);
252             exp.toIR(irs, 0);
253             irs.release(marksave);
254 
255             exp = null;         // release to garbage collector
256         }
257     }
258 }
259 
260 /****************************** VarDeclaration ******************************/
261 
262 class VarDeclaration
263 {
264     Loc loc;
265     Identifier *name;
266     Expression init;
267 
268     this(Loc loc, Identifier * name, Expression init)
269     {
270         this.loc = loc;
271         this.init = init;
272         this.name = name;
273     }
274 }
275 
276 /******************************** VarStatement ***************************/
277 
278 class VarStatement : Statement
279 {
280     VarDeclaration[] vardecls;
281 
282     this(Loc loc)
283     {
284         super(loc);
285         st = VARSTATEMENT;
286     }
287 
288     override Statement semantic(Scope *sc)
289     {
290         FunctionDefinition fd;
291         uint i;
292 
293         // Collect all the Var statements in order in the function
294         // declaration, this is so it is easy to instantiate them
295         fd = sc.funcdef;
296         //fd.varnames.reserve(vardecls.length);
297 
298         for(i = 0; i < vardecls.length; i++)
299         {
300             VarDeclaration vd;
301 
302             vd = vardecls[i];
303             if(vd.init)
304                 vd.init = vd.init.semantic(sc);
305             fd.varnames ~= vd.name;
306         }
307 
308         return this;
309     }
310 
311     override void toBuffer(ref tchar[] buf)
312     {
313         uint i;
314 
315         if(vardecls.length)
316         {
317             buf ~= "var ";
318 
319             for(i = 0; i < vardecls.length; i++)
320             {
321                 VarDeclaration vd;
322 
323                 vd = vardecls[i];
324                 buf ~= vd.name.toString();
325                 if(vd.init)
326                 {
327                     buf ~= " = ";
328                     vd.init.toBuffer(buf);
329                 }
330             }
331             buf ~= ";\n";
332         }
333     }
334 
335     override void toIR(IRstate *irs)
336     {
337         uint i;
338         uint ret;
339 
340         if(vardecls.length)
341         {
342             uint marksave;
343 
344             marksave = irs.mark();
345             ret = irs.alloc(1);
346 
347             for(i = 0; i < vardecls.length; i++)
348             {
349                 VarDeclaration vd;
350 
351                 vd = vardecls[i];
352 
353                 // This works like assignment statements:
354                 //	name = init;
355                 IR property;
356 
357                 if(vd.init)
358                 {
359                     vd.init.toIR(irs, ret);
360                     property.id = Identifier.build(vd.name.toString());
361                     irs.gen2(loc, IRputthis, ret, property.index);
362                 }
363             }
364             irs.release(marksave);
365             vardecls[] = null;          // help gc
366         }
367     }
368 }
369 
370 /******************************** BlockStatement ***************************/
371 
372 class BlockStatement : Statement
373 {
374     TopStatement[] statements;
375 
376     this(Loc loc)
377     {
378         super(loc);
379     }
380 
381     override Statement semantic(Scope *sc)
382     {
383         uint i;
384 
385         //writefln("BlockStatement.semantic()");
386         for(i = 0; i < statements.length; i++)
387         {
388             TopStatement s;
389 
390             s = statements[i];
391             assert(s);
392             statements[i] = s.semantic(sc);
393         }
394 
395         return this;
396     }
397 
398     override TopStatement ImpliedReturn()
399     {
400         uint i = statements.length;
401 
402         if(i)
403         {
404             TopStatement ts = statements[i - 1];
405             ts = ts.ImpliedReturn();
406             statements[i - 1] = cast(Statement)ts;
407         }
408         return this;
409     }
410 
411 
412     override void toBuffer(ref tchar[] buf)
413     {
414         buf ~= "{\n";
415 
416         foreach(TopStatement s; statements)
417         {
418             s.toBuffer(buf);
419         }
420 
421         buf ~= "}\n";
422     }
423 
424     override void toIR(IRstate *irs)
425     {
426         foreach(TopStatement s; statements)
427         {
428             s.toIR(irs);
429         }
430 
431         // Release to garbage collector
432         statements[] = null;
433         statements = null;
434     }
435 }
436 
437 /******************************** LabelStatement ***************************/
438 
439 class LabelStatement : Statement
440 {
441     Identifier* ident;
442     Statement statement;
443     uint gotoIP;
444     uint breakIP;
445     ScopeStatement scopeContext;
446     Scope whichScope;
447     
448     this(Loc loc, Identifier * ident, Statement statement)
449     {
450         //writef("LabelStatement.LabelStatement(%p, '%s', %p)\n", this, ident.toChars(), statement);
451         super(loc);
452         this.ident = ident;
453         this.statement = statement;
454         gotoIP = ~0u;
455         breakIP = ~0u;
456         scopeContext = null;
457     }
458 
459     override Statement semantic(Scope *sc)
460     {
461         LabelSymbol ls;
462 
463         //writef("LabelStatement.semantic('%ls')\n", ident.toString());
464         scopeContext = sc.scopeContext;
465         whichScope = *sc;
466         ls = sc.searchLabel(ident);
467         if(ls)
468         {
469             // Ignore multiple definition errors
470             //if (ls.statement)
471             //error(sc, "label '%s' is already defined", ident.toString());
472             ls.statement = this;
473         }
474         else
475         {
476             ls = new LabelSymbol(loc, ident, this);
477             sc.insertLabel(ls);
478         }
479         if(statement)
480             statement = statement.semantic(sc);
481         return this;
482     }
483 
484     override TopStatement ImpliedReturn()
485     {
486         if(statement)
487             statement = cast(Statement)statement.ImpliedReturn();
488         return this;
489     }
490 
491     override void toBuffer(ref tchar[] buf)
492     {
493         buf ~= ident.toString();
494         buf ~= ": ";
495         if(statement)
496             statement.toBuffer(buf);
497         else
498             buf ~= '\n';
499     }
500 
501     override void toIR(IRstate *irs)
502     {
503         gotoIP = irs.getIP();
504         statement.toIR(irs);
505         breakIP = irs.getIP();
506     }
507 
508     override uint getGoto()
509     {
510         return gotoIP;
511     }
512 
513     override uint getBreak()
514     {
515         return breakIP;
516     }
517 
518     override uint getContinue()
519     {
520         return statement.getContinue();
521     }
522 
523     override ScopeStatement getScope()
524     {
525         return scopeContext;
526     }
527 }
528 
529 /******************************** IfStatement ***************************/
530 
531 class IfStatement : Statement
532 {
533     Expression condition;
534     Statement ifbody;
535     Statement elsebody;
536 
537     this(Loc loc, Expression condition, Statement ifbody, Statement elsebody)
538     {
539         super(loc);
540         this.condition = condition;
541         this.ifbody = ifbody;
542         this.elsebody = elsebody;
543     }
544 
545     override Statement semantic(Scope *sc)
546     {
547         //writef("IfStatement.semantic(%p)\n", sc);
548         assert(condition);
549         condition = condition.semantic(sc);
550         ifbody = ifbody.semantic(sc);
551         if(elsebody)
552             elsebody = elsebody.semantic(sc);
553 
554         return this;
555     }
556 
557     override TopStatement ImpliedReturn()
558     {
559         assert(condition);
560         ifbody = cast(Statement)ifbody.ImpliedReturn();
561         if(elsebody)
562             elsebody = cast(Statement)elsebody.ImpliedReturn();
563         return this;
564     }
565 
566 
567 
568     override void toIR(IRstate *irs)
569     {
570         uint c;
571         uint u1;
572         uint u2;
573 
574         assert(condition);
575         c = irs.alloc(1);
576         condition.toIR(irs, c);
577         u1 = irs.getIP();
578         irs.gen2(loc, (condition.isBooleanResult() ? IRjfb : IRjf), 0, c);
579         irs.release(c, 1);
580         ifbody.toIR(irs);
581         if(elsebody)
582         {
583             u2 = irs.getIP();
584             irs.gen1(loc, IRjmp, 0);
585             irs.patchJmp(u1, irs.getIP());
586             elsebody.toIR(irs);
587             irs.patchJmp(u2, irs.getIP());
588         }
589         else
590         {
591             irs.patchJmp(u1, irs.getIP());
592         }
593 
594         // Help GC
595         condition = null;
596         ifbody = null;
597         elsebody = null;
598     }
599 }
600 
601 /******************************** SwitchStatement ***************************/
602 
603 class SwitchStatement : Statement
604 {
605     Expression condition;
606     Statement bdy;
607     uint breakIP;
608     ScopeStatement scopeContext;
609 
610     DefaultStatement swdefault;
611     CaseStatement[] cases;
612 
613     this(Loc loc, Expression c, Statement b)
614     {
615         super(loc);
616         condition = c;
617         bdy = b;
618         breakIP = ~0u;
619         scopeContext = null;
620 
621         swdefault = null;
622         cases = null;
623     }
624 
625     override Statement semantic(Scope *sc)
626     {
627         condition = condition.semantic(sc);
628 
629         SwitchStatement switchSave = sc.switchTarget;
630         Statement breakSave = sc.breakTarget;
631 
632         scopeContext = sc.scopeContext;
633         sc.switchTarget = this;
634         sc.breakTarget = this;
635 
636         bdy = bdy.semantic(sc);
637 
638         sc.switchTarget = switchSave;
639         sc.breakTarget = breakSave;
640 
641         return this;
642     }
643 
644     override void toIR(IRstate *irs)
645     {
646         uint c;
647         uint udefault;
648         uint marksave;
649 
650         //writef("SwitchStatement.toIR()\n");
651         marksave = irs.mark();
652         c = irs.alloc(1);
653         condition.toIR(irs, c);
654 
655         // Generate a sequence of cmp-jt
656         // Not the most efficient, but we await a more formal
657         // specification of switch before we attempt to optimize
658 
659         if(cases.length)
660         {
661             uint x;
662 
663             x = irs.alloc(1);
664             for(uint i = 0; i < cases.length; i++)
665             {
666                 CaseStatement cs;
667 
668                 x = irs.alloc(1);
669                 cs = cases[i];
670                 cs.exp.toIR(irs, x);
671                 irs.gen3(loc, IRcid, x, c, x);
672                 cs.patchIP = irs.getIP();
673                 irs.gen2(loc, IRjt, 0, x);
674             }
675         }
676         udefault = irs.getIP();
677         irs.gen1(loc, IRjmp, 0);
678 
679         Statement breakSave = irs.breakTarget;
680         irs.breakTarget = this;
681         bdy.toIR(irs);
682 
683         irs.breakTarget = breakSave;
684         breakIP = irs.getIP();
685 
686         // Patch jump addresses
687         if(cases.length)
688         {
689             for(uint i = 0; i < cases.length; i++)
690             {
691                 CaseStatement cs;
692 
693                 cs = cases[i];
694                 irs.patchJmp(cs.patchIP, cs.caseIP);
695             }
696         }
697         if(swdefault)
698             irs.patchJmp(udefault, swdefault.defaultIP);
699         else
700             irs.patchJmp(udefault, breakIP);
701         irs.release(marksave);
702 
703         // Help gc
704         condition = null;
705         bdy = null;
706     }
707 
708     override uint getBreak()
709     {
710         return breakIP;
711     }
712 
713     override ScopeStatement getScope()
714     {
715         return scopeContext;
716     }
717 }
718 
719 
720 /******************************** CaseStatement ***************************/
721 
722 class CaseStatement : Statement
723 {
724     Expression exp;
725     uint caseIP;
726     uint patchIP;
727 
728     this(Loc loc, Expression exp)
729     {
730         super(loc);
731         this.exp = exp;
732         caseIP = ~0u;
733         patchIP = ~0u;
734     }
735 
736     override Statement semantic(Scope *sc)
737     {
738         //writef("CaseStatement.semantic(%p)\n", sc);
739         exp = exp.semantic(sc);
740         if(sc.switchTarget)
741         {
742             SwitchStatement sw = sc.switchTarget;
743             uint i;
744 
745             // Look for duplicate
746             for(i = 0; i < sw.cases.length; i++)
747             {
748                 CaseStatement cs = sw.cases[i];
749 
750                 if(exp == cs.exp)
751                 {
752                     error(sc, errmsgtbl[ERR_SWITCH_REDUNDANT_CASE], exp.toString());
753                     return null;
754                 }
755             }
756             sw.cases ~= this;
757         }
758         else
759         {
760             error(sc, errmsgtbl[ERR_MISPLACED_SWITCH_CASE], exp.toString());
761             return null;
762         }
763         return this;
764     }
765 
766     override void toIR(IRstate *irs)
767     {
768         caseIP = irs.getIP();
769     }
770 }
771 
772 /******************************** DefaultStatement ***************************/
773 
774 class DefaultStatement : Statement
775 {
776     uint defaultIP;
777 
778     this(Loc loc)
779     {
780         super(loc);
781         defaultIP = ~0u;
782     }
783 
784     override Statement semantic(Scope *sc)
785     {
786         if(sc.switchTarget)
787         {
788             SwitchStatement sw = sc.switchTarget;
789 
790             if(sw.swdefault)
791             {
792                 error(sc, ERR_SWITCH_REDUNDANT_DEFAULT);
793                 return null;
794             }
795             sw.swdefault = this;
796         }
797         else
798         {
799             error(sc, ERR_MISPLACED_SWITCH_DEFAULT);
800             return null;
801         }
802         return this;
803     }
804 
805     override void toIR(IRstate *irs)
806     {
807         defaultIP = irs.getIP();
808     }
809 }
810 
811 /******************************** DoStatement ***************************/
812 
813 class DoStatement : Statement
814 {
815     Statement bdy;
816     Expression condition;
817     uint breakIP;
818     uint continueIP;
819     ScopeStatement scopeContext;
820 
821     this(Loc loc, Statement b, Expression c)
822     {
823         super(loc);
824         bdy = b;
825         condition = c;
826         breakIP = ~0u;
827         continueIP = ~0u;
828         scopeContext = null;
829     }
830 
831     override Statement semantic(Scope *sc)
832     {
833         Statement continueSave = sc.continueTarget;
834         Statement breakSave = sc.breakTarget;
835 
836         scopeContext = sc.scopeContext;
837         sc.continueTarget = this;
838         sc.breakTarget = this;
839 
840         bdy = bdy.semantic(sc);
841         condition = condition.semantic(sc);
842 
843         sc.continueTarget = continueSave;
844         sc.breakTarget = breakSave;
845 
846         return this;
847     }
848 
849     override TopStatement ImpliedReturn()
850     {
851         if(bdy)
852             bdy = cast(Statement)bdy.ImpliedReturn();
853         return this;
854     }
855 
856     override void toIR(IRstate *irs)
857     {
858         uint c;
859         uint u1;
860         Statement continueSave = irs.continueTarget;
861         Statement breakSave = irs.breakTarget;
862         uint marksave;
863 
864         irs.continueTarget = this;
865         irs.breakTarget = this;
866 
867         marksave = irs.mark();
868         u1 = irs.getIP();
869         bdy.toIR(irs);
870         c = irs.alloc(1);
871         continueIP = irs.getIP();
872         condition.toIR(irs, c);
873         irs.gen2(loc, (condition.isBooleanResult() ? IRjtb : IRjt), u1 - irs.getIP(), c);
874         breakIP = irs.getIP();
875         irs.release(marksave);
876 
877         irs.continueTarget = continueSave;
878         irs.breakTarget = breakSave;
879 
880         // Help GC
881         condition = null;
882         bdy = null;
883     }
884 
885     override uint getBreak()
886     {
887         return breakIP;
888     }
889 
890     override uint getContinue()
891     {
892         return continueIP;
893     }
894 
895     override ScopeStatement getScope()
896     {
897         return scopeContext;
898     }
899 }
900 
901 /******************************** WhileStatement ***************************/
902 
903 class WhileStatement : Statement
904 {
905     Expression condition;
906     Statement bdy;
907     uint breakIP;
908     uint continueIP;
909     ScopeStatement scopeContext;
910 
911     this(Loc loc, Expression c, Statement b)
912     {
913         super(loc);
914         condition = c;
915         bdy = b;
916         breakIP = ~0u;
917         continueIP = ~0u;
918         scopeContext = null;
919     }
920 
921     override Statement semantic(Scope *sc)
922     {
923         Statement continueSave = sc.continueTarget;
924         Statement breakSave = sc.breakTarget;
925 
926         scopeContext = sc.scopeContext;
927         sc.continueTarget = this;
928         sc.breakTarget = this;
929 
930         condition = condition.semantic(sc);
931         bdy = bdy.semantic(sc);
932 
933         sc.continueTarget = continueSave;
934         sc.breakTarget = breakSave;
935 
936         return this;
937     }
938 
939     override TopStatement ImpliedReturn()
940     {
941         if(bdy)
942             bdy = cast(Statement)bdy.ImpliedReturn();
943         return this;
944     }
945 
946     override void toIR(IRstate *irs)
947     {
948         uint c;
949         uint u1;
950         uint u2;
951 
952         Statement continueSave = irs.continueTarget;
953         Statement breakSave = irs.breakTarget;
954         uint marksave = irs.mark();
955 
956         irs.continueTarget = this;
957         irs.breakTarget = this;
958 
959         u1 = irs.getIP();
960         continueIP = u1;
961         c = irs.alloc(1);
962         condition.toIR(irs, c);
963         u2 = irs.getIP();
964         irs.gen2(loc, (condition.isBooleanResult() ? IRjfb : IRjf), 0, c);
965         bdy.toIR(irs);
966         irs.gen1(loc, IRjmp, u1 - irs.getIP());
967         irs.patchJmp(u2, irs.getIP());
968         breakIP = irs.getIP();
969 
970         irs.release(marksave);
971         irs.continueTarget = continueSave;
972         irs.breakTarget = breakSave;
973 
974         // Help GC
975         condition = null;
976         bdy = null;
977     }
978 
979     override uint getBreak()
980     {
981         return breakIP;
982     }
983 
984     override uint getContinue()
985     {
986         return continueIP;
987     }
988 
989     override ScopeStatement getScope()
990     {
991         return scopeContext;
992     }
993 }
994 
995 /******************************** ForStatement ***************************/
996 
997 class ForStatement : Statement
998 {
999     Statement init;
1000     Expression condition;
1001     Expression increment;
1002     Statement bdy;
1003     uint breakIP;
1004     uint continueIP;
1005     ScopeStatement scopeContext;
1006 
1007     this(Loc loc, Statement init, Expression condition, Expression increment, Statement bdy)
1008     {
1009         super(loc);
1010         this.init = init;
1011         this.condition = condition;
1012         this.increment = increment;
1013         this.bdy = bdy;
1014         breakIP = ~0u;
1015         continueIP = ~0u;
1016         scopeContext = null;
1017     }
1018 
1019     override Statement semantic(Scope *sc)
1020     {
1021         Statement continueSave = sc.continueTarget;
1022         Statement breakSave = sc.breakTarget;
1023 
1024         if(init)
1025             init = init.semantic(sc);
1026         if(condition)
1027             condition = condition.semantic(sc);
1028         if(increment)
1029             increment = increment.semantic(sc);
1030 
1031         scopeContext = sc.scopeContext;
1032         sc.continueTarget = this;
1033         sc.breakTarget = this;
1034 
1035         bdy = bdy.semantic(sc);
1036 
1037         sc.continueTarget = continueSave;
1038         sc.breakTarget = breakSave;
1039 
1040         return this;
1041     }
1042 
1043     override TopStatement ImpliedReturn()
1044     {
1045         if(bdy)
1046             bdy = cast(Statement)bdy.ImpliedReturn();
1047         return this;
1048     }
1049 
1050     override void toIR(IRstate *irs)
1051     {
1052         uint u1;
1053         uint u2 = 0;    // unneeded initialization keeps lint happy
1054 
1055         Statement continueSave = irs.continueTarget;
1056         Statement breakSave = irs.breakTarget;
1057         uint marksave = irs.mark();
1058 
1059         irs.continueTarget = this;
1060         irs.breakTarget = this;
1061 
1062         if(init)
1063             init.toIR(irs);
1064         u1 = irs.getIP();
1065         if(condition)
1066         {
1067             if(condition.op == TOKless || condition.op == TOKlessequal)
1068             {
1069                 BinExp be = cast(BinExp)condition;
1070                 RealExpression re;
1071                 uint b;
1072                 uint c;
1073 
1074                 b = irs.alloc(1);
1075                 be.e1.toIR(irs, b);
1076                 re = cast(RealExpression )be.e2;
1077                 if(be.e2.op == TOKreal && !isnan(re.value))
1078                 {
1079                     u2 = irs.getIP();
1080                     irs.gen(loc, (condition.op == TOKless) ? IRjltc : IRjlec, 4, 0, b, re.value);
1081                 }
1082                 else
1083                 {
1084                     c = irs.alloc(1);
1085                     be.e2.toIR(irs, c);
1086                     u2 = irs.getIP();
1087                     irs.gen3(loc, (condition.op == TOKless) ? IRjlt : IRjle, 0, b, c);
1088                 }
1089             }
1090             else
1091             {
1092                 uint c;
1093 
1094                 c = irs.alloc(1);
1095                 condition.toIR(irs, c);
1096                 u2 = irs.getIP();
1097                 irs.gen2(loc, (condition.isBooleanResult() ? IRjfb : IRjf), 0, c);
1098             }
1099         }
1100         bdy.toIR(irs);
1101         continueIP = irs.getIP();
1102         if(increment)
1103             increment.toIR(irs, 0);
1104         irs.gen1(loc, IRjmp, u1 - irs.getIP());
1105         if(condition)
1106             irs.patchJmp(u2, irs.getIP());
1107 
1108         breakIP = irs.getIP();
1109 
1110         irs.release(marksave);
1111         irs.continueTarget = continueSave;
1112         irs.breakTarget = breakSave;
1113 
1114         // Help GC
1115         init = null;
1116         condition = null;
1117         bdy = null;
1118         increment = null;
1119     }
1120 
1121     override uint getBreak()
1122     {
1123         return breakIP;
1124     }
1125 
1126     override uint getContinue()
1127     {
1128         return continueIP;
1129     }
1130 
1131     override ScopeStatement getScope()
1132     {
1133         return scopeContext;
1134     }
1135 }
1136 
1137 /******************************** ForInStatement ***************************/
1138 
1139 class ForInStatement : Statement
1140 {
1141     Statement init;
1142     Expression inexp;
1143     Statement bdy;
1144     uint breakIP;
1145     uint continueIP;
1146     ScopeStatement scopeContext;
1147 
1148     this(Loc loc, Statement init, Expression inexp, Statement bdy)
1149     {
1150         super(loc);
1151         this.init = init;
1152         this.inexp = inexp;
1153         this.bdy = bdy;
1154         breakIP = ~0u;
1155         continueIP = ~0u;
1156         scopeContext = null;
1157     }
1158 
1159     override Statement semantic(Scope *sc)
1160     {
1161         Statement continueSave = sc.continueTarget;
1162         Statement breakSave = sc.breakTarget;
1163 
1164         init = init.semantic(sc);
1165 
1166         if(init.st == EXPSTATEMENT)
1167         {
1168             ExpStatement es;
1169 
1170             es = cast(ExpStatement)(init);
1171             es.exp.checkLvalue(sc);
1172         }
1173         else if(init.st == VARSTATEMENT)
1174         {
1175         }
1176         else
1177         {
1178             error(sc, ERR_INIT_NOT_EXPRESSION);
1179             return null;
1180         }
1181 
1182         inexp = inexp.semantic(sc);
1183 
1184         scopeContext = sc.scopeContext;
1185         sc.continueTarget = this;
1186         sc.breakTarget = this;
1187 
1188         bdy = bdy.semantic(sc);
1189 
1190         sc.continueTarget = continueSave;
1191         sc.breakTarget = breakSave;
1192 
1193         return this;
1194     }
1195 
1196     override TopStatement ImpliedReturn()
1197     {
1198         bdy = cast(Statement)bdy.ImpliedReturn();
1199         return this;
1200     }
1201 
1202     override void toIR(IRstate *irs)
1203     {
1204         uint e;
1205         uint iter;
1206         ExpStatement es;
1207         VarStatement vs;
1208         uint base;
1209         IR property;
1210         int opoff;
1211         uint marksave = irs.mark();
1212 
1213         e = irs.alloc(1);
1214         inexp.toIR(irs, e);
1215         iter = irs.alloc(1);
1216         irs.gen2(loc, IRiter, iter, e);
1217 
1218         Statement continueSave = irs.continueTarget;
1219         Statement breakSave = irs.breakTarget;
1220 
1221         irs.continueTarget = this;
1222         irs.breakTarget = this;
1223 
1224         if(init.st == EXPSTATEMENT)
1225         {
1226             es = cast(ExpStatement)(init);
1227             es.exp.toLvalue(irs, base, &property, opoff);
1228         }
1229         else if(init.st == VARSTATEMENT)
1230         {
1231             VarDeclaration vd;
1232 
1233             vs = cast(VarStatement)(init);
1234             assert(vs.vardecls.length == 1);
1235             vd = vs.vardecls[0];
1236 
1237             property.id = Identifier.build(vd.name.toString());
1238             opoff = 2;
1239             base = ~0u;
1240         }
1241         else
1242         {   // Error already reported by semantic()
1243             return;
1244         }
1245 
1246         continueIP = irs.getIP();
1247         if(opoff == 2)
1248             irs.gen3(loc, IRnextscope, 0, property.index, iter);
1249         else
1250             irs.gen(loc, IRnext + opoff, 4, 0, base, property.index, iter);
1251         bdy.toIR(irs);
1252         irs.gen1(loc, IRjmp, continueIP - irs.getIP());
1253         irs.patchJmp(continueIP, irs.getIP());
1254 
1255         breakIP = irs.getIP();
1256 
1257         irs.continueTarget = continueSave;
1258         irs.breakTarget = breakSave;
1259         irs.release(marksave);
1260 
1261         // Help GC
1262         init = null;
1263         inexp = null;
1264         bdy = null;
1265     }
1266 
1267     override uint getBreak()
1268     {
1269         return breakIP;
1270     }
1271 
1272     override uint getContinue()
1273     {
1274         return continueIP;
1275     }
1276 
1277     override ScopeStatement getScope()
1278     {
1279         return scopeContext;
1280     }
1281 }
1282 
1283 /******************************** ScopeStatement ***************************/
1284 
1285 class ScopeStatement : Statement
1286 {
1287     ScopeStatement enclosingScope;
1288     int depth;                  // syntactical nesting level of ScopeStatement's
1289     int npops;                  // how many items added to scope chain
1290 
1291     this(Loc loc)
1292     {
1293         super(loc);
1294         enclosingScope = null;
1295         depth = 1;
1296         npops = 1;
1297     }
1298 }
1299 
1300 /******************************** WithStatement ***************************/
1301 
1302 class WithStatement : ScopeStatement
1303 {
1304     Expression exp;
1305     Statement bdy;
1306 
1307     this(Loc loc, Expression exp, Statement bdy)
1308     {
1309         super(loc);
1310         this.exp = exp;
1311         this.bdy = bdy;
1312     }
1313 
1314     override Statement semantic(Scope *sc)
1315     {
1316         exp = exp.semantic(sc);
1317 
1318         enclosingScope = sc.scopeContext;
1319         sc.scopeContext = this;
1320 
1321         // So enclosing FunctionDeclaration knows how deep the With's
1322         // can nest
1323         if(enclosingScope)
1324             depth = enclosingScope.depth + 1;
1325         if(depth > sc.funcdef.withdepth)
1326             sc.funcdef.withdepth = depth;
1327 
1328         sc.nestDepth++;
1329         bdy = bdy.semantic(sc);
1330         sc.nestDepth--;
1331 
1332         sc.scopeContext = enclosingScope;
1333         return this;
1334     }
1335 
1336     override TopStatement ImpliedReturn()
1337     {
1338         bdy = cast(Statement)bdy.ImpliedReturn();
1339         return this;
1340     }
1341 
1342 
1343 
1344     override void toIR(IRstate *irs)
1345     {
1346         uint c;
1347         uint marksave = irs.mark();
1348 
1349         irs.scopeContext = this;
1350 
1351         c = irs.alloc(1);
1352         exp.toIR(irs, c);
1353         irs.gen1(loc, IRpush, c);
1354         bdy.toIR(irs);
1355         irs.gen0(loc, IRpop);
1356 
1357         irs.scopeContext = enclosingScope;
1358         irs.release(marksave);
1359 
1360         // Help GC
1361         exp = null;
1362         bdy = null;
1363     }
1364 }
1365 
1366 /******************************** ContinueStatement ***************************/
1367 
1368 class ContinueStatement : Statement
1369 {
1370     Identifier *ident;
1371     Statement target;
1372 
1373     this(Loc loc, Identifier * ident)
1374     {
1375         super(loc);
1376         this.ident = ident;
1377         target = null;
1378     }
1379 
1380     override Statement semantic(Scope *sc)
1381     {
1382         if(ident == null)
1383         {
1384             target = sc.continueTarget;
1385             if(!target)
1386             {
1387                 error(sc, ERR_MISPLACED_CONTINUE);
1388                 return null;
1389             }
1390         }
1391         else
1392         {
1393             LabelSymbol ls;
1394 
1395             ls = sc.searchLabel(ident);
1396             if(!ls || !ls.statement)
1397             {
1398                 error(sc, errmsgtbl[ERR_UNDEFINED_STATEMENT_LABEL], ident.toString());
1399                 return null;
1400             }
1401             else
1402                 target = ls.statement;
1403         }
1404         return this;
1405     }
1406 
1407     override void toIR(IRstate *irs)
1408     {
1409         ScopeStatement w;
1410         ScopeStatement tw;
1411 
1412         tw = target.getScope();
1413         for(w = irs.scopeContext; !(w is tw); w = w.enclosingScope)
1414         {
1415             assert(w);
1416             irs.pops(w.npops);
1417         }
1418         irs.addFixup(irs.getIP());
1419         irs.gen1(loc, IRjmp, cast(uint)cast(void*)this);
1420     }
1421 
1422     override uint getTarget()
1423     {
1424         assert(target);
1425         return target.getContinue();
1426     }
1427 }
1428 
1429 /******************************** BreakStatement ***************************/
1430 
1431 class BreakStatement : Statement
1432 {
1433     Identifier *ident;
1434     Statement target;
1435 
1436     this(Loc loc, Identifier * ident)
1437     {
1438         super(loc);
1439         this.ident = ident;
1440         target = null;
1441     }
1442 
1443     override Statement semantic(Scope *sc)
1444     {
1445 //	writef("BreakStatement.semantic(%p)\n", sc);
1446         if(ident == null)
1447         {
1448             target = sc.breakTarget;
1449             if(!target)
1450             {
1451                 error(sc, ERR_MISPLACED_BREAK);
1452                 return null;
1453             }
1454         }
1455         else
1456         {
1457             LabelSymbol ls;
1458 
1459             ls = sc.searchLabel(ident);
1460             if(!ls || !ls.statement)
1461             {
1462                 error(sc, errmsgtbl[ERR_UNDEFINED_STATEMENT_LABEL], ident.toString());
1463                 return null;
1464             }
1465             else if(!sc.breakTarget)
1466             {
1467                 error(sc, errmsgtbl[ERR_MISPLACED_BREAK]);
1468             }
1469             else{
1470                 //Scope* s;
1471                 //for(s = sc; s && s != ls.statement.whichScope; s = s.enclosing){ }
1472                 if(ls.statement.whichScope == *sc)
1473                     error(sc,errmsgtbl[ERR_CANT_BREAK_INTERNAL],ls.ident.value..string);
1474                 target = ls.statement;
1475             }                
1476         }
1477         return this;
1478     }
1479 
1480     override void toIR(IRstate *irs)
1481     {
1482         ScopeStatement w;
1483         ScopeStatement tw;
1484 
1485         assert(target);
1486         tw = target.getScope();
1487         for(w = irs.scopeContext; !(w is tw); w = w.enclosingScope)
1488         {
1489             assert(w);
1490             irs.pops(w.npops);
1491         }
1492 
1493         irs.addFixup(irs.getIP());
1494         irs.gen1(loc, IRjmp, cast(uint)cast(void*)this);
1495     }
1496 
1497     override uint getTarget()
1498     {
1499         assert(target);
1500         return target.getBreak();
1501     }
1502 }
1503 
1504 /******************************** GotoStatement ***************************/
1505 
1506 class GotoStatement : Statement
1507 {
1508     Identifier *ident;
1509     LabelSymbol label;
1510 
1511     this(Loc loc, Identifier * ident)
1512     {
1513         super(loc);
1514         this.ident = ident;
1515         label = null;
1516     }
1517 
1518     override Statement semantic(Scope *sc)
1519     {
1520         LabelSymbol ls;
1521 
1522         ls = sc.searchLabel(ident);
1523         if(!ls)
1524         {
1525             ls = new LabelSymbol(loc, ident, null);
1526             sc.insertLabel(ls);
1527         }
1528         label = ls;
1529         return this;
1530     }
1531 
1532     override void toIR(IRstate *irs)
1533     {
1534         assert(label);
1535 
1536         // Determine how many with pops we need to do
1537         for(ScopeStatement w = irs.scopeContext;; w = w.enclosingScope)
1538         {
1539             if(!w)
1540             {
1541                 if(label.statement.scopeContext)
1542                 {
1543                     assert(0); // BUG: should do next statement instead
1544                     //script.error(errmsgtbl[ERR_GOTO_INTO_WITH]);
1545                 }
1546                 break;
1547             }
1548             if(w is label.statement.scopeContext)
1549                 break;
1550             irs.pops(w.npops);
1551         }
1552 
1553         irs.addFixup(irs.getIP());
1554         irs.gen1(loc, IRjmp, cast(uint)cast(void*)this);
1555     }
1556 
1557     override uint getTarget()
1558     {
1559         return label.statement.getGoto();
1560     }
1561 }
1562 
1563 /******************************** ReturnStatement ***************************/
1564 
1565 class ReturnStatement : Statement
1566 {
1567     Expression exp;
1568 
1569     this(Loc loc, Expression exp)
1570     {
1571         super(loc);
1572         this.exp = exp;
1573     }
1574 
1575     override Statement semantic(Scope *sc)
1576     {
1577         if(exp)
1578             exp = exp.semantic(sc);
1579 
1580         // Don't allow return from eval functions or global function
1581         if(sc.funcdef.iseval || sc.funcdef.isglobal)
1582             error(sc, ERR_MISPLACED_RETURN);
1583 
1584         return this;
1585     }
1586 
1587     override void toBuffer(ref tchar[] buf)
1588     {
1589         //writef("ReturnStatement.toBuffer()\n");
1590         buf ~= "return ";
1591         if(exp)
1592             exp.toBuffer(buf);
1593         buf ~= ";\n";
1594     }
1595 
1596     override void toIR(IRstate *irs)
1597     {
1598         ScopeStatement w;
1599         int npops;
1600 
1601         npops = 0;
1602         for(w = irs.scopeContext; w; w = w.enclosingScope)
1603             npops += w.npops;
1604 
1605         if(exp)
1606         {
1607             uint e;
1608 
1609             e = irs.alloc(1);
1610             exp.toIR(irs, e);
1611             if(npops)
1612             {
1613                 irs.gen1(loc, IRimpret, e);
1614                 irs.pops(npops);
1615                 irs.gen0(loc, IRret);
1616             }
1617             else
1618                 irs.gen1(loc, IRretexp, e);
1619             irs.release(e, 1);
1620         }
1621         else
1622         {
1623             if(npops)
1624                 irs.pops(npops);
1625             irs.gen0(loc, IRret);
1626         }
1627 
1628         // Help GC
1629         exp = null;
1630     }
1631 }
1632 
1633 /******************************** ImpliedReturnStatement ***************************/
1634 
1635 // Same as ReturnStatement, except that the return value is set but the
1636 // function does not actually return. Useful for setting the return
1637 // value for loop bodies.
1638 
1639 class ImpliedReturnStatement : Statement
1640 {
1641     Expression exp;
1642 
1643     this(Loc loc, Expression exp)
1644     {
1645         super(loc);
1646         this.exp = exp;
1647     }
1648 
1649     override Statement semantic(Scope *sc)
1650     {
1651         if(exp)
1652             exp = exp.semantic(sc);
1653         return this;
1654     }
1655 
1656     override void toBuffer(ref tchar[] buf)
1657     {
1658         if(exp)
1659             exp.toBuffer(buf);
1660         buf ~= ";\n";
1661     }
1662 
1663     override void toIR(IRstate *irs)
1664     {
1665         if(exp)
1666         {
1667             uint e;
1668 
1669             e = irs.alloc(1);
1670             exp.toIR(irs, e);
1671             irs.gen1(loc, IRimpret, e);
1672             irs.release(e, 1);
1673 
1674             // Help GC
1675             exp = null;
1676         }
1677     }
1678 }
1679 
1680 /******************************** ThrowStatement ***************************/
1681 
1682 class ThrowStatement : Statement
1683 {
1684     Expression exp;
1685 
1686     this(Loc loc, Expression exp)
1687     {
1688         super(loc);
1689         this.exp = exp;
1690     }
1691 
1692     override Statement semantic(Scope *sc)
1693     {
1694         if(exp)
1695             exp = exp.semantic(sc);
1696         else
1697         {
1698             error(sc, ERR_NO_THROW_EXPRESSION);
1699             return new EmptyStatement(loc);
1700         }
1701         return this;
1702     }
1703 
1704     override void toBuffer(ref tchar[] buf)
1705     {
1706         buf ~= "throw ";
1707         if(exp)
1708             exp.toBuffer(buf);
1709         buf ~= ";\n";
1710     }
1711 
1712     override void toIR(IRstate *irs)
1713     {
1714         uint e;
1715 
1716         assert(exp);
1717         e = irs.alloc(1);
1718         exp.toIR(irs, e);
1719         irs.gen1(loc, IRthrow, e);
1720         irs.release(e, 1);
1721 
1722         // Help GC
1723         exp = null;
1724     }
1725 }
1726 
1727 /******************************** TryStatement ***************************/
1728 
1729 class TryStatement : ScopeStatement
1730 {
1731     Statement bdy;
1732     Identifier* catchident;
1733     Statement catchbdy;
1734     Statement finalbdy;
1735 
1736     this(Loc loc, Statement bdy,
1737          Identifier * catchident, Statement catchbdy,
1738          Statement finalbdy)
1739     {
1740         super(loc);
1741         this.bdy = bdy;
1742         this.catchident = catchident;
1743         this.catchbdy = catchbdy;
1744         this.finalbdy = finalbdy;
1745         if(catchbdy && finalbdy)
1746             npops = 2;          // 2 items in scope chain
1747     }
1748 
1749     override Statement semantic(Scope *sc)
1750     {
1751         enclosingScope = sc.scopeContext;
1752         sc.scopeContext = this;
1753 
1754         // So enclosing FunctionDeclaration knows how deep the With's
1755         // can nest
1756         if(enclosingScope)
1757             depth = enclosingScope.depth + 1;
1758         if(depth > sc.funcdef.withdepth)
1759             sc.funcdef.withdepth = depth;
1760 
1761         bdy.semantic(sc);
1762         if(catchbdy)
1763             catchbdy.semantic(sc);
1764         if(finalbdy)
1765             finalbdy.semantic(sc);
1766 
1767         sc.scopeContext = enclosingScope;
1768         return this;
1769     }
1770 
1771     override void toBuffer(ref tchar[] buf)
1772     {
1773         buf ~= "try\n";
1774         bdy.toBuffer(buf);
1775         if(catchident)
1776         {
1777             buf ~= "catch (" ~
1778             catchident.toString() ~
1779             ")\n";
1780         }
1781         if(catchbdy)
1782             catchbdy.toBuffer(buf);
1783         if(finalbdy)
1784         {
1785             buf ~= "finally\n";
1786             finalbdy.toBuffer(buf);
1787         }
1788     }
1789 
1790     override void toIR(IRstate *irs)
1791     {
1792         uint f;
1793         uint c;
1794         uint e;
1795         uint e2;
1796         uint marksave = irs.mark();
1797 
1798         irs.scopeContext = this;
1799         if(finalbdy)
1800         {
1801             f = irs.getIP();
1802             irs.gen1(loc, IRtryfinally, 0);
1803             if(catchbdy)
1804             {
1805                 c = irs.getIP();
1806                 irs.gen2(loc, IRtrycatch, 0, cast(uint)Identifier.build(catchident.toString()));
1807                 bdy.toIR(irs);
1808                 irs.gen0(loc, IRpop);           // remove catch clause
1809                 irs.gen0(loc, IRpop);           // call finalbdy
1810 
1811                 e = irs.getIP();
1812                 irs.gen1(loc, IRjmp, 0);
1813                 irs.patchJmp(c, irs.getIP());
1814                 catchbdy.toIR(irs);
1815                 irs.gen0(loc, IRpop);           // remove catch object
1816                 irs.gen0(loc, IRpop);           // call finalbdy code
1817                 e2 = irs.getIP();
1818                 irs.gen1(loc, IRjmp, 0);        // jmp past finalbdy
1819 
1820                 irs.patchJmp(f, irs.getIP());
1821                 irs.scopeContext = enclosingScope;
1822                 finalbdy.toIR(irs);
1823                 irs.gen0(loc, IRfinallyret);
1824                 irs.patchJmp(e, irs.getIP());
1825                 irs.patchJmp(e2, irs.getIP());
1826             }
1827             else // finalbdy only
1828             {
1829                 bdy.toIR(irs);
1830                 irs.gen0(loc, IRpop);
1831                 e = irs.getIP();
1832                 irs.gen1(loc, IRjmp, 0);
1833                 irs.patchJmp(f, irs.getIP());
1834                 irs.scopeContext = enclosingScope;
1835                 finalbdy.toIR(irs);
1836                 irs.gen0(loc, IRfinallyret);
1837                 irs.patchJmp(e, irs.getIP());
1838             }
1839         }
1840         else // catchbdy only
1841         {
1842             c = irs.getIP();
1843             irs.gen2(loc, IRtrycatch, 0, cast(uint)Identifier.build(catchident.toString()));
1844             bdy.toIR(irs);
1845             irs.gen0(loc, IRpop);
1846             e = irs.getIP();
1847             irs.gen1(loc, IRjmp, 0);
1848             irs.patchJmp(c, irs.getIP());
1849             catchbdy.toIR(irs);
1850             irs.gen0(loc, IRpop);
1851             irs.patchJmp(e, irs.getIP());
1852         }
1853         irs.scopeContext = enclosingScope;
1854         irs.release(marksave);
1855 
1856         // Help GC
1857         bdy = null;
1858         catchident = null;
1859         catchbdy = null;
1860         finalbdy = null;
1861     }
1862 }