1 /// Author: Aziz Köksal
2 /// License: GPL3
3 /// $(Maturity high)
4 module dil.ast.Statements;
5 
6 public import dil.ast.Statement;
7 import dil.ast.Node,
8        dil.ast.Expression,
9        dil.ast.Declaration,
10        dil.ast.Type,
11        dil.ast.Parameters,
12        dil.ast.NodeCopier,
13        dil.ast.Meta;
14 import dil.lexer.IdTable;
15 import common;
16 
17 class CompoundStmt : Statement
18 {
19   this()
20   {
21     mixin(set_kind);
22   }
23 
24   this(Statement[] stmnts)
25   {
26     this();
27     addChildren(stmnts);
28   }
29 
30   void opCatAssign(Statement s)
31   {
32     addChild(s);
33   }
34 
35   Statement[] stmnts() @property
36   {
37     return cast(Statement[])this.children;
38   }
39 
40   void stmnts(Statement[] stmnts) @property
41   {
42     this.children = cast(Node[])stmnts;
43   }
44 
45   mixin(memberInfo("stmnts"));
46 
47   mixin methods;
48 }
49 
50 class IllegalStmt : Statement
51 {
52   mixin(memberInfo());
53   this()
54   {
55     mixin(set_kind);
56   }
57   mixin methods;
58 }
59 
60 class EmptyStmt : Statement
61 {
62   mixin(memberInfo());
63   this()
64   {
65     mixin(set_kind);
66   }
67   mixin methods;
68 }
69 
70 class FuncBodyStmt : Statement
71 {
72   Statement funcBody, inBody, outBody;
73   Token* outIdent; /// $(BNF "out" ("(" Identifier ")")?)
74   mixin(memberInfo("funcBody?", "inBody?", "outBody?", "outIdent?"));
75   this(Statement funcBody, Statement inBody, Statement outBody,
76        Token* outIdent)
77   {
78     mixin(set_kind);
79     addOptChild(funcBody);
80     addOptChild(inBody);
81     addOptChild(outBody);
82     this.funcBody = funcBody;
83     this.inBody = inBody;
84     this.outBody = outBody;
85     this.outIdent = outIdent;
86   }
87 
88   bool isEmpty()
89   {
90     return funcBody is null;
91   }
92 
93   mixin methods;
94 }
95 
96 class ScopeStmt : Statement
97 {
98   Statement stmnt;
99   mixin(memberInfo("stmnt"));
100   this(Statement s)
101   {
102     mixin(set_kind);
103     addChild(s);
104     this.stmnt = s;
105   }
106   mixin methods;
107 }
108 
109 class LabeledStmt : Statement
110 {
111   Token* label;
112   Statement stmnt;
113   mixin(memberInfo("label", "stmnt"));
114   this(Token* label, Statement s)
115   {
116     mixin(set_kind);
117     addChild(s);
118     this.label = label;
119     this.stmnt = s;
120   }
121   mixin methods;
122 }
123 
124 class ExpressionStmt : Statement
125 {
126   Expression expr;
127   mixin(memberInfo("expr"));
128   this(Expression e)
129   {
130     mixin(set_kind);
131     addChild(e);
132     this.expr = e;
133   }
134   mixin methods;
135 }
136 
137 class DeclarationStmt : Statement
138 {
139   Declaration decl;
140   mixin(memberInfo("decl"));
141   this(Declaration decl)
142   {
143     mixin(set_kind);
144     addChild(decl);
145     this.decl = decl;
146   }
147   mixin methods;
148 }
149 
150 class IfStmt : Statement
151 {
152   Declaration variable; // VariablesDecl
153   Expression condition;
154   Statement ifBody;
155   Statement elseBody;
156   mixin(memberInfo("variable?", "condition?", "ifBody", "elseBody?"));
157   this(Declaration variable, Expression condition, Statement ifBody,
158        Statement elseBody)
159   {
160     mixin(set_kind);
161     if (variable) {
162       addChild(variable);
163       assert(variable.kind == NodeKind.VariablesDecl);
164     }
165     else
166       addChild(condition);
167     addChild(ifBody);
168     addOptChild(elseBody);
169 
170     this.variable = variable;
171     this.condition = condition;
172     this.ifBody = ifBody;
173     this.elseBody = elseBody;
174   }
175   mixin methods;
176 }
177 
178 class WhileStmt : Statement
179 {
180   Expression condition;
181   Statement whileBody;
182   mixin(memberInfo("condition", "whileBody"));
183   this(Expression condition, Statement whileBody)
184   {
185     mixin(set_kind);
186     addChild(condition);
187     addChild(whileBody);
188 
189     this.condition = condition;
190     this.whileBody = whileBody;
191   }
192   mixin methods;
193 }
194 
195 class DoWhileStmt : Statement
196 {
197   Statement doBody;
198   Expression condition;
199   mixin(memberInfo("condition", "doBody"));
200   this(Expression condition, Statement doBody)
201   {
202     mixin(set_kind);
203     addChild(doBody);
204     addChild(condition);
205 
206     this.condition = condition;
207     this.doBody = doBody;
208   }
209   mixin methods;
210 }
211 
212 class ForStmt : Statement
213 {
214   Statement init;
215   Expression condition, increment;
216   Statement forBody;
217 
218   mixin(memberInfo("init?", "condition?", "increment?", "forBody"));
219   this(Statement init, Expression condition, Expression increment, Statement forBody)
220   {
221     mixin(set_kind);
222     addOptChild(init);
223     addOptChild(condition);
224     addOptChild(increment);
225     addChild(forBody);
226 
227     this.init = init;
228     this.condition = condition;
229     this.increment = increment;
230     this.forBody = forBody;
231   }
232   mixin methods;
233 }
234 
235 class ForeachStmt : Statement
236 {
237   TOK tok;
238   Parameters params;
239   Expression aggregate;
240   Statement forBody;
241 
242   mixin(memberInfo("tok", "params", "aggregate", "forBody"));
243   this(TOK tok, Parameters params, Expression aggregate, Statement forBody)
244   {
245     mixin(set_kind);
246     addChildren([cast(Node)params, aggregate, forBody]);
247 
248     this.tok = tok;
249     this.params = params;
250     this.aggregate = aggregate;
251     this.forBody = forBody;
252   }
253 
254   /// Returns true if this is a foreach_reverse statement.
255   bool isReverse()
256   {
257     return tok == TOK.ForeachReverse;
258   }
259 
260   /// Returns true if the aggregate is a RangeExpr.
261   bool hasRange()
262   {
263     return aggregate.kind == NodeKind.RangeExpr;
264   }
265 
266   mixin methods;
267 }
268 
269 class SwitchStmt : Statement
270 {
271   Expression condition;
272   Statement switchBody;
273   bool isFinal;
274 
275   mixin(memberInfo("condition", "switchBody", "isFinal"));
276   this(Expression condition, Statement switchBody, bool isFinal = false)
277   {
278     mixin(set_kind);
279     addChild(condition);
280     addChild(switchBody);
281 
282     this.condition = condition;
283     this.switchBody = switchBody;
284     this.isFinal = isFinal;
285   }
286   mixin methods;
287 }
288 
289 class CaseStmt : Statement
290 {
291   Expression[] values;
292   Statement caseBody;
293 
294   mixin(memberInfo("values", "caseBody"));
295   this(Expression[] values, Statement caseBody)
296   {
297     mixin(set_kind);
298     addChildren(values);
299     addChild(caseBody);
300 
301     this.values = values;
302     this.caseBody = caseBody;
303   }
304   mixin methods;
305 }
306 
307 // D2
308 class CaseRangeStmt : Statement
309 {
310   Expression left, right;
311   Statement caseBody;
312 
313   mixin(memberInfo("left", "right", "caseBody"));
314   this(Expression left, Expression right, Statement caseBody)
315   {
316     mixin(set_kind);
317     addChild(left);
318     addChild(right);
319     addChild(caseBody);
320 
321     this.left = left;
322     this.right = right;
323     this.caseBody = caseBody;
324   }
325   mixin methods;
326 }
327 
328 class DefaultStmt : Statement
329 {
330   Statement defaultBody;
331   mixin(memberInfo("defaultBody"));
332   this(Statement defaultBody)
333   {
334     mixin(set_kind);
335     addChild(defaultBody);
336 
337     this.defaultBody = defaultBody;
338   }
339   mixin methods;
340 }
341 
342 class ContinueStmt : Statement
343 {
344   Token* label;
345   mixin(memberInfo("label?"));
346   this(Token* label)
347   {
348     mixin(set_kind);
349     this.label = label;
350   }
351   mixin methods;
352 }
353 
354 class BreakStmt : Statement
355 {
356   Token* label;
357   mixin(memberInfo("label?"));
358   this(Token* label)
359   {
360     mixin(set_kind);
361     this.label = label;
362   }
363   mixin methods;
364 }
365 
366 class ReturnStmt : Statement
367 {
368   Expression expr;
369   mixin(memberInfo("expr?"));
370   this(Expression e)
371   {
372     mixin(set_kind);
373     addOptChild(e);
374     this.expr = e;
375   }
376   mixin methods;
377 }
378 
379 class GotoStmt : Statement
380 {
381   Token* ident; /// The label id, case or default.
382   Expression expr;
383   mixin(memberInfo("ident", "expr?"));
384   this(Token* ident, Expression expr)
385   {
386     mixin(set_kind);
387     addOptChild(expr);
388     this.ident = ident;
389     this.expr = expr;
390   }
391 
392   bool isGotoLabel() @property
393   {
394     return ident.kind == TOK.Identifier;
395   }
396 
397   bool isGotoCase() @property
398   {
399     return ident.kind == TOK.Goto;
400   }
401 
402   bool isGotoDefault() @property
403   {
404     return ident.kind == TOK.Default;
405   }
406 
407   mixin methods;
408 }
409 
410 class WithStmt : Statement
411 {
412   Expression expr;
413   Statement withBody;
414   mixin(memberInfo("expr", "withBody"));
415   this(Expression e, Statement withBody)
416   {
417     mixin(set_kind);
418     addChild(e);
419     addChild(withBody);
420 
421     this.expr = e;
422     this.withBody = withBody;
423   }
424   mixin methods;
425 }
426 
427 class SynchronizedStmt : Statement
428 {
429   Expression expr;
430   Statement syncBody;
431   mixin(memberInfo("expr?", "syncBody"));
432   this(Expression e, Statement syncBody)
433   {
434     mixin(set_kind);
435     addOptChild(e);
436     addChild(syncBody);
437 
438     this.expr = e;
439     this.syncBody = syncBody;
440   }
441   mixin methods;
442 }
443 
444 class TryStmt : Statement
445 {
446   Statement tryBody;
447   CatchStmt[] catchBodies;
448   FinallyStmt finallyBody;
449   mixin(memberInfo("tryBody", "catchBodies", "finallyBody?"));
450   this(Statement tryBody, CatchStmt[] catchBodies, FinallyStmt finallyBody)
451   {
452     mixin(set_kind);
453     addChild(tryBody);
454     addOptChildren(catchBodies);
455     addOptChild(finallyBody);
456 
457     this.tryBody = tryBody;
458     this.catchBodies = catchBodies;
459     this.finallyBody = finallyBody;
460   }
461   mixin methods;
462 }
463 
464 class CatchStmt : Statement
465 {
466   Parameter param;
467   Statement catchBody;
468   mixin(memberInfo("param?", "catchBody"));
469   this(Parameter param, Statement catchBody)
470   {
471     mixin(set_kind);
472     addOptChild(param);
473     addChild(catchBody);
474     this.param = param;
475     this.catchBody = catchBody;
476   }
477   mixin methods;
478 }
479 
480 class FinallyStmt : Statement
481 {
482   Statement finallyBody;
483   mixin(memberInfo("finallyBody"));
484   this(Statement finallyBody)
485   {
486     mixin(set_kind);
487     addChild(finallyBody);
488     this.finallyBody = finallyBody;
489   }
490   mixin methods;
491 }
492 
493 class ScopeGuardStmt : Statement
494 {
495   Token* condition;
496   Statement scopeBody;
497   mixin(memberInfo("condition", "scopeBody"));
498   this(Token* condition, Statement scopeBody)
499   {
500     mixin(set_kind);
501     addChild(scopeBody);
502     this.condition = condition;
503     this.scopeBody = scopeBody;
504   }
505   mixin methods;
506 }
507 
508 class ThrowStmt : Statement
509 {
510   Expression expr;
511   mixin(memberInfo("expr"));
512   this(Expression e)
513   {
514     mixin(set_kind);
515     addChild(e);
516     this.expr = e;
517   }
518   mixin methods;
519 }
520 
521 class VolatileStmt : Statement
522 {
523   Statement volatileBody;
524   mixin(memberInfo("volatileBody?"));
525   this(Statement volatileBody)
526   {
527     mixin(set_kind);
528     addOptChild(volatileBody);
529     this.volatileBody = volatileBody;
530   }
531   mixin methods;
532 }
533 
534 class AsmBlockStmt : Statement
535 {
536   CompoundStmt statements;
537   mixin(memberInfo("statements"));
538   this(CompoundStmt statements)
539   {
540     mixin(set_kind);
541     addChild(statements);
542     this.statements = statements;
543   }
544   mixin methods;
545 }
546 
547 class AsmStmt : Statement
548 {
549   Token* opcode;
550   Expression[] operands;
551   mixin(memberInfo("opcode", "operands"));
552   this(Token* opcode, Expression[] operands)
553   {
554     mixin(set_kind);
555     addOptChildren(operands);
556     this.opcode = opcode;
557     this.operands = operands;
558   }
559   mixin methods;
560 }
561 
562 class AsmAlignStmt : Statement
563 {
564   int number;
565   Token* numtok;
566   mixin(memberInfo("numtok"));
567   this(Token* numtok)
568   {
569     mixin(set_kind);
570     this.numtok = numtok;
571     this.number = numtok.int_;
572   }
573   mixin methods;
574 }
575 
576 class IllegalAsmStmt : Statement
577 {
578   mixin(memberInfo());
579   this()
580   {
581     mixin(set_kind);
582   }
583   mixin methods;
584 }
585 
586 class PragmaStmt : Statement
587 {
588   Token* name;
589   Expression[] args;
590   Statement pragmaBody;
591   mixin(memberInfo("name", "args", "pragmaBody"));
592   this(Token* name, Expression[] args, Statement pragmaBody)
593   {
594     mixin(set_kind);
595     addOptChildren(args);
596     addChild(pragmaBody);
597 
598     this.name = name;
599     this.args = args;
600     this.pragmaBody = pragmaBody;
601   }
602   mixin methods;
603 }
604 
605 class MixinStmt : Statement
606 {
607   Expression templateExpr;
608   Token* mixinIdent;
609   mixin(memberInfo("templateExpr", "mixinIdent"));
610   this(Expression templateExpr, Token* mixinIdent)
611   {
612     mixin(set_kind);
613     addChild(templateExpr);
614     this.templateExpr = templateExpr;
615     this.mixinIdent = mixinIdent;
616   }
617   mixin methods;
618 }
619 
620 class StaticIfStmt : Statement
621 {
622   Expression condition;
623   Statement ifBody, elseBody;
624   mixin(memberInfo("condition", "ifBody", "elseBody?"));
625   this(Expression condition, Statement ifBody, Statement elseBody)
626   {
627     mixin(set_kind);
628     addChild(condition);
629     addChild(ifBody);
630     addOptChild(elseBody);
631     this.condition = condition;
632     this.ifBody = ifBody;
633     this.elseBody = elseBody;
634   }
635   mixin methods;
636 }
637 
638 class StaticAssertStmt : Statement
639 {
640   Expression condition, message;
641   mixin(memberInfo("condition", "message?"));
642   this(Expression condition, Expression message)
643   {
644     mixin(set_kind);
645     addChild(condition);
646     addOptChild(message);
647     this.condition = condition;
648     this.message = message;
649   }
650   mixin methods;
651 }
652 
653 abstract class ConditionalCompilationStmt : Statement
654 {
655   Token* cond;
656   Statement mainBody, elseBody;
657   this(Token* cond, Statement mainBody, Statement elseBody)
658   {
659     addChild(mainBody);
660     addOptChild(elseBody);
661     this.cond = cond;
662     this.mainBody = mainBody;
663     this.elseBody = elseBody;
664   }
665 }
666 
667 class DebugStmt : ConditionalCompilationStmt
668 {
669   mixin(memberInfo("cond?", "mainBody", "elseBody?"));
670   this(Token* cond, Statement debugBody, Statement elseBody)
671   {
672     super(cond, debugBody, elseBody);
673     mixin(set_kind);
674   }
675   mixin methods;
676 }
677 
678 class VersionStmt : ConditionalCompilationStmt
679 {
680   mixin(memberInfo("cond", "mainBody", "elseBody?"));
681   this(Token* cond, Statement versionBody, Statement elseBody)
682   {
683     super(cond, versionBody, elseBody);
684     mixin(set_kind);
685   }
686   mixin methods;
687 }