mirror of https://github.com/mgba-emu/mgba.git
Scripting: Move equality into type implementation
This commit is contained in:
parent
16563fe4d2
commit
8818bf4048
|
@ -213,6 +213,7 @@ struct mScriptType {
|
|||
void (*alloc)(struct mScriptValue*);
|
||||
void (*free)(struct mScriptValue*);
|
||||
uint32_t (*hash)(const struct mScriptValue*);
|
||||
bool (*equal)(const struct mScriptValue*, const struct mScriptValue*);
|
||||
};
|
||||
|
||||
struct mScriptValue {
|
||||
|
|
|
@ -171,6 +171,235 @@ M_TEST_DEFINE(coerceFromFloat) {
|
|||
mScriptFrameDeinit(&frame);
|
||||
}
|
||||
|
||||
M_TEST_DEFINE(s32Equality) {
|
||||
struct mScriptValue s32A;
|
||||
struct mScriptValue s32B;
|
||||
struct mScriptValue u32;
|
||||
struct mScriptValue f32;
|
||||
|
||||
s32A = mSCRIPT_MAKE_S32(0);
|
||||
s32B = mSCRIPT_MAKE_S32(0);
|
||||
assert_true(s32A.type->equal(&s32A, &s32B));
|
||||
|
||||
s32B = mSCRIPT_MAKE_S32(1);
|
||||
assert_false(s32A.type->equal(&s32A, &s32B));
|
||||
|
||||
s32A = mSCRIPT_MAKE_S32(1);
|
||||
assert_true(s32A.type->equal(&s32A, &s32B));
|
||||
|
||||
s32B = mSCRIPT_MAKE_S32(-1);
|
||||
assert_false(s32A.type->equal(&s32A, &s32B));
|
||||
|
||||
s32A = mSCRIPT_MAKE_S32(-1);
|
||||
assert_true(s32A.type->equal(&s32A, &s32B));
|
||||
|
||||
s32A = mSCRIPT_MAKE_S32(0);
|
||||
u32 = mSCRIPT_MAKE_U32(0);
|
||||
assert_true(s32A.type->equal(&s32A, &u32));
|
||||
|
||||
s32A = mSCRIPT_MAKE_S32(1);
|
||||
u32 = mSCRIPT_MAKE_U32(1);
|
||||
assert_true(s32A.type->equal(&s32A, &u32));
|
||||
|
||||
s32A = mSCRIPT_MAKE_S32(0);
|
||||
u32 = mSCRIPT_MAKE_U32(1);
|
||||
assert_false(s32A.type->equal(&s32A, &u32));
|
||||
|
||||
s32A = mSCRIPT_MAKE_S32(1);
|
||||
u32 = mSCRIPT_MAKE_U32(0);
|
||||
assert_false(s32A.type->equal(&s32A, &u32));
|
||||
|
||||
s32A = mSCRIPT_MAKE_S32(0x7FFFFFFF);
|
||||
u32 = mSCRIPT_MAKE_U32(0x7FFFFFFF);
|
||||
assert_true(s32A.type->equal(&s32A, &u32));
|
||||
|
||||
s32A = mSCRIPT_MAKE_S32(0xFFFFFFFF);
|
||||
u32 = mSCRIPT_MAKE_U32(0xFFFFFFFF);
|
||||
assert_false(s32A.type->equal(&s32A, &u32));
|
||||
|
||||
s32A = mSCRIPT_MAKE_S32(0x80000000);
|
||||
u32 = mSCRIPT_MAKE_U32(0x80000000);
|
||||
assert_false(s32A.type->equal(&s32A, &u32));
|
||||
|
||||
s32A = mSCRIPT_MAKE_S32(0);
|
||||
f32 = mSCRIPT_MAKE_F32(0);
|
||||
assert_true(s32A.type->equal(&s32A, &f32));
|
||||
|
||||
s32A = mSCRIPT_MAKE_S32(1);
|
||||
f32 = mSCRIPT_MAKE_F32(1);
|
||||
assert_true(s32A.type->equal(&s32A, &f32));
|
||||
|
||||
s32A = mSCRIPT_MAKE_S32(0);
|
||||
f32 = mSCRIPT_MAKE_F32(1);
|
||||
assert_false(s32A.type->equal(&s32A, &f32));
|
||||
|
||||
s32A = mSCRIPT_MAKE_S32(1);
|
||||
f32 = mSCRIPT_MAKE_F32(0);
|
||||
assert_false(s32A.type->equal(&s32A, &f32));
|
||||
|
||||
s32A = mSCRIPT_MAKE_S32(-1);
|
||||
f32 = mSCRIPT_MAKE_F32(-1);
|
||||
assert_true(s32A.type->equal(&s32A, &f32));
|
||||
|
||||
s32A = mSCRIPT_MAKE_S32(0);
|
||||
f32 = mSCRIPT_MAKE_F32(-1);
|
||||
assert_false(s32A.type->equal(&s32A, &f32));
|
||||
|
||||
s32A = mSCRIPT_MAKE_S32(-1);
|
||||
f32 = mSCRIPT_MAKE_F32(0);
|
||||
assert_false(s32A.type->equal(&s32A, &f32));
|
||||
}
|
||||
|
||||
M_TEST_DEFINE(u32Equality) {
|
||||
struct mScriptValue u32A;
|
||||
struct mScriptValue u32B;
|
||||
struct mScriptValue s32;
|
||||
struct mScriptValue f32;
|
||||
|
||||
u32A = mSCRIPT_MAKE_U32(0);
|
||||
u32B = mSCRIPT_MAKE_U32(0);
|
||||
assert_true(u32A.type->equal(&u32A, &u32B));
|
||||
|
||||
u32B = mSCRIPT_MAKE_U32(1);
|
||||
assert_false(u32A.type->equal(&u32A, &u32B));
|
||||
|
||||
u32A = mSCRIPT_MAKE_U32(1);
|
||||
assert_true(u32A.type->equal(&u32A, &u32B));
|
||||
|
||||
u32B = mSCRIPT_MAKE_U32(0x80000000U);
|
||||
assert_false(u32A.type->equal(&u32A, &u32B));
|
||||
|
||||
u32A = mSCRIPT_MAKE_U32(0x80000000U);
|
||||
assert_true(u32A.type->equal(&u32A, &u32B));
|
||||
|
||||
u32A = mSCRIPT_MAKE_U32(0);
|
||||
s32 = mSCRIPT_MAKE_S32(0);
|
||||
assert_true(u32A.type->equal(&u32A, &s32));
|
||||
|
||||
u32A = mSCRIPT_MAKE_U32(1);
|
||||
s32 = mSCRIPT_MAKE_S32(1);
|
||||
assert_true(u32A.type->equal(&u32A, &s32));
|
||||
|
||||
u32A = mSCRIPT_MAKE_U32(0);
|
||||
s32 = mSCRIPT_MAKE_S32(1);
|
||||
assert_false(u32A.type->equal(&u32A, &s32));
|
||||
|
||||
u32A = mSCRIPT_MAKE_U32(1);
|
||||
s32 = mSCRIPT_MAKE_S32(0);
|
||||
assert_false(u32A.type->equal(&u32A, &s32));
|
||||
|
||||
u32A = mSCRIPT_MAKE_U32(0x7FFFFFFF);
|
||||
s32 = mSCRIPT_MAKE_S32(0x7FFFFFFF);
|
||||
assert_true(u32A.type->equal(&u32A, &s32));
|
||||
|
||||
u32A = mSCRIPT_MAKE_U32(0xFFFFFFFF);
|
||||
s32 = mSCRIPT_MAKE_S32(0xFFFFFFFF);
|
||||
assert_false(u32A.type->equal(&u32A, &s32));
|
||||
|
||||
u32A = mSCRIPT_MAKE_U32(0x80000000);
|
||||
s32 = mSCRIPT_MAKE_S32(0x80000000);
|
||||
assert_false(u32A.type->equal(&u32A, &s32));
|
||||
|
||||
u32A = mSCRIPT_MAKE_U32(0);
|
||||
f32 = mSCRIPT_MAKE_F32(0);
|
||||
assert_true(u32A.type->equal(&u32A, &f32));
|
||||
|
||||
u32A = mSCRIPT_MAKE_U32(1);
|
||||
f32 = mSCRIPT_MAKE_F32(1);
|
||||
assert_true(u32A.type->equal(&u32A, &f32));
|
||||
|
||||
u32A = mSCRIPT_MAKE_U32(0);
|
||||
f32 = mSCRIPT_MAKE_F32(1);
|
||||
assert_false(u32A.type->equal(&u32A, &f32));
|
||||
|
||||
u32A = mSCRIPT_MAKE_U32(1);
|
||||
f32 = mSCRIPT_MAKE_F32(0);
|
||||
assert_false(u32A.type->equal(&u32A, &f32));
|
||||
|
||||
u32A = mSCRIPT_MAKE_U32(0x80000000);
|
||||
f32 = mSCRIPT_MAKE_F32(0x80000000);
|
||||
assert_true(u32A.type->equal(&u32A, &f32));
|
||||
|
||||
u32A = mSCRIPT_MAKE_U32(0);
|
||||
f32 = mSCRIPT_MAKE_F32(0x80000000);
|
||||
assert_false(u32A.type->equal(&u32A, &f32));
|
||||
|
||||
u32A = mSCRIPT_MAKE_U32(0x80000000);
|
||||
f32 = mSCRIPT_MAKE_F32(0);
|
||||
assert_false(u32A.type->equal(&u32A, &f32));
|
||||
}
|
||||
|
||||
M_TEST_DEFINE(f32Equality) {
|
||||
struct mScriptValue f32A;
|
||||
struct mScriptValue f32B;
|
||||
struct mScriptValue s32;
|
||||
struct mScriptValue u32;
|
||||
|
||||
f32A = mSCRIPT_MAKE_F32(0);
|
||||
f32B = mSCRIPT_MAKE_F32(0);
|
||||
assert_true(f32A.type->equal(&f32A, &f32B));
|
||||
|
||||
f32B = mSCRIPT_MAKE_F32(1);
|
||||
assert_false(f32A.type->equal(&f32A, &f32B));
|
||||
|
||||
f32A = mSCRIPT_MAKE_F32(1);
|
||||
assert_true(f32A.type->equal(&f32A, &f32B));
|
||||
|
||||
f32B = mSCRIPT_MAKE_F32(1.1);
|
||||
assert_false(f32A.type->equal(&f32A, &f32B));
|
||||
|
||||
f32A = mSCRIPT_MAKE_F32(1.1);
|
||||
assert_true(f32A.type->equal(&f32A, &f32B));
|
||||
|
||||
f32A = mSCRIPT_MAKE_F32(0);
|
||||
s32 = mSCRIPT_MAKE_S32(0);
|
||||
assert_true(f32A.type->equal(&f32A, &s32));
|
||||
|
||||
f32A = mSCRIPT_MAKE_F32(1);
|
||||
s32 = mSCRIPT_MAKE_S32(1);
|
||||
assert_true(f32A.type->equal(&f32A, &s32));
|
||||
|
||||
f32A = mSCRIPT_MAKE_F32(0);
|
||||
s32 = mSCRIPT_MAKE_S32(1);
|
||||
assert_false(f32A.type->equal(&f32A, &s32));
|
||||
|
||||
f32A = mSCRIPT_MAKE_F32(1);
|
||||
s32 = mSCRIPT_MAKE_S32(0);
|
||||
assert_false(f32A.type->equal(&f32A, &s32));
|
||||
|
||||
f32A = mSCRIPT_MAKE_F32(1.1);
|
||||
s32 = mSCRIPT_MAKE_S32(1);
|
||||
assert_false(f32A.type->equal(&f32A, &s32));
|
||||
|
||||
f32A = mSCRIPT_MAKE_F32(0x40000000);
|
||||
s32 = mSCRIPT_MAKE_S32(0x40000000);
|
||||
assert_true(f32A.type->equal(&f32A, &s32));
|
||||
|
||||
f32A = mSCRIPT_MAKE_F32(0);
|
||||
u32 = mSCRIPT_MAKE_U32(0);
|
||||
assert_true(f32A.type->equal(&f32A, &u32));
|
||||
|
||||
f32A = mSCRIPT_MAKE_F32(1);
|
||||
u32 = mSCRIPT_MAKE_U32(1);
|
||||
assert_true(f32A.type->equal(&f32A, &u32));
|
||||
|
||||
f32A = mSCRIPT_MAKE_F32(0);
|
||||
u32 = mSCRIPT_MAKE_U32(1);
|
||||
assert_false(f32A.type->equal(&f32A, &u32));
|
||||
|
||||
f32A = mSCRIPT_MAKE_F32(1);
|
||||
u32 = mSCRIPT_MAKE_U32(0);
|
||||
assert_false(f32A.type->equal(&f32A, &u32));
|
||||
|
||||
f32A = mSCRIPT_MAKE_F32(1.1);
|
||||
u32 = mSCRIPT_MAKE_U32(1);
|
||||
assert_false(f32A.type->equal(&f32A, &u32));
|
||||
|
||||
f32A = mSCRIPT_MAKE_F32(0x40000000);
|
||||
u32 = mSCRIPT_MAKE_U32(0x40000000);
|
||||
assert_true(f32A.type->equal(&f32A, &u32));
|
||||
}
|
||||
|
||||
M_TEST_DEFINE(hashTableBasic) {
|
||||
struct mScriptValue* table = mScriptValueAlloc(mSCRIPT_TYPE_MS_TABLE);
|
||||
assert_non_null(table);
|
||||
|
@ -213,4 +442,7 @@ M_TEST_SUITE_DEFINE(mScript,
|
|||
cmocka_unit_test(wrongArgType),
|
||||
cmocka_unit_test(coerceToFloat),
|
||||
cmocka_unit_test(coerceFromFloat),
|
||||
cmocka_unit_test(s32Equality),
|
||||
cmocka_unit_test(u32Equality),
|
||||
cmocka_unit_test(f32Equality),
|
||||
cmocka_unit_test(hashTableBasic))
|
||||
|
|
|
@ -18,6 +18,11 @@ static bool _valEqual(const void* a, const void* b);
|
|||
static void* _valRef(void*);
|
||||
static void _valDeref(void*);
|
||||
|
||||
static bool _typeEqual(const struct mScriptValue*, const struct mScriptValue*);
|
||||
static bool _s32Equal(const struct mScriptValue*, const struct mScriptValue*);
|
||||
static bool _u32Equal(const struct mScriptValue*, const struct mScriptValue*);
|
||||
static bool _f32Equal(const struct mScriptValue*, const struct mScriptValue*);
|
||||
|
||||
const struct mScriptType mSTVoid = {
|
||||
.base = mSCRIPT_TYPE_VOID,
|
||||
.size = 0,
|
||||
|
@ -25,6 +30,7 @@ const struct mScriptType mSTVoid = {
|
|||
.alloc = NULL,
|
||||
.free = NULL,
|
||||
.hash = NULL,
|
||||
.equal = _typeEqual,
|
||||
};
|
||||
|
||||
const struct mScriptType mSTSInt32 = {
|
||||
|
@ -34,6 +40,7 @@ const struct mScriptType mSTSInt32 = {
|
|||
.alloc = NULL,
|
||||
.free = NULL,
|
||||
.hash = _hashScalar,
|
||||
.equal = _s32Equal,
|
||||
};
|
||||
|
||||
const struct mScriptType mSTUInt32 = {
|
||||
|
@ -43,6 +50,7 @@ const struct mScriptType mSTUInt32 = {
|
|||
.alloc = NULL,
|
||||
.free = NULL,
|
||||
.hash = _hashScalar,
|
||||
.equal = _u32Equal,
|
||||
};
|
||||
|
||||
const struct mScriptType mSTFloat32 = {
|
||||
|
@ -52,6 +60,7 @@ const struct mScriptType mSTFloat32 = {
|
|||
.alloc = NULL,
|
||||
.free = NULL,
|
||||
.hash = NULL,
|
||||
.equal = _f32Equal,
|
||||
};
|
||||
|
||||
const struct mScriptType mSTTable = {
|
||||
|
@ -113,22 +122,7 @@ uint32_t _valHash(const void* val, size_t len, uint32_t seed) {
|
|||
bool _valEqual(const void* a, const void* b) {
|
||||
const struct mScriptValue* valueA = a;
|
||||
const struct mScriptValue* valueB = b;
|
||||
// TODO: Move equality into type
|
||||
if (valueA->type != valueB->type) {
|
||||
return false;
|
||||
}
|
||||
switch (valueA->type->base) {
|
||||
case mSCRIPT_TYPE_VOID:
|
||||
return true;
|
||||
case mSCRIPT_TYPE_SINT:
|
||||
return valueA->value.s32 == valueB->value.s32;
|
||||
case mSCRIPT_TYPE_UINT:
|
||||
return valueA->value.u32 == valueB->value.u32;
|
||||
case mSCRIPT_TYPE_FLOAT:
|
||||
return valueA->value.f32 == valueB->value.f32;
|
||||
default:
|
||||
return valueA->value.opaque == valueB->value.opaque;
|
||||
}
|
||||
return valueA->type->equal(valueA, valueB);
|
||||
}
|
||||
|
||||
void* _valRef(void* val) {
|
||||
|
@ -140,6 +134,77 @@ void _valDeref(void* val) {
|
|||
mScriptValueDeref(val);
|
||||
}
|
||||
|
||||
bool _typeEqual(const struct mScriptValue* a, const struct mScriptValue* b) {
|
||||
return a->type == b->type;
|
||||
|
||||
}
|
||||
|
||||
bool _s32Equal(const struct mScriptValue* a, const struct mScriptValue* b) {
|
||||
int32_t val;
|
||||
switch (b->type->base) {
|
||||
case mSCRIPT_TYPE_SINT:
|
||||
val = b->value.s32;
|
||||
break;
|
||||
case mSCRIPT_TYPE_UINT:
|
||||
if (b->value.u32 > (uint32_t) INT_MAX) {
|
||||
return false;
|
||||
}
|
||||
if (a->value.s32 < 0) {
|
||||
return false;
|
||||
}
|
||||
val = b->value.u32;
|
||||
break;
|
||||
case mSCRIPT_TYPE_VOID:
|
||||
return false;
|
||||
default:
|
||||
return b->type->equal && b->type->equal(b, a);
|
||||
}
|
||||
return a->value.s32 == val;
|
||||
}
|
||||
|
||||
bool _u32Equal(const struct mScriptValue* a, const struct mScriptValue* b) {
|
||||
uint32_t val;
|
||||
switch (b->type->base) {
|
||||
case mSCRIPT_TYPE_SINT:
|
||||
if (b->value.s32 < 0) {
|
||||
return false;
|
||||
}
|
||||
if (a->value.u32 > (uint32_t) INT_MAX) {
|
||||
return false;
|
||||
}
|
||||
val = b->value.s32;
|
||||
break;
|
||||
case mSCRIPT_TYPE_UINT:
|
||||
val = b->value.u32;
|
||||
break;
|
||||
case mSCRIPT_TYPE_VOID:
|
||||
return false;
|
||||
default:
|
||||
return b->type->equal && b->type->equal(b, a);
|
||||
}
|
||||
return a->value.u32 == val;
|
||||
}
|
||||
|
||||
bool _f32Equal(const struct mScriptValue* a, const struct mScriptValue* b) {
|
||||
float val;
|
||||
switch (b->type->base) {
|
||||
case mSCRIPT_TYPE_SINT:
|
||||
val = b->value.s32;
|
||||
break;
|
||||
case mSCRIPT_TYPE_UINT:
|
||||
val = b->value.u32;
|
||||
break;
|
||||
case mSCRIPT_TYPE_FLOAT:
|
||||
val = b->value.f32;
|
||||
break;
|
||||
case mSCRIPT_TYPE_VOID:
|
||||
return false;
|
||||
default:
|
||||
return b->type->equal && b->type->equal(b, a);
|
||||
}
|
||||
return a->value.f32 == val;
|
||||
}
|
||||
|
||||
struct mScriptValue* mScriptValueAlloc(const struct mScriptType* type) {
|
||||
// TODO: Use an arena instead of just the generic heap
|
||||
struct mScriptValue* val = malloc(sizeof(*val));
|
||||
|
|
Loading…
Reference in New Issue