mirror of https://github.com/mgba-emu/mgba.git
Scripting: Add lambdas with 0 arguments and 0 return values
This commit is contained in:
parent
44ab21ab35
commit
b8261a0c66
|
@ -335,6 +335,8 @@ bool mScriptTableIteratorLookup(struct mScriptValue* table, struct TableIterator
|
|||
void mScriptFrameInit(struct mScriptFrame* frame);
|
||||
void mScriptFrameDeinit(struct mScriptFrame* frame);
|
||||
|
||||
struct mScriptValue* mScriptLambdaCreate0(struct mScriptValue* fn, struct mScriptList* args);
|
||||
|
||||
void mScriptClassInit(struct mScriptTypeClass* cls);
|
||||
void mScriptClassDeinit(struct mScriptTypeClass* cls);
|
||||
|
||||
|
|
|
@ -82,6 +82,10 @@ static bool isNullStruct(struct Test* arg) {
|
|||
return !arg;
|
||||
}
|
||||
|
||||
static void increment(struct Test* t) {
|
||||
++t->a;
|
||||
}
|
||||
|
||||
mSCRIPT_BIND_FUNCTION(boundVoidOne, S32, voidOne, 0);
|
||||
mSCRIPT_BIND_VOID_FUNCTION(boundDiscard, discard, 1, S32, ignored);
|
||||
mSCRIPT_BIND_FUNCTION(boundIdentityInt, S32, identityInt, 1, S32, in);
|
||||
|
@ -95,6 +99,7 @@ mSCRIPT_BIND_FUNCTION(boundIsSequential, S32, isSequential, 1, LIST, list);
|
|||
mSCRIPT_BIND_FUNCTION(boundIsNullCharp, BOOL, isNullCharp, 1, CHARP, arg);
|
||||
mSCRIPT_BIND_FUNCTION(boundIsNullStruct, BOOL, isNullStruct, 1, S(Test), arg);
|
||||
mSCRIPT_BIND_FUNCTION_WITH_DEFAULTS(boundAddIntWithDefaults, S32, addInts, 2, S32, a, S32, b);
|
||||
mSCRIPT_BIND_VOID_FUNCTION(boundIncrement, increment, 1, S(Test), this);
|
||||
|
||||
mSCRIPT_DEFINE_FUNCTION_BINDING_DEFAULTS(boundAddIntWithDefaults)
|
||||
mSCRIPT_NO_DEFAULT,
|
||||
|
@ -1336,6 +1341,28 @@ M_TEST_DEFINE(nullStruct) {
|
|||
mScriptFrameDeinit(&frame);
|
||||
}
|
||||
|
||||
M_TEST_DEFINE(lambda0) {
|
||||
struct mScriptList args;
|
||||
struct Test t = {
|
||||
.a = 0
|
||||
};
|
||||
|
||||
mScriptListInit(&args, 1);
|
||||
mSCRIPT_PUSH(&args, S(Test), &t);
|
||||
struct mScriptValue* fn = mScriptLambdaCreate0(&boundIncrement, &args);
|
||||
assert_non_null(fn);
|
||||
mScriptListDeinit(&args);
|
||||
|
||||
struct mScriptFrame frame;
|
||||
mScriptFrameInit(&frame);
|
||||
assert_int_equal(t.a, 0);
|
||||
assert_true(mScriptInvoke(fn, &frame));
|
||||
assert_int_equal(t.a, 1);
|
||||
mScriptFrameDeinit(&frame);
|
||||
|
||||
mScriptValueDeref(fn);
|
||||
}
|
||||
|
||||
M_TEST_SUITE_DEFINE(mScript,
|
||||
cmocka_unit_test(voidArgs),
|
||||
cmocka_unit_test(voidFunc),
|
||||
|
@ -1373,4 +1400,5 @@ M_TEST_SUITE_DEFINE(mScript,
|
|||
cmocka_unit_test(invokeList),
|
||||
cmocka_unit_test(nullString),
|
||||
cmocka_unit_test(nullStruct),
|
||||
cmocka_unit_test(lambda0),
|
||||
)
|
||||
|
|
|
@ -12,6 +12,11 @@
|
|||
#include <mgba-util/string.h>
|
||||
#include <mgba-util/table.h>
|
||||
|
||||
struct mScriptLambda {
|
||||
struct mScriptValue* fn;
|
||||
struct mScriptList arguments;
|
||||
};
|
||||
|
||||
static void _allocList(struct mScriptValue*);
|
||||
static void _freeList(struct mScriptValue*);
|
||||
|
||||
|
@ -47,6 +52,10 @@ static bool _boolEqual(const struct mScriptValue*, const struct mScriptValue*);
|
|||
static bool _charpEqual(const struct mScriptValue*, const struct mScriptValue*);
|
||||
static bool _stringEqual(const struct mScriptValue*, const struct mScriptValue*);
|
||||
|
||||
static void _lambdaAlloc(struct mScriptValue* val);
|
||||
static void _lambdaFree(struct mScriptValue* val);
|
||||
static bool _callLambda0(struct mScriptFrame* frame, void* context);
|
||||
|
||||
const struct mScriptType mSTVoid = {
|
||||
.base = mSCRIPT_TYPE_VOID,
|
||||
.size = 0,
|
||||
|
@ -268,6 +277,25 @@ const struct mScriptType mSTWeakref = {
|
|||
.hash = NULL,
|
||||
};
|
||||
|
||||
const struct mScriptType mSTLambda0 = {
|
||||
.base = mSCRIPT_TYPE_FUNCTION,
|
||||
.size = sizeof(struct mScriptLambda),
|
||||
.name = "lambda",
|
||||
.details = {
|
||||
.function = {
|
||||
.parameters = {
|
||||
.count = 0,
|
||||
},
|
||||
.returnType = {
|
||||
.count = 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
.alloc = _lambdaAlloc,
|
||||
.free = _lambdaFree,
|
||||
.hash = NULL,
|
||||
};
|
||||
|
||||
struct mScriptValue mScriptValueNull = {
|
||||
.type = &mSTVoid,
|
||||
.refs = mSCRIPT_VALUE_UNREF
|
||||
|
@ -826,6 +854,32 @@ bool _stringEqual(const struct mScriptValue* a, const struct mScriptValue* b) {
|
|||
return strncmp(valA, valB, lenA) == 0;
|
||||
}
|
||||
|
||||
void _lambdaAlloc(struct mScriptValue* value) {
|
||||
struct mScriptLambda* lambda = calloc(1, sizeof(*lambda));
|
||||
struct mScriptFunction* fn = calloc(1, sizeof(*fn));
|
||||
fn->context = lambda;
|
||||
mScriptListInit(&lambda->arguments, 0);
|
||||
value->value.opaque = fn;
|
||||
}
|
||||
|
||||
void _lambdaFree(struct mScriptValue* value) {
|
||||
struct mScriptFunction* fn = value->value.opaque;
|
||||
struct mScriptLambda* lambda = fn->context;
|
||||
size_t i;
|
||||
for (i = 0; i < mScriptListSize(&lambda->arguments); ++i) {
|
||||
struct mScriptValue* val = mScriptListGetPointer(&lambda->arguments, i);
|
||||
if (val->type->base != mSCRIPT_TYPE_WRAPPER) {
|
||||
continue;
|
||||
}
|
||||
val = mScriptValueUnwrap(val);
|
||||
mScriptValueDeref(val);
|
||||
}
|
||||
mScriptListDeinit(&lambda->arguments);
|
||||
mScriptValueDeref(lambda->fn);
|
||||
free(lambda);
|
||||
free(fn);
|
||||
}
|
||||
|
||||
struct mScriptValue* mScriptValueAlloc(const struct mScriptType* type) {
|
||||
// TODO: Use an arena instead of just the generic heap
|
||||
struct mScriptValue* val = malloc(sizeof(*val));
|
||||
|
@ -1074,6 +1128,44 @@ void mScriptFrameDeinit(struct mScriptFrame* frame) {
|
|||
mScriptListDeinit(&frame->arguments);
|
||||
}
|
||||
|
||||
struct mScriptValue* mScriptLambdaCreate0(struct mScriptValue* fn, struct mScriptList* args) {
|
||||
struct mScriptValue* value = mScriptValueAlloc(&mSTLambda0);
|
||||
struct mScriptFunction* lfn = value->value.opaque;
|
||||
struct mScriptLambda* lambda = lfn->context;
|
||||
lfn->call = _callLambda0;
|
||||
lambda->fn = fn;
|
||||
mScriptValueRef(fn);
|
||||
if (args) {
|
||||
mScriptListCopy(&lambda->arguments, args);
|
||||
size_t i;
|
||||
for (i = 0; i < mScriptListSize(args); ++i) {
|
||||
struct mScriptValue* val = mScriptListGetPointer(args, i);
|
||||
if (val->type->base != mSCRIPT_TYPE_WRAPPER) {
|
||||
continue;
|
||||
}
|
||||
val = mScriptValueUnwrap(val);
|
||||
mScriptValueRef(val);
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
bool _callLambda0(struct mScriptFrame* frame, void* context) {
|
||||
if (mScriptListSize(&frame->arguments)) {
|
||||
return false;
|
||||
}
|
||||
struct mScriptLambda* lambda = context;
|
||||
struct mScriptFrame subframe;
|
||||
mScriptFrameInit(&subframe);
|
||||
mScriptListCopy(&subframe.arguments, &lambda->arguments);
|
||||
bool ok = mScriptInvoke(lambda->fn, &subframe);
|
||||
if (mScriptListSize(&subframe.returnValues)) {
|
||||
ok = false;
|
||||
}
|
||||
mScriptFrameDeinit(&subframe);
|
||||
return ok;
|
||||
}
|
||||
|
||||
static void _mScriptClassInit(struct mScriptTypeClass* cls, const struct mScriptClassInitDetails* details, bool child) {
|
||||
const char* docstring = NULL;
|
||||
|
||||
|
|
Loading…
Reference in New Issue