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