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