mirror of https://github.com/mgba-emu/mgba.git
Scripting: Allow basic pointer following
This commit is contained in:
parent
6d8060034f
commit
fc2b94f9f7
|
@ -304,6 +304,8 @@ void mScriptValueWrap(struct mScriptValue* val, struct mScriptValue* out);
|
|||
struct mScriptValue* mScriptValueUnwrap(struct mScriptValue* val);
|
||||
const struct mScriptValue* mScriptValueUnwrapConst(const struct mScriptValue* val);
|
||||
|
||||
void mScriptValueFollowPointer(struct mScriptValue* ptr, struct mScriptValue* out);
|
||||
|
||||
struct mScriptValue* mScriptStringCreateEmpty(size_t size);
|
||||
struct mScriptValue* mScriptStringCreateFromBytes(const void* string, size_t size);
|
||||
struct mScriptValue* mScriptStringCreateFromUTF8(const char* string);
|
||||
|
|
|
@ -693,6 +693,31 @@ bool _luaWrap(struct mScriptEngineContextLua* luaContext, struct mScriptValue* v
|
|||
return true;
|
||||
}
|
||||
}
|
||||
struct mScriptValue derefPtr;
|
||||
if (value->type->base == mSCRIPT_TYPE_OPAQUE) {
|
||||
if (!value->type->details.type) {
|
||||
return false;
|
||||
}
|
||||
mScriptValueFollowPointer(value, &derefPtr);
|
||||
switch (derefPtr.type->base) {
|
||||
case mSCRIPT_TYPE_VOID:
|
||||
case mSCRIPT_TYPE_SINT:
|
||||
case mSCRIPT_TYPE_UINT:
|
||||
case mSCRIPT_TYPE_FLOAT:
|
||||
value = &derefPtr;
|
||||
break;
|
||||
case mSCRIPT_TYPE_OBJECT:
|
||||
value = mScriptValueAlloc(derefPtr.type);
|
||||
value->value.opaque = derefPtr.value.opaque;
|
||||
weakref = mScriptContextSetWeakref(luaContext->d.context, value);
|
||||
needsWeakref = true;
|
||||
mScriptContextDisownWeakref(luaContext->d.context, weakref);
|
||||
mScriptValueDeref(value);
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (value->type == mSCRIPT_TYPE_MS_WEAKREF) {
|
||||
weakref = value->value.u32;
|
||||
value = mScriptContextAccessWeakref(luaContext->d.context, value);
|
||||
|
|
|
@ -22,6 +22,7 @@ struct Test {
|
|||
void (*vfn0)(struct Test*);
|
||||
void (*vfn1)(struct Test*, int);
|
||||
int32_t (*icfn0)(const struct Test*);
|
||||
struct Test* next;
|
||||
};
|
||||
|
||||
static int identityInt(int in) {
|
||||
|
@ -83,6 +84,7 @@ mSCRIPT_DECLARE_STRUCT_VOID_METHOD(Test, v1, testV1, 1, S32, b);
|
|||
|
||||
mSCRIPT_DEFINE_STRUCT(Test)
|
||||
mSCRIPT_DEFINE_STRUCT_MEMBER(Test, S32, i)
|
||||
mSCRIPT_DEFINE_STRUCT_MEMBER(Test, PS(Test), next)
|
||||
mSCRIPT_DEFINE_STRUCT_METHOD(Test, ifn0)
|
||||
mSCRIPT_DEFINE_STRUCT_METHOD(Test, ifn1)
|
||||
mSCRIPT_DEFINE_STRUCT_METHOD(Test, icfn0)
|
||||
|
@ -726,6 +728,42 @@ M_TEST_DEFINE(callList) {
|
|||
mScriptContextDeinit(&context);
|
||||
}
|
||||
|
||||
M_TEST_DEFINE(linkedList) {
|
||||
SETUP_LUA;
|
||||
|
||||
struct Test first = {
|
||||
.i = 1
|
||||
};
|
||||
struct Test second = {
|
||||
.i = 2
|
||||
};
|
||||
struct mScriptValue a = mSCRIPT_MAKE_S(Test, &first);
|
||||
|
||||
assert_true(lua->setGlobal(lua, "l", &a));
|
||||
TEST_PROGRAM("assert(l)");
|
||||
TEST_PROGRAM("assert(l.i == 1)");
|
||||
TEST_PROGRAM("assert(not l.next)");
|
||||
|
||||
first.next = &second;
|
||||
TEST_PROGRAM("assert(l)");
|
||||
TEST_PROGRAM("assert(l.i == 1)");
|
||||
TEST_PROGRAM("assert(l.next)");
|
||||
TEST_PROGRAM("assert(l.next.i == 2)");
|
||||
TEST_PROGRAM("assert(not l.next.next)");
|
||||
|
||||
TEST_PROGRAM(
|
||||
"n = l.next\n"
|
||||
"function readN()\n"
|
||||
" assert(n)\n"
|
||||
" assert(n.i or not n.i)\n"
|
||||
"end\n"
|
||||
"assert(pcall(readN))\n");
|
||||
// The weakref stored in `n` gets pruned between executions to avoid stale pointers
|
||||
TEST_PROGRAM("assert(not pcall(readN))");
|
||||
|
||||
mScriptContextDeinit(&context);
|
||||
}
|
||||
|
||||
M_TEST_SUITE_DEFINE_SETUP_TEARDOWN(mScriptLua,
|
||||
cmocka_unit_test(create),
|
||||
cmocka_unit_test(loadGood),
|
||||
|
@ -744,4 +782,5 @@ M_TEST_SUITE_DEFINE_SETUP_TEARDOWN(mScriptLua,
|
|||
cmocka_unit_test(tableLookup),
|
||||
cmocka_unit_test(tableIterate),
|
||||
cmocka_unit_test(callList),
|
||||
cmocka_unit_test(linkedList)
|
||||
)
|
||||
|
|
|
@ -853,6 +853,21 @@ const struct mScriptValue* mScriptValueUnwrapConst(const struct mScriptValue* va
|
|||
return NULL;
|
||||
}
|
||||
|
||||
void mScriptValueFollowPointer(struct mScriptValue* ptr, struct mScriptValue* out) {
|
||||
if (ptr->type->base != mSCRIPT_TYPE_OPAQUE || !ptr->type->details.type) {
|
||||
return;
|
||||
}
|
||||
|
||||
out->value.opaque = *(void**) ptr->value.opaque;
|
||||
if (out->value.opaque) {
|
||||
out->type = ptr->type->details.type;
|
||||
} else {
|
||||
out->type = mSCRIPT_TYPE_MS_VOID;
|
||||
}
|
||||
out->refs = mSCRIPT_VALUE_UNREF;
|
||||
out->flags = 0;
|
||||
}
|
||||
|
||||
struct mScriptValue* mScriptStringCreateEmpty(size_t size) {
|
||||
struct mScriptValue* val = mScriptValueAlloc(mSCRIPT_TYPE_MS_STR);
|
||||
struct mScriptString* internal = val->value.opaque;
|
||||
|
|
Loading…
Reference in New Issue