mirror of https://github.com/mgba-emu/mgba.git
Scripting: Add bitmask handling functions
This commit is contained in:
parent
d4c1ab1728
commit
00bd093fe3
|
@ -14,8 +14,9 @@ CXX_GUARD_START
|
|||
#include <mgba-util/table.h>
|
||||
#include <mgba-util/vfs.h>
|
||||
|
||||
#define mSCRIPT_KV_PAIR(KEY, VALUE) { #KEY, VALUE }
|
||||
#define mSCRIPT_CONSTANT_PAIR(NS, CONST) { #CONST, mScriptValueCreateFromSInt(NS ## _ ## CONST) }
|
||||
#define mSCRIPT_CONSTANT_SENTINEL { NULL, NULL }
|
||||
#define mSCRIPT_KV_SENTINEL { NULL, NULL }
|
||||
|
||||
struct mScriptFrame;
|
||||
struct mScriptFunction;
|
||||
|
@ -80,6 +81,7 @@ void mScriptContextClearWeakref(struct mScriptContext*, uint32_t weakref);
|
|||
|
||||
void mScriptContextAttachStdlib(struct mScriptContext* context);
|
||||
void mScriptContextExportConstants(struct mScriptContext* context, const char* nspace, struct mScriptKVPair* constants);
|
||||
void mScriptContextExportNamespace(struct mScriptContext* context, const char* nspace, struct mScriptKVPair* value);
|
||||
|
||||
void mScriptContextTriggerCallback(struct mScriptContext*, const char* callback);
|
||||
void mScriptContextAddCallback(struct mScriptContext*, const char* callback, struct mScriptValue* value);
|
||||
|
|
|
@ -41,6 +41,7 @@ CXX_GUARD_START
|
|||
#define mSCRIPT_TYPE_C_PS(X) void
|
||||
#define mSCRIPT_TYPE_C_PCS(X) void
|
||||
#define mSCRIPT_TYPE_C_WSTR struct mScriptValue*
|
||||
#define mSCRIPT_TYPE_C_WLIST struct mScriptValue*
|
||||
#define mSCRIPT_TYPE_C_W(X) struct mScriptValue*
|
||||
#define mSCRIPT_TYPE_C_CW(X) const struct mScriptValue*
|
||||
|
||||
|
@ -67,6 +68,7 @@ CXX_GUARD_START
|
|||
#define mSCRIPT_TYPE_FIELD_PS(STRUCT) opaque
|
||||
#define mSCRIPT_TYPE_FIELD_PCS(STRUCT) copaque
|
||||
#define mSCRIPT_TYPE_FIELD_WSTR opaque
|
||||
#define mSCRIPT_TYPE_FIELD_WLIST opaque
|
||||
#define mSCRIPT_TYPE_FIELD_W(TYPE) opaque
|
||||
#define mSCRIPT_TYPE_FIELD_CW(TYPE) opaque
|
||||
|
||||
|
@ -92,6 +94,7 @@ CXX_GUARD_START
|
|||
#define mSCRIPT_TYPE_MS_PS(STRUCT) (&mSTStructPtr_ ## STRUCT)
|
||||
#define mSCRIPT_TYPE_MS_PCS(STRUCT) (&mSTStructConstPtr_ ## STRUCT)
|
||||
#define mSCRIPT_TYPE_MS_WSTR (&mSTStringWrapper)
|
||||
#define mSCRIPT_TYPE_MS_WLIST (&mSTListWrapper)
|
||||
#define mSCRIPT_TYPE_MS_W(TYPE) (&mSTWrapper_ ## TYPE)
|
||||
#define mSCRIPT_TYPE_MS_CW(TYPE) (&mSTWrapperConst_ ## TYPE)
|
||||
|
||||
|
@ -116,6 +119,7 @@ CXX_GUARD_START
|
|||
#define mSCRIPT_TYPE_CMP_S_METHOD(STRUCT, NAME) mSCRIPT_TYPE_MS_S_METHOD(STRUCT, NAME)->name == _mSCRIPT_FIELD_NAME
|
||||
#define mSCRIPT_TYPE_CMP(TYPE0, TYPE1) mSCRIPT_TYPE_CMP_ ## TYPE0(TYPE1)
|
||||
#define mSCRIPT_TYPE_CMP_WSTR(TYPE) (mSCRIPT_TYPE_CMP_GENERIC(mSCRIPT_TYPE_MS_STR, TYPE) || mSCRIPT_TYPE_CMP_GENERIC(mSCRIPT_TYPE_MS_CHARP, TYPE))
|
||||
#define mSCRIPT_TYPE_CMP_WLIST(TYPE) (mSCRIPT_TYPE_CMP_GENERIC(mSCRIPT_TYPE_MS_LIST, TYPE))
|
||||
|
||||
enum mScriptTypeBase {
|
||||
mSCRIPT_TYPE_VOID = 0,
|
||||
|
@ -168,6 +172,7 @@ extern const struct mScriptType mSTTable;
|
|||
extern const struct mScriptType mSTWrapper;
|
||||
extern const struct mScriptType mSTWeakref;
|
||||
extern const struct mScriptType mSTStringWrapper;
|
||||
extern const struct mScriptType mSTListWrapper;
|
||||
|
||||
struct mScriptType;
|
||||
struct mScriptValue {
|
||||
|
|
|
@ -10,7 +10,9 @@ set(TEST_FILES
|
|||
|
||||
if(USE_LUA)
|
||||
list(APPEND SOURCE_FILES engines/lua.c)
|
||||
list(APPEND TEST_FILES test/lua.c)
|
||||
list(APPEND TEST_FILES
|
||||
test/stdlib.c
|
||||
test/lua.c)
|
||||
endif()
|
||||
|
||||
source_group("Scripting" FILES ${SOURCE_FILES})
|
||||
|
|
|
@ -237,6 +237,18 @@ void mScriptContextExportConstants(struct mScriptContext* context, const char* n
|
|||
mScriptValueDeref(table);
|
||||
}
|
||||
|
||||
void mScriptContextExportNamespace(struct mScriptContext* context, const char* nspace, struct mScriptKVPair* values) {
|
||||
struct mScriptValue* table = mScriptValueAlloc(mSCRIPT_TYPE_MS_TABLE);
|
||||
size_t i;
|
||||
for (i = 0; values[i].key; ++i) {
|
||||
struct mScriptValue* key = mScriptStringCreateFromUTF8(values[i].key);
|
||||
mScriptTableInsert(table, key, values[i].value);
|
||||
mScriptValueDeref(key);
|
||||
mScriptValueDeref(values[i].value);
|
||||
}
|
||||
mScriptContextSetGlobal(context, nspace, table);
|
||||
}
|
||||
|
||||
bool mScriptContextLoadVF(struct mScriptContext* context, const char* name, struct VFile* vf) {
|
||||
struct mScriptFileInfo info = {
|
||||
.name = name,
|
||||
|
|
|
@ -30,6 +30,38 @@ static void _mScriptCallbackAdd(struct mScriptCallbackManager* adapter, struct m
|
|||
mSCRIPT_DECLARE_STRUCT(mScriptCallbackManager);
|
||||
mSCRIPT_DECLARE_STRUCT_VOID_METHOD(mScriptCallbackManager, add, _mScriptCallbackAdd, 2, STR, callback, WRAPPER, function);
|
||||
|
||||
static uint64_t mScriptMakeBitmask(struct mScriptList* list) {
|
||||
size_t i;
|
||||
uint64_t mask = 0;
|
||||
for (i = 0; i < mScriptListSize(list); ++i) {
|
||||
struct mScriptValue bit;
|
||||
struct mScriptValue* value = mScriptListGetPointer(list, i);
|
||||
if (value->type->base == mSCRIPT_TYPE_WRAPPER) {
|
||||
value = mScriptValueUnwrap(value);
|
||||
}
|
||||
if (!mScriptCast(mSCRIPT_TYPE_MS_U64, value, &bit)) {
|
||||
continue;
|
||||
}
|
||||
mask |= 1ULL << bit.value.u64;
|
||||
}
|
||||
return mask;
|
||||
}
|
||||
|
||||
static struct mScriptValue* mScriptExpandBitmask(uint64_t mask) {
|
||||
struct mScriptValue* list = mScriptValueAlloc(mSCRIPT_TYPE_MS_LIST);
|
||||
size_t i;
|
||||
for (i = 0; mask; ++i, mask >>= 1) {
|
||||
if (!(mask & 1)) {
|
||||
continue;
|
||||
}
|
||||
*mScriptListAppend(list->value.list) = mSCRIPT_MAKE_U32(i);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
mSCRIPT_BIND_FUNCTION(mScriptMakeBitmask_Binding, U64, mScriptMakeBitmask, 1, LIST, bits);
|
||||
mSCRIPT_BIND_FUNCTION(mScriptExpandBitmask_Binding, WLIST, mScriptExpandBitmask, 1, U64, mask);
|
||||
|
||||
mSCRIPT_DEFINE_STRUCT(mScriptCallbackManager)
|
||||
mSCRIPT_DEFINE_CLASS_DOCSTRING(
|
||||
"A global singleton object `callbacks` used for managing callbacks. The following callbacks are defined:\n\n"
|
||||
|
@ -66,17 +98,17 @@ void mScriptContextAttachStdlib(struct mScriptContext* context) {
|
|||
mSCRIPT_CONSTANT_PAIR(SAVESTATE, RTC),
|
||||
mSCRIPT_CONSTANT_PAIR(SAVESTATE, METADATA),
|
||||
mSCRIPT_CONSTANT_PAIR(SAVESTATE, ALL),
|
||||
mSCRIPT_CONSTANT_SENTINEL
|
||||
mSCRIPT_KV_SENTINEL
|
||||
});
|
||||
mScriptContextExportConstants(context, "PLATFORM", (struct mScriptKVPair[]) {
|
||||
mSCRIPT_CONSTANT_PAIR(mPLATFORM, NONE),
|
||||
mSCRIPT_CONSTANT_PAIR(mPLATFORM, GBA),
|
||||
mSCRIPT_CONSTANT_PAIR(mPLATFORM, GB),
|
||||
mSCRIPT_CONSTANT_SENTINEL
|
||||
mSCRIPT_KV_SENTINEL
|
||||
});
|
||||
mScriptContextExportConstants(context, "CHECKSUM", (struct mScriptKVPair[]) {
|
||||
mSCRIPT_CONSTANT_PAIR(mCHECKSUM, CRC32),
|
||||
mSCRIPT_CONSTANT_SENTINEL
|
||||
mSCRIPT_KV_SENTINEL
|
||||
});
|
||||
#ifdef M_CORE_GBA
|
||||
mScriptContextExportConstants(context, "GBA_KEY", (struct mScriptKVPair[]) {
|
||||
|
@ -90,7 +122,7 @@ void mScriptContextAttachStdlib(struct mScriptContext* context) {
|
|||
mSCRIPT_CONSTANT_PAIR(GBA_KEY, DOWN),
|
||||
mSCRIPT_CONSTANT_PAIR(GBA_KEY, R),
|
||||
mSCRIPT_CONSTANT_PAIR(GBA_KEY, L),
|
||||
mSCRIPT_CONSTANT_SENTINEL
|
||||
mSCRIPT_KV_SENTINEL
|
||||
});
|
||||
#endif
|
||||
#ifdef M_CORE_GB
|
||||
|
@ -103,8 +135,14 @@ void mScriptContextAttachStdlib(struct mScriptContext* context) {
|
|||
mSCRIPT_CONSTANT_PAIR(GB_KEY, LEFT),
|
||||
mSCRIPT_CONSTANT_PAIR(GB_KEY, UP),
|
||||
mSCRIPT_CONSTANT_PAIR(GB_KEY, DOWN),
|
||||
mSCRIPT_CONSTANT_SENTINEL
|
||||
mSCRIPT_KV_SENTINEL
|
||||
});
|
||||
#endif
|
||||
mScriptContextSetGlobal(context, "C", context->constants);
|
||||
|
||||
mScriptContextExportNamespace(context, "util", (struct mScriptKVPair[]) {
|
||||
mSCRIPT_KV_PAIR(makeBitmask, &mScriptMakeBitmask_Binding),
|
||||
mSCRIPT_KV_PAIR(expandBitmask, &mScriptExpandBitmask_Binding),
|
||||
mSCRIPT_KV_SENTINEL
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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 "util/test/suite.h"
|
||||
|
||||
#include <mgba/internal/script/lua.h>
|
||||
#include <mgba/script/context.h>
|
||||
#include <mgba/script/types.h>
|
||||
|
||||
#define SETUP_LUA \
|
||||
struct mScriptContext context; \
|
||||
mScriptContextInit(&context); \
|
||||
struct mScriptEngineContext* lua = mScriptContextRegisterEngine(&context, mSCRIPT_ENGINE_LUA); \
|
||||
mScriptContextAttachStdlib(&context)
|
||||
|
||||
#define LOAD_PROGRAM(PROG) \
|
||||
do { \
|
||||
struct VFile* vf = VFileFromConstMemory(PROG, strlen(PROG)); \
|
||||
assert_true(lua->load(lua, NULL, vf)); \
|
||||
vf->close(vf); \
|
||||
} while(0)
|
||||
|
||||
#define TEST_PROGRAM(PROG) \
|
||||
LOAD_PROGRAM(PROG); \
|
||||
assert_true(lua->run(lua)); \
|
||||
|
||||
#define TEST_VALUE(TYPE, NAME, VALUE) \
|
||||
do { \
|
||||
struct mScriptValue val = mSCRIPT_MAKE(TYPE, VALUE); \
|
||||
struct mScriptValue* global = lua->getGlobal(lua, NAME); \
|
||||
assert_non_null(global); \
|
||||
assert_true(global->type->equal(global, &val)); \
|
||||
mScriptValueDeref(global); \
|
||||
} while(0)
|
||||
|
||||
M_TEST_SUITE_SETUP(mScriptStdlib) {
|
||||
if (mSCRIPT_ENGINE_LUA->init) {
|
||||
mSCRIPT_ENGINE_LUA->init(mSCRIPT_ENGINE_LUA);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
M_TEST_SUITE_TEARDOWN(mScriptStdlib) {
|
||||
if (mSCRIPT_ENGINE_LUA->deinit) {
|
||||
mSCRIPT_ENGINE_LUA->deinit(mSCRIPT_ENGINE_LUA);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
M_TEST_DEFINE(bitMask) {
|
||||
SETUP_LUA;
|
||||
|
||||
TEST_PROGRAM("assert(util)");
|
||||
TEST_PROGRAM("assert(util.makeBitmask)");
|
||||
TEST_PROGRAM("assert(util.makeBitmask{0} == 1)");
|
||||
TEST_PROGRAM("assert(util.makeBitmask{1} == 2)");
|
||||
TEST_PROGRAM("assert(util.makeBitmask{0, 1} == 3)");
|
||||
TEST_PROGRAM("assert(util.makeBitmask{1, 1} == 2)");
|
||||
|
||||
mScriptContextDeinit(&context);
|
||||
}
|
||||
|
||||
M_TEST_DEFINE(bitUnmask) {
|
||||
SETUP_LUA;
|
||||
|
||||
TEST_PROGRAM("assert(util)");
|
||||
TEST_PROGRAM("assert(util.expandBitmask)");
|
||||
TEST_PROGRAM("assert(#util.expandBitmask(0) == 0)");
|
||||
TEST_PROGRAM("assert(#util.expandBitmask(1) == 1)");
|
||||
TEST_PROGRAM("assert(util.expandBitmask(1)[1] == 0)");
|
||||
TEST_PROGRAM("assert(#util.expandBitmask(2) == 1)");
|
||||
TEST_PROGRAM("assert(util.expandBitmask(2)[1] == 1)");
|
||||
TEST_PROGRAM("assert(#util.expandBitmask(3) == 2)");
|
||||
TEST_PROGRAM("assert(util.expandBitmask(3)[1] == 0 or util.expandBitmask(3)[1] == 1)");
|
||||
TEST_PROGRAM("assert(util.expandBitmask(3)[2] == 0 or util.expandBitmask(3)[2] == 1)");
|
||||
TEST_PROGRAM("assert(#util.expandBitmask(6) == 2)");
|
||||
TEST_PROGRAM("assert(util.expandBitmask(6)[1] == 1 or util.expandBitmask(6)[1] == 2)");
|
||||
TEST_PROGRAM("assert(util.expandBitmask(6)[2] == 1 or util.expandBitmask(6)[2] == 2)");
|
||||
TEST_PROGRAM("assert(#util.expandBitmask(7) == 3)");
|
||||
TEST_PROGRAM("assert(#util.expandBitmask(11) == 3)");
|
||||
TEST_PROGRAM("assert(#util.expandBitmask(15) == 4)");
|
||||
|
||||
mScriptContextDeinit(&context);
|
||||
}
|
||||
|
||||
M_TEST_SUITE_DEFINE_SETUP_TEARDOWN(mScriptStdlib,
|
||||
cmocka_unit_test(bitMask),
|
||||
cmocka_unit_test(bitUnmask),
|
||||
)
|
|
@ -221,6 +221,15 @@ const struct mScriptType mSTStringWrapper = {
|
|||
.hash = NULL,
|
||||
};
|
||||
|
||||
const struct mScriptType mSTListWrapper = {
|
||||
.base = mSCRIPT_TYPE_WRAPPER,
|
||||
.size = sizeof(struct mScriptValue),
|
||||
.name = "wrapper list",
|
||||
.alloc = NULL,
|
||||
.free = NULL,
|
||||
.hash = NULL,
|
||||
};
|
||||
|
||||
const struct mScriptType mSTWeakref = {
|
||||
.base = mSCRIPT_TYPE_WEAKREF,
|
||||
.size = sizeof(uint32_t),
|
||||
|
|
Loading…
Reference in New Issue