bool TestExecuteString() { bool fail = false; asIScriptEngine *engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); engine->RegisterObjectType("Obj", sizeof(Obj), asOBJ_VALUE | asOBJ_POD | asOBJ_APP_CLASS); engine->RegisterObjectProperty("Obj", "bool a", asOFFSET(Obj,a)); engine->RegisterObjectProperty("Obj", "bool b", asOFFSET(Obj,b)); engine->RegisterGlobalProperty("Obj g_Obj", &g_Obj); g_Obj.a = false; g_Obj.b = true; COutStream out; engine->SetMessageCallback(asMETHOD(COutStream,Callback), &out, asCALL_THISCALL); ExecuteString(engine, "g_Obj.a = true;\n" "g_Obj.b = false;\n"); engine->Release(); if( !g_Obj.a || g_Obj.b ) { printf("%s: ExecuteString() didn't execute correctly\n", TESTNAME); TEST_FAILED; } // Success return fail; }
void RegisterTimeAddon( asIScriptEngine *engine ) { int r; // register object behaviours r = engine->RegisterObjectBehaviour( "Time", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION( objectTime_DefaultConstructor ), asCALL_CDECL_OBJLAST ); assert( r >= 0 ); r = engine->RegisterObjectBehaviour( "Time", asBEHAVE_CONSTRUCT, "void f(uint64 t)", asFUNCTION( objectTime_ConstructorUInt64 ), asCALL_CDECL_OBJLAST ); assert( r >= 0 ); r = engine->RegisterObjectBehaviour( "Time", asBEHAVE_CONSTRUCT, "void f(const Time &in)", asFUNCTION( objectTime_CopyConstructor ), asCALL_CDECL_OBJLAST ); assert( r >= 0 ); // register object methods // assignments r = engine->RegisterObjectMethod( "Time", "Time &opAssign(const Time &in)", asFUNCTION( objectTime_AssignBehaviour ), asCALL_CDECL_OBJLAST ); assert( r >= 0 ); // == != r = engine->RegisterObjectMethod( "Time", "bool opEquals(const Time &in, const Time &in)", asFUNCTION( objectTime_EqualBehaviour ), asCALL_CDECL_OBJFIRST ); assert( r >= 0 ); // properties r = engine->RegisterObjectProperty( "Time", "const uint64 time", asOFFSET( astime_t, time ) ); assert( r >= 0 ); r = engine->RegisterObjectProperty( "Time", "const int sec", asOFFSET( astime_t, localtime.tm_sec ) ); assert( r >= 0 ); r = engine->RegisterObjectProperty( "Time", "const int min", asOFFSET( astime_t, localtime.tm_min ) ); assert( r >= 0 ); r = engine->RegisterObjectProperty( "Time", "const int hour", asOFFSET( astime_t, localtime.tm_hour ) ); assert( r >= 0 ); r = engine->RegisterObjectProperty( "Time", "const int mday", asOFFSET( astime_t, localtime.tm_mday ) ); assert( r >= 0 ); r = engine->RegisterObjectProperty( "Time", "const int mon", asOFFSET( astime_t, localtime.tm_mon ) ); assert( r >= 0 ); r = engine->RegisterObjectProperty( "Time", "const int year", asOFFSET( astime_t, localtime.tm_year ) ); assert( r >= 0 ); r = engine->RegisterObjectProperty( "Time", "const int wday", asOFFSET( astime_t, localtime.tm_wday ) ); assert( r >= 0 ); r = engine->RegisterObjectProperty( "Time", "const int yday", asOFFSET( astime_t, localtime.tm_yday ) ); assert( r >= 0 ); r = engine->RegisterObjectProperty( "Time", "const int isdst", asOFFSET( astime_t, localtime.tm_isdst ) ); assert( r >= 0 ); }
void RegisterPoint2F(asIScriptEngine* engine) { int r; r = engine->RegisterObjectType("Point2F", sizeof(Point2F), asOBJ_VALUE | asOBJ_POD); MEDUSA_ASSERT_SILENT(r >= 0); r = engine->RegisterObjectProperty("Point2F", "float X", asOFFSET(Point2F, X)); MEDUSA_ASSERT_SILENT(r >= 0); r = engine->RegisterObjectProperty("Point2F", "float Y", asOFFSET(Point2F, Y)); MEDUSA_ASSERT_SILENT(r >= 0); }
bool Test() { if( strstr(asGetLibraryOptions(), "AS_MAX_PORTABILITY") ) { printf("%s: This test has not been adapted for AS_MAX_PORTABILITY\n", TESTNAME); return false; } bool fail = false; int r; asIScriptEngine *engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); r = engine->RegisterObjectType("Point", sizeof(Point), asOBJ_REF); assert( r >= 0 ); r = engine->RegisterObjectProperty("Point", "int x", asOFFSET(Point, x)); assert( r >= 0 ); r = engine->RegisterObjectProperty("Point", "int y", asOFFSET(Point, y)); assert( r >= 0 ); r = engine->RegisterObjectMethod("Point", "void Add(Point&in)", asFUNCTION(Point_Add), asCALL_CDECL_OBJFIRST); assert( r >= 0 ); r = engine->RegisterObjectBehaviour("Point", asBEHAVE_FACTORY, "Point@ f()", asFUNCTION(Point_Factory), asCALL_CDECL); assert( r >= 0 ); r = engine->RegisterObjectMethod("Point", "Point &opAssign(Point &in)", asFUNCTION(Point_Assign), asCALL_CDECL_OBJFIRST); assert( r >= 0 ); r = engine->RegisterObjectMethod("Point", "int &opIndex(int)", asFUNCTION(Point_Index), asCALL_CDECL_OBJFIRST); assert( r >= 0 ); r = engine->RegisterObjectBehaviour("Point", asBEHAVE_ADDREF, "void f()", asFUNCTION(Point_AddRef), asCALL_CDECL_OBJFIRST); assert( r >= 0 ); r = engine->RegisterObjectBehaviour("Point", asBEHAVE_RELEASE, "void f()", asFUNCTION(Point_Release), asCALL_CDECL_OBJFIRST); assert( r >= 0 ); COutStream out; asIScriptModule *mod = engine->GetModule(0, asGM_ALWAYS_CREATE); mod->AddScriptSection(TESTNAME, script, strlen(script)); engine->SetMessageCallback(asMETHOD(COutStream,Callback), &out, asCALL_THISCALL); r = mod->Build(); if( r < 0 ) { printf("%s: Failed to build\n", TESTNAME); TEST_FAILED; } else { // Internal return asIScriptFunction *func = engine->GetModule(0)->GetFunctionByName("AddPoints"); asIScriptContext *ctx = engine->CreateContext(); ctx->Prepare(func); Point a, b, c; a.x = 1; a.y = 1; b.x = 2; b.y = 2; ctx->SetArgObject(0, &a); ctx->SetArgObject(1, &b); r = ctx->Execute(); if( r != asEXECUTION_FINISHED ) TEST_FAILED; Point *ret = (Point*)ctx->GetReturnObject(); c = *ret; ctx->Release(); } engine->Release(); return fail; }
void RegisterVec3Addon( asIScriptEngine *engine ) { int r; // register object behaviours r = engine->RegisterObjectBehaviour( "Vec3", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION( objectVec3_DefaultConstructor ), asCALL_CDECL_OBJLAST ); assert( r >= 0 ); r = engine->RegisterObjectBehaviour( "Vec3", asBEHAVE_CONSTRUCT, "void f(float x, float y, float z)", asFUNCTION( objectVec3_Constructor3F ), asCALL_CDECL_OBJLAST ); assert( r >= 0 ); r = engine->RegisterObjectBehaviour( "Vec3", asBEHAVE_CONSTRUCT, "void f(float v)", asFUNCTION( objectVec3_Constructor1F ), asCALL_CDECL_OBJLAST ); assert( r >= 0 ); r = engine->RegisterObjectBehaviour( "Vec3", asBEHAVE_CONSTRUCT, "void f(const Vec3 &in)", asFUNCTION( objectVec3_CopyConstructor ), asCALL_CDECL_OBJLAST ); assert( r >= 0 ); // register object methods // assignments r = engine->RegisterObjectMethod( "Vec3", "Vec3 &opAssign(Vec3 &in)", asFUNCTION( objectVec3_AssignBehaviour ), asCALL_CDECL_OBJLAST ); assert( r >= 0 ); r = engine->RegisterObjectMethod( "Vec3", "Vec3 &opAssign(int)", asFUNCTION( objectVec3_AssignBehaviourI ), asCALL_CDECL_OBJLAST ); assert( r >= 0 ); r = engine->RegisterObjectMethod( "Vec3", "Vec3 &opAssign(float)", asFUNCTION( objectVec3_AssignBehaviourD ), asCALL_CDECL_OBJLAST ); assert( r >= 0 ); r = engine->RegisterObjectMethod( "Vec3", "Vec3 &opAddAssign(Vec3 &in)", asFUNCTION( objectVec3_AddAssignBehaviour ), asCALL_CDECL_OBJLAST ); assert( r >= 0 ); r = engine->RegisterObjectMethod( "Vec3", "Vec3 &opSubAssign(Vec3 &in)", asFUNCTION( objectVec3_SubAssignBehaviour ), asCALL_CDECL_OBJLAST ); assert( r >= 0 ); r = engine->RegisterObjectMethod( "Vec3", "Vec3 &opMulAssign(Vec3 &in)", asFUNCTION( objectVec3_MulAssignBehaviour ), asCALL_CDECL_OBJLAST ); assert( r >= 0 ); r = engine->RegisterObjectMethod( "Vec3", "Vec3 &opXorAssign(Vec3 &in)", asFUNCTION( objectVec3_XORAssignBehaviour ), asCALL_CDECL_OBJLAST ); assert( r >= 0 ); r = engine->RegisterObjectMethod( "Vec3", "Vec3 &opMulAssign(int)", asFUNCTION( objectVec3_MulAssignBehaviourI ), asCALL_CDECL_OBJLAST ); assert( r >= 0 ); r = engine->RegisterObjectMethod( "Vec3", "Vec3 &opMulAssign(float)", asFUNCTION( objectVec3_MulAssignBehaviourD ), asCALL_CDECL_OBJLAST ); assert( r >= 0 ); r = engine->RegisterObjectMethod( "Vec3", "Vec3 opAdd(Vec3 &in) const", asFUNCTION( objectVec3_AddBehaviour ), asCALL_CDECL_OBJFIRST ); assert( r >= 0 ); r = engine->RegisterObjectMethod( "Vec3", "Vec3 opSub(Vec3 &in) const", asFUNCTION( objectVec3_SubtractBehaviour ), asCALL_CDECL_OBJFIRST ); assert( r >= 0 ); r = engine->RegisterObjectMethod( "Vec3", "float opMul(Vec3 &in) const", asFUNCTION( objectVec3_MultiplyBehaviour ), asCALL_CDECL_OBJFIRST ); assert( r >= 0 ); r = engine->RegisterObjectMethod( "Vec3", "Vec3 opMul(float) const", asFUNCTION( objectVec3_MultiplyBehaviourVD ), asCALL_CDECL_OBJFIRST ); assert( r >= 0 ); r = engine->RegisterObjectMethod( "Vec3", "Vec3 opMul_r(float) const", asFUNCTION( objectVec3_MultiplyBehaviourDV ), asCALL_CDECL_OBJLAST ); assert( r >= 0 ); r = engine->RegisterObjectMethod( "Vec3", "Vec3 opMul(int) const", asFUNCTION( objectVec3_MultiplyBehaviourVI ), asCALL_CDECL_OBJFIRST ); assert( r >= 0 ); r = engine->RegisterObjectMethod( "Vec3", "Vec3 opMul_r(int) const", asFUNCTION( objectVec3_MultiplyBehaviourIV ), asCALL_CDECL_OBJLAST ); assert( r >= 0 ); r = engine->RegisterObjectMethod( "Vec3", "Vec3 opXor(const Vec3 &in) const", asFUNCTION( objectVec3_XORBehaviour ), asCALL_CDECL_OBJFIRST ); assert( r >= 0 ); // == != r = engine->RegisterObjectMethod( "Vec3", "bool opEquals(const Vec3 &in) const", asFUNCTION( objectVec3_EqualBehaviour ), asCALL_CDECL_OBJFIRST ); assert( r >= 0 ); r = engine->RegisterObjectMethod( "Vec3", "void set(float x, float y, float z)", asFUNCTION( objectVec3_Set ), asCALL_CDECL_OBJLAST ); assert( r >= 0 ); r = engine->RegisterObjectMethod( "Vec3", "float length() const", asFUNCTION( objectVec3_Length ), asCALL_CDECL_OBJLAST ); assert( r >= 0 ); r = engine->RegisterObjectMethod( "Vec3", "float normalize() const", asFUNCTION( objectVec3_Normalize ), asCALL_CDECL_OBJLAST ); assert( r >= 0 ); r = engine->RegisterObjectMethod( "Vec3", "float distance(const Vec3 &in) const", asFUNCTION( objectVec3_Distance ), asCALL_CDECL_OBJLAST ); assert( r >= 0 ); r = engine->RegisterObjectMethod( "Vec3", "void angleVectors(Vec3 &out, Vec3 &out, Vec3 &out) const", asFUNCTION( objectVec3_AngleVectors ), asCALL_CDECL_OBJLAST ); assert( r >= 0 ); r = engine->RegisterObjectMethod( "Vec3", "Vec3 toAngles() const", asFUNCTION( objectVec3_VecToAngles ), asCALL_CDECL_OBJLAST ); assert( r >= 0 ); r = engine->RegisterObjectMethod( "Vec3", "Vec3 perpendicular() const", asFUNCTION( objectVec3_Perpendicular ), asCALL_CDECL_OBJLAST ); assert( r >= 0 ); r = engine->RegisterObjectMethod( "Vec3", "void makeNormalVectors(Vec3 &out, Vec3 &out) const", asFUNCTION( objectVec3_MakeNormalVectors ), asCALL_CDECL_OBJLAST ); assert( r >= 0 ); // properties r = engine->RegisterObjectProperty( "Vec3", "float x", asOFFSET( asvec3_t, v[0] ) ); assert( r >= 0 ); r = engine->RegisterObjectProperty( "Vec3", "float y", asOFFSET( asvec3_t, v[1] ) ); assert( r >= 0 ); r = engine->RegisterObjectProperty( "Vec3", "float z", asOFFSET( asvec3_t, v[2] ) ); assert( r >= 0 ); }
bool Test() { bool fail = false; int r; asIScriptEngine *engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); RegisterScriptArray(engine, true); RegisterScriptString_Generic(engine); engine->RegisterObjectType("Obj", sizeof(Obj), asOBJ_VALUE | asOBJ_POD | asOBJ_APP_CLASS); engine->RegisterObjectProperty("Obj", "int v", asOFFSET(Obj, v)); COutStream out; asIScriptModule *mod = engine->GetModule(0, asGM_ALWAYS_CREATE); mod->AddScriptSection(TESTNAME, script1, strlen(script1), 0); engine->SetMessageCallback(asMETHOD(COutStream,Callback), &out, asCALL_THISCALL); r = mod->Build(); if( r < 0 ) { TEST_FAILED; PRINTF("%s: Failed to compile the script\n", TESTNAME); } engine->Release(); // Success return fail; }
AEResult TimeAddOnAS::RegisterTimerParamsObject(asIScriptEngine* engine) { int ret = 0; //////////////////////// //Register TimerParams //////////////////////// ret = engine->RegisterObjectType("TimerParams", sizeof(TimerParams), asOBJ_VALUE | asOBJ_POD | asOBJ_APP_CLASS); if (ret < 0) { return AEResult::RegObjTypeFail; } ret = engine->RegisterObjectProperty("TimerParams", "double m_ElapsedTime", asOFFSET(TimerParams, m_ElapsedTime)); if (ret < 0) { return AEResult::RegObjPropFail; } ret = engine->RegisterObjectProperty("TimerParams", "double m_PreviousCallTime", asOFFSET(TimerParams, m_PreviousCallTime)); if (ret < 0) { return AEResult::RegObjPropFail; } ret = engine->RegisterObjectProperty("TimerParams", "double m_TotalElapsedTime", asOFFSET(TimerParams, m_TotalElapsedTime)); if (ret < 0) { return AEResult::RegObjPropFail; } ret = engine->RegisterObjectBehaviour("TimerParams", asBEHAVE_CONSTRUCT, "void AEAS_TimerParams_Constructor()", asFUNCTION(TimerParams_Constructor), asCALL_CDECL_OBJLAST); if (ret < 0) { return AEResult::RegObjBehaviorFail; } ret = engine->RegisterObjectBehaviour("TimerParams", asBEHAVE_DESTRUCT, "void AEAS_TimerParams_Destructor()", asFUNCTION(TimerParams_Destructor), asCALL_CDECL_OBJLAST); if (ret < 0) { return AEResult::RegObjBehaviorFail; } return AEResult::Ok; }
bool Test() { if( strstr(asGetLibraryOptions(), "AS_MAX_PORTABILITY") ) { printf("Skipped due to AS_MAX_PORTABILITY\n"); return false; } bool fail = false; int r; CBufferedOutStream bout; COutStream out; asIScriptModule *mod; asIScriptEngine *engine; engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); engine->SetMessageCallback(asMETHOD(CBufferedOutStream,Callback), &bout, asCALL_THISCALL); RegisterScriptArray(engine, true); RegisterScriptString(engine); engine->RegisterGlobalFunction("void assert(bool)", asFUNCTION(Assert), asCALL_GENERIC); mod = engine->GetModule(0, asGM_ALWAYS_CREATE); // The getter can return a handle while the setter takes a reference { const char *script = "class Test \n" "{ \n" " string @get_s() { return 'test'; } \n" " void set_s(const string &in) {} \n" "} \n" "void func() \n" "{ \n" " Test t; \n" " string s = t.s; \n" " t.s = s; \n" "} \n"; mod->AddScriptSection("script", script); bout.buffer = ""; r = mod->Build(); if( r < 0 ) { TEST_FAILED; printf("Failed to compile the script\n"); } r = ExecuteString(engine, "Test t; @t.s = 'test';", mod); if( r >= 0 ) { TEST_FAILED; printf("Shouldn't be allowed\n"); } if( bout.buffer != "ExecuteString (1, 14) : Error : It is not allowed to perform a handle assignment on a non-handle property\n" ) { printf("%s", bout.buffer.c_str()); TEST_FAILED; } } // main1 and main2 should produce the same bytecode const char *script1 = "class Test \n" "{ \n" " int get_prop() { return _prop; } \n" " void set_prop(int v) { _prop = v; } \n" " int _prop; \n" "} \n" "void main1() \n" "{ \n" " Test t; \n" " t.set_prop(42); \n" " assert( t.get_prop() == 42 ); \n" "} \n" "void main2() \n" "{ \n" " Test t; \n" " t.prop = 42; \n" " assert( t.prop == 42 ); \n" "} \n"; mod->AddScriptSection("script", script1); bout.buffer = ""; r = mod->Build(); if( r < 0 ) { TEST_FAILED; printf("Failed to compile the script\n"); } if( bout.buffer != "" ) { printf("%s", bout.buffer.c_str()); TEST_FAILED; } r = ExecuteString(engine, "main1()", mod); if( r != asEXECUTION_FINISHED ) { TEST_FAILED; } r = ExecuteString(engine, "main2()", mod); if( r != asEXECUTION_FINISHED ) { TEST_FAILED; } // Test compound assignment with accessors (not allowed) const char *script2 = "class Test \n" "{ \n" " void set_prop(int v) { _prop = v; } \n" " int _prop; \n" "} \n" "void main1() \n" "{ \n" " Test t; \n" " t.prop += 42; \n" "} \n"; mod->AddScriptSection("script", script2); bout.buffer = ""; r = mod->Build(); if( r >= 0 ) { TEST_FAILED; } if( bout.buffer != "script (6, 1) : Info : Compiling void main1()\n" "script (9, 10) : Error : Compound assignments with property accessors are not allowed\n" ) { printf("%s", bout.buffer.c_str()); TEST_FAILED; } // Test get accessor with boolean operators const char *script3 = "class Test \n" "{ \n" " bool get_boolProp() { return true; } \n" "} \n" "void main1() \n" "{ \n" " Test t; \n" " if( t.boolProp ) {} \n" " if( t.boolProp && true ) {} \n" " if( false || t.boolProp ) {} \n" " if( t.boolProp ^^ t.boolProp ) {} \n" " if( !t.boolProp ) {} \n" " t.boolProp ? t.boolProp : t.boolProp; \n" "} \n"; mod->AddScriptSection("script", script3); bout.buffer = ""; r = mod->Build(); if( r < 0 ) { TEST_FAILED; printf("Failed to compile the script\n"); } if( bout.buffer != "" ) { printf("%s", bout.buffer.c_str()); TEST_FAILED; } // Test get accessor with math operators const char *script4 = "class Test \n" "{ \n" " float get_prop() { return 1.0f; } \n" "} \n" "void main1() \n" "{ \n" " Test t; \n" " float f = t.prop * 1; \n" " f = (t.prop) + 1; \n" " 10 / t.prop; \n" " -t.prop; \n" "} \n"; mod->AddScriptSection("script", script4); bout.buffer = ""; r = mod->Build(); if( r < 0 ) { TEST_FAILED; printf("Failed to compile the script\n"); } if( bout.buffer != "" ) { printf("%s", bout.buffer.c_str()); TEST_FAILED; } // Test get accessor with bitwise operators const char *script5 = "class Test \n" "{ \n" " uint get_prop() { return 1; } \n" "} \n" "void main1() \n" "{ \n" " Test t; \n" " t.prop << t.prop; \n" " t.prop & t.prop; \n" " ~t.prop; \n" "} \n"; mod->AddScriptSection("script", script5); bout.buffer = ""; r = mod->Build(); if( r < 0 ) { TEST_FAILED; printf("Failed to compile the script\n"); } if( bout.buffer != "" ) { printf("%s", bout.buffer.c_str()); TEST_FAILED; } // Test multiple get accessors for same property. Should give error // Test multiple set accessors for same property. Should give error const char *script6 = "class Test \n" "{ \n" " uint get_p() {return 0;} \n" " float get_p() {return 0;} \n" " void set_s(float) {} \n" " void set_s(uint) {} \n" "} \n" "void main() \n" "{ \n" " Test t; \n" " t.p; \n" " t.s = 0; \n" "} \n"; mod->AddScriptSection("script", script6); bout.buffer = ""; r = mod->Build(); if( r >= 0 ) { TEST_FAILED; printf("Failed to compile the script\n"); } if( bout.buffer != "script (8, 1) : Info : Compiling void main()\n" "script (11, 4) : Error : Found multiple get accessors for property 'p'\n" "script (11, 4) : Info : uint Test::get_p()\n" "script (11, 4) : Info : float Test::get_p()\n" "script (12, 4) : Error : Found multiple set accessors for property 's'\n" "script (12, 4) : Info : void Test::set_s(float)\n" "script (12, 4) : Info : void Test::set_s(uint)\n" ) { printf("%s", bout.buffer.c_str()); TEST_FAILED; } // Test mismatching type between get accessor and set accessor. Should give error const char *script7 = "class Test \n" "{ \n" " uint get_p() {return 0;} \n" " void set_p(float) {} \n" "} \n" "void main() \n" "{ \n" " Test t; \n" " t.p; \n" "} \n"; mod->AddScriptSection("script", script7); bout.buffer = ""; r = mod->Build(); if( r >= 0 ) { TEST_FAILED; printf("Failed to compile the script\n"); } if( bout.buffer != "script (6, 1) : Info : Compiling void main()\n" "script (9, 4) : Error : The property 'p' has mismatching types for the get and set accessors\n" "script (9, 4) : Info : uint Test::get_p()\n" "script (9, 4) : Info : void Test::set_p(float)\n" ) { printf("%s", bout.buffer.c_str()); TEST_FAILED; } // Test only set accessor for read expression // Test only get accessor for write expression const char *script8 = "class Test \n" "{ \n" " uint get_g() {return 0;} \n" " void set_s(float) {} \n" "} \n" "void main() \n" "{ \n" " Test t; \n" " t.g = 0; \n" " t.s + 1; \n" "} \n"; mod->AddScriptSection("script", script8); bout.buffer = ""; r = mod->Build(); if( r >= 0 ) { TEST_FAILED; printf("Failed to compile the script\n"); } if( bout.buffer != "script (6, 1) : Info : Compiling void main()\n" "script (9, 7) : Error : The property has no set accessor\n" "script (10, 7) : Error : The property has no get accessor\n" ) { printf("%s", bout.buffer.c_str()); TEST_FAILED; } // Test pre and post ++. Should fail, since the expression is not a variable const char *script9 = "class Test \n" "{ \n" " uint get_p() {return 0;} \n" " void set_p(uint) {} \n" "} \n" "void main() \n" "{ \n" " Test t; \n" " t.p++; \n" " --t.p; \n" "} \n"; mod->AddScriptSection("script", script9); bout.buffer = ""; r = mod->Build(); if( r >= 0 ) { TEST_FAILED; printf("Didn't fail to compile the script\n"); } if( bout.buffer != "script (6, 1) : Info : Compiling void main()\n" "script (9, 6) : Error : Invalid reference. Property accessors cannot be used in combined read/write operations\n" "script (10, 3) : Error : Invalid reference. Property accessors cannot be used in combined read/write operations\n" ) { printf("%s", bout.buffer.c_str()); TEST_FAILED; } // Test using property accessors from within class methods without 'this' // Test accessor where the object is a handle const char *script10 = "class Test \n" "{ \n" " uint get_p() {return 0;} \n" " void set_p(uint) {} \n" " void test() \n" " { \n" " p = 0; \n" " int a = p; \n" " } \n" "} \n" "void func() \n" "{ \n" " Test @a = Test(); \n" " a.p = 1; \n" " int b = a.p; \n" "} \n"; mod->AddScriptSection("script", script10); bout.buffer = ""; r = mod->Build(); if( r < 0 ) { TEST_FAILED; printf("Failed to compile the script\n"); } if( bout.buffer != "" ) { printf("%s", bout.buffer.c_str()); TEST_FAILED; } r = ExecuteString(engine, "func()", mod); if( r != asEXECUTION_FINISHED ) { TEST_FAILED; } // Test accessors with function arguments (by value, in ref, out ref) const char *script11 = "class Test \n" "{ \n" " uint get_p() {return 0;} \n" " void set_p(uint) {} \n" "} \n" "void func() \n" "{ \n" " Test a(); \n" " byVal(a.p); \n" " inArg(a.p); \n" " outArg(a.p); \n" "} \n" "void byVal(int v) {} \n" "void inArg(int &in v) {} \n" "void outArg(int &out v) {} \n"; mod->AddScriptSection("script", script11); bout.buffer = ""; r = mod->Build(); if( r < 0 ) { TEST_FAILED; printf("Failed to compile the script\n"); } if( bout.buffer != "" ) { printf("%s", bout.buffer.c_str()); TEST_FAILED; } r = ExecuteString(engine, "func()", mod); if( r != asEXECUTION_FINISHED ) { TEST_FAILED; } // When the property is an object type, then the set accessor should be // used instead of the overloaded assignment operator to set the value. // Properties of object properties, must allow having different // types for get and set. IsEqualExceptConstAndRef should be used. engine->RegisterGlobalFunction("void Log(const string&inout)", asFUNCTION(Log), asCALL_CDECL); const char *script12 = "class Test \n" "{ \n" " string get_s() {return _s;} \n" " void set_s(const string &in n) {_s = n;} \n" " string _s; \n" "} \n" "void func() \n" "{ \n" " Test t; \n" " t.s = 'hello'; \n" " assert(t.s == 'hello'); \n" " Log(t.s); \n" // &inout parameter wasn't working " Log(t.get_s()); \n" "} \n"; mod->AddScriptSection("script", script12); bout.buffer = ""; r = mod->Build(); if( r < 0 ) { TEST_FAILED; printf("Failed to compile the script\n"); } if( bout.buffer != "" ) { printf("%s", bout.buffer.c_str()); TEST_FAILED; } r = ExecuteString(engine, "func()", mod); if( r != asEXECUTION_FINISHED ) { TEST_FAILED; } // Compound assignments for object properties will not be allowed r = ExecuteString(engine, "Test t; t.s += 'hello';", mod); if( r >= 0 ) { TEST_FAILED; } if( bout.buffer != "ExecuteString (1, 13) : Error : Compound assignments with property accessors are not allowed\n" ) { printf("%s", bout.buffer.c_str()); TEST_FAILED; } // Test @t.prop = @obj; Property is a handle, and the property is assigned a new handle. Should work const char *script13 = "class Test \n" "{ \n" " string@ get_s() {return _s;} \n" " void set_s(string @n) {@_s = @n;} \n" " string@ _s; \n" "} \n" "void func() \n" "{ \n" " Test t; \n" " string s = 'hello'; \n" " @t.s = @s; \n" // handle assignment " assert(t.s is s); \n" " t.s = 'other'; \n" // value assignment " assert(s == 'other'); \n" "} \n"; mod->AddScriptSection("script", script13); bout.buffer = ""; r = mod->Build(); if( r < 0 ) { TEST_FAILED; printf("Failed to compile the script\n"); } if( bout.buffer != "" ) { printf("%s", bout.buffer.c_str()); TEST_FAILED; } r = ExecuteString(engine, "func()", mod); if( r != asEXECUTION_FINISHED ) { TEST_FAILED; } // Test accessing members of an object property const char *script14 = "class Test \n" "{ \n" " string get_s() {return _s;} \n" " void set_s(string n) {_s = n;} \n" " string _s; \n" "} \n" "void func() \n" "{ \n" " Test t; \n" " t.s = 'hello'; \n" // value assignment " assert(t.s == 'hello'); \n" " assert(t.s.length() == 5); \n" // this should work as length is const "} \n"; mod->AddScriptSection("script", script14); bout.buffer = ""; r = mod->Build(); if( r < 0 ) { TEST_FAILED; printf("Failed to compile the script\n"); } if( bout.buffer != "" ) { printf("%s", bout.buffer.c_str()); TEST_FAILED; } r = ExecuteString(engine, "func()", mod); if( r != asEXECUTION_FINISHED ) { TEST_FAILED; } // Test accessing a non-const method on an object through a get accessor // Should at least warn since the object is just a temporary one /* // This warning isn't done anymore as there are times when it is valid to call a non-const method on temporary objects, for example if a stream like object is implemented bout.buffer = ""; r = ExecuteString(engine, "Test t; t.s.resize(4);", mod); if( r < 0 ) TEST_FAILED; if( (sizeof(void*) == 4 && bout.buffer != "ExecuteString (1, 13) : Warning : A non-const method is called on temporary object. Changes to the object may be lost.\n" "ExecuteString (1, 13) : Info : void string::resize(uint)\n") || (sizeof(void*) == 8 && bout.buffer != "ExecuteString (1, 13) : Warning : A non-const method is called on temporary object. Changes to the object may be lost.\n" "ExecuteString (1, 13) : Info : void string::resize(uint64)\n") ) { printf("%s", bout.buffer.c_str()); TEST_FAILED; } */ // Test opNeg for object through get accessor const char *script15 = "class Val { int opNeg() const { return -1; } } \n" "class Test \n" "{ \n" " Val get_s() const {return Val();} \n" "} \n" "void func() \n" "{ \n" " Test t; \n" " assert( -t.s == -1 ); \n" "} \n"; mod->AddScriptSection("script", script15); bout.buffer = ""; r = mod->Build(); if( r < 0 ) { TEST_FAILED; printf("Failed to compile the script\n"); } if( bout.buffer != "" ) { printf("%s", bout.buffer.c_str()); TEST_FAILED; } r = ExecuteString(engine, "func()", mod); if( r != asEXECUTION_FINISHED ) { TEST_FAILED; } // Test index operator for object through get accessor const char *script16 = "class Test \n" "{ \n" " int[] get_s() const { int[] a(1); a[0] = 42; return a; } \n" "} \n" "void func() \n" "{ \n" " Test t; \n" " assert( t.s[0] == 42 ); \n" "} \n"; mod->AddScriptSection("script", script16); bout.buffer = ""; r = mod->Build(); if( r < 0 ) { TEST_FAILED; printf("Failed to compile the script\n"); } if( bout.buffer != "" ) { printf("%s", bout.buffer.c_str()); TEST_FAILED; } r = ExecuteString(engine, "func()", mod); if( r != asEXECUTION_FINISHED ) { TEST_FAILED; } // Test accessing normal properties for object through get accessor const char *script17 = "class Val { int val; } \n" "class Test \n" "{ \n" " Val get_s() const { Val v; v.val = 42; return v;} \n" "} \n" "void func() \n" "{ \n" " Test t; \n" " assert( t.s.val == 42 ); \n" "} \n"; mod->AddScriptSection("script", script17); bout.buffer = ""; r = mod->Build(); if( r < 0 ) { TEST_FAILED; printf("Failed to compile the script\n"); } if( bout.buffer != "" ) { printf("%s", bout.buffer.c_str()); TEST_FAILED; } r = ExecuteString(engine, "func()", mod); if( r != asEXECUTION_FINISHED ) { TEST_FAILED; } // Test const/non-const get and set accessors const char *script18 = "class Test \n" "{ \n" " int get_p() { return 42; } \n" " int get_c() const { return 42; } \n" " void set_s(int) {} \n" "} \n" "void func() \n" "{ \n" " const Test @t = @Test(); \n" " assert( t.p == 42 ); \n" // Fail " assert( t.c == 42 ); \n" // Success " t.s = 42; \n" // Fail "} \n"; mod->AddScriptSection("script", script18); bout.buffer = ""; r = mod->Build(); if( r >= 0 ) TEST_FAILED; if( bout.buffer != "script (7, 1) : Info : Compiling void func()\n" "script (10, 15) : Error : Non-const method call on read-only object reference\n" "script (10, 15) : Info : int Test::get_p()\n" "script (12, 7) : Error : Non-const method call on read-only object reference\n" "script (12, 7) : Info : void Test::set_s(int)\n" ) { printf("%s", bout.buffer.c_str()); TEST_FAILED; } // Test accessor with property of the same name const char *script19 = "int direction; \n" "void set_direction(int val) { direction = val; } \n" "void test_set() \n" "{ \n" " direction = 9; \n" // calls the set_direction property accessor "} \n" "void test_get() \n" "{ \n" " assert( direction == 9 ); \n" // fails, since there is no get accessor "} \n"; mod->AddScriptSection("script", script19); bout.buffer = ""; r = mod->Build(); if( r >= 0 ) TEST_FAILED; if( bout.buffer != "script (7, 1) : Info : Compiling void test_get()\n" "script (9, 21) : Error : The property has no get accessor\n" ) { printf("%s", bout.buffer.c_str()); TEST_FAILED; } const char *script20 = "class Test { \n" " int direction; \n" " void set_direction(int val) { direction = val; } \n" "} \n"; mod->AddScriptSection("script", script20); bout.buffer = ""; r = mod->Build(); if( r < 0 ) TEST_FAILED; if( bout.buffer != "" ) { printf("%s", bout.buffer.c_str()); TEST_FAILED; } r = ExecuteString(engine, "Test t; t.set_direction(3);", mod); if( r != asEXECUTION_FINISHED ) TEST_FAILED; // Test accessing property of the same name on a member object const char *script21 = "class Test { \n" " int a; \n" " Test @member; \n" " int get_a() const { return a; } \n" " void set_a(int val) {a = val; if( member !is null ) member.a = val;} \n" "} \n"; mod->AddScriptSection("script", script21); bout.buffer = ""; r = mod->Build(); if( r < 0 ) TEST_FAILED; r = ExecuteString(engine, "Test t, s, u; @t.member = s; @s.member = u; t.set_a(3); assert( u.a == 3 );", mod); if( r != asEXECUTION_FINISHED ) TEST_FAILED; if( bout.buffer != "" ) { printf("%s", bout.buffer.c_str()); TEST_FAILED; } // TODO: Test non-const get accessor for object type with const overloaded dual operator // TODO: Test get accessor that returns a reference (only from application func to start with) // TODO: Test property accessor with inout references. Shouldn't be allowed as the value is not a valid reference // TODO: Test set accessor with parameter declared as out ref (shouldn't be found) // TODO: What should be done with expressions like t.prop; Should the get accessor be called even though // the value is never used? // TODO: Accessing a class member from within the property accessor with the same name as the property // shouldn't call the accessor again. Instead it should access the real member. FindPropertyAccessor() // shouldn't find any if the function being compiler is the property accessor itself engine->Release(); // Test property accessor on temporary object handle { engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); engine->SetMessageCallback(asMETHOD(COutStream, Callback), &out, asCALL_THISCALL); RegisterStdString(engine); const char *script = "class Obj { void set_opacity(float v) {} }\n" "Obj @GetObject() { return @Obj(); } \n"; asIScriptModule *mod = engine->GetModule(0, asGM_ALWAYS_CREATE); mod->AddScriptSection("script", script); r = mod->Build(); if( r < 0 ) TEST_FAILED; r = ExecuteString(engine, "GetObject().opacity = 1.0f;", mod); if( r != asEXECUTION_FINISHED ) TEST_FAILED; engine->Release(); } // Test bug reported by Scarabus2 // The bug was an incorrect reusage of temporary variable by the // property get accessor when compiling a binary operator { engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); engine->SetMessageCallback(asMETHOD(COutStream, Callback), &out, asCALL_THISCALL); engine->RegisterGlobalFunction("void assert(bool)", asFUNCTION(Assert), asCALL_GENERIC); const char *script = "class Object { \n" " Object() {rot = 0;} \n" " void set_rotation(float r) {rot = r;} \n" " float get_rotation() const {return rot;} \n" " float rot; } \n"; asIScriptModule *mod = engine->GetModule(0, asGM_ALWAYS_CREATE); mod->AddScriptSection("script", script); r = mod->Build(); if( r < 0 ) TEST_FAILED; r = ExecuteString(engine, "Object obj; \n" "float elapsed = 1.0f; \n" "float temp = obj.rotation + elapsed * 1.0f; \n" "obj.rotation = obj.rotation + elapsed * 1.0f; \n" "assert( obj.rot == 1 ); \n", mod); if( r != asEXECUTION_FINISHED ) TEST_FAILED; engine->Release(); } // Test global property accessor { engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); engine->SetMessageCallback(asMETHOD(COutStream, Callback), &out, asCALL_THISCALL); engine->RegisterGlobalFunction("void assert(bool)", asFUNCTION(Assert), asCALL_GENERIC); const char *script = "int _s = 0; \n" "int get_s() { return _s; } \n" "void set_s(int v) { _s = v; } \n"; asIScriptModule *mod = engine->GetModule(0, asGM_ALWAYS_CREATE); mod->AddScriptSection("script", script); r = mod->Build(); if( r < 0 ) TEST_FAILED; r = ExecuteString(engine, "s = 10; assert( s == 10 );", mod); if( r != asEXECUTION_FINISHED ) TEST_FAILED; engine->Release(); // The global property accessors are available to initialize global // variables, but can possibly throw an exception if used inappropriately. // This test also verifies that circular references between global // properties and functions is properly resolved by the GC. engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); engine->SetMessageCallback(asMETHOD(CBufferedOutStream, Callback), &bout, asCALL_THISCALL); RegisterStdString(engine); bout.buffer = ""; script = "string _s = s; \n" "string get_s() { return _s; } \n"; mod = engine->GetModule(0, asGM_ALWAYS_CREATE); mod->AddScriptSection("script", script); r = mod->Build(); if( r != asINIT_GLOBAL_VARS_FAILED ) TEST_FAILED; if( bout.buffer != "script (1, 13) : Error : Failed to initialize global variable '_s'\n" "script (2, 0) : Info : Exception 'Null pointer access' in 'string get_s()'\n" ) { printf("%s", bout.buffer.c_str()); TEST_FAILED; } engine->Release(); } // Test property accessor for object in array { engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); engine->SetMessageCallback(asMETHOD(COutStream, Callback), &out, asCALL_THISCALL); RegisterScriptArray(engine, true); engine->RegisterGlobalFunction("void assert(bool)", asFUNCTION(Assert), asCALL_GENERIC); const char *script = "class MyObj { bool get_Active() { return true; } } \n"; asIScriptModule *mod = engine->GetModule(0, asGM_ALWAYS_CREATE); mod->AddScriptSection("script", script); r = mod->Build(); if( r < 0 ) TEST_FAILED; r = ExecuteString(engine, "MyObj[] a(1); if( a[0].Active == true ) { } if( a[0].get_Active() == true ) { }", mod); if( r != asEXECUTION_FINISHED ) TEST_FAILED; engine->Release(); } // Test property accessor from within class method { engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); engine->SetMessageCallback(asMETHOD(COutStream, Callback), &out, asCALL_THISCALL); const char *script = "class Vector3 \n" "{ \n" " float x; \n" " float y; \n" " float z; \n" "}; \n" "class Hoge \n" "{ \n" " const Vector3 get_pos() { return mPos; } \n" " const Vector3 foo() { return pos; } \n" " const Vector3 zoo() { return get_pos(); } \n" " Vector3 mPos; \n" "}; \n" "void main() \n" "{ \n" " Hoge h; \n" " Vector3 vec; \n" " vec = h.zoo(); \n" // ok " vec = h.foo(); \n" // runtime exception "} \n"; asIScriptModule *mod = engine->GetModule(0, asGM_ALWAYS_CREATE); mod->AddScriptSection("script", script); r = mod->Build(); if( r < 0 ) TEST_FAILED; r = ExecuteString(engine, "main", mod); if( r != asEXECUTION_FINISHED ) TEST_FAILED; engine->Release(); } // Test property accessor in type conversion { engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); engine->SetMessageCallback(asMETHOD(COutStream, Callback), &out, asCALL_THISCALL); RegisterScriptArray(engine, true); const char *script = "class sound \n" "{ \n" " int get_pitch() { return 1; } \n" " void set_pitch(int p) {} \n" "} \n" "void main() \n" "{ \n" " sound[] sounds(1) ; \n" " sounds[0].pitch = int(sounds[0].pitch)/2; \n" "} \n"; asIScriptModule *mod = engine->GetModule(0, asGM_ALWAYS_CREATE); mod->AddScriptSection("script", script); r = mod->Build(); if( r < 0 ) TEST_FAILED; r = ExecuteString(engine, "main", mod); if( r != asEXECUTION_FINISHED ) TEST_FAILED; engine->Release(); } // Test property accessor in type conversion (2) { engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); engine->SetMessageCallback(asMETHOD(COutStream, Callback), &out, asCALL_THISCALL); const char *script = "class sound \n" "{ \n" " const int &get_id() const { return i; } \n" " int i; \n" "} \n" "void main() \n" "{ \n" " sound s; \n" " if( s.id == 1 ) \n" " return; \n" "} \n"; asIScriptModule *mod = engine->GetModule(0, asGM_ALWAYS_CREATE); mod->AddScriptSection("script", script); r = mod->Build(); if( r < 0 ) TEST_FAILED; r = ExecuteString(engine, "main", mod); if( r != asEXECUTION_FINISHED ) TEST_FAILED; engine->Release(); } // Test property accessors for opIndex { engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); engine->SetMessageCallback(asMETHOD(CBufferedOutStream, Callback), &bout, asCALL_THISCALL); RegisterScriptArray(engine, false); RegisterScriptString(engine); engine->RegisterGlobalFunction("void assert(bool)", asFUNCTION(Assert), asCALL_GENERIC); const char *script = "class CTest \n" "{ \n" " CTest() { arr.resize(5); } \n" " int get_opIndex(int i) const { return arr[i]; } \n" " void set_opIndex(int i, int v) { arr[i] = v; } \n" " array<int> arr; \n" "} \n" "class CTest2 \n" "{ \n" " CTest2() { arr.resize(1); } \n" " CTest @get_opIndex(int i) const { return arr[i]; } \n" " void set_opIndex(int i, CTest @v) { @arr[i] = v; } \n" " array<CTest@> arr; \n" "} \n" "void main() \n" "{ \n" " CTest s; \n" " s[0] = 42; \n" " assert( s[0] == 42 ); \n" " s[1] = 24; \n" " assert( s[1] == 24 ); \n" " CTest2 t; \n" " @t[0] = s; \n" " assert( t[0] is s ); \n" "} \n"; bout.buffer = ""; asIScriptModule *mod = engine->GetModule(0, asGM_ALWAYS_CREATE); mod->AddScriptSection("script", script); r = mod->Build(); if( r < 0 ) TEST_FAILED; r = ExecuteString(engine, "main", mod); if( r != asEXECUTION_FINISHED ) TEST_FAILED; // Test error script = "class CTest \n" "{ \n" " CTest() { } \n" " int get_opIndex(int i) const { return arr[i]; } \n" " void set_opIndex(int i, int v) { arr[i] = v; } \n" " array<int> arr; \n" "} \n" "class CTest2 \n" "{ \n" " CTest2() { } \n" " CTest get_opIndex(int i) const { return arr[i]; } \n" " void set_opIndex(int i, CTest v) { @arr[i] = v; } \n" " array<CTest@> arr; \n" "} \n" "void main() \n" "{ \n" " CTest s; \n" " s[0] += 42; \n" // compound assignment is not allowed " CTest2 t; \n" " @t[0] = s; \n" // handle assign is not allowed for non-handle property "} \n"; mod->AddScriptSection("script", script); r = mod->Build(); if( r > 0 ) TEST_FAILED; if( bout.buffer != "script (15, 1) : Info : Compiling void main()\n" "script (18, 8) : Error : Compound assignments with property accessors are not allowed\n" "script (20, 9) : Error : It is not allowed to perform a handle assignment on a non-handle property\n" ) { printf("%s", bout.buffer.c_str()); TEST_FAILED; } engine->Release(); } // Test global property accessors with index argument { engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); engine->SetMessageCallback(asMETHOD(COutStream, Callback), &out, asCALL_THISCALL); RegisterScriptArray(engine, false); RegisterScriptString(engine); engine->RegisterGlobalFunction("void assert(bool)", asFUNCTION(Assert), asCALL_GENERIC); const char *script = " int get_arr(int i) { arr.resize(5); return arr[i]; } \n" " void set_arr(int i, int v) { arr.resize(5); arr[i] = v; } \n" " array<int> arr; \n" "void main() \n" "{ \n" " arr[0] = 42; \n" " assert( arr[0] == 42 ); \n" " arr[1] = 24; \n" " assert( arr[1] == 24 ); \n" "} \n"; asIScriptModule *mod = engine->GetModule(0, asGM_ALWAYS_CREATE); mod->AddScriptSection("script", script); r = mod->Build(); if( r < 0 ) TEST_FAILED; r = ExecuteString(engine, "main()", mod); if( r != asEXECUTION_FINISHED ) TEST_FAILED; engine->Release(); } // Test member property accessors with index argument { engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); engine->SetMessageCallback(asMETHOD(COutStream, Callback), &out, asCALL_THISCALL); RegisterScriptArray(engine, false); RegisterScriptString(engine); engine->RegisterGlobalFunction("void assert(bool)", asFUNCTION(Assert), asCALL_GENERIC); const char *script = "class CTest \n" "{ \n" " CTest() { arr.resize(5); } \n" " int get_arr(int i) { return arr[i]; } \n" " void set_arr(int i, int v) { arr[i] = v; } \n" " private array<int> arr; \n" " void test() \n" " { \n" " arr[0] = 42; \n" " assert( arr[0] == 42 ); \n" " arr[1] = 24; \n" " assert( arr[1] == 24 ); \n" " } \n" "} \n" "void main() \n" "{ \n" " CTest s; \n" " s.arr[0] = 42; \n" " assert( s.arr[0] == 42 ); \n" " s.arr[1] = 24; \n" " assert( s.arr[1] == 24 ); \n" " s.test(); \n" "} \n"; asIScriptModule *mod = engine->GetModule(0, asGM_ALWAYS_CREATE); mod->AddScriptSection("script", script); r = mod->Build(); if( r < 0 ) TEST_FAILED; r = ExecuteString(engine, "main()", mod); if( r != asEXECUTION_FINISHED ) TEST_FAILED; engine->Release(); } // Test member property accessors with ++ where the set accessor takes a reference { engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); engine->SetMessageCallback(asMETHOD(CBufferedOutStream, Callback), &bout, asCALL_THISCALL); bout.buffer = ""; const char *script = "class CTest \n" "{ \n" " double _vol; \n" " double get_vol() const { return _vol; } \n" " void set_vol(double &in v) { _vol = v; } \n" "} \n" "CTest t; \n" "void main() \n" "{ \n" " for( t.vol = 0; t.vol < 10; t.vol++ ); \n" "} \n"; asIScriptModule *mod = engine->GetModule(0, asGM_ALWAYS_CREATE); mod->AddScriptSection("script", script); r = mod->Build(); if( r >= 0 ) TEST_FAILED; if( bout.buffer != "script (8, 1) : Info : Compiling void main()\n" "script (10, 36) : Error : Invalid reference. Property accessors cannot be used in combined read/write operations\n" ) { printf("%s", bout.buffer.c_str()); TEST_FAILED; } engine->Release(); } // Test get property returning reference { engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); engine->SetMessageCallback(asMETHOD(CBufferedOutStream, Callback), &bout, asCALL_THISCALL); engine->RegisterObjectType("LevelType", sizeof(CLevel), asOBJ_VALUE | asOBJ_POD); engine->RegisterObjectProperty("LevelType", "float attr", asOFFSET(CLevel, attr)); engine->RegisterGlobalFunction("LevelType &get_Level()", asFUNCTION(get_Level), asCALL_CDECL); r = ExecuteString(engine, "Level.attr = 0.5f;"); if( r != asEXECUTION_FINISHED ) TEST_FAILED; if( g_level.attr != 0.5f ) TEST_FAILED; engine->Release(); } // Make sure it is possible to update properties of objects returned by reference through getter { engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); engine->SetMessageCallback(asMETHOD(COutStream, Callback), &out, asCALL_THISCALL); RegisterScriptMath3D(engine); engine->RegisterObjectType("node", 0, asOBJ_REF); engine->RegisterObjectBehaviour("node", asBEHAVE_FACTORY, "node @f()", asFUNCTION(CNode::CNodeFactory), asCALL_CDECL); engine->RegisterObjectBehaviour("node", asBEHAVE_ADDREF, "void f()", asMETHOD(CNode, AddRef), asCALL_THISCALL); engine->RegisterObjectBehaviour("node", asBEHAVE_RELEASE, "void f()", asMETHOD(CNode, Release), asCALL_THISCALL); engine->RegisterObjectMethod("node", "node @+ get_child()", asMETHOD(CNode, GetChild), asCALL_THISCALL); engine->RegisterObjectMethod("node", "void set_child(node @+)", asMETHOD(CNode, SetChild), asCALL_THISCALL); engine->RegisterObjectProperty("node", "vector3 vector", asOFFSET(CNode, vector)); engine->RegisterObjectProperty("node", "float x", asOFFSET(CNode, vector)); r = ExecuteString(engine, "node @a = node(); \n" "@a.child = node(); \n" "a.child.x = 0; \n" "a.child.vector = vector3(0,0,0); \n"); if( r != asEXECUTION_FINISHED ) TEST_FAILED; engine->Release(); } // Make sure it is not possible to update properties of objects returned by value through getter { engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); bout.buffer = ""; engine->SetMessageCallback(asMETHOD(CBufferedOutStream, Callback), &bout, asCALL_THISCALL); RegisterScriptMath3D(engine); engine->RegisterObjectType("node", 0, asOBJ_REF); engine->RegisterObjectBehaviour("node", asBEHAVE_FACTORY, "node @f()", asFUNCTION(CNode::CNodeFactory), asCALL_CDECL); engine->RegisterObjectBehaviour("node", asBEHAVE_ADDREF, "void f()", asMETHOD(CNode, AddRef), asCALL_THISCALL); engine->RegisterObjectBehaviour("node", asBEHAVE_RELEASE, "void f()", asMETHOD(CNode, Release), asCALL_THISCALL); engine->RegisterObjectMethod("node", "vector3 get_vector() const", asMETHOD(CNode, GetVector), asCALL_THISCALL); engine->RegisterObjectMethod("node", "void set_vector(const vector3 &in)", asMETHOD(CNode, SetVector), asCALL_THISCALL); r = ExecuteString(engine, "node @a = node(); \n" "a.vector.x = 1; \n" // Not OK "a.vector = vector3(1,0,0); \n"); // OK if( r >= 0 ) TEST_FAILED; if( bout.buffer != "ExecuteString (2, 1) : Error : Expression is not an l-value\n" ) { printf("%s", bout.buffer.c_str()); TEST_FAILED; } engine->Release(); } fail = Test2() || fail; // Success return fail; }
bool Test() { if( strstr(asGetLibraryOptions(), "AS_MAX_PORTABILITY") ) { printf("%s: Skipped due to AS_MAX_PORTABILITY\n", TESTNAME); return false; } bool fail = Test2(); int r; int funcId; asIScriptEngine *engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); engine->RegisterGlobalFunction("void Assert(bool)", asFUNCTION(Assert), asCALL_GENERIC); engine->RegisterObjectType("Object", sizeof(CObject), asOBJ_VALUE | asOBJ_POD | asOBJ_APP_CLASS_CD); engine->RegisterObjectBehaviour("Object", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(Construct), asCALL_CDECL_OBJLAST); engine->RegisterObjectBehaviour("Object", asBEHAVE_DESTRUCT, "void f()", asFUNCTION(Destruct), asCALL_CDECL_OBJLAST); funcId = engine->RegisterObjectMethod("Object", "void Set(int)", asMETHOD(CObject, Set), asCALL_THISCALL); engine->RegisterObjectMethod("Object", "int Get()", asMETHOD(CObject, Get), asCALL_THISCALL); engine->RegisterObjectProperty("Object", "int val", asOFFSET(CObject, val)); r = engine->RegisterObjectMethod("Object", "int &GetRef()", asMETHOD(CObject, GetRef), asCALL_THISCALL); assert( r >= 0 ); engine->RegisterObjectType("Object2", sizeof(CObject2), asOBJ_VALUE | asOBJ_POD | asOBJ_APP_CLASS); engine->RegisterObjectBehaviour("Object2", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(Construct2), asCALL_CDECL_OBJLAST); engine->RegisterObjectBehaviour("Object2", asBEHAVE_DESTRUCT, "void f()", asFUNCTION(Destruct2), asCALL_CDECL_OBJLAST); engine->RegisterObjectProperty("Object2", "Object obj", asOFFSET(CObject2, obj)); engine->RegisterGlobalFunction("Object TestReturnObject()", asFUNCTION(TestReturnObject), asCALL_CDECL); engine->RegisterGlobalFunction("Object &TestReturnObjectRef()", asFUNCTION(TestReturnObjectRef), asCALL_CDECL); engine->RegisterGlobalFunction("void TestSysArgVal(Object)", asFUNCTION(TestSysArgVal), asCALL_CDECL); engine->RegisterGlobalFunction("void TestSysArgRef(Object &out)", asFUNCTION(TestSysArgRef), asCALL_CDECL); engine->RegisterGlobalProperty("Object obj", &obj); // Test objects with no default constructor engine->RegisterObjectType("ObjNoConstruct", sizeof(int), asOBJ_VALUE | asOBJ_POD | asOBJ_APP_PRIMITIVE); COutStream out; asIScriptModule *mod = engine->GetModule(0, asGM_ALWAYS_CREATE); mod->AddScriptSection(TESTNAME, script1, strlen(script1), 0); engine->SetMessageCallback(asMETHOD(COutStream,Callback), &out, asCALL_THISCALL); r = mod->Build(); if( r < 0 ) { TEST_FAILED; printf("%s: Failed to compile the script\n", TESTNAME); } asIScriptContext *ctx = engine->CreateContext(); r = ExecuteString(engine, "TestObject()", mod, ctx); if( r != asEXECUTION_FINISHED ) { if( r == asEXECUTION_EXCEPTION ) PrintException(ctx); printf("%s: Failed to execute script\n", TESTNAME); TEST_FAILED; } if( ctx ) ctx->Release(); ExecuteString(engine, "ObjNoConstruct a; a = ObjNoConstruct();"); if( r != 0 ) { TEST_FAILED; printf("%s: Failed\n", TESTNAME); } CBufferedOutStream bout; engine->SetMessageCallback(asMETHOD(CBufferedOutStream,Callback), &bout, asCALL_THISCALL); r = ExecuteString(engine, "Object obj; float r = 0; obj = r;"); if( r >= 0 || bout.buffer != "ExecuteString (1, 32) : Error : Can't implicitly convert from 'float' to 'const Object&'.\n" ) { printf("%s: Didn't fail to compile as expected\n", TESTNAME); printf("%s", bout.buffer.c_str()); TEST_FAILED; } // Verify that the registered types can be enumerated int count = engine->GetObjectTypeCount(); if( count != 3 ) TEST_FAILED; asIObjectType *type = engine->GetObjectTypeByIndex(0); if( strcmp(type->GetName(), "Object") != 0 ) TEST_FAILED; // Test calling an application registered method directly with context ctx = engine->CreateContext(); ctx->Prepare(funcId); ctx->SetObject(&obj); ctx->SetArgDWord(0, 42); r = ctx->Execute(); if( r != asEXECUTION_FINISHED ) TEST_FAILED; if( obj.val != 42 ) TEST_FAILED; ctx->Release(); // Test GetObjectTypeCount for the module const char *script2 = "class ScriptType {}"; engine->SetMessageCallback(asMETHOD(COutStream,Callback), &out, asCALL_THISCALL); mod = engine->GetModule(0, asGM_ALWAYS_CREATE); mod->AddScriptSection("script", script2); mod->Build(); count = engine->GetObjectTypeCount(); if( count != 3 ) TEST_FAILED; count = engine->GetModule(0)->GetObjectTypeCount(); if( count != 1 ) TEST_FAILED; // Test assigning value to reference returned by class method where the reference points to a member of the class // This test attempts to verify that the object isn't freed before the reference goes out of scope. r = ExecuteString(engine, "Object o; o.GetRef() = 10;"); if( r != asEXECUTION_FINISHED ) { TEST_FAILED; } engine->SetMessageCallback(asMETHOD(CBufferedOutStream, Callback), &bout, asCALL_THISCALL); bout.buffer = ""; r = ExecuteString(engine, "Object().GetRef() = 10;"); if( r != asEXECUTION_FINISHED ) { TEST_FAILED; } if( bout.buffer != "" ) { printf("%s", bout.buffer.c_str()); TEST_FAILED; } // TODO: Make the same test with the index operator engine->Release(); // Success return fail; }
bool Test() { bool fail = Test2(); int r; COutStream out; CBufferedOutStream bout; // Test that removing a group doesn't remove other functions // http://www.gamedev.net/topic/657987-bug-new-functions-not-accessibly-by-getglobalfunctionbyindex-after-removing-different-configuration-group/ { asIScriptEngine *engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); engine->SetMessageCallback(asMETHOD(COutStream, Callback), &out, asCALL_THISCALL); // register 3 script functions a(), b() and c() r = engine->RegisterGlobalFunction("void a()", asFUNCTION(0), asCALL_GENERIC); assert(r>=0); r = engine->RegisterGlobalFunction("void b()", asFUNCTION(0), asCALL_GENERIC); assert(r>=0); r = engine->RegisterGlobalFunction("void c()", asFUNCTION(0), asCALL_GENERIC); assert(r>=0); asIScriptFunction *func = engine->GetGlobalFunctionByIndex(0); if( func == 0 || string(func->GetName()) != "a" ) TEST_FAILED; func = engine->GetGlobalFunctionByIndex(1); if( func == 0 || string(func->GetName()) != "b" ) TEST_FAILED; func = engine->GetGlobalFunctionByIndex(2); if( func == 0 || string(func->GetName()) != "c" ) TEST_FAILED; // Add a dynamic group, then remove it r = engine->BeginConfigGroup("myconfig"); assert(r>=0); r = engine->RegisterGlobalFunction("void x()", asFUNCTION(0), asCALL_GENERIC); assert(r>=0); r = engine->RegisterGlobalFunction("void y()", asFUNCTION(0), asCALL_GENERIC); assert(r>=0); r = engine->EndConfigGroup(); assert(r>=0); r = engine->RemoveConfigGroup("myconfig"); assert(r>=0); // original functions should still be available func = engine->GetGlobalFunctionByIndex(0); if( func == 0 || string(func->GetName()) != "a" ) TEST_FAILED; func = engine->GetGlobalFunctionByIndex(1); if( func == 0 || string(func->GetName()) != "b" ) TEST_FAILED; func = engine->GetGlobalFunctionByIndex(2); if( func == 0 || string(func->GetName()) != "c" ) TEST_FAILED; // add some more functions in the default group r = engine->RegisterGlobalFunction("void d()", asFUNCTION(0), asCALL_GENERIC); assert(r>=0); r = engine->RegisterGlobalFunction("void e()", asFUNCTION(0), asCALL_GENERIC); assert(r>=0); r = engine->RegisterGlobalFunction("void f()", asFUNCTION(0), asCALL_GENERIC); assert(r>=0); // original functions should still be available func = engine->GetGlobalFunctionByIndex(0); if( func == 0 || string(func->GetName()) != "a" ) TEST_FAILED; func = engine->GetGlobalFunctionByIndex(1); if( func == 0 || string(func->GetName()) != "b" ) TEST_FAILED; func = engine->GetGlobalFunctionByIndex(2); if( func == 0 || string(func->GetName()) != "c" ) TEST_FAILED; // new functions must also be available func = engine->GetGlobalFunctionByIndex(3); if( func == 0 || string(func->GetName()) != "d" ) TEST_FAILED; func = engine->GetGlobalFunctionByIndex(4); if( func == 0 || string(func->GetName()) != "e" ) TEST_FAILED; func = engine->GetGlobalFunctionByIndex(5); if( func == 0 || string(func->GetName()) != "f" ) TEST_FAILED; engine->Release(); } // Test dynamic config groups with function definitions used for callbacks // http://www.gamedev.net/topic/618909-assertion-failure-in-as-configgroupcpp/ { asIScriptEngine *engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); engine->SetMessageCallback(asMETHOD(CBufferedOutStream, Callback), &bout, asCALL_THISCALL); engine->BeginConfigGroup("gr"); engine->RegisterObjectType("type", 0, asOBJ_REF); #ifndef AS_MAX_PORTABILITY engine->RegisterObjectBehaviour("type", asBEHAVE_ADDREF, "void f()", asMETHOD(Type,AddRef), asCALL_THISCALL); engine->RegisterObjectBehaviour("type", asBEHAVE_RELEASE, "void f()", asMETHOD(Type,Release), asCALL_THISCALL); #else engine->RegisterObjectBehaviour("type", asBEHAVE_ADDREF, "void f()", WRAP_MFN(Type,AddRef), asCALL_GENERIC); engine->RegisterObjectBehaviour("type", asBEHAVE_RELEASE, "void f()", WRAP_MFN(Type,Release), asCALL_GENERIC); #endif engine->RegisterFuncdef("void fun(type @)"); engine->RegisterObjectProperty("type", "fun @callback", asOFFSET(Type,callback)); engine->EndConfigGroup(); asIScriptModule *mod = engine->GetModule("mod", asGM_ALWAYS_CREATE); mod->AddScriptSection("s", "void func(type @) {} \n" "void main(type @t) \n" "{ \n" " @t.callback = func; \n" "} \n"); r = mod->Build(); if( r < 0 ) TEST_FAILED; Type *t = new Type(); // Call the function that sets the callback on the object asIScriptFunction *m = mod->GetFunctionByName("main"); asIScriptContext *ctx = engine->CreateContext(); ctx->Prepare(m); ctx->SetArgObject(0, t); r = ctx->Execute(); if( r != asEXECUTION_FINISHED ) TEST_FAILED; ctx->Release(); // Release the engine, while the object holding the callback is still alive engine->Release(); t->Release(); // The engine will warn about the callback not being released before the engine if( bout.buffer != " (0, 0) : Warning : There is an external reference to an object in module 'mod', preventing it from being deleted\n" " (0, 0) : Info : The function in previous message is named 'func'. The func type is 1\n" ) { PRINTF("%s", bout.buffer.c_str()); TEST_FAILED; } } //------------ // Test global function asIScriptEngine *engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); r = engine->BeginConfigGroup("group1"); assert( r >= 0 ); r = engine->RegisterGlobalFunction("void MyFunc()", asFUNCTION(MyFunc), asCALL_GENERIC); assert( r >= 0 ); r = engine->EndConfigGroup(); assert( r >= 0 ); engine->SetMessageCallback(asMETHOD(COutStream,Callback), &out, asCALL_THISCALL); asIScriptModule *mod = engine->GetModule(0, asGM_ALWAYS_CREATE); mod->AddScriptSection(TESTNAME, script1, strlen(script1), 0); r = mod->Build(); if( r < 0 ) { TEST_FAILED; } r = engine->RemoveConfigGroup("group1"); assert( r == asCONFIG_GROUP_IS_IN_USE ); engine->DiscardModule(0); engine->GarbageCollect(); r = engine->RemoveConfigGroup("group1"); assert( r >= 0 ); bout.buffer = ""; engine->SetMessageCallback(asMETHOD(CBufferedOutStream,Callback), &bout, asCALL_THISCALL); mod = engine->GetModule(0, asGM_ALWAYS_CREATE); mod->AddScriptSection(TESTNAME, script1, strlen(script1), 0); r = mod->Build(); if( r >= 0 || bout.buffer != "TestDynamicConfig (1, 1) : Info : Compiling void Test()\n" "TestDynamicConfig (3, 3) : Error : No matching symbol 'MyFunc'\n" ) { PRINTF("%s", bout.buffer.c_str()); TEST_FAILED; } engine->Release(); //---------------- // Test global property engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); r = engine->BeginConfigGroup("group1"); assert( r >= 0 ); r = engine->RegisterGlobalProperty("int global", (void*)1); assert( r >= 0 ); r = engine->EndConfigGroup(); assert( r >= 0 ); mod = engine->GetModule(0, asGM_ALWAYS_CREATE); mod->AddScriptSection(TESTNAME, script2, strlen(script2), 0); engine->SetMessageCallback(asMETHOD(COutStream,Callback), &out, asCALL_THISCALL); r = mod->Build(); if( r < 0 ) { TEST_FAILED; } r = engine->RemoveConfigGroup("group1"); assert( r == asCONFIG_GROUP_IS_IN_USE ); engine->DiscardModule(0); engine->GarbageCollect(); r = engine->RemoveConfigGroup("group1"); assert( r >= 0 ); bout.buffer = ""; mod = engine->GetModule(0, asGM_ALWAYS_CREATE); mod->AddScriptSection(TESTNAME, script2, strlen(script2), 0); engine->SetMessageCallback(asMETHOD(CBufferedOutStream,Callback), &bout, asCALL_THISCALL); r = mod->Build(); if( r >= 0 || bout.buffer != "TestDynamicConfig (1, 1) : Info : Compiling void Test()\n" "TestDynamicConfig (3, 3) : Error : No matching symbol 'global'\n" ) { PRINTF("%s", bout.buffer.c_str()); TEST_FAILED; } // Try registering the property again r = engine->BeginConfigGroup("group1"); assert( r >= 0 ); r = engine->RegisterGlobalProperty("int global", (void*)1); assert( r >= 0 ); r = engine->EndConfigGroup(); assert( r >= 0 ); engine->Release(); //------------- // Test object types engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); r = engine->BeginConfigGroup("group1"); assert( r >= 0 ); r = engine->RegisterObjectType("mytype", sizeof(int), asOBJ_VALUE | asOBJ_POD | asOBJ_APP_PRIMITIVE); r = engine->EndConfigGroup(); assert( r >= 0 ); mod = engine->GetModule(0, asGM_ALWAYS_CREATE); mod->AddScriptSection(TESTNAME, script3, strlen(script3), 0); engine->SetMessageCallback(asMETHOD(COutStream,Callback), &out, asCALL_THISCALL); r = mod->Build(); if( r < 0 ) { TEST_FAILED; } r = engine->RemoveConfigGroup("group1"); assert( r == asCONFIG_GROUP_IS_IN_USE ); engine->DiscardModule(0); engine->GarbageCollect(); r = engine->RemoveConfigGroup("group1"); assert( r >= 0 ); bout.buffer = ""; mod = engine->GetModule(0, asGM_ALWAYS_CREATE); mod->AddScriptSection(TESTNAME, script3, strlen(script3), 0); engine->SetMessageCallback(asMETHOD(CBufferedOutStream,Callback), &bout, asCALL_THISCALL); r = mod->Build(); if( r >= 0 || bout.buffer != "TestDynamicConfig (1, 1) : Info : Compiling void Test()\n" "TestDynamicConfig (3, 3) : Error : Identifier 'mytype' is not a data type\n" ) { PRINTF("%s", bout.buffer.c_str()); TEST_FAILED; } engine->Release(); //------------------ // Test global behaviours engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); RegisterScriptString_Generic(engine); r = engine->BeginConfigGroup("group1"); assert( r >= 0 ); r = engine->RegisterObjectType("mytype", sizeof(int), asOBJ_VALUE | asOBJ_POD | asOBJ_APP_PRIMITIVE); r = engine->RegisterObjectMethod("mytype", "string@ opAdd_r(const string &in)", asFUNCTION(MyFunc), asCALL_GENERIC); assert( r >= 0 ); r = engine->EndConfigGroup(); assert( r >= 0 ); mod = engine->GetModule(0, asGM_ALWAYS_CREATE); mod->AddScriptSection(TESTNAME, script4, strlen(script4), 0); engine->SetMessageCallback(asMETHOD(COutStream,Callback), &out, asCALL_THISCALL); r = mod->Build(); if( r < 0 ) { TEST_FAILED; } r = engine->RemoveConfigGroup("group1"); assert( r == asCONFIG_GROUP_IS_IN_USE ); engine->DiscardModule(0); engine->GarbageCollect(); r = engine->RemoveConfigGroup("group1"); assert( r >= 0 ); // Register the type again, but without the operator overload r = engine->BeginConfigGroup("group1"); assert( r >= 0 ); r = engine->RegisterObjectType("mytype", sizeof(int), asOBJ_VALUE | asOBJ_POD | asOBJ_APP_PRIMITIVE); r = engine->EndConfigGroup(); assert( r >= 0 ); bout.buffer = ""; mod = engine->GetModule(0, asGM_ALWAYS_CREATE); mod->AddScriptSection(TESTNAME, script4, strlen(script4), 0); engine->SetMessageCallback(asMETHOD(CBufferedOutStream,Callback), &bout, asCALL_THISCALL); r = mod->Build(); if( r >= 0 || bout.buffer != "TestDynamicConfig (1, 1) : Info : Compiling void Test()\n" "TestDynamicConfig (5, 9) : Error : No matching operator that takes the types 'string&' and 'mytype' found\n" ) { PRINTF("%s", bout.buffer.c_str()); TEST_FAILED; } engine->Release(); //------------------ // Test object types held by external variable, i.e. any CScriptAny *any = 0; engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); RegisterScriptAny(engine); engine->BeginConfigGroup("group1"); r = engine->RegisterObjectType("mytype", sizeof(int), asOBJ_REF); r = engine->RegisterObjectBehaviour("mytype", asBEHAVE_FACTORY, "mytype @f()", asFUNCTION(Factory), asCALL_GENERIC); r = engine->RegisterObjectBehaviour("mytype", asBEHAVE_ADDREF, "void f()", asFUNCTION(AddRef), asCALL_GENERIC); r = engine->RegisterObjectBehaviour("mytype", asBEHAVE_RELEASE, "void f()", asFUNCTION(Release), asCALL_GENERIC); any = (CScriptAny*)engine->CreateScriptObject(engine->GetTypeInfoByName("any")); r = engine->RegisterGlobalProperty("any g_any", any); engine->EndConfigGroup(); mod = engine->GetModule(0, asGM_ALWAYS_CREATE); mod->AddScriptSection(0, script5); engine->SetMessageCallback(asMETHOD(COutStream,Callback), &out, asCALL_THISCALL); r = mod->Build(); if( r < 0 ) TEST_FAILED; r = ExecuteString(engine, "Test()", mod); if( r != asEXECUTION_FINISHED ) { TEST_FAILED; } engine->DiscardModule(0); engine->GarbageCollect(); int *o = 0; any->Retrieve(&o, engine->GetTypeIdByDecl("mytype@")); if( o == 0 ) TEST_FAILED; if( --(*o) != 1 ) TEST_FAILED; // The mytype variable is still stored in the any variable so we shouldn't be allowed to remove it's configuration group r = engine->RemoveConfigGroup("group1"); assert( r < 0 ); any->Release(); engine->GarbageCollect(); // Now it should be possible to remove the group r = engine->RemoveConfigGroup("group1"); assert( r >= 0 ); engine->Release(); //------------- // Test array types engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); RegisterScriptArray(engine, true); r = engine->BeginConfigGroup("group1"); assert( r >= 0 ); r = engine->RegisterObjectType("int[]", sizeof(int), asOBJ_VALUE | asOBJ_POD | asOBJ_APP_PRIMITIVE); r = engine->EndConfigGroup(); assert( r >= 0 ); asITypeInfo *ot = engine->GetTypeInfoByDecl("int[]"); if( ot->GetSubTypeId() != asTYPEID_INT32 ) TEST_FAILED; mod = engine->GetModule(0, asGM_ALWAYS_CREATE); mod->AddScriptSection(TESTNAME, script6, strlen(script6), 0); engine->SetMessageCallback(asMETHOD(COutStream,Callback), &out, asCALL_THISCALL); r = mod->Build(); if( r < 0 ) { TEST_FAILED; } r = engine->RemoveConfigGroup("group1"); assert( r == asCONFIG_GROUP_IS_IN_USE ); engine->DiscardModule(0); engine->GarbageCollect(); r = engine->RemoveConfigGroup("group1"); assert( r >= 0 ); engine->Release(); //------------- // Test object types in struct members engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); r = engine->BeginConfigGroup("group1"); assert( r >= 0 ); r = engine->RegisterObjectType("mytype", sizeof(int), asOBJ_VALUE | asOBJ_POD | asOBJ_APP_PRIMITIVE); r = engine->EndConfigGroup(); assert( r >= 0 ); mod = engine->GetModule(0, asGM_ALWAYS_CREATE); mod->AddScriptSection(TESTNAME, script7, strlen(script7), 0); engine->SetMessageCallback(asMETHOD(COutStream,Callback), &out, asCALL_THISCALL); r = mod->Build(); if( r < 0 ) { TEST_FAILED; } r = engine->RemoveConfigGroup("group1"); assert( r == asCONFIG_GROUP_IS_IN_USE ); engine->DiscardModule(0); engine->GarbageCollect(); r = engine->RemoveConfigGroup("group1"); assert( r >= 0 ); bout.buffer = ""; mod = engine->GetModule(0, asGM_ALWAYS_CREATE); mod->AddScriptSection(TESTNAME, script7, strlen(script7), 0); engine->SetMessageCallback(asMETHOD(CBufferedOutStream,Callback), &bout, asCALL_THISCALL); r = mod->Build(); if( r >= 0 || bout.buffer != "TestDynamicConfig (3, 3) : Error : Identifier 'mytype' is not a data type in global namespace\n" ) { PRINTF("%s", bout.buffer.c_str()); TEST_FAILED; } engine->Release(); //------------- // Test object types in function declarations engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); r = engine->BeginConfigGroup("group1"); assert( r >= 0 ); r = engine->RegisterObjectType("mytype", sizeof(int), asOBJ_VALUE | asOBJ_POD | asOBJ_APP_PRIMITIVE); r = engine->EndConfigGroup(); assert( r >= 0 ); mod = engine->GetModule(0, asGM_ALWAYS_CREATE); mod->AddScriptSection(TESTNAME, script8, strlen(script8), 0); engine->SetMessageCallback(asMETHOD(COutStream,Callback), &out, asCALL_THISCALL); r = mod->Build(); if( r < 0 ) { TEST_FAILED; } r = engine->RemoveConfigGroup("group1"); assert( r == asCONFIG_GROUP_IS_IN_USE ); engine->DiscardModule(0); engine->GarbageCollect(); r = engine->RemoveConfigGroup("group1"); assert( r >= 0 ); bout.buffer = ""; mod = engine->GetModule(0, asGM_ALWAYS_CREATE); mod->AddScriptSection(TESTNAME, script8, strlen(script8), 0); engine->SetMessageCallback(asMETHOD(CBufferedOutStream,Callback), &bout, asCALL_THISCALL); r = mod->Build(); if( r >= 0 || bout.buffer != "TestDynamicConfig (1, 11) : Error : Identifier 'mytype' is not a data type in global namespace\n" ) { PRINTF("%s", bout.buffer.c_str()); TEST_FAILED; } engine->Release(); //------------- // Test object types in script arrays engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); RegisterScriptArray(engine, true); r = engine->BeginConfigGroup("group1"); assert( r >= 0 ); r = engine->RegisterObjectType("mytype", sizeof(int), asOBJ_VALUE | asOBJ_POD | asOBJ_APP_PRIMITIVE); r = engine->EndConfigGroup(); assert( r >= 0 ); mod = engine->GetModule(0, asGM_ALWAYS_CREATE); mod->AddScriptSection(TESTNAME, script9, strlen(script9), 0); engine->SetMessageCallback(asMETHOD(COutStream,Callback), &out, asCALL_THISCALL); r = mod->Build(); if( r < 0 ) { TEST_FAILED; } r = engine->RemoveConfigGroup("group1"); assert( r == asCONFIG_GROUP_IS_IN_USE ); engine->DiscardModule(0); engine->GarbageCollect(); r = engine->RemoveConfigGroup("group1"); assert( r >= 0 ); bout.buffer = ""; mod = engine->GetModule(0, asGM_ALWAYS_CREATE); mod->AddScriptSection(TESTNAME, script9, strlen(script9), 0); engine->SetMessageCallback(asMETHOD(CBufferedOutStream,Callback), &bout, asCALL_THISCALL); r = mod->Build(); if( r >= 0 || bout.buffer != "TestDynamicConfig (1, 1) : Info : Compiling void Test()\n" "TestDynamicConfig (3, 4) : Error : Identifier 'mytype' is not a data type\n" ) { PRINTF("%s", bout.buffer.c_str()); TEST_FAILED; } engine->Release(); //------------------ // Test object types held by external variable, i.e. any engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); RegisterScriptArray(engine, true); RegisterScriptAny(engine); engine->BeginConfigGroup("group1"); r = engine->RegisterObjectType("mytype", sizeof(int), asOBJ_VALUE | asOBJ_POD); any = (CScriptAny*)engine->CreateScriptObject(engine->GetTypeInfoByName("any")); r = engine->RegisterGlobalProperty("any g_any", any); engine->EndConfigGroup(); mod = engine->GetModule(0, asGM_ALWAYS_CREATE); mod->AddScriptSection(TESTNAME, script10); engine->SetMessageCallback(asMETHOD(COutStream,Callback), &out, asCALL_THISCALL); r = mod->Build(); if( r < 0 ) TEST_FAILED; r = ExecuteString(engine, "Test()", mod); if( r != asEXECUTION_FINISHED ) { TEST_FAILED; } engine->DiscardModule(0); engine->GarbageCollect(); CScriptArray *array = 0; any->Retrieve(&array, engine->GetTypeIdByDecl("mytype[]@")); if( array == 0 ) { TEST_FAILED; } else array->Release(); engine->GarbageCollect(); // The mytype variable is still stored in the any variable so we shouldn't be allowed to remove it's configuration group r = engine->RemoveConfigGroup("group1"); assert( r < 0 ); any->Release(); engine->GarbageCollect(); // Now it should be possible to remove the group r = engine->RemoveConfigGroup("group1"); assert( r >= 0 ); engine->Release(); //------------------- // Test references between config groups engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); engine->BeginConfigGroup("group1"); r = engine->RegisterObjectType("mytype", sizeof(int), asOBJ_VALUE | asOBJ_POD | asOBJ_APP_PRIMITIVE); assert( r >= 0 ); engine->EndConfigGroup(); engine->BeginConfigGroup("group2"); r = engine->RegisterGlobalFunction("void func(mytype)", asFUNCTION(0), asCALL_GENERIC); assert( r >= 0 ); engine->EndConfigGroup(); r = engine->RemoveConfigGroup("group1"); assert( r == asCONFIG_GROUP_IS_IN_USE ); r = engine->RemoveConfigGroup("group2"); assert( r <= 0 ); r = engine->RemoveConfigGroup("group1"); assert( r <= 0 ); engine->Release(); //-------------------- // Test situation where the default group references a dynamic group. It will then be impossible // to remove the dynamic group, but the application must still be able to release the engine. engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); engine->BeginConfigGroup("group1"); r = engine->RegisterObjectType("mytype", sizeof(int), asOBJ_VALUE | asOBJ_POD | asOBJ_APP_PRIMITIVE); assert( r >= 0 ); engine->EndConfigGroup(); r = engine->RegisterGlobalFunction("void func(mytype)", asFUNCTION(0), asCALL_GENERIC); assert( r >= 0 ); r = engine->RemoveConfigGroup("group1"); assert( r == asCONFIG_GROUP_IS_IN_USE ); engine->Release(); //---------------------- // Test that it is possible to repeat the registration of the config group engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); r = engine->BeginConfigGroup("g1"); assert( r >= 0 ); RegisterScriptString_Generic(engine); r = engine->EndConfigGroup(); assert( r >= 0 ); r = ExecuteString(engine, "string a = \"test\""); assert( r == asEXECUTION_FINISHED ); r = engine->GarbageCollect(); assert( r >= 0 ); r = engine->RemoveConfigGroup("g1"); assert( r >= 0 ); // again.. r = engine->BeginConfigGroup("g1"); assert( r >= 0 ); RegisterScriptString_Generic(engine); r = engine->EndConfigGroup(); assert( r >= 0 ); r = ExecuteString(engine, "string a = \"test\""); assert( r == asEXECUTION_FINISHED ); r = engine->GarbageCollect(); assert( r >= 0 ); r = engine->RemoveConfigGroup("g1"); assert( r >= 0 ); engine->Release(); //----------------------------- // Test that it isn't possible to register the same property in two different groups engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); engine->BeginConfigGroup("a"); r = engine->RegisterGlobalProperty("int a", (void*)1); assert( r >= 0 ); engine->EndConfigGroup(); r = engine->RegisterGlobalProperty("int a", (void*)1); assert( r < 0 ); engine->Release(); //------------------------------ // Test that ExecuteString doesn't lock dynamic config groups engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); r = engine->BeginConfigGroup("g1"); assert( r >= 0 ); RegisterScriptString_Generic(engine); r = engine->EndConfigGroup(); assert( r >= 0 ); r = ExecuteString(engine, "string a = \"test\""); assert( r == asEXECUTION_FINISHED ); // Garbage collect and remove config group before discarding module r = engine->GarbageCollect(); assert( r >= 0 ); r = engine->RemoveConfigGroup("g1"); assert( r >= 0 ); engine->Release(); //----------------------- // Make sure the clean-up works when there a groups using types in the default group engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); RegisterStdString(engine); engine->BeginConfigGroup("g"); r = engine->RegisterGlobalFunction("void SaveLesson(const string &in)", asFUNCTION(0), asCALL_GENERIC); assert( r >= 0 ); engine->EndConfigGroup(); engine->Release(); //------------------------- // Test registering object members in a group // http://www.gamedev.net/topic/636396-config-groups-and-object-property-accessors/ engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); engine->RegisterObjectType("type", 0, asOBJ_REF | asOBJ_NOCOUNT); // TODO: It should be possible to register methods and properties in different groups from where the type itself was registered engine->BeginConfigGroup("g"); engine->RegisterObjectMethod("type", "void func()", asFUNCTION(0), asCALL_GENERIC); engine->EndConfigGroup(); asITypeInfo *type = engine->GetTypeInfoByName("type"); if( type->GetMethodCount() != 1 ) TEST_FAILED; r = engine->RemoveConfigGroup("g"); if( r < 0 ) TEST_FAILED; // TODO: Currently the method is not removed as the method will be placed in the same group as the type. When this changes, the method should be removed if( type->GetMethodCount() != 1 ) TEST_FAILED; engine->Release(); // Success return fail; }
void RegisterScriptScheduler( asIScriptEngine* pEngine ) { RegisterScriptScheduledFunction( pEngine ); const char* pszObjectName = "CScheduler"; pEngine->RegisterObjectType( pszObjectName, sizeof( CASScheduler ), asOBJ_REF | asOBJ_NOCOUNT ); pEngine->RegisterObjectProperty( pszObjectName, "const int REPEAT_INFINITE_TIMES", asOFFSET( CASScheduler, REPEAT_INFINITE_TIMES ) ); /* * SetTimeout variants */ as::RegisterVarArgsMethod( *pEngine, pszObjectName, "CScheduledFunction@", "SetTimeout", "const string& in szFunction, float flDelay", 0, 8, asFUNCTION( CASScheduler::SetTimeoutHandler ) ); as::RegisterVarArgsMethod( *pEngine, pszObjectName, "CScheduledFunction@", "SetTimeout", "?& in thisObject, const string& in szFunction, float flDelay", 0, 8, asFUNCTION( CASScheduler::SetTimeoutObj ) ); /* * SetInterval variants */ as::RegisterVarArgsMethod( *pEngine, pszObjectName, "CScheduledFunction@", "SetInterval", "const string& in szFunction, float flRepeatTime, int iRepeatCount", 0, 8, asFUNCTION( CASScheduler::SetIntervalHandler ) ); pEngine->RegisterObjectMethod( pszObjectName, "CScheduledFunction@ SetInterval(const string& in szFunction, float flRepeatTime)", asFUNCTION( CASScheduler::SetInterval_NoArgs ), asCALL_GENERIC ); as::RegisterVarArgsMethod( *pEngine, pszObjectName, "CScheduledFunction@", "SetInterval", "?& in thisObject, const string& in szFunction, float flRepeatTime, int iRepeatCount", 0, 8, asFUNCTION( CASScheduler::SetIntervalObj ) ); pEngine->RegisterObjectMethod( pszObjectName, "CScheduledFunction@ SetInterval(?& in thisObject, const string& in szFunction, float flRepeatTime)", asFUNCTION( CASScheduler::SetIntervalObj_NoArgs ), asCALL_GENERIC ); pEngine->RegisterObjectMethod( pszObjectName, "void RemoveTimer(CScheduledFunction@ pFunction)", asMETHOD( CASScheduler, RemoveTimer ), asCALL_THISCALL ); pEngine->RegisterObjectMethod( pszObjectName, "CScheduledFunction@ GetCurrentFunction() const", asMETHOD( CASScheduler, GetCurrentFunction ), asCALL_THISCALL ); pEngine->RegisterObjectMethod( pszObjectName, "void ClearTimerList()", asMETHOD( CASScheduler, ClearTimerList ), asCALL_THISCALL ); }
void RectCollideService::registerToEngine(asIScriptEngine* e) { engine = e; RectCollideServiceDone::ID = engine->RegisterObjectType("RectCollideServiceDone", sizeof(RectCollideServiceDone), asOBJ_VALUE | asOBJ_POD); RegisterScriptHandle(engine); engine->RegisterObjectType("CollidableRect", sizeof(CollidableRect), asOBJ_REF | asOBJ_NOCOUNT); engine->RegisterObjectProperty("CollidableRect", "float x", asOFFSET(CollidableRect,x)); engine->RegisterObjectProperty("CollidableRect", "float y", asOFFSET(CollidableRect,y)); engine->RegisterObjectProperty("CollidableRect", "float w", asOFFSET(CollidableRect,w)); engine->RegisterObjectProperty("CollidableRect", "float h", asOFFSET(CollidableRect,h)); engine->RegisterObjectProperty("CollidableRect", "float vx", asOFFSET(CollidableRect,vx)); engine->RegisterObjectProperty("CollidableRect", "float vy", asOFFSET(CollidableRect,vy)); engine->RegisterObjectProperty("CollidableRect", "bool blockable", asOFFSET(CollidableRect,blockable)); engine->RegisterObjectProperty("CollidableRect", "bool blocking", asOFFSET(CollidableRect,blocking)); engine->RegisterObjectProperty("CollidableRect", "bool active", asOFFSET(CollidableRect,active)); engine->RegisterObjectProperty("CollidableRect", "ref@ object", asOFFSET(CollidableRect,objHandle)); engine->RegisterEnum("CollisionDirection"); engine->RegisterEnumValue("CollisionDirection", "UP", CollisionDirection::UP); engine->RegisterEnumValue("CollisionDirection", "DOWN", CollisionDirection::DOWN); engine->RegisterEnumValue("CollisionDirection", "LEFT", CollisionDirection::LEFT); engine->RegisterEnumValue("CollisionDirection", "RIGHT", CollisionDirection::RIGHT); RectCollision::ID = engine->RegisterObjectType("RectCollision", sizeof(RectCollision), asOBJ_REF | asOBJ_NOCOUNT); engine->RegisterObjectProperty("RectCollision", "CollidableRect a", asOFFSET(RectCollision,a)); engine->RegisterObjectProperty("RectCollision", "CollidableRect b", asOFFSET(RectCollision,b)); engine->RegisterObjectProperty("RectCollision", "CollisionDirection direction", asOFFSET(RectCollision,direction)); engine->RegisterObjectType("RectCollideServiceType", 0, asOBJ_REF | asOBJ_NOCOUNT); engine->RegisterObjectMethod("RectCollideServiceType", "CollidableRect@ createRect(?&in, float, float, float, float, float, float, bool, bool, bool)", asMETHOD(RectCollideService, createRect), asCALL_THISCALL); engine->RegisterGlobalProperty("RectCollideServiceType RectCollideService", this); }
AEResult TimeAddOnAS::RegisterTimeStampObject(asIScriptEngine* engine) { int ret = 0; ///////////////////// //Register TimeStamp ///////////////////// ret = engine->RegisterObjectType("TimeStamp", sizeof(TimeStamp), asOBJ_VALUE | asOBJ_POD | asOBJ_APP_CLASS); if (ret < 0) { return AEResult::RegObjTypeFail; } ret = engine->RegisterObjectProperty("TimeStamp", "uint m_Day", asOFFSET(TimeStamp, m_Day)); if (ret < 0) { return AEResult::RegObjPropFail; } ret = engine->RegisterObjectProperty("TimeStamp", "uint m_Month", asOFFSET(TimeStamp, m_Month)); if (ret < 0) { return AEResult::RegObjPropFail; } ret = engine->RegisterObjectProperty("TimeStamp", "uint m_Year", asOFFSET(TimeStamp, m_Year)); if (ret < 0) { return AEResult::RegObjPropFail; } ret = engine->RegisterObjectProperty("TimeStamp", "uint m_Hour", asOFFSET(TimeStamp, m_Hour)); if (ret < 0) { return AEResult::RegObjPropFail; } ret = engine->RegisterObjectProperty("TimeStamp", "uint m_Minute", asOFFSET(TimeStamp, m_Minute)); if (ret < 0) { return AEResult::RegObjPropFail; } ret = engine->RegisterObjectProperty("TimeStamp", "uint m_Second", asOFFSET(TimeStamp, m_Second)); if (ret < 0) { return AEResult::RegObjPropFail; } ret = engine->RegisterObjectMethod("TimeStamp", "wstring ToString() const", asMETHOD(TimeStamp, ToString), asCALL_THISCALL); if (ret < 0) { return AEResult::RegObjMethodFail; } ret = engine->RegisterObjectBehaviour("TimeStamp", asBEHAVE_CONSTRUCT, "void AEAS_TimeStamp_Constructor()", asFUNCTION(TimeStamp_Constructor), asCALL_CDECL_OBJLAST); if (ret < 0) { return AEResult::RegObjBehaviorFail; } ret = engine->RegisterObjectBehaviour("TimeStamp", asBEHAVE_DESTRUCT, "void AEAS_TimeStamp_Destructor()", asFUNCTION(TimeStamp_Destructor), asCALL_CDECL_OBJLAST); if (ret < 0) { return AEResult::RegObjBehaviorFail; } return AEResult::Ok; }