mirror of https://github.com/mgba-emu/mgba.git
Scripting: Add Lua function call thunk
This commit is contained in:
parent
9d92c185c6
commit
7fb7d53c5d
|
@ -17,8 +17,8 @@ static bool _luaRun(struct mScriptEngineContext*);
|
|||
static bool _luaCall(struct mScriptFrame*, void* context);
|
||||
|
||||
struct mScriptEngineContextLua;
|
||||
static bool _luaPushFrame(struct mScriptEngineContextLua*, struct mScriptFrame*);
|
||||
static bool _luaPopFrame(struct mScriptEngineContextLua*, struct mScriptFrame*);
|
||||
static bool _luaPushFrame(struct mScriptEngineContextLua*, struct mScriptList*);
|
||||
static bool _luaPopFrame(struct mScriptEngineContextLua*, struct mScriptList*);
|
||||
static bool _luaInvoke(struct mScriptEngineContextLua*, struct mScriptFrame*);
|
||||
|
||||
static struct mScriptValue* _luaCoerce(struct mScriptEngineContextLua* luaContext);
|
||||
|
@ -26,6 +26,8 @@ static bool _luaWrap(struct mScriptEngineContextLua* luaContext, struct mScriptV
|
|||
|
||||
static void _luaDeref(struct mScriptValue*);
|
||||
|
||||
static int _luaThunk(lua_State* lua);
|
||||
|
||||
#if LUA_VERSION_NUM < 503
|
||||
#define lua_pushinteger lua_pushnumber
|
||||
#endif
|
||||
|
@ -190,12 +192,18 @@ bool _luaWrap(struct mScriptEngineContextLua* luaContext, struct mScriptValue* v
|
|||
ok = false;
|
||||
}
|
||||
break;
|
||||
case mSCRIPT_TYPE_FUNCTION:
|
||||
lua_pushlightuserdata(luaContext->lua, value);
|
||||
lua_pushcclosure(luaContext->lua, _luaThunk, 1);
|
||||
break;
|
||||
default:
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
|
||||
mScriptValueDeref(value);
|
||||
if (ok) {
|
||||
mScriptValueDeref(value);
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
|
@ -249,12 +257,12 @@ bool _luaRun(struct mScriptEngineContext* context) {
|
|||
return _luaInvoke(luaContext, NULL);
|
||||
}
|
||||
|
||||
bool _luaPushFrame(struct mScriptEngineContextLua* luaContext, struct mScriptFrame* frame) {
|
||||
bool _luaPushFrame(struct mScriptEngineContextLua* luaContext, struct mScriptList* frame) {
|
||||
bool ok = true;
|
||||
if (frame) {
|
||||
size_t i;
|
||||
for (i = 0; i < mScriptListSize(&frame->arguments); ++i) {
|
||||
if (!_luaWrap(luaContext, mScriptListGetPointer(&frame->arguments, i))) {
|
||||
for (i = 0; i < mScriptListSize(frame); ++i) {
|
||||
if (!_luaWrap(luaContext, mScriptListGetPointer(frame, i))) {
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
|
@ -266,7 +274,7 @@ bool _luaPushFrame(struct mScriptEngineContextLua* luaContext, struct mScriptFra
|
|||
return ok;
|
||||
}
|
||||
|
||||
bool _luaPopFrame(struct mScriptEngineContextLua* luaContext, struct mScriptFrame* frame) {
|
||||
bool _luaPopFrame(struct mScriptEngineContextLua* luaContext, struct mScriptList* frame) {
|
||||
int count = lua_gettop(luaContext->lua);
|
||||
bool ok = true;
|
||||
if (frame) {
|
||||
|
@ -277,8 +285,7 @@ bool _luaPopFrame(struct mScriptEngineContextLua* luaContext, struct mScriptFram
|
|||
ok = false;
|
||||
break;
|
||||
}
|
||||
lua_pop(luaContext->lua, 1);
|
||||
mScriptValueWrap(value, mScriptListAppend(&frame->returnValues));
|
||||
mScriptValueWrap(value, mScriptListAppend(frame));
|
||||
mScriptValueDeref(value);
|
||||
}
|
||||
if (count > i) {
|
||||
|
@ -303,11 +310,17 @@ bool _luaInvoke(struct mScriptEngineContextLua* luaContext, struct mScriptFrame*
|
|||
nargs = mScriptListSize(&frame->arguments);
|
||||
}
|
||||
|
||||
if (frame && !_luaPushFrame(luaContext, frame)) {
|
||||
if (frame && !_luaPushFrame(luaContext, &frame->arguments)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
lua_pushliteral(luaContext->lua, "mCtx");
|
||||
lua_pushlightuserdata(luaContext->lua, luaContext);
|
||||
lua_rawset(luaContext->lua, LUA_REGISTRYINDEX);
|
||||
int ret = lua_pcall(luaContext->lua, nargs, LUA_MULTRET, 0);
|
||||
lua_pushliteral(luaContext->lua, "mCtx");
|
||||
lua_pushnil(luaContext->lua);
|
||||
lua_rawset(luaContext->lua, LUA_REGISTRYINDEX);
|
||||
|
||||
if (ret == LUA_ERRRUN) {
|
||||
lua_pop(luaContext->lua, 1);
|
||||
|
@ -316,7 +329,7 @@ bool _luaInvoke(struct mScriptEngineContextLua* luaContext, struct mScriptFrame*
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!_luaPopFrame(luaContext, frame)) {
|
||||
if (!_luaPopFrame(luaContext, &frame->returnValues)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -335,3 +348,44 @@ void _luaDeref(struct mScriptValue* value) {
|
|||
luaL_unref(ref->context->lua, LUA_REGISTRYINDEX, ref->ref);
|
||||
free(ref);
|
||||
}
|
||||
|
||||
int _luaThunk(lua_State* lua) {
|
||||
lua_pushliteral(lua, "mCtx");
|
||||
int type = lua_rawget(lua, LUA_REGISTRYINDEX);
|
||||
if (type != LUA_TLIGHTUSERDATA) {
|
||||
lua_pop(lua, 1);
|
||||
lua_pushliteral(lua, "Function called from invalid context");
|
||||
lua_error(lua);
|
||||
}
|
||||
|
||||
struct mScriptEngineContextLua* luaContext = lua_touserdata(lua, -1);
|
||||
lua_pop(lua, 1);
|
||||
if (luaContext->lua != lua) {
|
||||
lua_pushliteral(lua, "Function called from invalid context");
|
||||
lua_error(lua);
|
||||
}
|
||||
|
||||
struct mScriptFrame frame;
|
||||
mScriptFrameInit(&frame);
|
||||
if (!_luaPopFrame(luaContext, &frame.arguments)) {
|
||||
mScriptFrameDeinit(&frame);
|
||||
lua_pushliteral(lua, "Error calling function (setting arguments)");
|
||||
lua_error(lua);
|
||||
}
|
||||
|
||||
struct mScriptValue* fn = lua_touserdata(lua, lua_upvalueindex(1));
|
||||
if (!fn || !mScriptInvoke(fn, &frame)) {
|
||||
mScriptFrameDeinit(&frame);
|
||||
lua_pushliteral(lua, "Error calling function (invoking)");
|
||||
lua_error(lua);
|
||||
}
|
||||
|
||||
if (!_luaPushFrame(luaContext, &frame.returnValues)) {
|
||||
mScriptFrameDeinit(&frame);
|
||||
lua_pushliteral(lua, "Error calling function (getting return values)");
|
||||
lua_error(lua);
|
||||
}
|
||||
mScriptFrameDeinit(&frame);
|
||||
|
||||
return lua_gettop(luaContext->lua);
|
||||
}
|
||||
|
|
|
@ -7,6 +7,17 @@
|
|||
|
||||
#include <mgba/internal/script/lua.h>
|
||||
|
||||
static int identityInt(int in) {
|
||||
return in;
|
||||
}
|
||||
|
||||
static int addInts(int a, int b) {
|
||||
return a + b;
|
||||
}
|
||||
|
||||
mSCRIPT_BIND_FUNCTION(boundIdentityInt, S32, identityInt, 1, S32);
|
||||
mSCRIPT_BIND_FUNCTION(boundAddInts, S32, addInts, 2, S32, S32);
|
||||
|
||||
M_TEST_SUITE_SETUP(mScriptLua) {
|
||||
if (mSCRIPT_ENGINE_LUA->init) {
|
||||
mSCRIPT_ENGINE_LUA->init(mSCRIPT_ENGINE_LUA);
|
||||
|
@ -214,7 +225,7 @@ M_TEST_DEFINE(callLuaFunc) {
|
|||
struct VFile* vf;
|
||||
const char* error;
|
||||
|
||||
program = "function a(b) return b + 1 end";
|
||||
program = "function a(b) return b + 1 end; function c(d, e) return d + e end";
|
||||
vf = VFileFromConstMemory(program, strlen(program));
|
||||
error = NULL;
|
||||
assert_true(lua->load(lua, vf, &error));
|
||||
|
@ -236,6 +247,56 @@ M_TEST_DEFINE(callLuaFunc) {
|
|||
mScriptFrameDeinit(&frame);
|
||||
mScriptValueDeref(fn);
|
||||
|
||||
fn = lua->getGlobal(lua, "c");
|
||||
assert_non_null(fn);
|
||||
assert_int_equal(fn->type->base, mSCRIPT_TYPE_FUNCTION);
|
||||
|
||||
mScriptFrameInit(&frame);
|
||||
mSCRIPT_PUSH(&frame.arguments, S32, 1);
|
||||
mSCRIPT_PUSH(&frame.arguments, S32, 2);
|
||||
assert_true(mScriptInvoke(fn, &frame));
|
||||
assert_true(mScriptPopS64(&frame.returnValues, &val));
|
||||
assert_int_equal(val, 3);
|
||||
|
||||
mScriptFrameDeinit(&frame);
|
||||
mScriptValueDeref(fn);
|
||||
|
||||
lua->destroy(lua);
|
||||
mScriptContextDeinit(&context);
|
||||
}
|
||||
|
||||
M_TEST_DEFINE(callCFunc) {
|
||||
struct mScriptContext context;
|
||||
mScriptContextInit(&context);
|
||||
struct mScriptEngineContext* lua = mSCRIPT_ENGINE_LUA->create(mSCRIPT_ENGINE_LUA, &context);
|
||||
|
||||
struct mScriptValue a = mSCRIPT_MAKE_S32(1);
|
||||
struct mScriptValue* val;
|
||||
const char* program;
|
||||
struct VFile* vf;
|
||||
const char* error;
|
||||
|
||||
program = "a = b(1); c = d(1, 2)";
|
||||
vf = VFileFromConstMemory(program, strlen(program));
|
||||
error = NULL;
|
||||
assert_true(lua->load(lua, vf, &error));
|
||||
assert_null(error);
|
||||
|
||||
assert_true(lua->setGlobal(lua, "b", &boundIdentityInt));
|
||||
assert_true(lua->setGlobal(lua, "d", &boundAddInts));
|
||||
assert_true(lua->run(lua));
|
||||
|
||||
val = lua->getGlobal(lua, "a");
|
||||
assert_non_null(val);
|
||||
assert_true(a.type->equal(&a, val));
|
||||
mScriptValueDeref(val);
|
||||
|
||||
a = mSCRIPT_MAKE_S32(3);
|
||||
val = lua->getGlobal(lua, "c");
|
||||
assert_non_null(val);
|
||||
assert_true(a.type->equal(&a, val));
|
||||
mScriptValueDeref(val);
|
||||
|
||||
lua->destroy(lua);
|
||||
mScriptContextDeinit(&context);
|
||||
}
|
||||
|
@ -247,4 +308,5 @@ M_TEST_SUITE_DEFINE_SETUP_TEARDOWN(mScriptLua,
|
|||
cmocka_unit_test(runNop),
|
||||
cmocka_unit_test(getGlobal),
|
||||
cmocka_unit_test(setGlobal),
|
||||
cmocka_unit_test(callLuaFunc))
|
||||
cmocka_unit_test(callLuaFunc),
|
||||
cmocka_unit_test(callCFunc))
|
||||
|
|
Loading…
Reference in New Issue