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