1 /**
2 This module implements the expression and statement node classes, which are used internally as a syntax tree.
3 The Parser generates the tree and the Compiler traverses it to emit bytecode into Chunks.
4 
5 ────────────────────────────────────────────────────────────────────────────────
6 
7 Copyright (C) 2021 pillager86.rf.gd
8 
9 This program is free software: you can redistribute it and/or modify it under 
10 the terms of the GNU General Public License as published by the Free Software 
11 Foundation, either version 3 of the License, or (at your option) any later 
12 version.
13 
14 This program is distributed in the hope that it will be useful, but WITHOUT ANY
15 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
16 PARTICULAR PURPOSE.  See the GNU General Public License for more details.
17 
18 You should have received a copy of the GNU General Public License along with 
19 this program.  If not, see <https://www.gnu.org/licenses/>.
20  */
21 module mildew.nodes;
22 
23 import std.format: format;
24 import std.variant;
25 
26 import mildew.environment: Environment;
27 import mildew.exceptions: ScriptRuntimeException;
28 import mildew.lexer: Token;
29 import mildew.types;
30 import mildew.visitors;
31 
32 package:
33 
34 /// handles class expression and declaration data
35 class ClassDefinition
36 {
37     this(string clsname, FunctionLiteralNode ctor,
38             string[] mnames, FunctionLiteralNode[] ms,
39             string[] gmnames, FunctionLiteralNode[] gms,
40             string[] smnames, FunctionLiteralNode[] sms,
41             string[] statNames, FunctionLiteralNode[] statms,
42             ExpressionNode base = null)
43     {
44         className = clsname;
45         constructor = ctor;
46         methodNames = mnames;
47         methods = ms;
48         assert(methodNames.length == methods.length);
49         getMethodNames = gmnames;
50         getMethods = gms;
51         assert(getMethodNames.length == getMethods.length);
52         setMethodNames = smnames;
53         setMethods = sms;
54         assert(setMethodNames.length == setMethods.length);
55         staticMethodNames = statNames;
56         staticMethods = statms;
57         assert(staticMethodNames.length == staticMethods.length);
58         baseClass = base;
59     }
60 
61     override string toString() const 
62     {
63         string output = "class " ~ className;
64         if(baseClass) output ~= " extends " ~ baseClass.toString();
65         output ~= " {...}";
66         return output;
67     }
68 
69     string className;
70     FunctionLiteralNode constructor;
71     string[] methodNames;
72     FunctionLiteralNode[] methods;
73     string[] getMethodNames;
74     FunctionLiteralNode[] getMethods;
75     string[] setMethodNames;
76     FunctionLiteralNode[] setMethods;
77 	string[] staticMethodNames;
78 	FunctionLiteralNode[] staticMethods;
79     ExpressionNode baseClass; // should be an expression that returns a constructor function
80 }
81 
82 /// root class of expression nodes
83 abstract class ExpressionNode
84 {
85     abstract Variant accept(IExpressionVisitor visitor);
86 
87     // have to override here for subclasses' override to work
88     override string toString() const
89     {
90         assert(false, "This should never be called as it is virtual");
91     }
92 }
93 
94 class LiteralNode : ExpressionNode 
95 {
96     this(Token token, ScriptAny val)
97     {
98         literalToken = token;
99         value = val;
100     }
101 
102     override Variant accept(IExpressionVisitor visitor)
103     {
104         return visitor.visitLiteralNode(this);
105     }
106 
107     override string toString() const
108     {
109         if(value.type == ScriptAny.Type.STRING)
110             return "\"" ~ literalToken.text ~ "\"";
111         else
112             return literalToken.text;
113     }
114 
115     Token literalToken;
116     ScriptAny value;
117 }
118 
119 class FunctionLiteralNode : ExpressionNode
120 {
121     this(Token t, string[] args, ExpressionNode[] defArgs, StatementNode[] stmts, string optional = "", 
122          bool isC = false, bool isG=false)
123     {
124         token = t;
125         argList = args;
126         defaultArguments = defArgs;
127         statements = stmts;
128         optionalName = optional;
129         isClass = isC;
130         isGenerator = isG;
131     }
132 
133     override Variant accept(IExpressionVisitor visitor)
134     {
135         return visitor.visitFunctionLiteralNode(this);
136     }
137 
138     override string toString() const
139     {
140         string output = "function(";
141         for(size_t i = 0; i < argList.length; ++i)
142         {
143             output ~= argList[i];
144             if(i < argList.length - 1)
145                 output ~= ", ";
146         }
147         output ~= "){\n";
148         foreach(stmt ; statements)
149         {
150             output ~= "\t" ~ stmt.toString();
151         }
152         output ~= "\n}";
153         return output;
154     }
155 
156     Token token;
157     string[] argList;
158     ExpressionNode[] defaultArguments;
159     StatementNode[] statements;
160     string optionalName;
161     bool isClass;
162     bool isGenerator;
163 }
164 
165 class LambdaNode : ExpressionNode
166 {
167     this(Token arrow, string[] args, ExpressionNode[] defArgs, StatementNode[] stmts)
168     {
169         arrowToken = arrow;
170         argList = args;
171         defaultArguments = defArgs;
172         statements = stmts;
173     }
174 
175     this(Token arrow, string[] args, ExpressionNode[] defArgs, ExpressionNode ret)
176     {
177         arrowToken = arrow;
178         argList = args;
179         defaultArguments = defArgs;
180         returnExpression = ret;
181     }
182 
183     override string toString() const
184     {
185         auto result = "(";
186         for(size_t i = 0; i < argList.length; ++i)
187         {
188             result ~= argList[i];
189             if(i < argList.length - 1)
190                 result ~= ", ";
191         }
192         result ~= ") => ";
193         if(returnExpression)
194         {
195             result ~= returnExpression.toString();
196         }
197         else
198         {
199             result ~= "{";
200             foreach(stmt ; statements)
201                 result ~= stmt.toString() ~ " ";
202             result ~= "}";
203         }
204         return result;
205     }
206 
207     override Variant accept(IExpressionVisitor visitor)
208     {
209         return visitor.visitLambdaNode(this);
210     }
211 
212     Token arrowToken;
213     string[] argList;
214     ExpressionNode[] defaultArguments;
215     StatementNode[] statements;
216     ExpressionNode returnExpression;
217 }
218 
219 class TemplateStringNode : ExpressionNode
220 {
221     this(ExpressionNode[] ns)
222     {
223         nodes = ns;
224     }
225 
226     override Variant accept(IExpressionVisitor visitor)
227     {
228         return visitor.visitTemplateStringNode(this);
229     }
230 
231     override string toString() const
232     {
233         import std.format: format;
234         string output = "`";
235         foreach(node ; nodes)
236         {
237             if(auto lit = cast(LiteralNode)node)
238                 output ~= lit.literalToken.text;
239             else // any other expression
240                 output ~= format("${%s}", node.toString());
241         }
242         output ~= "`";
243         return output;
244     }
245 
246     ExpressionNode[] nodes;
247 }
248 
249 class ArrayLiteralNode : ExpressionNode 
250 {
251     this(ExpressionNode[] values)
252     {
253         valueNodes = values;
254     }
255 
256     override Variant accept(IExpressionVisitor visitor)
257     {
258         return visitor.visitArrayLiteralNode(this);
259     }
260 
261     override string toString() const
262     {
263         return format("%s", valueNodes);
264     }
265 
266     ExpressionNode[] valueNodes;
267 }
268 
269 class ObjectLiteralNode : ExpressionNode 
270 {
271     this(string[] ks, ExpressionNode[] vs)
272     {
273         keys = ks;
274         valueNodes = vs;
275     }
276 
277     override Variant accept(IExpressionVisitor visitor)
278     {
279         return visitor.visitObjectLiteralNode(this);
280     }
281 
282     override string toString() const
283     {
284         // return "(object literal node)";
285         if(keys.length != valueNodes.length)
286             return "{invalid_object}";
287         auto result = "{";
288         for(size_t i = 0; i < keys.length; ++i)
289             result ~= keys[i] ~ ":" ~ valueNodes[i].toString;
290         result ~= "}";
291         return result;
292     }
293 
294     string[] keys;
295     ExpressionNode[] valueNodes;
296 }
297 
298 class DestructureTargetNode : ExpressionNode
299 {
300     this(string[] names, string rname, bool isObj)
301     {
302         varNames = names;
303         remainderName = rname;
304         isObject = isObj;
305     }
306 
307     // this can't be directly visited because its meaning is different depending on context
308     override Variant accept(IExpressionVisitor visitor)
309     {
310         throw new Exception("DestructureTargetNode cannot be directly visited");
311     }
312 
313     override string toString() const
314     {
315         auto result = isObject ? "{" : "[";
316         for(size_t i = 0; i < varNames.length; ++i)
317         {
318             result ~= varNames[i];
319             if(i < varNames.length - 1)
320                 result ~= ", ";
321         }
322         if(remainderName)
323             result ~= remainderName ~ "...";
324         result ~= isObject ? "}" : "]";
325         return result;
326     }
327 
328     string[] varNames;
329     string remainderName;
330     bool isObject; // false for array
331 }
332 
333 class ClassLiteralNode : ExpressionNode 
334 {
335     this(Token ctoken, ClassDefinition cdef)
336     {
337         classToken = ctoken;
338         classDefinition = cdef;
339     }
340 
341     override Variant accept(IExpressionVisitor visitor)
342     {
343         return visitor.visitClassLiteralNode(this);
344     }
345 
346     override string toString() const 
347     {
348         return classDefinition.toString();
349     }
350 
351     Token classToken;
352     ClassDefinition classDefinition;
353 }
354 
355 class BinaryOpNode : ExpressionNode
356 {
357     this(Token op, ExpressionNode left, ExpressionNode right)
358     {
359         opToken = op;
360         leftNode = left;
361         rightNode = right;
362     }
363 
364     override Variant accept(IExpressionVisitor visitor)
365     {
366         return visitor.visitBinaryOpNode(this);
367     }
368 
369     override string toString() const
370     {
371         return format("(%s %s %s)", leftNode, opToken.symbol, rightNode);
372     }
373 
374     Token opToken;
375     ExpressionNode leftNode;
376     ExpressionNode rightNode;
377 }
378 
379 class UnaryOpNode : ExpressionNode
380 {
381     this(Token op, ExpressionNode operand)
382     {
383         opToken = op;
384         operandNode = operand;
385     }
386 
387     override Variant accept(IExpressionVisitor visitor)
388     {
389         return visitor.visitUnaryOpNode(this);
390     }
391 
392     override string toString() const
393     {
394         return format("(%s %s)", opToken.symbol, operandNode);
395     }
396 
397     Token opToken;
398     ExpressionNode operandNode;
399 }
400 
401 class PostfixOpNode : ExpressionNode 
402 {
403     this(Token op, ExpressionNode node)
404     {
405         opToken = op;
406         operandNode = node;
407     }
408 
409     override Variant accept(IExpressionVisitor visitor)
410     {
411         return visitor.visitPostfixOpNode(this);
412     }
413 
414     override string toString() const 
415     {
416         return operandNode.toString() ~ opToken.symbol;
417     }
418 
419     Token opToken;
420     ExpressionNode operandNode;
421 }
422 
423 class TerniaryOpNode : ExpressionNode 
424 {
425     this(ExpressionNode cond, ExpressionNode onTrue, ExpressionNode onFalse)
426     {
427         conditionNode = cond;
428         onTrueNode = onTrue;
429         onFalseNode = onFalse;
430     }
431 
432     override Variant accept(IExpressionVisitor visitor)
433     {
434         return visitor.visitTerniaryOpNode(this);
435     }
436 
437     override string toString() const 
438     {
439         return conditionNode.toString() ~ "? " ~ onTrueNode.toString() ~ " : " ~ onFalseNode.toString();
440     }
441 
442     ExpressionNode conditionNode;
443     ExpressionNode onTrueNode;
444     ExpressionNode onFalseNode;
445 }
446 
447 class VarAccessNode : ExpressionNode
448 {
449     this(Token token)
450     {
451         varToken = token;
452     }
453 
454     override Variant accept(IExpressionVisitor visitor)
455     {
456         return visitor.visitVarAccessNode(this);
457     }
458 
459     override string toString() const
460     {
461         return varToken.text;
462     }
463 
464     Token varToken;
465 }
466 
467 class FunctionCallNode : ExpressionNode
468 {
469     this(ExpressionNode fn, ExpressionNode[] args, bool retThis=false)
470     {
471         functionToCall = fn;
472         expressionArgs = args;
473         returnThis = retThis;
474     }
475 
476     override Variant accept(IExpressionVisitor visitor)
477     {
478         return visitor.visitFunctionCallNode(this);
479     }
480 
481     override string toString() const
482     {
483         auto str = functionToCall.toString ~ "(";
484         for(size_t i = 0; i < expressionArgs.length; ++i)
485         {
486             str ~= expressionArgs[i].toString;
487             if(i < expressionArgs.length - 1) // @suppress(dscanner.suspicious.length_subtraction)
488                 str ~= ", ";
489         }
490         str ~= ")";
491         return str;
492     }
493 
494     ExpressionNode functionToCall;
495     ExpressionNode[] expressionArgs;
496     bool returnThis;
497 }
498 
499 // when [] operator is used
500 class ArrayIndexNode : ExpressionNode 
501 {
502     this(ExpressionNode obj, ExpressionNode index)
503     {
504         objectNode = obj;
505         indexValueNode = index;
506     }    
507 
508     override Variant accept(IExpressionVisitor visitor)
509     {
510         return visitor.visitArrayIndexNode(this);
511     }
512 
513     override string toString() const
514     {
515         return objectNode.toString() ~ "[" ~ indexValueNode.toString() ~ "]";
516     }
517 
518     ExpressionNode objectNode;
519     ExpressionNode indexValueNode;
520 }
521 
522 class MemberAccessNode : ExpressionNode 
523 {
524     this(ExpressionNode obj, Token dt, ExpressionNode member)
525     {
526         objectNode = obj;
527         dotToken = dt;
528         memberNode = member;
529     }
530 
531     override Variant accept(IExpressionVisitor visitor)
532     {
533         return visitor.visitMemberAccessNode(this);
534     }
535 
536     override string toString() const
537     {
538         return objectNode.toString() ~ "." ~ memberNode.toString();
539     }
540 
541     ExpressionNode objectNode;
542     Token dotToken;
543     ExpressionNode memberNode;
544 }
545 
546 class NewExpressionNode : ExpressionNode 
547 {
548     this(ExpressionNode fn)
549     {
550         functionCallExpression = fn;
551     }
552 
553     override Variant accept(IExpressionVisitor visitor)
554     {
555         return visitor.visitNewExpressionNode(this);
556     }
557 
558     override string toString() const
559     {
560         return "new " ~ functionCallExpression.toString();
561     }
562 
563     ExpressionNode functionCallExpression;
564 }
565 
566 /// for when the super keyword is not used as a constructor
567 class SuperNode : ExpressionNode
568 {
569     this(Token stoken, ExpressionNode bc)
570     {
571         superToken = stoken;
572         baseClass = bc;
573     }
574 
575     override Variant accept(IExpressionVisitor visitor)
576     {
577         return visitor.visitSuperNode(this);
578     }
579 
580     override string toString() const 
581     {
582         return "super";
583     }
584 
585     Token superToken;
586     ExpressionNode baseClass;
587 }
588 
589 class YieldNode : ExpressionNode
590 {
591     this(Token yToken, ExpressionNode expr)
592     {
593         yieldToken = yToken;
594         yieldExpression = expr;
595     }
596 
597     override Variant accept(IExpressionVisitor visitor)
598     {
599         return visitor.visitYieldNode(this);
600     }
601 
602     override string toString() const
603     {
604         return "yield " ~ (yieldExpression? yieldExpression.toString: "");
605     }
606 
607     Token yieldToken;
608     ExpressionNode yieldExpression;
609 }
610 
611 /// root class of all statement nodes
612 abstract class StatementNode
613 {
614     this(size_t lineNo)
615     {
616         line = lineNo;
617     }
618 
619     abstract Variant accept(IStatementVisitor visitor);
620 
621     override string toString() const
622     {
623         assert(false, "This method is virtual and should never be called directly");
624     }
625 
626     immutable size_t line;
627 }
628 
629 class VarDeclarationStatementNode : StatementNode
630 {
631     this(Token qual, ExpressionNode[] nodes)
632     {
633         super(qual.position.line);
634         qualifier = qual;
635         varAccessOrAssignmentNodes = nodes;
636     }
637 
638     this(size_t lineNo, Token qual, ExpressionNode[] nodes)
639     {
640         super(lineNo);
641         qualifier = qual;
642         varAccessOrAssignmentNodes = nodes;
643     }
644 
645     override Variant accept(IStatementVisitor visitor)
646     {
647         return visitor.visitVarDeclarationStatementNode(this);
648     }
649 
650     override string toString() const
651     {
652         string str = qualifier.text ~ " ";
653         for(size_t i = 0; i < varAccessOrAssignmentNodes.length; ++i)
654         {
655             str ~= varAccessOrAssignmentNodes[i].toString();
656             if(i < varAccessOrAssignmentNodes.length - 1) // @suppress(dscanner.suspicious.length_subtraction)
657                 str ~= ", ";
658         }
659         return str;
660     }
661 
662     Token qualifier; // must be var, let, or const
663     ExpressionNode[] varAccessOrAssignmentNodes; // must be VarAccessNode or BinaryOpNode. should be validated by parser
664 }
665 
666 class BlockStatementNode: StatementNode
667 {
668     this(size_t lineNo, StatementNode[] statements)
669     {
670         super(lineNo);
671         statementNodes = statements;
672     }
673 
674     override Variant accept(IStatementVisitor visitor)
675     {
676         return visitor.visitBlockStatementNode(this);
677     }
678 
679     override string toString() const
680     {
681         string str = "{\n";
682         foreach(st ; statementNodes)
683         {
684             str ~= "  " ~ st.toString ~ "\n";
685         }
686         str ~= "}";
687         return str;
688     }
689 
690     StatementNode[] statementNodes;
691 }
692 
693 class IfStatementNode : StatementNode
694 {
695     this(size_t lineNo, ExpressionNode condition, StatementNode onTrue, StatementNode onFalse=null)
696     {
697         super(lineNo);
698         conditionNode = condition;
699         onTrueStatement = onTrue;
700         onFalseStatement = onFalse;
701     }
702 
703     override Variant accept(IStatementVisitor visitor)
704     {
705         return visitor.visitIfStatementNode(this);
706     }
707 
708     override string toString() const
709     {
710         auto str = "if(" ~ conditionNode.toString() ~ ") ";
711         str ~= onTrueStatement.toString();
712         if(onFalseStatement !is null)
713             str ~= " else " ~ onFalseStatement.toString();
714         return str;
715     }
716 
717     ExpressionNode conditionNode;
718     StatementNode onTrueStatement, onFalseStatement;
719 }
720 
721 class SwitchStatementNode : StatementNode
722 {
723     this(size_t lineNo, ExpressionNode expr, SwitchBody sbody)
724     {
725         super(lineNo);
726         expressionNode = expr;
727         switchBody = sbody;
728     }
729 
730     override Variant accept(IStatementVisitor visitor)
731     {
732         return visitor.visitSwitchStatementNode(this);
733     }
734 
735     ExpressionNode expressionNode; // expression to test
736     SwitchBody switchBody;
737 }
738 
739 class SwitchBody
740 {
741     this(StatementNode[] statements, size_t defaultID, size_t[ScriptAny] jumpTableID)
742     {
743         statementNodes = statements;
744         defaultStatementID = defaultID;
745         jumpTable = jumpTableID;
746     }
747 
748     StatementNode[] statementNodes;
749     size_t defaultStatementID; // index into statementNodes
750     size_t[ScriptAny] jumpTable; // indexes into statementNodes
751 }
752 
753 class WhileStatementNode : StatementNode
754 {
755     this(size_t lineNo, ExpressionNode condition, StatementNode bnode, string lbl = "")
756     {
757         super(lineNo);
758         conditionNode = condition;
759         bodyNode = bnode;
760         label = lbl;
761     }
762 
763     override Variant accept(IStatementVisitor visitor)
764     {
765         return visitor.visitWhileStatementNode(this);
766     }
767 
768     override string toString() const
769     {
770         auto str = "while(" ~ conditionNode.toString() ~ ") ";
771         str ~= bodyNode.toString();
772         return str;
773     }
774 
775     ExpressionNode conditionNode;
776     StatementNode bodyNode;
777     string label;
778 }
779 
780 class DoWhileStatementNode : StatementNode
781 {
782     this(size_t lineNo, StatementNode bnode, ExpressionNode condition, string lbl="")
783     {
784         super(lineNo);
785         bodyNode = bnode;
786         conditionNode = condition;
787         label = lbl;
788     }
789 
790     override Variant accept(IStatementVisitor visitor)
791     {
792         return visitor.visitDoWhileStatementNode(this);
793     }
794 
795     override string toString() const
796     {
797         auto str = "do " ~ bodyNode.toString() ~ " while("
798             ~ conditionNode.toString() ~ ")";
799         return str;
800     }
801 
802     StatementNode bodyNode;
803     ExpressionNode conditionNode;
804     string label;
805 }
806 
807 class ForStatementNode : StatementNode
808 {
809     this(size_t lineNo, VarDeclarationStatementNode decl, ExpressionNode condition, ExpressionNode increment, 
810          StatementNode bnode, string lbl="")
811     {
812         super(lineNo);
813         varDeclarationStatement = decl;
814         conditionNode = condition;
815         incrementNode = increment;
816         bodyNode = bnode;
817         label = lbl;
818     }
819 
820     override Variant accept(IStatementVisitor visitor)
821     {
822         return visitor.visitForStatementNode(this);
823     }
824 
825     override string toString() const
826     {
827         auto decl = "";
828         if(varDeclarationStatement !is null)
829             decl = varDeclarationStatement.toString();
830         auto str = "for(" ~ decl ~ ";" ~ conditionNode.toString() 
831             ~ ";" ~ incrementNode.toString() ~ ") " ~ bodyNode.toString();
832         return str;
833     }
834 
835     VarDeclarationStatementNode varDeclarationStatement;
836     ExpressionNode conditionNode;
837     ExpressionNode incrementNode;
838     StatementNode bodyNode;
839     string label;
840 }
841 
842 // for of can't do let {a,b} but it can do let a,b and be used the same as for in in JS
843 class ForOfStatementNode : StatementNode
844 {
845     this(size_t lineNo, Token qual, Token ofIn, VarAccessNode[] vans, ExpressionNode obj, 
846          StatementNode bnode, string lbl="")
847     {
848         super(lineNo);
849         qualifierToken = qual;
850         ofInToken = ofIn;
851         varAccessNodes = vans;
852         objectToIterateNode = obj;
853         bodyNode = bnode;
854         label = lbl;
855     }
856 
857     override Variant accept(IStatementVisitor visitor)
858     {
859         return visitor.visitForOfStatementNode(this);
860     }
861 
862     override string toString() const
863     {
864         auto str = "for(" ~ qualifierToken.text;
865         for(size_t i = 0; i < varAccessNodes.length; ++i)
866         {
867             str ~= varAccessNodes[i].varToken.text;
868             if(i < varAccessNodes.length - 1) // @suppress(dscanner.suspicious.length_subtraction)
869                 str ~= ", ";
870         }
871         str ~= " of " 
872             ~ objectToIterateNode.toString() ~ ")" 
873             ~ bodyNode.toString();
874         return str;
875     }
876 
877     Token qualifierToken;
878     Token ofInToken;
879     VarAccessNode[] varAccessNodes;
880     ExpressionNode objectToIterateNode;
881     StatementNode bodyNode;
882     string label;
883 }
884 
885 class BreakStatementNode : StatementNode
886 {
887     this(size_t lineNo, string lbl="")
888     {
889         super(lineNo);
890         label = lbl;
891     }
892 
893     override Variant accept(IStatementVisitor visitor)
894     {
895         return visitor.visitBreakStatementNode(this);
896     }
897 
898     override string toString() const
899     {
900         return "break " ~ label ~ ";";
901     }
902 
903     string label;
904 }
905 
906 class ContinueStatementNode : StatementNode
907 {
908     this(size_t lineNo, string lbl = "")
909     {
910         super(lineNo);
911         label = lbl;
912     }
913 
914     override Variant accept(IStatementVisitor visitor)
915     {
916         return visitor.visitContinueStatementNode(this);
917     }
918 
919     override string toString() const
920     {
921         return "continue " ~ label ~ ";";
922     }
923 
924     string label;
925 }
926 
927 class ReturnStatementNode : StatementNode
928 {
929     this(size_t lineNo, ExpressionNode expr = null)
930     {
931         super(lineNo);
932         expressionNode = expr;
933     }
934 
935     override Variant accept(IStatementVisitor visitor)
936     {
937         return visitor.visitReturnStatementNode(this);
938     }
939 
940     override string toString() const
941     {
942         auto str = "return";
943         if(expressionNode !is null)
944             str ~= " " ~ expressionNode.toString;
945         return str ~ ";";
946     }
947 
948     ExpressionNode expressionNode;
949 }
950 
951 class FunctionDeclarationStatementNode : StatementNode
952 {
953     this(size_t lineNo, string n, string[] args, ExpressionNode[] defArgs, StatementNode[] statements, bool isG = false)
954     {
955         super(lineNo);
956         name = n;
957         argNames = args;
958         defaultArguments = defArgs;
959         statementNodes = statements;
960         isGenerator = isG;
961     }
962 
963     override Variant accept(IStatementVisitor visitor)
964     {
965         return visitor.visitFunctionDeclarationStatementNode(this);
966     }
967 
968     override string toString() const
969     {
970         auto str = "function " ~ name ~ "(";
971         for(int i = 0; i < argNames.length; ++i)
972         {
973             str ~= argNames[i];
974             if(i < argNames.length - 1) // @suppress(dscanner.suspicious.length_subtraction)
975                 str ~= ", ";
976         }
977         str ~= ") {";
978         foreach(st ; statementNodes)
979             str ~= "\t" ~ st.toString;
980         str ~= "}";
981         return str;
982     }
983 
984     string name;
985     string[] argNames;
986     ExpressionNode[] defaultArguments;
987     StatementNode[] statementNodes;
988     bool isGenerator;
989 }
990 
991 class ThrowStatementNode : StatementNode
992 {
993     this(size_t lineNo, ExpressionNode expr)
994     {
995         super(lineNo);
996         expressionNode = expr;
997     }
998 
999     override Variant accept(IStatementVisitor visitor)
1000     {
1001         return visitor.visitThrowStatementNode(this);
1002     }
1003 
1004     override string toString() const
1005     {
1006         return "throw " ~ expressionNode.toString() ~ ";";
1007     }
1008 
1009     ExpressionNode expressionNode;
1010 }
1011 
1012 class TryCatchBlockStatementNode : StatementNode
1013 {
1014     this(size_t lineNo, StatementNode tryBlock, string name, StatementNode catchBlock=null, StatementNode fin=null)
1015     {
1016         super(lineNo);
1017         tryBlockNode = tryBlock;
1018         exceptionName = name;
1019         catchBlockNode = catchBlock;
1020         finallyBlockNode = fin;
1021     }
1022 
1023     override Variant accept(IStatementVisitor visitor)
1024     {
1025         return visitor.visitTryCatchBlockStatementNode(this);
1026     }
1027 
1028     override string toString() const
1029     {
1030         string output = "try " ~ tryBlockNode.toString();
1031         if(catchBlockNode)
1032             output ~= " catch(" ~ exceptionName ~ ")" ~ catchBlockNode.toString();
1033         if(finallyBlockNode)
1034             output ~= " finally " ~ finallyBlockNode.toString();
1035         return output;
1036     }
1037 
1038     StatementNode tryBlockNode;
1039     string exceptionName;
1040     StatementNode catchBlockNode;
1041     StatementNode finallyBlockNode;
1042 }
1043 
1044 class DeleteStatementNode : StatementNode
1045 {
1046     this(size_t lineNo, Token deleteTok, ExpressionNode accessNode)
1047     {
1048         super(lineNo);
1049         deleteToken = deleteTok;
1050         memberAccessOrArrayIndexNode = accessNode;
1051     }
1052 
1053     override Variant accept(IStatementVisitor visitor)
1054     {
1055         return visitor.visitDeleteStatementNode(this);
1056     }
1057 
1058     override string toString() const
1059     {
1060         return "delete " ~ memberAccessOrArrayIndexNode.toString ~ ";";
1061     }
1062 
1063     Token deleteToken;
1064     ExpressionNode memberAccessOrArrayIndexNode;
1065 }
1066 
1067 class ClassDeclarationStatementNode : StatementNode
1068 {
1069     this(size_t lineNo, Token ctoken, ClassDefinition cdef)
1070     {
1071         super(lineNo);
1072         classToken = ctoken;
1073         classDefinition = cdef;
1074     }
1075 
1076     override Variant accept(IStatementVisitor visitor)
1077     {
1078         return visitor.visitClassDeclarationStatementNode(this);
1079     }
1080 
1081     override string toString() const
1082     {
1083         return classDefinition.toString();
1084     }
1085 
1086     Token classToken;
1087     ClassDefinition classDefinition;
1088 }
1089 
1090 class ExpressionStatementNode : StatementNode
1091 {
1092     this(size_t lineNo, ExpressionNode expression)
1093     {
1094         super(lineNo);
1095         expressionNode = expression;
1096     }
1097 
1098     override Variant accept(IStatementVisitor visitor)
1099 	{
1100         return visitor.visitExpressionStatementNode(this);
1101     }
1102 
1103     override string toString() const
1104     {
1105         if(expressionNode is null)
1106             return ";";
1107         return expressionNode.toString() ~ ";";
1108     }
1109 
1110     ExpressionNode expressionNode;
1111 }