1 /**
2  * This module implements the expression and statement node subclasses, which are used internally as a syntax tree.
3  */
4 module mildew.nodes;
5 
6 import std.format: format;
7 import std.variant;
8 
9 import mildew.context: Context;
10 import mildew.exceptions: ScriptRuntimeException;
11 import mildew.lexer: Token;
12 import mildew.types;
13 import mildew.visitors;
14 
15 package:
16 
17 /// handles class expression and declaration data
18 class ClassDefinition
19 {
20     this(string clsname, FunctionLiteralNode ctor,
21             string[] mnames, FunctionLiteralNode[] ms,
22             string[] gmnames, FunctionLiteralNode[] gms,
23             string[] smnames, FunctionLiteralNode[] sms,
24             string[] statNames, FunctionLiteralNode[] statms,
25             ExpressionNode base = null)
26     {
27         className = clsname;
28         constructor = ctor;
29         methodNames = mnames;
30         methods = ms;
31         assert(methodNames.length == methods.length);
32         getMethodNames = gmnames;
33         getMethods = gms;
34         assert(getMethodNames.length == getMethods.length);
35         setMethodNames = smnames;
36         setMethods = sms;
37         assert(setMethodNames.length == setMethods.length);
38         staticMethodNames = statNames;
39         staticMethods = statms;
40         assert(staticMethodNames.length == staticMethods.length);
41         baseClass = base;
42     }
43 
44     ScriptFunction create(Context context)
45     {
46         import mildew.interpreter: Interpreter;
47 
48         ScriptFunction ctor;
49         if(constructor !is null)
50             ctor = new ScriptFunction(className, constructor.argList, constructor.statements, context, true);
51         else
52             ctor = ScriptFunction.emptyFunction(className, true);
53         // fill in the function.prototype with the methods
54         for(size_t i = 0; i < methodNames.length; ++i) 
55 		{
56             ctor["prototype"][methodNames[i]] = new ScriptFunction(methodNames[i], 
57                     methods[i].argList, methods[i].statements, context, false);
58 		}
59         // fill in any get properties
60         for(size_t i = 0; i < getMethodNames.length; ++i)
61 		{
62             ctor["prototype"].addGetterProperty(getMethodNames[i], new ScriptFunction(
63                 getMethodNames[i], getMethods[i].argList, getMethods[i].statements, 
64                 context, false));
65 		}
66         // fill in any set properties
67         for(size_t i = 0; i < setMethodNames.length; ++i)
68 		{
69             ctor["prototype"].addSetterProperty(setMethodNames[i], new ScriptFunction(
70                 setMethodNames[i], setMethods[i].argList, setMethods[i].statements,
71                 context, false));
72 		}
73 		// static methods are assigned directly to the constructor itself
74 		for(size_t i=0; i < staticMethodNames.length; ++i)
75 		{
76 			ctor[staticMethodNames[i]] = new ScriptFunction(staticMethodNames[i], 
77                 staticMethods[i].argList, staticMethods[i].statements, context, false);
78 		}
79 
80         if(baseClass !is null)
81         {
82             immutable vr = cast(immutable)baseClass.accept(context.interpreter).get!(Interpreter.VisitResult);
83             if(vr.exception !is null)
84                 throw vr.exception;
85             if(vr.result.type != ScriptAny.Type.FUNCTION)
86             {
87                 throw new ScriptRuntimeException("Only classes can be extended");
88             }   
89             auto baseClassConstructor = vr.result.toValue!ScriptFunction;
90             auto constructorPrototype = ctor["prototype"].toValue!ScriptObject;
91             // if the base class constructor's "prototype" is null or non-object, it won't work anyway
92             // NOTE that ["prototype"] and .prototype are completely unrelated
93             constructorPrototype.prototype = baseClassConstructor["prototype"].toValue!ScriptObject;
94             // set the constructor's __proto__ to the base class so that static methods are inherited
95             // and the Function.call look up should still work
96             ctor.prototype = baseClassConstructor;
97         }
98         return ctor;
99     }
100 
101     override string toString() const 
102     {
103         string output = "class " ~ className;
104         if(baseClass) output ~= " extends " ~ baseClass.toString();
105         output ~= " {...}";
106         return output;
107     }
108 
109     string className;
110     FunctionLiteralNode constructor;
111     string[] methodNames;
112     FunctionLiteralNode[] methods;
113     string[] getMethodNames;
114     FunctionLiteralNode[] getMethods;
115     string[] setMethodNames;
116     FunctionLiteralNode[] setMethods;
117 	string[] staticMethodNames;
118 	FunctionLiteralNode[] staticMethods;
119     ExpressionNode baseClass; // should be an expression that returns a constructor function
120 }
121 
122 /// root class of expression nodes
123 abstract class ExpressionNode
124 {
125 	abstract Variant accept(IExpressionVisitor visitor);
126 
127     // have to override here for subclasses' override to work
128     override string toString() const
129     {
130         assert(false, "This should never be called as it is virtual");
131     }
132 }
133 
134 class LiteralNode : ExpressionNode 
135 {
136     this(Token token, ScriptAny val)
137     {
138         literalToken = token;
139         value = val;
140     }
141 
142 	override Variant accept(IExpressionVisitor visitor)
143 	{
144 		return visitor.visitLiteralNode(this);
145 	}
146 
147     override string toString() const
148     {
149         if(value.type == ScriptAny.Type.STRING)
150             return "\"" ~ literalToken.text ~ "\"";
151         else
152             return literalToken.text;
153     }
154 
155     Token literalToken;
156     ScriptAny value;
157 }
158 
159 class FunctionLiteralNode : ExpressionNode
160 {
161     this(string[] args, StatementNode[] stmts)
162     {
163         argList = args;
164         statements = stmts;
165     }
166 
167     override Variant accept(IExpressionVisitor visitor)
168     {
169         return visitor.visitFunctionLiteralNode(this);
170     }
171 
172     override string toString() const
173     {
174         string output = "function(";
175         for(size_t i = 0; i < argList.length; ++i)
176         {
177             output ~= argList[i];
178             if(i < argList.length - 1)
179                 output ~= ", ";
180         }
181         output ~= "){\n";
182         foreach(stmt ; statements)
183         {
184             output ~= "\t" ~ stmt.toString();
185         }
186         output ~= "\n}";
187         return output;
188     }
189 
190     string[] argList;
191     StatementNode[] statements;
192 }
193 
194 class ArrayLiteralNode : ExpressionNode 
195 {
196     this(ExpressionNode[] values)
197     {
198         valueNodes = values;
199     }
200 
201 	override Variant accept(IExpressionVisitor visitor)
202 	{
203 		return visitor.visitArrayLiteralNode(this);
204 	}
205 
206     override string toString() const
207     {
208         return format("%s", valueNodes);
209     }
210 
211     ExpressionNode[] valueNodes;
212 }
213 
214 class ObjectLiteralNode : ExpressionNode 
215 {
216     this(string[] ks, ExpressionNode[] vs)
217     {
218         keys = ks;
219         valueNodes = vs;
220     }
221 
222 	override Variant accept(IExpressionVisitor visitor)
223 	{
224 		return visitor.visitObjectLiteralNode(this);
225 	}
226 
227     override string toString() const
228     {
229         // return "(object literal node)";
230         if(keys.length != valueNodes.length)
231             return "{invalid_object}";
232         auto result = "{";
233         for(size_t i = 0; i < keys.length; ++i)
234             result ~= keys[i] ~ ":" ~ valueNodes[i].toString;
235         result ~= "}";
236         return result;
237     }
238 
239     string[] keys;
240     ExpressionNode[] valueNodes;
241 }
242 
243 class ClassLiteralNode : ExpressionNode 
244 {
245     this(ClassDefinition cdef)
246     {
247         classDefinition = cdef;
248     }
249 
250 	override Variant accept(IExpressionVisitor visitor)
251 	{
252 		return visitor.visitClassLiteralNode(this);
253 	}
254 
255     override string toString() const 
256     {
257         return classDefinition.toString();
258     }
259 
260     ClassDefinition classDefinition;
261 }
262 
263 class BinaryOpNode : ExpressionNode
264 {
265     this(Token op, ExpressionNode left, ExpressionNode right)
266     {
267         opToken = op;
268         leftNode = left;
269         rightNode = right;
270     }
271 
272 	override Variant accept(IExpressionVisitor visitor)
273 	{
274 		return visitor.visitBinaryOpNode(this);
275 	}
276 
277     override string toString() const
278     {
279         return format("(%s %s %s)", leftNode, opToken.symbol, rightNode);
280     }
281 
282     Token opToken;
283     ExpressionNode leftNode;
284     ExpressionNode rightNode;
285 }
286 
287 class UnaryOpNode : ExpressionNode
288 {
289     this(Token op, ExpressionNode operand)
290     {
291         opToken = op;
292         operandNode = operand;
293     }
294 
295 	override Variant accept(IExpressionVisitor visitor)
296 	{
297 		return visitor.visitUnaryOpNode(this);
298 	}
299 
300     override string toString() const
301     {
302         return format("(%s %s)", opToken.symbol, operandNode);
303     }
304 
305     Token opToken;
306     ExpressionNode operandNode;
307 }
308 
309 class PostfixOpNode : ExpressionNode 
310 {
311     this(Token op, ExpressionNode node)
312     {
313         opToken = op;
314         operandNode = node;
315     }
316 
317 	override Variant accept(IExpressionVisitor visitor)
318 	{
319 		return visitor.visitPostfixOpNode(this);
320 	}
321 
322     override string toString() const 
323     {
324         return operandNode.toString() ~ opToken.symbol;
325     }
326 
327     Token opToken;
328     ExpressionNode operandNode;
329 }
330 
331 class TerniaryOpNode : ExpressionNode 
332 {
333     this(ExpressionNode cond, ExpressionNode onTrue, ExpressionNode onFalse)
334     {
335         conditionNode = cond;
336         onTrueNode = onTrue;
337         onFalseNode = onFalse;
338     }
339 
340 	override Variant accept(IExpressionVisitor visitor)
341 	{
342 		return visitor.visitTerniaryOpNode(this);
343 	}
344 
345     override string toString() const 
346     {
347         return conditionNode.toString() ~ "? " ~ onTrueNode.toString() ~ " : " ~ onFalseNode.toString();
348     }
349 
350     ExpressionNode conditionNode;
351     ExpressionNode onTrueNode;
352     ExpressionNode onFalseNode;
353 }
354 
355 class VarAccessNode : ExpressionNode
356 {
357     this(Token token)
358     {
359         varToken = token;
360     }
361 
362 	override Variant accept(IExpressionVisitor visitor)
363 	{
364 		return visitor.visitVarAccessNode(this);
365 	}
366 
367     override string toString() const
368     {
369         return varToken.text;
370     }
371 
372     Token varToken;
373 }
374 
375 class FunctionCallNode : ExpressionNode
376 {
377     this(ExpressionNode fn, ExpressionNode[] args, bool retThis=false)
378     {
379         functionToCall = fn;
380         expressionArgs = args;
381         returnThis = retThis;
382     }
383 
384 	override Variant accept(IExpressionVisitor visitor)
385 	{
386 		return visitor.visitFunctionCallNode(this);
387 	}
388 
389     override string toString() const
390     {
391         auto str = functionToCall.toString ~ "(";
392         for(size_t i = 0; i < expressionArgs.length; ++i)
393         {
394             str ~= expressionArgs[i].toString;
395             if(i < expressionArgs.length - 1) // @suppress(dscanner.suspicious.length_subtraction)
396                 str ~= ", ";
397         }
398         str ~= ")";
399         return str;
400     }
401 
402     ExpressionNode functionToCall;
403     ExpressionNode[] expressionArgs;
404     bool returnThis;
405 }
406 
407 // when [] operator is used
408 class ArrayIndexNode : ExpressionNode 
409 {
410     this(ExpressionNode obj, ExpressionNode index)
411     {
412         objectNode = obj;
413         indexValueNode = index;
414     }    
415 
416 	override Variant accept(IExpressionVisitor visitor)
417 	{
418 		return visitor.visitArrayIndexNode(this);
419 	}
420 
421     override string toString() const
422     {
423         return objectNode.toString() ~ "[" ~ indexValueNode.toString() ~ "]";
424     }
425 
426     ExpressionNode objectNode;
427     ExpressionNode indexValueNode;
428 }
429 
430 class MemberAccessNode : ExpressionNode 
431 {
432     this(ExpressionNode obj, ExpressionNode member)
433     {
434         objectNode = obj;
435         memberNode = member;
436     }
437 
438 	override Variant accept(IExpressionVisitor visitor)
439 	{
440 		return visitor.visitMemberAccessNode(this);
441 	}
442 
443     override string toString() const
444     {
445         return objectNode.toString() ~ "." ~ memberNode.toString();
446     }
447 
448     ExpressionNode objectNode;
449     ExpressionNode memberNode;
450 }
451 
452 class NewExpressionNode : ExpressionNode 
453 {
454     this(ExpressionNode fn)
455     {
456         functionCallExpression = fn;
457     }
458 
459 	override Variant accept(IExpressionVisitor visitor)
460 	{
461 		return visitor.visitNewExpressionNode(this);
462 	}
463 
464     override string toString() const
465     {
466         return "new " ~ functionCallExpression.toString();
467     }
468 
469     ExpressionNode functionCallExpression;
470 }
471 
472 /// root class of all statement nodes
473 abstract class StatementNode
474 {
475     this(size_t lineNo)
476     {
477         line = lineNo;
478     }
479 
480 	abstract Variant accept(IStatementVisitor visitor);
481 
482     override string toString() const
483     {
484         assert(false, "This method is virtual and should never be called directly");
485     }
486 
487     immutable size_t line;
488 }
489 
490 class VarDeclarationStatementNode : StatementNode
491 {
492     this(Token qual, ExpressionNode[] nodes)
493     {
494         super(qual.position.line);
495         qualifier = qual;
496         varAccessOrAssignmentNodes = nodes;
497     }
498 
499 	override Variant accept(IStatementVisitor visitor)
500 	{
501 		return visitor.visitVarDeclarationStatementNode(this);
502 	}
503 
504     override string toString() const
505     {
506         string str = qualifier.text ~ " ";
507         for(size_t i = 0; i < varAccessOrAssignmentNodes.length; ++i)
508         {
509             str ~= varAccessOrAssignmentNodes[i].toString();
510             if(i < varAccessOrAssignmentNodes.length - 1) // @suppress(dscanner.suspicious.length_subtraction)
511                 str ~= ", ";
512         }
513         return str;
514     }
515 
516     Token qualifier; // must be var, let, or const
517     ExpressionNode[] varAccessOrAssignmentNodes; // must be VarAccessNode or BinaryOpNode. should be validated by parser
518 }
519 
520 class BlockStatementNode: StatementNode
521 {
522     this(size_t lineNo, StatementNode[] statements)
523     {
524         super(lineNo);
525         statementNodes = statements;
526     }
527 
528 	override Variant accept(IStatementVisitor visitor)
529 	{
530 		return visitor.visitBlockStatementNode(this);
531 	}
532 
533     override string toString() const
534     {
535         string str = "{\n";
536         foreach(st ; statementNodes)
537         {
538             str ~= "  " ~ st.toString ~ "\n";
539         }
540         str ~= "}";
541         return str;
542     }
543 
544     StatementNode[] statementNodes;
545 }
546 
547 class IfStatementNode : StatementNode
548 {
549     this(size_t lineNo, ExpressionNode condition, StatementNode onTrue, StatementNode onFalse=null)
550     {
551         super(lineNo);
552         conditionNode = condition;
553         onTrueStatement = onTrue;
554         onFalseStatement = onFalse;
555     }
556 
557 	override Variant accept(IStatementVisitor visitor)
558 	{
559 		return visitor.visitIfStatementNode(this);
560 	}
561 
562     override string toString() const
563     {
564         auto str = "if(" ~ conditionNode.toString() ~ ") ";
565         str ~= onTrueStatement.toString();
566         if(onFalseStatement !is null)
567             str ~= " else " ~ onFalseStatement.toString();
568         return str;
569     }
570 
571     ExpressionNode conditionNode;
572     StatementNode onTrueStatement, onFalseStatement;
573 }
574 
575 class SwitchStatementNode : StatementNode
576 {
577     this(size_t lineNo, ExpressionNode expr, SwitchBody sbody)
578     {
579         super(lineNo);
580         expressionNode = expr;
581         switchBody = sbody;
582     }
583 
584 	override Variant accept(IStatementVisitor visitor)
585 	{
586 		return visitor.visitSwitchStatementNode(this);
587 	}
588 
589     ExpressionNode expressionNode; // expression to test
590     SwitchBody switchBody;
591 }
592 
593 class SwitchBody
594 {
595     this(StatementNode[] statements, size_t defaultID, size_t[ScriptAny] jumpTableID)
596     {
597         statementNodes = statements;
598         defaultStatementID = defaultID;
599         jumpTable = jumpTableID;
600     }
601 
602     StatementNode[] statementNodes;
603     size_t defaultStatementID; // index into statementNodes
604     size_t[ScriptAny] jumpTable; // indexes into statementNodes
605 }
606 
607 class WhileStatementNode : StatementNode
608 {
609     this(size_t lineNo, ExpressionNode condition, StatementNode bnode, string lbl = "")
610     {
611         super(lineNo);
612         conditionNode = condition;
613         bodyNode = bnode;
614         label = lbl;
615     }
616 
617 	override Variant accept(IStatementVisitor visitor)
618 	{
619 		return visitor.visitWhileStatementNode(this);
620 	}
621 
622     override string toString() const
623     {
624         auto str = "while(" ~ conditionNode.toString() ~ ") ";
625         str ~= bodyNode.toString();
626         return str;
627     }
628 
629     ExpressionNode conditionNode;
630     StatementNode bodyNode;
631     string label;
632 }
633 
634 class DoWhileStatementNode : StatementNode
635 {
636     this(size_t lineNo, StatementNode bnode, ExpressionNode condition, string lbl="")
637     {
638         super(lineNo);
639         bodyNode = bnode;
640         conditionNode = condition;
641         label = lbl;
642     }
643 
644 	override Variant accept(IStatementVisitor visitor)
645 	{
646 		return visitor.visitDoWhileStatementNode(this);
647 	}
648 
649     override string toString() const
650     {
651         auto str = "do " ~ bodyNode.toString() ~ " while("
652             ~ conditionNode.toString() ~ ")";
653         return str;
654     }
655 
656     StatementNode bodyNode;
657     ExpressionNode conditionNode;
658     string label;
659 }
660 
661 class ForStatementNode : StatementNode
662 {
663     this(size_t lineNo, VarDeclarationStatementNode decl, ExpressionNode condition, ExpressionNode increment, 
664          StatementNode bnode, string lbl="")
665     {
666         super(lineNo);
667         varDeclarationStatement = decl;
668         conditionNode = condition;
669         incrementNode = increment;
670         bodyNode = bnode;
671         label = lbl;
672     }
673 
674 	override Variant accept(IStatementVisitor visitor)
675 	{
676 		return visitor.visitForStatementNode(this);
677 	}
678 
679     override string toString() const
680     {
681         auto decl = "";
682         if(varDeclarationStatement !is null)
683             decl = varDeclarationStatement.toString();
684         auto str = "for(" ~ decl ~ ";" ~ conditionNode.toString() 
685             ~ ";" ~ incrementNode.toString() ~ ") " ~ bodyNode.toString();
686         return str;
687     }
688 
689     VarDeclarationStatementNode varDeclarationStatement;
690     ExpressionNode conditionNode;
691     ExpressionNode incrementNode;
692     StatementNode bodyNode;
693     string label;
694 }
695 
696 // 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
697 class ForOfStatementNode : StatementNode
698 {
699     this(size_t lineNo, Token qual, VarAccessNode[] vans, ExpressionNode obj, StatementNode bnode, string lbl="")
700     {
701         super(lineNo);
702         qualifierToken = qual;
703         varAccessNodes = vans;
704         objectToIterateNode = obj;
705         bodyNode = bnode;
706         label = lbl;
707     }
708 
709 	override Variant accept(IStatementVisitor visitor)
710 	{
711 		return visitor.visitForOfStatementNode(this);
712 	}
713 
714     override string toString() const
715     {
716         auto str = "for(" ~ qualifierToken.text;
717         for(size_t i = 0; i < varAccessNodes.length; ++i)
718         {
719             str ~= varAccessNodes[i].varToken.text;
720             if(i < varAccessNodes.length - 1) // @suppress(dscanner.suspicious.length_subtraction)
721                 str ~= ", ";
722         }
723         str ~= " of " 
724             ~ objectToIterateNode.toString() ~ ")" 
725             ~ bodyNode.toString();
726         return str;
727     }
728 
729     Token qualifierToken;
730     VarAccessNode[] varAccessNodes;
731     ExpressionNode objectToIterateNode;
732     StatementNode bodyNode;
733     string label;
734 }
735 
736 class BreakStatementNode : StatementNode
737 {
738     this(size_t lineNo, string lbl="")
739     {
740         super(lineNo);
741         label = lbl;
742     }
743 
744 	override Variant accept(IStatementVisitor visitor)
745 	{
746 		return visitor.visitBreakStatementNode(this);
747 	}
748 
749     override string toString() const
750     {
751         return "break " ~ label ~ ";";
752     }
753 
754     string label;
755 }
756 
757 class ContinueStatementNode : StatementNode
758 {
759     this(size_t lineNo, string lbl = "")
760     {
761         super(lineNo);
762         label = lbl;
763     }
764 
765 	override Variant accept(IStatementVisitor visitor)
766 	{
767 		return visitor.visitContinueStatementNode(this);
768 	}
769 
770     override string toString() const
771     {
772         return "continue " ~ label ~ ";";
773     }
774 
775     string label;
776 }
777 
778 class ReturnStatementNode : StatementNode
779 {
780     this(size_t lineNo, ExpressionNode expr = null)
781     {
782         super(lineNo);
783         expressionNode = expr;
784     }
785 
786 	override Variant accept(IStatementVisitor visitor)
787 	{
788 		return visitor.visitReturnStatementNode(this);
789 	}
790 
791     override string toString() const
792     {
793         auto str = "return";
794         if(expressionNode !is null)
795             str ~= " " ~ expressionNode.toString;
796         return str ~ ";";
797     }
798 
799     ExpressionNode expressionNode;
800 }
801 
802 class FunctionDeclarationStatementNode : StatementNode
803 {
804     this(size_t lineNo, string n, string[] args, StatementNode[] statements)
805     {
806         super(lineNo);
807         name = n;
808         argNames = args;
809         statementNodes = statements;
810     }
811 
812 	override Variant accept(IStatementVisitor visitor)
813 	{
814 		return visitor.visitFunctionDeclarationStatementNode(this);
815 	}
816 
817     override string toString() const
818     {
819         auto str = "function " ~ name ~ "(";
820         for(int i = 0; i < argNames.length; ++i)
821         {
822             str ~= argNames[i];
823             if(i < argNames.length - 1) // @suppress(dscanner.suspicious.length_subtraction)
824                 str ~= ", ";
825         }
826         str ~= ") {";
827         foreach(st ; statementNodes)
828             str ~= "\t" ~ st.toString;
829         str ~= "}";
830         return str;
831     }
832 
833     string name;
834     string[] argNames;
835     StatementNode[] statementNodes;
836 }
837 
838 class ThrowStatementNode : StatementNode
839 {
840     this(size_t lineNo, ExpressionNode expr)
841     {
842         super(lineNo);
843         expressionNode = expr;
844     }
845 
846 	override Variant accept(IStatementVisitor visitor)
847 	{
848 		return visitor.visitThrowStatementNode(this);
849 	}
850 
851     override string toString() const
852     {
853         return "throw " ~ expressionNode.toString() ~ ";";
854     }
855 
856     ExpressionNode expressionNode;
857 }
858 
859 class TryCatchBlockStatementNode : StatementNode
860 {
861     this(size_t lineNo, StatementNode tryBlock, string name, StatementNode catchBlock)
862     {
863         super(lineNo);
864         tryBlockNode = tryBlock;
865         exceptionName = name;
866         catchBlockNode = catchBlock;
867     }
868 
869 	override Variant accept(IStatementVisitor visitor)
870 	{
871 		return visitor.visitTryCatchBlockStatementNode(this);
872 	}
873 
874     override string toString() const
875     {
876         return "try " ~ tryBlockNode.toString ~ " catch(" ~ exceptionName ~ ")"
877             ~ catchBlockNode.toString;
878     }
879 
880     StatementNode tryBlockNode;
881     string exceptionName;
882     StatementNode catchBlockNode;
883 }
884 
885 class DeleteStatementNode : StatementNode
886 {
887     this(size_t lineNo, ExpressionNode accessNode)
888     {
889         super(lineNo);
890         memberAccessOrArrayIndexNode = accessNode;
891     }
892 
893 	override Variant accept(IStatementVisitor visitor)
894 	{
895 		return visitor.visitDeleteStatementNode(this);
896 	}
897 
898     override string toString() const
899     {
900         return "delete " ~ memberAccessOrArrayIndexNode.toString ~ ";";
901     }
902 
903     ExpressionNode memberAccessOrArrayIndexNode;
904 }
905 
906 class ClassDeclarationStatementNode : StatementNode
907 {
908     this(size_t lineNo, ClassDefinition cdef)
909     {
910         super(lineNo);
911         classDefinition = cdef;
912     }
913 
914 	override Variant accept(IStatementVisitor visitor)
915 	{
916 		return visitor.visitClassDeclarationStatementNode(this);
917 	}
918 
919     ClassDefinition classDefinition;
920 }
921 
922 class SuperCallStatementNode : StatementNode
923 {
924     this(size_t lineNo, ExpressionNode ctc, ExpressionNode[] args)
925     {
926         super(lineNo);
927         classConstructorToCall = ctc; // Cannot be null or something wrong with parser
928         argExpressionNodes = args;
929     }
930 
931 	override Variant accept(IStatementVisitor visitor)
932 	{
933 		return visitor.visitSuperCallStatementNode(this);
934 	}
935 
936     ExpressionNode classConstructorToCall; // should always evaluate to a function
937     ExpressionNode[] argExpressionNodes;
938 }
939 
940 class ExpressionStatementNode : StatementNode
941 {
942     this(size_t lineNo, ExpressionNode expression)
943     {
944         super(lineNo);
945         expressionNode = expression;
946     }
947 
948 	override Variant accept(IStatementVisitor visitor)
949 	{
950 		return visitor.visitExpressionStatementNode(this);
951 	}
952 
953     override string toString() const
954     {
955         if(expressionNode is null)
956             return ";";
957         return expressionNode.toString() ~ ";";
958     }
959 
960     ExpressionNode expressionNode;
961 }