mirror of https://github.com/mgba-emu/mgba.git
Scripting: Add struct dynamic dispatch binding
This commit is contained in:
parent
af2e226cc4
commit
1a6fa25a33
|
@ -13,7 +13,13 @@ CXX_GUARD_START
|
||||||
#include <mgba-util/table.h>
|
#include <mgba-util/table.h>
|
||||||
#include <mgba-util/vector.h>
|
#include <mgba-util/vector.h>
|
||||||
|
|
||||||
|
#define _mCPP_EMPTY()
|
||||||
|
#define _mCPP_CAT(A, B) A ## B
|
||||||
|
|
||||||
|
#define _mDEFER(X) X _mCPP_EMPTY()
|
||||||
|
#define _mBLOCK(...) __VA_ARGS__ _mDEFER(_mCPP_EMPTY)()
|
||||||
#define _mAPPLY(...) __VA_ARGS__
|
#define _mAPPLY(...) __VA_ARGS__
|
||||||
|
#define _mCAT(A, B) _mCPP_CAT(A, B)
|
||||||
|
|
||||||
#define mSCRIPT_VALUE_UNREF -1
|
#define mSCRIPT_VALUE_UNREF -1
|
||||||
#define mSCRIPT_PARAMS_MAX 8
|
#define mSCRIPT_PARAMS_MAX 8
|
||||||
|
@ -34,6 +40,7 @@ CXX_GUARD_START
|
||||||
#define mSCRIPT_TYPE_C_TABLE Table*
|
#define mSCRIPT_TYPE_C_TABLE Table*
|
||||||
#define mSCRIPT_TYPE_C_WRAPPER struct mScriptValue*
|
#define mSCRIPT_TYPE_C_WRAPPER struct mScriptValue*
|
||||||
#define mSCRIPT_TYPE_C_S(STRUCT) struct STRUCT*
|
#define mSCRIPT_TYPE_C_S(STRUCT) struct STRUCT*
|
||||||
|
#define mSCRIPT_TYPE_C_S_METHOD(STRUCT, NAME) _mSTStructFunctionType_ ## STRUCT ## _ ## NAME
|
||||||
|
|
||||||
#define mSCRIPT_TYPE_FIELD_S8 s32
|
#define mSCRIPT_TYPE_FIELD_S8 s32
|
||||||
#define mSCRIPT_TYPE_FIELD_U8 s32
|
#define mSCRIPT_TYPE_FIELD_U8 s32
|
||||||
|
@ -51,6 +58,7 @@ CXX_GUARD_START
|
||||||
#define mSCRIPT_TYPE_FIELD_TABLE opaque
|
#define mSCRIPT_TYPE_FIELD_TABLE opaque
|
||||||
#define mSCRIPT_TYPE_FIELD_WRAPPER opaque
|
#define mSCRIPT_TYPE_FIELD_WRAPPER opaque
|
||||||
#define mSCRIPT_TYPE_FIELD_S(STRUCT) opaque
|
#define mSCRIPT_TYPE_FIELD_S(STRUCT) opaque
|
||||||
|
#define mSCRIPT_TYPE_FIELD_S_METHOD(STRUCT, NAME) copaque
|
||||||
|
|
||||||
#define mSCRIPT_TYPE_MS_S8 (&mSTSInt8)
|
#define mSCRIPT_TYPE_MS_S8 (&mSTSInt8)
|
||||||
#define mSCRIPT_TYPE_MS_U8 (&mSTUInt8)
|
#define mSCRIPT_TYPE_MS_U8 (&mSTUInt8)
|
||||||
|
@ -67,6 +75,7 @@ CXX_GUARD_START
|
||||||
#define mSCRIPT_TYPE_MS_TABLE (&mSTTable)
|
#define mSCRIPT_TYPE_MS_TABLE (&mSTTable)
|
||||||
#define mSCRIPT_TYPE_MS_WRAPPER (&mSTWrapper)
|
#define mSCRIPT_TYPE_MS_WRAPPER (&mSTWrapper)
|
||||||
#define mSCRIPT_TYPE_MS_S(STRUCT) (&mSTStruct_ ## STRUCT)
|
#define mSCRIPT_TYPE_MS_S(STRUCT) (&mSTStruct_ ## STRUCT)
|
||||||
|
#define mSCRIPT_TYPE_MS_S_METHOD(STRUCT, NAME) (&_mSTStructBindingType_ ## STRUCT ## _ ## NAME)
|
||||||
|
|
||||||
#define _mSCRIPT_FIELD_NAME(V) (V)->name
|
#define _mSCRIPT_FIELD_NAME(V) (V)->name
|
||||||
|
|
||||||
|
@ -85,6 +94,7 @@ CXX_GUARD_START
|
||||||
#define mSCRIPT_TYPE_CMP_CHARP(TYPE) mSCRIPT_TYPE_CMP_GENERIC(mSCRIPT_TYPE_MS_CHARP, TYPE)
|
#define mSCRIPT_TYPE_CMP_CHARP(TYPE) mSCRIPT_TYPE_CMP_GENERIC(mSCRIPT_TYPE_MS_CHARP, TYPE)
|
||||||
#define mSCRIPT_TYPE_CMP_PTR(TYPE) ((TYPE)->base >= mSCRIPT_TYPE_OPAQUE)
|
#define mSCRIPT_TYPE_CMP_PTR(TYPE) ((TYPE)->base >= mSCRIPT_TYPE_OPAQUE)
|
||||||
#define mSCRIPT_TYPE_CMP_S(STRUCT) mSCRIPT_TYPE_MS_S(STRUCT)->name == _mSCRIPT_FIELD_NAME
|
#define mSCRIPT_TYPE_CMP_S(STRUCT) mSCRIPT_TYPE_MS_S(STRUCT)->name == _mSCRIPT_FIELD_NAME
|
||||||
|
#define mSCRIPT_TYPE_CMP_S_METHOD(STRUCT, NAME) mSCRIPT_TYPE_MS_S_METHOD(STRUCT, NAME)->name == _mSCRIPT_FIELD_NAME
|
||||||
#define mSCRIPT_TYPE_CMP(TYPE0, TYPE1) _mAPPLY(mSCRIPT_TYPE_CMP_ ## TYPE0(TYPE1))
|
#define mSCRIPT_TYPE_CMP(TYPE0, TYPE1) _mAPPLY(mSCRIPT_TYPE_CMP_ ## TYPE0(TYPE1))
|
||||||
|
|
||||||
#define mSCRIPT_POP(STACK, TYPE, NAME) \
|
#define mSCRIPT_POP(STACK, TYPE, NAME) \
|
||||||
|
@ -116,6 +126,15 @@ CXX_GUARD_START
|
||||||
#define mSCRIPT_POP_7(FRAME, T0, T1, T2, T3, T4, T5, T6) mSCRIPT_POP(FRAME, T6, p6); mSCRIPT_POP_6(FRAME, T0, T1, T2, T3, T4, T5)
|
#define mSCRIPT_POP_7(FRAME, T0, T1, T2, T3, T4, T5, T6) mSCRIPT_POP(FRAME, T6, p6); mSCRIPT_POP_6(FRAME, T0, T1, T2, T3, T4, T5)
|
||||||
#define mSCRIPT_POP_8(FRAME, T0, T1, T2, T3, T4, T5, T6, T7) mSCRIPT_POP(FRAME, T7, p7); mSCRIPT_POP_7(FRAME, T0, T1, T2, T3, T4, T5, T6)
|
#define mSCRIPT_POP_8(FRAME, T0, T1, T2, T3, T4, T5, T6, T7) mSCRIPT_POP(FRAME, T7, p7); mSCRIPT_POP_7(FRAME, T0, T1, T2, T3, T4, T5, T6)
|
||||||
|
|
||||||
|
#define _mCOMMA_0(N, ...) N
|
||||||
|
#define _mCOMMA_1(N, ...) N, __VA_ARGS__
|
||||||
|
#define _mCOMMA_2(N, ...) N, __VA_ARGS__
|
||||||
|
#define _mCOMMA_3(N, ...) N, __VA_ARGS__
|
||||||
|
#define _mCOMMA_4(N, ...) N, __VA_ARGS__
|
||||||
|
#define _mCOMMA_5(N, ...) N, __VA_ARGS__
|
||||||
|
#define _mCOMMA_6(N, ...) N, __VA_ARGS__
|
||||||
|
#define _mCOMMA_7(N, ...) N, __VA_ARGS__
|
||||||
|
|
||||||
#define mSCRIPT_PUSH(STACK, TYPE, NAME) \
|
#define mSCRIPT_PUSH(STACK, TYPE, NAME) \
|
||||||
do { \
|
do { \
|
||||||
struct mScriptValue* _val = mScriptListAppend(STACK); \
|
struct mScriptValue* _val = mScriptListAppend(STACK); \
|
||||||
|
@ -143,10 +162,29 @@ CXX_GUARD_START
|
||||||
#define mSCRIPT_PREFIX_6(PREFIX, T0, T1, T2, T3, T4, T5) PREFIX ## T0, PREFIX ## T1, PREFIX ## T2, PREFIX ## T3, PREFIX ## T4, PREFIX ## T5
|
#define mSCRIPT_PREFIX_6(PREFIX, T0, T1, T2, T3, T4, T5) PREFIX ## T0, PREFIX ## T1, PREFIX ## T2, PREFIX ## T3, PREFIX ## T4, PREFIX ## T5
|
||||||
#define mSCRIPT_PREFIX_7(PREFIX, T0, T1, T2, T3, T4, T5, T6) PREFIX ## T0, PREFIX ## T1, PREFIX ## T2, PREFIX ## T3, PREFIX ## T4, PREFIX ## T5, PREFIX ## T6
|
#define mSCRIPT_PREFIX_7(PREFIX, T0, T1, T2, T3, T4, T5, T6) PREFIX ## T0, PREFIX ## T1, PREFIX ## T2, PREFIX ## T3, PREFIX ## T4, PREFIX ## T5, PREFIX ## T6
|
||||||
#define mSCRIPT_PREFIX_8(PREFIX, T0, T1, T2, T3, T4, T5, T6, T7) PREFIX ## T0, PREFIX ## T1, PREFIX ## T2, PREFIX ## T3, PREFIX ## T4, PREFIX ## T5, PREFIX ## T6, PREFIX ## T7
|
#define mSCRIPT_PREFIX_8(PREFIX, T0, T1, T2, T3, T4, T5, T6, T7) PREFIX ## T0, PREFIX ## T1, PREFIX ## T2, PREFIX ## T3, PREFIX ## T4, PREFIX ## T5, PREFIX ## T6, PREFIX ## T7
|
||||||
|
#define mSCRIPT_PREFIX_N(N) _mAPPLY(mSCRIPT_PREFIX_ ## N)
|
||||||
|
|
||||||
#define _mSCRIPT_CALL_VOID(FUNCTION, NPARAMS) FUNCTION(mSCRIPT_ARG_NAMES_ ## NPARAMS)
|
#define _mSUCC0 1
|
||||||
|
#define _mSUCC1 2
|
||||||
|
#define _mSUCC2 3
|
||||||
|
#define _mSUCC3 4
|
||||||
|
#define _mSUCC4 5
|
||||||
|
#define _mSUCC5 6
|
||||||
|
#define _mSUCC6 7
|
||||||
|
#define _mSUCC7 8
|
||||||
|
|
||||||
|
#define _mPREC1 0
|
||||||
|
#define _mPREC2 1
|
||||||
|
#define _mPREC3 2
|
||||||
|
#define _mPREC4 3
|
||||||
|
#define _mPREC5 4
|
||||||
|
#define _mPREC6 5
|
||||||
|
#define _mPREC7 6
|
||||||
|
#define _mPREC8 7
|
||||||
|
|
||||||
|
#define _mSCRIPT_CALL_VOID(FUNCTION, NPARAMS) FUNCTION(_mCAT(mSCRIPT_ARG_NAMES_, NPARAMS))
|
||||||
#define _mSCRIPT_CALL(RETURN, FUNCTION, NPARAMS) \
|
#define _mSCRIPT_CALL(RETURN, FUNCTION, NPARAMS) \
|
||||||
_mAPPLY(mSCRIPT_TYPE_C_ ## RETURN) out = FUNCTION(mSCRIPT_ARG_NAMES_ ## NPARAMS); \
|
_mAPPLY(mSCRIPT_TYPE_C_ ## RETURN) out = FUNCTION(_mCAT(mSCRIPT_ARG_NAMES_, NPARAMS)); \
|
||||||
mSCRIPT_PUSH(&frame->returnValues, RETURN, out)
|
mSCRIPT_PUSH(&frame->returnValues, RETURN, out)
|
||||||
|
|
||||||
#define mSCRIPT_EXPORT_STRUCT(STRUCT) \
|
#define mSCRIPT_EXPORT_STRUCT(STRUCT) \
|
||||||
|
@ -161,8 +199,9 @@ CXX_GUARD_START
|
||||||
.free = NULL, \
|
.free = NULL, \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define mSCRIPT_DECLARE_STRUCT(STRUCT) extern const struct mScriptType mSTStruct_ ## STRUCT;
|
#define mSCRIPT_DECLARE_STRUCT(STRUCT) extern const struct mScriptType mSTStruct_ ## STRUCT
|
||||||
#define mSCRIPT_DEFINE_STRUCT(STRUCT) \
|
#define mSCRIPT_DEFINE_STRUCT(STRUCT) \
|
||||||
|
const struct mScriptType mSTStruct_ ## STRUCT; \
|
||||||
static struct mScriptTypeClass _mSTStructDetails_ ## STRUCT = { \
|
static struct mScriptTypeClass _mSTStructDetails_ ## STRUCT = { \
|
||||||
.init = false, \
|
.init = false, \
|
||||||
.details = (const struct mScriptClassInitDetails[]) {
|
.details = (const struct mScriptClassInitDetails[]) {
|
||||||
|
@ -180,7 +219,7 @@ CXX_GUARD_START
|
||||||
.member = { \
|
.member = { \
|
||||||
.name = #NAME, \
|
.name = #NAME, \
|
||||||
.type = _mAPPLY(mSCRIPT_TYPE_MS_ ## TYPE), \
|
.type = _mAPPLY(mSCRIPT_TYPE_MS_ ## TYPE), \
|
||||||
.offset = offsetof(STRUCT, NAME) \
|
.offset = offsetof(struct STRUCT, NAME) \
|
||||||
} \
|
} \
|
||||||
} \
|
} \
|
||||||
},
|
},
|
||||||
|
@ -195,7 +234,72 @@ CXX_GUARD_START
|
||||||
}, \
|
}, \
|
||||||
},
|
},
|
||||||
|
|
||||||
#define mSCRIPT_DEFINE_END { .type = mSCRIPT_CLASS_INIT_END } } };
|
#define _mSCRIPT_STRUCT_METHOD_POP(TYPE, NPARAMS, ...) \
|
||||||
|
_mDEFER(_mDEFER(_mCAT(mSCRIPT_POP_, _mSUCC ## NPARAMS)) (&frame->arguments, _mCOMMA_ ## NPARAMS(S(TYPE), __VA_ARGS__))); \
|
||||||
|
if (mScriptListSize(&frame->arguments)) { \
|
||||||
|
return false; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define _mSCRIPT_DECLARE_STRUCT_METHOD(TYPE, NAME, NRET, RETURN, NPARAMS, ...) \
|
||||||
|
static bool _mSTStructBinding_ ## TYPE ## _ ## NAME(struct mScriptFrame* frame, void* ctx); \
|
||||||
|
static const struct mScriptFunction _mSTStructBindingFunction_ ## TYPE ## _ ## NAME = { \
|
||||||
|
.call = &_mSTStructBinding_ ## TYPE ## _ ## NAME \
|
||||||
|
}; \
|
||||||
|
\
|
||||||
|
static void _mSTStructBindingAlloc_ ## TYPE ## _ ## NAME(struct mScriptValue* val) { \
|
||||||
|
val->value.copaque = &_mSTStructBindingFunction_ ## TYPE ## _ ## NAME; \
|
||||||
|
}\
|
||||||
|
static const struct mScriptType _mSTStructBindingType_ ## TYPE ## _ ## NAME = { \
|
||||||
|
.base = mSCRIPT_TYPE_FUNCTION, \
|
||||||
|
.name = "struct::" #TYPE "." #NAME, \
|
||||||
|
.alloc = _mSTStructBindingAlloc_ ## TYPE ## _ ## NAME, \
|
||||||
|
.details = { \
|
||||||
|
.function = { \
|
||||||
|
.parameters = { \
|
||||||
|
.count = _mSUCC ## NPARAMS, \
|
||||||
|
.entries = { _mAPPLY(mSCRIPT_TYPE_MS_S(TYPE)), mSCRIPT_PREFIX_ ## NPARAMS(mSCRIPT_TYPE_MS_, __VA_ARGS__) } \
|
||||||
|
}, \
|
||||||
|
.returnType = { \
|
||||||
|
.count = NRET, \
|
||||||
|
.entries = { RETURN } \
|
||||||
|
}, \
|
||||||
|
}, \
|
||||||
|
} \
|
||||||
|
};
|
||||||
|
|
||||||
|
#define mSCRIPT_DECLARE_STRUCT_METHOD(TYPE, RETURN, NAME, NPARAMS, ...) \
|
||||||
|
typedef _mAPPLY(mSCRIPT_TYPE_C_ ## RETURN) (*_mSTStructFunctionType_ ## TYPE ## _ ## NAME)(_mAPPLY(_mCOMMA_ ## NPARAMS(struct TYPE* , mSCRIPT_PREFIX_ ## NPARAMS(mSCRIPT_TYPE_C_, __VA_ARGS__)))); \
|
||||||
|
_mSCRIPT_DECLARE_STRUCT_METHOD(TYPE, NAME, 1, mSCRIPT_TYPE_MS_ ## RETURN, NPARAMS, __VA_ARGS__) \
|
||||||
|
\
|
||||||
|
static bool _mSTStructBinding_ ## TYPE ## _ ## NAME(struct mScriptFrame* frame, void* ctx) { \
|
||||||
|
UNUSED(ctx); \
|
||||||
|
_mSCRIPT_STRUCT_METHOD_POP(TYPE, NPARAMS, __VA_ARGS__); \
|
||||||
|
_mSCRIPT_CALL(RETURN, p0->NAME, _mSUCC ## NPARAMS); \
|
||||||
|
return true; \
|
||||||
|
} \
|
||||||
|
|
||||||
|
#define mSCRIPT_DECLARE_STRUCT_VOID_METHOD(TYPE, NAME, NPARAMS, ...) \
|
||||||
|
typedef void (*_mSTStructFunctionType_ ## TYPE ## _ ## NAME)(_mAPPLY(_mCOMMA_ ## NPARAMS(struct TYPE* , mSCRIPT_PREFIX_ ## NPARAMS(mSCRIPT_TYPE_C_, __VA_ARGS__)))); \
|
||||||
|
_mSCRIPT_DECLARE_STRUCT_METHOD(TYPE, NAME, 0, , NPARAMS, __VA_ARGS__) \
|
||||||
|
\
|
||||||
|
static bool _mSTStructBinding_ ## TYPE ## _ ## NAME(struct mScriptFrame* frame, void* ctx) { \
|
||||||
|
UNUSED(ctx); \
|
||||||
|
_mSCRIPT_STRUCT_METHOD_POP(TYPE, NPARAMS, __VA_ARGS__); \
|
||||||
|
_mSCRIPT_CALL_VOID(p0->NAME, _mSUCC ## NPARAMS); \
|
||||||
|
return true; \
|
||||||
|
} \
|
||||||
|
|
||||||
|
#define mSCRIPT_DEFINE_STRUCT_METHOD(TYPE, NAME) { \
|
||||||
|
.type = mSCRIPT_CLASS_INIT_INSTANCE_MEMBER, \
|
||||||
|
.info = { \
|
||||||
|
.member = { \
|
||||||
|
.name = #NAME, \
|
||||||
|
.type = &_mSTStructBindingType_ ## TYPE ## _ ## NAME \
|
||||||
|
} \
|
||||||
|
}, \
|
||||||
|
},
|
||||||
|
|
||||||
|
#define mSCRIPT_DEFINE_END { .type = mSCRIPT_CLASS_INIT_END } } }
|
||||||
|
|
||||||
#define _mSCRIPT_BIND_FUNCTION(NAME, NRET, RETURN, NPARAMS, ...) \
|
#define _mSCRIPT_BIND_FUNCTION(NAME, NRET, RETURN, NPARAMS, ...) \
|
||||||
static const struct mScriptType _type_ ## NAME = { \
|
static const struct mScriptType _type_ ## NAME = { \
|
||||||
|
@ -220,7 +324,7 @@ CXX_GUARD_START
|
||||||
.type = &_type_ ## NAME, \
|
.type = &_type_ ## NAME, \
|
||||||
.refs = mSCRIPT_VALUE_UNREF, \
|
.refs = mSCRIPT_VALUE_UNREF, \
|
||||||
.value = { \
|
.value = { \
|
||||||
.opaque = &_function_ ## NAME \
|
.copaque = &_function_ ## NAME \
|
||||||
} \
|
} \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -267,6 +371,7 @@ CXX_GUARD_START
|
||||||
#define mSCRIPT_MAKE_U64(VALUE) mSCRIPT_MAKE(mSCRIPT_TYPE_MS_U64, u64, VALUE)
|
#define mSCRIPT_MAKE_U64(VALUE) mSCRIPT_MAKE(mSCRIPT_TYPE_MS_U64, u64, VALUE)
|
||||||
#define mSCRIPT_MAKE_F64(VALUE) mSCRIPT_MAKE(mSCRIPT_TYPE_MS_F64, f64, VALUE)
|
#define mSCRIPT_MAKE_F64(VALUE) mSCRIPT_MAKE(mSCRIPT_TYPE_MS_F64, f64, VALUE)
|
||||||
#define mSCRIPT_MAKE_CHARP(VALUE) mSCRIPT_MAKE(mSCRIPT_TYPE_MS_CHARP, opaque, VALUE)
|
#define mSCRIPT_MAKE_CHARP(VALUE) mSCRIPT_MAKE(mSCRIPT_TYPE_MS_CHARP, opaque, VALUE)
|
||||||
|
#define mSCRIPT_MAKE_S(STRUCT, VALUE) mSCRIPT_MAKE(mSCRIPT_TYPE_MS_S(STRUCT), opaque, VALUE)
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
mSCRIPT_TYPE_VOID = 0,
|
mSCRIPT_TYPE_VOID = 0,
|
||||||
|
@ -373,6 +478,7 @@ struct mScriptValue {
|
||||||
uint64_t u64;
|
uint64_t u64;
|
||||||
double f64;
|
double f64;
|
||||||
void* opaque;
|
void* opaque;
|
||||||
|
const void* copaque;
|
||||||
} value;
|
} value;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -414,6 +520,8 @@ void mScriptFrameDeinit(struct mScriptFrame* frame);
|
||||||
void mScriptClassInit(struct mScriptTypeClass* cls);
|
void mScriptClassInit(struct mScriptTypeClass* cls);
|
||||||
void mScriptClassDeinit(struct mScriptTypeClass* cls);
|
void mScriptClassDeinit(struct mScriptTypeClass* cls);
|
||||||
|
|
||||||
|
bool mScriptObjectGet(struct mScriptValue* obj, const char* member, struct mScriptValue*);
|
||||||
|
|
||||||
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);
|
||||||
bool mScriptPopF32(struct mScriptList* list, float* out);
|
bool mScriptPopF32(struct mScriptList* list, float* out);
|
||||||
|
|
|
@ -13,23 +13,53 @@ struct TestA {
|
||||||
int32_t i2;
|
int32_t i2;
|
||||||
int8_t b8;
|
int8_t b8;
|
||||||
int16_t hUnaligned;
|
int16_t hUnaligned;
|
||||||
|
int32_t (*ifn0)(struct TestA*);
|
||||||
|
int32_t (*ifn1)(struct TestA*, int);
|
||||||
|
void (*vfn0)(struct TestA*);
|
||||||
|
void (*vfn1)(struct TestA*, int);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static int32_t testAi0(struct TestA* a) {
|
||||||
|
return a->i;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int32_t testAi1(struct TestA* a, int b) {
|
||||||
|
return a->i + b;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void testAv0(struct TestA* a) {
|
||||||
|
++a->i;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void testAv1(struct TestA* a, int b) {
|
||||||
|
a->i += b;
|
||||||
|
}
|
||||||
|
|
||||||
#define MEMBER_A_DOCSTRING "Member a"
|
#define MEMBER_A_DOCSTRING "Member a"
|
||||||
|
|
||||||
|
mSCRIPT_DECLARE_STRUCT(TestA);
|
||||||
|
mSCRIPT_DECLARE_STRUCT_METHOD(TestA, S32, ifn0, 0);
|
||||||
|
mSCRIPT_DECLARE_STRUCT_METHOD(TestA, S32, ifn1, 1, S32);
|
||||||
|
mSCRIPT_DECLARE_STRUCT_VOID_METHOD(TestA, vfn0, 0);
|
||||||
|
mSCRIPT_DECLARE_STRUCT_VOID_METHOD(TestA, vfn1, 1, S32);
|
||||||
|
|
||||||
mSCRIPT_DEFINE_STRUCT(TestA)
|
mSCRIPT_DEFINE_STRUCT(TestA)
|
||||||
mSCRIPT_DEFINE_DOCSTRING(MEMBER_A_DOCSTRING)
|
mSCRIPT_DEFINE_DOCSTRING(MEMBER_A_DOCSTRING)
|
||||||
mSCRIPT_DEFINE_STRUCT_MEMBER(struct TestA, S32, i)
|
mSCRIPT_DEFINE_STRUCT_MEMBER(TestA, S32, i)
|
||||||
mSCRIPT_DEFINE_STRUCT_MEMBER(struct TestA, S32, i2)
|
mSCRIPT_DEFINE_STRUCT_MEMBER(TestA, S32, i2)
|
||||||
mSCRIPT_DEFINE_STRUCT_MEMBER(struct TestA, S8, b8)
|
mSCRIPT_DEFINE_STRUCT_MEMBER(TestA, S8, b8)
|
||||||
mSCRIPT_DEFINE_STRUCT_MEMBER(struct TestA, S16, hUnaligned)
|
mSCRIPT_DEFINE_STRUCT_MEMBER(TestA, S16, hUnaligned)
|
||||||
|
mSCRIPT_DEFINE_STRUCT_METHOD(TestA, ifn0)
|
||||||
|
mSCRIPT_DEFINE_STRUCT_METHOD(TestA, ifn1)
|
||||||
|
mSCRIPT_DEFINE_STRUCT_METHOD(TestA, vfn0)
|
||||||
|
mSCRIPT_DEFINE_STRUCT_METHOD(TestA, vfn1)
|
||||||
|
|
||||||
mSCRIPT_DEFINE_DOCSTRING(MEMBER_A_DOCSTRING)
|
mSCRIPT_DEFINE_DOCSTRING(MEMBER_A_DOCSTRING)
|
||||||
mSCRIPT_DEFINE_STATIC_MEMBER(S32, i)
|
mSCRIPT_DEFINE_STATIC_MEMBER(S32, s_i)
|
||||||
mSCRIPT_DEFINE_STATIC_MEMBER(S32, i2)
|
mSCRIPT_DEFINE_STATIC_MEMBER(S32, s_i2)
|
||||||
mSCRIPT_DEFINE_STATIC_MEMBER(S8, b8)
|
mSCRIPT_DEFINE_STATIC_MEMBER(S8, s_b8)
|
||||||
mSCRIPT_DEFINE_STATIC_MEMBER(S16, hUnaligned)
|
mSCRIPT_DEFINE_STATIC_MEMBER(S16, s_hUnaligned)
|
||||||
mSCRIPT_DEFINE_END
|
mSCRIPT_DEFINE_END;
|
||||||
|
|
||||||
mSCRIPT_EXPORT_STRUCT(TestA);
|
mSCRIPT_EXPORT_STRUCT(TestA);
|
||||||
|
|
||||||
|
@ -74,30 +104,30 @@ M_TEST_DEFINE(testALayout) {
|
||||||
assert_null(member);
|
assert_null(member);
|
||||||
|
|
||||||
// Static members
|
// Static members
|
||||||
member = HashTableLookup(&cls->staticMembers, "i");
|
member = HashTableLookup(&cls->staticMembers, "s_i");
|
||||||
assert_non_null(member);
|
assert_non_null(member);
|
||||||
assert_string_equal(member->name, "i");
|
assert_string_equal(member->name, "s_i");
|
||||||
assert_string_equal(member->docstring, MEMBER_A_DOCSTRING);
|
assert_string_equal(member->docstring, MEMBER_A_DOCSTRING);
|
||||||
assert_ptr_equal(member->type, mSCRIPT_TYPE_MS_S32);
|
assert_ptr_equal(member->type, mSCRIPT_TYPE_MS_S32);
|
||||||
assert_int_equal(member->offset, 0);
|
assert_int_equal(member->offset, 0);
|
||||||
|
|
||||||
member = HashTableLookup(&cls->staticMembers, "i2");
|
member = HashTableLookup(&cls->staticMembers, "s_i2");
|
||||||
assert_non_null(member);
|
assert_non_null(member);
|
||||||
assert_string_equal(member->name, "i2");
|
assert_string_equal(member->name, "s_i2");
|
||||||
assert_null(member->docstring);
|
assert_null(member->docstring);
|
||||||
assert_ptr_equal(member->type, mSCRIPT_TYPE_MS_S32);
|
assert_ptr_equal(member->type, mSCRIPT_TYPE_MS_S32);
|
||||||
assert_int_equal(member->offset, sizeof(int32_t));
|
assert_int_equal(member->offset, sizeof(int32_t));
|
||||||
|
|
||||||
member = HashTableLookup(&cls->staticMembers, "b8");
|
member = HashTableLookup(&cls->staticMembers, "s_b8");
|
||||||
assert_non_null(member);
|
assert_non_null(member);
|
||||||
assert_string_equal(member->name, "b8");
|
assert_string_equal(member->name, "s_b8");
|
||||||
assert_null(member->docstring);
|
assert_null(member->docstring);
|
||||||
assert_ptr_equal(member->type, mSCRIPT_TYPE_MS_S8);
|
assert_ptr_equal(member->type, mSCRIPT_TYPE_MS_S8);
|
||||||
assert_int_equal(member->offset, sizeof(int32_t) * 2);
|
assert_int_equal(member->offset, sizeof(int32_t) * 2);
|
||||||
|
|
||||||
member = HashTableLookup(&cls->staticMembers, "hUnaligned");
|
member = HashTableLookup(&cls->staticMembers, "s_hUnaligned");
|
||||||
assert_non_null(member);
|
assert_non_null(member);
|
||||||
assert_string_equal(member->name, "hUnaligned");
|
assert_string_equal(member->name, "s_hUnaligned");
|
||||||
assert_null(member->docstring);
|
assert_null(member->docstring);
|
||||||
assert_ptr_equal(member->type, mSCRIPT_TYPE_MS_S16);
|
assert_ptr_equal(member->type, mSCRIPT_TYPE_MS_S16);
|
||||||
assert_int_not_equal(member->offset, sizeof(int32_t) * 2 + 1);
|
assert_int_not_equal(member->offset, sizeof(int32_t) * 2 + 1);
|
||||||
|
@ -109,5 +139,120 @@ M_TEST_DEFINE(testALayout) {
|
||||||
assert_false(cls->init);
|
assert_false(cls->init);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
M_TEST_DEFINE(testATranslation) {
|
||||||
|
struct mScriptTypeClass* cls = mSCRIPT_TYPE_MS_S(TestA)->details.cls;
|
||||||
|
|
||||||
|
struct TestA s = {
|
||||||
|
.i = 1,
|
||||||
|
.i2 = 2,
|
||||||
|
.b8 = 3,
|
||||||
|
.hUnaligned = 4
|
||||||
|
};
|
||||||
|
|
||||||
|
struct mScriptValue sval = mSCRIPT_MAKE_S(TestA, &s);
|
||||||
|
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));
|
||||||
|
|
||||||
|
assert_true(cls->init);
|
||||||
|
mScriptClassDeinit(cls);
|
||||||
|
assert_false(cls->init);
|
||||||
|
}
|
||||||
|
|
||||||
|
M_TEST_DEFINE(testAFunctions) {
|
||||||
|
struct mScriptTypeClass* cls = mSCRIPT_TYPE_MS_S(TestA)->details.cls;
|
||||||
|
assert_false(cls->init);
|
||||||
|
mScriptClassInit(cls);
|
||||||
|
assert_true(cls->init);
|
||||||
|
|
||||||
|
struct mScriptClassMember* member;
|
||||||
|
|
||||||
|
// Instance methods
|
||||||
|
member = HashTableLookup(&cls->instanceMembers, "ifn0");
|
||||||
|
assert_non_null(member);
|
||||||
|
assert_string_equal(member->name, "ifn0");
|
||||||
|
assert_int_equal(member->type->base, mSCRIPT_TYPE_FUNCTION);
|
||||||
|
assert_int_equal(member->type->details.function.parameters.count, 1);
|
||||||
|
assert_ptr_equal(member->type->details.function.parameters.entries[0], mSCRIPT_TYPE_MS_S(TestA));
|
||||||
|
|
||||||
|
struct TestA s = {
|
||||||
|
.i = 1,
|
||||||
|
.ifn0 = testAi0,
|
||||||
|
.ifn1 = testAi1,
|
||||||
|
.vfn0 = testAv0,
|
||||||
|
.vfn1 = testAv1,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct mScriptValue sval = mSCRIPT_MAKE_S(TestA, &s);
|
||||||
|
struct mScriptValue val;
|
||||||
|
struct mScriptFrame frame;
|
||||||
|
int32_t rval;
|
||||||
|
|
||||||
|
assert_true(mScriptObjectGet(&sval, "ifn0", &val));
|
||||||
|
mScriptFrameInit(&frame);
|
||||||
|
mSCRIPT_PUSH(&frame.arguments, S(TestA), &s);
|
||||||
|
assert_true(mScriptInvoke(&val, &frame));
|
||||||
|
assert_true(mScriptPopS32(&frame.returnValues, &rval));
|
||||||
|
assert_int_equal(rval, 1);
|
||||||
|
mScriptFrameDeinit(&frame);
|
||||||
|
|
||||||
|
assert_true(mScriptObjectGet(&sval, "ifn1", &val));
|
||||||
|
mScriptFrameInit(&frame);
|
||||||
|
mSCRIPT_PUSH(&frame.arguments, S(TestA), &s);
|
||||||
|
mSCRIPT_PUSH(&frame.arguments, S32, 1);
|
||||||
|
assert_true(mScriptInvoke(&val, &frame));
|
||||||
|
assert_true(mScriptPopS32(&frame.returnValues, &rval));
|
||||||
|
assert_int_equal(rval, 2);
|
||||||
|
mScriptFrameDeinit(&frame);
|
||||||
|
|
||||||
|
assert_true(mScriptObjectGet(&sval, "vfn0", &val));
|
||||||
|
mScriptFrameInit(&frame);
|
||||||
|
mSCRIPT_PUSH(&frame.arguments, S(TestA), &s);
|
||||||
|
assert_true(mScriptInvoke(&val, &frame));
|
||||||
|
mScriptFrameDeinit(&frame);
|
||||||
|
assert_true(mScriptObjectGet(&sval, "ifn0", &val));
|
||||||
|
mScriptFrameInit(&frame);
|
||||||
|
mSCRIPT_PUSH(&frame.arguments, S(TestA), &s);
|
||||||
|
assert_true(mScriptInvoke(&val, &frame));
|
||||||
|
assert_true(mScriptPopS32(&frame.returnValues, &rval));
|
||||||
|
assert_int_equal(rval, 2);
|
||||||
|
mScriptFrameDeinit(&frame);
|
||||||
|
|
||||||
|
assert_true(mScriptObjectGet(&sval, "vfn1", &val));
|
||||||
|
mScriptFrameInit(&frame);
|
||||||
|
mSCRIPT_PUSH(&frame.arguments, S(TestA), &s);
|
||||||
|
mSCRIPT_PUSH(&frame.arguments, S32, 2);
|
||||||
|
assert_true(mScriptInvoke(&val, &frame));
|
||||||
|
mScriptFrameDeinit(&frame);
|
||||||
|
assert_true(mScriptObjectGet(&sval, "ifn0", &val));
|
||||||
|
mScriptFrameInit(&frame);
|
||||||
|
mSCRIPT_PUSH(&frame.arguments, S(TestA), &s);
|
||||||
|
assert_true(mScriptInvoke(&val, &frame));
|
||||||
|
assert_true(mScriptPopS32(&frame.returnValues, &rval));
|
||||||
|
assert_int_equal(rval, 4);
|
||||||
|
mScriptFrameDeinit(&frame);
|
||||||
|
|
||||||
|
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(testATranslation),
|
||||||
|
cmocka_unit_test(testAFunctions))
|
||||||
|
|
|
@ -13,7 +13,7 @@ struct Test {
|
||||||
};
|
};
|
||||||
|
|
||||||
mSCRIPT_DEFINE_STRUCT(Test)
|
mSCRIPT_DEFINE_STRUCT(Test)
|
||||||
mSCRIPT_DEFINE_END
|
mSCRIPT_DEFINE_END;
|
||||||
|
|
||||||
mSCRIPT_EXPORT_STRUCT(Test);
|
mSCRIPT_EXPORT_STRUCT(Test);
|
||||||
|
|
||||||
|
|
|
@ -807,6 +807,84 @@ void mScriptClassDeinit(struct mScriptTypeClass* cls) {
|
||||||
cls->init = false;
|
cls->init = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool mScriptObjectGet(struct mScriptValue* obj, const char* member, struct mScriptValue* val) {
|
||||||
|
if (obj->type->base != mSCRIPT_TYPE_OBJECT) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct mScriptTypeClass* cls = obj->type->details.cls;
|
||||||
|
if (!cls) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
mScriptClassInit(cls);
|
||||||
|
|
||||||
|
struct mScriptClassMember* m = HashTableLookup(&cls->instanceMembers, member);
|
||||||
|
if (!m) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* rawMember = (void *)((uintptr_t) obj->value.opaque + m->offset);
|
||||||
|
switch (m->type->base) {
|
||||||
|
case mSCRIPT_TYPE_SINT:
|
||||||
|
switch (m->type->size) {
|
||||||
|
case 1:
|
||||||
|
*val = mSCRIPT_MAKE_S32(*(int8_t *) rawMember);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
*val = mSCRIPT_MAKE_S32(*(int16_t *) rawMember);
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
*val = mSCRIPT_MAKE_S32(*(int32_t *) rawMember);
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
*val = mSCRIPT_MAKE_S64(*(int64_t *) rawMember);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case mSCRIPT_TYPE_UINT:
|
||||||
|
switch (m->type->size) {
|
||||||
|
case 1:
|
||||||
|
*val = mSCRIPT_MAKE_U32(*(uint8_t *) rawMember);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
*val = mSCRIPT_MAKE_U32(*(uint16_t *) rawMember);
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
*val = mSCRIPT_MAKE_U32(*(uint32_t *) rawMember);
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
*val = mSCRIPT_MAKE_U64(*(uint64_t *) rawMember);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case mSCRIPT_TYPE_FLOAT:
|
||||||
|
switch (m->type->size) {
|
||||||
|
case 4:
|
||||||
|
*val = mSCRIPT_MAKE_F32(*(mSCRIPT_TYPE_C_F32 *) rawMember);
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
*val = mSCRIPT_MAKE_F64(*(mSCRIPT_TYPE_C_F64 *) rawMember);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case mSCRIPT_TYPE_FUNCTION:
|
||||||
|
val->refs = mSCRIPT_VALUE_UNREF;
|
||||||
|
val->type = m->type;
|
||||||
|
m->type->alloc(val);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
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