1 module as.engine;
2 import as.def;
3 import std..string;
4 import std.traits;
5 import as;
6 
7 class ScriptEngine {
8 private:
9     asIScriptEngine* engine;
10 
11     ~this() {
12         this.shutDownAndRelease();
13     }
14 
15     this(asIScriptEngine* engine) {
16         this.engine = engine;
17     }
18 
19 public:
20 
21     /**
22         Creates a new script engine
23     */
24     static ScriptEngine create(asDWORD version_ = ANGELSCRIPT_VERSION) {
25         return new ScriptEngine(asCreateScriptEngine(version_));
26     }
27 
28     /**
29         Adds reference
30     */
31     int addRef() {
32         return asEngine_AddRef(engine);
33     }
34 
35     /**
36         Releases reference
37     */
38     int release() {
39         return asEngine_Release(engine);
40     }
41 
42     /**
43         Shuts down the scripting engine and releases it
44     */
45     int shutDownAndRelease() {
46         return asEngine_ShutDownAndRelease(engine);
47     }
48 
49     /**
50         Sets an engine property
51     */
52     void setProperty(asEEngineProp property, asPWORD value) {
53         int err = asEngine_SetEngineProperty(engine, property, value);
54         assert(err != asERetCodes.asINVALID_ARG, "Invalid argument");
55     }
56 
57     /**
58         Gets an engine property
59     */
60     asPWORD getProperty(asEEngineProp property) {
61         return asEngine_GetEngineProperty(engine, property);
62     }
63 
64     /**
65         Sets the message callback
66     */
67     void setMessageCallback(MessageCallback callback) {
68         int err = asEngine_SetMessageCallback(engine, cast(asFUNCTION_t)callback, null, CDECL);
69         assert(err != asERetCodes.asINVALID_ARG, "Invalid argument");
70         assert(err != asERetCodes.asNOT_SUPPORTED, "Not supported");
71     }
72 
73     /**
74         Clears the message callback
75     */
76     void clearMessageCallback() {
77         asEngine_ClearMessageCallback(engine);
78     }
79 
80     /**
81         Writes a message
82     */
83     void writeMessage(string section, int row, int col, MessageType type, string message) {
84         asEngine_WriteMessage(engine, section.toStringz, row, col, cast(asEMsgType)type, message.toStringz);
85     }
86 
87     // TODO: Jit Compiler
88 
89     /**
90         Register a global function
91     */
92     void registerGlobalFunction(T)(string declaration, T func, void* aux = null) if (isFunctionPointer!T) {
93         int err = asEngine_RegisterGlobalFunction(engine, declaration.toStringz, cast(asFUNCTION_t)func, DCall, aux);
94         assert(err != asERetCodes.asNOT_SUPPORTED, "Not supported");
95         assert(err != asERetCodes.asWRONG_CALLING_CONV, "Wrong calling convetion");
96         assert(err != asERetCodes.asINVALID_DECLARATION, "Function declaration is invalid");
97         assert(err != asERetCodes.asNAME_TAKEN, "Function name is already taken");
98         assert(err != asERetCodes.asALREADY_REGISTERED, "Function is already registered");
99         assert(err != asERetCodes.asINVALID_ARG, "Invalid argument");
100     }
101 
102     /**
103         Gets the amount of global functions
104     */
105     asUINT getGlobalFunctionCount() {
106         return asEngine_GetGlobalFunctionCount(engine);
107     }
108     
109     /**
110         Gets a global function by its index
111     */
112     Function getGlobalFunctionByIndex(uint index) {
113         return new Function(this, asEngine_GetGlobalFunctionByIndex(engine, index));
114     }
115     
116     /**
117         Gets a global function by its declaration
118     */
119     Function getGlobalFunctionByDecl(string decl) {
120         return new Function(this, asEngine_GetGlobalFunctionByDecl(engine, decl.toStringz));
121     }
122 
123     /**
124         Registers a global property
125     */
126     void registerGlobalProperty(T)(string declaration, ref T pointer) {
127         int err = asEngine_RegisterGlobalProperty(engine, declaration.toStringz, cast(void*)&pointer);
128         assert(err != asERetCodes.asINVALID_DECLARATION, "Declaration is invalid");
129         assert(err != asERetCodes.asINVALID_TYPE, "Declaration type is invalid");
130         assert(err != asERetCodes.asINVALID_ARG, "Reference is null");
131         assert(err != asERetCodes.asNAME_TAKEN, "Name is already taken");
132     }
133 
134     /**
135         Gets the count of global properties
136     */
137     asUINT getGlobalPropertyCount() {
138         return asEngine_GetGlobalPropertyCount(engine);
139     }
140 
141     /**
142         Gets a global property by its index
143     */
144     void getGlobalPropertyByIndex(uint index, ref string name, ref string namespace, ref int typeId, ref bool isConst, ref string configGroup, void* ptr, ref asDWORD accessMask) {
145         const(char)* c_name;
146         const(char)* c_namespace;
147         int c_typeId;
148         bool c_isConst;
149         const(char)* c_configGroup;
150         void* c_ptr;
151         asDWORD c_accessMask;
152 
153         int err = asEngine_GetGlobalPropertyByIndex(engine, index, &c_name, &c_namespace, &c_typeId, &c_isConst, &c_configGroup, &c_ptr, &c_accessMask);
154         assert(err != asERetCodes.asINVALID_ARG, "Index is too large");
155         
156         // move all this data to the appropriate place
157         name = cast(string)c_name.fromStringz.idup;
158         namespace = cast(string)c_namespace.fromStringz.idup;
159         typeId = c_typeId;
160         isConst = c_isConst;
161         configGroup = cast(string)c_configGroup.fromStringz.idup;
162         ptr = c_ptr;
163         accessMask = c_accessMask;
164     }
165 
166     /**
167         Gets the index of a global property by its name
168     */
169     int getGlobalPropertyIndexByName(string name) {
170         int err = asEngine_GetGlobalPropertyIndexByName(engine, name.toStringz);
171         assert(err != asERetCodes.asNO_GLOBAL_VAR, "No matching property was found");
172         return err;
173     }
174 
175     /**
176         Gets the index of a global property by its declaration
177     */
178     int getGlobalPropertyIndexByDecl(string decl) {
179         int err = asEngine_GetGlobalPropertyIndexByDecl(engine, decl.toStringz);
180         assert(err != asERetCodes.asNO_GLOBAL_VAR, "No matching property was found");
181         assert(err != asERetCodes.asINVALID_DECLARATION, "Invalid declaration");
182         return err;
183     }
184 
185     /**
186         Registers an object type
187     */
188     void registerObjectType(string name, int byteSize, TypeFlags flags) {
189         int err = asEngine_RegisterObjectType(engine, name.toStringz, byteSize, flags);
190         assert(err != asERetCodes.asINVALID_ARG, "Invalid flags");
191         assert(err != asERetCodes.asINVALID_NAME, "Invalid name");
192         assert(err != asERetCodes.asALREADY_REGISTERED, "An object with the same name already exists");
193         assert(err != asERetCodes.asNAME_TAKEN, "Name is already taken by an other symbol");
194         assert(err != asERetCodes.asLOWER_ARRAY_DIMENSION_NOT_REGISTERED, "Registered array type element must be a primitive or registered type");
195         assert(err != asERetCodes.asINVALID_TYPE, "Array type was malformed");
196         assert(err != asERetCodes.asNOT_SUPPORTED, "Array type is not supported or already in use.");
197     }
198 
199     /**
200         Registers a property for an object
201     */
202     void registerObjectProperty(string obj, string decl, int byteOffset) {
203         int err = asEngine_RegisterObjectProperty(engine, obj.toStringz, decl.toStringz, byteOffset);
204         assert(err != asERetCodes.asWRONG_CONFIG_GROUP, "Object type was registered in a different config group");
205         assert(err != asERetCodes.asINVALID_OBJECT, "obj does not specify an object type");
206         assert(err != asERetCodes.asINVALID_TYPE, "obj parameter syntax invalid");
207         assert(err != asERetCodes.asNAME_TAKEN, "Name conflicts with other members");
208     }
209 
210     /**
211         Registers a method for an object
212     */
213     void registerObjectMethod(T)(string obj, string decl, T func, CallConv callConv = DCall, void* aux = null) if (isFunctionPointer!T) {
214         int err = asEngine_RegisterObjectMethod(engine, obj.toStringz, decl.toStringz, cast(asFUNCTION_t)func, callConv, aux);
215         assert(err != asERetCodes.asWRONG_CONFIG_GROUP, "Object type was registered in a different config group");
216         assert(err != asERetCodes.asNOT_SUPPORTED, "The calling convention is not supported");
217         assert(err != asERetCodes.asINVALID_TYPE, "obj parameter syntax invalid");
218         assert(err != asERetCodes.asINVALID_DECLARATION, "Invalid declaration");
219         assert(err != asERetCodes.asNAME_TAKEN, "Name conflicts with other members");
220         assert(err != asERetCodes.asWRONG_CALLING_CONV, "The function's calling convention is not compatible with callConv");
221         assert(err != asERetCodes.asALREADY_REGISTERED, "The method is already registered with the same parameter list");
222         assert(err != asERetCodes.asINVALID_ARG, "aux pointer was not set according to calling convention");
223     }
224 
225     /**
226         Registers a behaviour for an object
227     */
228     void registerObjectBehaviour(T)(string obj, Behaviours behaviour, string decl, T func, CallConv callConv = DCall, void* aux = null) if (isFunctionPointer!T) {
229         int err = asEngine_RegisterObjectBehaviour(engine, obj.toStringz, behaviour, decl.toStringz, cast(asFUNCTION_t)func, callConv, aux);
230         assert(err != asERetCodes.asWRONG_CONFIG_GROUP, "Object type was registered in a different config group");
231         assert(err != asERetCodes.asINVALID_ARG, "obj not set, global behaviour given in behaviour or the objForThiscall pointer wasn't set correctly");
232         assert(err != asERetCodes.asWRONG_CALLING_CONV, "The function's calling convention is not compatible with callConv");
233         assert(err != asERetCodes.asNOT_SUPPORTED, "The calling convention or behaviour signature is not supported");
234         assert(err != asERetCodes.asINVALID_TYPE, "Invalid obj parameter");
235         assert(err != asERetCodes.asINVALID_DECLARATION, "Invalid declaration");
236         assert(err != asERetCodes.asILLEGAL_BEHAVIOUR_FOR_TYPE, "Illegal behaviour for type");
237         assert(err != asERetCodes.asALREADY_REGISTERED, "The method is already registered with the same parameter list");
238     }
239 
240     /**
241         Registers a new interface
242     */
243     void registerInterface(string name) {
244         int err = asEngine_RegisterInterface(engine, name.toStringz);
245         assert(err != asERetCodes.asINVALID_NAME, "Name is null or reserved keyword");
246         assert(err != asERetCodes.asALREADY_REGISTERED, "Object type with this name already exists");
247         assert(err != asERetCodes.asERROR, "Name is not a proper identifier");
248         assert(err != asERetCodes.asNAME_TAKEN, "Name is already used elsewhere");
249     }
250 
251     /**
252         Registers an interface method
253     */
254     void registerInterfaceMethod(string intf, string decl) {
255         int err = asEngine_RegisterInterfaceMethod(engine, intf.toStringz, decl.toStringz);
256         assert(err != asERetCodes.asWRONG_CONFIG_GROUP, "Interface was registered in a different config group");
257         assert(err != asERetCodes.asINVALID_TYPE, "intf is not an interface");
258         assert(err != asERetCodes.asINVALID_DECLARATION, "Invalid declaration");
259         assert(err != asERetCodes.asNAME_TAKEN, "Name is already taken");
260     }
261 
262     /**
263         Gets the count of the objects in the engine
264     */
265     asUINT getObjectTypeCount() {
266         return asEngine_GetObjectTypeCount(engine);
267     }
268 
269     /**
270         Gets the type info of an object by its index
271     */
272     Type getObjectTypeByIndex(asUINT index) {
273         auto type = asEngine_GetObjectTypeByIndex(engine, index);
274         return type !is null ? new Type(this, type) : null;
275     }
276 
277     /**
278         Registers a string factory type with the specified creation functions
279     */
280     void registerStringFactory(string type, asGETSTRINGCONSTFUNC_t getStr, asRELEASESTRINGCONSTFUNC_t releaseStr, asGETRAWSTRINGDATAFUNC_t getRawStr) {
281         int err = asEngine_RegisterStringFactory(engine, type.toStringz, getStr, releaseStr, getRawStr);
282         assert(err != asERetCodes.asINVALID_ARG, "The factory is null");
283         assert(err != asERetCodes.asINVALID_TYPE, "Type is not valid or it is a reference/handle.");
284     }
285 
286     /**
287         Gets the return type id of the string type the factory returns
288     */
289     asUINT getStringFactoryReturnTypeId(asDWORD* flags = null) {
290         asUINT err = asEngine_GetStringFactoryReturnTypeId(engine, flags);
291         assert(err != asERetCodes.asNO_FUNCTION, "String factory has not been registered");
292         return err;
293     }
294 
295     /**
296         Registers the default array type
297     */
298     void registerDefaultArrayType(string type) {
299         int err = asEngine_RegisterDefaultArrayType(engine, type.toStringz);
300         assert(err != asERetCodes.asINVALID_TYPE, "Type is not a template type");
301     }
302 
303     /**
304         Gets the type id of the default array type
305     */
306     int getDefaultArrayTypeId() {
307         int err = asEngine_GetDefaultArrayTypeId(engine);
308         assert(err != asERetCodes.asINVALID_TYPE, "Array type has not been registered");
309         return err;
310     }
311 
312     /**
313         Registers a D enum in Angelscript
314     */
315     void registerEnum(T)() if (is(T == enum)) {
316         mixin("import ", moduleName!T, ";");
317         registerEnum(T.stringof);
318         static foreach(member; __traits(allMembers, T)) {
319             registerEnumValue(T.stringof, member, cast(int)mixin(T.stringof, ".", member));
320         }
321     }
322 
323     /**
324         Registers an enum
325     */
326     void registerEnum(string type) {
327         int err = asEngine_RegisterEnum(engine, type.toStringz);
328         assert(err != asERetCodes.asINVALID_NAME, "Invalid name");
329         assert(err != asERetCodes.asALREADY_REGISTERED, "Already registered");
330         assert(err != asERetCodes.asERROR, "Couldn't parse type");
331         assert(err != asERetCodes.asNAME_TAKEN, "Name already taken");
332     }
333 
334     /**
335         Registers a value for the enum
336     */
337     void registerEnumValue(string type, string name, int value) {
338         int err = asEngine_RegisterEnumValue(engine, type.toStringz, name.toStringz, value);
339         assert(err != asERetCodes.asWRONG_CONFIG_GROUP, "Wrong config group");
340         assert(err != asERetCodes.asINVALID_TYPE, "Invalid type");
341         assert(err != asERetCodes.asALREADY_REGISTERED, "Already registered");
342     }
343 
344     /**
345         Gets the amount of enums registered
346     */
347     asUINT getEnumCount() {
348         return asEngine_GetEnumCount(engine);
349     }
350 
351     /**
352         Gets the type of an enum by its index
353     */
354     Type getEnumByindex(asUINT index) {
355         auto type = asEngine_GetEnumByIndex(engine, index);
356         return type !is null ? new Type(this, type) : null;
357     }
358 
359     void registerFuncDef(string decl) {
360         int err = asEngine_RegisterFuncdef(engine, decl.toStringz);
361         assert(err != asERetCodes.asINVALID_ARG, "Declaration not given");
362         assert(err != asERetCodes.asINVALID_DECLARATION, "Invalid function definition");
363         assert(err != asERetCodes.asNAME_TAKEN, "Name conflicts with an other name");
364     }
365 
366     /**
367         Gets the amount of enums registered
368     */
369     asUINT getFuncdefConut() {
370         return asEngine_GetFuncdefCount(engine);
371     }
372 
373     /**
374         Gets the type of a fundef by its index
375     */
376     Type getFuncdefByIndex(asUINT index) {
377         auto type = asEngine_GetFuncdefByIndex(engine, index);
378         return type !is null ? new Type(this, type) : null;
379     }
380 
381     /**
382         Starts a new dynamic configuration group
383     */
384     void beginConfigGroup(string groupName) {
385         int err = asEngine_BeginConfigGroup(engine, groupName.toStringz);
386         assert(err != asERetCodes.asNAME_TAKEN, "Group name is already in use");
387         assert(err != asERetCodes.asNOT_SUPPORTED, "Nested configuration groups isn't supported");
388     }
389 
390     /**
391         Ends the configuration group
392     */
393     void endConfigGroup() {
394         int err = asEngine_EndConfigGroup(engine);
395         assert(err != asERetCodes.asERROR, "No configuration groups to end");
396     }
397 
398     /**
399         Removes a configuration group
400     */
401     void removeConfigGroup(string groupName) {
402         int err = asEngine_RemoveConfigGroup(engine, groupName.toStringz);
403         assert(err != asERetCodes.asCONFIG_GROUP_IS_IN_USE, "Group is in use and can't be removed");
404     }
405 
406     /**
407         Sets the access mask that should be used for subsequent registered entities
408     */
409     asDWORD setDefaultAccessMask(asDWORD defaultMask) {
410         return asEngine_SetDefaultAccessMask(engine, defaultMask);
411     }
412 
413     /**
414         Sets the default namespace
415     */
416     void setDefaultNamespace(string nameSpace) {
417         int err = asEngine_SetDefaultNamespace(engine, nameSpace.toStringz);
418         assert(err != asERetCodes.asINVALID_ARG, "Invalid namespace");
419     }
420 
421     /**
422         Gets the current default namespace
423     */
424     string getDefaultNamespace() {
425         return cast(string)asEngine_GetDefaultNamespace(engine).fromStringz;
426     }
427 
428     /**
429         Gets a module in the engine by name
430     */
431     Module getModule(string name, ModuleCreateFlags flags = ModuleCreateFlags.OnlyIfExists) {
432         auto mod = asEngine_GetModule(engine, name.toStringz, flags);
433         return mod !is null ? new Module(this, mod) : null;
434     }
435 
436     /**
437         Gets a module in the engine by index
438     */
439     Module getModule(asUINT index) {
440         auto mod = asEngine_GetModuleByIndex(engine, index);
441         return mod !is null ? new Module(this, mod) : null;
442     }
443 
444     /**
445         Discards a module by name
446         Note: Any class instances of the module in question will be rendered invalid.
447     */
448     void discardModule(string name) {
449         asEngine_DiscardModule(engine, name.toStringz);
450     }
451 
452     /**
453         Gets the count of modules
454     */
455     asUINT getModuleCount() {
456         return asEngine_GetModuleCount(engine);
457     }
458 
459     /**
460         Get a function by its ID in the engine
461     */
462     Function getFunctionById(int funcId) {
463         return new Function(this, asEngine_GetFunctionById(engine, funcId));
464     }
465 
466     /**
467         Creates a new script context
468     */
469     ScriptContext createContext() {
470         return new ScriptContext(this, asEngine_CreateContext(engine));
471     }
472 }