//======================================================================
bool CScriptInt::Initialize(const std::string& szScriptDir, void* pCallbackFunction)
{
	//Initialize scripting interface object

	if (/*(!szScriptDir.length()) ||*/ (!pCallbackFunction))
		return false;

	//Initialize AngelScript
	this->m_pScriptEngine = asCreateScriptEngine();
	if (!this->m_pScriptEngine)
		return false;

	//Set message callback function
	if (AS_FAILED(this->m_pScriptEngine->SetMessageCallback(asFUNCTION(pCallbackFunction), 0, asCALL_CDECL))) {
		this->m_pScriptEngine->ShutDownAndRelease();
		return false;
	}

	//Register string type
	RegisterStdString(this->m_pScriptEngine);

	//Register array type
	RegisterScriptArray(this->m_pScriptEngine, false);

	//Register math functions
	RegisterScriptMath(this->m_pScriptEngine);

	//Save script path
	this->m_szScriptPath = szScriptDir;
	
	//Set and return indicator value
	return this->m_bInitialized = true;
}
bool TestExecuteScript()
{
	bool fail = false;
	COutStream out;

	engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
	engine->SetMessageCallback(asMETHOD(COutStream,Callback), &out, asCALL_THISCALL);
	
	RegisterStdString(engine);
	engine->RegisterGlobalFunction("void assert(bool)", asFUNCTION(Assert), asCALL_GENERIC);

	CScriptBuilder builder;

	int r = builder.StartNewModule(engine, 0);
	if( r >= 0 )
		r = builder.AddSectionFromFile("scripts/TestExecuteScript.as");
	if( r >= 0 )
		r = builder.BuildModule();
	if( r >= 0 )
	{
		fail = ExecuteScript();
	}

	engine->Release();
	engine = NULL;

	return fail;
}
Example #3
0
void ConfigureEngine(asIScriptEngine *engine)
{
	int r;

	// Register the script string type
	// Look at the implementation for this function for more information  
	// on how to register a custom string type, and other object types.
	RegisterStdString(engine);

	if( !strstr(asGetLibraryOptions(), "AS_MAX_PORTABILITY") )
	{
		// Register the functions that the scripts will be allowed to use.
		// Note how the return code is validated with an assert(). This helps
		// us discover where a problem occurs, and doesn't pollute the code
		// with a lot of if's. If an error occurs in release mode it will
		// be caught when a script is being built, so it is not necessary
		// to do the verification here as well.
		r = engine->RegisterGlobalFunction("void print(const string &in)", asFUNCTION(PrintString), asCALL_CDECL); assert( r >= 0 );
	}


	// It is possible to register the functions, properties, and types in 
	// configuration groups as well. When compiling the scripts it then
	// be defined which configuration groups should be available for that
	// script. If necessary a configuration group can also be removed from
	// the engine, so that the engine configuration could be changed 
	// without having to recompile all the scripts.
}
bool Test()
{
	bool fail = false;
	int r;

 	asIScriptEngine *engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);

	RegisterStdString(engine);

	engine->RegisterObjectType("Obj", sizeof(Obj), asOBJ_CLASS);
	engine->RegisterObjectProperty("Obj", "int v", offsetof(Obj, v));

	COutStream out;

	engine->AddScriptSection(0, TESTNAME, script1, strlen(script1), 0);
	r = engine->Build(0, &out);
	if( r < 0 )
	{
		fail = true;
		printf("%s: Failed to compile the script\n", TESTNAME);
	}

	engine->Release();

	// Success
	return fail;
}
Example #5
0
bool CommonAPI::InitAS()
{
	engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
	engine->SetMessageCallback(asFUNCTION(MessageCallback), 0, asCALL_CDECL);
	RegisterStdString(engine);

	RegisterAPI();

	CScriptBuilder builder;

	if(builder.StartNewModule(engine, "MyModule") < 0)
		FILE_LOG(logERROR) << "Unrecoverable error while starting a new module.";

	string scriptPath = exePath.substr(0, exePath.find_last_of(".")).append(".tes");

	if(builder.AddSectionFromFile(scriptPath.c_str()) < 0)
		FILE_LOG(logERROR) << "Unable to load script." << scriptPath;
	else
		FILE_LOG(logINFO) << "Script " << scriptPath << " loaded successfully.";

	if(builder.BuildModule() < 0)
		FILE_LOG(logERROR) << "Please correct the errors in the script and try again.";

	
	module = engine->GetModule("MyModule");

	return true;
}
Example #6
0
void Engine::init()
{
	_engine->SetMessageCallback(asMETHOD(Engine, messageCallback), this, asCALL_THISCALL);

	RegisterStdString(_engine);
	RegisterScriptHandle(_engine);
	RegisterScriptAny(_engine);
}
	bool Test()
	{
		bool fail = false;
		int r;

		COutStream out;

		asIScriptEngine *engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
		engine->SetMessageCallback(asMETHOD(COutStream, Callback), &out, asCALL_THISCALL);
		RegisterStdString(engine);
		engine->RegisterGlobalFunction("void assert(bool)", asFUNCTION(Assert), asCALL_GENERIC);

		// Test type conversions
		r = ExecuteString(engine, 
			"string a = 123; assert( a == '123' ); \n"
			"a += 123; assert( a == '123123' ); \n");
		if (r != asEXECUTION_FINISHED) TEST_FAILED;

		r = ExecuteString(engine,
			"string a = 123.4; \n"
			"assert( a == '123.4' ); \n"
			"a += 123.4; \n"
			"assert( a == '123.4123.4' ); \n");
		if (r != asEXECUTION_FINISHED) TEST_FAILED;

		// Test find routines
		r = ExecuteString(engine,
			"string a = 'The brown fox jumped the white fox'; \n"
			"assert( a.findFirst('fox') == 10); \n"
			"assert( a.findFirstOf('fjq') == 10); \n"
			"assert( a.findFirstNotOf('The') == 3); \n"
			"assert( a.findLast('fox') == 31); \n"
			"assert( a.findLastOf('fjq') == 31); \n"
			"assert( a.findLastNotOf('fox') == 33); \n");
		if (r != asEXECUTION_FINISHED) TEST_FAILED;

		// Test insert and erase
		r = ExecuteString(engine,
			"string a; \n"
			"a.insert(5, 'hello'); \n");  // attempt to insert beyond the size of the string
		if (r != asEXECUTION_EXCEPTION) TEST_FAILED;

		r = ExecuteString(engine,
			"string a; \n"
			"a.insert(0, 'hello'); \n" // at index 1 beyond the last it is allowed
			"a.erase(2,2); \n"
			"assert( a == 'heo' ); \n"); 
		if (r != asEXECUTION_FINISHED) TEST_FAILED;

		engine->ShutDownAndRelease();

		return fail;
	}
Example #8
0
//#################### CONSTRUCTORS ####################
ASXEngine::ASXEngine()
{
    m_engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);

    if(!m_engine)
    {
        throw ASXException("Could not create scripting engine");
    }

    m_engine->SetMessageCallback(asMETHOD(ASXEngine, message_callback), this, asCALL_THISCALL);

    RegisterStdString(m_engine);
}
Example #9
0
bool Test()
{
	if( strstr(asGetLibraryOptions(), "AS_MAX_PORTABILITY") )
	{
		printf("%s: Skipped due to AS_MAX_PORTABILITY\n", TESTNAME);
		return false;
	}
	bool fail = false;
	int r;

 	asIScriptEngine *engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
	COutStream out;
	engine->SetMessageCallback(asMETHOD(COutStream,Callback), &out, asCALL_THISCALL);

	RegisterStdString(engine);

	engine->RegisterGlobalFunction("void Assert(bool)", asFUNCTION(Assert), asCALL_GENERIC);

	engine->RegisterObjectType("Dict", sizeof(CDict), asOBJ_VALUE | asOBJ_APP_CLASS_CDA);	
	engine->RegisterObjectBehaviour("Dict", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(Construct), asCALL_CDECL_OBJLAST);
	engine->RegisterObjectBehaviour("Dict", asBEHAVE_DESTRUCT, "void f()", asFUNCTION(Destruct), asCALL_CDECL_OBJLAST);
	engine->RegisterObjectMethod("Dict", "Dict &opAssign(const Dict &in)", asMETHOD(CDict,operator=), asCALL_THISCALL);

	engine->RegisterObjectMethod("Dict", "Dict &opIndex(string)", asMETHOD(CDict, operator[]), 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;
		printf("%s: Failed to compile the script\n", TESTNAME);
	}

	asIScriptContext *ctx = engine->CreateContext();
	r = ExecuteString(engine, "TestDict()", 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();

	engine->Release();

	// Success
	return fail;
}
Example #10
0
bool Test2()
{
	bool fail = false;
	COutStream out;
	CBufferedOutStream bout;
	int r;

	asIScriptEngine *engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
	engine->SetMessageCallback(asMETHOD(COutStream, Callback), &out, asCALL_THISCALL);

	RegisterStdString(engine);

	engine->RegisterObjectType("CMyObj", 0, asOBJ_REF);
	engine->RegisterObjectBehaviour("CMyObj", asBEHAVE_FACTORY, "CMyObj @f()", asFUNCTION(MyObj_factory), asCALL_CDECL);
	engine->RegisterObjectBehaviour("CMyObj", asBEHAVE_ADDREF, "void f()", asMETHOD(CMyObj, AddRef), asCALL_THISCALL);
	engine->RegisterObjectBehaviour("CMyObj", asBEHAVE_RELEASE, "void f()", asMETHOD(CMyObj, Release), asCALL_THISCALL);
	engine->RegisterObjectMethod("CMyObj", "void set_Text(const string &in)", asMETHOD(CMyObj, set_Text), asCALL_THISCALL);

	const char *string = 
		"void main() { \n"
		"  CMyObj @obj = @CMyObj(); \n"
		"  obj.Text = 'Hello world!'; \n"
		"} \n";
	asIScriptModule *mod = engine->GetModule("mod", asGM_ALWAYS_CREATE);
	mod->AddScriptSection("string", string);
	r = mod->Build();
	if( r < 0 ) 
		TEST_FAILED;

	r = ExecuteString(engine, "main()", mod);
	if( r != asEXECUTION_FINISHED )
		TEST_FAILED;

	// Test disabling property accessors
	engine->SetMessageCallback(asMETHOD(CBufferedOutStream, Callback), &bout, asCALL_THISCALL);
	engine->SetEngineProperty(asEP_PROPERTY_ACCESSOR_MODE, 0);
	r = ExecuteString(engine, "CMyObj o; o.Text = 'hello';");
	if( r >= 0 )
		TEST_FAILED;
	if( bout.buffer != "ExecuteString (1, 12) : Error   : 'Text' is not a member of 'CMyObj'\n" )
	{
		TEST_FAILED;
		printf("%s", bout.buffer.c_str());
	}

	engine->Release();

	return fail;
}
Example #11
0
	asIScriptEngine * ScriptEngine::CreateEngine()
	{
		asPrepareMultithread();

		mScriptEngine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
		mScriptContext = mScriptEngine->CreateContext();

		mScriptEngine->SetMessageCallback(asFUNCTION(ScriptEngine::MessageCallback), NULL, asCALL_CDECL);

		RegisterStdString(mScriptEngine);

		mScriptEngine->RegisterGlobalFunction("void print(const string &in)", asFUNCTION(ScriptEngine::Print), asCALL_CDECL);

		return mScriptEngine;
	}
Example #12
0
	cLowLevelSystemSDL::cLowLevelSystemSDL()
	{
		mpScriptEngine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
		
		mpScriptOutput = hplNew( cScriptOutput, () );
		mpScriptEngine->SetMessageCallback(asMETHOD(cScriptOutput,AddMessage), mpScriptOutput, asCALL_THISCALL);

#ifdef AS_MAX_PORTABILITY
		RegisterScriptString(mpScriptEngine);
#else
		RegisterStdString(mpScriptEngine);
#endif

		mlHandleCount = 0;

		Log("-------- THE HPL ENGINE LOG ------------\n\n");
	}
Example #13
0
/** Configures the script engine by binding functions, enums
*  \param asIScriptEngine engine = engine to configure
*/
void ScriptEngine::configureEngine(asIScriptEngine *engine)
{
    // Register the script string type
    RegisterStdString(engine); //register std::string
    RegisterVec3(engine);      //register Vec3

    Scripting::Track::registerScriptFunctions(m_engine);

    Scripting::Track::registerScriptEnums(m_engine);

    Scripting::Kart::registerScriptFunctions(m_engine);

    Scripting::Physics::registerScriptFunctions(m_engine);

    
    // It is possible to register the functions, properties, and types in 
    // configuration groups as well. When compiling the scripts it can then
    // be defined which configuration groups should be available for that
    // script. If necessary a configuration group can also be removed from
    // the engine, so that the engine configuration could be changed 
    // without having to recompile all the scripts.
}
Example #14
0
	bool RegisterCoreAPI( CASManager& manager ) override
	{
		auto& engine = *manager.GetEngine();

		RegisterStdString( &engine );

		RegisterScriptCTime( engine );
		RegisterScriptCDateTime( engine );
		RegisterScriptSQLCommon( engine );
		RegisterScriptSQLite( engine );
		RegisterScriptMySQL( engine );

		RegisterScriptEventAPI( engine );

		engine.RegisterObjectType( "CSQL", 0, asOBJ_REF | asOBJ_NOCOUNT );

		engine.RegisterObjectMethod( 
			"CSQL", "SQLiteConnection@ CreateSQLiteConnection(const " AS_STRING_OBJNAME "& in szFilename)",
			asMETHOD( CASSQL, CreateSQLiteConnection ), asCALL_THISCALL );

		engine.RegisterObjectMethod(
			"CSQL", "MySQLConnection@ CreateMySQLConnection("
			"const " AS_STRING_OBJNAME "& in szHost, const " AS_STRING_OBJNAME "& in szUser,"
			"const " AS_STRING_OBJNAME "& in szPassword, const " AS_STRING_OBJNAME "& in szDatabase = \"\")",
			asMETHOD( CASSQL, CreateMySQLConnection ), asCALL_THISCALL );

		engine.RegisterGlobalProperty( "CSQL SQL", &g_ASSQL );

		as::RegisterVarArgsFunction( 
			engine, "void", "Print", "const " AS_STRING_OBJNAME "& in szFormat",
			0, 8, asFUNCTION( Print ) );

		engine.RegisterGlobalFunction( 
			"void Assert(const bool bCondition)", 
			asFUNCTION( ScriptAssert ), asCALL_CDECL );

		return true;
	}
Example #15
0
void run(GLFWwindow* window, std::string const& scriptFile)
{
  asIScriptEngine* engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
  anglhck::registerToEngine(engine);

  RegisterStdString(engine);
  engine->RegisterGlobalFunction("void print(const string &in)", asFUNCTION(print), asCALL_CDECL);

  CScriptBuilder builder;
  builder.StartNewModule(engine, "MyModule");
  builder.AddSectionFromFile(scriptFile);
  builder.BuildModule();
  asIScriptModule *mod = engine->GetModule("MyModule");
  asIScriptFunction *func = mod->GetFunctionByDecl("void main()");
  asIScriptContext *ctx = engine->CreateContext();
  ctx->Prepare(func);
  int ret = ctx->Execute();

  if( ret == asEXECUTION_EXCEPTION )
  {
    std::cout << ctx->GetExceptionString() << std::endl;
  }
}
Example #16
0
ScriptEngine::ScriptEngine()
	: m_engine(asCreateScriptEngine())
{
	if (!m_engine)
		return;

	// Set the message callback to receive information on errors in human readable form.
	int r = m_engine->SetMessageCallback(asFUNCTION(MessageCallback), &m_errorString, asCALL_CDECL); assert(r >= 0);

	RegisterStdString(m_engine);
	//	RegisterStdStringUtils(engine);

	// The scripts can directly print text
	r = m_engine->RegisterGlobalFunction("void print(const string &in message)", asMETHOD(ScriptEngine, print), asCALL_THISCALL_ASGLOBAL, this); assert(r >= 0);

	RegisterScriptMath(m_engine);
	aatc::RegisterAllContainers(m_engine);
	
	registerObject(m_engine);
	registerAllTypes(m_engine);
	
	generateReference();
}
Example #17
0
Context::Context()
{
	// Create the asEngine if the asEngine hasn't been created yet.
	static bool done = false;
	
	
	if(!done)
	{
		done = true;
		
		asDetails.asEngine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
		assert(asDetails.asEngine);
		
		asDetails.asEngine->SetMessageCallback(asFUNCTION(MessageCallback), 0, asCALL_CDECL);
		
		asDetails.asEngine->GetModule(0, asGM_CREATE_IF_NOT_EXISTS);
		
		RegisterStdString(asDetails.asEngine);
		RegisterScriptArray(asDetails.asEngine, true);
	}
	
	asDetails.asContext = asDetails.asEngine->CreateContext();
	assert(asDetails.asContext);
}
bool Test()
{
	RET_ON_MAX_PORT

	bool fail = false;
	int r;
	COutStream out;
	CBufferedOutStream bout;
//	asIScriptContext *ctx;
	asIScriptEngine *engine;
//	asIScriptModule *mod;

	// Test circular reference between grid and ref
	{
		engine = asCreateScriptEngine();
		engine->SetMessageCallback(asMETHOD(COutStream, Callback), &out, asCALL_THISCALL);
		RegisterScriptHandle(engine);
		RegisterScriptGrid(engine);

		// Create the circular reference
		r = ExecuteString(engine, "grid<ref> a; a.resize(1,1); @a[0,0] = a;");
		if (r != asEXECUTION_FINISHED)
			TEST_FAILED;

		engine->GarbageCollect();

		asUINT currSize, totDestroy, totDetect;
		engine->GetGCStatistics(&currSize, &totDestroy, &totDetect);
		if (currSize != 0 || totDestroy != 1 || totDetect != 1)
			TEST_FAILED;

		engine->ShutDownAndRelease();
	}

	// Test empty initialization list
	// http://www.gamedev.net/topic/658849-empty-array-initialization/
	{
		engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
		engine->SetMessageCallback(asMETHOD(COutStream, Callback), &out, asCALL_THISCALL);

		RegisterScriptGrid(engine);

		r = ExecuteString(engine, "grid<int> a = {};"); // Valid 0x0 grid
		if( r != asEXECUTION_FINISHED )
			TEST_FAILED;

		r = ExecuteString(engine, "grid<int> a = {{}};"); // Valid 0x1 grid
		if( r != asEXECUTION_FINISHED )
			TEST_FAILED;

		r = ExecuteString(engine, "grid<int> a = {{},{}};"); // Valid 0x2 grid
		if( r != asEXECUTION_FINISHED )
			TEST_FAILED;

		engine->Release();
	}

	// Test grid object forcibly destroyed by garbage collector
	// http://www.gamedev.net/topic/657955-a-quite-specific-bug/
	{
		engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
		engine->SetMessageCallback(asMETHOD(COutStream, Callback), &out, asCALL_THISCALL);

		RegisterScriptGrid(engine);
		RegisterScriptAny(engine);
		RegisterScriptArray(engine, false);

		asIScriptModule *mod = engine->GetModule("test", asGM_ALWAYS_CREATE);
		mod->AddScriptSection("test", 
			"class B {} \n"
			"class A \n"
			"{ \n"
			"	any a; \n"
			"	grid<B@> t(10, 10); \n"
			"	A() \n"
			"	{ \n"
			"		a.store(@this); \n"
			"	} \n"
			"} \n"
			"array<A@> arr; \n"
			"void main() \n"
			"{ \n"
			"	arr.insertLast(@A()); \n"
			"} \n");
		r = mod->Build();
		if( r < 0 )
			TEST_FAILED;

		// The type B is not really garbage collected
		asITypeInfo *t = mod->GetTypeInfoByDecl("B");
		if( t == 0 || (t->GetFlags() & asOBJ_GC) )
			TEST_FAILED;

		// grid<B> is not garbage collected since B is not
		t = mod->GetTypeInfoByDecl("grid<B>");
		if( t == 0 || (t->GetFlags() & asOBJ_GC) )
			TEST_FAILED;

		// grid<B@> is however garbage collected because it is not possible to know 
		// that no class derived from B can't form a circular reference with it.
		t = mod->GetTypeInfoByDecl("grid<B@>");
		if( t == 0 || !(t->GetFlags() & asOBJ_GC) )
			TEST_FAILED;

		r = ExecuteString(engine, "main()", mod);
		if( r != asEXECUTION_FINISHED )
			TEST_FAILED;

		engine->Release();
	}

	// Test resize
	{
		engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
		engine->SetMessageCallback(asMETHOD(COutStream, Callback), &out, asCALL_THISCALL);

		RegisterScriptGrid(engine);
		RegisterStdString(engine);

		engine->RegisterGlobalFunction("void assert(bool)", asFUNCTION(Assert), asCALL_GENERIC);

		r = ExecuteString(engine,
			"grid<string> g; \n"
			"g.resize(1,1); \n"
			"g[0,0] = 'hello'; \n"
			"g.resize(2,2); \n"
			"assert( g[0,0] == 'hello' ); \n"
			"g[1,1] = 'there'; \n"
			"g.resize(1,1); \n"
			"assert( g.width() == 1 && g.height() == 1 ); \n");
		if( r != asEXECUTION_FINISHED )
			TEST_FAILED;

		engine->Release();
	}

	// Test initialization lists
	{
		engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
		engine->SetMessageCallback(asMETHOD(COutStream, Callback), &out, asCALL_THISCALL);

		RegisterScriptGrid(engine);
		RegisterStdString(engine);

		engine->RegisterGlobalFunction("void assert(bool)", asFUNCTION(Assert), asCALL_GENERIC);

		r = ExecuteString(engine, 
			"grid<int8> g = {{1,2,3},{4,5,6},{7,8,9}}; \n"
			"assert( g[0,0] == 1 ); \n"
			"assert( g[2,2] == 9 ); \n"
			"assert( g[0,2] == 7 ); \n");
		if( r != asEXECUTION_FINISHED )
			TEST_FAILED;

		r = ExecuteString(engine, 
			"grid<string> g = {{'1','2'},{'4','5'}}; \n"
			"assert( g[0,0] == '1' ); \n"
			"assert( g[1,1] == '5' ); \n"
			"assert( g[0,1] == '4' ); \n");
		if( r != asEXECUTION_FINISHED )
			TEST_FAILED;

		r = ExecuteString(engine,
			"grid<grid<int>@> g = {{grid<int> = {{1}}, grid<int> = {{2}}}, {grid<int> = {{3}}, grid<int> = {{4}}}}; \n"
			"assert( g[0,0][0,0] == 1 ); \n"
			"assert( g[1,1][0,0] == 4 ); \n");
		if( r != asEXECUTION_FINISHED )
			TEST_FAILED;
	
		engine->Release();
	}

	// Success
	return fail;
}
Example #19
0
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.
	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"
		"}                          \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(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_opIndex(int i) const { return arr[i]; } \n"
			"  void set_opIndex(int i, int v) { arr[i] = v; } \n"
			"  array<int> 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"
			"} \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 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", offsetof(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 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", offsetof(CNode, vector));
		engine->RegisterObjectProperty("node", "float x", offsetof(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();
	}

	fail = Test2() || fail;

	// Success
	return fail;
}
bool TestRefScoped()
{
	if( strstr(asGetLibraryOptions(), "AS_MAX_PORTABILITY") )
	{
		// Skipping this due to not supporting native calling conventions
		printf("Skipped due to AS_MAX_PORTABILITY\n");
		return false;
	}

	bool fail = false;
	int r = 0;
	CBufferedOutStream bout;
 	asIScriptEngine *engine;
	asIScriptModule *mod;

	// REF+SCOPED
	// This type requires a factory and a release behaviour. It cannot have the addref behaviour.
	// The intention of this type is to permit value types that have special needs for memory management,
	// for example must be aligned on 16 byte boundaries, or must use a memory pool. The type must not allow
	// object handles (except when returning a new value from registered functions).
	bout.buffer = "";
	engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
	RegisterStdString(engine);
	engine->SetMessageCallback(asMETHOD(CBufferedOutStream, Callback), &bout, asCALL_THISCALL);
	r = engine->RegisterObjectType("scoped", 0, asOBJ_REF | asOBJ_SCOPED); assert( r >= 0 );
	r = engine->RegisterObjectBehaviour("scoped", asBEHAVE_FACTORY, "scoped @f()", asFUNCTION(Scoped_Factory), asCALL_CDECL); assert( r >= 0 );
	r = engine->RegisterObjectBehaviour("scoped", asBEHAVE_RELEASE, "void f()", asFUNCTION(Scoped_Release), asCALL_CDECL_OBJLAST); assert( r >= 0 );
	r = engine->RegisterObjectMethod("scoped", "scoped @opNeg()", asFUNCTION(Scoped_Negate), asCALL_CDECL_OBJLAST); assert( r >= 0 );
	r = engine->RegisterObjectMethod("scoped", "scoped &opAssign(const scoped &in)", asFUNCTION(Scoped_Assignment), asCALL_CDECL_OBJLAST); assert( r >= 0 );
	r = engine->RegisterObjectMethod("scoped", "scoped @opAdd(int)", asFUNCTION(Scoped_Add), asCALL_CDECL_OBJFIRST); assert( r >= 0 );

	// Enumerate the objects behaviours
	asIObjectType *ot = engine->GetObjectTypeById(engine->GetTypeIdByDecl("scoped"));
	if( ot->GetBehaviourCount() != 1 )
		fail = true;
	asEBehaviours beh;
	ot->GetBehaviourByIndex(0, &beh);
	if( beh != asBEHAVE_RELEASE )
		fail = true;

	// Must be possible to determine type id for scoped types with handle
	asIScriptFunction *func = engine->GetFunctionDescriptorById(ot->GetFactoryIdByIndex(0));
	int typeId = func->GetReturnTypeId();
	if( typeId != engine->GetTypeIdByDecl("scoped@") )
		fail = true;

	// Don't permit handles to be taken
	r = engine->ExecuteString(0, "scoped @s = null");
	if( r >= 0 ) fail = true;
	// TODO: The second message is a consequence of the first error, and should ideally not be shown
	if( sizeof(void*) == 4 )
	{
		if( bout.buffer != "ExecuteString (1, 8) : Error   : Object handle is not supported for this type\n"
						   "ExecuteString (1, 13) : Error   : Can't implicitly convert from '<null handle>' to 'scoped&'.\n" )
		{
			printf(bout.buffer.c_str());
			fail = true;
		}
	}
	else
	{
		if( bout.buffer != "ExecuteString (1, 8) : Error   : Object handle is not supported for this type\n"
						   "ExecuteString (1, 13) : Error   : Can't implicitly convert from '<null handle>' to 'scoped&'.\n" )
		{
			printf(bout.buffer.c_str());
			fail = true;
		}
	}

	// Test a legal actions
	r = engine->ExecuteString(0, "scoped a");
	if( r != asEXECUTION_FINISHED ) fail = true;

	bout.buffer = "";
	r = engine->ExecuteString(0, "scoped s; scoped t = s + 10;");
	if( r != asEXECUTION_FINISHED ) fail = true;
	if( bout.buffer != "" )
	{
		printf(bout.buffer.c_str());
		fail = true;
	}

	// Test a compiler assert failure reported by Jeff Slutter on 2009-04-02
	bout.buffer = "";
	const char *script =
		"SetObjectPosition( GetWorldPositionByName() ); \n";

	r = engine->RegisterGlobalFunction("const scoped @GetWorldPositionByName()", asFUNCTION(Scoped_Factory), asCALL_CDECL); assert( r >= 0 );
	r = engine->RegisterGlobalFunction("void SetObjectPosition(scoped &in)", asFUNCTION(Scoped_InRef), asCALL_CDECL); assert( r >= 0 );
	
	r = engine->ExecuteString(0, script);
	if( r != asEXECUTION_FINISHED ) fail = true;
	if( bout.buffer != "" )
	{
		printf(bout.buffer.c_str());
		fail = true;
	}

	// It must be possible to include the scoped type as member in script class
	bout.buffer = "";
	mod = engine->GetModule(0, asGM_ALWAYS_CREATE);
	mod->AddScriptSection("test", "class A { scoped s; }");
	r = mod->Build();
	if( r < 0 )
		fail = true;
	if( bout.buffer != "" )
	{
		printf(bout.buffer.c_str());
		fail = true;
	}
	r = engine->ExecuteString(0, "A a; scoped s; a.s = s;");
	if( r != asEXECUTION_FINISHED )
	{
		fail = true;
	}


	// Don't permit functions to be registered with handle for parameters
	bout.buffer = "";
	r = engine->RegisterGlobalFunction("void f(scoped@)", asFUNCTION(DummyFunc), asCALL_GENERIC);
	if( r >= 0 ) fail = true;
	if( bout.buffer != "System function (1, 14) : Error   : Object handle is not supported for this type\n" )
	{
		printf(bout.buffer.c_str());
		fail = true;
	}

	// Don't permit functions to be registered to take type by reference (since that require handles)
	bout.buffer = "";
	r = engine->RegisterGlobalFunction("void f(scoped&)", asFUNCTION(DummyFunc), asCALL_GENERIC);
	if( r >= 0 ) fail = true;
	if( bout.buffer != "System function (1, 14) : Error   : Only object types that support object handles can use &inout. Use &in or &out instead\n" )
	{
		printf(bout.buffer.c_str());
		fail = true;
	}

	// Permit &in
	r = engine->RegisterGlobalFunction("void f(scoped&in)", asFUNCTION(DummyFunc), asCALL_GENERIC);
	if( r < 0 ) fail = true;


	engine->Release();

	return fail;
}
void Test()
{
	printf("---------------------------------------------\n");
	printf("%s\n\n", TESTNAME);
	printf("AngelScript 2.31.0: Build 1.02 secs, Save 0.0920 secs, Load 0.125 secs\n");

	asIScriptEngine *engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);

	COutStream out;
	engine->SetMessageCallback(asMETHOD(COutStream,Callback), &out, asCALL_THISCALL);

	RegisterScriptArray(engine, true);
	RegisterStdString(engine);
	engine->RegisterGlobalFunction("void print(const string &in)", asFUNCTION(print), asCALL_CDECL);

	////////////////////////////////////////////
	printf("\nGenerating...\n");

	const int numArrays = 2;
#ifdef _DEBUG
	const int numElements = 10;
#else
	const int numElements = 200000;
#endif

	string script;
    std::stringstream script_buffer;
    for (unsigned i = 0; i < numArrays; i++)
    {
        script_buffer << "int[] array_" << i << " = {";
        if (numElements > 0)
        {
            script_buffer << 0;
        }
        for (unsigned j = 1; j < numElements; j++)
        {
            script_buffer << ", " << j;
        }
        script_buffer << "};";
    }
    script_buffer << std::endl << "int main() { print (\"elem 999 = \" + array_0[999] + \"\\n\"); return 0; }";
    script = script_buffer.str();

	////////////////////////////////////////////
	printf("\nBuilding...\n");

	double time = GetSystemTimer();

	asIScriptModule *mod = engine->GetModule(0, asGM_ALWAYS_CREATE);
	mod->AddScriptSection(TESTNAME, script.c_str(), script.size(), 0);
	int r = mod->Build();

	time = GetSystemTimer() - time;

	if( r != 0 )
		printf("Build failed\n");
	else
		printf("Time = %f secs\n", time);

	////////////////////////////////////////////
	printf("\nSaving...\n");

	time = GetSystemTimer();

	CBytecodeStream stream("");
	mod->SaveByteCode(&stream);

	time = GetSystemTimer() - time;
	printf("Time = %f secs\n", time);
	printf("Size = %d\n", int(stream.buffer.size()));

	////////////////////////////////////////////
	printf("\nLoading...\n");

	time = GetSystemTimer();

	asIScriptModule *mod2 = engine->GetModule(0, asGM_ALWAYS_CREATE);
	mod2->LoadByteCode(&stream);

	time = GetSystemTimer() - time;
	printf("Time = %f secs\n", time);

	engine->Release();
}
Example #22
0
bool Test()
{
	if( strstr(asGetLibraryOptions(), "AS_MAX_PORTABILITY") )
	{
		printf("Skipped due to AS_MAX_PORTABILITY\n");
		return false;
	}

	bool fail = false;
	int r;
	COutStream out;
	asIScriptEngine *engine;
	asIScriptModule *mod;
	asIScriptContext *ctx;
	CBufferedOutStream bout;
	const char *script;

	// opEquals with funcdef
	// http://www.gamedev.net/topic/647797-difference-between-xopequalsy-and-xy-with-funcdefs/
	{
		engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
		engine->SetMessageCallback(asMETHOD(COutStream, Callback), &out, asCALL_THISCALL);
		engine->RegisterGlobalFunction("void assert(bool)", asFUNCTION(Assert), asCALL_GENERIC);

		mod = engine->GetModule("mod", asGM_ALWAYS_CREATE);
		mod->AddScriptSection("test",
			"funcdef void CALLBACK(); \n"
			"class Test { \n"
			"  bool opEquals(CALLBACK @f) { \n"
			"    return f is func; \n"
			"  } \n"
			"  CALLBACK @func; \n"
			"} \n"
			"void func() {} \n");
		r = mod->Build();
		if( r < 0 )
			TEST_FAILED;

		r = ExecuteString(engine, "Test t; \n"
			                      "@t.func = func; \n"
								  "assert( t == func );", mod);
		if( r != asEXECUTION_FINISHED )
			TEST_FAILED;

		mod = engine->GetModule("mod", asGM_ALWAYS_CREATE);
		mod->AddScriptSection("test",
			"funcdef void CALLBACK(); \n"
			"class Test { \n"
			"  bool opEquals(CALLBACK @f) { \n"
			"    return f is func; \n"
			"  } \n"
			"  CALLBACK @func; \n"
			"} \n"
			"namespace ns { \n"
			"void func() {} \n"
			"} \n");
		r = mod->Build();
		if( r < 0 )
			TEST_FAILED;

		r = ExecuteString(engine, "Test t; \n"
								  "@t.func = ns::func; \n"
								  "assert( t == ns::func );", mod);
		if( r != asEXECUTION_FINISHED )
			TEST_FAILED;

		engine->Release();
	}

	// Test funcdefs and namespaces
	// http://www.gamedev.net/topic/644586-application-function-returning-a-funcdef-handle-crashes-when-called-in-as/
	{
		engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
		engine->SetMessageCallback(asMETHOD(COutStream, Callback), &out, asCALL_THISCALL);
		engine->RegisterGlobalFunction("void assert(bool)", asFUNCTION(Assert), asCALL_GENERIC);

		mod = engine->GetModule("mod", asGM_ALWAYS_CREATE);
		mod->AddScriptSection("test",
			"bool called = false; \n"
			"funcdef void simpleFuncDef(); \n"
			"namespace foo { \n"
			"  void simpleFunction() { called = true; } \n"
			"} \n"
			"void takeSimpleFuncDef(simpleFuncDef@ f) { f(); } \n"
			"void main() { \n"
			"  takeSimpleFuncDef(foo::simpleFunction); \n"
			"  assert( called ); \n"
			"} \n");
		r = mod->Build();
		if( r < 0 )
			TEST_FAILED;
		r = ExecuteString(engine, "main()", mod);
		if( r != asEXECUTION_FINISHED )
			TEST_FAILED;

		mod->AddScriptSection("test",
			"bool called = false; \n"
			"funcdef void simpleFuncDef();\n"
			"namespace foo {\n"
			"  void simpleFunction() { called = true; }\n"
			"}\n"
			"void main() {\n"
			"  simpleFuncDef@ bar = foo::simpleFunction;\n"
			"  bar(); \n"
			"  assert( called ); \n"
			"}\n");
		r = mod->Build();
		if( r < 0 )
			TEST_FAILED;
		r = ExecuteString(engine, "main()", mod);
		if( r != asEXECUTION_FINISHED )
			TEST_FAILED;
		engine->Release();
	}

	// Test registering global property of funcdef type
	// http://www.gamedev.net/topic/644586-application-function-returning-a-funcdef-handle-crashes-when-called-in-as/
	{
		engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
		engine->SetMessageCallback(asMETHOD(COutStream, Callback), &out, asCALL_THISCALL);

		asIScriptFunction *f = 0;
		engine->RegisterFuncdef("void myfunc()");
		r = engine->RegisterGlobalProperty("myfunc @f", &f);
		if( r < 0 )
			TEST_FAILED;

		mod = engine->GetModule("mod", asGM_ALWAYS_CREATE);
		mod->AddScriptSection("test",
			"void func() {} \n");
		mod->Build();

		r = ExecuteString(engine, "@f = func; \n", mod);
		if( r != asEXECUTION_FINISHED )
			TEST_FAILED;

		if( f == 0 )
			TEST_FAILED;
		if( strcmp(f->GetName(), "func") != 0 )
			TEST_FAILED;

		f->Release();
		f = 0;

		engine->Release();
	}

	// Test casting with funcdefs
	// http://www.gamedev.net/topic/644586-application-function-returning-a-funcdef-handle-crashes-when-called-in-as/
	{
		engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
		engine->SetMessageCallback(asMETHOD(COutStream, Callback), &out, asCALL_THISCALL);
		engine->RegisterGlobalFunction("void assert(bool)", asFUNCTION(Assert), asCALL_GENERIC);

		mod = engine->GetModule("mod", asGM_ALWAYS_CREATE);
		mod->AddScriptSection("test",
			"funcdef void myfunc1(); \n"
			"funcdef void myfunc2(); \n"
			"funcdef void myfunc3(); \n"
			"bool called = false; \n"
			"void func() { called = true; } \n"
			"void main() \n"
			"{ \n"
			"  myfunc1 @f1 = func; \n"
			"  myfunc2 @f2 = cast<myfunc2>(f1); \n" // explicit cast
			"  myfunc3 @f3 = f2; \n"                // implicit cast
			"  assert( f1 is f2 ); \n"
			"  assert( f2 is f3 ); \n"
			"  assert( f3 is func ); \n"
			"  f3(); \n"
			"  assert( called ); \n"
			"} \n");
		r = mod->Build();
		if( r < 0 )
			TEST_FAILED;

		r = ExecuteString(engine, "main()", mod);
		if( r != asEXECUTION_FINISHED )
			TEST_FAILED;

		engine->Release();
	}

	// Don't allow application to register additional behaviours to funcdefs
	// http://www.gamedev.net/topic/644586-application-function-returning-a-funcdef-handle-crashes-when-called-in-as/
	{
		engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
		engine->SetMessageCallback(asMETHOD(CBufferedOutStream, Callback), &bout, asCALL_THISCALL);
		bout.buffer = "";

		engine->RegisterObjectType("jjOBJ", 0, asOBJ_REF | asOBJ_NOCOUNT);
		engine->RegisterFuncdef("void jjBEHAVIOR(jjOBJ@)");
		engine->RegisterFuncdef("void DifferentFunctionPointer()");
		r = engine->RegisterObjectBehaviour("jjBEHAVIOR", asBEHAVE_IMPLICIT_REF_CAST, "DifferentFunctionPointer@ a()", asFUNCTION(0), asCALL_CDECL_OBJLAST);
		if( r >= 0 )
			TEST_FAILED;

		if( bout.buffer != " (0, 0) : Error   : Failed in call to function 'RegisterObjectBehaviour' with 'jjBEHAVIOR' and 'DifferentFunctionPointer@ a()' (Code: -12)\n" )
			TEST_FAILED;

		engine->Release();
	}

	// Test delegate function pointers for object methods
	{
		engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
		engine->SetMessageCallback(asMETHOD(CBufferedOutStream, Callback), &bout, asCALL_THISCALL);
		bout.buffer = "";

		RegisterScriptArray(engine, false);
		engine->RegisterGlobalFunction("void assert(bool)", asFUNCTION(Assert), asCALL_GENERIC);
		RegisterStdString(engine);

		mod = engine->GetModule("test", asGM_ALWAYS_CREATE);
		mod->AddScriptSection("test",
			"class Test { \n"
			"  void method() {} \n"
			"  int func(int) { return 0; } \n"
			"  void func() { called = true; } \n" // The compiler should pick the right overload
			"  bool called = false; \n"
			"} \n"
			"funcdef void CALLBACK(); \n"
			"void main() { \n"
			"  Test t; \n"
			"  CALLBACK @cb = CALLBACK(t.func); \n" // instanciate a delegate
			"  cb(); \n" // invoke the delegate
			"  assert( t.called ); \n"
			"} \n");
		r = mod->Build();
		if( r < 0 )
			TEST_FAILED;

		if( bout.buffer != "" )
		{
			printf("%s", bout.buffer.c_str());
			TEST_FAILED;
		}

		r = ExecuteString(engine, "main()", mod);
		if( r != asEXECUTION_FINISHED )
			TEST_FAILED;

		// Must be possible to save/load bytecode
		CBytecodeStream stream("test");
		mod->SaveByteCode(&stream);

		mod = engine->GetModule("test2", asGM_ALWAYS_CREATE);
		r = mod->LoadByteCode(&stream);
		if( r < 0 )
			TEST_FAILED;

		r = ExecuteString(engine, "main()", mod);
		if( r != asEXECUTION_FINISHED )
			TEST_FAILED;

		// Must be possible to create delegate from within class method, i.e. implicit this.method
		bout.buffer = "";
		mod->AddScriptSection("test",
			"funcdef void CALL(); \n"
			"class Test { \n"
			"  bool called = false; \n"
			"  void callMe() { called = true; } \n"
			"  CALL @GetCallback() { return CALL(callMe); } \n"
			"} \n"
			"void main() { \n"
			"  Test t; \n"
			"  CALL @cb = t.GetCallback(); \n"
			"  cb(); \n"
			"  assert( t.called ); \n"
			"} \n");
		r = mod->Build();
		if( r < 0 )
			TEST_FAILED;

		if( bout.buffer != "" )
		{
			printf("%s", bout.buffer.c_str());
			TEST_FAILED;
		}

		r = ExecuteString(engine, "main()", mod);
		if( r != asEXECUTION_FINISHED )
			TEST_FAILED;

		// A delegate to own method held as member of class must be properly resolved by gc
		mod->AddScriptSection("test",
			"funcdef void CALL(); \n"
			"class Test { \n"
			"  void call() {}; \n"
			"  CALL @c; \n"
			"} \n"
			"void main() { \n"
			"  Test t; \n"
			"  t.c = CALL(t.call); \n"
			"} \n");
		r = mod->Build();
		if( r < 0 )
			TEST_FAILED;

		engine->GarbageCollect();

		asUINT currSize, totalDestr, totalDetect;
		engine->GetGCStatistics(&currSize, &totalDestr, &totalDetect);

		r = ExecuteString(engine, "main()", mod);
		if( r != asEXECUTION_FINISHED )
			TEST_FAILED;

		engine->GarbageCollect();

		asUINT currSize2, totalDestr2, totalDetect2;
		engine->GetGCStatistics(&currSize2, &totalDestr2, &totalDetect2);

		if( totalDetect2 == totalDetect )
			TEST_FAILED;

		// Must be possible to call delegate from application
		mod->AddScriptSection("test",
			"funcdef void CALL(); \n"
			"class Test { \n"
			"  bool called = false; \n"
			"  void call() { called = true; } \n"
			"} \n"
			"Test t; \n"
			"CALL @callback = CALL(t.call); \n");
		r = mod->Build();
		if( r != asEXECUTION_FINISHED )
			TEST_FAILED;

		int idx = mod->GetGlobalVarIndexByDecl("CALL @callback");
		if( idx < 0 )
			TEST_FAILED;

		asIScriptFunction *callback = *(asIScriptFunction**)mod->GetAddressOfGlobalVar(idx);
		if( callback == 0 )
			TEST_FAILED;
		if( callback->GetFuncType() != asFUNC_DELEGATE )
			TEST_FAILED;
		if( callback->GetDelegateObject() == 0 )
			TEST_FAILED;
		if( std::string(callback->GetDelegateFunction()->GetDeclaration()) != "void Test::call()" )
			TEST_FAILED;

		ctx = engine->CreateContext();
		ctx->Prepare(callback);
		r = ctx->Execute();
		if( r != asEXECUTION_FINISHED )
			TEST_FAILED;
		ctx->Release();

		r = ExecuteString(engine, "assert( t.called );", mod);
		if( r != asEXECUTION_FINISHED )
			TEST_FAILED;

		// Must be possible to create the delegate from the application
		asIScriptObject *obj = (asIScriptObject*)mod->GetAddressOfGlobalVar(mod->GetGlobalVarIndexByDecl("Test t"));
		asIScriptFunction *func = obj->GetObjectType()->GetMethodByName("call");
		asIScriptFunction *delegate = engine->CreateDelegate(func, obj);
		if( delegate == 0 )
			TEST_FAILED;
		delegate->Release();

		// Must be possible to create delegate for registered type too
		mod->AddScriptSection("test",
			"funcdef bool EMPTY(); \n"
			"void main() { \n"
			"  array<int> a; \n"
			"  EMPTY @empty = EMPTY(a.isEmpty); \n"
			"  assert( empty() == true ); \n"
			"  a.insertLast(42); \n"
			"  assert( empty() == false ); \n"
			"} \n");
		r = mod->Build();
		if( r < 0 )
			TEST_FAILED;

		r = ExecuteString(engine, "main()", mod);
		if( r != asEXECUTION_FINISHED )
			TEST_FAILED;

		// Must not be possible to create delegate with const object and non-const method
		bout.buffer = "";
		mod->AddScriptSection("test",
			"funcdef void F(); \n"
			"class Test { \n"
			"  void f() {} \n"
			"} \n"
			"void main() { \n"
			" const Test @t; \n"
			" F @f = F(t.f); \n" // t is read-only, so this delegate must not be allowed
			"} \n");
		r = mod->Build();
		if( r >= 0 )
			TEST_FAILED;

		// TODO: Error message should be better, so it is understood that the error is because of const object
		if( bout.buffer != "test (5, 1) : Info    : Compiling void main()\n"
		                   "test (7, 9) : Error   : No matching signatures to 'void F()'\n" )
		{
			printf("%s", bout.buffer.c_str());
			TEST_FAILED;
		}

		// Must not be possible to create delegates for non-reference types
		bout.buffer = "";
		mod->AddScriptSection("test",
			"funcdef bool CB(); \n"
			"string s; \n"
			"CB @cb = CB(s.isEmpty); \n");
		r = mod->Build();
		if( r >= 0 )
			TEST_FAILED;

		if( bout.buffer != "test (3, 5) : Info    : Compiling CB@ cb\n"
		                   "test (3, 10) : Error   : Can't create delegate for types that do not support handles\n" )
		{
			printf("%s", bout.buffer.c_str());
			TEST_FAILED;
		}

		engine->Release();
	}

	// Test ordinary function pointers for global functions
	{
		engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
		engine->RegisterGlobalFunction("void assert(bool)", asFUNCTION(Assert), asCALL_GENERIC);
		engine->SetMessageCallback(asMETHOD(COutStream, Callback), &out, asCALL_THISCALL);
		mod = engine->GetModule(0, asGM_ALWAYS_CREATE);

		// Test the declaration of new function signatures
		script = "funcdef void functype();\n"
		// It must be possible to declare variables of the funcdef type
				 "functype @myFunc = null;\n"
		// It must be possible to initialize the function pointer directly
				 "functype @myFunc1 = @func;\n"
		 		 "void func() { called = true; }\n"
				 "bool called = false;\n"
		// It must be possible to compare the function pointer with another
				 "void main() { \n"
				 "  assert( myFunc1 !is null ); \n"
				 "  assert( myFunc1 is func ); \n"
		// It must be possible to call a function through the function pointer
	    		 "  myFunc1(); \n"
				 "  assert( called ); \n"
		// Local function pointer variables are also possible
				 "  functype @myFunc2 = @func;\n"
				 "} \n";
		mod->AddScriptSection("script", script);
		r = mod->Build();
		if( r != 0 )
			TEST_FAILED;
		r = ExecuteString(engine, "main()", mod);
		if( r != asEXECUTION_FINISHED )
			TEST_FAILED;

		// It must be possible to save the byte code with function handles
		CBytecodeStream bytecode(__FILE__"1");
		mod->SaveByteCode(&bytecode);
		{
			asIScriptModule *mod2 = engine->GetModule("mod2", asGM_ALWAYS_CREATE);
			mod2->LoadByteCode(&bytecode);
			r = ExecuteString(engine, "main()", mod2);
			if( r != asEXECUTION_FINISHED )
				TEST_FAILED;
		}

		// Test function pointers as members of classes. It should be possible to call the function
		// from within a class method. It should also be possible to call it from outside through the . operator.
		script = "funcdef void FUNC();       \n"
				 "class CMyObj               \n"
				 "{                          \n"
				 "  CMyObj() { @f = @func; } \n"
				 "  FUNC@ f;                 \n"
				 "  void test()              \n"
				 "  {                        \n"
				 "    this.f();              \n"
				 "    f();                   \n"
				 "    CMyObj o;              \n"
				 "    o.f();                 \n"
				 "    main();                \n"
				 "    assert( called == 4 ); \n"
				 "  }                        \n"
				 "}                          \n"
				 "void main()                \n"
				 "{                          \n"
				 "  CMyObj o;                \n"
				 "  o.f();                   \n"
				 "}                          \n"
				 "int called = 0;            \n"
				 "void func() { called++; }  \n";
		mod->AddScriptSection("script", script);
		r = mod->Build();
		if( r < 0 )
			TEST_FAILED;
		asIScriptContext *ctx = engine->CreateContext();
		r = ExecuteString(engine, "CMyObj o; o.test();", mod, ctx);
		if( r != asEXECUTION_FINISHED )
		{
			TEST_FAILED;
			if( r == asEXECUTION_EXCEPTION )
				PrintException(ctx);
		}
		ctx->Release();

		// It must not be possible to declare a non-handle variable of the funcdef type
		engine->SetMessageCallback(asMETHOD(CBufferedOutStream, Callback), &bout, asCALL_THISCALL);
		bout.buffer = "";
		script = "funcdef void functype();\n"
				 "functype myFunc;\n";
		mod->AddScriptSection("script", script);
		r = mod->Build();
		if( r >= 0 )
			TEST_FAILED;
		if( bout.buffer != "script (2, 1) : Error   : Data type can't be 'functype'\n"
						   "script (2, 10) : Info    : Compiling functype myFunc\n"
						   "script (2, 10) : Error   : No default constructor for object of type 'functype'.\n" )
		{
			printf("%s", bout.buffer.c_str());
			TEST_FAILED;
		}

		// It must not be possible to invoke the funcdef
		bout.buffer = "";
		script = "funcdef void functype();\n"
				 "void func() { functype(); } \n";
		mod->AddScriptSection("script", script);
		r = mod->Build();
		if( r >= 0 )
			TEST_FAILED;
		if( bout.buffer != "script (2, 1) : Info    : Compiling void func()\n"
						   "script (2, 15) : Error   : No matching signatures to 'functype()'\n" )
		{
			printf("%s", bout.buffer.c_str());
			TEST_FAILED;
		}

		// Test that a funcdef can't have the same name as other global entities
		bout.buffer = "";
		script = "funcdef void test();  \n"
				 "int test; \n";
		mod->AddScriptSection("script", script);
		r = mod->Build();
		if( r >= 0 )
			TEST_FAILED;
		if( bout.buffer != "script (2, 5) : Error   : Name conflict. 'test' is a funcdef.\n" )
		{
			printf("%s", bout.buffer.c_str());
			TEST_FAILED;
		}

		// It is possible to take the address of class methods, but not to assign to funcdef variable
		bout.buffer = "";
		script = 
			"funcdef void F(); \n"
		    "class t { \n"
			"  void func() { \n"
			"    @func; \n" // TODO: Should warn about expression that doesn't do anything
			"    F @f = @func; \n"
            "    } \n"
			"} \n";
		mod->AddScriptSection("script", script);
		r = mod->Build();
		if( r >= 0 )
			TEST_FAILED;
		// TODO: The error message should be better
		if( bout.buffer != "script (3, 3) : Info    : Compiling void t::func()\n"
		                   "script (5, 12) : Error   : Can't implicitly convert from 't' to 'F@&'.\n" )
		{
			printf("%s", bout.buffer.c_str());
			TEST_FAILED;
		}

		// A more complex sample
		bout.buffer = "";
		script = 
			"funcdef bool CALLBACK(int, int); \n"
			"funcdef bool CALLBACK2(CALLBACK @); \n"
			"void main() \n"
			"{ \n"
			"	CALLBACK @func = @myCompare; \n"
			"	CALLBACK2 @func2 = @test; \n"
			"	func2(func); \n"
			"} \n"
			"bool test(CALLBACK @func) \n"
			"{ \n"
			"	return func(1, 2); \n"
			"} \n"
			"bool myCompare(int a, int b) \n"
			"{ \n"
			"	return a > b; \n"
			"} \n";
		mod->AddScriptSection("script", script);
		r = mod->Build();
		if( r < 0 )
			TEST_FAILED;
		if( bout.buffer != "" )
		{
			printf("%s", bout.buffer.c_str());
			TEST_FAILED;
		}
		r = ExecuteString(engine, "main()", mod);
		if( r != asEXECUTION_FINISHED )
			TEST_FAILED;

		// It must be possible to register the function signature from the application
		r = engine->RegisterFuncdef("void AppCallback()");
		if( r < 0 )
			TEST_FAILED;

		r = engine->RegisterGlobalFunction("void ReceiveFuncPtr(AppCallback @)", asFUNCTION(ReceiveFuncPtr), asCALL_CDECL); assert( r >= 0 );

		// It must be possible to use the registered funcdef
		// It must be possible to receive a function pointer for a registered func def
		bout.buffer = "";
		script = 
			"void main() \n"
			"{ \n"
			"	AppCallback @func = @test; \n"
			"   func(); \n"
			"   ReceiveFuncPtr(func); \n"
			"} \n"
			"void test() \n"
			"{ \n"
			"} \n";
		mod->AddScriptSection("script", script);
		r = mod->Build();
		if( r < 0 )
			TEST_FAILED;
		if( bout.buffer != "" )
		{
			printf("%s", bout.buffer.c_str());
			TEST_FAILED;
		}

		r = ExecuteString(engine, "main()", mod);
		if( r != asEXECUTION_FINISHED )
			TEST_FAILED;

		if( !receivedFuncPtrIsOK )
			TEST_FAILED;

		mod->SaveByteCode(&bytecode);
		{
			receivedFuncPtrIsOK = false;
			asIScriptModule *mod2 = engine->GetModule("mod2", asGM_ALWAYS_CREATE);
			mod2->LoadByteCode(&bytecode);
			r = ExecuteString(engine, "main()", mod2);
			if( r != asEXECUTION_FINISHED )
				TEST_FAILED;

			if( !receivedFuncPtrIsOK )
				TEST_FAILED;
		}

		// The compiler should be able to determine the right function overload
		// by the destination of the function pointer
		bout.buffer = "";
		mod->AddScriptSection("test",
		         "funcdef void f(); \n"
				 "f @fp = @func;  \n"
				 "bool called = false; \n"
				 "void func() { called = true; }    \n"
				 "void func(int) {} \n");
		r = mod->Build();
		if( r < 0 )
			TEST_FAILED;
		if( bout.buffer != "" )
		{
			printf("%s", bout.buffer.c_str());
			TEST_FAILED;
		}
		r = ExecuteString(engine, "fp(); assert( called );", mod);
		if( r != asEXECUTION_FINISHED )
			TEST_FAILED;

		//----------------------------------------------------------
		// TODO: Future improvements below

		// If the function referred to when taking a function pointer is removed from the module,
		// the code must not be invalidated. After removing func() from the module, it must still 
		// be possible to execute func2()
		script = "funcdef void FUNC(); \n"
				 "void func() {} \n";
				 "void func2() { FUNC@ f = @func; f(); } \n";

		// Test that the function in a function pointer isn't released while the function 
		// is being executed, even though the function pointer itself is cleared
		script = "DYNFUNC@ funcPtr;        \n"
				 "funcdef void DYNFUNC(); \n"
				 "@funcPtr = @CompileDynFunc('void func() { @funcPtr = null; }'); \n";

		// Test that it is possible to declare the function signatures out of order
		// This also tests the circular reference between the function signatures
		script = "funcdef void f1(f2@) \n"
				 "funcdef void f2(f1@) \n";

		// It must be possible to identify a function handle type from the type id

		// It must be possible enumerate the function definitions in the module, 
		// and to enumerate the parameters the function accepts

		// A funcdef defined in multiple modules must share the id and signature so that a function implemented 
		// in one module can be called from another module by storing the handle in the funcdef variable

		// An interface that takes a funcdef as parameter must still have its typeid shared if the funcdef can also be shared
		// If the funcdef takes an interface as parameter, it must still be shared

		// Must have a generic function pointer that can store any signature. The function pointer
		// can then be dynamically cast to the correct function signature so that the function it points
		// to can be invoked.

		engine->Release();
	}

	// Test function pointers with virtual property accessors
	// http://www.gamedev.net/topic/639243-funcdef-inside-shared-interface-interface-already-implement-warning/
	{
		engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
		engine->SetMessageCallback(asMETHOD(COutStream,Callback), &out, asCALL_THISCALL);

		engine->RegisterGlobalFunction("void assert(bool)", asFUNCTION(Assert), asCALL_GENERIC);

		mod = engine->GetModule(0, asGM_ALWAYS_CREATE);
		mod->AddScriptSection("test",
			"funcdef void funcdef1( ifuncdef1_1& i ); \n"
			"shared interface ifuncdef1_1 \n"
			"{ \n"
			"    ifuncdef1_2@ events { get; set; } \n"
			"    void crashme(); \n"
			"} \n"
			"shared interface ifuncdef1_2 \n"
			"{ \n"
			"    funcdef1@ f { get; set; } \n"
			"} \n"
			"class cfuncdef1_1 : ifuncdef1_1 \n"
			"{ \n"
			"    ifuncdef1_2@ _events_; \n"
			"    cfuncdef1_1() { @this._events_ = cfuncdef1_2(); } \n"
			"    ifuncdef1_2@ get_events() { return( this._events_ ); } \n"
			"    void set_events( ifuncdef1_2@ events ) { @this._events_ = events; } \n"
			"    void crashme() \n"
			"    { \n"
			"         if( @this._events_ != null && @this._events_.f != null ) \n"
			"         { \n"
			"            this.events.f( this ); \n"
//			"            this.get_events().get_f()( this ); \n" // This should produce the same bytecode as the above
			"         } \n"
			"    } \n"
			"} \n"
			"class cfuncdef1_2 : ifuncdef1_2 \n"
			"{ \n"
			"    funcdef1@ ff; \n"
			"    cfuncdef1_2() { @ff = null; } \n"
			"    funcdef1@ get_f() { return( @this.ff ); } \n"
			"    void set_f( funcdef1@ _f ) { @this.ff = _f; } \n"
			"} \n"
			"void start() \n"
			"{ \n"
			"    ifuncdef1_1@ i = cfuncdef1_1(); \n"
			"    i.events.f = end; \n" // TODO: Shouldn't this give an error? It's attempting to do an value assignment to a function pointer
			"    i.crashme(); \n"
			"} \n"
			"bool called = false; \n"
			"void end( ifuncdef1_1& i  ) \n"
			"{ \n"
			"    called = true; \n"
			"} \n");

		r = mod->Build(); 
		if( r < 0 )
			TEST_FAILED;

		ctx = engine->CreateContext();
		r = ExecuteString(engine, "start(); assert( called );", mod, ctx);
		if( r != asEXECUTION_FINISHED )
			TEST_FAILED;
		if( r == asEXECUTION_EXCEPTION )
			PrintException(ctx, true);
		ctx->Release();

		CBytecodeStream stream(__FILE__"1");
		
		r = mod->SaveByteCode(&stream);
		if( r < 0 )
			TEST_FAILED;
		
		engine->Release();

		// Load the bytecode 
		engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
		engine->SetMessageCallback(asMETHOD(COutStream,Callback), &out, asCALL_THISCALL);
		engine->RegisterGlobalFunction("void assert(bool)", asFUNCTION(Assert), asCALL_GENERIC);

		stream.Restart();
		mod = engine->GetModule("A", asGM_ALWAYS_CREATE);
		r = mod->LoadByteCode(&stream);
		if( r < 0 )
			TEST_FAILED;

		ctx = engine->CreateContext();
		r = ExecuteString(engine, "start(); assert( called );", mod);
		if( r != asEXECUTION_FINISHED )
			TEST_FAILED;
		ctx->Release();

		stream.Restart();
		mod = engine->GetModule("B", asGM_ALWAYS_CREATE);
		r = mod->LoadByteCode(&stream);
		if( r < 0 )
			TEST_FAILED;

		ctx = engine->CreateContext();
		r = ExecuteString(engine, "start(); assert( called );", mod);
		if( r != asEXECUTION_FINISHED )
			TEST_FAILED;
		ctx->Release();

		engine->Release();
	}

	// Test clean up with registered function definitions
	{
		engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
		RegisterScriptString(engine);
		r = engine->RegisterFuncdef("void MSG_NOTIFY_CB(const string& strCommand, const string& strTarget)"); assert(r>=0);

		engine->Release();
	}

	// Test registering function pointer as property
	{
		engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
		r = engine->RegisterFuncdef("void fptr()");
		r = engine->RegisterGlobalProperty("fptr f", 0);
		if( r >= 0 ) TEST_FAILED;
		engine->RegisterObjectType("obj", 0, asOBJ_REF);
		r = engine->RegisterObjectProperty("obj", "fptr f", 0);
		if( r >= 0 ) TEST_FAILED;

		engine->Release();
	}

	// Test passing handle to function pointer
	{
		engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
		engine->RegisterGlobalFunction("void assert(bool)", asFUNCTION(Assert), asCALL_GENERIC);

		engine->SetMessageCallback(asMETHOD(COutStream, Callback), &out, asCALL_THISCALL);
		mod = engine->GetModule(0, asGM_ALWAYS_CREATE);

		mod->AddScriptSection("script",
			"class CTempObj             \n"
			"{                          \n"
			"  int Temp;                \n"
			"}                          \n"
			"funcdef void FUNC2(CTempObj@);\n"
			"class CMyObj               \n"
			"{                          \n"
			"  CMyObj() { @f2= @func2; }\n"
			"  FUNC2@ f2;               \n"
			"}                          \n"
			"void main()                \n"
			"{                          \n"
			"  CMyObj o;                \n"
			"  CTempObj t;              \n"
			"  o.f2(t);                 \n"
			"  assert( called == 1 );   \n"
			"}                          \n"
			"int called = 0;            \n"
			"void func2(CTempObj@ Obj)  \n"
			"{ called++; }              \n");

		r = mod->Build();
		if( r < 0 )
			TEST_FAILED;

		r = ExecuteString(engine, "main()", mod);
		if( r != asEXECUTION_FINISHED )
			TEST_FAILED;

		engine->Release();
	}

	// Test out of order declaration with function pointers
	{
		engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
		engine->SetMessageCallback(asMETHOD(COutStream, Callback), &out, asCALL_THISCALL);
		mod = engine->GetModule(0, asGM_ALWAYS_CREATE);

		mod->AddScriptSection("script",
			"funcdef void FUNC2(CTempObj@);\n"
			"class CTempObj {}             \n");

		r = mod->Build();
		if( r < 0 )
			TEST_FAILED;

		engine->Release();
	}

	// It must be possible calling system functions through pointers too
	{
		asIScriptEngine *engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);

		engine->RegisterFuncdef("bool fun(bool)");
		engine->RegisterGlobalFunction("bool assert(bool)", asFUNCTION(Assert), asCALL_GENERIC);

		r = ExecuteString(engine, "fun @f = assert; f(true);");
		if( r != asEXECUTION_FINISHED )
			TEST_FAILED;

		engine->Release();
	}

	// It should be possible to call functions through function pointers returned by an expression
	// http://www.gamedev.net/topic/627386-bug-with-parsing-of-callable-expressions/
	{
		asIScriptEngine *engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
		engine->SetMessageCallback(asMETHOD(COutStream, Callback), &out, asCALL_THISCALL);
		RegisterScriptArray(engine, false);
		engine->RegisterGlobalFunction("void assert(bool)", asFUNCTION(Assert), asCALL_GENERIC);

		mod = engine->GetModule(0, asGM_ALWAYS_CREATE);

		mod->AddScriptSection("Test",
			"funcdef void F(int); \n"
			"array<F@> arr(1); \n"
			"F@ g()            \n"
			"{                 \n"
			"  return test;    \n"
			"}                 \n"
			"void test(int a)  \n"
			"{                 \n"
			"  assert(a == 42); \n"
			"  called++;       \n"
			"}                 \n"
			"int called = 0;   \n"
			"void f()          \n"
			"{                 \n"
			"  @arr[0] = test; \n"
			"  arr[0](42);     \n"
			"  g()(42);        \n"
			"  F@ p; \n"
			"  (@p = arr[0])(42);     \n"
			"  (@p = g())(42);        \n"
			"}                        \n");

	//	engine->SetEngineProperty(asEP_OPTIMIZE_BYTECODE, false);
		r = mod->Build();
		if( r < 0 )
			TEST_FAILED;

		r = ExecuteString(engine, "f()", mod);
		if( r != asEXECUTION_FINISHED )
			TEST_FAILED;

		int idx = mod->GetGlobalVarIndexByName("called");
		int *called = (int*)mod->GetAddressOfGlobalVar(idx);
		if( *called != 4 )
			TEST_FAILED;

		engine->Release();
	}

	// Global function pointers must not overload local class methods
	// Local variables take precedence over class methods
	// http://www.gamedev.net/topic/626746-function-call-operators-in-the-future/
	{
		const char *script = 
			"funcdef void FUNC(); \n"
			"FUNC @func; \n"
			"class Class \n"
			"{ \n"
			"  void func() {} \n"
			"  void method() \n"
			"  { \n"
			"    func(); \n"       // Should call Class::func()
			"  } \n"
			"  void func2() {} \n"
			"  void method2() \n"
			"  { \n"
			"    FUNC @func2; \n"
			"    func2(); \n"      // Should call variable func2
			"  } \n"
			"} \n";

		engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);

		engine->SetMessageCallback(asMETHOD(COutStream, Callback), &out, asCALL_THISCALL);

		mod = engine->GetModule("test", asGM_ALWAYS_CREATE);
		mod->AddScriptSection("test", script);
		r = mod->Build();
		if( r < 0 )
			TEST_FAILED;

		r = ExecuteString(engine, "Class c; c.method();", mod);
		if( r != asEXECUTION_FINISHED )
			TEST_FAILED;

		r = ExecuteString(engine, "Class c; c.method2();", mod);
		if( r != asEXECUTION_EXCEPTION )
			TEST_FAILED;

		engine->Release();
	}

	// Success
 	return fail;
}
void Test()
{
	printf("---------------------------------------------\n");
	printf("%s\n\n", TESTNAME);
	printf("AngelScript 2.30.0 WIP:   4.14 secs\n");

 	asIScriptEngine *engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);

	COutStream out;
	engine->SetMessageCallback(asMETHOD(COutStream,Callback), &out, asCALL_THISCALL);

	RegisterScriptArray(engine, true);
	RegisterStdString(engine);

	////////////////////////////////////////////
	printf("\nGenerating...\n");

#ifdef _DEBUG
	const int numLines = 40;
#else
	const int numLines = 40000;
#endif

	string script;
	script.reserve(strlen(scriptBegin) + numLines*(strlen(scriptMiddle)+5) + strlen(scriptEnd));
	script += scriptBegin;
	for( int n = 0; n < numLines; n++ )
	{
		char buf[500];
		sprintf(buf, scriptMiddle, n);
		script += buf;
	}
	script += scriptEnd;

	////////////////////////////////////////////
	printf("\nBuilding...\n");

	double time = GetSystemTimer();

	asIScriptModule *mod = engine->GetModule(0, asGM_ALWAYS_CREATE);
	mod->AddScriptSection(TESTNAME, script.c_str(), script.size(), 0);
	int r = mod->Build();

	time = GetSystemTimer() - time;

	if( r != 0 )
		printf("Build failed\n", TESTNAME);
	else
		printf("Time = %f secs\n", time);

	////////////////////////////////////////////
	printf("\nSaving...\n");

	time = GetSystemTimer();

	CBytecodeStream stream("");
	mod->SaveByteCode(&stream);

	time = GetSystemTimer() - time;
	printf("Time = %f secs\n", time);
	printf("Size = %d\n", int(stream.buffer.size()));

	////////////////////////////////////////////
	printf("\nLoading...\n");

	time = GetSystemTimer();

	asIScriptModule *mod2 = engine->GetModule(0, asGM_ALWAYS_CREATE);
	mod2->LoadByteCode(&stream);

	time = GetSystemTimer() - time;
	printf("Time = %f secs\n", time);

	engine->Release();
}
void Test()
{
	printf("---------------------------------------------\n");
	printf("%s\n\n", TESTNAME);
	printf("AngelScript 2.25.1 WIP 0: 0.28 secs\n");
	printf("AngelScript 2.25.1 WIP 1: 0.28 secs (local bytecode optimizations)\n");
	printf("AngelScript 2.25.1 WIP 2: 0.27 secs (reversed order)\n");


 	asIScriptEngine *engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);

	COutStream out;
	engine->SetMessageCallback(asMETHOD(COutStream,Callback), &out, asCALL_THISCALL);

	RegisterScriptArray(engine, true);
	RegisterStdString(engine);

	////////////////////////////////////////////
	printf("\nGenerating...\n");

	const int numFuncs = 2000;
	const int numCalls = 20000;

	string script;
	script.reserve(strlen(scriptBegin) + numFuncs*(strlen(scriptFuncDecl)+5) + numCalls*(strlen(scriptMiddle)+5) + strlen(scriptEnd));
	for( int a = 0; a < numFuncs; a++ )
	{
		char buf[500];
		sprintf(buf, scriptFuncDecl, a);
		script += buf;
	}
	script += scriptBegin;
	for( int n = 0; n < numCalls; n++ )
	{
		char buf[500];
		sprintf(buf, scriptMiddle, n%numFuncs);
		script += buf;
	}
	script += scriptEnd;

	////////////////////////////////////////////
	printf("\nBuilding...\n");

	double time = GetSystemTimer();

	asIScriptModule *mod = engine->GetModule(0, asGM_ALWAYS_CREATE);
	mod->AddScriptSection(TESTNAME, script.c_str(), script.size(), 0);
	int r = mod->Build();

	time = GetSystemTimer() - time;

	if( r != 0 )
		printf("Build failed\n", TESTNAME);
	else
		printf("Time = %f secs\n", time);

	////////////////////////////////////////////
	printf("\nSaving...\n");

	time = GetSystemTimer();

	CBytecodeStream stream("");
	mod->SaveByteCode(&stream);

	time = GetSystemTimer() - time;
	printf("Time = %f secs\n", time);
	printf("Size = %d\n", int(stream.buffer.size()));

	////////////////////////////////////////////
	printf("\nLoading...\n");

	time = GetSystemTimer();

	asIScriptModule *mod2 = engine->GetModule(0, asGM_ALWAYS_CREATE);
	mod2->LoadByteCode(&stream);

	time = GetSystemTimer() - time;
	printf("Time = %f secs\n", time);

	engine->Release();
}
Example #25
0
bool Test()
{
	bool fail = false;

	if( !fail ) fail = Test2();

	int r;

 	asIScriptEngine *engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);

	COutStream out;
	CBufferedOutStream bout;
	engine->SetMessageCallback(asMETHOD(COutStream,Callback), &out, asCALL_THISCALL);

	RegisterScriptString_Generic(engine);

	engine->RegisterGlobalFunction("void Assert(bool)", asFUNCTION(Assert), asCALL_GENERIC);

	// Register an interface from the application
	r = engine->RegisterInterface("appintf"); assert( r >= 0 );
	r = engine->RegisterInterfaceMethod("appintf", "void test()"); assert( r >= 0 );

	// Test working example
	asIScriptModule *mod = engine->GetModule(0, asGM_ALWAYS_CREATE);
	mod->AddScriptSection(TESTNAME, script1, strlen(script1), 0);
	r = mod->Build();
	if( r < 0 ) TEST_FAILED;

	r = ExecuteString(engine, "test()", mod);
	if( r != asEXECUTION_FINISHED ) TEST_FAILED;

	// Test calling the interface method from the application
	int typeId = engine->GetModule(0)->GetTypeIdByDecl("myclass");
	asIScriptObject *obj = (asIScriptObject*)engine->CreateScriptObject(typeId);

	int intfTypeId = engine->GetModule(0)->GetTypeIdByDecl("myintf");
	asIObjectType *type = engine->GetObjectTypeById(intfTypeId);
	asIScriptFunction *func = type->GetMethodByDecl("void test()");
	asIScriptContext *ctx = engine->CreateContext();
	r = ctx->Prepare(func);
	if( r < 0 ) TEST_FAILED;
	ctx->SetObject(obj);
	ctx->Execute();
	if( r != asEXECUTION_FINISHED )
		TEST_FAILED;

	intfTypeId = engine->GetTypeIdByDecl("appintf");
	type = engine->GetObjectTypeById(intfTypeId);
	func = type->GetMethodByDecl("void test()");

	r = ctx->Prepare(func);
	if( r < 0 ) TEST_FAILED;
	ctx->SetObject(obj);
	ctx->Execute();
	if( r != asEXECUTION_FINISHED )
		TEST_FAILED;

	if( ctx ) ctx->Release();
	if( obj ) obj->Release();

	// Test class that don't implement all functions of the interface.
	// Test instanciating an interface. Shouldn't work.
	// Test that classes don't implement the same interface twice
	// Try copying an interface variable to another. Shouldn't work.
	// Test implicit conversion from class to interface that is not being implemented. Should give compiler error
	// Test implicit conversion from interface to class. Should give compiler error.
	engine->SetMessageCallback(asMETHOD(CBufferedOutStream,Callback), &bout, asCALL_THISCALL);
	mod = engine->GetModule(0, asGM_ALWAYS_CREATE);
	mod->AddScriptSection(TESTNAME, script2, strlen(script2), 0);
	r = mod->Build();
	if( r >= 0 ) TEST_FAILED;
	if( bout.buffer != "TestInterface (5, 23) : Warning : The interface 'intf' is already implemented\n"
					   "TestInterface (5, 7) : Error   : Missing implementation of 'void intf::test()'\n"
					   "TestInterface (9, 1) : Info    : Compiling void test(intf&inout)\n"
					   "TestInterface (11, 9) : Error   : Data type can't be 'intf'\n"
					   "TestInterface (13, 6) : Error   : There is no copy operator for the type 'intf' available.\n"
					   "TestInterface (15, 16) : Error   : Can't implicitly convert from 'myclass&' to 'nointf@&'.\n"
					   "TestInterface (16, 16) : Error   : Can't implicitly convert from 'intf@&' to 'myclass@&'.\n" )
	{
		printf("%s", bout.buffer.c_str());
		TEST_FAILED;
	}

	engine->Release();

	// Test cast for both temporary handle and non-temporary handle
	{
		const char *script = 
			"interface ScriptLogic {} \n"
			"class PlayerLogic : ScriptLogic {} \n"
			"ScriptLogic @getScriptObject() { return PlayerLogic(); } \n";

		engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
		engine->SetMessageCallback(asMETHOD(COutStream,Callback), &out, asCALL_THISCALL);
		RegisterStdString(engine);
		mod = engine->GetModule(0, asGM_ALWAYS_CREATE);
		mod->AddScriptSection(TESTNAME, script);
		r = mod->Build();
		if( r < 0 ) TEST_FAILED;

		// Non-temporary handle
		r = ExecuteString(engine, "ScriptLogic @c = getScriptObject(); cast<PlayerLogic>(c);", mod);
		if( r != asEXECUTION_FINISHED )
			TEST_FAILED;

		// Temporary handle
		r = ExecuteString(engine, "cast<PlayerLogic>(getScriptObject());", mod);
		if( r != asEXECUTION_FINISHED )
			TEST_FAILED;

		engine->Release();			
	}

	// It should be possible to inherit the implementation of an interface method
	{
		const char *script = 
			"interface I { void method(); } \n"
			"class B { void method() {} } \n"
			"class D : B, I {} \n"
			"D d; \n";

		engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
		engine->SetMessageCallback(asMETHOD(COutStream,Callback), &out, asCALL_THISCALL);
		mod = engine->GetModule(0, asGM_ALWAYS_CREATE);
		mod->AddScriptSection(TESTNAME, script);
		r = mod->Build();
		if( r < 0 ) TEST_FAILED;

		engine->Release();			
	}

	// Allow script declared interfaces to inherit from other interfaces
	{
		engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
		engine->SetMessageCallback(asMETHOD(CBufferedOutStream,Callback), &bout, asCALL_THISCALL);
		mod = engine->GetModule(0, asGM_ALWAYS_CREATE);

		const char *script = 
			"interface A { void a(); } \n"
			"interface B : A { void b(); } \n"
			"class C : B {} \n"; // Must implement both a() and b()

		bout.buffer = "";
		mod->AddScriptSection(TESTNAME, script);
		r = mod->Build();
		if( r >= 0 ) TEST_FAILED;
		if( bout.buffer != "TestInterface (3, 7) : Error   : Missing implementation of 'void B::b()'\n"
		                   "TestInterface (3, 7) : Error   : Missing implementation of 'void A::a()'\n" )
		{
			printf("%s", bout.buffer.c_str());
			TEST_FAILED;
		}

		// Don't allow shared interface to implement non-shared interface
		script = 
			"interface A {} \n"
			"shared interface B : A {} \n";

		bout.buffer = "";
		mod->AddScriptSection(TESTNAME, script);
		r = mod->Build();
		if( r >= 0 ) TEST_FAILED;
		if( bout.buffer != "TestInterface (2, 22) : Error   : Shared type cannot implement non-shared interface 'A'\n" )
		{
			printf("%s", bout.buffer.c_str());
			TEST_FAILED;
		}

		// Implicit casts to an inherited interface should work
		script = 
			"interface A {} \n"
			"interface B : A {} \n"
			"void func() \n"
			"{ \n"
			"  A@ a; B@ b; \n"
			"  @a = b; \n"
			"} \n";

		bout.buffer = "";
		mod->AddScriptSection(TESTNAME, script);
		r = mod->Build();
		if( r < 0 ) TEST_FAILED;
		if( bout.buffer != "" )
		{
			printf("%s", bout.buffer.c_str());
			TEST_FAILED;
		}

		// Don't allow circular inheritance
		script = 
			"interface A : C {} \n"
			"interface B : A {} \n"
			"interface C : B {} \n";
		bout.buffer = "";
		mod->AddScriptSection(TESTNAME, script);
		r = mod->Build();
		if( r >= 0 ) TEST_FAILED;
		if( bout.buffer != "TestInterface (3, 15) : Error   : Can't implement itself, or another interface that implements this interface\n" )
		{
			printf("%s", bout.buffer.c_str());
			TEST_FAILED;
		}

		engine->Release();
	}

	// Success
	return fail;
}
Example #26
0
bool Test()
{
	bool fail = false;
	int r;
	COutStream out;

	const char *script = 
		"void Test() {} \n"
		"class A : I { void i(float) {} void a(int) {} float f; } \n"
		"class B : A { B(int) {} } \n"
		"interface I { void i(float); } \n"
		"float a; \n"
		"const float aConst = 3.141592f; \n"
		"I@ i; \n"
		"enum E { eval = 0, eval2 = 2 } \n"
		"E e; \n"
		"typedef float real; \n"
		"real pi = 3.14f; \n"
		"import void ImpFunc() from \"mod\"; \n";

	asIScriptEngine *engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
	engine->SetMessageCallback(asMETHOD(COutStream, Callback), &out, asCALL_THISCALL);

	RegisterStdString(engine);

	float f;
	engine->RegisterTypedef("myFloat", "float");
	engine->RegisterGlobalProperty("myFloat f", &f);
	engine->RegisterGlobalProperty("const float myConst", &f);
	engine->RegisterGlobalFunction("void func(int &in)", asFUNCTION(0), asCALL_GENERIC);

	engine->BeginConfigGroup("test");
	engine->RegisterGlobalFunction("void func2()", asFUNCTION(0), asCALL_GENERIC);
	engine->EndConfigGroup();

	engine->RegisterEnum("myEnum");
	engine->RegisterEnumValue("myEnum", "value1", 1);
	engine->RegisterEnumValue("myEnum", "value2", 2);

	engine->RegisterFuncdef("void Callback(int a, int b)");

	engine->RegisterInterface("MyIntf");
	engine->RegisterInterfaceMethod("MyIntf", "void func() const");

	asIScriptModule *mod = engine->GetModule(0, asGM_ALWAYS_CREATE);

	mod->AddScriptSection("script", script);
	r = mod->Build();
	if( r < 0 )
		fail = true;

	WriteConfigToFile(engine, "AS_DEBUG/config.txt");

	DumpModule(mod);

	// Save/Restore the bytecode and then test again for the loaded bytecode
	CBytecodeStream stream(__FILE__"1");
	mod->SaveByteCode(&stream);

	mod = engine->GetModule("2", asGM_ALWAYS_CREATE);
	mod->LoadByteCode(&stream);

	DumpModule(mod);

	engine->Release();

	return fail;
}
Example #27
0
static bool TestEnum()
{
	if( strstr(asGetLibraryOptions(), "AS_MAX_PORTABILITY") )
	{
		// Skipping this due to not supporting native calling conventions
		printf("Skipped due to AS_MAX_PORTABILITY\n");
		return false;
	}

	asIScriptEngine   *engine;
	CBufferedOutStream bout;
	int		 		   r;
	bool               fail = false;

 	engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);

	bout.buffer = "";
	r = engine->SetMessageCallback(asMETHOD(CBufferedOutStream,Callback), &bout, asCALL_THISCALL);

	r = engine->RegisterGlobalFunction("void assert(bool)", asFUNCTION(Assert), asCALL_GENERIC);

	// Register the enum value
	r = engine->RegisterEnum("TEST_ENUM"); assert(r >= 0);
	r = engine->RegisterEnumValue("TEST_ENUM", "ENUM1", ENUM1); assert(r >= 0);
	r = engine->RegisterEnumValue("TEST_ENUM", "ENUM2", ENUM2); assert(r >= 0);
	r = engine->RegisterEnumValue("TEST_ENUM", "ENUM3", ENUM3); assert(r >= 0);

	r = engine->RegisterGlobalFunction("void funce(TEST_ENUM)", asFUNCTION(func), asCALL_GENERIC); assert( r >= 0 );
	r = engine->RegisterGlobalFunction("void output(int val1)", asFUNCTION(scriptOutput), asCALL_CDECL); assert(r >= 0);

	// Test calling generic function with enum value
	r = ExecuteString(engine, "funce(ENUM1);");
	if( r != asEXECUTION_FINISHED )
		TEST_FAILED;
	r = ExecuteString(engine, "funce(TEST_ENUM::ENUM3);");
	if( r != asEXECUTION_FINISHED )
		TEST_FAILED;

	// Test using the registered enum values
	r = ExecuteString(engine, "output(ENUM1); output(ENUM2)");
	if( r != asEXECUTION_FINISHED )
		TEST_FAILED;
	if( buffer != "1\n10\n" )
		TEST_FAILED;

	// Test script that declare an enum
	// enum value can be given as expression of constants
	// enum can be implicitly cast to number
	buffer = "";
	asIScriptModule *mod = engine->GetModule(0, asGM_ALWAYS_CREATE);
	r = mod->AddScriptSection(NULL, script, strlen(script), 0);
	r = mod->Build();
	if( r < 0 )
		TEST_FAILED;

	r = ExecuteString(engine, "Test1()", mod);
	if( r != asEXECUTION_FINISHED )
		TEST_FAILED;
	if( buffer != "-1\n1\n2\n1200\n1201\n1202\n1203\n1205\n0\n1\n2\n" )
	{
		TEST_FAILED;
		printf("%s", buffer.c_str());
	}

	// Registered enums are literal constants
	// variable of enum type can be implictly cast to primitive
	buffer = "";
	r = ExecuteString(engine, "TEST_ENUM e = ENUM1; switch( e ) { case ENUM1: output(e); }");
	if( r != asEXECUTION_FINISHED )
		TEST_FAILED;
	if( buffer != "1\n" )
		TEST_FAILED;

	// Script declared enums behave the same
	buffer = "";
	r = ExecuteString(engine, "TEST2_ENUM e = TEST_1; switch( e ) {case TEST_1: output(e); }", mod);
	if( r != asEXECUTION_FINISHED )
		TEST_FAILED;
	if( buffer != "-1\n" )
		TEST_FAILED;

	// enum values can't be declared with expressions including subsequent values
	bout.buffer = "";
	r = engine->SetMessageCallback(asMETHOD(CBufferedOutStream,Callback), &bout, asCALL_THISCALL);
	const char *script2 = "enum TEST_ERR { ERR1 = ERR2, ERR2 }";
	mod = engine->GetModule("error", asGM_ALWAYS_CREATE);
	r = mod->AddScriptSection("error", script2, strlen(script2));
	r = mod->Build();
	if( r >= 0 )
		TEST_FAILED;
	if( bout.buffer != "error (1, 22) : Info    : Compiling TEST_ERR ERR1\n"
					   "error (1, 24) : Error   : Use of uninitialized global variable 'ERR2'.\n"
					   "error (1, 1) : Info    : Compiling TEST_ERR ERR2\n"
                       "error (1, 1) : Error   : Use of uninitialized global variable 'ERR1'.\n" )
	{
		printf("%s", bout.buffer.c_str());
		TEST_FAILED;
	}

	// enum type name can't be overloaded with variable name in another scope
	bout.buffer = "";
	r = ExecuteString(engine, "int TEST_ENUM = 999");
	if( r >= 0  )
		TEST_FAILED;
	if( bout.buffer != "ExecuteString (1, 5) : Error   : Illegal variable name 'TEST_ENUM'.\n" )
	{
		printf("%s", bout.buffer.c_str());
		TEST_FAILED;
	}
	r = engine->SetMessageCallback(asMETHOD(CBufferedOutStream,Callback), &bout, asCALL_THISCALL);

	// enum value name can be overloaded with variable name in another scope
	buffer = "";
	r = ExecuteString(engine, "int ENUM1 = 999; output(ENUM1)");
	if( r != asEXECUTION_FINISHED )
		TEST_FAILED;
	if( buffer != "999\n" )
		TEST_FAILED;

	// number cannot be implicitly cast to enum type
	bout.buffer = "";
	r = engine->SetMessageCallback(asMETHOD(CBufferedOutStream,Callback), &bout, asCALL_THISCALL);
	r = ExecuteString(engine, "TEST_ENUM val = 1");
	if( r >= 0 )
		TEST_FAILED;
	r = ExecuteString(engine, "float f = 1.2f; TEST_ENUM val = f");
	if( r >= 0 )
		TEST_FAILED;
	if( bout.buffer != "ExecuteString (1, 17) : Error   : Can't implicitly convert from 'uint' to 'TEST_ENUM'.\n"
                       "ExecuteString (1, 33) : Error   : Can't implicitly convert from 'float' to 'TEST_ENUM'.\n" )
	{
		printf("%s", bout.buffer.c_str());
		TEST_FAILED;
	}
	r = engine->SetMessageCallback(asMETHOD(CBufferedOutStream,Callback), &bout, asCALL_THISCALL);

	// constant number can be explicitly cast to enum type
	r = ExecuteString(engine, "TEST_ENUM val = TEST_ENUM(1)");
	if( r != asEXECUTION_FINISHED )
		TEST_FAILED;

	// primitive value can be explicitly cast to enum type
	r = ExecuteString(engine, "float f = 1.2f; TEST_ENUM val = TEST_ENUM(f)");
	if( r != asEXECUTION_FINISHED )
		TEST_FAILED;

	// math operator with enums
	buffer = "";
	r = ExecuteString(engine, "int a = ENUM2 * 10; output(a); output(ENUM2 + ENUM1)");
	if( r != asEXECUTION_FINISHED )
		TEST_FAILED;
	if( buffer != "100\n11\n" )
		TEST_FAILED;

	// comparison operator with enums
	buffer = "";
	r = ExecuteString(engine, "if( ENUM2 > ENUM1 ) output(1);");
	if( r != asEXECUTION_FINISHED )
		TEST_FAILED;
	if( buffer != "1\n" )
		TEST_FAILED;

	// bitwise operators with enums
	buffer = "";
	r = ExecuteString(engine, "output( ENUM2 << ENUM1 )");
	if( r != asEXECUTION_FINISHED )
		TEST_FAILED;
	if( buffer != "20\n" )
		TEST_FAILED;

	// circular reference between enum and global variable are
	// allowed if they can be resolved
	const char *script3 =
	"enum TEST_EN                \n"
	"{                           \n"
	"  EN1,                      \n"
	"  EN2 = gvar,               \n"
	"  EN3,                      \n"
	"}                           \n"
	"const int gvar = EN1 + 10;  \n";
	mod = engine->GetModule("en", asGM_ALWAYS_CREATE);
	mod->AddScriptSection("en", script3, strlen(script3));
	r = mod->Build();
	if( r < 0 )
		TEST_FAILED;
	buffer = "";
	r = ExecuteString(engine, "output(EN2); output(EN3)", mod);
	if( r != asEXECUTION_FINISHED )
		TEST_FAILED;
	if( buffer != "10\n11\n" )
		TEST_FAILED;

	// functions can be overloaded for parameters with enum type
	const char *script4 =
	"void func(TEST_ENUM) { output(1); } \n"
	"void func(int) { output(2); } \n";
	mod = engine->GetModule(0, asGM_ALWAYS_CREATE);
	mod->AddScriptSection("script", script4, strlen(script4));
	r = mod->Build();
	if( r < 0 )
		TEST_FAILED;
	buffer = "";
	r = ExecuteString(engine, "func(1); func(1.0f); TEST_ENUM e = ENUM1; func(e)", mod);
	if( r != asEXECUTION_FINISHED )
		TEST_FAILED;
	if( buffer != "2\n2\n1\n" )
		TEST_FAILED;

	// Using registered enum type in a script
	engine->RegisterEnum("game_type_t");
	const char *script5 =
	"game_type_t random_game_type;\n"
	"void foo(game_type_t game_type)\n"
	"{\n"
	"   random_game_type = game_type;\n"
	"};\n";
	r = mod->AddScriptSection("script", script5, strlen(script5));
	r = mod->Build();
	if( r < 0 )
		TEST_FAILED;

	// enum with assignment without comma
	const char *script6 = "enum test_wo_comma { value = 0 }";
	r = mod->AddScriptSection("script", script6, strlen(script6));
	r = mod->Build();
	if( r < 0 )
		TEST_FAILED;

	// Enums are not object types
	int eid;
	const char *ename = mod->GetEnumByIndex(0, &eid);
	if( eid < 0 || ename == 0 )
		TEST_FAILED;
	asIObjectType *eot = engine->GetObjectTypeById(eid);
	if( eot )
		TEST_FAILED;

	// enum must allow negate and binary complement operators
	bout.buffer = "";
	r = engine->SetMessageCallback(asMETHOD(CBufferedOutStream,Callback), &bout, asCALL_THISCALL);
	r = ExecuteString(engine, "int a = -ENUM1; int b = ~ENUM1;");
	if( r < 0 )
		TEST_FAILED;
	if( bout.buffer != "ExecuteString (1, 25) : Warning : Implicit conversion changed sign of value\n" )
	{
		printf("%s", bout.buffer.c_str());
		TEST_FAILED;
	}

	// Test specifying an unknown enum type name
	bout.buffer = "";
	r = engine->SetMessageCallback(asMETHOD(CBufferedOutStream,Callback), &bout, asCALL_THISCALL);
	const char *script7 = "void f() { funce(UNKNOWN_ENUM::ENUM1); }";
	mod = engine->GetModule("error", asGM_ALWAYS_CREATE);
	r = mod->AddScriptSection("error", script7, strlen(script7));
	r = mod->Build();
	if( r >= 0 )
		TEST_FAILED;
	if( bout.buffer != "error (1, 1) : Info    : Compiling void f()\n"
                       "error (1, 18) : Error   : 'UNKNOWN_ENUM::ENUM1' is not declared\n")
	{
		printf("%s", bout.buffer.c_str());
		TEST_FAILED;
	}

	// Test specifying a non enum type name before the scope
	bout.buffer = "";
	r = engine->SetMessageCallback(asMETHOD(CBufferedOutStream,Callback), &bout, asCALL_THISCALL);
	const char *script8 =
	"class SomeClass\n"
	"{\n"
	"  int SOMEVALUE;\n"
	"}\n"
	"void f() { funce(SomeClass::SOMEVALUE); }";
	mod = engine->GetModule("error", asGM_ALWAYS_CREATE);
	r = mod->AddScriptSection("error", script8, strlen(script8));
	r = mod->Build();
	if( r >= 0 )
		TEST_FAILED;
	if( bout.buffer != "error (5, 1) : Info    : Compiling void f()\n"
		               "error (5, 18) : Error   : 'SomeClass::SOMEVALUE' is not declared\n")
	{
		printf("%s", bout.buffer.c_str());
		TEST_FAILED;
	}

	// Test engine property
	r = engine->SetEngineProperty(asEP_REQUIRE_ENUM_SCOPE, 1);
	if( r != 0 )
		TEST_FAILED;

	bout.buffer = "";
	r = engine->SetMessageCallback(asMETHOD(CBufferedOutStream,Callback), &bout, asCALL_THISCALL);
	const char *script9 = "void f() { funce(ENUM1); }";
	mod = engine->GetModule("error", asGM_ALWAYS_CREATE);
	r = mod->AddScriptSection("error", script9, strlen(script9));
	r = mod->Build();
	if( r >= 0 )
		TEST_FAILED;
	if( bout.buffer != "error (1, 1) : Info    : Compiling void f()\n"
		               "error (1, 18) : Error   : 'ENUM1' is not declared\n")
	{
		printf("%s", bout.buffer.c_str());
		TEST_FAILED;
	}

	buffer = "";
	r = ExecuteString(engine, "output(TEST_ENUM::ENUM1);");
	if( r != asEXECUTION_FINISHED )
		TEST_FAILED;
	if( buffer != "1\n" )
		TEST_FAILED;

	// Test enum in param to class method
	assert( sizeof(TEST_ENUM) == 4 );
	r = engine->SetEngineProperty(asEP_REQUIRE_ENUM_SCOPE, 0);
	r = engine->RegisterObjectType("Obj", 0, asOBJ_REF | asOBJ_NOHANDLE); assert( r >= 0 );
	r = engine->RegisterObjectMethod("Obj", "bool TestEnum(TEST_ENUM)", asMETHOD(CTestObject, TestEnum), asCALL_THISCALL); assert( r >= 0 );
	
	CTestObject obj;
	obj.val = ENUM1;

	r = engine->RegisterGlobalProperty("Obj obj", &obj); assert( r >= 0 );

	bout.buffer = "";
	r = ExecuteString(engine, "if( !obj.TestEnum(ENUM2) ) assert(false); ");
	if( r != asEXECUTION_FINISHED )
		TEST_FAILED;
	if( bout.buffer != "" )
	{
		printf("%s", bout.buffer.c_str());
		TEST_FAILED;
	}
	if( obj.val != ENUM2 )
		TEST_FAILED;

	// Repeated enum values would enter an infinit loop
	bout.buffer = "";
	const char *script10 = "enum Infinite { inf, inf }";
	mod->AddScriptSection("test", script10);
	r = mod->Build();
	if( r >= 0 )
		TEST_FAILED;
	if( bout.buffer != "test (1, 22) : Error   : Name conflict. 'inf' is already used.\n" )
	{
		printf("%s", bout.buffer.c_str());
		TEST_FAILED;
	}

	engine->Release();

	{
		COutStream out;
		engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
		engine->SetMessageCallback(asMETHOD(COutStream,Callback), &out, asCALL_THISCALL);
		RegisterStdString(engine);
		engine->RegisterGlobalFunction("void assert(bool)", asFUNCTION(Assert), asCALL_GENERIC);

		asIScriptModule *mod = engine->GetModule(0, asGM_ALWAYS_CREATE);
		mod->AddScriptSection("script", "enum waveformType \n"
										"{ \n"
										"  sawtoothWave = 1, \n"
										"  squareWave = 2, \n"
										"  sineWave = 3 \n"
										"} \n"
										"void main() \n"
										"{ \n"
										"  tone_synth synth; \n"
										"  synth.waveform_type = sineWave; \n"
										"  assert( '' + sineWave + '' == '3' ); \n"
										"  assert( synth.waveform_type == 3 ); \n"
										"} \n"
										"class tone_synth { void set_waveform_type(double v) {prop = v;} double get_waveform_type() {return prop;} double prop; }\n");

		r = mod->Build();
		if( r < 0 ) 
			TEST_FAILED;

		r = ExecuteString(engine, "main()", mod);
		if( r != asEXECUTION_FINISHED )
			TEST_FAILED;

		engine->Release();
	}

	//paste at the end of TestEnum()
	{    
		COutStream out;
		engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
		engine->SetMessageCallback(asMETHOD(COutStream,Callback), &out, asCALL_THISCALL);
		r = engine->SetEngineProperty(asEP_REQUIRE_ENUM_SCOPE, 1); assert(r >= 0);

		r = engine->RegisterEnum("RENUM_1"); assert(r >= 0);
		r = engine->RegisterEnumValue("RENUM_1", "R_GLOBAL", 0); assert(r >= 0);
		r = engine->RegisterEnumValue("RENUM_1", "RE1_1", 1); assert(r >= 0);
		r = engine->RegisterEnumValue("RENUM_1", "RE1_2", 2); assert(r >= 0);

		r = engine->RegisterEnum("RENUM_2"); assert(r >= 0);
		r = engine->RegisterEnumValue("RENUM_2", "R_GLOBAL", 13); assert(r >= 0);
		r = engine->RegisterEnumValue("RENUM_2", "RE2_1", 1); assert(r >= 0);
		r = engine->RegisterEnumValue("RENUM_2", "RE2_2", 2); assert(r >= 0);

		r = engine->RegisterGlobalFunction("void output(int val1)", asFUNCTION(scriptOutput), asCALL_CDECL); assert(r >= 0);
		asIScriptModule *mod = engine->GetModule(0, asGM_ALWAYS_CREATE);
		mod->AddScriptSection("script", 
			"enum ENUM_1            \n"
			"{                      \n"
			"  TEST_GLOBAL = 0,     \n"
			"  E1_VAL1,             \n"
			"  E1_VAL2,             \n"
			"  RE1_2                \n"
			"}                      \n"
			"enum ENUM_2            \n"
			"{                      \n"
			"  TEST_GLOBAL = 0,     \n" 
			"  E2_VAL1,             \n"
			"  E2_VAL2              \n"
			"}                      \n"
			"ENUM_1 g_e1 = ENUM_1::E1_VAL1;         \n"
			"RENUM_1 rg_e1 = RENUM_1::RE1_2;        \n" 
			"                                       \n"
			"void main()                            \n"
			"{                                      \n"
			"   ENUM_1 l_e1 = ENUM_1::E1_VAL1;      \n"
			"   g_e1 = ENUM_1::E1_VAL1;             \n"
			"   rg_e1 = RENUM_1::R_GLOBAL;          \n"
			"   RENUM_2 rl_e2 = RENUM_2::R_GLOBAL;  \n"
			"   output(rg_e1);                      \n"
			"   output(rl_e2);                      \n"
			"}                                      \n");
		r = mod->Build();
		if( r < 0 )
			TEST_FAILED;
		buffer = "";
		r = ExecuteString(engine, "main();", mod);
		if( r != asEXECUTION_FINISHED )
			TEST_FAILED;
		if( buffer != "0\n13\n" )
			TEST_FAILED;
		engine->Release();
	} 

	// Some validations that must be done
	{
		engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
		bout.buffer = "";
		r = engine->SetMessageCallback(asMETHOD(CBufferedOutStream,Callback), &bout, asCALL_THISCALL);
		r = engine->SetEngineProperty(asEP_REQUIRE_ENUM_SCOPE, 1); assert(r >= 0);
		asIScriptModule *mod = engine->GetModule(0, asGM_ALWAYS_CREATE);
		mod->AddScriptSection("script", 
			"enum ENUM_1            \n"
			"{                      \n"
			"  E1_VAL1              \n"
			"};                     \n"   // Semi colon after enum declaration is allowed, but optional
			"ENUM_1 g_e1 = ENUM_1::E1_VAL1;         \n"
			"ENUM_1 g_e2 = E2_VAL1;                 \n"); // <- that shouldn't (?)
		r = mod->Build();
		if( r >= 0 )
			TEST_FAILED;
		if( bout.buffer != "script (6, 13) : Info    : Compiling ENUM_1 g_e2\n"
		                   "script (6, 15) : Error   : 'E2_VAL1' is not declared\n" )
		{
			printf("%s", bout.buffer.c_str());
			TEST_FAILED;
		}

		r = engine->RegisterEnum("RENUM_1"); assert(r >= 0);
		r = engine->RegisterEnumValue("RENUM_1", "@#$%", 777); // shouldn't work
		if( r >= 0 )
			TEST_FAILED;

		engine->Release();
	}

	// Test problem reported by Andrew Ackermann
	// The code crashed in ALLOC as the enum was copied as 8bytes on 64bit platforms
	{
		const char *script = 
		"enum TestEnum { \n"
		" TE_0, \n"
		" TE_1, \n"
		"}; \n"
		"class TestClass { \n"
		" TestClass(TestEnum en) { \n"
		" } \n"
		"}; \n"
		"void init() { \n"
		" TestClass@ cl = TestClass(TE_1); \n"
		"} \n";

		engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
		bout.buffer = "";
		r = engine->SetMessageCallback(asMETHOD(CBufferedOutStream,Callback), &bout, asCALL_THISCALL);

		asIScriptModule *mod = engine->GetModule(0, asGM_ALWAYS_CREATE);
		mod->AddScriptSection("script", script);
		r = mod->Build();
		if( r < 0 )
			TEST_FAILED;
		if( bout.buffer != "" )
		{
			printf("%s", bout.buffer.c_str());
			TEST_FAILED;
		}
	
		r = ExecuteString(engine, "init()", mod);
		if( r != asEXECUTION_FINISHED )
			TEST_FAILED;

		engine->Release();
	}

	// Test problem reported by SadSingleton
	// http://www.gamedev.net/topic/622524-crash-using-the-identity-operator-with-enum-values/
	{
		const char *script = 
			"enum MyEnum { MyEnumValue = 1 } \n"
			"void Update() \n"
			"{ \n"
			"        MyEnum enumValue = MyEnumValue; \n"
			"        bool condition = true; \n"
			"        if (condition) \n"
			"        { \n"
			"                if(enumValue is MyEnumValue) \n"
			"                { \n"
			"                        int i = 0; \n"
			"                } \n"
			"        } \n"
			"        else \n"
			"        { \n"
			"                int j = 1; \n"
			"        } \n"
			"} \n";

		engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
		bout.buffer = "";
		r = engine->SetMessageCallback(asMETHOD(CBufferedOutStream,Callback), &bout, asCALL_THISCALL);

		asIScriptModule *mod = engine->GetModule(0, asGM_ALWAYS_CREATE);
		mod->AddScriptSection("script", script);
		r = mod->Build();
		if( r >= 0 )
			TEST_FAILED;
		if( bout.buffer != "script (2, 1) : Info    : Compiling void Update()\n"
		                   "script (8, 30) : Error   : Both operands must be handles when comparing identity\n" )
		{
			printf("%s", bout.buffer.c_str());
			TEST_FAILED;
		}
		engine->Release();
	}

	// Success
	return fail;
}
void Test()
{
	printf("---------------------------------------------\n");
	printf("%s\n\n", TESTNAME);
	printf("Machine 1\n");
	printf("AngelScript 1.9.0             : 11.00 secs\n");
	printf("AngelScript 1.9.1             : 9.618 secs\n");
	printf("AngelScript 1.9.2             : 8.748 secs\n");
	printf("AngelScript 1.10.0 with C++ VM: 7.073 secs\n");
	printf("AngelScript 1.10.0 with ASM VM: 7.613 secs\n");
	printf("AngelScript 1.10.1 with ASM VM: 6.432 secs\n");
	printf("\n");
	printf("Machine 2\n");
	printf("AngelScript 1.9.0             : 4.806 secs\n");
	printf("AngelScript 1.9.1             : 4.300 secs\n");
	printf("AngelScript 1.9.2             : 3.686 secs\n");
	printf("AngelScript 1.10.0 with C++ VM: 2.973 secs\n");
	printf("AngelScript 1.10.0 with ASM VM: 3.329 secs\n");
	printf("AngelScript 1.10.1 with ASM VM: 2.936 secs\n");
	printf("AngelScript 2.0.0  with C++ VM: 6.182 secs\n");
	printf("AngelScript 2.0.0  with ASM VM: 5.958 secs\n");

	printf("\nBuilding...\n");

 	asIScriptEngine *engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);

	RegisterStdString(engine);

	COutStream out;
	engine->AddScriptSection(0, TESTNAME, script, strlen(script), 0);
	engine->Build(0, &out);

	asIScriptContext *ctx;
	engine->CreateContext(&ctx);
	ctx->Prepare(engine->GetFunctionIDByDecl(0, "void TestString()"));

	printf("Executing AngelScript version...\n");

	double time = GetSystemTimer();

	int r = ctx->Execute();

	time = GetSystemTimer() - time;

	if( r != 0 )
	{
		printf("Execution didn't terminate with asEXECUTION_FINISHED\n", TESTNAME);
		if( r == asEXECUTION_EXCEPTION )
		{
			printf("Script exception\n");
			printf("Func: %s\n", engine->GetFunctionName(ctx->GetExceptionFunction()));
			printf("Line: %d\n", ctx->GetExceptionLineNumber());
			printf("Desc: %s\n", ctx->GetExceptionString());
		}
	}
	else
		printf("Time = %f secs\n", time);

	ctx->Release();
	engine->Release();
}
Example #29
0
bool Test()
{
	bool fail = false;
	int r;
	COutStream out;
	asIScriptContext *ctx;

 	asIScriptEngine *engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);

	engine->SetMessageCallback(asMETHOD(COutStream,Callback), &out, asCALL_THISCALL);
	RegisterScriptArray(engine, true);
	RegisterStdString(engine);
	engine->RegisterGlobalFunction("void assert(bool)", asFUNCTION(Assert), asCALL_GENERIC);
	engine->RegisterGlobalFunction("void print(int)", asFUNCTION(print_generic), asCALL_GENERIC);
	engine->RegisterGlobalFunction("void print(const string &in)", asFUNCTION(print_generic), asCALL_GENERIC);

	asIScriptModule *mod = engine->GetModule(0, asGM_ALWAYS_CREATE);
	mod->AddScriptSection(TESTNAME, script1, strlen(script1), 0);
	r = mod->Build();
	if( r < 0 )
	{
		TEST_FAILED;
		PRINTF("%s: Failed to compile the script\n", TESTNAME);
	}

	ctx = engine->CreateContext();
	r = ExecuteString(engine, "main()", mod, ctx);
	if( r != asEXECUTION_FINISHED )
	{
		if( r == asEXECUTION_EXCEPTION )
			PRINTF("%s", GetExceptionInfo(ctx).c_str());

		PRINTF("%s: Failed to execute script\n", TESTNAME);
		TEST_FAILED;
	}
	if( ctx ) ctx->Release();

	{
		const char *script =
			"class CTest \n"
			"{ \n"
			"	string name; \n"
			"	 \n"
			"   CTest() { name = 'temp'; print('CTest::CTest() for ' + name + '\\n'); } \n"
			"	CTest(string s) { name = s; print('CTest::CTest() for ' + name + '\\n'); } \n"
			"	~CTest(){ print('CTest::~CTest() for ' + name + '\\n'); } \n"
			"	 \n"
		//	"   CTest @opAssign(const CTest &in o) { print('CTest::opAssign(), ' + name + ' becomes ' + o.name + '\\n'); name = o.name; return this; } \n"
			"	void test(){ print('CTest::test() for ' + name + '\\n'); } \n"
			"} \n"
			"void test() \n"
			"{ \n"
			"	CTest t1('Ent1'); \n"
			"	CTest t2('Ent2'); \n"
			"	 \n"
			"	t1.test(); \n"
			"	t2.test(); \n"
			"	 \n"
			"	t2 = t1; \n"
			"} \n";

		mod->AddScriptSection(TESTNAME, script);
		r = mod->Build();
		if( r < 0 )
		{
			TEST_FAILED;
			PRINTF("%s: Failed to compile the script\n", TESTNAME);
		}

		r = ExecuteString(engine, "test()", mod);
		if( r != asEXECUTION_FINISHED )
		{
			TEST_FAILED;
		}

		// There shouldn't be any temporary variable created for the assignment
		if( buffer != "CTest::CTest() for Ent1\n"
		              "CTest::CTest() for Ent2\n"
		              "CTest::test() for Ent1\n"
		              "CTest::test() for Ent2\n"
		              "CTest::~CTest() for Ent1\n"
		              "CTest::~CTest() for Ent1\n" )
		{
			PRINTF("%s", buffer.c_str());
			TEST_FAILED;
		}
	}

	engine->Release();

	// Success
	return fail;
}
bool Test()
{
	bool fail = false;
	int r;
	CBufferedOutStream bout;
	COutStream out;
	asIScriptModule *mod;
 	asIScriptEngine *engine;
	
	// Test calling a function with default argument
	{
		engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
		engine->SetMessageCallback(asMETHOD(COutStream,Callback), &out, asCALL_THISCALL);
		RegisterScriptString(engine);
		engine->RegisterGlobalFunction("void assert(bool)", asFUNCTION(Assert), asCALL_GENERIC);

		mod = engine->GetModule(0, asGM_ALWAYS_CREATE);

		const char *script =
			"void func(int b, const string &in a = 'default') \n"
			"{ \n"
			"  if( b == 0 ) \n"
			"    assert( a == 'default' ); \n"
			"  else  \n"
			"    assert( a == 'test' ); \n"
			"} \n" 
			"void main() \n"
			"{ \n"
			"  func(0); \n"
			"  func(0, 'default'); \n"
			"  func(1, 'test'); \n"
			"} \n";

		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();
	}

	// Must be possible to register functions with default args as well
	{
		engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
		engine->SetMessageCallback(asMETHOD(COutStream,Callback), &out, asCALL_THISCALL);
		r = engine->RegisterGlobalFunction("void defarg(bool, int a = 34 + /* comments will be removed */ 45, int b = 23)", asFUNCTION(0), asCALL_GENERIC);
		if( r < 0 )
			TEST_FAILED;
		asIScriptFunction *func = engine->GetFunctionDescriptorById(r);
		string decl = func->GetDeclaration();
		if( decl != "void defarg(bool, int arg1 = 34 + 45, int arg2 = 23)" )
		{
			printf("%s\n", decl.c_str());
			TEST_FAILED;
		}
		engine->Release();
	}

	// When default arg is used, all other args after that must have default args
	{
		engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
		bout.buffer = "";
		engine->SetMessageCallback(asMETHOD(CBufferedOutStream,Callback), &bout, asCALL_THISCALL);
		r = engine->RegisterGlobalFunction("void defarg(bool, int a = 34+45, int)", asFUNCTION(0), asCALL_GENERIC);
		if( r >= 0 )
			TEST_FAILED;
		if( bout.buffer != "System function (1, 1) : Error   : All subsequent parameters after the first default value must have default values in function 'void defarg(bool, int arg1 = 34 + 45, int)'\n" )
		{
			printf("%s", bout.buffer.c_str());
			TEST_FAILED;
		}
		engine->Release();
	}

	// Shouldn't be possible to write default arg expressions that access local variables, globals are ok though
	{
		engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
		bout.buffer = "";
		engine->SetMessageCallback(asMETHOD(CBufferedOutStream,Callback), &bout, asCALL_THISCALL);

		mod = engine->GetModule(0, asGM_ALWAYS_CREATE);

		const char *script =
			"void func(int a = n) {} \n"
			"void main() \n"
			"{ \n"
			"  int n; \n"
			"  func(); \n"
			"} \n";

		mod->AddScriptSection("script", script);
		r = mod->Build();
		if( r >= 0 )
			TEST_FAILED;

		// TODO: The first line in the error message should show the real script name
		if( bout.buffer != "default arg (2, 1) : Info    : Compiling void main()\n"
		                   "default arg (1, 1) : Error   : 'n' is not declared\n"
		                   "script (5, 3) : Error   : Failed while compiling default arg for parameter 0 in function 'void func(int arg0 = n)'\n" )
		{
			printf("%s", bout.buffer.c_str());
			TEST_FAILED;
		}

		engine->Release();
	}

	// Default args in script class constructors
	{
		engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
		engine->SetMessageCallback(asMETHOD(COutStream,Callback), &out, asCALL_THISCALL);
		engine->RegisterGlobalFunction("void assert(bool)", asFUNCTION(Assert), asCALL_GENERIC);

		mod = engine->GetModule(0, asGM_ALWAYS_CREATE);

		const char *script =
			"class T \n"
			"{ \n"
			"  T(int a, int b = 25) \n"
			"  { \n"
			"    assert(a == 10); \n"
			"    assert(b == 25); \n"
			"  } \n"
			"} \n" 
			"T g(10); \n"
			"void main() \n"
			"{ \n"
			"  T(10); \n"
			"  T l(10); \n"
			"} \n";

		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();
	}

	// Default arg must not end up using variables that are used 
	// in previously compiled variables as temporaries
	{
		engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
		engine->SetMessageCallback(asMETHOD(COutStream,Callback), &out, asCALL_THISCALL);
		engine->RegisterGlobalFunction("void assert(bool)", asFUNCTION(Assert), asCALL_GENERIC);
		RegisterStdString(engine);

		mod = engine->GetModule(0, asGM_ALWAYS_CREATE);

		const char *script =
			"void func(uint8 a, string b = 'b') \n"
			"{ \n"
			"  assert( a == 97 ); \n"
			"  assert( b == 'b' ); \n"
			"} \n" 
			"void main() \n"
			"{ \n"
			"  uint8 a; \n"
			"  func(a = 'a'[0]); \n"
			"} \n";

		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();
	}

	// Shouldn't crash if attempting to call incorrect function
	{
		engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
		bout.buffer = "";
		engine->SetMessageCallback(asMETHOD(CBufferedOutStream,Callback), &bout, asCALL_THISCALL);

		mod = engine->GetModule(0, asGM_ALWAYS_CREATE);

		const char *script =
			"void myFunc( float f, int a=0, int b ) {} \n"
			"void main() \n"
			"{ \n"
			"  int n; \n"
			"  myFunc( 1.2, 6 ); \n"
			"} \n";

		mod->AddScriptSection("script", script);
		r = mod->Build();
		if( r >= 0 )
			TEST_FAILED;

		if( bout.buffer != "script (1, 1) : Error   : All subsequent parameters after the first default value must have default values in function 'void myFunc(float, int arg1 = 0, int)'\n" )
		{
			printf("%s", bout.buffer.c_str());
			TEST_FAILED;
		}

		engine->Release();
	}


	// The test to make sure the saved bytecode keeps the default args is done in test_saveload.cpp
	// A test to make sure script class methods with default args work is done in test_saveload.cpp

	// TODO: The compilation of the default args must not add any LINE instructions in the byte code, because they wouldn't match the real script

	// Success
	return fail;
}