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