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 mScriptFrameInit(struct mScriptFrame* frame);
|
||||||
void mScriptFrameDeinit(struct mScriptFrame* frame);
|
void mScriptFrameDeinit(struct mScriptFrame* frame);
|
||||||
|
|
||||||
|
struct mScriptValue* mScriptLambdaCreate0(struct mScriptValue* fn, struct mScriptList* args);
|
||||||
|
|
||||||
void mScriptClassInit(struct mScriptTypeClass* cls);
|
void mScriptClassInit(struct mScriptTypeClass* cls);
|
||||||
void mScriptClassDeinit(struct mScriptTypeClass* cls);
|
void mScriptClassDeinit(struct mScriptTypeClass* cls);
|
||||||
|
|
||||||
|
|
|
@ -82,6 +82,10 @@ static bool isNullStruct(struct Test* arg) {
|
||||||
return !arg;
|
return !arg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void increment(struct Test* t) {
|
||||||
|
++t->a;
|
||||||
|
}
|
||||||
|
|
||||||
mSCRIPT_BIND_FUNCTION(boundVoidOne, S32, voidOne, 0);
|
mSCRIPT_BIND_FUNCTION(boundVoidOne, S32, voidOne, 0);
|
||||||
mSCRIPT_BIND_VOID_FUNCTION(boundDiscard, discard, 1, S32, ignored);
|
mSCRIPT_BIND_VOID_FUNCTION(boundDiscard, discard, 1, S32, ignored);
|
||||||
mSCRIPT_BIND_FUNCTION(boundIdentityInt, S32, identityInt, 1, S32, in);
|
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(boundIsNullCharp, BOOL, isNullCharp, 1, CHARP, arg);
|
||||||
mSCRIPT_BIND_FUNCTION(boundIsNullStruct, BOOL, isNullStruct, 1, S(Test), 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_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_DEFINE_FUNCTION_BINDING_DEFAULTS(boundAddIntWithDefaults)
|
||||||
mSCRIPT_NO_DEFAULT,
|
mSCRIPT_NO_DEFAULT,
|
||||||
|
@ -1336,6 +1341,28 @@ M_TEST_DEFINE(nullStruct) {
|
||||||
mScriptFrameDeinit(&frame);
|
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,
|
M_TEST_SUITE_DEFINE(mScript,
|
||||||
cmocka_unit_test(voidArgs),
|
cmocka_unit_test(voidArgs),
|
||||||
cmocka_unit_test(voidFunc),
|
cmocka_unit_test(voidFunc),
|
||||||
|
@ -1373,4 +1400,5 @@ M_TEST_SUITE_DEFINE(mScript,
|
||||||
cmocka_unit_test(invokeList),
|
cmocka_unit_test(invokeList),
|
||||||
cmocka_unit_test(nullString),
|
cmocka_unit_test(nullString),
|
||||||
cmocka_unit_test(nullStruct),
|
cmocka_unit_test(nullStruct),
|
||||||
|
cmocka_unit_test(lambda0),
|
||||||
)
|
)
|
||||||
|
|
|
@ -12,6 +12,11 @@
|
||||||
#include <mgba-util/string.h>
|
#include <mgba-util/string.h>
|
||||||
#include <mgba-util/table.h>
|
#include <mgba-util/table.h>
|
||||||
|
|
||||||
|
struct mScriptLambda {
|
||||||
|
struct mScriptValue* fn;
|
||||||
|
struct mScriptList arguments;
|
||||||
|
};
|
||||||
|
|
||||||
static void _allocList(struct mScriptValue*);
|
static void _allocList(struct mScriptValue*);
|
||||||
static void _freeList(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 _charpEqual(const struct mScriptValue*, const struct mScriptValue*);
|
||||||
static bool _stringEqual(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 = {
|
const struct mScriptType mSTVoid = {
|
||||||
.base = mSCRIPT_TYPE_VOID,
|
.base = mSCRIPT_TYPE_VOID,
|
||||||
.size = 0,
|
.size = 0,
|
||||||
|
@ -268,6 +277,25 @@ const struct mScriptType mSTWeakref = {
|
||||||
.hash = NULL,
|
.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 = {
|
struct mScriptValue mScriptValueNull = {
|
||||||
.type = &mSTVoid,
|
.type = &mSTVoid,
|
||||||
.refs = mSCRIPT_VALUE_UNREF
|
.refs = mSCRIPT_VALUE_UNREF
|
||||||
|
@ -826,6 +854,32 @@ bool _stringEqual(const struct mScriptValue* a, const struct mScriptValue* b) {
|
||||||
return strncmp(valA, valB, lenA) == 0;
|
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) {
|
struct mScriptValue* mScriptValueAlloc(const struct mScriptType* type) {
|
||||||
// TODO: Use an arena instead of just the generic heap
|
// TODO: Use an arena instead of just the generic heap
|
||||||
struct mScriptValue* val = malloc(sizeof(*val));
|
struct mScriptValue* val = malloc(sizeof(*val));
|
||||||
|
@ -1074,6 +1128,44 @@ void mScriptFrameDeinit(struct mScriptFrame* frame) {
|
||||||
mScriptListDeinit(&frame->arguments);
|
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) {
|
static void _mScriptClassInit(struct mScriptTypeClass* cls, const struct mScriptClassInitDetails* details, bool child) {
|
||||||
const char* docstring = NULL;
|
const char* docstring = NULL;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue