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