mirror of https://github.com/mgba-emu/mgba.git
Scripting: Add basic inheritance + struct struct member access + const casting
This commit is contained in:
parent
9ddada00f2
commit
7c9ea1ec9b
|
@ -202,6 +202,7 @@ CXX_GUARD_START
|
||||||
.alloc = NULL, \
|
.alloc = NULL, \
|
||||||
.free = NULL, \
|
.free = NULL, \
|
||||||
.cast = _mSTStructCast_ ## STRUCT, \
|
.cast = _mSTStructCast_ ## STRUCT, \
|
||||||
|
.constType = &mSTStructConst_ ## STRUCT, \
|
||||||
}; \
|
}; \
|
||||||
const struct mScriptType mSTStructConst_ ## STRUCT = { \
|
const struct mScriptType mSTStructConst_ ## STRUCT = { \
|
||||||
.base = mSCRIPT_TYPE_OBJECT, \
|
.base = mSCRIPT_TYPE_OBJECT, \
|
||||||
|
@ -255,6 +256,13 @@ CXX_GUARD_START
|
||||||
}, \
|
}, \
|
||||||
},
|
},
|
||||||
|
|
||||||
|
#define mSCRIPT_DEFINE_INHERIT(PARENT) { \
|
||||||
|
.type = mSCRIPT_CLASS_INIT_INHERIT, \
|
||||||
|
.info = { \
|
||||||
|
.parent = mSCRIPT_TYPE_MS_S(PARENT) \
|
||||||
|
} \
|
||||||
|
},
|
||||||
|
|
||||||
#define _mSCRIPT_STRUCT_METHOD_POP(TYPE, S, NPARAMS, ...) \
|
#define _mSCRIPT_STRUCT_METHOD_POP(TYPE, S, NPARAMS, ...) \
|
||||||
_mDEFER(_mDEFER(_mCAT(mSCRIPT_POP_, _mSUCC ## NPARAMS)) (&frame->arguments, _mCOMMA_ ## NPARAMS(S(TYPE), __VA_ARGS__))); \
|
_mDEFER(_mDEFER(_mCAT(mSCRIPT_POP_, _mSUCC ## NPARAMS)) (&frame->arguments, _mCOMMA_ ## NPARAMS(S(TYPE), __VA_ARGS__))); \
|
||||||
if (mScriptListSize(&frame->arguments)) { \
|
if (mScriptListSize(&frame->arguments)) { \
|
||||||
|
@ -493,7 +501,7 @@ struct mScriptClassInitDetails {
|
||||||
enum mScriptClassInitType type;
|
enum mScriptClassInitType type;
|
||||||
union {
|
union {
|
||||||
const char* comment;
|
const char* comment;
|
||||||
const struct mScriptTypeClass* parent;
|
const struct mScriptType* parent;
|
||||||
struct mScriptClassMember member;
|
struct mScriptClassMember member;
|
||||||
} info;
|
} info;
|
||||||
};
|
};
|
||||||
|
@ -501,6 +509,7 @@ struct mScriptClassInitDetails {
|
||||||
struct mScriptTypeClass {
|
struct mScriptTypeClass {
|
||||||
bool init;
|
bool init;
|
||||||
const struct mScriptClassInitDetails* details;
|
const struct mScriptClassInitDetails* details;
|
||||||
|
const struct mScriptType* parent;
|
||||||
struct Table staticMembers;
|
struct Table staticMembers;
|
||||||
struct Table instanceMembers;
|
struct Table instanceMembers;
|
||||||
};
|
};
|
||||||
|
@ -518,6 +527,7 @@ struct mScriptType {
|
||||||
struct mScriptTypeClass* cls;
|
struct mScriptTypeClass* cls;
|
||||||
void* opaque;
|
void* opaque;
|
||||||
} details;
|
} details;
|
||||||
|
const struct mScriptType* constType;
|
||||||
void (*alloc)(struct mScriptValue*);
|
void (*alloc)(struct mScriptValue*);
|
||||||
void (*free)(struct mScriptValue*);
|
void (*free)(struct mScriptValue*);
|
||||||
uint32_t (*hash)(const struct mScriptValue*);
|
uint32_t (*hash)(const struct mScriptValue*);
|
||||||
|
|
|
@ -21,6 +21,20 @@ struct TestA {
|
||||||
int32_t (*icfn1)(const struct TestA*, int);
|
int32_t (*icfn1)(const struct TestA*, int);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct TestB {
|
||||||
|
struct TestA d;
|
||||||
|
int32_t i3;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct TestC {
|
||||||
|
int32_t i;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct TestD {
|
||||||
|
struct TestC a;
|
||||||
|
struct TestC b;
|
||||||
|
};
|
||||||
|
|
||||||
static int32_t testAi0(struct TestA* a) {
|
static int32_t testAi0(struct TestA* a) {
|
||||||
return a->i;
|
return a->i;
|
||||||
}
|
}
|
||||||
|
@ -87,7 +101,24 @@ mSCRIPT_DEFINE_STRUCT(TestA)
|
||||||
mSCRIPT_DEFINE_STATIC_MEMBER(S16, s_hUnaligned)
|
mSCRIPT_DEFINE_STATIC_MEMBER(S16, s_hUnaligned)
|
||||||
mSCRIPT_DEFINE_END;
|
mSCRIPT_DEFINE_END;
|
||||||
|
|
||||||
|
mSCRIPT_DEFINE_STRUCT(TestB)
|
||||||
|
mSCRIPT_DEFINE_INHERIT(TestA)
|
||||||
|
mSCRIPT_DEFINE_STRUCT_MEMBER(TestB, S32, i3)
|
||||||
|
mSCRIPT_DEFINE_END;
|
||||||
|
|
||||||
|
mSCRIPT_DEFINE_STRUCT(TestC)
|
||||||
|
mSCRIPT_DEFINE_STRUCT_MEMBER(TestC, S32, i)
|
||||||
|
mSCRIPT_DEFINE_END;
|
||||||
|
|
||||||
|
mSCRIPT_DEFINE_STRUCT(TestD)
|
||||||
|
mSCRIPT_DEFINE_STRUCT_MEMBER(TestD, S(TestC), a)
|
||||||
|
mSCRIPT_DEFINE_STRUCT_MEMBER(TestD, S(TestC), b)
|
||||||
|
mSCRIPT_DEFINE_END;
|
||||||
|
|
||||||
mSCRIPT_EXPORT_STRUCT(TestA);
|
mSCRIPT_EXPORT_STRUCT(TestA);
|
||||||
|
mSCRIPT_EXPORT_STRUCT(TestB);
|
||||||
|
mSCRIPT_EXPORT_STRUCT(TestC);
|
||||||
|
mSCRIPT_EXPORT_STRUCT(TestD);
|
||||||
|
|
||||||
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;
|
||||||
|
@ -492,9 +523,331 @@ M_TEST_DEFINE(testADynamic) {
|
||||||
assert_false(cls->init);
|
assert_false(cls->init);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
M_TEST_DEFINE(testBLayout) {
|
||||||
|
struct mScriptTypeClass* cls = mSCRIPT_TYPE_MS_S(TestB)->details.cls;
|
||||||
|
assert_false(cls->init);
|
||||||
|
mScriptClassInit(cls);
|
||||||
|
assert_true(cls->init);
|
||||||
|
|
||||||
|
struct mScriptClassMember* member;
|
||||||
|
|
||||||
|
// Instance members
|
||||||
|
member = HashTableLookup(&cls->instanceMembers, "i");
|
||||||
|
assert_non_null(member);
|
||||||
|
assert_string_equal(member->name, "i");
|
||||||
|
assert_string_equal(member->docstring, MEMBER_A_DOCSTRING);
|
||||||
|
assert_ptr_equal(member->type, mSCRIPT_TYPE_MS_S32);
|
||||||
|
assert_int_equal(member->offset, 0);
|
||||||
|
|
||||||
|
member = HashTableLookup(&cls->instanceMembers, "i2");
|
||||||
|
assert_non_null(member);
|
||||||
|
assert_string_equal(member->name, "i2");
|
||||||
|
assert_null(member->docstring);
|
||||||
|
assert_ptr_equal(member->type, mSCRIPT_TYPE_MS_S32);
|
||||||
|
assert_int_equal(member->offset, sizeof(int32_t));
|
||||||
|
|
||||||
|
member = HashTableLookup(&cls->instanceMembers, "b8");
|
||||||
|
assert_non_null(member);
|
||||||
|
assert_string_equal(member->name, "b8");
|
||||||
|
assert_null(member->docstring);
|
||||||
|
assert_ptr_equal(member->type, mSCRIPT_TYPE_MS_S8);
|
||||||
|
assert_int_equal(member->offset, sizeof(int32_t) * 2);
|
||||||
|
|
||||||
|
member = HashTableLookup(&cls->instanceMembers, "hUnaligned");
|
||||||
|
assert_non_null(member);
|
||||||
|
assert_string_equal(member->name, "hUnaligned");
|
||||||
|
assert_null(member->docstring);
|
||||||
|
assert_ptr_equal(member->type, mSCRIPT_TYPE_MS_S16);
|
||||||
|
assert_int_not_equal(member->offset, sizeof(int32_t) * 2 + 1);
|
||||||
|
size_t hOffset = member->offset;
|
||||||
|
|
||||||
|
member = HashTableLookup(&cls->instanceMembers, "i3");
|
||||||
|
assert_non_null(member);
|
||||||
|
assert_string_equal(member->name, "i3");
|
||||||
|
assert_null(member->docstring);
|
||||||
|
assert_ptr_equal(member->type, mSCRIPT_TYPE_MS_S32);
|
||||||
|
assert_true(member->offset >= hOffset + sizeof(int16_t));
|
||||||
|
|
||||||
|
member = HashTableLookup(&cls->instanceMembers, "_super");
|
||||||
|
assert_non_null(member);
|
||||||
|
assert_string_equal(member->name, "_super");
|
||||||
|
assert_null(member->docstring);
|
||||||
|
assert_ptr_equal(member->type, mSCRIPT_TYPE_MS_S(TestA));
|
||||||
|
assert_int_equal(member->offset, 0);
|
||||||
|
|
||||||
|
member = HashTableLookup(&cls->instanceMembers, "unknown");
|
||||||
|
assert_null(member);
|
||||||
|
|
||||||
|
mScriptClassDeinit(cls);
|
||||||
|
assert_false(cls->init);
|
||||||
|
}
|
||||||
|
|
||||||
|
M_TEST_DEFINE(testBGet) {
|
||||||
|
struct mScriptTypeClass* cls = mSCRIPT_TYPE_MS_S(TestB)->details.cls;
|
||||||
|
|
||||||
|
struct TestB s = {
|
||||||
|
.d = {
|
||||||
|
.i = 1,
|
||||||
|
.i2 = 2,
|
||||||
|
.b8 = 3,
|
||||||
|
.hUnaligned = 4
|
||||||
|
},
|
||||||
|
.i3 = 5
|
||||||
|
};
|
||||||
|
|
||||||
|
struct mScriptValue sval = mSCRIPT_MAKE_S(TestB, &s);
|
||||||
|
struct mScriptValue super;
|
||||||
|
struct mScriptValue val;
|
||||||
|
struct mScriptValue compare;
|
||||||
|
|
||||||
|
compare = mSCRIPT_MAKE_S32(1);
|
||||||
|
assert_true(mScriptObjectGet(&sval, "i", &val));
|
||||||
|
assert_true(compare.type->equal(&compare, &val));
|
||||||
|
|
||||||
|
compare = mSCRIPT_MAKE_S32(2);
|
||||||
|
assert_true(mScriptObjectGet(&sval, "i2", &val));
|
||||||
|
assert_true(compare.type->equal(&compare, &val));
|
||||||
|
|
||||||
|
compare = mSCRIPT_MAKE_S32(3);
|
||||||
|
assert_true(mScriptObjectGet(&sval, "b8", &val));
|
||||||
|
assert_true(compare.type->equal(&compare, &val));
|
||||||
|
|
||||||
|
compare = mSCRIPT_MAKE_S32(4);
|
||||||
|
assert_true(mScriptObjectGet(&sval, "hUnaligned", &val));
|
||||||
|
assert_true(compare.type->equal(&compare, &val));
|
||||||
|
|
||||||
|
compare = mSCRIPT_MAKE_S32(5);
|
||||||
|
assert_true(mScriptObjectGet(&sval, "i3", &val));
|
||||||
|
assert_true(compare.type->equal(&compare, &val));
|
||||||
|
|
||||||
|
// Superclass explicit access
|
||||||
|
assert_true(mScriptObjectGet(&sval, "_super", &super));
|
||||||
|
assert_true(super.type == mSCRIPT_TYPE_MS_S(TestA));
|
||||||
|
|
||||||
|
compare = mSCRIPT_MAKE_S32(1);
|
||||||
|
assert_true(mScriptObjectGet(&super, "i", &val));
|
||||||
|
assert_true(compare.type->equal(&compare, &val));
|
||||||
|
|
||||||
|
compare = mSCRIPT_MAKE_S32(2);
|
||||||
|
assert_true(mScriptObjectGet(&super, "i2", &val));
|
||||||
|
assert_true(compare.type->equal(&compare, &val));
|
||||||
|
|
||||||
|
compare = mSCRIPT_MAKE_S32(3);
|
||||||
|
assert_true(mScriptObjectGet(&super, "b8", &val));
|
||||||
|
assert_true(compare.type->equal(&compare, &val));
|
||||||
|
|
||||||
|
compare = mSCRIPT_MAKE_S32(4);
|
||||||
|
assert_true(mScriptObjectGet(&super, "hUnaligned", &val));
|
||||||
|
assert_true(compare.type->equal(&compare, &val));
|
||||||
|
|
||||||
|
assert_false(mScriptObjectGet(&super, "i3", &val));
|
||||||
|
|
||||||
|
// Test const-correctness
|
||||||
|
sval = mSCRIPT_MAKE_CS(TestB, &s);
|
||||||
|
assert_true(mScriptObjectGet(&sval, "_super", &super));
|
||||||
|
assert_true(super.type == mSCRIPT_TYPE_MS_CS(TestA));
|
||||||
|
|
||||||
|
assert_true(cls->init);
|
||||||
|
mScriptClassDeinit(cls);
|
||||||
|
assert_false(cls->init);
|
||||||
|
}
|
||||||
|
|
||||||
|
M_TEST_DEFINE(testBSet) {
|
||||||
|
struct mScriptTypeClass* cls = mSCRIPT_TYPE_MS_S(TestB)->details.cls;
|
||||||
|
|
||||||
|
struct TestB s = {
|
||||||
|
.d = {
|
||||||
|
.i = 1,
|
||||||
|
.i2 = 2,
|
||||||
|
.b8 = 3,
|
||||||
|
.hUnaligned = 4
|
||||||
|
},
|
||||||
|
.i3 = 5
|
||||||
|
};
|
||||||
|
|
||||||
|
struct mScriptValue sval = mSCRIPT_MAKE_S(TestB, &s);
|
||||||
|
struct mScriptValue super;
|
||||||
|
struct mScriptValue val;
|
||||||
|
|
||||||
|
val = mSCRIPT_MAKE_S32(2);
|
||||||
|
assert_true(mScriptObjectSet(&sval, "i", &val));
|
||||||
|
assert_int_equal(s.d.i, 2);
|
||||||
|
|
||||||
|
val = mSCRIPT_MAKE_S32(3);
|
||||||
|
assert_true(mScriptObjectSet(&sval, "i2", &val));
|
||||||
|
assert_int_equal(s.d.i2, 3);
|
||||||
|
|
||||||
|
val = mSCRIPT_MAKE_S32(4);
|
||||||
|
assert_true(mScriptObjectSet(&sval, "b8", &val));
|
||||||
|
assert_int_equal(s.d.b8, 4);
|
||||||
|
|
||||||
|
val = mSCRIPT_MAKE_S32(5);
|
||||||
|
assert_true(mScriptObjectSet(&sval, "hUnaligned", &val));
|
||||||
|
assert_int_equal(s.d.hUnaligned, 5);
|
||||||
|
|
||||||
|
val = mSCRIPT_MAKE_S32(6);
|
||||||
|
assert_true(mScriptObjectSet(&sval, "i3", &val));
|
||||||
|
assert_int_equal(s.i3, 6);
|
||||||
|
|
||||||
|
// Superclass explicit access
|
||||||
|
assert_true(mScriptObjectGet(&sval, "_super", &super));
|
||||||
|
assert_true(super.type == mSCRIPT_TYPE_MS_S(TestA));
|
||||||
|
|
||||||
|
val = mSCRIPT_MAKE_S32(3);
|
||||||
|
assert_true(mScriptObjectSet(&super, "i", &val));
|
||||||
|
assert_int_equal(s.d.i, 3);
|
||||||
|
|
||||||
|
val = mSCRIPT_MAKE_S32(4);
|
||||||
|
assert_true(mScriptObjectSet(&super, "i2", &val));
|
||||||
|
assert_int_equal(s.d.i2, 4);
|
||||||
|
|
||||||
|
val = mSCRIPT_MAKE_S32(5);
|
||||||
|
assert_true(mScriptObjectSet(&super, "b8", &val));
|
||||||
|
assert_int_equal(s.d.b8, 5);
|
||||||
|
|
||||||
|
val = mSCRIPT_MAKE_S32(6);
|
||||||
|
assert_true(mScriptObjectSet(&super, "hUnaligned", &val));
|
||||||
|
assert_int_equal(s.d.hUnaligned, 6);
|
||||||
|
|
||||||
|
val = mSCRIPT_MAKE_S32(7);
|
||||||
|
assert_false(mScriptObjectSet(&super, "i3", &val));
|
||||||
|
assert_int_equal(s.i3, 6);
|
||||||
|
|
||||||
|
// Const access
|
||||||
|
sval = mSCRIPT_MAKE_CS(TestB, &s);
|
||||||
|
|
||||||
|
val = mSCRIPT_MAKE_S32(4);
|
||||||
|
assert_false(mScriptObjectSet(&sval, "i", &val));
|
||||||
|
assert_int_equal(s.d.i, 3);
|
||||||
|
|
||||||
|
val = mSCRIPT_MAKE_S32(5);
|
||||||
|
assert_false(mScriptObjectSet(&sval, "i2", &val));
|
||||||
|
assert_int_equal(s.d.i2, 4);
|
||||||
|
|
||||||
|
val = mSCRIPT_MAKE_S32(6);
|
||||||
|
assert_false(mScriptObjectSet(&sval, "b8", &val));
|
||||||
|
assert_int_equal(s.d.b8, 5);
|
||||||
|
|
||||||
|
val = mSCRIPT_MAKE_S32(7);
|
||||||
|
assert_false(mScriptObjectSet(&sval, "hUnaligned", &val));
|
||||||
|
assert_int_equal(s.d.hUnaligned, 6);
|
||||||
|
|
||||||
|
val = mSCRIPT_MAKE_S32(8);
|
||||||
|
assert_false(mScriptObjectSet(&sval, "i3", &val));
|
||||||
|
assert_int_equal(s.i3, 6);
|
||||||
|
|
||||||
|
assert_true(cls->init);
|
||||||
|
mScriptClassDeinit(cls);
|
||||||
|
assert_false(cls->init);
|
||||||
|
}
|
||||||
|
|
||||||
|
M_TEST_DEFINE(testDLayout) {
|
||||||
|
struct mScriptTypeClass* cls = mSCRIPT_TYPE_MS_S(TestD)->details.cls;
|
||||||
|
assert_false(cls->init);
|
||||||
|
mScriptClassInit(cls);
|
||||||
|
assert_true(cls->init);
|
||||||
|
|
||||||
|
struct mScriptClassMember* member;
|
||||||
|
|
||||||
|
// Instance members
|
||||||
|
member = HashTableLookup(&cls->instanceMembers, "a");
|
||||||
|
assert_non_null(member);
|
||||||
|
assert_string_equal(member->name, "a");
|
||||||
|
assert_null(member->docstring);
|
||||||
|
assert_ptr_equal(member->type, mSCRIPT_TYPE_MS_S(TestC));
|
||||||
|
assert_int_equal(member->offset, 0);
|
||||||
|
|
||||||
|
member = HashTableLookup(&cls->instanceMembers, "b");
|
||||||
|
assert_non_null(member);
|
||||||
|
assert_string_equal(member->name, "b");
|
||||||
|
assert_null(member->docstring);
|
||||||
|
assert_ptr_equal(member->type, mSCRIPT_TYPE_MS_S(TestC));
|
||||||
|
assert_int_equal(member->offset, sizeof(struct TestC));
|
||||||
|
|
||||||
|
mScriptClassDeinit(cls);
|
||||||
|
assert_false(cls->init);
|
||||||
|
}
|
||||||
|
|
||||||
|
M_TEST_DEFINE(testDGet) {
|
||||||
|
struct mScriptTypeClass* cls = mSCRIPT_TYPE_MS_S(TestD)->details.cls;
|
||||||
|
|
||||||
|
struct TestD s = {
|
||||||
|
.a = { 1 },
|
||||||
|
.b = { 2 },
|
||||||
|
};
|
||||||
|
|
||||||
|
struct mScriptValue sval = mSCRIPT_MAKE_S(TestD, &s);
|
||||||
|
struct mScriptValue val;
|
||||||
|
struct mScriptValue member;
|
||||||
|
struct mScriptValue compare;
|
||||||
|
|
||||||
|
compare = mSCRIPT_MAKE_S32(1);
|
||||||
|
assert_true(mScriptObjectGet(&sval, "a", &member));
|
||||||
|
assert_true(mScriptObjectGet(&member, "i", &val));
|
||||||
|
assert_true(compare.type->equal(&compare, &val));
|
||||||
|
|
||||||
|
compare = mSCRIPT_MAKE_S32(2);
|
||||||
|
assert_true(mScriptObjectGet(&sval, "b", &member));
|
||||||
|
assert_true(mScriptObjectGet(&member, "i", &val));
|
||||||
|
assert_true(compare.type->equal(&compare, &val));
|
||||||
|
|
||||||
|
assert_true(cls->init);
|
||||||
|
mScriptClassDeinit(cls);
|
||||||
|
assert_false(cls->init);
|
||||||
|
}
|
||||||
|
|
||||||
|
M_TEST_DEFINE(testDSet) {
|
||||||
|
struct mScriptTypeClass* cls = mSCRIPT_TYPE_MS_S(TestD)->details.cls;
|
||||||
|
|
||||||
|
struct TestD s = {
|
||||||
|
.a = { 1 },
|
||||||
|
.b = { 2 },
|
||||||
|
};
|
||||||
|
|
||||||
|
struct mScriptValue sval = mSCRIPT_MAKE_S(TestD, &s);
|
||||||
|
struct mScriptValue member;
|
||||||
|
struct mScriptValue val;
|
||||||
|
|
||||||
|
val = mSCRIPT_MAKE_S32(2);
|
||||||
|
assert_true(mScriptObjectGet(&sval, "a", &member));
|
||||||
|
assert_true(mScriptObjectSet(&member, "i", &val));
|
||||||
|
assert_int_equal(s.a.i, 2);
|
||||||
|
assert_int_equal(s.b.i, 2);
|
||||||
|
|
||||||
|
val = mSCRIPT_MAKE_S32(3);
|
||||||
|
assert_true(mScriptObjectGet(&sval, "b", &member));
|
||||||
|
assert_true(mScriptObjectSet(&member, "i", &val));
|
||||||
|
assert_int_equal(s.a.i, 2);
|
||||||
|
assert_int_equal(s.b.i, 3);
|
||||||
|
|
||||||
|
sval = mSCRIPT_MAKE_CS(TestD, &s);
|
||||||
|
|
||||||
|
val = mSCRIPT_MAKE_S32(4);
|
||||||
|
assert_true(mScriptObjectGet(&sval, "a", &member));
|
||||||
|
assert_false(mScriptObjectSet(&member, "i", &val));
|
||||||
|
assert_int_equal(s.a.i, 2);
|
||||||
|
assert_int_equal(s.b.i, 3);
|
||||||
|
|
||||||
|
val = mSCRIPT_MAKE_S32(5);
|
||||||
|
assert_true(mScriptObjectGet(&sval, "b", &member));
|
||||||
|
assert_false(mScriptObjectSet(&member, "i", &val));
|
||||||
|
assert_int_equal(s.a.i, 2);
|
||||||
|
assert_int_equal(s.b.i, 3);
|
||||||
|
|
||||||
|
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(testAGet),
|
cmocka_unit_test(testAGet),
|
||||||
cmocka_unit_test(testASet),
|
cmocka_unit_test(testASet),
|
||||||
cmocka_unit_test(testAStatic),
|
cmocka_unit_test(testAStatic),
|
||||||
cmocka_unit_test(testADynamic))
|
cmocka_unit_test(testADynamic),
|
||||||
|
cmocka_unit_test(testBLayout),
|
||||||
|
cmocka_unit_test(testBGet),
|
||||||
|
cmocka_unit_test(testBSet),
|
||||||
|
cmocka_unit_test(testDLayout),
|
||||||
|
cmocka_unit_test(testDGet),
|
||||||
|
cmocka_unit_test(testDSet))
|
||||||
|
|
|
@ -741,33 +741,34 @@ void mScriptFrameDeinit(struct mScriptFrame* frame) {
|
||||||
mScriptListDeinit(&frame->arguments);
|
mScriptListDeinit(&frame->arguments);
|
||||||
}
|
}
|
||||||
|
|
||||||
void mScriptClassInit(struct mScriptTypeClass* cls) {
|
static void _mScriptClassInit(struct mScriptTypeClass* cls, const struct mScriptClassInitDetails* details, bool child) {
|
||||||
if (cls->init) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
HashTableInit(&cls->staticMembers, 0, free);
|
|
||||||
HashTableInit(&cls->instanceMembers, 0, free);
|
|
||||||
size_t staticOffset = 0;
|
|
||||||
const char* docstring = NULL;
|
const char* docstring = NULL;
|
||||||
|
size_t staticOffset = 0;
|
||||||
|
|
||||||
size_t i;
|
size_t i;
|
||||||
for (i = 0; cls->details[i].type != mSCRIPT_CLASS_INIT_END; ++i) {
|
for (i = 0; details[i].type != mSCRIPT_CLASS_INIT_END; ++i) {
|
||||||
const struct mScriptClassInitDetails* details = &cls->details[i];
|
const struct mScriptClassInitDetails* detail = &details[i];
|
||||||
struct mScriptClassMember* member;
|
struct mScriptClassMember* member;
|
||||||
|
|
||||||
switch (details->type) {
|
switch (detail->type) {
|
||||||
case mSCRIPT_CLASS_INIT_END:
|
case mSCRIPT_CLASS_INIT_END:
|
||||||
break;
|
break;
|
||||||
case mSCRIPT_CLASS_INIT_DOCSTRING:
|
case mSCRIPT_CLASS_INIT_DOCSTRING:
|
||||||
docstring = details->info.comment;
|
docstring = detail->info.comment;
|
||||||
break;
|
break;
|
||||||
case mSCRIPT_CLASS_INIT_INHERIT:
|
case mSCRIPT_CLASS_INIT_INHERIT:
|
||||||
// TODO
|
member = calloc(1, sizeof(*member));
|
||||||
abort();
|
member->name = "_super";
|
||||||
|
member->type = detail->info.parent;
|
||||||
|
if (!child) {
|
||||||
|
cls->parent = detail->info.parent;
|
||||||
|
}
|
||||||
|
HashTableInsert(&cls->instanceMembers, member->name, member);
|
||||||
|
_mScriptClassInit(cls, detail->info.parent->details.cls->details, true);
|
||||||
break;
|
break;
|
||||||
case mSCRIPT_CLASS_INIT_INSTANCE_MEMBER:
|
case mSCRIPT_CLASS_INIT_INSTANCE_MEMBER:
|
||||||
member = calloc(1, sizeof(*member));
|
member = calloc(1, sizeof(*member));
|
||||||
memcpy(member, &details->info.member, sizeof(*member));
|
memcpy(member, &detail->info.member, sizeof(*member));
|
||||||
if (docstring) {
|
if (docstring) {
|
||||||
member->docstring = docstring;
|
member->docstring = docstring;
|
||||||
docstring = NULL;
|
docstring = NULL;
|
||||||
|
@ -775,27 +776,40 @@ void mScriptClassInit(struct mScriptTypeClass* cls) {
|
||||||
HashTableInsert(&cls->instanceMembers, member->name, member);
|
HashTableInsert(&cls->instanceMembers, member->name, member);
|
||||||
break;
|
break;
|
||||||
case mSCRIPT_CLASS_INIT_STATIC_MEMBER:
|
case mSCRIPT_CLASS_INIT_STATIC_MEMBER:
|
||||||
member = calloc(1, sizeof(*member));
|
if (!child) {
|
||||||
memcpy(member, &details->info.member, sizeof(*member));
|
member = calloc(1, sizeof(*member));
|
||||||
if (docstring) {
|
memcpy(member, &detail->info.member, sizeof(*member));
|
||||||
member->docstring = docstring;
|
if (docstring) {
|
||||||
docstring = NULL;
|
member->docstring = docstring;
|
||||||
}
|
docstring = NULL;
|
||||||
|
|
||||||
// Alignment check
|
|
||||||
if (staticOffset & (details->info.member.type->size - 1)) {
|
|
||||||
size_t size = details->info.member.type->size;
|
|
||||||
if (size > MAX_ALIGNMENT) {
|
|
||||||
size = MAX_ALIGNMENT;
|
|
||||||
}
|
}
|
||||||
staticOffset = (staticOffset & ~(size - 1)) + size;
|
|
||||||
|
// Alignment check
|
||||||
|
if (staticOffset & (detail->info.member.type->size - 1)) {
|
||||||
|
size_t size = detail->info.member.type->size;
|
||||||
|
if (size > MAX_ALIGNMENT) {
|
||||||
|
size = MAX_ALIGNMENT;
|
||||||
|
}
|
||||||
|
staticOffset = (staticOffset & ~(size - 1)) + size;
|
||||||
|
}
|
||||||
|
member->offset = staticOffset;
|
||||||
|
staticOffset += detail->info.member.type->size;
|
||||||
|
HashTableInsert(&cls->staticMembers, member->name, member);
|
||||||
}
|
}
|
||||||
member->offset = staticOffset;
|
|
||||||
staticOffset += details->info.member.type->size;
|
|
||||||
HashTableInsert(&cls->staticMembers, member->name, member);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void mScriptClassInit(struct mScriptTypeClass* cls) {
|
||||||
|
if (cls->init) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
HashTableInit(&cls->staticMembers, 0, free);
|
||||||
|
HashTableInit(&cls->instanceMembers, 0, free);
|
||||||
|
|
||||||
|
_mScriptClassInit(cls, cls->details, false);
|
||||||
|
|
||||||
cls->init = true;
|
cls->init = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -880,6 +894,15 @@ bool mScriptObjectGet(struct mScriptValue* obj, const char* member, struct mScri
|
||||||
val->type = m->type;
|
val->type = m->type;
|
||||||
m->type->alloc(val);
|
m->type->alloc(val);
|
||||||
break;
|
break;
|
||||||
|
case mSCRIPT_TYPE_OBJECT:
|
||||||
|
val->refs = mSCRIPT_VALUE_UNREF;
|
||||||
|
val->value.opaque = rawMember;
|
||||||
|
if (obj->type->isConst && !m->type->isConst) {
|
||||||
|
val->type = m->type->constType;
|
||||||
|
} else {
|
||||||
|
val->type = m->type;
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue