1 /++ 2 Contains definitions for "nodes" making the AST 3 +/ 4 module qscript.compiler.ast; 5 6 import utils.misc; 7 import utils.lists; 8 import qscript.compiler.compiler; 9 import qscript.compiler.tokengen : Token, TokenList; 10 11 import std.conv : to; 12 13 /// a node representing the script 14 package struct ScriptNode{ 15 /// list of functions defined in this script 16 public FunctionNode[] functions; 17 /// structs defined in this script 18 public StructNode[] structs; 19 /// enums defined in this script 20 public EnumNode[] enums; 21 /// global variables defined in this script 22 public VarDeclareNode[] variables; 23 /// stores what this script imports 24 public string[] imports; 25 /// constructor 26 this (FunctionNode[] scriptFunctions){ 27 functions = scriptFunctions.dup; 28 } 29 } 30 31 /// a node representing a function definition 32 package struct FunctionNode{ 33 /// struct to store arguments for function 34 public struct Argument{ 35 string argName; /// the name of the var storing the arg 36 DataType argType; /// the data type of the arg 37 /// constructor 38 this (string name, DataType type){ 39 argName = name; 40 argType = type; 41 } 42 } 43 /// the line number (starts from 1) from which this node begins, or ends 44 public uinteger lineno; 45 /// Stores visibility for this node 46 public Visibility visibility = Visibility.Private; 47 /// number of elements to allocate on stack for variables, this is set by ASTCheck 48 public uinteger varStackCount; 49 /// stores arguments with their data type 50 public FunctionNode.Argument[] arguments; 51 /// returns: data types of arguments 52 public @property DataType[] argTypes(){ 53 DataType[] r; 54 r.length = arguments.length; 55 foreach (i, arg; arguments){ 56 r[i] = arg.argType; 57 } 58 return r; 59 } 60 /// the name of the function 61 public string name; 62 /// body block of this function 63 public BlockNode bodyBlock; 64 /// the data type of the return value of this function 65 public DataType returnType = DataType(DataType.Type.Void); 66 /// the id of this function, assigned after checkAST has been called on this 67 public uinteger id; 68 /// constructor 69 this (DataType returnDataType, string fName, FunctionNode.Argument[] funcArgs, BlockNode fBody){ 70 bodyBlock = fBody; 71 name = fName; 72 arguments = funcArgs.dup; 73 returnType = returnType; 74 } 75 /// Returns: the data types for arguments 76 @property DataType[] argumentTypes(){ 77 DataType[] r; 78 r.length = arguments.length; 79 foreach (i, arg; arguments){ 80 r[i] = arg.argType; 81 } 82 return r; 83 } 84 /// Returns: the names for arguments 85 @property string[] argumentNames(){ 86 string[] r; 87 r.length = arguments.length; 88 foreach (i, arg; arguments){ 89 r[i] = arg.argName; 90 } 91 return r; 92 } 93 } 94 95 /// To store a struct definition 96 package struct StructNode{ 97 /// the line number (starts from 1) from which this node begins, or ends 98 public uinteger lineno; 99 /// Stores visibility for this node 100 public Visibility visibility = Visibility.Private; 101 /// the actual struct 102 private Struct _struct; 103 /// the name of this struct 104 public @property string name(){ 105 return _struct.name; 106 } 107 /// ditto 108 public @property string name(string newName){ 109 return _struct.name = newName; 110 } 111 /// name of members of this struct 112 public @property ref string[] membersName() return { 113 return _struct.membersName; 114 } 115 /// ditto 116 public @property ref string[] membersName(string[] newMembersName) return { 117 return _struct.membersName = newMembersName; 118 } 119 /// data types of members of this struct 120 public @property ref DataType[] membersDataType() return{ 121 return _struct.membersDataType; 122 } 123 /// ditto 124 public @property ref DataType[] membersDataType(DataType[] newMembersDataType) return{ 125 return _struct.membersDataType = newMembersDataType; 126 } 127 /// Returns: true if this struct contains a reference 128 public @property bool containsRef(){ 129 foreach (type; _struct.membersDataType){ 130 if (type.isRef) 131 return true; 132 } 133 return false; 134 } 135 /// Returns: Library.Struct representing this 136 public @property Struct toStruct(){ 137 return _struct; 138 } 139 } 140 141 /// To store a enum definition 142 package struct EnumNode{ 143 /// the line number (starts from 1) from which this node begins, or ends 144 public uinteger lineno; 145 /// Stores visibility for this node 146 public Visibility visibility = Visibility.Private; 147 /// stores the actual enum 148 private Enum _enum; 149 /// Returns: the name of this enum 150 public @property string name() return{ 151 return _enum.name; 152 } 153 /// ditto 154 public @property string name(string newName) return{ 155 return _enum.name = newName; 156 } 157 /// Returns: the members' names (index is the int value it gets replaced with) 158 public @property ref string[] members() return{ 159 return _enum.members; 160 } 161 /// ditto 162 public @property ref string[] members(string[] newMembers) return{ 163 return _enum.members = newMembers; 164 } 165 /// returns: misc.Enum representing this enum 166 public Enum toEnum(){ 167 return _enum; 168 } 169 } 170 171 /// to store var declaration 172 package struct VarDeclareNode{ 173 /// the line number (starts from 1) from which this node begins, or ends 174 public uinteger lineno; 175 /// Stores visibility for this node 176 public Visibility visibility = Visibility.Private; 177 /// the data typre of defined vars 178 public DataType type; 179 /// stores names of vars declared 180 private string[] varNames; 181 /// stores IDs of vars declared, only assigned after ASTCheck has checked it 182 private uinteger[string] _varIDs; 183 /// stores vars' assigned values, with key=varName 184 private CodeNode[string] varValues; 185 /// returns: array contataining names of declared vars. Modifying this array won't have any effect 186 public @property string[] vars(){ 187 return varNames.dup; 188 } 189 /// returns: array containig ID's of variables in assoc_array 190 public @property uinteger[string] varIDs(){ 191 return _varIDs.dup; 192 } 193 /// Returns: assigned value for a var 194 /// 195 /// Throws: Exception if that variable was not assigned in this statement, or no value was assigned to it 196 public ref CodeNode getValue(string varName){ 197 if (varName in varValues){ 198 return varValues[varName]; 199 } 200 throw new Exception ("variable "~varName~" does not exist in array"); 201 } 202 /// Returns: true if a variable has a value assigned to it 203 public bool hasValue(string varName){ 204 if (varName in varValues) 205 return true; 206 return false; 207 } 208 /// adds a variable to the list 209 public void addVar(string varName){ 210 varNames = varNames ~ varName; 211 } 212 /// adds a variable to the list, along with it's assigned value 213 public void addVar(string varName, CodeNode value){ 214 varValues[varName] = value; 215 varNames = varNames ~ varName; 216 } 217 /// sets a stored var's assigned value 218 public void setVarValue(string varName, CodeNode value){ 219 varValues[varName] = value; 220 } 221 /// sets a stored var's ID 222 public void setVarID(string varName, uinteger id){ 223 _varIDs[varName] = id; 224 } 225 /// constructor 226 this (string[] vars){ 227 varNames = vars.dup; 228 } 229 } 230 231 /// a node representing a "set-of-statements" AKA a "block" 232 package struct BlockNode{ 233 /// the line number (starts from 1) from which this node begins, or ends 234 public uinteger lineno; 235 /// an array of statements that make this block 236 public StatementNode[] statements; 237 /// constructor 238 this (StatementNode[] blockStatements){ 239 statements = blockStatements.dup; 240 } 241 } 242 243 /// a node to represent code that evaluates to some data. 244 /// 245 /// This node can contain: 246 /// 1. Function call - to only those functions that return some data 247 /// 2. Literals 248 /// 3. Operators 249 /// 4. Variables 250 /// 5. Arrays (Literal, or with variable elements) 251 package struct CodeNode{ 252 /// Returns: the line number (starts from 1) from which this node begins, or ends 253 @property uinteger lineno(){ 254 if (_type == Type.FunctionCall){ 255 return fCall.lineno; 256 }else if (_type == Type.Literal){ 257 return literal.lineno; 258 }else if (_type == Type.Operator){ 259 return operator.lineno; 260 }else if (_type == Type.Variable){ 261 return var.lineno; 262 }else if (_type == Type.ReadElement){ 263 return arrayRead.lineno; 264 }else if (_type == Type.Array){ 265 return array.lineno; 266 }else if (_type == Type.SOperator){ 267 return sOperator.lineno; 268 }else if (_type == Type.MemberSelector){ 269 return memberSelector.lineno; 270 } 271 return 0; 272 } 273 /// ditto 274 @property uinteger lineno(uinteger newLineno){ 275 if (_type == Type.FunctionCall){ 276 return fCall.lineno = newLineno; 277 }else if (_type == Type.Literal){ 278 return literal.lineno = newLineno; 279 }else if (_type == Type.Operator){ 280 return operator.lineno = newLineno; 281 }else if (_type == Type.Variable){ 282 return var.lineno = newLineno; 283 }else if (_type == Type.ReadElement){ 284 return arrayRead.lineno = newLineno; 285 }else if (_type == Type.Array){ 286 return array.lineno = newLineno; 287 }else if (_type == Type.SOperator){ 288 return sOperator.lineno = newLineno; 289 }else if (_type == Type.MemberSelector){ 290 return memberSelector.lineno = newLineno; 291 } 292 return 0; 293 } 294 /// enum defining the possible types this node can store 295 public enum Type{ 296 FunctionCall, 297 Literal, 298 Negative, 299 Operator, // double operand operator 300 SOperator, // single operand operator 301 Variable, 302 ReadElement, 303 Array, 304 MemberSelector 305 } 306 /// the stored type 307 private Type _type; 308 /// union storing all possible nodes 309 private union{ 310 FunctionCallNode fCall; 311 LiteralNode literal; 312 NegativeValueNode negativeVal; 313 OperatorNode operator; 314 SOperatorNode sOperator; 315 VariableNode var; 316 ReadElement arrayRead; 317 ArrayNode array; 318 MemberSelectorNode memberSelector; 319 } 320 /// returns the type of the stored type 321 @property CodeNode.Type type(){ 322 return _type; 323 } 324 /// sets the stored node 325 @property auto ref node (T)(T newNode){ 326 static if (is (T == FunctionCallNode)){ 327 _type = CodeNode.Type.FunctionCall; 328 return fCall = newNode; 329 }else static if (is (T == LiteralNode)){ 330 _type = CodeNode.Type.Literal; 331 return literal = newNode; 332 }else static if (is (T == NegativeValueNode)){ 333 _type = CodeNode.Type.Negative; 334 return negativeVal = newNode; 335 }else static if (is (T == OperatorNode)){ 336 _type = CodeNode.Type.Operator; 337 return operator = newNode; 338 }else static if (is (T == VariableNode)){ 339 _type = CodeNode.Type.Variable; 340 return var = newNode; 341 }else static if (is (T == ReadElement)){ 342 _type = CodeNode.Type.ReadElement; 343 return arrayRead = newNode; 344 }else static if(is (T == ArrayNode)){ 345 _type = CodeNode.Type.Array; 346 return array = newNode; 347 }else static if (is (T == SOperatorNode)){ 348 _type = CodeNode.Type.SOperator; 349 return sOperator = newNode; 350 }else static if (is (T == MemberSelectorNode)){ 351 _type = CodeNode.Type.MemberSelector; 352 return memberSelector = newNode; 353 } 354 } 355 /// returns the stored type 356 @property auto ref node(CodeNode.Type T)(){ 357 // make sure it's the correct type 358 if (T != _type){ 359 throw new Exception("attempting to retrieve invalid type from CodeNode.node"); 360 } 361 static if (T == CodeNode.Type.FunctionCall){ 362 return fCall; 363 }else static if (T == CodeNode.Type.Literal){ 364 return literal; 365 }else static if (T == CodeNode.Type.Negative){ 366 return negativeVal; 367 }else static if (T == CodeNode.Type.Operator){ 368 return operator; 369 }else static if (T == CodeNode.Type.Variable){ 370 return var; 371 }else static if (T == CodeNode.Type.ReadElement){ 372 return arrayRead; 373 }else static if (T == CodeNode.Type.Array){ 374 return array; 375 }else static if (T == CodeNode.Type.SOperator){ 376 return sOperator; 377 }else static if (T == CodeNode.Type.MemberSelector){ 378 return memberSelector; 379 }else{ 380 throw new Exception("attempting to retrieve invalid type from CodeNode.node"); 381 } 382 } 383 /// Returns: true if the stored data is literal 384 public @property bool isLiteral (){ 385 if (_type == CodeNode.Type.Literal) 386 return true; 387 if (_type == CodeNode.Type.Negative) 388 return negativeVal.isLiteral; 389 if (_type == CodeNode.Type.Array) 390 return array.isLiteral; 391 if (_type == CodeNode.Type.Operator) 392 return operator.isLiteral; 393 if (_type == CodeNode.Type.ReadElement) 394 return arrayRead.isLiteral; 395 if (_type == CodeNode.Type.SOperator) 396 return sOperator.isLiteral; 397 if (_type == CodeNode.Type.Variable) 398 return var.isLiteral; 399 if (_type == CodeNode.Type.MemberSelector) 400 return memberSelector.isLiteral; 401 return false; 402 } 403 /// the return type, only available after ASTCheck has checked it 404 @property DataType returnType (){ 405 if (_type == CodeNode.Type.Array){ 406 return array.returnType; 407 }else if (_type == CodeNode.Type.FunctionCall){ 408 return fCall.returnType; 409 }else if (_type == CodeNode.Type.Literal){ 410 return literal.returnType; 411 }else if (_type == CodeNode.Type.Negative){ 412 return negativeVal.returnType; 413 }else if (_type == CodeNode.Type.Operator){ 414 return operator.returnType; 415 }else if (_type == CodeNode.Type.ReadElement){ 416 return arrayRead.returnType; 417 }else if (_type == CodeNode.Type.SOperator){ 418 return sOperator.returnType; 419 }else if (_type == CodeNode.Type.Variable){ 420 return var.returnType; 421 }else if (_type == CodeNode.Type.MemberSelector){ 422 return memberSelector.returnType; 423 } 424 return DataType(); 425 } 426 /// ditto 427 @property DataType returnType (DataType newType){ 428 if (_type == CodeNode.Type.Array){ 429 return array.returnType = newType; 430 }else if (_type == CodeNode.Type.FunctionCall){ 431 return fCall.returnType = newType; 432 }else if (_type == CodeNode.Type.Literal){ 433 return literal.returnType = newType; 434 }else if (_type == CodeNode.Type.Negative){ 435 return negativeVal.returnType = newType; 436 }else if (_type == CodeNode.Type.Operator){ 437 return operator.returnType = newType; 438 }else if (_type == CodeNode.Type.ReadElement){ 439 return arrayRead.returnType = newType; 440 }else if (_type == CodeNode.Type.SOperator){ 441 return sOperator.returnType = newType; 442 }else if (_type == CodeNode.Type.Variable){ 443 return var.returnType = newType; 444 }else if (_type == CodeNode.Type.MemberSelector){ 445 return memberSelector.returnType = newType; 446 } 447 return DataType(); 448 } 449 /// constructor 450 this (T)(T newNode){ 451 node = newNode; 452 } 453 } 454 455 /// to store a member selection (someStructOrEnum.memberName) 456 package struct MemberSelectorNode{ 457 /// Types 458 public enum Type{ 459 EnumMemberRead, /// reading a member from an enum 460 StructMemberRead, /// reading a member from a struct 461 } 462 /// stores the type this MemberSelector is of. Only valid after ASTCheck has been called on this 463 public Type type; 464 /// the line number (starts from 1) from which this node begins, or ends 465 public uinteger lineno; 466 /// the parent node (to select member from) 467 private CodeNode* _parentPtr; 468 /// name of member, this is valid for Type.EnumMemberRead & Type.StructMemberRead 469 public string memberName; 470 /// Return type. Only valid after ASTCheck 471 public DataType returnType; 472 /// index of memberName in struct definition or enum definition. Only valid after ASTCheck 473 public integer memberNameIndex = -1; 474 /// stores if value is static 475 public bool isLiteral = false; 476 /// Returns: the parent node 477 @property ref CodeNode parent(){ 478 return *_parentPtr; 479 } 480 /// ditto 481 @property CodeNode parent(CodeNode newParent){ 482 if (!_parentPtr) 483 _parentPtr = new CodeNode; 484 return *_parentPtr = newParent; 485 } 486 /// Constructor 487 this(CodeNode parent, string member, uinteger lineno){ 488 this.parent = parent; 489 this.memberName = member; 490 this.lineno = lineno; 491 } 492 } 493 494 /// stores a variable 495 package struct VariableNode{ 496 /// the line number (starts from 1) from which this node begins, or ends 497 public uinteger lineno; 498 /// the name of this var 499 public string varName; 500 /// the ID of the variable. This is assigned in the ASTCheck stage, not in ASTGen 501 public integer id; 502 /// the library ID where this is defined 503 public integer libraryId = -1; 504 /// stores if this is a global variable. Only valid valid after ASTCheck has been called on this. 505 public bool isGlobal = false; 506 /// if the variable is script defined (global or not), assigned after checkAST has been called on this 507 public deprecated @property bool isScriptDefined(){ 508 return libraryId == -1; 509 } 510 /// stores the return type. Only stored after ASTCheck has checked it 511 public DataType returnType = DataType(DataType.Type.Void); 512 /// true if its return value is static, i.e, will always return same value when evaluated 513 /// 514 /// determined by ASTCheck 515 /// 516 /// TODO yet to be implemented, probably won't be done till 0.7.1 517 public bool isLiteral = false; 518 /// constructor 519 this (string name){ 520 varName = name; 521 isLiteral = false; 522 returnType = DataType(DataType.Type.Void); 523 libraryId = -1; 524 isGlobal = false; 525 } 526 } 527 528 /// stores array, for example, `[0, 1, x, y]` will be stored using this 529 package struct ArrayNode{ 530 /// the line number (starts from 1) from which this node begins, or ends 531 uinteger lineno; 532 /// stores the elements 533 public CodeNode[] elements; 534 /// Returns: true if its return value is static, i.e, will always return same value when executed 535 public @property bool isLiteral (){ 536 foreach (element; elements) 537 if (!element.isLiteral) 538 return false; 539 return true; 540 } 541 /// the return type 542 @property DataType returnType (){ 543 if (elements.length == 0) 544 return DataType(DataType.Type.Void,1); 545 DataType r = elements[0].returnType; 546 if (r.type == DataType.Type.Void) 547 return r; 548 r.arrayDimensionCount++; 549 return r; 550 } 551 /// does nothing (besides existing) 552 @property DataType returnType(DataType newType){ 553 return this.returnType; 554 } 555 /// constructor 556 this (CodeNode[] elements){ 557 this.elements = elements; 558 } 559 } 560 561 /// stores literal data, i.e data that was availabe at runtime. Can store strings, double, integer, 562 /// but arrays (even ones without variables, only literals) are stored in ArrayNode 563 package struct LiteralNode{ 564 /// the line number (starts from 1) from which this node begins, or ends 565 public uinteger lineno; 566 /// stores the data type for the literal 567 public DataType returnType = DataType(DataType.Type.Void); 568 /// stores the literal 569 public string literal; 570 /// constructor 571 this (string data, DataType dataType){ 572 literal = data; 573 returnType = dataType; 574 } 575 /// constructor using `fromTokens` 576 this (Token tokenLiteral){ 577 fromToken(tokenLiteral); 578 } 579 /// reads the literal from a string 580 /// 581 /// throws Exception on error 582 void fromToken(Token token){ 583 returnType.fromData(token); 584 literal = token.token; 585 } 586 } 587 588 /// stores `-x` 589 package struct NegativeValueNode{ 590 /// the line number (starts from 1) from which this node begins, or ends 591 public uinteger lineno; 592 /// stores the value to make negative 593 private CodeNode* _valuePtr; 594 /// value to make negative 595 @property ref CodeNode value(){ 596 return *_valuePtr; 597 } 598 /// ditto 599 @property ref CodeNode value(CodeNode newVal){ 600 if (_valuePtr is null) 601 _valuePtr = new CodeNode(); 602 return *_valuePtr = newVal; 603 } 604 /// return data type 605 public @property DataType returnType(){ 606 return (*_valuePtr).returnType; 607 } 608 /// ditto 609 public @property DataType returnType(DataType newType){ 610 return this.returnType; 611 } 612 /// Returns: true if it's value is literal, i.e fixed/constant 613 @property bool isLiteral(){ 614 return (*_valuePtr).isLiteral; 615 } 616 /// constructor 617 this(CodeNode val){ 618 value = val; 619 } 620 } 621 622 /// stores an operator with two operands 623 package struct OperatorNode{ 624 /// the line number (starts from 1) from which this node begins, or ends 625 public uinteger lineno; 626 /// stores the operator (like '+' ...) 627 public string operator; 628 /// operands. [0] = left, [1] = right 629 public CodeNode[] operands; 630 /// Returns: true if its return value is static, i.e, will always return same value when executed 631 public @property bool isLiteral (){ 632 foreach (operand; operands){ 633 if (!operand.isLiteral) 634 return false; 635 } 636 return true; 637 } 638 /// the return type. Only valid after ASTCheck has checked it 639 public @property DataType returnType(){ 640 return fCall.returnType; 641 } 642 /// ditto 643 public @property DataType returnType(DataType newType){ 644 return fCall.returnType = newType; 645 } 646 /// FunctionCallNode corresponding to this OperatorNode. Only valid after ASTCheck 647 public FunctionCallNode fCall; 648 /// constructor 649 this (string operatorString, CodeNode a, CodeNode b){ 650 operator = operatorString; 651 operands.length = 2; 652 operands[0] = a; 653 operands[1] = b; 654 } 655 } 656 657 /// stores an operator with single operand (like ! and @) 658 package struct SOperatorNode{ 659 /// the line number (starts from 1) from which this node begins, or ends 660 public uinteger lineno; 661 /// the operator string 662 public string operator; 663 /// the stored operand 664 private CodeNode* operandPtr; 665 /// the operand 666 public @property ref CodeNode operand(CodeNode newOperand){ 667 if (operandPtr is null){ 668 operandPtr = new CodeNode; 669 } 670 return *operandPtr = newOperand; 671 } 672 /// the operand 673 public @property ref CodeNode operand(){ 674 return *operandPtr; 675 } 676 /// the return type. Only valid after ASTCheck has checked it 677 public @property DataType returnType(){ 678 return fCall.returnType; 679 } 680 /// ditto 681 public @property DataType returnType(DataType newType){ 682 return fCall.returnType = newType; 683 } 684 /// FunctionCallNode corresponding to this OperatorNode. Only valid after ASTCheck 685 public FunctionCallNode fCall; 686 /// Returns: true if its return value is static, i.e will always be same when executed 687 @property bool isLiteral(){ 688 return (operandPtr !is null && operand.isLiteral); 689 } 690 } 691 692 /// stores an "array-read" (instruction `readElement` or for string, `readChar`) 693 package struct ReadElement{ 694 /// the line number (starts from 1) from which this node begins, or ends 695 public uinteger lineno; 696 /// the node to read from 697 private CodeNode* readFromPtr = null; 698 /// the index to read at 699 private CodeNode* readIndexPtr = null; 700 /// the node to read from 701 public @property ref CodeNode readFromNode(){ 702 if (readFromPtr is null) 703 readFromPtr = new CodeNode; 704 return *readFromPtr; 705 } 706 /// the node to read from 707 public @property ref CodeNode readFromNode(CodeNode newNode){ 708 if (readFromPtr is null) 709 readFromPtr = new CodeNode; 710 return *readFromPtr = newNode; 711 } 712 /// the index to read at 713 public @property ref CodeNode index(){ 714 if (readIndexPtr is null) 715 readIndexPtr = new CodeNode; 716 return *readIndexPtr; 717 } 718 /// the index to read at 719 public @property ref CodeNode index(CodeNode newNode){ 720 if (readIndexPtr is null) 721 readIndexPtr = new CodeNode; 722 return *readIndexPtr = newNode; 723 } 724 /// returns the data type this node will return 725 public @property DataType returnType(){ 726 DataType r = (*readFromPtr).returnType; 727 r.arrayDimensionCount --; 728 return r; 729 } 730 /// does nothing, besides existing but needed for compiling 731 public @property DataType returnType(DataType newType){ 732 return this.returnType; 733 } 734 /// Returns: true if its return value is static, i.e, will always return same value when executed 735 @property bool isLiteral(){ 736 return (readFromPtr !is null && readIndexPtr !is null && readFromNode.isLiteral && index.isLiteral); 737 } 738 /// constructor 739 this (CodeNode toReadNode, CodeNode index){ 740 this.readFromNode = toReadNode; 741 this.index = index; 742 } 743 } 744 745 /// a node representing statements, including: if, while, function-call.. 746 package struct StatementNode{ 747 /// types of a statement 748 public enum Type{ 749 If, 750 While, 751 For, 752 DoWhile, 753 Block, 754 Assignment, 755 FunctionCall, 756 VarDeclare, 757 Return 758 } 759 /// Returns: the line number (starts from 1) from which this node begins, or ends 760 public @property uinteger lineno(){ 761 if (_type == Type.If){ 762 return ifNode.lineno; 763 }else if (_type == Type.While){ 764 return whileNode.lineno; 765 }else if (_type == Type.For){ 766 return forNode.lineno; 767 }else if (_type == Type.DoWhile){ 768 return doWhile.lineno; 769 }else if (_type == Type.Block){ 770 return blockNode.lineno; 771 }else if (_type == Type.Assignment){ 772 return assignNode.lineno; 773 }else if (_type == Type.FunctionCall){ 774 return functionCallNode.lineno; 775 }else if (_type == Type.VarDeclare){ 776 return varDeclareNode.lineno; 777 }else if (_type == Type.Return){ 778 return returnNode.lineno; 779 } 780 return 0; 781 } 782 /// ditto 783 public @property uinteger lineno(uinteger newLineno){ 784 if (_type == Type.If){ 785 return ifNode.lineno = newLineno; 786 }else if (_type == Type.While){ 787 return whileNode.lineno = newLineno; 788 }else if (_type == Type.For){ 789 return forNode.lineno = newLineno; 790 }else if (_type == Type.DoWhile){ 791 return doWhile.lineno = newLineno; 792 }else if (_type == Type.Block){ 793 return blockNode.lineno = newLineno; 794 }else if (_type == Type.Assignment){ 795 return assignNode.lineno = newLineno; 796 }else if (_type == Type.FunctionCall){ 797 return functionCallNode.lineno = newLineno; 798 }else if (_type == Type.VarDeclare){ 799 return varDeclareNode.lineno = newLineno; 800 }else if (_type == Type.Return){ 801 return returnNode.lineno = newLineno; 802 } 803 return 0; 804 } 805 /// type of this statement 806 private Type _type; 807 /// the stored node, is in this union 808 private union{ 809 IfNode ifNode; 810 WhileNode whileNode; 811 ForNode forNode; 812 DoWhileNode doWhile; 813 BlockNode blockNode; 814 FunctionCallNode functionCallNode; 815 VarDeclareNode varDeclareNode; 816 AssignmentNode assignNode; 817 ReturnNode returnNode; 818 } 819 /// modifies the stored node 820 @property void node(T)(T newNode){ 821 static if (is (T == IfNode)){ 822 _type = StatementNode.Type.If; 823 ifNode = newNode; 824 }else static if (is (T == WhileNode)){ 825 _type = StatementNode.Type.While; 826 whileNode = newNode; 827 }else static if (is (T == ForNode)){ 828 _type = StatementNode.Type.For; 829 forNode = newNode; 830 }else static if (is (T == DoWhileNode)){ 831 _type = StatementNode.Type.DoWhile; 832 doWhile = newNode; 833 }else static if (is (T == BlockNode)){ 834 _type = StatementNode.Type.Block; 835 blockNode = newNode; 836 }else static if (is (T == FunctionCallNode)){ 837 _type = StatementNode.Type.FunctionCall; 838 functionCallNode = newNode; 839 }else static if (is (T == VarDeclareNode)){ 840 _type = StatementNode.Type.VarDeclare; 841 varDeclareNode = newNode; 842 }else static if (is (T == AssignmentNode)){ 843 _type = StatementNode.Type.Assignment; 844 assignNode = newNode; 845 }else static if (is (T == ReturnNode)){ 846 _type = Type.Return; 847 returnNode = newNode; 848 }else{ 849 throw new Exception("attempting to assign invalid node type to StatementNode.node"); 850 } 851 } 852 /// returns the stored type 853 @property auto ref node(StatementNode.Type T)(){ 854 // make sure type is correct 855 if (T != _type){ 856 throw new Exception("stored type does not match with type being retrieved"); 857 } 858 static if (T == StatementNode.Type.If){ 859 return ifNode; 860 }else static if (T == StatementNode.Type.While){ 861 return whileNode; 862 }else static if (T == StatementNode.Type.For){ 863 return forNode; 864 }else static if (T == StatementNode.Type.DoWhile){ 865 return doWhile; 866 }else static if (T == StatementNode.Type.Block){ 867 return blockNode; 868 }else static if (T == StatementNode.Type.FunctionCall){ 869 return functionCallNode; 870 }else static if (T == StatementNode.Type.VarDeclare){ 871 return varDeclareNode; 872 }else static if (T == StatementNode.Type.Assignment){ 873 return assignNode; 874 }else static if (T == StatementNode.Type.Return){ 875 return returnNode; 876 }else{ 877 throw new Exception("attempting to retrieve invalid type from StatementNode.node"); 878 } 879 } 880 /// returns the type of the stored node 881 @property StatementNode.Type type(){ 882 return _type; 883 } 884 /// constructor 885 this (T)(T newNode){ 886 node = newNode; 887 } 888 } 889 890 /// to store assignment statements 891 package struct AssignmentNode{ 892 /// the line number (starts from 1) from which this node begins, or ends 893 public uinteger lineno; 894 /// stores whether the assignment is to a variable (false) or if it has to dereference first (true) 895 public bool deref = false; 896 /// the variable to assign to 897 public CodeNode lvalue; 898 /// the value to assign 899 public CodeNode rvalue; 900 /// constructor 901 this (CodeNode lv, CodeNode rv, bool deref = false){ 902 lvalue = lv; 903 rvalue = rv; 904 this.deref = deref; 905 } 906 } 907 908 /// to store if statements 909 package struct IfNode{ 910 /// the line number (starts from 1) from which this node begins, or ends 911 public uinteger lineno; 912 /// the condition for this if statement 913 public CodeNode condition; 914 /// stores the pointer to the statement to execute 915 private StatementNode* statementPtr; 916 /// returns the statement to execute, if true 917 public @property ref StatementNode statement(){ 918 if (statementPtr is null) 919 statementPtr = new StatementNode; 920 return *statementPtr; 921 } 922 /// sets the statement to execute, if true 923 public @property ref StatementNode statement(StatementNode newStatement){ 924 if (statementPtr is null){ 925 statementPtr = new StatementNode; 926 } 927 return *statementPtr = newStatement; 928 } 929 /// stores the pointer to the statement to execute if the condition is false. 930 private StatementNode* elseStatementPtr; 931 /// returns the statement to execute, if false 932 public @property ref StatementNode elseStatement(){ 933 if (elseStatementPtr is null) 934 elseStatementPtr = new StatementNode; 935 return *elseStatementPtr; 936 } 937 /// sets the statement to execute, if true 938 public @property ref StatementNode elseStatement(StatementNode newElseStatement){ 939 if (elseStatementPtr is null){ 940 elseStatementPtr = new StatementNode; 941 } 942 return *elseStatementPtr = newElseStatement; 943 } 944 945 /// stores whether this if has an else statement too 946 public bool hasElse = false; 947 /// constructor 948 this (CodeNode conditionNode, StatementNode statementToExecute, StatementNode elseStatementToExec){ 949 condition = conditionNode; 950 statement = statementToExecute; 951 elseStatement = elseStatementToExec; 952 hasElse = true; 953 } 954 /// constructor 955 this (CodeNode conditionNode, StatementNode statementsToExecute){ 956 condition = conditionNode; 957 statement = statementsToExecute; 958 hasElse = false; 959 } 960 } 961 962 /// to store while statements 963 package struct WhileNode{ 964 /// the line number (starts from 1) from which this node begins, or ends 965 public uinteger lineno; 966 /// the condition for this while statement 967 public CodeNode condition; 968 /// stores the pointer to the statement to execute in loop while the condition is true 969 private StatementNode* statementPtr; 970 /// returns the statement to execute, while true 971 public @property ref StatementNode statement(){ 972 if (statementPtr is null) 973 statementPtr = new StatementNode; 974 return *statementPtr; 975 } 976 /// sets the statement to execute, while true 977 public @property ref StatementNode statement(StatementNode newStatement){ 978 if (statementPtr is null){ 979 statementPtr = new StatementNode; 980 } 981 return *statementPtr = newStatement; 982 } 983 /// constructor 984 this (CodeNode conditionNode, StatementNode statementToExec){ 985 condition = conditionNode; 986 statement = statementToExec; 987 } 988 } 989 990 /// to store do-while statements 991 package struct DoWhileNode{ 992 /// the line number (starts from 1) from which this node begins, or ends 993 public uinteger lineno; 994 /// the condition for this do-while statement 995 public CodeNode condition; 996 /// stores pointer to the statement to execute in this loop 997 private StatementNode* statementPtr; 998 /// the statement to execute in this loop 999 public @property ref StatementNode statement(){ 1000 if (statementPtr is null) 1001 statementPtr = new StatementNode; 1002 return *statementPtr; 1003 } 1004 /// ditto 1005 public @property ref StatementNode statement(StatementNode newStatement){ 1006 if (statementPtr is null){ 1007 statementPtr = new StatementNode; 1008 } 1009 return *statementPtr = newStatement; 1010 } 1011 /// constructor 1012 this (CodeNode conditionNode, StatementNode statementToExec){ 1013 condition = conditionNode; 1014 statement = statementToExec; 1015 } 1016 } 1017 1018 /// to store for loop statements 1019 package struct ForNode{ 1020 /// the line number (starts from 1) from which this node begins, or ends 1021 public uinteger lineno; 1022 /// stores the pointer to initialization statement, i.e: `for (<this one>; bla; bla)...` 1023 private StatementNode* initStatementPtr; 1024 /// stores the pointer to the increment statement, i.e: `for (bla; bla; <this one>)...` 1025 private StatementNode* incStatementPtr; 1026 /// stores the condition CodeNode 1027 public CodeNode condition; 1028 /// stores the pointer to the statement to execute in loop 1029 private StatementNode* statementPtr; 1030 /// the init statement for this for loop 1031 public @property ref StatementNode initStatement(){ 1032 if (initStatementPtr is null) 1033 initStatementPtr = new StatementNode; 1034 return *initStatementPtr; 1035 } 1036 /// ditto 1037 public @property ref StatementNode initStatement(StatementNode newStatement){ 1038 if (initStatementPtr is null){ 1039 initStatementPtr = new StatementNode; 1040 } 1041 return *initStatementPtr = newStatement; 1042 } 1043 /// the increment statement for this for loop 1044 public @property ref StatementNode incStatement(){ 1045 if (incStatementPtr is null) 1046 incStatementPtr = new StatementNode; 1047 return *incStatementPtr; 1048 } 1049 /// ditto 1050 public @property ref StatementNode incStatement(StatementNode newStatement){ 1051 if (incStatementPtr is null){ 1052 incStatementPtr = new StatementNode; 1053 } 1054 return *incStatementPtr = newStatement; 1055 } 1056 /// the statement to execute in loop 1057 public @property ref StatementNode statement(){ 1058 if (statementPtr is null) 1059 statementPtr = new StatementNode; 1060 return *statementPtr; 1061 } 1062 /// ditto 1063 public @property ref StatementNode statement(StatementNode newStatement){ 1064 if (statementPtr is null){ 1065 statementPtr = new StatementNode; 1066 } 1067 return *statementPtr = newStatement; 1068 } 1069 /// constructor 1070 this (StatementNode initNode, CodeNode conditionNode, StatementNode incNode, StatementNode statementToExec){ 1071 initStatement = initNode; 1072 condition = conditionNode; 1073 incStatement = incNode; 1074 statement = statementToExec; 1075 } 1076 } 1077 1078 /// to store functionCall nodes 1079 package struct FunctionCallNode{ 1080 /// the line number (starts from 1) from which this node begins, or ends 1081 public uinteger lineno; 1082 /// the id of the library this function is from. 1083 public integer libraryId = -1; 1084 /// the name of the function 1085 public string fName; 1086 /// the id of the function, assigned after checkAST has been called on this 1087 public integer id; 1088 /// if the function being called is script defined or not, assigned after checkAST has been called on this 1089 public deprecated @property bool isScriptDefined(){ 1090 return libraryId == -1; 1091 } 1092 /// the arguments for this function. 1093 private CodeNode[] _arguments; 1094 /// returns the values for arguments 1095 @property ref CodeNode[] arguments() return{ 1096 return _arguments; 1097 } 1098 /// sets value for storedArguments 1099 @property ref CodeNode[] arguments(CodeNode[] newArgs) return{ 1100 return _arguments = newArgs.dup; 1101 } 1102 /// stores the return type. Only stored after ASTCheck has checked it 1103 public DataType returnType = DataType(DataType.Type.Void); 1104 /// constructor 1105 this (string functionName, CodeNode[] functionArguments){ 1106 fName = functionName; 1107 arguments = functionArguments; 1108 returnType = DataType(DataType.Type.Void); 1109 libraryId = -1; 1110 } 1111 } 1112 1113 package struct ReturnNode{ 1114 /// the line number on which this node was read from 1115 public uinteger lineno; 1116 /// the value to return from function 1117 public CodeNode value; 1118 }