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 }