1 /++
2 For generating byte code from AST
3 +/
4 module qscript.compiler.codegen;
5 
6 import qscript.compiler.ast;
7 import qscript.compiler.astcheck;
8 import qscript.compiler.misc;
9 
10 import utils.misc;
11 import utils.lists;
12 
13 import navm.navm : Instruction, NaData;
14 import navm.navm : readData;
15 import navm.bytecodedefs; // needed to check how many elements instruction wants from stack
16 
17 import std.conv : to;
18 
19 /// Contains functions to generate ByteCode from AST nodes
20 class CodeGen{
21 private:
22 	/// writer
23 	NaByteCodeWriter _writer;
24 	/// stores script defined functions
25 	Function[] _functions;
26 protected:
27 	/// generates byte code for a FunctionNode
28 	void generateByteCode(FunctionNode node){
29 		_writer.startFunction(node.arguments.length);
30 		// use push to reserve space on stack for variables
31 		foreach (i; 0 .. node.varCount - node.arguments.length){
32 			_writer.addInstruction(Instruction.Push, ["0"]);
33 		}
34 		generateByteCode(node.bodyBlock);
35 		// don't forget to Terminate
36 		_writer.addInstruction(Instruction.Terminate);
37 		_writer.appendFunction();
38 		// add itself to _functions
39 		Function itself;
40 		itself.name = node.name;
41 		itself.returnType = node.returnType;
42 		itself.argTypes.length = node.arguments.length;
43 		foreach (i, arg; node.arguments)
44 			itself.argTypes[i] = arg.argType;
45 		_functions[node.id] = itself;
46 	}
47 	/// generates byte code for a BlockNode
48 	void generateByteCode(BlockNode node){
49 		foreach (statement; node.statements){
50 			generateByteCode(statement);
51 		}
52 	}
53 	/// generates byte code for a StatementNode
54 	void generateByteCode(StatementNode node){
55 		if (node.type == StatementNode.Type.Assignment){
56 			generateByteCode(node.node!(StatementNode.Type.Assignment));
57 		}else if (node.type == StatementNode.Type.Block){
58 			generateByteCode(node.node!(StatementNode.Type.Block));
59 		}else if (node.type == StatementNode.Type.DoWhile){
60 			generateByteCode(node.node!(StatementNode.Type.DoWhile));
61 		}else if (node.type == StatementNode.Type.For){
62 			generateByteCode(node.node!(StatementNode.Type.For));
63 		}else if (node.type == StatementNode.Type.FunctionCall){
64 			generateByteCode(node.node!(StatementNode.Type.FunctionCall), false, true);
65 		}else if (node.type == StatementNode.Type.If){
66 			generateByteCode(node.node!(StatementNode.Type.If));
67 		}else if (node.type == StatementNode.Type.VarDeclare){
68 			generateByteCode(node.node!(StatementNode.Type.VarDeclare));
69 		}else if (node.type == StatementNode.Type.While){
70 			generateByteCode(node.node!(StatementNode.Type.While));
71 		}else if (node.type == StatementNode.Type.Return){
72 			generateByteCode(node.node!(StatementNode.Type.Return));
73 		}
74 	}
75 	/// generates byte code for AssignmentNode
76 	void generateByteCode(AssignmentNode node){
77 		// first get the value
78 		generateByteCode(node.val);
79 		if (node.indexes.length > 0){
80 			// use ReadElement to get the element to write to
81 			for (integer i = node.indexes.length -1; i >= 0;i--){
82 				generateByteCode(node.indexes[i]);
83 			}
84 			_writer.addInstruction(node.deref ? Instruction.PushFrom : Instruction.PushRefFrom, [to!string(node.var.id)]); // this gets the ref ot array
85 			// now add readElement for each of those
86 			foreach (i; 0 .. node.indexes.length){
87 				_writer.addInstruction(Instruction.ArrayRefElement);
88 			}
89 			_writer.addInstruction(Instruction.WriteToRef); // and this writes value to ref
90 		}else if (node.deref){
91 			_writer.addInstruction(Instruction.PushFrom, [to!string(node.var.id)]); // this gets the ref
92 			_writer.addInstruction(Instruction.WriteToRef); // and this writes value to ref
93 		}else{
94 			// just do pushTo 
95 			_writer.addInstruction(Instruction.WriteTo, [to!string(node.var.id)]);
96 		}
97 	}
98 	/// generates ByteCode for DoWhileNode
99 	void generateByteCode(DoWhileNode node){
100 		static uinteger jumpID = 0;
101 		const uinteger currentJumpID = jumpID;
102 		jumpID++;
103 		// get the index of where the loop starts
104 		_writer.addJumpPos("DoWhileStart"~currentJumpID.to!string);
105 		// now comes loop body
106 		generateByteCode(node.statement);
107 		// condition
108 		generateByteCode(node.condition);
109 		_writer.addInstruction(Instruction.JumpIf, ["DoWhileStart"~currentJumpID.to!string]);
110 	}
111 	/// generates byte code for ForNode
112 	void generateByteCode(ForNode node){
113 		static uinteger jumpID = 0;
114 		const uinteger currentJumpID = jumpID;
115 		jumpID++;
116 		generateByteCode(node.initStatement);
117 		// condition
118 		_writer.addJumpPos("ForStart"~currentJumpID.to!string);
119 		generateByteCode(node.condition);
120 		_writer.addInstruction(Instruction.Not);
121 		_writer.addInstruction(Instruction.JumpIf, ["ForEnd"~currentJumpID.to!string]); //placeholder, will write jumpToIndex later
122 		// loop body
123 		generateByteCode(node.statement);
124 		// now the increment statement
125 		generateByteCode(node.incStatement);
126 		// jump back
127 		_writer.addInstruction(Instruction.Jump, ["ForStart"~currentJumpID.to!string]);
128 		_writer.addJumpPos("ForEnd"~currentJumpID.to!string);
129 	}
130 	/// generates byte code for FunctionCallNode
131 	/// 
132 	/// pushRef is ignored
133 	void generateByteCode(FunctionCallNode node, bool pushRef = false, bool popReturn = false){
134 		if (!node.isScriptDefined && node.isInBuilt){
135 			generateInBuiltFunctionByteCode(node, popReturn);
136 		}else{
137 			// push args
138 			foreach (arg; node.arguments){
139 				generateByteCode(arg);
140 			}
141 			_writer.addInstruction(node.isScriptDefined ? Instruction.ExecuteFunction : Instruction.ExecuteFunctionExternal,
142 				[to!string(node.id), to!string(node.arguments.length)]);
143 			if (popReturn)
144 				_writer.addInstruction(Instruction.Pop);
145 		}
146 	}
147 	/// generates byte code for inbuilt QScript functions (`length(void[])` and stuff)
148 	void generateInBuiltFunctionByteCode(FunctionCallNode node, bool popReturn = false){
149 		/// argument types of function call
150 		DataType[] argTypes;
151 		argTypes.length = node.arguments.length;
152 		foreach (i, arg; node.arguments){
153 			argTypes[i] = arg.returnType;
154 		}
155 		/// encoded name of function
156 		string fName = encodeFunctionName(node.fName, argTypes);
157 		/// stores if the instructions added push 1 element to stack, or zero (false)
158 		bool pushesToStack = true;
159 		/// length(@void[], int)
160 		if (node.fName == "length"){
161 			if (matchArguments([DataType(DataType.Type.Void, 1, true), DataType(DataType.Type.Integer)],argTypes)){
162 				// set array length
163 				generateByteCode(node.arguments[1]); // length comes first, coz it's popped later
164 				generateByteCode(node.arguments[0]);
165 				_writer.addInstruction(Instruction.ArrayLengthSet);
166 				pushesToStack = false;
167 			}else if (matchArguments([DataType(DataType.Type.Void, 1, false)], argTypes) ||
168 			matchArguments([DataType(DataType.Type.Char, 1, true)], argTypes)){
169 				// get array/string length
170 				generateByteCode(node.arguments[0]);
171 				_writer.addInstruction(Instruction.ArrayLength);
172 			}
173 		}else if (fName == encodeFunctionName("toInt", [DataType(DataType.Type.Char, 1)])){
174 			/// toInt(string)
175 			generateByteCode(node.arguments[0]);
176 			_writer.addInstruction(Instruction.StringToInt);
177 		}else if (fName == encodeFunctionName("toInt", [DataType(DataType.Type.Double)])){
178 			/// toInt(double)
179 			generateByteCode(node.arguments[0]);
180 			_writer.addInstruction(Instruction.DoubleToInt);
181 		}else if (fName == encodeFunctionName("toDouble", [DataType(DataType.Type.Char, 1)])){
182 			/// toDouble(string)
183 			generateByteCode(node.arguments[0]);
184 			_writer.addInstruction(Instruction.StringToDouble);
185 		}else if (fName == encodeFunctionName("toDouble", [DataType(DataType.Type.Integer)])){
186 			/// toDouble(int)
187 			generateByteCode(node.arguments[0]);
188 			_writer.addInstruction(Instruction.IntToDouble);
189 		}else if (fName == encodeFunctionName("toStr", [DataType(DataType.Type.Integer)])){
190 			/// toStr(int)
191 			generateByteCode(node.arguments[0]);
192 			_writer.addInstruction(Instruction.IntToString);
193 		}else if (fName == encodeFunctionName("toStr", [DataType(DataType.Type.Double)])){
194 			/// toStr(double)
195 			generateByteCode(node.arguments[0]);
196 			_writer.addInstruction(Instruction.DoubleToString);
197 		}else if (node.fName == "copy" && matchArguments(
198 			[DataType(DataType.Type.Void, 1), DataType(DataType.Type.Void, 1, true)], argTypes)){
199 			// first push the argument
200 			generateByteCode(node.arguments[0]);
201 			_writer.addInstruction(Instruction.CopyArray, []);
202 			generateByteCode(node.arguments[1]);
203 			_writer.addInstruction(Instruction.WriteToRef, []);
204 			pushesToStack = false;
205 		}
206 		if (pushesToStack && popReturn)
207 			_writer.addInstruction(Instruction.Pop);
208 	}
209 	/// generates byte code for IfNode
210 	void generateByteCode(IfNode node){
211 		static uinteger jumpID = 0;
212 		const uinteger currentJumpID = jumpID;
213 		jumpID++;
214 		generateByteCode(node.condition);
215 		_writer.addInstruction(Instruction.JumpIf, ["IfTrue"~currentJumpID.to!string]);
216 		if (node.hasElse)
217 			generateByteCode(node.elseStatement);
218 		_writer.addInstruction(Instruction.Jump, ["IfEnd"~currentJumpID.to!string]);
219 		_writer.addJumpPos("IfTrue"~currentJumpID.to!string);
220 		generateByteCode(node.statement);
221 		_writer.addJumpPos("IfEnd"~currentJumpID.to!string);
222 
223 	}
224 	/// generates byte code for VarDeclareNode - actually, just checks if a value is being assigned to it, if yes, makes var a ref to that val
225 	void generateByteCode(VarDeclareNode node){
226 		foreach (varName; node.vars){
227 			if (node.hasValue(varName))
228 				generateByteCode(node.getValue(varName));
229 			else
230 				_writer.addInstruction(Instruction.Push, [node.type == DataType(DataType.Type.Double) ? "0.0" : "0"]);
231 			_writer.addInstruction(Instruction.WriteTo, [to!string(node.varIDs[varName])]);
232 		}
233 	}
234 	/// generates byte code for WhileNode
235 	void generateByteCode(WhileNode node){
236 		static uinteger jumpID = 0;
237 		const uinteger currentJumpID = jumpID;
238 		jumpID++;
239 		immutable uinteger conditionIndex = _writer.instructionCount;
240 		_writer.addJumpPos("WhileStart"~currentJumpID.to!string);
241 		generateByteCode(node.condition);
242 		_writer.addInstruction(Instruction.Not);
243 		_writer.addInstruction(Instruction.JumpIf, ["WhileEnd"~currentJumpID.to!string]);
244 		generateByteCode(node.statement);
245 		_writer.addInstruction(Instruction.Jump, ["WhileStart"~currentJumpID.to!string]);
246 		_writer.addJumpPos("WhileEnd"~currentJumpID.to!string);
247 	}
248 	/// generates byte code for ReturnNode
249 	void generateByteCode(ReturnNode node){
250 		generateByteCode(node.value);
251 		_writer.addInstruction(Instruction.ReturnVal);
252 		// remember, return terminates execution in qscript, not in navm
253 		_writer.addInstruction(Instruction.Terminate);
254 	}
255 
256 	/// generates byte code for CodeNode
257 	void generateByteCode(CodeNode node, bool pushRef = false){
258 		if (node.type == CodeNode.Type.FunctionCall){
259 			generateByteCode(node.node!(CodeNode.Type.FunctionCall), pushRef);
260 		}else if (node.type == CodeNode.Type.Literal){
261 			generateByteCode(node.node!(CodeNode.Type.Literal), pushRef);
262 		}else if (node.type == CodeNode.Type.Negative){
263 			generateByteCode(node.node!(CodeNode.Type.Negative), pushRef);
264 		}else if (node.type == CodeNode.Type.Operator){
265 			generateByteCode(node.node!(CodeNode.Type.Operator), pushRef);
266 		}else if (node.type == CodeNode.Type.SOperator){
267 			generateByteCode(node.node!(CodeNode.Type.SOperator), pushRef);
268 		}else if (node.type == CodeNode.Type.ReadElement){
269 			generateByteCode(node.node!(CodeNode.Type.ReadElement), pushRef);
270 		}else if (node.type == CodeNode.Type.Variable){
271 			generateByteCode(node.node!(CodeNode.Type.Variable), pushRef);
272 		}else if (node.type == CodeNode.Type.Array){
273 			generateByteCode(node.node!(CodeNode.Type.Array), pushRef);
274 		}
275 	}
276 	/// generates byte code for LiteralNode
277 	/// 
278 	/// pushRef is ignored
279 	void generateByteCode(LiteralNode node, bool pushRef = false){
280 		_writer.addInstruction(Instruction.Push, [node.literal]);
281 	}
282 	/// generates byte code for NegativeValueNode
283 	/// 
284 	/// pushRef is ignored
285 	void generateByteCode(NegativeValueNode node, bool pushRef = false){
286 		// push the value
287 		generateByteCode(node.value, false);
288 		// push the appropriate zero
289 		_writer.addInstruction(Instruction.Push, [node.value.returnType.type == DataType.Type.Integer ? "0" : "0.0"]);
290 		// now subtract
291 		_writer.addInstruction(node.value.returnType.type == DataType.Type.Integer ?
292 			Instruction.MathSubtractInt : Instruction.MathSubtractDouble);
293 	}
294 	/// generates byte code for OperatorNode
295 	/// 
296 	/// pushRef is ignored
297 	void generateByteCode(OperatorNode node, bool pushRef = false){
298 		bool isFloat = false;
299 		if (node.operands[0].returnType == DataType(DataType.Type.Double) ||
300 			node.operands[1].returnType == DataType(DataType.Type.Double)){
301 			isFloat = true;
302 		}
303 		Instruction opInst;
304 		switch (node.operator){
305 		case "/":
306 			opInst = isFloat ? Instruction.MathDivideDouble : Instruction.MathDivideInt;
307 			break;
308 		case "*":
309 			opInst = isFloat ? Instruction.MathMultiplyDouble : Instruction.MathMultiplyInt;
310 			break;
311 		case "+":
312 			opInst = isFloat ? Instruction.MathAddDouble : Instruction.MathAddInt;
313 			break;
314 		case "-":
315 			opInst = isFloat ? Instruction.MathSubtractDouble : Instruction.MathSubtractInt;
316 			break;
317 		case "%":
318 			opInst = isFloat ? Instruction.MathModDouble : Instruction.MathModInt;
319 			break;
320 		case "<":
321 			// the the end, just flip the oprands and use > (isGreater) because < doesnt exist in navm
322 			opInst = isFloat ? Instruction.IsGreaterDouble : Instruction.IsGreaterInt;
323 			break;
324 		case ">":
325 			opInst = isFloat ? Instruction.IsGreaterDouble : Instruction.IsGreaterInt;
326 			break;
327 		case "<=":
328 			// the the end, just flip the oprands and use >= (isGreaterSame) because <= doesnt exist in navm
329 			opInst = isFloat ? Instruction.IsGreaterSameDouble : Instruction.IsGreaterSameInt;
330 			break;
331 		case ">=":
332 			opInst = isFloat ? Instruction.IsGreaterSameDouble : Instruction.IsGreaterSameInt;
333 			break;
334 		case "==":
335 			opInst = node.operands[0].returnType.isArray ? Instruction.IsSameArray : Instruction.IsSame;
336 			break;
337 		case "&&":
338 			opInst = Instruction.And;
339 			break;
340 		case "||":
341 			opInst = Instruction.Or;
342 			break;
343 		case "~":
344 			opInst = Instruction.Concatenate;
345 			break;
346 		default:
347 			break;
348 		}
349 		// if operator is < or <=, then need to flip operands and change operator to > or >=
350 		if (node.operator == "<" || node.operator == "<="){
351 			node.operator = node.operator == "<" ? ">" : ">=";
352 			CodeNode operand = node.operands[0];
353 			node.operands[0] = node.operands[1];
354 			node.operands[1] = operand;
355 		}
356 		generateByteCode(node.operands[1]);
357 		generateByteCode(node.operands[0]);
358 		_writer.addInstruction(opInst);
359 	}
360 	/// generates byte code for SOperatorNode
361 	/// 
362 	/// pushRef is ignored
363 	void generateByteCode(SOperatorNode node, bool pushRef = false){
364 		// only 2 SOperators exist at this point, ref/de-ref, and `!`
365 		if (node.operator == "@"){
366 			// check if its being de-ref-ed
367 			if (node.operand.returnType.isRef){
368 				generateByteCode(node.operand);
369 				_writer.addInstruction(Instruction.Deref,[]);
370 			}else if (node.operand.type == CodeNode.Type.Variable){
371 				generateByteCode(node.operand, true);
372 			}else if (node.operand.type == CodeNode.Type.ReadElement){
373 				generateByteCode(node.operand.node!(CodeNode.Type.ReadElement), true);
374 			}
375 		}else if (node.operator == "!"){
376 			generateByteCode(node.operand);
377 			_writer.addInstruction(Instruction.Not);
378 		}
379 	}
380 	/// generates byte code for ReadElement
381 	void generateByteCode(ReadElement node, bool pushRef = false){
382 		generateByteCode(node.index);
383 		// the array should be a ref to array, following if-else takes care of that
384 		if (node.readFromNode.type == CodeNode.Type.ReadElement || node.readFromNode.type == CodeNode.Type.Variable){
385 			generateByteCode(node.readFromNode, true);
386 			_writer.addInstruction(Instruction.ArrayRefElement);
387 		}else{
388 			generateByteCode(node.readFromNode);
389 			_writer.addInstruction(Instruction.ArrayElement);
390 		}
391 		if (!pushRef)
392 			_writer.addInstruction(Instruction.Deref);
393 	}
394 	/// generates byte code for VariableNode
395 	void generateByteCode(VariableNode node, bool pushRef = false){
396 		_writer.addInstruction(pushRef ? Instruction.PushRefFrom : Instruction.PushFrom, [to!string(node.id)]);
397 	}
398 	/// generates byte code for ArrayNode
399 	/// 
400 	/// pushRef is ignored
401 	void generateByteCode(ArrayNode node, bool pushRef = false){
402 		foreach (element; node.elements){
403 			generateByteCode(element);
404 		}
405 		_writer.addInstruction(Instruction.MakeArray, [node.elements.length.to!string]);
406 	}
407 public:
408 	/// constructor
409 	this (){
410 		_writer = new NaByteCodeWriter();
411 	}
412 	/// destructor
413 	~this(){
414 		.destroy(_writer);
415 	}
416 	/// Returns: generated bytecode
417 	string[] getByteCode(){
418 		return _writer.getCode;
419 	}
420 	/// Returns: array of functions defined in script. The index is the function id (used to call function at runtime)
421 	Function[] getFunctionMap(){
422 		return _functions.dup;
423 	}
424 	/// generates byte code for ScriptNode
425 	void generateByteCode(ScriptNode node){
426 		_functions.length = node.functions.length;
427 		foreach (func; node.functions){
428 			generateByteCode(func);
429 		}
430 	}
431 }
432 
433 /// Used to generate byte code.
434 /// 
435 /// Code is really messy in here, needs improving
436 private class NaByteCodeWriter{
437 private:
438 	/// instructions of all functions
439 	List!(string[]) _generatedInstructions;
440 	/// arguments of all functions' instructions
441 	List!(string[][]) _generatedInstructionArgs;
442 	/// stackLength of each function
443 	List!uinteger _stackLengths;
444 	/// instructions of function currently being written to
445 	List!string _currentInst;
446 	/// arguments of instructions of functions currently being written to
447 	List!(string[]) _currentInstArgs;
448 	/// number of elements used up on stack at a point
449 	uinteger _currentStackUsage;
450 	/// max number of elements used on on stack (reset to 0 before starting on a new function)
451 	uinteger _maxStackUsage;
452 
453 	/// called to update _maxStackUsageg if necessary
454 	void updateStackUsage(){
455 		if (_currentStackUsage > _maxStackUsage)
456 			_maxStackUsage = _currentStackUsage;
457 	}
458 public:
459 	/// Stores types of errors given by `this.addInstruction`
460 	enum ErrorType : ubyte{
461 		StackElementsInsufficient, /// the instructions needs to pop more elements than there are, on the stack
462 		ArgumentCountMismatch, /// instruction needs different number of arguemnts than provided
463 		NoError, /// there was no error
464 	}
465 	/// constructor
466 	this(){
467 		_generatedInstructions = new List!(string[]);
468 		_generatedInstructionArgs = new List!(string[][]);
469 		_currentInst = new List!string;
470 		_currentInstArgs = new List!(string[]);
471 		_stackLengths = new List!uinteger;
472 	}
473 	/// destructor
474 	~this(){
475 		.destroy(_generatedInstructions);
476 		.destroy(_generatedInstructionArgs);
477 		.destroy(_currentInst);
478 		.destroy(_currentInstArgs);
479 		.destroy(_stackLengths);
480 	}
481 	/// Returns: generated byte code in a NaFunction[]
482 	string[] getCode(){
483 		string[] r;
484 		{
485 			uinteger l = 0;
486 			foreach (instArray; _generatedInstructions.toArray){
487 				l += instArray.length+1;
488 			}
489 			r.length = l;
490 		}
491 		uinteger writeTo = 0;
492 		foreach (i, instList; _generatedInstructions.toArray){
493 			r[writeTo] = "def "~to!string(_stackLengths.read(i));
494 			writeTo ++;
495 			string[][] args = _generatedInstructionArgs.read(i);
496 			foreach (index, inst; instList){
497 				string argStr = "";
498 				foreach (arg; args[index]){
499 					argStr ~= ' ' ~ arg;
500 				}
501 				r[writeTo] = to!string(inst) ~ argStr;
502 				writeTo++;
503 			}
504 		}
505 		return r;
506 	}
507 	/// Call to prepare writing a function
508 	void startFunction(uinteger argCount){
509 		// clear lists
510 		_currentInst.clear;
511 		_currentInstArgs.clear;
512 		// make space for arguments on stack
513 		_maxStackUsage = argCount;
514 		_currentStackUsage = argCount;
515 	}
516 	/// Call when a function has been completely written to.
517 	void appendFunction(){
518 		string[] instructions;
519 		instructions.length = _currentInst.length;
520 		string[] inst = _currentInst.toArray;
521 		foreach (i, instruction; inst){
522 			instructions[i] = '\t'~instruction;
523 		}
524 		_generatedInstructions.append(instructions);
525 		_generatedInstructionArgs.append(_currentInstArgs.toArray);
526 		_stackLengths.append(_maxStackUsage);
527 		// reset
528 		_currentInst.clear;
529 		_currentInstArgs.clear;
530 		_maxStackUsage = 0;
531 		_currentStackUsage = 0;
532 	}
533 	/// Returns: nunmber of elements currently on stack
534 	@property uinteger stackLength(){
535 		return _currentStackUsage;
536 	}
537 	/// Returns: number of instructions
538 	@property uinteger instructionCount(){
539 		return _currentInst.length;
540 	}
541 	/// Adds an instruction
542 	///
543 	/// Returns: type of error if any, else, ErrorType.NoError
544 	ErrorType addInstruction(Instruction inst, string[] args = []){
545 		if (args.length != INSTRUCTION_ARG_COUNT[inst])
546 			return ErrorType.ArgumentCountMismatch;
547 		NaData[] argsNaData;
548 		argsNaData.length = args.length;
549 		foreach (i, arg; args){
550 			try{
551 				argsNaData[i] = readData(arg);
552 			}catch (Exception e){
553 				argsNaData[i] = NaData(0); // its a ugly hack, i know, but it works...
554 			}
555 		}
556 		immutable uinteger popCount = instructionPopCount(inst, argsNaData);
557 		immutable uinteger pushCount = INSTRUCTION_PUSH_COUNT[inst];
558 		if (popCount > _currentStackUsage)
559 			return ErrorType.StackElementsInsufficient;
560 		_currentStackUsage -= popCount;
561 		_currentStackUsage += pushCount;
562 		updateStackUsage;
563 		_currentInst.append(inst.to!string);
564 		_currentInstArgs.append(args.dup);
565 		return ErrorType.NoError;
566 	}
567 	/// Adds a jump position
568 	void addJumpPos(string name){
569 		_currentInst.append(name~':');
570 		_currentInstArgs.append(cast(string[])[]);
571 	}
572 }