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