1 /++
2 Contains everything needed to run QScript scripts.
3 +/
4 module qscript.qscript;
5 
6 import utils.misc;
7 import utils.lists;
8 import qscript.compiler.compiler;
9 import qscript.compiler.misc;
10 import std.conv:to;
11 
12 import navm.navm;
13 
14 alias ExternFunction = navm.navm.ExternFunction;
15 alias NaData = navm.navm.NaData;
16 deprecated alias QData = NaData;
17 alias CompileError = qscript.compiler.misc.CompileError;
18 alias Function = qscript.compiler.misc.Function;
19 alias DataType = qscript.compiler.misc.DataType;
20 
21 /// Runs generated byte code generated from the compiler.
22 /// Uses NaVM, so any ordinary NaVM bytecode can also be run
23 class QScript{
24 private:
25 	NaVM _vm; /// the vm doing all the heavylifting
26 	Function[] _externFunctionMap; /// stores external functions
27 	ExternFunction[] _externFunctionPtr; /// stores external function's pointers
28 	Function[] _functionMap; /// stores script defined functions
29 	uinteger[string] _functionID; /// stores function names as index, and IDs are read using `_functionID[ID]`
30 public:
31 	/// constructor
32 	this(Function[] externalFunctions, ExternFunction[] externalFunctionPtr){
33 		_externFunctionMap = externalFunctions.dup;
34 		_externFunctionPtr = externalFunctionPtr.dup;
35 		_vm = null;
36 	}
37 	~this(){
38 		if (_vm)
39 			.destroy(_vm);
40 	}
41 	/// adds an external function.
42 	/// 
43 	/// Returns: the ID assigned to that function that will be used in the bytecode
44 	uinteger addFunction(Function externalFunc, ExternFunction externalFuncPtr){
45 		_externFunctionMap ~= externalFunc;
46 		_externFunctionPtr ~= externalFuncPtr;
47 		return _externFunctionPtr.length-1;
48 	}
49 	///
50 	void addFunction(Function[] externalFunc, ExternFunction[] externalFuncPtr){
51 		_externFunctionMap ~= externalFunc.dup;
52 		_externFunctionPtr ~= externalFuncPtr.dup;
53 	}
54 	/// Initializes the VM. must be called before executing anything in the script. And should only be called after all
55 	/// external functions have been added
56 	void initialize(){
57 		if (_vm)
58 			.destroy(_vm);
59 		_vm = new NaVM(_externFunctionPtr);
60 	}
61 	/// loads a script, and compiles it
62 	/// 
63 	/// Returns: CompileErrors in an array, or arary length == 0 if no errors
64 	CompileError[] loadScript(string[] script, ref string[] byteCode){
65 		_vm = new NaVM(_externFunctionPtr);
66 		CompileError[] errors;
67 		byteCode = compileScript(script, _externFunctionMap, errors, _functionMap);
68 		// load bytecode
69 		if (!_vm)
70 			throw new Exception("this.initizlize not called before loadScript");
71 		try{
72 			_vm.load(byteCode);
73 		}catch (Exception e){
74 			errors ~= CompileError(0, e.msg);
75 		}
76 		// put function names and IDs in _functionID
77 		foreach (i, func; _functionMap){
78 			_functionID[func.name] = i;
79 		}
80 		return errors;
81 	}
82 	/// ditto
83 	CompileError[] loadScript(string[] script){
84 		string[] byteCode;
85 		return this.loadScript(script, byteCode);
86 	}
87 	/// loads pre-compiled NaVM byte code
88 	/// 
89 	/// Be careful that if you load byte code using this function, you cannot use `this.functionID` or any function 
90 	/// that needs a function map to be present. You will only be able to call using function IDs
91 	/// 
92 	/// Returns: true if sucessfully loaded, false if not
93 	bool loadByteCode(string[] byteCode){
94 		try{
95 			_vm.load(byteCode);
96 		}catch (Exception e){
97 			.destroy(e);
98 			return false;
99 		}
100 		return true;
101 	}
102 	/// Returns: ID of a function, -1 if it does not exist
103 	integer functionID(string functionName){
104 		if (functionName in _functionID){
105 			return _functionID[functionName];
106 		}
107 		return -1;
108 	}
109 	/// executes a function
110 	/// 
111 	/// Returns: the return value, if function returned any, otherwise, garbage data
112 	NaData execute(uinteger functionID, NaData[] args){
113 		return _vm.execute(functionID, args);
114 	}
115 	/// ditto
116 	NaData execute(string functionName, NaData[] args){
117 		integer id = this.functionID(functionName);
118 		if (id < 0)
119 			throw new Exception("function '"~functionName~"' does not exist, or function map not present.");
120 		return _vm.execute(id, args);
121 	}
122 }