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), \
|
.size = sizeof(struct STRUCT), \
|
||||||
.name = "struct::" #STRUCT, \
|
.name = "struct::" #STRUCT, \
|
||||||
.alloc = NULL, \
|
.alloc = NULL, \
|
||||||
.free = NULL, \
|
.free = mScriptObjectFree, \
|
||||||
.cast = mScriptObjectCast, \
|
.cast = mScriptObjectCast, \
|
||||||
.constType = &mSTStructConst_ ## STRUCT, \
|
.constType = &mSTStructConst_ ## STRUCT, \
|
||||||
}; \
|
}; \
|
||||||
|
@ -355,7 +355,6 @@ CXX_GUARD_START
|
||||||
return true; \
|
return true; \
|
||||||
} \
|
} \
|
||||||
|
|
||||||
|
|
||||||
#define mSCRIPT_DECLARE_STRUCT_D_METHOD(TYPE, RETURN, NAME, NPARAMS, ...) \
|
#define mSCRIPT_DECLARE_STRUCT_D_METHOD(TYPE, RETURN, NAME, NPARAMS, ...) \
|
||||||
mSCRIPT_DECLARE_STRUCT_METHOD(TYPE, RETURN, NAME, p0->NAME, NPARAMS, __VA_ARGS__)
|
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, ...) \
|
#define mSCRIPT_DECLARE_STRUCT_VOID_CD_METHOD(TYPE, NAME, NPARAMS, ...) \
|
||||||
mSCRIPT_DECLARE_STRUCT_VOID_C_METHOD(TYPE, NAME, p0->NAME, NPARAMS, __VA_ARGS__)
|
mSCRIPT_DECLARE_STRUCT_VOID_C_METHOD(TYPE, NAME, p0->NAME, NPARAMS, __VA_ARGS__)
|
||||||
|
|
||||||
#define mSCRIPT_DEFINE_STRUCT_METHOD_NAMED(TYPE, EXPORTED_NAME, NAME) { \
|
#define _mSCRIPT_DEFINE_STRUCT_BINDING(INIT_TYPE, TYPE, EXPORTED_NAME, NAME) { \
|
||||||
.type = mSCRIPT_CLASS_INIT_INSTANCE_MEMBER, \
|
.type = mSCRIPT_CLASS_INIT_ ## INIT_TYPE, \
|
||||||
.info = { \
|
.info = { \
|
||||||
.member = { \
|
.member = { \
|
||||||
.name = #EXPORTED_NAME, \
|
.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_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) { \
|
#define mSCRIPT_DEFINE_STRUCT_CAST_TO_MEMBER(TYPE, CAST_TYPE, MEMBER) { \
|
||||||
.type = mSCRIPT_CLASS_INIT_CAST_TO_MEMBER, \
|
.type = mSCRIPT_CLASS_INIT_CAST_TO_MEMBER, \
|
||||||
|
@ -495,6 +500,10 @@ enum mScriptClassInitType {
|
||||||
mSCRIPT_CLASS_INIT_INSTANCE_MEMBER,
|
mSCRIPT_CLASS_INIT_INSTANCE_MEMBER,
|
||||||
mSCRIPT_CLASS_INIT_INHERIT,
|
mSCRIPT_CLASS_INIT_INHERIT,
|
||||||
mSCRIPT_CLASS_INIT_CAST_TO_MEMBER,
|
mSCRIPT_CLASS_INIT_CAST_TO_MEMBER,
|
||||||
|
mSCRIPT_CLASS_INIT_INIT,
|
||||||
|
mSCRIPT_CLASS_INIT_DEINIT,
|
||||||
|
mSCRIPT_CLASS_INIT_GET,
|
||||||
|
mSCRIPT_CLASS_INIT_SET,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
|
@ -560,6 +569,10 @@ struct mScriptTypeClass {
|
||||||
const struct mScriptType* parent;
|
const struct mScriptType* parent;
|
||||||
struct Table instanceMembers;
|
struct Table instanceMembers;
|
||||||
struct Table castToMembers;
|
struct Table castToMembers;
|
||||||
|
struct mScriptClassMember* alloc; // TODO
|
||||||
|
struct mScriptClassMember* free;
|
||||||
|
struct mScriptClassMember* get;
|
||||||
|
struct mScriptClassMember* set; // TODO
|
||||||
};
|
};
|
||||||
|
|
||||||
struct mScriptValue;
|
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 mScriptObjectGetConst(const struct mScriptValue* obj, const char* member, struct mScriptValue*);
|
||||||
bool mScriptObjectSet(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) ;
|
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 mScriptPopS32(struct mScriptList* list, int32_t* out);
|
||||||
bool mScriptPopU32(struct mScriptList* list, uint32_t* out);
|
bool mScriptPopU32(struct mScriptList* list, uint32_t* out);
|
||||||
|
|
|
@ -38,6 +38,10 @@ struct TestD {
|
||||||
struct TestE {
|
struct TestE {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct TestF {
|
||||||
|
int* ref;
|
||||||
|
};
|
||||||
|
|
||||||
static int32_t testAi0(struct TestA* a) {
|
static int32_t testAi0(struct TestA* a) {
|
||||||
return a->i;
|
return a->i;
|
||||||
}
|
}
|
||||||
|
@ -67,6 +71,10 @@ static int32_t testGet(struct TestE* e, const char* name) {
|
||||||
return name[0];
|
return name[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void testDeinit(struct TestF* f) {
|
||||||
|
++*f->ref;
|
||||||
|
}
|
||||||
|
|
||||||
#define MEMBER_A_DOCSTRING "Member a"
|
#define MEMBER_A_DOCSTRING "Member a"
|
||||||
|
|
||||||
mSCRIPT_DECLARE_STRUCT(TestA);
|
mSCRIPT_DECLARE_STRUCT(TestA);
|
||||||
|
@ -124,6 +132,13 @@ mSCRIPT_DEFINE_STRUCT(TestE)
|
||||||
mSCRIPT_DEFINE_STRUCT_DEFAULT_GET(TestE)
|
mSCRIPT_DEFINE_STRUCT_DEFAULT_GET(TestE)
|
||||||
mSCRIPT_DEFINE_END;
|
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) {
|
M_TEST_DEFINE(testALayout) {
|
||||||
struct mScriptTypeClass* cls = mSCRIPT_TYPE_MS_S(TestA)->details.cls;
|
struct mScriptTypeClass* cls = mSCRIPT_TYPE_MS_S(TestA)->details.cls;
|
||||||
assert_false(cls->init);
|
assert_false(cls->init);
|
||||||
|
@ -910,6 +925,23 @@ M_TEST_DEFINE(testEGet) {
|
||||||
assert_false(cls->init);
|
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,
|
M_TEST_SUITE_DEFINE(mScriptClasses,
|
||||||
cmocka_unit_test(testALayout),
|
cmocka_unit_test(testALayout),
|
||||||
cmocka_unit_test(testASignatures),
|
cmocka_unit_test(testASignatures),
|
||||||
|
@ -924,4 +956,5 @@ M_TEST_SUITE_DEFINE(mScriptClasses,
|
||||||
cmocka_unit_test(testDGet),
|
cmocka_unit_test(testDGet),
|
||||||
cmocka_unit_test(testDSet),
|
cmocka_unit_test(testDSet),
|
||||||
cmocka_unit_test(testEGet),
|
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:
|
case mSCRIPT_CLASS_INIT_CAST_TO_MEMBER:
|
||||||
HashTableInsert(&cls->castToMembers, detail->info.castMember.type->name, (char*) detail->info.castMember.member);
|
HashTableInsert(&cls->castToMembers, detail->info.castMember.type->name, (char*) detail->info.castMember.member);
|
||||||
break;
|
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->instanceMembers, 0, free);
|
||||||
HashTableInit(&cls->castToMembers, 0, NULL);
|
HashTableInit(&cls->castToMembers, 0, NULL);
|
||||||
|
|
||||||
|
cls->alloc = NULL;
|
||||||
|
cls->free = NULL;
|
||||||
|
cls->get = NULL;
|
||||||
|
cls->set = NULL;
|
||||||
_mScriptClassInit(cls, cls->details, false);
|
_mScriptClassInit(cls, cls->details, false);
|
||||||
|
|
||||||
cls->init = true;
|
cls->init = true;
|
||||||
|
@ -934,7 +970,7 @@ bool mScriptObjectGet(struct mScriptValue* obj, const char* member, struct mScri
|
||||||
struct mScriptClassMember* m = HashTableLookup(&cls->instanceMembers, member);
|
struct mScriptClassMember* m = HashTableLookup(&cls->instanceMembers, member);
|
||||||
if (!m) {
|
if (!m) {
|
||||||
struct mScriptValue getMember;
|
struct mScriptValue getMember;
|
||||||
m = HashTableLookup(&cls->instanceMembers, "_get");
|
m = cls->get;
|
||||||
if (!m || !_accessRawMember(m, obj->value.opaque, obj->type->isConst, &getMember)) {
|
if (!m || !_accessRawMember(m, obj->value.opaque, obj->type->isConst, &getMember)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -1084,6 +1120,30 @@ bool mScriptObjectCast(const struct mScriptValue* input, const struct mScriptTyp
|
||||||
return false;
|
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) {
|
bool mScriptPopS32(struct mScriptList* list, int32_t* out) {
|
||||||
mSCRIPT_POP(list, S32, val);
|
mSCRIPT_POP(list, S32, val);
|
||||||
*out = val;
|
*out = val;
|
||||||
|
|
Loading…
Reference in New Issue