1 // This file is part of Visual D
2 //
3 // Visual D integrates the D programming language into Visual Studio
4 // Copyright (c) 2010-2011 by Rainer Schuetze, All Rights Reserved
5 //
6 // Distributed under the Boost Software License, Version 1.0.
7 // See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt
8 //
9 // interpret: return null to indicate that execution should continue
10 //            return special values for program flow control
11 //            return normal values for returning values
12 //
13 module vdc.ast.stmt;
14 
15 import vdc.util;
16 import vdc.lexer;
17 import vdc.ast.node;
18 import vdc.ast.expr;
19 import vdc.ast.decl;
20 import vdc.ast.type;
21 import vdc.ast.writer;
22 import vdc.semantic;
23 import vdc.interpret;
24 
25 import vdc.parser.engine;
26 
27 import stdext.util;
28 
29 import std.conv;
30 
31 //Statement:
32 //    [Statement...]
33 class Statement : Node
34 {
35     mixin ForwardCtor!();
36 
37     override Value interpret(Context sc)
38     {
39         foreach(m; members)
40         {
41             Value v = m.interpret(sc);
42             if(v)
43                 return v;
44         }
45         return null;
46     }
47 }
48 
49 class EmptyStatement : Statement
50 {
51     mixin ForwardCtor!();
52 
53     override void toD(CodeWriter writer)
54     {
55         writer(";");
56         writer.nl;
57     }
58 }
59 
60 version(obsolete)
61 {
62 //ScopeStatement:
63 //    ;
64 //    NonEmptyStatement
65 //    ScopeBlockStatement
66 //
67 //ScopeBlockStatement:
68 //    BlockStatement
69 class ScopeStatement : Statement
70 {
71     mixin ForwardCtor!();
72 }
73 
74 //ScopeNonEmptyStatement:
75 //    NonEmptyStatement
76 //    BlockStatement
77 class ScopeNonEmptyStatement : Statement
78 {
79     mixin ForwardCtor!();
80 }
81 
82 //NoScopeNonEmptyStatement:
83 //    NonEmptyStatement
84 //    BlockStatement
85 class NoScopeNonEmptyStatement : ScopeNonEmptyStatement
86 {
87     mixin ForwardCtor!();
88 }
89 
90 //NoScopeStatement:
91 //    ;
92 //    NonEmptyStatement
93 //    BlockStatement
94 class NoScopeStatement : ScopeStatement
95 {
96     mixin ForwardCtor!();
97 }
98 
99 //NonEmptyStatement:
100 //    LabeledStatement
101 //    ExpressionStatement
102 //    DeclarationStatement
103 //    IfStatement
104 //    WhileStatement
105 //    DoStatement
106 //    ForStatement
107 //    ForeachStatement
108 //    SwitchStatement
109 //    FinalSwitchStatement
110 //    CaseStatement
111 //    CaseRangeStatement
112 //    DefaultStatement
113 //    ContinueStatement
114 //    BreakStatement
115 //    ReturnStatement
116 //    GotoStatement
117 //    WithStatement
118 //    SynchronizedStatement
119 //    VolatileStatement
120 //    TryStatement
121 //    ScopeGuardStatement
122 //    ThrowStatement
123 //    AsmStatement
124 //    PragmaStatement
125 //    MixinStatement
126 //    ForeachRangeStatement
127 //    ConditionalStatement
128 //    StaticAssert
129 //    TemplateMixin
130 class NonEmptyStatement : Statement
131 {
132     mixin ForwardCtor!();
133 }
134 } // version(obsolete)
135 
136 //LabeledStatement:
137 //    Identifier : NoScopeStatement
138 class LabeledStatement : Statement
139 {
140     string ident;
141 
142     Statement getStatement() { return getMember!Statement(0); }
143 
144     this() {} // default constructor needed for clone()
145 
146     this(Token tok)
147     {
148         super(tok);
149         ident = tok.txt;
150     }
151 
152     override LabeledStatement clone()
153     {
154         LabeledStatement n = static_cast!LabeledStatement(super.clone());
155         n.ident = ident;
156         return n;
157     }
158     override bool compare(const(Node) n) const
159     {
160         if(!super.compare(n))
161             return false;
162 
163         auto tn = static_cast!(typeof(this))(n);
164         return tn.ident == ident;
165     }
166 
167     override void toD(CodeWriter writer)
168     {
169         {
170             CodeIndenter indent = CodeIndenter(writer, -1);
171             writer.writeIdentifier(ident);
172             writer(":");
173             writer.nl;
174         }
175         writer(getStatement());
176     }
177 }
178 
179 //BlockStatement:
180 //    { }
181 //    { StatementList }
182 //
183 //StatementList:
184 //    Statement
185 //    Statement StatementList
186 class BlockStatement : Statement
187 {
188     mixin ForwardCtor!();
189 
190     override void toD(CodeWriter writer)
191     {
192         writer("{");
193         writer.nl;
194         {
195             CodeIndenter indent = CodeIndenter(writer);
196             foreach(m; members)
197                 writer(m);
198         }
199         writer("}");
200         writer.nl;
201     }
202 
203     override bool createsScope() const { return true; }
204 
205     override void _semantic(Scope sc)
206     {
207         // TODO: TemplateParameterList, Constraint
208         if(members.length > 0)
209         {
210             sc = enterScope(sc);
211             super._semantic(sc);
212             sc = sc.pop();
213         }
214     }
215 
216 }
217 
218 //ExpressionStatement:
219 //    [Expression]
220 class ExpressionStatement : Statement
221 {
222     mixin ForwardCtor!();
223 
224     override void toD(CodeWriter writer)
225     {
226         writer(getMember(0), ";");
227         writer.nl;
228     }
229 
230     override Value interpret(Context sc)
231     {
232         getMember(0).interpret(sc);
233         return null;
234     }
235 }
236 
237 //DeclarationStatement:
238 //    [Decl]
239 class DeclarationStatement : Statement
240 {
241     mixin ForwardCtor!();
242 
243     override void toD(CodeWriter writer)
244     {
245         writer(getMember(0));
246     }
247 
248     override Node[] expandNonScopeBlock(Scope sc, Node[] athis)
249     {
250         Node n = getMember(0);
251         Node[1] nthis = [ n ];
252         Node[] nm = n.expandNonScopeBlock(sc, nthis);
253         if(nm.length == 1 && nm[0] == n)
254             return athis;
255 
256         Node[] decls;
257         foreach(m; nm)
258         {
259             auto decl = new DeclarationStatement(id, span);
260             decl.addMember(m);
261             decls ~= decl;
262         }
263         return decls;
264     }
265 
266     override void addSymbols(Scope sc)
267     {
268         addMemberSymbols(sc);
269     }
270 
271     override void _semantic(Scope sc)
272     {
273         auto decl = getMember(0);
274         decl.addSymbols(sc); // symbols might already be referenced in an initializer
275         super._semantic(sc);
276         if(decl.attr & Attr_Static)
277         {
278             Context ctx = new Context(nullContext);
279             ctx.scop = sc;
280             initValues(ctx, false);
281         }
282     }
283 
284     override Value interpret(Context sc)
285     {
286         auto decl = getMember(0);
287         if(!(decl.attr & Attr_Static))
288             initValues(sc, true);
289         return null;
290     }
291 
292     void initValues(Context sc, bool reinit)
293     {
294         auto decl = cast(Decl)getMember(0);
295         if(!decl)
296             return; // classes, enums, etc
297         //if(decl.getFunctionBody())
298         //    return; // nothing to do for local functions
299 
300         auto decls = decl.getDeclarators();
301         for(int n = 0; n < decls.members.length; n++)
302         {
303             auto d = decls.getDeclarator(n);
304             if(reinit)
305             {
306                 d.value = null;
307                 d.interpretReinit(sc);
308             }
309             else
310                 d.interpret(sc);
311         }
312     }
313 }
314 
315 //ImportStatement:
316 //    [ImportDeclaration]
317 class ImportStatement : Statement
318 {
319     mixin ForwardCtor!();
320 
321     override void toD(CodeWriter writer)
322     {
323         getMember(0).toD(writer);
324     }
325 
326     override Value interpret(Context sc)
327     {
328         return null;
329     }
330 }
331 
332 //IfStatement:
333 //    if ( IfCondition ) ThenStatement
334 //    if ( IfCondition ) ThenStatement else ElseStatement
335 //
336 //IfCondition:
337 //    Expression
338 //    auto Identifier = Expression
339 //    Declarator = Expression
340 //
341 //ThenStatement:
342 //    ScopeNonEmptyStatement
343 //
344 //ElseStatement:
345 //    ScopeNonEmptyStatement
346 class IfStatement : Statement
347 {
348     mixin ForwardCtor!();
349 
350     override void toD(CodeWriter writer)
351     {
352         writer("if(", getMember(0), ")");
353         writer.nl;
354         {
355             CodeIndenter indent = CodeIndenter(writer);
356             writer(getMember(1));
357         }
358         if(members.length > 2)
359         {
360             writer("else");
361             writer.nl;
362             {
363                 CodeIndenter indent = CodeIndenter(writer);
364                 writer(getMember(2));
365             }
366         }
367     }
368 
369     override bool createsScope() const { return true; }
370 
371     override Value interpret(Context sc)
372     {
373         Value cond = getMember(0).interpret(sc);
374         if(cond.toBool())
375         {
376             if(Value v = getMember(1).interpret(sc))
377                 return v;
378         }
379         else if(members.length > 2)
380         {
381             if(Value v = getMember(2).interpret(sc))
382                 return v;
383         }
384         return null;
385     }
386 }
387 
388 //WhileStatement:
389 //    while ( Expression ) ScopeNonEmptyStatement
390 class WhileStatement : Statement
391 {
392     mixin ForwardCtor!();
393 
394     override bool createsScope() const { return true; }
395 
396     override void toD(CodeWriter writer)
397     {
398         writer("while(", getMember(0), ")");
399         writer.nl;
400         {
401             CodeIndenter indent = CodeIndenter(writer);
402             writer(getMember(1));
403         }
404     }
405 
406     override Value interpret(Context sc)
407     {
408         while(getMember(0).interpret(sc).toBool())
409         {
410             if(Value v = getMember(1).interpret(sc))
411             {
412                 if(auto bv = cast(BreakValue)v)
413                 {
414                     if(!bv.label)
415                         break;
416                     if(auto ls = cast(LabeledStatement)parent)
417                         if(ls.ident == bv.label)
418                             break;
419                 }
420                 else if(auto cv = cast(ContinueValue)v)
421                 {
422                     if(!cv.label)
423                         continue;
424                     if(auto ls = cast(LabeledStatement)parent)
425                         if(ls.ident == cv.label)
426                             continue;
427                 }
428                 return v;
429             }
430         }
431         return null;
432     }
433 }
434 
435 //DoStatement:
436 //    do ScopeNonEmptyStatement while ( Expression )
437 class DoStatement : Statement
438 {
439     mixin ForwardCtor!();
440 
441     override bool createsScope() const { return true; }
442 
443     override void toD(CodeWriter writer)
444     {
445         writer("do");
446         writer.nl;
447         {
448             CodeIndenter indent = CodeIndenter(writer);
449             writer(getMember(0));
450         }
451         writer("while(", getMember(1), ")");
452         writer.nl;
453     }
454 
455     override Value interpret(Context sc)
456     {
457         do
458         {
459             if(Value v = getMember(0).interpret(sc))
460             {
461                 if(auto bv = cast(BreakValue)v)
462                 {
463                     if(!bv.label)
464                         break;
465                     if(auto ls = cast(LabeledStatement)parent)
466                         if(ls.ident == bv.label)
467                             break;
468                 }
469                 else if(auto cv = cast(ContinueValue)v)
470                 {
471                     if(!cv.label)
472                         continue;
473                     if(auto ls = cast(LabeledStatement)parent)
474                         if(ls.ident == cv.label)
475                             continue;
476                 }
477                 return v;
478             }
479         }
480         while(getMember(1).interpret(sc).toBool());
481         return null;
482     }
483 }
484 
485 //ForStatement:
486 //    for ( Initialize Test ; Increment ) ScopeNonEmptyStatement
487 //Initialize:
488 //    ;
489 //    NoScopeNonEmptyStatement
490 //
491 //Test:
492 //    Expression_opt
493 //
494 //Increment:
495 //    Expression_opt
496 //
497 class ForStatement : Statement
498 {
499     mixin ForwardCtor!();
500 
501     override bool createsScope() const { return true; }
502 
503     override void toD(CodeWriter writer)
504     {
505         writer("for(", getMember(0), getMember(1), "; ", getMember(2), ")");
506         writer.nl;
507         {
508             CodeIndenter indent = CodeIndenter(writer);
509             writer(getMember(3));
510         }
511     }
512 
513     override Value interpret(Context sc)
514     {
515         for(getMember(0).interpret(sc); getMember(1).interpret(sc).toBool();
516             getMember(2).interpret(sc))
517         {
518             if(Value v = getMember(3).interpret(sc))
519             {
520                 if(auto bv = cast(BreakValue)v)
521                 {
522                     if(!bv.label)
523                         break;
524                     if(auto ls = cast(LabeledStatement)parent)
525                         if(ls.ident == bv.label)
526                             break;
527                 }
528                 else if(auto cv = cast(ContinueValue)v)
529                 {
530                     if(!cv.label)
531                         continue;
532                     if(auto ls = cast(LabeledStatement)parent)
533                         if(ls.ident == cv.label)
534                             continue;
535                 }
536                 return v;
537             }
538         }
539         return null;
540     }
541 }
542 
543 //ForeachStatement:
544 //    Foreach ( ForeachTypeList ; Aggregate ) NoScopeNonEmptyStatement
545 //
546 //Foreach:
547 //    foreach
548 //    foreach_reverse
549 //
550 //ForeachTypeList:
551 //    ForeachType
552 //    ForeachType , ForeachTypeList
553 //
554 //ForeachType:
555 //    ref Type Identifier
556 //    Type Identifier
557 //    ref Identifier
558 //    Identifier
559 //
560 //Aggregate:
561 //    Expression
562 //
563 //ForeachRangeStatement:
564 //    Foreach ( ForeachType ; LwrExpression .. UprExpression ) ScopeNonEmptyStatement
565 //
566 //LwrExpression:
567 //    Expression
568 //
569 //UprExpression:
570 //    Expression
571 class ForeachStatement : Statement
572 {
573     mixin ForwardCtor!();
574 
575     override bool createsScope() const { return true; }
576 
577     Expression getAggregate() { return getMember!Expression(1); }
578     Expression getLwrExpression() { return getMember!Expression(1); }
579     Expression getUprExpression() { return getMember!Expression(2); }
580 
581     final bool isRangeForeach() const { return members.length > 3; }
582 
583     override void toD(CodeWriter writer)
584     {
585         writer(id, "(", getMember(0), "; ");
586         if(members.length == 3)
587             writer(getMember(1));
588         else
589             writer(getMember(1), " .. ", getMember(2));
590 
591         writer(")");
592         writer.nl;
593         {
594             CodeIndenter indent = CodeIndenter(writer);
595             writer(getMember(members.length - 1));
596         }
597     }
598 
599     override Value interpret(Context sc)
600     {
601         return semanticErrorValue(this, " not implemented.");
602     }
603 }
604 
605 class ForeachTypeList : Node
606 {
607     mixin ForwardCtor!();
608 
609     override void toD(CodeWriter writer)
610     {
611         writer.writeArray(members);
612     }
613 
614     override void addSymbols(Scope sc)
615     {
616         addMemberSymbols(sc);
617     }
618 }
619 
620 class ForeachType : Node
621 {
622     mixin ForwardCtor!();
623 
624     bool isRef;
625     Type type;
626 
627     Type getType() { return members.length == 2 ? getMember!Type(0) : null; }
628     Identifier getIdentifier() { return getMember!Identifier(members.length - 1); }
629 
630     override ForeachType clone()
631     {
632         ForeachType n = static_cast!ForeachType(super.clone());
633         n.isRef = isRef;
634         return n;
635     }
636     override bool compare(const(Node) n) const
637     {
638         if(!super.compare(n))
639             return false;
640 
641         auto tn = static_cast!(typeof(this))(n);
642         return tn.isRef == isRef;
643     }
644 
645     override void toD(CodeWriter writer)
646     {
647         if(isRef)
648             writer("ref ");
649         writer.writeArray(members, " ");
650     }
651 
652     override void addSymbols(Scope sc)
653     {
654         string ident = getIdentifier().ident;
655         sc.addSymbol(ident, this);
656     }
657 
658     override Type calcType()
659     {
660         if(type)
661             return type;
662 
663         if(auto t = getType())
664             type = t.calcType();
665 
666         else if(ForeachStatement stmt = parent ? cast(ForeachStatement) parent.parent : null)
667         {
668             if(stmt.isRangeForeach())
669                 type = stmt.getLwrExpression().calcType();
670             else
671             {
672                 Expression expr = stmt.getAggregate();
673                 Type et = expr.calcType();
674                 if(auto ti = cast(TypeIndirection) et)
675                 {
676                     type = ti.getNextType();
677                 }
678             }
679         }
680         if(!type)
681             type = semanticErrorType("cannot infer type of foreach variable ", getIdentifier().ident);
682         return type;
683     }
684 }
685 
686 //SwitchStatement:
687 //    switch ( Expression ) ScopeNonEmptyStatement
688 class SwitchStatement : Statement
689 {
690     mixin ForwardCtor!();
691 
692     bool isFinal;
693 
694     override bool createsScope() const { return true; }
695 
696     override SwitchStatement clone()
697     {
698         SwitchStatement n = static_cast!SwitchStatement(super.clone());
699         n.isFinal = isFinal;
700         return n;
701     }
702     override bool compare(const(Node) n) const
703     {
704         if(!super.compare(n))
705             return false;
706 
707         auto tn = static_cast!(typeof(this))(n);
708         return tn.isFinal == isFinal;
709     }
710 
711     override void toD(CodeWriter writer)
712     {
713         if(isFinal)
714             writer("final ");
715         writer("switch(", getMember(0), ")");
716         writer.nl;
717         {
718             CodeIndenter indent = CodeIndenter(writer);
719             writer(getMember(1));
720         }
721     }
722 
723     override Value interpret(Context sc)
724     {
725         return semanticErrorValue(this, " not implemented.");
726     }
727 }
728 
729 //FinalSwitchStatement:
730 //    final switch ( Expression ) ScopeNonEmptyStatement
731 //
732 class FinalSwitchStatement : Statement
733 {
734     mixin ForwardCtor!();
735 
736     override Value interpret(Context sc)
737     {
738         return semanticErrorValue(this, " not implemented.");
739     }
740 }
741 
742 //CaseStatement:
743 //    case ArgumentList : Statement
744 //
745 //CaseRangeStatement:
746 //    case FirstExp : .. case LastExp : Statement
747 //
748 //FirstExp:
749 //    AssignExpression
750 //
751 //LastExp:
752 //    AssignExpression
753 class CaseStatement : Statement
754 {
755     mixin ForwardCtor!();
756 
757     override void toD(CodeWriter writer)
758     {
759         {
760             CodeIndenter indent = CodeIndenter(writer, -1);
761             writer("case ", getMember(0));
762             if(id == TOK_slice)
763             {
764                 writer(": .. case ", getMember(1));
765             }
766             else
767             {
768                 writer.writeArray(members[1..$], ", ", true);
769             }
770             writer(":");
771         }
772         writer.nl();
773     }
774 
775     override Value interpret(Context sc)
776     {
777         return semanticErrorValue(this, " not implemented.");
778     }
779 }
780 
781 //DefaultStatement:
782 //    default : Statement
783 class DefaultStatement : Statement
784 {
785     mixin ForwardCtor!();
786 
787     override void toD(CodeWriter writer)
788     {
789         {
790             CodeIndenter indent = CodeIndenter(writer, -1);
791             writer("default:");
792         }
793         writer.nl();
794     }
795 
796     override Value interpret(Context sc)
797     {
798         return semanticErrorValue(this, " not implemented.");
799     }
800 }
801 
802 //ContinueStatement:
803 //    continue ;
804 //    continue Identifier ;
805 class ContinueStatement : Statement
806 {
807     mixin ForwardCtor!();
808 
809     string ident;
810 
811     override ContinueStatement clone()
812     {
813         ContinueStatement n = static_cast!ContinueStatement(super.clone());
814         n.ident = ident;
815         return n;
816     }
817     override bool compare(const(Node) n) const
818     {
819         if(!super.compare(n))
820             return false;
821 
822         auto tn = static_cast!(typeof(this))(n);
823         return tn.ident == ident;
824     }
825 
826     override void toD(CodeWriter writer)
827     {
828         writer("continue");
829         if(ident.length)
830         {
831             writer(" ");
832             writer.writeIdentifier(ident);
833         }
834         writer(";");
835         writer.nl;
836     }
837 
838     override Value interpret(Context sc)
839     {
840         return new ContinueValue(ident);
841     }
842 }
843 
844 //BreakStatement:
845 //    break ;
846 //    break Identifier ;
847 class BreakStatement : Statement
848 {
849     mixin ForwardCtor!();
850 
851     string ident;
852 
853     override BreakStatement clone()
854     {
855         BreakStatement n = static_cast!BreakStatement(super.clone());
856         n.ident = ident;
857         return n;
858     }
859     override bool compare(const(Node) n) const
860     {
861         if(!super.compare(n))
862             return false;
863 
864         auto tn = static_cast!(typeof(this))(n);
865         return tn.ident == ident;
866     }
867 
868     override void toD(CodeWriter writer)
869     {
870         writer("break");
871         if(ident.length)
872         {
873             writer(" ");
874             writer.writeIdentifier(ident);
875         }
876         writer(";");
877         writer.nl;
878     }
879 
880     override Value interpret(Context sc)
881     {
882         return new BreakValue(ident);
883     }
884 }
885 
886 
887 //ReturnStatement:
888 //    return ;
889 //    return Expression ;
890 class ReturnStatement : Statement
891 {
892     mixin ForwardCtor!();
893 
894     override void toD(CodeWriter writer)
895     {
896         writer("return ", getMember(0), ";");
897         writer.nl;
898     }
899 
900     override Value interpret(Context sc)
901     {
902         return getMember(0).interpret(sc);
903     }
904 }
905 
906 
907 //GotoStatement:
908 //    goto Identifier ;
909 //    goto default ;
910 //    goto case ;
911 //    goto case Expression ;
912 class GotoStatement : Statement
913 {
914     mixin ForwardCtor!();
915 
916     string ident;
917 
918     override GotoStatement clone()
919     {
920         GotoStatement n = static_cast!GotoStatement(super.clone());
921         n.ident = ident;
922         return n;
923     }
924     override bool compare(const(Node) n) const
925     {
926         if(!super.compare(n))
927             return false;
928 
929         auto tn = static_cast!(typeof(this))(n);
930         return tn.ident == ident;
931     }
932 
933     override void toD(CodeWriter writer)
934     {
935         if(id == TOK_Identifier)
936         {
937             writer("goto ");
938             writer.writeIdentifier(ident);
939             writer(";");
940         }
941         else if(id == TOK_default)
942             writer("goto default;");
943         else
944         {
945             if(members.length > 0)
946                 writer("goto case ", getMember(0), ";");
947             else
948                 writer("goto case;");
949         }
950         writer.nl;
951     }
952 
953     override Value interpret(Context sc)
954     {
955         return semanticErrorValue(this, " not implemented.");
956     }
957 }
958 
959 //WithStatement:
960 //    with ( Expression ) ScopeNonEmptyStatement
961 //    with ( Symbol ) ScopeNonEmptyStatement
962 //    with ( TemplateInstance ) ScopeNonEmptyStatement
963 class WithStatement : Statement
964 {
965     mixin ForwardCtor!();
966 
967     override bool createsScope() const { return true; }
968 
969     override void toD(CodeWriter writer)
970     {
971         writer("with(", getMember(0), ")");
972         writer.nl;
973         {
974             CodeIndenter indent = CodeIndenter(writer);
975             writer(getMember(1));
976         }
977     }
978 
979     override Value interpret(Context sc)
980     {
981         return semanticErrorValue(this, " not implemented.");
982     }
983 }
984 
985 //SynchronizedStatement:
986 //    [Expression_opt ScopeNonEmptyStatement]
987 class SynchronizedStatement : Statement
988 {
989     mixin ForwardCtor!();
990 
991     override bool createsScope() const { return true; }
992 
993     override void toD(CodeWriter writer)
994     {
995         if(members.length > 1)
996             writer("synchronized(", getMember(0), ") ");
997         else
998             writer("synchronized ");
999 
1000         writer.nl;
1001         {
1002             CodeIndenter indent = CodeIndenter(writer);
1003             writer(getMember(members.length - 1));
1004         }
1005     }
1006 
1007     override Value interpret(Context sc)
1008     {
1009         // no need to synhronize, interpreter is single-threaded
1010         return getMember(members.length - 1).interpret(sc);
1011     }
1012 }
1013 
1014 //VolatileStatement:
1015 //    [ScopeNonEmptyStatement]
1016 class VolatileStatement : Statement
1017 {
1018     mixin ForwardCtor!();
1019 
1020     override bool createsScope() const { return true; }
1021 
1022     override void toD(CodeWriter writer)
1023     {
1024         writer("volatile ");
1025         writer.nl;
1026         {
1027             CodeIndenter indent = CodeIndenter(writer);
1028             writer(getMember(members.length - 1));
1029         }
1030     }
1031 
1032     override Value interpret(Context sc)
1033     {
1034         // no need to synhronize, interpreter is single-threaded
1035         return super.interpret(sc);
1036     }
1037 }
1038 
1039 
1040 //TryStatement:
1041 //    try ScopeNonEmptyStatement Catches
1042 //    try ScopeNonEmptyStatement Catches FinallyStatement
1043 //    try ScopeNonEmptyStatement FinallyStatement
1044 //
1045 //Catches:
1046 //    LastCatch
1047 //    Catch
1048 //    Catch Catches
1049 //
1050 //LastCatch:
1051 //    catch NoScopeNonEmptyStatement
1052 //
1053 //Catch:
1054 //    catch ( CatchParameter ) NoScopeNonEmptyStatement
1055 //
1056 //CatchParameter:
1057 //    BasicType Identifier
1058 //
1059 //FinallyStatement:
1060 //    finally NoScopeNonEmptyStatement
1061 class TryStatement : Statement
1062 {
1063     mixin ForwardCtor!();
1064 
1065     override bool createsScope() const { return true; }
1066 
1067     override void toD(CodeWriter writer)
1068     {
1069         writer("try");
1070         writer.nl();
1071         {
1072             CodeIndenter indent = CodeIndenter(writer);
1073             writer(getMember(0));
1074         }
1075         foreach(m; members[1..$])
1076             writer(m);
1077     }
1078 
1079     override Value interpret(Context sc)
1080     {
1081         return semanticErrorValue(this, " not implemented.");
1082     }
1083 }
1084 
1085 class Catch : Node
1086 {
1087     mixin ForwardCtor!();
1088 
1089     override bool createsScope() const { return true; }
1090 
1091     override void toD(CodeWriter writer)
1092     {
1093         if(members.length > 2)
1094             writer("catch(", getMember(0), " ", getMember(1), ")");
1095         else if(members.length > 1)
1096             writer("catch(", getMember(0), ")");
1097         else
1098             writer("catch");
1099         writer.nl();
1100         {
1101             CodeIndenter indent = CodeIndenter(writer);
1102             writer(getMember(members.length - 1));
1103         }
1104     }
1105 }
1106 
1107 class FinallyStatement : Catch
1108 {
1109     mixin ForwardCtor!();
1110 
1111     override bool createsScope() const { return true; }
1112 
1113     override void toD(CodeWriter writer)
1114     {
1115         writer("finally");
1116         writer.nl();
1117         {
1118             CodeIndenter indent = CodeIndenter(writer);
1119             writer(getMember(0));
1120         }
1121     }
1122 }
1123 
1124 
1125 //ThrowStatement:
1126 //    throw Expression ;
1127 class ThrowStatement : Statement
1128 {
1129     mixin ForwardCtor!();
1130 
1131     override void toD(CodeWriter writer)
1132     {
1133         writer("throw ", getMember(0), ";");
1134         writer.nl;
1135     }
1136 
1137     override Value interpret(Context sc)
1138     {
1139         return semanticErrorValue(this, " not implemented.");
1140     }
1141 }
1142 
1143 //ScopeGuardStatement:
1144 //    scope ( "exit" ) ScopeNonEmptyStatement
1145 //    scope ( "success" ) ScopeNonEmptyStatement
1146 //    scope ( "failure" ) ScopeNonEmptyStatement
1147 class ScopeGuardStatement : Statement
1148 {
1149     mixin ForwardCtor!();
1150 
1151     override bool createsScope() const { return true; }
1152 
1153     override void toD(CodeWriter writer)
1154     {
1155         writer("scope(", getMember(0), ")");
1156         writer.nl;
1157         {
1158             CodeIndenter indent = CodeIndenter(writer);
1159             writer(getMember(1));
1160         }
1161     }
1162 
1163     override Value interpret(Context sc)
1164     {
1165         return semanticErrorValue(this, " not implemented.");
1166     }
1167 }
1168 
1169 //AsmStatement:
1170 //    asm { }
1171 //    asm { AsmInstructionList }
1172 //
1173 //AsmInstructionList:
1174 //    AsmInstruction ;
1175 //    AsmInstruction ; AsmInstructionList
1176 class AsmStatement : Statement
1177 {
1178     mixin ForwardCtor!();
1179 
1180     override void toD(CodeWriter writer)
1181     {
1182         writer("asm {");
1183         writer.nl;
1184         {
1185             CodeIndenter indent = CodeIndenter(writer);
1186             writer(getMember(0));
1187         }
1188         writer("}");
1189         writer.nl;
1190     }
1191 
1192     override Value interpret(Context sc)
1193     {
1194         return semanticErrorValue(this, " cannot be interpreted.");
1195     }
1196 }
1197 
1198 class AsmInstructionList : Node
1199 {
1200     mixin ForwardCtor!();
1201 
1202     override void toD(CodeWriter writer)
1203     {
1204         foreach(m; members)
1205         {
1206             writer(m, ";");
1207             writer.nl();
1208         }
1209     }
1210 }
1211 
1212 //PragmaStatement:
1213 //    Pragma NoScopeStatement
1214 class PragmaStatement : Statement
1215 {
1216     mixin ForwardCtor!();
1217 
1218     override void toD(CodeWriter writer)
1219     {
1220         writer(getMember(0), " ", getMember(1));
1221     }
1222 
1223     override Value interpret(Context sc)
1224     {
1225         getMember(0).interpret(sc);
1226         return getMember(1).interpret(sc);
1227     }
1228 }
1229 
1230 //MixinStatement:
1231 //    [ AssignExpression ]
1232 class MixinStatement : Statement
1233 {
1234     mixin ForwardCtor!();
1235 
1236     override void toD(CodeWriter writer)
1237     {
1238         writer("mixin(", getMember(0), ");");
1239         writer.nl;
1240     }
1241 
1242     override void _semantic(Scope sc)
1243     {
1244         Context ctx = new Context(nullContext);
1245         ctx.scop = sc;
1246         Value v = getMember(0).interpretCatch(ctx);
1247         string s = v.toMixin();
1248         Parser parser = new Parser;
1249         if(auto prj = sc.getProject())
1250             parser.saveErrors = prj.saveErrors;
1251         Node[] n = parser.parseStatements(s, span);
1252         parent.replaceMember(this, n);
1253     }
1254 
1255     override Value interpret(Context sc)
1256     {
1257         return semanticErrorValue(this, " semantic not run");
1258     }
1259 }