Scripting: Lua method calling cleanup and testing

This commit is contained in:
Vicki Pfau 2022-05-03 20:44:56 -07:00
parent 16bad9f141
commit 5c67c3b600
3 changed files with 226 additions and 28 deletions

View File

@ -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, \

View File

@ -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;
}

View File

@ -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))