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 }