mirror of https://github.com/mgba-emu/mgba.git
Scripting: Lua method calling cleanup and testing
This commit is contained in:
parent
16bad9f141
commit
5c67c3b600
|
@ -366,8 +366,16 @@ CXX_GUARD_START
|
|||
#define mSCRIPT_DEFINE_END { .type = mSCRIPT_CLASS_INIT_END } } }
|
||||
|
||||
#define _mSCRIPT_BIND_FUNCTION(NAME, NRET, RETURN, NPARAMS, ...) \
|
||||
static struct mScriptFunction _function_ ## NAME = { \
|
||||
.call = _binding_ ## NAME \
|
||||
}; \
|
||||
static void _alloc_ ## NAME(struct mScriptValue* val) { \
|
||||
val->value.copaque = &_function_ ## NAME; \
|
||||
} \
|
||||
static const struct mScriptType _type_ ## NAME = { \
|
||||
.base = mSCRIPT_TYPE_FUNCTION, \
|
||||
.name = "function::" #NAME, \
|
||||
.alloc = _alloc_ ## NAME, \
|
||||
.details = { \
|
||||
.function = { \
|
||||
.parameters = { \
|
||||
|
@ -381,9 +389,6 @@ CXX_GUARD_START
|
|||
}, \
|
||||
} \
|
||||
}; \
|
||||
static struct mScriptFunction _function_ ## NAME = { \
|
||||
.call = _binding_ ## NAME \
|
||||
}; \
|
||||
const struct mScriptValue NAME = { \
|
||||
.type = &_type_ ## NAME, \
|
||||
.refs = mSCRIPT_VALUE_UNREF, \
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#include <mgba/internal/script/lua.h>
|
||||
#include <lualib.h>
|
||||
#include <lauxlib.h>
|
||||
|
||||
static struct mScriptEngineContext* _luaCreate(struct mScriptEngine2*, struct mScriptContext*);
|
||||
|
@ -79,6 +80,12 @@ static struct mScriptEngineLua {
|
|||
|
||||
struct mScriptEngine2* const mSCRIPT_ENGINE_LUA = &_engineLua.d;
|
||||
|
||||
static const luaL_Reg _mSTStruct[] = {
|
||||
{ "__index", _luaGetObject },
|
||||
{ "__newindex", _luaSetObject },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
struct mScriptEngineContext* _luaCreate(struct mScriptEngine2* engine, struct mScriptContext* context) {
|
||||
UNUSED(engine);
|
||||
struct mScriptEngineContextLua* luaContext = calloc(1, sizeof(*luaContext));
|
||||
|
@ -93,13 +100,14 @@ struct mScriptEngineContext* _luaCreate(struct mScriptEngine2* engine, struct mS
|
|||
luaContext->lua = luaL_newstate();
|
||||
luaContext->func = -1;
|
||||
|
||||
luaL_openlibs(luaContext->lua);
|
||||
|
||||
luaL_newmetatable(luaContext->lua, "mSTStruct");
|
||||
lua_pushliteral(luaContext->lua, "__index");
|
||||
lua_pushcfunction(luaContext->lua, _luaGetObject);
|
||||
lua_rawset(luaContext->lua, -3);
|
||||
lua_pushliteral(luaContext->lua, "__newindex");
|
||||
lua_pushcfunction(luaContext->lua, _luaSetObject);
|
||||
lua_rawset(luaContext->lua, -3);
|
||||
#if LUA_VERSION_NUM < 502
|
||||
luaL_register(luaContext->lua, NULL, _mSTStruct);
|
||||
#else
|
||||
luaL_setfuncs(luaContext->lua, _mSTStruct, 0);
|
||||
#endif
|
||||
lua_pop(luaContext->lua, 1);
|
||||
|
||||
return &luaContext->d;
|
||||
|
@ -129,7 +137,7 @@ bool _luaSetGlobal(struct mScriptEngineContext* ctx, const char* name, struct mS
|
|||
return true;
|
||||
}
|
||||
|
||||
struct mScriptValue* _luaWrapFunction(struct mScriptEngineContextLua* luaContext) {
|
||||
struct mScriptValue* _luaCoerceFunction(struct mScriptEngineContextLua* luaContext) {
|
||||
struct mScriptValue* value = mScriptValueAlloc(&mSTLuaFunc);
|
||||
struct mScriptFunction* fn = calloc(1, sizeof(*fn));
|
||||
struct mScriptEngineContextLuaRef* ref = calloc(1, sizeof(*ref));
|
||||
|
@ -167,7 +175,18 @@ struct mScriptValue* _luaCoerce(struct mScriptEngineContextLua* luaContext) {
|
|||
case LUA_TSTRING:
|
||||
break;
|
||||
case LUA_TFUNCTION:
|
||||
return _luaWrapFunction(luaContext);
|
||||
return _luaCoerceFunction(luaContext);
|
||||
case LUA_TUSERDATA:
|
||||
if (!lua_getmetatable(luaContext->lua, -1)) {
|
||||
break;
|
||||
}
|
||||
luaL_getmetatable(luaContext->lua, "mSTStruct");
|
||||
if (!lua_rawequal(luaContext->lua, -1, -2)) {
|
||||
lua_pop(luaContext->lua, 2);
|
||||
break;
|
||||
}
|
||||
lua_pop(luaContext->lua, 2);
|
||||
value = lua_touserdata(luaContext->lua, -1);
|
||||
}
|
||||
lua_pop(luaContext->lua, 1);
|
||||
return value;
|
||||
|
@ -178,6 +197,7 @@ bool _luaWrap(struct mScriptEngineContextLua* luaContext, struct mScriptValue* v
|
|||
value = mScriptValueUnwrap(value);
|
||||
}
|
||||
bool ok = true;
|
||||
struct mScriptValue* newValue;
|
||||
switch (value->type->base) {
|
||||
case mSCRIPT_TYPE_SINT:
|
||||
if (value->type->size <= 4) {
|
||||
|
@ -207,14 +227,16 @@ bool _luaWrap(struct mScriptEngineContextLua* luaContext, struct mScriptValue* v
|
|||
}
|
||||
break;
|
||||
case mSCRIPT_TYPE_FUNCTION:
|
||||
lua_pushlightuserdata(luaContext->lua, value);
|
||||
newValue = lua_newuserdata(luaContext->lua, sizeof(*newValue));
|
||||
newValue->type = value->type;
|
||||
newValue->refs = mSCRIPT_VALUE_UNREF;
|
||||
newValue->type->alloc(newValue);
|
||||
lua_pushcclosure(luaContext->lua, _luaThunk, 1);
|
||||
mScriptValueRef(value);
|
||||
break;
|
||||
case mSCRIPT_TYPE_OBJECT:
|
||||
lua_pushlightuserdata(luaContext->lua, value);
|
||||
newValue = lua_newuserdata(luaContext->lua, sizeof(*newValue));
|
||||
mScriptValueWrap(value, newValue);
|
||||
luaL_setmetatable(luaContext->lua, "mSTStruct");
|
||||
mScriptValueRef(value);
|
||||
break;
|
||||
default:
|
||||
ok = false;
|
||||
|
@ -308,6 +330,15 @@ bool _luaPopFrame(struct mScriptEngineContextLua* luaContext, struct mScriptList
|
|||
if (count > i) {
|
||||
lua_pop(luaContext->lua, count - i);
|
||||
}
|
||||
|
||||
if (ok) {
|
||||
for (i = 0; i < (ssize_t) (mScriptListSize(frame) / 2); ++i) {
|
||||
struct mScriptValue buffer;
|
||||
memcpy(&buffer, mScriptListGetPointer(frame, i), sizeof(buffer));
|
||||
memcpy(mScriptListGetPointer(frame, i), mScriptListGetPointer(frame, mScriptListSize(frame) - i - 1), sizeof(buffer));
|
||||
memcpy(mScriptListGetPointer(frame, mScriptListSize(frame) - i - 1), &buffer, sizeof(buffer));
|
||||
}
|
||||
}
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
@ -346,7 +377,7 @@ bool _luaInvoke(struct mScriptEngineContextLua* luaContext, struct mScriptFrame*
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!_luaPopFrame(luaContext, &frame->returnValues)) {
|
||||
if (frame && !_luaPopFrame(luaContext, &frame->returnValues)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -324,24 +324,26 @@ M_TEST_DEFINE(callCFunc) {
|
|||
mScriptContextDeinit(&context);
|
||||
}
|
||||
|
||||
M_TEST_DEFINE(setGlobalStruct) {
|
||||
M_TEST_DEFINE(globalStructFieldGet) {
|
||||
struct mScriptContext context;
|
||||
mScriptContextInit(&context);
|
||||
struct mScriptEngineContext* lua = mSCRIPT_ENGINE_LUA->create(mSCRIPT_ENGINE_LUA, &context);
|
||||
|
||||
struct Test s = {
|
||||
.i = 1
|
||||
.i = 1,
|
||||
};
|
||||
|
||||
struct mScriptValue a = mSCRIPT_MAKE_S(Test, &s);
|
||||
struct mScriptValue a;
|
||||
struct mScriptValue b;
|
||||
struct mScriptValue* val;
|
||||
|
||||
LOAD_PROGRAM("b = a.i");
|
||||
|
||||
a = mSCRIPT_MAKE_S(Test, &s);
|
||||
assert_true(lua->setGlobal(lua, "a", &a));
|
||||
|
||||
s.i = 1;
|
||||
assert_true(lua->run(lua));
|
||||
|
||||
b = mSCRIPT_MAKE_S32(1);
|
||||
val = lua->getGlobal(lua, "b");
|
||||
assert_non_null(val);
|
||||
|
@ -350,30 +352,188 @@ M_TEST_DEFINE(setGlobalStruct) {
|
|||
|
||||
s.i = 2;
|
||||
assert_true(lua->run(lua));
|
||||
|
||||
b = mSCRIPT_MAKE_S32(2);
|
||||
val = lua->getGlobal(lua, "b");
|
||||
assert_non_null(val);
|
||||
assert_true(b.type->equal(&b, val));
|
||||
mScriptValueDeref(val);
|
||||
|
||||
LOAD_PROGRAM("a.i = b");
|
||||
b = mSCRIPT_MAKE_S32(3);
|
||||
assert_true(lua->setGlobal(lua, "b", &b));
|
||||
a = mSCRIPT_MAKE_CS(Test, &s);
|
||||
assert_true(lua->setGlobal(lua, "a", &a));
|
||||
|
||||
s.i = 1;
|
||||
assert_true(lua->run(lua));
|
||||
b = mSCRIPT_MAKE_S32(1);
|
||||
val = lua->getGlobal(lua, "b");
|
||||
assert_non_null(val);
|
||||
assert_true(b.type->equal(&b, val));
|
||||
mScriptValueDeref(val);
|
||||
|
||||
lua->destroy(lua);
|
||||
mScriptContextDeinit(&context);
|
||||
}
|
||||
|
||||
|
||||
M_TEST_DEFINE(globalStructFieldSet) {
|
||||
struct mScriptContext context;
|
||||
mScriptContextInit(&context);
|
||||
struct mScriptEngineContext* lua = mSCRIPT_ENGINE_LUA->create(mSCRIPT_ENGINE_LUA, &context);
|
||||
|
||||
struct Test s = {
|
||||
.i = 1,
|
||||
};
|
||||
|
||||
struct mScriptValue a;
|
||||
struct mScriptValue b;
|
||||
|
||||
LOAD_PROGRAM("a.i = b");
|
||||
|
||||
a = mSCRIPT_MAKE_S(Test, &s);
|
||||
assert_true(lua->setGlobal(lua, "a", &a));
|
||||
s.i = 1;
|
||||
b = mSCRIPT_MAKE_S32(2);
|
||||
assert_true(lua->setGlobal(lua, "b", &b));
|
||||
assert_true(lua->run(lua));
|
||||
assert_int_equal(s.i, 2);
|
||||
|
||||
a = mSCRIPT_MAKE_CS(Test, &s);
|
||||
assert_true(lua->setGlobal(lua, "a", &a));
|
||||
s.i = 1;
|
||||
b = mSCRIPT_MAKE_S32(2);
|
||||
assert_true(lua->setGlobal(lua, "b", &b));
|
||||
assert_false(lua->run(lua));
|
||||
assert_int_equal(s.i, 1);
|
||||
|
||||
lua->destroy(lua);
|
||||
mScriptContextDeinit(&context);
|
||||
}
|
||||
|
||||
|
||||
M_TEST_DEFINE(globalStructMethods) {
|
||||
struct mScriptContext context;
|
||||
mScriptContextInit(&context);
|
||||
struct mScriptEngineContext* lua = mSCRIPT_ENGINE_LUA->create(mSCRIPT_ENGINE_LUA, &context);
|
||||
|
||||
struct Test s = {
|
||||
.i = 1,
|
||||
.ifn0 = testI0,
|
||||
.ifn1 = testI1,
|
||||
.icfn0 = testIC0,
|
||||
.vfn0 = testV0,
|
||||
.vfn1 = testV1,
|
||||
};
|
||||
|
||||
struct mScriptValue a;
|
||||
struct mScriptValue b;
|
||||
struct mScriptValue* val;
|
||||
|
||||
// ifn0
|
||||
LOAD_PROGRAM("b = a:ifn0()");
|
||||
|
||||
a = mSCRIPT_MAKE_S(Test, &s);
|
||||
assert_true(lua->setGlobal(lua, "a", &a));
|
||||
s.i = 1;
|
||||
assert_true(lua->run(lua));
|
||||
b = mSCRIPT_MAKE_S32(1);
|
||||
val = lua->getGlobal(lua, "b");
|
||||
assert_non_null(val);
|
||||
assert_true(b.type->equal(&b, val));
|
||||
mScriptValueDeref(val);
|
||||
|
||||
a = mSCRIPT_MAKE_CS(Test, &s);
|
||||
assert_true(lua->setGlobal(lua, "a", &a));
|
||||
assert_false(lua->run(lua));
|
||||
|
||||
// ifn1
|
||||
LOAD_PROGRAM("b = a:ifn1(c)");
|
||||
|
||||
a = mSCRIPT_MAKE_S(Test, &s);
|
||||
assert_true(lua->setGlobal(lua, "a", &a));
|
||||
s.i = 1;
|
||||
b = mSCRIPT_MAKE_S32(1);
|
||||
assert_true(lua->setGlobal(lua, "c", &b));
|
||||
assert_true(lua->run(lua));
|
||||
b = mSCRIPT_MAKE_S32(2);
|
||||
val = lua->getGlobal(lua, "b");
|
||||
assert_non_null(val);
|
||||
assert_true(b.type->equal(&b, val));
|
||||
mScriptValueDeref(val);
|
||||
|
||||
b = mSCRIPT_MAKE_S32(2);
|
||||
assert_true(lua->setGlobal(lua, "c", &b));
|
||||
assert_true(lua->run(lua));
|
||||
b = mSCRIPT_MAKE_S32(3);
|
||||
val = lua->getGlobal(lua, "b");
|
||||
assert_non_null(val);
|
||||
assert_true(b.type->equal(&b, val));
|
||||
mScriptValueDeref(val);
|
||||
|
||||
a = mSCRIPT_MAKE_CS(Test, &s);
|
||||
assert_true(lua->setGlobal(lua, "a", &a));
|
||||
assert_false(lua->run(lua));
|
||||
|
||||
// vfn0
|
||||
LOAD_PROGRAM("a:vfn0()");
|
||||
|
||||
a = mSCRIPT_MAKE_S(Test, &s);
|
||||
assert_true(lua->setGlobal(lua, "a", &a));
|
||||
s.i = 1;
|
||||
assert_true(lua->run(lua));
|
||||
assert_int_equal(s.i, 2);
|
||||
assert_true(lua->run(lua));
|
||||
assert_int_equal(s.i, 3);
|
||||
|
||||
a = mSCRIPT_MAKE_CS(Test, &s);
|
||||
assert_true(lua->setGlobal(lua, "a", &a));
|
||||
b = mSCRIPT_MAKE_S32(4);
|
||||
assert_true(lua->setGlobal(lua, "b", &b));
|
||||
|
||||
assert_false(lua->run(lua));
|
||||
|
||||
// vfn1
|
||||
LOAD_PROGRAM("a:vfn1(c)");
|
||||
|
||||
a = mSCRIPT_MAKE_S(Test, &s);
|
||||
assert_true(lua->setGlobal(lua, "a", &a));
|
||||
s.i = 1;
|
||||
b = mSCRIPT_MAKE_S32(1);
|
||||
assert_true(lua->setGlobal(lua, "c", &b));
|
||||
assert_true(lua->run(lua));
|
||||
assert_int_equal(s.i, 2);
|
||||
b = mSCRIPT_MAKE_S32(2);
|
||||
assert_true(lua->setGlobal(lua, "c", &b));
|
||||
s.i = 1;
|
||||
assert_true(lua->run(lua));
|
||||
assert_int_equal(s.i, 3);
|
||||
|
||||
a = mSCRIPT_MAKE_CS(Test, &s);
|
||||
assert_true(lua->setGlobal(lua, "a", &a));
|
||||
s.i = 1;
|
||||
b = mSCRIPT_MAKE_S32(1);
|
||||
assert_true(lua->setGlobal(lua, "c", &b));
|
||||
assert_false(lua->run(lua));
|
||||
assert_int_equal(s.i, 1);
|
||||
|
||||
// icfn0
|
||||
LOAD_PROGRAM("b = a:icfn0()");
|
||||
|
||||
a = mSCRIPT_MAKE_S(Test, &s);
|
||||
assert_true(lua->setGlobal(lua, "a", &a));
|
||||
s.i = 1;
|
||||
assert_true(lua->run(lua));
|
||||
b = mSCRIPT_MAKE_S32(1);
|
||||
val = lua->getGlobal(lua, "b");
|
||||
assert_non_null(val);
|
||||
assert_true(b.type->equal(&b, val));
|
||||
mScriptValueDeref(val);
|
||||
|
||||
a = mSCRIPT_MAKE_CS(Test, &s);
|
||||
assert_true(lua->setGlobal(lua, "a", &a));
|
||||
s.i = 1;
|
||||
assert_true(lua->run(lua));
|
||||
b = mSCRIPT_MAKE_S32(1);
|
||||
val = lua->getGlobal(lua, "b");
|
||||
assert_non_null(val);
|
||||
assert_true(b.type->equal(&b, val));
|
||||
mScriptValueDeref(val);
|
||||
|
||||
lua->destroy(lua);
|
||||
mScriptContextDeinit(&context);
|
||||
}
|
||||
|
@ -387,4 +547,6 @@ M_TEST_SUITE_DEFINE_SETUP_TEARDOWN(mScriptLua,
|
|||
cmocka_unit_test(setGlobal),
|
||||
cmocka_unit_test(callLuaFunc),
|
||||
cmocka_unit_test(callCFunc),
|
||||
cmocka_unit_test(setGlobalStruct))
|
||||
cmocka_unit_test(globalStructFieldGet),
|
||||
cmocka_unit_test(globalStructFieldSet),
|
||||
cmocka_unit_test(globalStructMethods))
|
||||
|
|
Loading…
Reference in New Issue