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