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 }