Scripting: Add bitmask handling functions

This commit is contained in:
Vicki Pfau 2022-06-05 02:04:09 -07:00
parent d4c1ab1728
commit 00bd093fe3
7 changed files with 166 additions and 7 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

91
src/script/test/stdlib.c Normal file
View File

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

View File

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