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 }