mirror of https://github.com/mgba-emu/mgba.git
Scripting: Start bringing up Lua bindings
This commit is contained in:
parent
512572769e
commit
ce97d86906
|
@ -57,6 +57,7 @@ if(NOT LIBMGBA_ONLY)
|
|||
set(USE_LIBZIP ON CACHE BOOL "Whether or not to enable LIBZIP support")
|
||||
set(USE_SQLITE3 ON CACHE BOOL "Whether or not to enable SQLite3 support")
|
||||
set(USE_ELF ON CACHE BOOL "Whether or not to enable ELF support")
|
||||
set(USE_LUA ON CACHE BOOL "Whether or not to enable Lua scripting support")
|
||||
set(M_CORE_GBA ON CACHE BOOL "Build Game Boy Advance core")
|
||||
set(M_CORE_GB ON CACHE BOOL "Build Game Boy core")
|
||||
set(USE_LZMA ON CACHE BOOL "Whether or not to enable 7-Zip support")
|
||||
|
@ -735,6 +736,17 @@ endif()
|
|||
if(ENABLE_SCRIPTING)
|
||||
add_subdirectory(src/script)
|
||||
list(APPEND ENABLES SCRIPTING)
|
||||
if(NOT USE_LUA VERSION_LESS 5.1)
|
||||
find_feature(USE_LUA "Lua" ${USE_LUA})
|
||||
else()
|
||||
find_feature(USE_LUA "Lua")
|
||||
endif()
|
||||
if(USE_LUA)
|
||||
list(APPEND FEATURE_DEFINES USE_LUA)
|
||||
include_directories(AFTER ${LUA_INCLUDE_DIR})
|
||||
list(APPEND FEATURE_DEFINES LUA_VERSION_ONLY=\"${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}\")
|
||||
list(APPEND DEPENDENCY_LIB ${LUA_LIBRARY})
|
||||
endif()
|
||||
|
||||
if(BUILD_PYTHON)
|
||||
find_package(PythonLibs ${USE_PYTHON_VERSION})
|
||||
|
@ -1226,6 +1238,14 @@ if(NOT QUIET AND NOT LIBMGBA_ONLY)
|
|||
message(STATUS " ELF loading support: ${USE_ELF}")
|
||||
message(STATUS " Discord Rich Presence support: ${USE_DISCORD_RPC}")
|
||||
message(STATUS " OpenGL support: ${SUMMARY_GL}")
|
||||
message(STATUS "Scripting support: ${ENABLE_SCRIPTING}")
|
||||
if(ENABLE_SCRIPTING)
|
||||
if(LUA_VERSION_STRING)
|
||||
message(STATUS " Lua: ${LUA_VERSION_STRING}")
|
||||
else()
|
||||
message(STATUS " Lua: ${USE_LUA}")
|
||||
endif()
|
||||
endif()
|
||||
message(STATUS "Frontends:")
|
||||
message(STATUS " Qt: ${BUILD_QT}")
|
||||
message(STATUS " SDL (${SDL_VERSION}): ${BUILD_SDL}")
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
/* Copyright (c) 2013-2022 Jeffrey Pfau
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* 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/. */
|
||||
#ifndef M_SCRIPT_LUA_H
|
||||
#define M_SCRIPT_LUA_H
|
||||
#include <mgba/script/context.h>
|
||||
|
||||
extern struct mScriptEngine2* const mSCRIPT_ENGINE_LUA;
|
||||
|
||||
#endif
|
|
@ -6,6 +6,11 @@ set(SOURCE_FILES
|
|||
set(TEST_FILES
|
||||
test/types.c)
|
||||
|
||||
if(USE_LUA)
|
||||
list(APPEND SOURCE_FILES engines/lua.c)
|
||||
list(APPEND TEST_FILES test/lua.c)
|
||||
endif()
|
||||
|
||||
source_group("Scripting" FILES ${SOURCE_FILES})
|
||||
source_group("Scripting tests" FILES ${TEST_FILES})
|
||||
|
||||
|
|
|
@ -0,0 +1,91 @@
|
|||
/* Copyright (c) 2013-2022 Jeffrey Pfau
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* 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 <lauxlib.h>
|
||||
|
||||
static struct mScriptEngineContext* _luaCreate(struct mScriptEngine2*, struct mScriptContext*);
|
||||
|
||||
static void _luaDestroy(struct mScriptEngineContext*);
|
||||
static bool _luaLoad(struct mScriptEngineContext*, struct VFile*, const char** error);
|
||||
|
||||
struct mScriptEngineContextLua {
|
||||
struct mScriptEngineContext d;
|
||||
lua_State* lua;
|
||||
};
|
||||
|
||||
static struct mScriptEngineLua {
|
||||
struct mScriptEngine2 d;
|
||||
} _engineLua = {
|
||||
.d = {
|
||||
.name = "lua-" LUA_VERSION_ONLY,
|
||||
.init = NULL,
|
||||
.deinit = NULL,
|
||||
.create = _luaCreate
|
||||
}
|
||||
};
|
||||
|
||||
struct mScriptEngine2* const mSCRIPT_ENGINE_LUA = &_engineLua.d;
|
||||
|
||||
struct mScriptEngineContext* _luaCreate(struct mScriptEngine2* engine, struct mScriptContext* context) {
|
||||
UNUSED(engine);
|
||||
struct mScriptEngineContextLua* luaContext = calloc(1, sizeof(*luaContext));
|
||||
luaContext->d = (struct mScriptEngineContext) {
|
||||
.context = context,
|
||||
.destroy = _luaDestroy,
|
||||
.load = _luaLoad,
|
||||
};
|
||||
luaContext->lua = luaL_newstate();
|
||||
return &luaContext->d;
|
||||
}
|
||||
|
||||
void _luaDestroy(struct mScriptEngineContext* ctx) {
|
||||
struct mScriptEngineContextLua* luaContext = (struct mScriptEngineContextLua*) ctx;
|
||||
lua_close(luaContext->lua);
|
||||
free(luaContext);
|
||||
}
|
||||
|
||||
#define LUA_BLOCKSIZE 0x1000
|
||||
struct mScriptEngineLuaReader {
|
||||
struct VFile* vf;
|
||||
char block[LUA_BLOCKSIZE];
|
||||
};
|
||||
|
||||
static const char* _reader(lua_State* lua, void* context, size_t* size) {
|
||||
UNUSED(lua);
|
||||
struct mScriptEngineLuaReader* reader = context;
|
||||
ssize_t s = reader->vf->read(reader->vf, reader->block, sizeof(reader->block));
|
||||
if (s < 0) {
|
||||
return NULL;
|
||||
}
|
||||
*size = s;
|
||||
return reader->block;
|
||||
}
|
||||
|
||||
bool _luaLoad(struct mScriptEngineContext* ctx, struct VFile* vf, const char** error) {
|
||||
struct mScriptEngineContextLua* luaContext = (struct mScriptEngineContextLua*) ctx;
|
||||
struct mScriptEngineLuaReader data = {
|
||||
.vf = vf
|
||||
};
|
||||
int ret = lua_load(luaContext->lua, _reader, &data, NULL, "t");
|
||||
switch (ret) {
|
||||
case LUA_OK:
|
||||
if (error) {
|
||||
*error = NULL;
|
||||
}
|
||||
return true;
|
||||
case LUA_ERRSYNTAX:
|
||||
if (error) {
|
||||
*error = "Syntax error";
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (error) {
|
||||
*error = "Unknown error";
|
||||
}
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
/* Copyright (c) 2013-2022 Jeffrey Pfau
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* 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 "util/test/suite.h"
|
||||
|
||||
#include <mgba/internal/script/lua.h>
|
||||
|
||||
M_TEST_SUITE_SETUP(mScriptLua) {
|
||||
if (mSCRIPT_ENGINE_LUA->init) {
|
||||
mSCRIPT_ENGINE_LUA->init(mSCRIPT_ENGINE_LUA);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
M_TEST_SUITE_TEARDOWN(mScriptLua) {
|
||||
if (mSCRIPT_ENGINE_LUA->deinit) {
|
||||
mSCRIPT_ENGINE_LUA->deinit(mSCRIPT_ENGINE_LUA);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
M_TEST_DEFINE(create) {
|
||||
struct mScriptContext context;
|
||||
mScriptContextInit(&context);
|
||||
struct mScriptEngineContext* lua = mSCRIPT_ENGINE_LUA->create(mSCRIPT_ENGINE_LUA, &context);
|
||||
lua->destroy(lua);
|
||||
mScriptContextDeinit(&context);
|
||||
}
|
||||
|
||||
M_TEST_DEFINE(loadGood) {
|
||||
struct mScriptContext context;
|
||||
mScriptContextInit(&context);
|
||||
struct mScriptEngineContext* lua = mSCRIPT_ENGINE_LUA->create(mSCRIPT_ENGINE_LUA, &context);
|
||||
|
||||
const char* program = "-- test\n";
|
||||
struct VFile* vf = VFileFromConstMemory(program, strlen(program));
|
||||
const char* error = NULL;
|
||||
assert_true(lua->load(lua, vf, &error));
|
||||
assert_null(error);
|
||||
|
||||
lua->destroy(lua);
|
||||
mScriptContextDeinit(&context);
|
||||
}
|
||||
|
||||
M_TEST_DEFINE(loadSyntax) {
|
||||
struct mScriptContext context;
|
||||
mScriptContextInit(&context);
|
||||
struct mScriptEngineContext* lua = mSCRIPT_ENGINE_LUA->create(mSCRIPT_ENGINE_LUA, &context);
|
||||
|
||||
const char* program = "Invalid syntax! )\n";
|
||||
struct VFile* vf = VFileFromConstMemory(program, strlen(program));
|
||||
const char* error = NULL;
|
||||
assert_false(lua->load(lua, vf, &error));
|
||||
assert_non_null(error);
|
||||
|
||||
lua->destroy(lua);
|
||||
mScriptContextDeinit(&context);
|
||||
}
|
||||
|
||||
M_TEST_SUITE_DEFINE_SETUP_TEARDOWN(mScriptLua,
|
||||
cmocka_unit_test(create),
|
||||
cmocka_unit_test(loadGood),
|
||||
cmocka_unit_test(loadSyntax))
|
Loading…
Reference in New Issue