Scripting: Add overloads, overload isKeyActive

This commit is contained in:
Vicki Pfau 2024-04-02 22:53:02 -07:00
parent e3edca1f41
commit 5ff777d301
9 changed files with 255 additions and 55 deletions

View File

@ -254,7 +254,7 @@ CXX_GUARD_START
return false; \
}
#define _mSCRIPT_DECLARE_STRUCT_METHOD(TYPE, NAME, S, NRET, RETURN, NPARAMS, DEFAULTS, ...) \
#define _mSCRIPT_DECLARE_STRUCT_METHOD_HEAD(TYPE, NAME) \
static bool _mSTStructBinding_ ## TYPE ## _ ## NAME(struct mScriptFrame* frame, void* ctx); \
static const struct mScriptFunction _mSTStructBindingFunction_ ## TYPE ## _ ## NAME = { \
.call = &_mSTStructBinding_ ## TYPE ## _ ## NAME \
@ -269,6 +269,9 @@ CXX_GUARD_START
.alloc = _mSTStructBindingAlloc_ ## TYPE ## _ ## NAME, \
.details = { \
.function = { \
#define _mSCRIPT_DECLARE_STRUCT_METHOD(TYPE, NAME, S, NRET, RETURN, NPARAMS, DEFAULTS, ...) \
_mSCRIPT_DECLARE_STRUCT_METHOD_HEAD(TYPE, NAME) \
.parameters = { \
.count = _mSUCC_ ## NPARAMS, \
.entries = { mSCRIPT_TYPE_MS_ ## S(TYPE), _mCALL(mSCRIPT_PREFIX_ ## NPARAMS, mSCRIPT_TYPE_MS_, _mEVEN_ ## NPARAMS(__VA_ARGS__)) }, \
@ -283,6 +286,23 @@ CXX_GUARD_START
} \
};
#define _mSCRIPT_DECLARE_STRUCT_OVERLOADED_METHOD(TYPE, NAME, S, NRET, RETURN) \
_mSCRIPT_DECLARE_STRUCT_METHOD_HEAD(TYPE, NAME) \
.parameters = { \
.count = 1, \
.entries = { mSCRIPT_TYPE_MS_ ## S(TYPE) }, \
.names = { "this" }, \
.defaults = NULL, \
.variable = true, \
}, \
.returnType = { \
.count = NRET, \
.entries = { RETURN } \
}, \
}, \
} \
};
#define _mSCRIPT_DECLARE_STRUCT_METHOD_SIGNATURE(TYPE, RETURN, NAME, CONST, NPARAMS, ...) \
typedef RETURN (*_mSTStructFunctionType_ ## TYPE ## _ ## NAME)(_mCOMMA_ ## NPARAMS(CONST struct TYPE* , mSCRIPT_PREFIX_ ## NPARAMS(mSCRIPT_TYPE_C_, __VA_ARGS__)))
@ -302,6 +322,20 @@ CXX_GUARD_START
return true; \
} \
#define _mSCRIPT_DECLARE_STRUCT_OVERLOADED_METHOD_BINDING(TYPE, NAME, T) \
static const struct mScriptFunctionOverload _mSTStructBindingOverloads_ ## TYPE ## _ ## NAME[]; \
static bool _mSTStructBinding_ ## TYPE ## _ ## NAME(struct mScriptFrame* frame, void* ctx) { \
UNUSED(ctx); \
const struct mScriptFunctionOverload* overload = mScriptFunctionFindOverload(_mSTStructBindingOverloads_ ## TYPE ## _ ## NAME, &frame->arguments); \
if (!overload) { \
return false; \
} \
if (!mScriptCoerceFrame(&overload->type->details.function.parameters, &frame->arguments, &frame->arguments)) { \
return false; \
} \
return overload->function->call(frame, overload->function->context); \
}
#define mSCRIPT_DECLARE_STRUCT_METHOD(TYPE, RETURN, NAME, FUNCTION, NPARAMS, ...) \
_mSCRIPT_DECLARE_STRUCT_METHOD_SIGNATURE(TYPE, mSCRIPT_TYPE_C_ ## RETURN, NAME, , NPARAMS, _mEVEN_ ## NPARAMS(__VA_ARGS__)); \
_mSCRIPT_DECLARE_STRUCT_METHOD(TYPE, NAME, S, 1, mSCRIPT_TYPE_MS_ ## RETURN, NPARAMS, NULL, __VA_ARGS__) \
@ -346,6 +380,22 @@ CXX_GUARD_START
_mSCRIPT_DECLARE_STRUCT_METHOD(TYPE, NAME, CS, 0, 0, NPARAMS, _mIDENT(_mSTStructBindingDefaults_ ## TYPE ## _ ## NAME, __VA_ARGS__) \
_mSCRIPT_DECLARE_STRUCT_VOID_METHOD_BINDING(TYPE, NAME, FUNCTION, CS, NPARAMS, __VA_ARGS__)
#define mSCRIPT_DECLARE_STRUCT_OVERLOADED_METHOD(TYPE, RETURN, NAME) \
_mSCRIPT_DECLARE_STRUCT_OVERLOADED_METHOD(TYPE, NAME, S, 1, mSCRIPT_TYPE_MS_ ## RETURN) \
_mSCRIPT_DECLARE_STRUCT_OVERLOADED_METHOD_BINDING(TYPE, NAME, S)
#define mSCRIPT_DECLARE_STRUCT_OVERLOADED_VOID_METHOD(TYPE, NAME) \
_mSCRIPT_DECLARE_STRUCT_OVERLOADED_METHOD(TYPE, NAME, S, 0, 0) \
_mSCRIPT_DECLARE_STRUCT_OVERLOADED_METHOD_BINDING(TYPE, NAME, S)
#define mSCRIPT_DECLARE_STRUCT_OVERLOADED_C_METHOD(TYPE, RETURN, NAME) \
_mSCRIPT_DECLARE_STRUCT_OVERLOADED_METHOD(TYPE, NAME, CS, 1, mSCRIPT_TYPE_MS_ ## RETURN) \
_mSCRIPT_DECLARE_STRUCT_OVERLOADED_METHOD_BINDING(TYPE, NAME, CS)
#define mSCRIPT_DECLARE_STRUCT_OVERLOADED_VOID_C_METHOD(TYPE, NAME) \
_mSCRIPT_DECLARE_STRUCT_OVERLOADED_METHOD(TYPE, NAME, CS, 0, 0) \
_mSCRIPT_DECLARE_STRUCT_OVERLOADED_METHOD_BINDING(TYPE, NAME, CS)
#define mSCRIPT_DECLARE_STRUCT_D_METHOD(TYPE, RETURN, NAME, NPARAMS, ...) \
mSCRIPT_DECLARE_STRUCT_METHOD(TYPE, RETURN, NAME, p0->NAME, NPARAMS, __VA_ARGS__)
@ -417,27 +467,39 @@ CXX_GUARD_START
#define mSCRIPT_DEFINE_DEFAULTS_END }
#define _mSCRIPT_DEFINE_STRUCT_BINDING(INIT_TYPE, TYPE, EXPORTED_NAME, NAME) { \
#define mSCRIPT_DEFINE_STRUCT_METHOD_OVERLOADS(STRUCT, METHOD) \
static const struct mScriptFunctionOverload _mSTStructBindingOverloads_ ## STRUCT ## _ ## METHOD[] = { \
#define mSCRIPT_DEFINE_STRUCT_METHOD_OVERLOAD(TYPE, FUNCTION) { \
.type = &_mSTStructBindingType_ ## TYPE ## _ ## FUNCTION, \
.function = &_mSTStructBindingFunction_ ## TYPE ## _ ## FUNCTION \
},
#define mSCRIPT_DEFINE_OVERLOADS_END { NULL, NULL } }
#define _mSCRIPT_DEFINE_STRUCT_BINDING(INIT_TYPE, TYPE, EXPORTED_NAME, NAME, OVERLOADS) { \
.type = mSCRIPT_CLASS_INIT_ ## INIT_TYPE, \
.info = { \
.member = { \
.name = #EXPORTED_NAME, \
.type = &_mSTStructBindingType_ ## TYPE ## _ ## NAME \
.type = &_mSTStructBindingType_ ## TYPE ## _ ## NAME, \
.overloads = OVERLOADS, \
} \
}, \
},
#define mSCRIPT_DEFINE_STRUCT_METHOD_NAMED(TYPE, EXPORTED_NAME, NAME) \
_mSCRIPT_DEFINE_STRUCT_BINDING(INSTANCE_MEMBER, TYPE, EXPORTED_NAME, NAME)
_mSCRIPT_DEFINE_STRUCT_BINDING(INSTANCE_MEMBER, TYPE, EXPORTED_NAME, NAME, NULL)
#define mSCRIPT_DEFINE_STRUCT_METHOD(TYPE, NAME) mSCRIPT_DEFINE_STRUCT_METHOD_NAMED(TYPE, NAME, NAME)
#define mSCRIPT_DEFINE_STRUCT_OVERLOADED_METHOD(TYPE, NAME) _mSCRIPT_DEFINE_STRUCT_BINDING(INSTANCE_MEMBER, TYPE, NAME, NAME, _mSTStructBindingOverloads_ ## TYPE ## _ ## NAME)
#define mSCRIPT_DEFINE_STRUCT_INIT(TYPE) _mSCRIPT_DEFINE_STRUCT_BINDING(INIT, TYPE, _init, _init)
#define mSCRIPT_DEFINE_STRUCT_INIT_NAMED(TYPE, NAME) _mSCRIPT_DEFINE_STRUCT_BINDING(INIT, TYPE, _init, NAME)
#define mSCRIPT_DEFINE_STRUCT_DEINIT(TYPE) _mSCRIPT_DEFINE_STRUCT_BINDING(DEINIT, TYPE, _deinit, _deinit)
#define mSCRIPT_DEFINE_STRUCT_DEINIT_NAMED(TYPE, NAME) _mSCRIPT_DEFINE_STRUCT_BINDING(DEINIT, TYPE, _deinit, NAME)
#define mSCRIPT_DEFINE_STRUCT_DEFAULT_GET(TYPE) _mSCRIPT_DEFINE_STRUCT_BINDING(GET, TYPE, _get, _get)
#define mSCRIPT_DEFINE_STRUCT_DEFAULT_SET(TYPE, SETTER) _mSCRIPT_DEFINE_STRUCT_BINDING(SET, TYPE, SETTER, SETTER)
#define mSCRIPT_DEFINE_STRUCT_INIT(TYPE) _mSCRIPT_DEFINE_STRUCT_BINDING(INIT, TYPE, _init, _init, NULL)
#define mSCRIPT_DEFINE_STRUCT_INIT_NAMED(TYPE, NAME) _mSCRIPT_DEFINE_STRUCT_BINDING(INIT, TYPE, _init, NAME, NULL)
#define mSCRIPT_DEFINE_STRUCT_DEINIT(TYPE) _mSCRIPT_DEFINE_STRUCT_BINDING(DEINIT, TYPE, _deinit, _deinit, NULL)
#define mSCRIPT_DEFINE_STRUCT_DEINIT_NAMED(TYPE, NAME) _mSCRIPT_DEFINE_STRUCT_BINDING(DEINIT, TYPE, _deinit, NAME, NULL)
#define mSCRIPT_DEFINE_STRUCT_DEFAULT_GET(TYPE) _mSCRIPT_DEFINE_STRUCT_BINDING(GET, TYPE, _get, _get, NULL)
#define mSCRIPT_DEFINE_STRUCT_DEFAULT_SET(TYPE, SETTER) _mSCRIPT_DEFINE_STRUCT_BINDING(SET, TYPE, SETTER, SETTER, NULL)
#define mSCRIPT_DEFINE_DOC_STRUCT_METHOD(SCOPE, TYPE, NAME) mSCRIPT_DEFINE_STRUCT_METHOD_NAMED(doc_ ## TYPE, NAME, NAME)

View File

@ -259,6 +259,7 @@ struct mScriptClassMember {
const char* name;
const char* docstring;
const struct mScriptType* type;
const struct mScriptFunctionOverload* overloads;
size_t offset;
bool readonly;
};
@ -275,6 +276,7 @@ struct mScriptClassInitDetails {
const struct mScriptType* parent;
struct mScriptClassMember member;
struct mScriptClassCastMember castMember;
const struct mScriptFunctionOverload* overload;
} info;
};
@ -332,6 +334,11 @@ struct mScriptFunction {
void* context;
};
struct mScriptFunctionOverload {
const struct mScriptType* type;
const struct mScriptFunction* function;
};
struct mScriptValue* mScriptValueAlloc(const struct mScriptType* type);
void mScriptValueRef(struct mScriptValue* val);
void mScriptValueDeref(struct mScriptValue* val);
@ -385,7 +392,8 @@ bool mScriptPopBool(struct mScriptList* list, bool* out);
bool mScriptPopPointer(struct mScriptList* list, void** out);
bool mScriptCast(const struct mScriptType* type, const struct mScriptValue* input, struct mScriptValue* output);
bool mScriptCoerceFrame(const struct mScriptTypeTuple* types, struct mScriptList* frame);
bool mScriptCoerceFrame(const struct mScriptTypeTuple* types, const struct mScriptList* input, struct mScriptList* output);
const struct mScriptFunctionOverload* mScriptFunctionFindOverload(const struct mScriptFunctionOverload* overloads, struct mScriptList* frame);
CXX_GUARD_END

View File

@ -481,7 +481,7 @@ bool mScriptInvoke(const struct mScriptValue* val, struct mScriptFrame* frame) {
return false;
}
const struct mScriptTypeFunction* signature = &val->type->details.function;
if (!mScriptCoerceFrame(&signature->parameters, &frame->arguments)) {
if (!mScriptCoerceFrame(&signature->parameters, &frame->arguments, &frame->arguments)) {
return false;
}
const struct mScriptFunction* fn = val->value.opaque;

View File

@ -35,20 +35,28 @@ struct mScriptInputContext {
};
static void _mScriptInputDeinit(struct mScriptInputContext*);
static bool _mScriptInputIsKeyActive(const struct mScriptInputContext*, struct mScriptValue*);
static bool _mScriptInputIsKeyActiveStr(const struct mScriptInputContext*, const char*);
static bool _mScriptInputIsKeyActiveNum(const struct mScriptInputContext*, uint32_t);
static struct mScriptValue* _mScriptInputActiveKeys(const struct mScriptInputContext*);
mSCRIPT_DECLARE_STRUCT(mScriptInputContext);
mSCRIPT_DECLARE_STRUCT_VOID_METHOD(mScriptInputContext, _deinit, _mScriptInputDeinit, 0);
mSCRIPT_DECLARE_STRUCT_C_METHOD(mScriptInputContext, BOOL, isKeyActive, _mScriptInputIsKeyActive, 1, WRAPPER, key);
mSCRIPT_DECLARE_STRUCT_C_METHOD(mScriptInputContext, BOOL, isKeyActiveStr, _mScriptInputIsKeyActiveStr, 1, CHARP, key);
mSCRIPT_DECLARE_STRUCT_C_METHOD(mScriptInputContext, BOOL, isKeyActiveNum, _mScriptInputIsKeyActiveNum, 1, U32, key);
mSCRIPT_DECLARE_STRUCT_OVERLOADED_C_METHOD(mScriptInputContext, BOOL, isKeyActive);
mSCRIPT_DECLARE_STRUCT_C_METHOD(mScriptInputContext, WLIST, activeKeys, _mScriptInputActiveKeys, 0);
mSCRIPT_DEFINE_STRUCT_METHOD_OVERLOADS(mScriptInputContext, isKeyActive)
mSCRIPT_DEFINE_STRUCT_METHOD_OVERLOAD(mScriptInputContext, isKeyActiveStr)
mSCRIPT_DEFINE_STRUCT_METHOD_OVERLOAD(mScriptInputContext, isKeyActiveNum)
mSCRIPT_DEFINE_OVERLOADS_END;
mSCRIPT_DEFINE_STRUCT(mScriptInputContext)
mSCRIPT_DEFINE_STRUCT_DEINIT(mScriptInputContext)
mSCRIPT_DEFINE_DOCSTRING("Sequence number of the next event to be emitted")
mSCRIPT_DEFINE_STRUCT_MEMBER(mScriptInputContext, U64, seq)
mSCRIPT_DEFINE_DOCSTRING("Check if a given keyboard key is currently held. The input can be either the printable character for a key, the numerical Unicode codepoint, or a special value from C.KEY")
mSCRIPT_DEFINE_STRUCT_METHOD(mScriptInputContext, isKeyActive)
mSCRIPT_DEFINE_STRUCT_OVERLOADED_METHOD(mScriptInputContext, isKeyActive)
mSCRIPT_DEFINE_DOCSTRING("Get a list of the currently active keys. The values are Unicode codepoints or special key values from C.KEY, not strings, so make sure to convert as needed")
mSCRIPT_DEFINE_STRUCT_METHOD(mScriptInputContext, activeKeys)
mSCRIPT_DEFINE_DOCSTRING("The currently active gamepad, if any")
@ -319,33 +327,18 @@ void _mScriptInputDeinit(struct mScriptInputContext* context) {
TableDeinit(&context->activeKeys);
}
bool _mScriptInputIsKeyActive(const struct mScriptInputContext* context, struct mScriptValue* value) {
bool _mScriptInputIsKeyActiveStr(const struct mScriptInputContext* context, const char* value) {
uint32_t key;
struct mScriptValue intValue;
size_t length;
const char* strbuf;
switch (value->type->base) {
case mSCRIPT_TYPE_SINT:
case mSCRIPT_TYPE_UINT:
case mSCRIPT_TYPE_FLOAT:
if (!mScriptCast(mSCRIPT_TYPE_MS_U32, value, &intValue)) {
return false;
}
key = intValue.value.u32;
break;
case mSCRIPT_TYPE_STRING:
if (value->value.string->length > 1) {
return false;
}
strbuf = value->value.string->buffer;
length = value->value.string->size;
key = utf8Char(&strbuf, &length);
break;
default:
size_t length = strlen(value);
key = utf8Char(&value, &length);
if (length > 0) {
return false;
}
void* down = TableLookup(&context->activeKeys, key);
return down != NULL;
}
bool _mScriptInputIsKeyActiveNum(const struct mScriptInputContext* context, uint32_t key) {
void* down = TableLookup(&context->activeKeys, key);
return down != NULL;
}

View File

@ -57,6 +57,11 @@ struct TestH {
int32_t j;
};
struct TestI {
uint32_t num;
const char* str;
};
static int32_t testAi0(struct TestA* a) {
return a->i;
}
@ -114,6 +119,14 @@ static void testSetC(struct TestG* g, const char* name, const char* val) {
g->c = val;
}
static void callNum(struct TestI* i, uint32_t num) {
i->num = num;
}
static void callStr(struct TestI* i, const char* str) {
i->str = str;
}
#define MEMBER_A_DOCSTRING "Member a"
mSCRIPT_DECLARE_STRUCT(TestA);
@ -201,12 +214,25 @@ mSCRIPT_DEFINE_STRUCT(TestG)
mSCRIPT_DEFINE_STRUCT_DEFAULT_SET(TestG, setC)
mSCRIPT_DEFINE_END;
mSCRIPT_DEFINE_STRUCT(TestH)
mSCRIPT_DEFINE_STRUCT_MEMBER(TestH, S32, i)
mSCRIPT_DEFINE_STRUCT_CONST_MEMBER(TestH, S32, j)
mSCRIPT_DEFINE_END;
mSCRIPT_DECLARE_STRUCT(TestI);
mSCRIPT_DECLARE_STRUCT_VOID_METHOD(TestI, callStr, callStr, 1, CHARP, value);
mSCRIPT_DECLARE_STRUCT_VOID_METHOD(TestI, callNum, callNum, 1, U32, value);
mSCRIPT_DECLARE_STRUCT_OVERLOADED_VOID_METHOD(TestI, call);
mSCRIPT_DEFINE_STRUCT_METHOD_OVERLOADS(TestI, call)
mSCRIPT_DEFINE_STRUCT_METHOD_OVERLOAD(TestI, callStr)
mSCRIPT_DEFINE_STRUCT_METHOD_OVERLOAD(TestI, callNum)
mSCRIPT_DEFINE_OVERLOADS_END;
mSCRIPT_DEFINE_STRUCT(TestI)
mSCRIPT_DEFINE_STRUCT_OVERLOADED_METHOD(TestI, call)
mSCRIPT_DEFINE_END;
M_TEST_DEFINE(testALayout) {
struct mScriptTypeClass* cls = mSCRIPT_TYPE_MS_S(TestA)->details.cls;
assert_false(cls->init);
@ -1184,6 +1210,44 @@ M_TEST_DEFINE(testHSet) {
assert_false(cls->init);
}
M_TEST_DEFINE(testOverloadsBasic) {
struct mScriptTypeClass* cls = mSCRIPT_TYPE_MS_S(TestI)->details.cls;
assert_false(cls->init);
mScriptClassInit(cls);
assert_true(cls->init);
struct TestI s = {
.num = 0,
.str = NULL,
};
struct mScriptValue sval = mSCRIPT_MAKE_S(TestI, &s);
struct mScriptValue fn;
struct mScriptFrame frame;
assert_true(mScriptObjectGet(&sval, "call", &fn));
mScriptFrameInit(&frame);
mSCRIPT_PUSH(&frame.arguments, S(TestI), &s);
mSCRIPT_PUSH(&frame.arguments, U32, 1);
assert_true(mScriptInvoke(&fn, &frame));
mScriptFrameDeinit(&frame);
assert_int_equal(s.num, 1);
assert_null(s.str);
mScriptFrameInit(&frame);
mSCRIPT_PUSH(&frame.arguments, S(TestI), &s);
mSCRIPT_PUSH(&frame.arguments, CHARP, "called");
assert_true(mScriptInvoke(&fn, &frame));
mScriptFrameDeinit(&frame);
assert_int_equal(s.num, 1);
assert_string_equal(s.str, "called");
assert_true(cls->init);
mScriptClassDeinit(cls);
assert_false(cls->init);
}
M_TEST_SUITE_DEFINE(mScriptClasses,
cmocka_unit_test(testALayout),
cmocka_unit_test(testASignatures),
@ -1201,4 +1265,5 @@ M_TEST_SUITE_DEFINE(mScriptClasses,
cmocka_unit_test(testFDeinit),
cmocka_unit_test(testGSet),
cmocka_unit_test(testHSet),
cmocka_unit_test(testOverloadsBasic),
)

View File

@ -172,6 +172,43 @@ M_TEST_DEFINE(clearKeys) {
mScriptContextDeinit(&context);
}
M_TEST_DEFINE(numericKeys) {
SETUP_LUA;
TEST_PROGRAM("assert(not input:isKeyActive(C.KEY.F1))");
TEST_PROGRAM(
"activeKey = false\n"
"state = nil\n"
"function cb(ev)\n"
" assert(ev.type == C.EV_TYPE.KEY)\n"
" activeKey = ev.key\n"
" state = ev.state\n"
"end\n"
"id = callbacks:add('key', cb)\n"
"assert(id)\n"
"assert(not activeKey)\n"
);
struct mScriptKeyEvent keyEvent = {
.d = { .type = mSCRIPT_EV_TYPE_KEY },
.state = mSCRIPT_INPUT_STATE_DOWN,
.key = mSCRIPT_KEY_F1
};
mScriptContextFireEvent(&context, &keyEvent.d);
TEST_PROGRAM("assert(input:isKeyActive(C.KEY.F1))");
TEST_PROGRAM("assert(activeKey == C.KEY.F1)");
TEST_PROGRAM("assert(state == C.INPUT_STATE.DOWN)");
keyEvent.state = mSCRIPT_INPUT_STATE_UP;
mScriptContextFireEvent(&context, &keyEvent.d);
TEST_PROGRAM("assert(not input:isKeyActive(C.KEY.F1))");
TEST_PROGRAM("assert(state == C.INPUT_STATE.UP)");
mScriptContextDeinit(&context);
}
M_TEST_DEFINE(gamepadExport) {
SETUP_LUA;
@ -219,5 +256,6 @@ M_TEST_SUITE_DEFINE_SETUP_TEARDOWN(mScriptInput,
cmocka_unit_test(fireKey),
cmocka_unit_test(activeKeys),
cmocka_unit_test(clearKeys),
cmocka_unit_test(numericKeys),
cmocka_unit_test(gamepadExport),
)

View File

@ -372,25 +372,25 @@ M_TEST_DEFINE(wrongConst) {
mScriptFrameInit(&frame);
mSCRIPT_PUSH(&frame.arguments, S(Test), &a);
signature.entries[0] = mSCRIPT_TYPE_MS_S(Test);
assert_true(mScriptCoerceFrame(&signature, &frame.arguments));
assert_true(mScriptCoerceFrame(&signature, &frame.arguments, &frame.arguments));
mScriptFrameDeinit(&frame);
mScriptFrameInit(&frame);
mSCRIPT_PUSH(&frame.arguments, CS(Test), &a);
signature.entries[0] = mSCRIPT_TYPE_MS_CS(Test);
assert_true(mScriptCoerceFrame(&signature, &frame.arguments));
assert_true(mScriptCoerceFrame(&signature, &frame.arguments, &frame.arguments));
mScriptFrameDeinit(&frame);
mScriptFrameInit(&frame);
mSCRIPT_PUSH(&frame.arguments, S(Test), &a);
signature.entries[0] = mSCRIPT_TYPE_MS_CS(Test);
assert_true(mScriptCoerceFrame(&signature, &frame.arguments));
assert_true(mScriptCoerceFrame(&signature, &frame.arguments, &frame.arguments));
mScriptFrameDeinit(&frame);
mScriptFrameInit(&frame);
mSCRIPT_PUSH(&frame.arguments, CS(Test), &a);
signature.entries[0] = mSCRIPT_TYPE_MS_S(Test);
assert_false(mScriptCoerceFrame(&signature, &frame.arguments));
assert_false(mScriptCoerceFrame(&signature, &frame.arguments, &frame.arguments));
mScriptFrameDeinit(&frame);
mScriptFrameInit(&frame);
@ -402,7 +402,7 @@ M_TEST_DEFINE(wrongConst) {
mSCRIPT_PUSH(&frame.arguments, S(Test), &a);
assert_false(mScriptPopCSTest(&frame.arguments, &cb));
signature.entries[0] = mSCRIPT_TYPE_MS_CS(Test);
assert_true(mScriptCoerceFrame(&signature, &frame.arguments));
assert_true(mScriptCoerceFrame(&signature, &frame.arguments, &frame.arguments));
assert_true(mScriptPopCSTest(&frame.arguments, &cb));
mScriptFrameDeinit(&frame);
@ -410,7 +410,7 @@ M_TEST_DEFINE(wrongConst) {
mSCRIPT_PUSH(&frame.arguments, CS(Test), &a);
assert_false(mScriptPopSTest(&frame.arguments, &b));
signature.entries[0] = mSCRIPT_TYPE_MS_S(Test);
assert_false(mScriptCoerceFrame(&signature, &frame.arguments));
assert_false(mScriptCoerceFrame(&signature, &frame.arguments, &frame.arguments));
assert_false(mScriptPopSTest(&frame.arguments, &b));
mScriptFrameDeinit(&frame);

View File

@ -1238,6 +1238,9 @@ static void _mScriptClassInit(struct mScriptTypeClass* cls, const struct mScript
member->docstring = docstring;
docstring = NULL;
}
if (detail->info.member.type->base != mSCRIPT_TYPE_FUNCTION) {
abort();
}
if (detail->info.member.type->details.function.parameters.count != 3) {
abort();
}
@ -1773,21 +1776,24 @@ bool mScriptCast(const struct mScriptType* type, const struct mScriptValue* inpu
return false;
}
bool mScriptCoerceFrame(const struct mScriptTypeTuple* types, struct mScriptList* frame) {
if (types->count < mScriptListSize(frame) && !types->variable) {
bool mScriptCoerceFrame(const struct mScriptTypeTuple* types, const struct mScriptList* input, struct mScriptList* output) {
if (types->count < mScriptListSize(input) && !types->variable) {
return false;
}
if (types->count > mScriptListSize(frame) && !types->variable && !types->defaults) {
if (types->count > mScriptListSize(input) && !types->variable && !types->defaults) {
return false;
}
if (output) {
mScriptListResize(output, mScriptListSize(input) - mScriptListSize(output));
}
size_t i;
for (i = 0; i < mScriptListSize(frame) && i < types->count; ++i) {
if (types->entries[i] == mScriptListGetPointer(frame, i)->type) {
for (i = 0; i < mScriptListSize(input) && i < types->count; ++i) {
if (types->entries[i] == mScriptListGetConstPointer(input, i)->type) {
continue;
}
struct mScriptValue* unwrapped = NULL;
if (mScriptListGetPointer(frame, i)->type->base == mSCRIPT_TYPE_WRAPPER) {
unwrapped = mScriptValueUnwrap(mScriptListGetPointer(frame, i));
const struct mScriptValue* unwrapped = NULL;
if (mScriptListGetConstPointer(input, i)->type->base == mSCRIPT_TYPE_WRAPPER) {
unwrapped = mScriptValueUnwrapConst(mScriptListGetConstPointer(input, i));
if (types->entries[i]->base == mSCRIPT_TYPE_WRAPPER) {
if (types->entries[i]->details.type == unwrapped->type) {
continue;
@ -1796,7 +1802,12 @@ bool mScriptCoerceFrame(const struct mScriptTypeTuple* types, struct mScriptList
continue;
}
}
if (!mScriptCast(types->entries[i], mScriptListGetPointer(frame, i), mScriptListGetPointer(frame, i))) {
struct mScriptValue fakeVal;
struct mScriptValue* castTo = &fakeVal;
if (output) {
castTo = mScriptListGetPointer(output, i);
}
if (!mScriptCast(types->entries[i], mScriptListGetConstPointer(input, i), castTo)) {
return false;
}
}
@ -1808,11 +1819,26 @@ bool mScriptCoerceFrame(const struct mScriptTypeTuple* types, struct mScriptList
if (!types->defaults[i].type) {
return false;
}
memcpy(mScriptListAppend(frame), &types->defaults[i], sizeof(struct mScriptValue));
if (output) {
memcpy(mScriptListAppend(output), &types->defaults[i], sizeof(struct mScriptValue));
}
}
return true;
}
const struct mScriptFunctionOverload* mScriptFunctionFindOverload(const struct mScriptFunctionOverload* overloads, struct mScriptList* frame) {
size_t i;
for (i = 0; overloads[i].type; ++i) {
if (overloads[i].type->base != mSCRIPT_TYPE_FUNCTION) {
continue;
}
if (mScriptCoerceFrame(&overloads[i].type->details.function.parameters, frame, NULL)) {
return &overloads[i];
}
}
return NULL;
}
static void addTypesFromTuple(struct Table* types, const struct mScriptTypeTuple* tuple) {
size_t i;
for (i = 0; i < tuple->count; ++i) {

View File

@ -190,6 +190,14 @@ void explainClass(struct mScriptTypeClass* cls, int level) {
fprintf(out, "%s readonly: true\n", indent);
}
fprintf(out, "%s type: %s\n", indent, details->info.member.type->name);
if (details->info.member.overloads) {
fprintf(out, "%s overloads:\n", indent);
size_t i;
for (i = 0; details->info.member.overloads[i].type; ++i) {
mScriptTypeAdd(&types, details->info.member.overloads[i].type);
fprintf(out, "%s - %s\n", indent, details->info.member.overloads[i].type->name);
}
}
break;
case mSCRIPT_CLASS_INIT_END:
break;