mirror of https://github.com/mgba-emu/mgba.git
Scripting: Start bringing up constructors/destructors
This commit is contained in:
parent
bbf6d94fe2
commit
076299a5f6
|
@ -208,7 +208,7 @@ CXX_GUARD_START
|
|||
.size = sizeof(struct STRUCT), \
|
||||
.name = "struct::" #STRUCT, \
|
||||
.alloc = NULL, \
|
||||
.free = NULL, \
|
||||
.free = mScriptObjectFree, \
|
||||
.cast = mScriptObjectCast, \
|
||||
.constType = &mSTStructConst_ ## STRUCT, \
|
||||
}; \
|
||||
|
@ -355,7 +355,6 @@ CXX_GUARD_START
|
|||
return true; \
|
||||
} \
|
||||
|
||||
|
||||
#define mSCRIPT_DECLARE_STRUCT_D_METHOD(TYPE, RETURN, NAME, NPARAMS, ...) \
|
||||
mSCRIPT_DECLARE_STRUCT_METHOD(TYPE, RETURN, NAME, p0->NAME, NPARAMS, __VA_ARGS__)
|
||||
|
||||
|
@ -368,8 +367,8 @@ CXX_GUARD_START
|
|||
#define mSCRIPT_DECLARE_STRUCT_VOID_CD_METHOD(TYPE, NAME, NPARAMS, ...) \
|
||||
mSCRIPT_DECLARE_STRUCT_VOID_C_METHOD(TYPE, NAME, p0->NAME, NPARAMS, __VA_ARGS__)
|
||||
|
||||
#define mSCRIPT_DEFINE_STRUCT_METHOD_NAMED(TYPE, EXPORTED_NAME, NAME) { \
|
||||
.type = mSCRIPT_CLASS_INIT_INSTANCE_MEMBER, \
|
||||
#define _mSCRIPT_DEFINE_STRUCT_BINDING(INIT_TYPE, TYPE, EXPORTED_NAME, NAME) { \
|
||||
.type = mSCRIPT_CLASS_INIT_ ## INIT_TYPE, \
|
||||
.info = { \
|
||||
.member = { \
|
||||
.name = #EXPORTED_NAME, \
|
||||
|
@ -378,9 +377,15 @@ CXX_GUARD_START
|
|||
}, \
|
||||
},
|
||||
|
||||
#define mSCRIPT_DEFINE_STRUCT_METHOD_NAMED(TYPE, EXPORTED_NAME, NAME) \
|
||||
_mSCRIPT_DEFINE_STRUCT_BINDING(INSTANCE_MEMBER, TYPE, EXPORTED_NAME, NAME)
|
||||
|
||||
#define mSCRIPT_DEFINE_STRUCT_METHOD(TYPE, NAME) mSCRIPT_DEFINE_STRUCT_METHOD_NAMED(TYPE, NAME, NAME)
|
||||
|
||||
#define mSCRIPT_DEFINE_STRUCT_DEFAULT_GET(TYPE) mSCRIPT_DEFINE_STRUCT_METHOD_NAMED(TYPE, _get, _get)
|
||||
#define mSCRIPT_DEFINE_STRUCT_INIT(TYPE) _mSCRIPT_DEFINE_STRUCT_BINDING(INIT, TYPE, _init, _init)
|
||||
#define mSCRIPT_DEFINE_STRUCT_DEINIT(TYPE) _mSCRIPT_DEFINE_STRUCT_BINDING(DEINIT, TYPE, _deinit, _deinit)
|
||||
#define mSCRIPT_DEFINE_STRUCT_DEFAULT_GET(TYPE) _mSCRIPT_DEFINE_STRUCT_BINDING(GET, TYPE, _get, _get)
|
||||
#define mSCRIPT_DEFINE_STRUCT_DEFAULT_SET(TYPE) _mSCRIPT_DEFINE_STRUCT_BINDING(SET, TYPE, _set, _set)
|
||||
|
||||
#define mSCRIPT_DEFINE_STRUCT_CAST_TO_MEMBER(TYPE, CAST_TYPE, MEMBER) { \
|
||||
.type = mSCRIPT_CLASS_INIT_CAST_TO_MEMBER, \
|
||||
|
@ -495,6 +500,10 @@ enum mScriptClassInitType {
|
|||
mSCRIPT_CLASS_INIT_INSTANCE_MEMBER,
|
||||
mSCRIPT_CLASS_INIT_INHERIT,
|
||||
mSCRIPT_CLASS_INIT_CAST_TO_MEMBER,
|
||||
mSCRIPT_CLASS_INIT_INIT,
|
||||
mSCRIPT_CLASS_INIT_DEINIT,
|
||||
mSCRIPT_CLASS_INIT_GET,
|
||||
mSCRIPT_CLASS_INIT_SET,
|
||||
};
|
||||
|
||||
enum {
|
||||
|
@ -560,6 +569,10 @@ struct mScriptTypeClass {
|
|||
const struct mScriptType* parent;
|
||||
struct Table instanceMembers;
|
||||
struct Table castToMembers;
|
||||
struct mScriptClassMember* alloc; // TODO
|
||||
struct mScriptClassMember* free;
|
||||
struct mScriptClassMember* get;
|
||||
struct mScriptClassMember* set; // TODO
|
||||
};
|
||||
|
||||
struct mScriptValue;
|
||||
|
@ -643,6 +656,7 @@ bool mScriptObjectGet(struct mScriptValue* obj, const char* member, struct mScri
|
|||
bool mScriptObjectGetConst(const struct mScriptValue* obj, const char* member, struct mScriptValue*);
|
||||
bool mScriptObjectSet(struct mScriptValue* obj, const char* member, struct mScriptValue*);
|
||||
bool mScriptObjectCast(const struct mScriptValue* input, const struct mScriptType* type, struct mScriptValue* output) ;
|
||||
void mScriptObjectFree(struct mScriptValue* obj);
|
||||
|
||||
bool mScriptPopS32(struct mScriptList* list, int32_t* out);
|
||||
bool mScriptPopU32(struct mScriptList* list, uint32_t* out);
|
||||
|
|
|
@ -38,6 +38,10 @@ struct TestD {
|
|||
struct TestE {
|
||||
};
|
||||
|
||||
struct TestF {
|
||||
int* ref;
|
||||
};
|
||||
|
||||
static int32_t testAi0(struct TestA* a) {
|
||||
return a->i;
|
||||
}
|
||||
|
@ -67,6 +71,10 @@ static int32_t testGet(struct TestE* e, const char* name) {
|
|||
return name[0];
|
||||
}
|
||||
|
||||
static void testDeinit(struct TestF* f) {
|
||||
++*f->ref;
|
||||
}
|
||||
|
||||
#define MEMBER_A_DOCSTRING "Member a"
|
||||
|
||||
mSCRIPT_DECLARE_STRUCT(TestA);
|
||||
|
@ -124,6 +132,13 @@ mSCRIPT_DEFINE_STRUCT(TestE)
|
|||
mSCRIPT_DEFINE_STRUCT_DEFAULT_GET(TestE)
|
||||
mSCRIPT_DEFINE_END;
|
||||
|
||||
mSCRIPT_DECLARE_STRUCT(TestF);
|
||||
mSCRIPT_DECLARE_STRUCT_VOID_METHOD(TestF, _deinit, testDeinit, 0);
|
||||
|
||||
mSCRIPT_DEFINE_STRUCT(TestF)
|
||||
mSCRIPT_DEFINE_STRUCT_DEINIT(TestF)
|
||||
mSCRIPT_DEFINE_END;
|
||||
|
||||
M_TEST_DEFINE(testALayout) {
|
||||
struct mScriptTypeClass* cls = mSCRIPT_TYPE_MS_S(TestA)->details.cls;
|
||||
assert_false(cls->init);
|
||||
|
@ -910,6 +925,23 @@ M_TEST_DEFINE(testEGet) {
|
|||
assert_false(cls->init);
|
||||
}
|
||||
|
||||
M_TEST_DEFINE(testFDeinit) {
|
||||
struct mScriptTypeClass* cls = mSCRIPT_TYPE_MS_S(TestF)->details.cls;
|
||||
|
||||
int ref = 0;
|
||||
struct TestF* s = calloc(1, sizeof(struct TestF));
|
||||
s->ref = &ref;
|
||||
struct mScriptValue* val = mScriptValueAlloc(mSCRIPT_TYPE_MS_S(TestF));
|
||||
val->value.opaque = s;
|
||||
val->flags = mSCRIPT_VALUE_FLAG_FREE_BUFFER;
|
||||
mScriptValueDeref(val);
|
||||
assert_int_equal(ref, 1);
|
||||
|
||||
assert_true(cls->init);
|
||||
mScriptClassDeinit(cls);
|
||||
assert_false(cls->init);
|
||||
}
|
||||
|
||||
M_TEST_SUITE_DEFINE(mScriptClasses,
|
||||
cmocka_unit_test(testALayout),
|
||||
cmocka_unit_test(testASignatures),
|
||||
|
@ -924,4 +956,5 @@ M_TEST_SUITE_DEFINE(mScriptClasses,
|
|||
cmocka_unit_test(testDGet),
|
||||
cmocka_unit_test(testDSet),
|
||||
cmocka_unit_test(testEGet),
|
||||
cmocka_unit_test(testFDeinit),
|
||||
)
|
||||
|
|
|
@ -806,6 +806,38 @@ static void _mScriptClassInit(struct mScriptTypeClass* cls, const struct mScript
|
|||
case mSCRIPT_CLASS_INIT_CAST_TO_MEMBER:
|
||||
HashTableInsert(&cls->castToMembers, detail->info.castMember.type->name, (char*) detail->info.castMember.member);
|
||||
break;
|
||||
case mSCRIPT_CLASS_INIT_INIT:
|
||||
cls->alloc = calloc(1, sizeof(*member));
|
||||
memcpy(cls->alloc, &detail->info.member, sizeof(*member));
|
||||
if (docstring) {
|
||||
cls->alloc->docstring = docstring;
|
||||
docstring = NULL;
|
||||
}
|
||||
break;
|
||||
case mSCRIPT_CLASS_INIT_DEINIT:
|
||||
cls->free = calloc(1, sizeof(*member));
|
||||
memcpy(cls->free, &detail->info.member, sizeof(*member));
|
||||
if (docstring) {
|
||||
cls->free->docstring = docstring;
|
||||
docstring = NULL;
|
||||
}
|
||||
break;
|
||||
case mSCRIPT_CLASS_INIT_GET:
|
||||
cls->get = calloc(1, sizeof(*member));
|
||||
memcpy(cls->get, &detail->info.member, sizeof(*member));
|
||||
if (docstring) {
|
||||
cls->get->docstring = docstring;
|
||||
docstring = NULL;
|
||||
}
|
||||
break;
|
||||
case mSCRIPT_CLASS_INIT_SET:
|
||||
cls->set = calloc(1, sizeof(*member));
|
||||
memcpy(cls->set, &detail->info.member, sizeof(*member));
|
||||
if (docstring) {
|
||||
cls->set->docstring = docstring;
|
||||
docstring = NULL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -817,6 +849,10 @@ void mScriptClassInit(struct mScriptTypeClass* cls) {
|
|||
HashTableInit(&cls->instanceMembers, 0, free);
|
||||
HashTableInit(&cls->castToMembers, 0, NULL);
|
||||
|
||||
cls->alloc = NULL;
|
||||
cls->free = NULL;
|
||||
cls->get = NULL;
|
||||
cls->set = NULL;
|
||||
_mScriptClassInit(cls, cls->details, false);
|
||||
|
||||
cls->init = true;
|
||||
|
@ -934,7 +970,7 @@ bool mScriptObjectGet(struct mScriptValue* obj, const char* member, struct mScri
|
|||
struct mScriptClassMember* m = HashTableLookup(&cls->instanceMembers, member);
|
||||
if (!m) {
|
||||
struct mScriptValue getMember;
|
||||
m = HashTableLookup(&cls->instanceMembers, "_get");
|
||||
m = cls->get;
|
||||
if (!m || !_accessRawMember(m, obj->value.opaque, obj->type->isConst, &getMember)) {
|
||||
return false;
|
||||
}
|
||||
|
@ -1084,6 +1120,30 @@ bool mScriptObjectCast(const struct mScriptValue* input, const struct mScriptTyp
|
|||
return false;
|
||||
}
|
||||
|
||||
void mScriptObjectFree(struct mScriptValue* value) {
|
||||
if (value->type->base != mSCRIPT_TYPE_OBJECT) {
|
||||
return;
|
||||
}
|
||||
if (value->flags & mSCRIPT_VALUE_FLAG_FREE_BUFFER) {
|
||||
mScriptClassInit(value->type->details.cls);
|
||||
if (value->type->details.cls->free) {
|
||||
struct mScriptValue deinitMember;
|
||||
if (_accessRawMember(value->type->details.cls->free, value->value.opaque, value->type->isConst, &deinitMember)) {
|
||||
struct mScriptFrame frame;
|
||||
mScriptFrameInit(&frame);
|
||||
struct mScriptValue* this = mScriptListAppend(&frame.arguments);
|
||||
this->type = mSCRIPT_TYPE_MS_WRAPPER;
|
||||
this->refs = mSCRIPT_VALUE_UNREF;
|
||||
this->flags = 0;
|
||||
this->value.opaque = value;
|
||||
mScriptInvoke(&deinitMember, &frame);
|
||||
mScriptFrameDeinit(&frame);
|
||||
}
|
||||
}
|
||||
free(value->value.opaque);
|
||||
}
|
||||
}
|
||||
|
||||
bool mScriptPopS32(struct mScriptList* list, int32_t* out) {
|
||||
mSCRIPT_POP(list, S32, val);
|
||||
*out = val;
|
||||
|
|
Loading…
Reference in New Issue