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