diff --git a/include/mgba/script/context.h b/include/mgba/script/context.h index 9c2310a41..0b83a02fe 100644 --- a/include/mgba/script/context.h +++ b/include/mgba/script/context.h @@ -51,6 +51,6 @@ void mScriptContextRegisterEngine(struct mScriptContext*, struct mScriptEngine2* void mScriptContextAddGlobal(struct mScriptContext*, const char* key, struct mScriptValue* value); void mScriptContextRemoveGlobal(struct mScriptContext*, const char* key); -bool mScriptInvoke(const struct mScriptFunction* fn, struct mScriptFrame* frame); +bool mScriptInvoke(const struct mScriptValue* fn, struct mScriptFrame* frame); #endif diff --git a/include/mgba/script/types.h b/include/mgba/script/types.h index 0af2c11db..b5f52d2dd 100644 --- a/include/mgba/script/types.h +++ b/include/mgba/script/types.h @@ -27,6 +27,7 @@ CXX_GUARD_START #define mSCRIPT_TYPE_C_CHARP const char* #define mSCRIPT_TYPE_C_PTR void* #define mSCRIPT_TYPE_C_TABLE Table* +#define mSCRIPT_TYPE_C_WRAPPER mScriptValue* #define mSCRIPT_TYPE_C_S(STRUCT) struct STRUCT* #define mSCRIPT_TYPE_FIELD_S32 s32 @@ -39,6 +40,7 @@ CXX_GUARD_START #define mSCRIPT_TYPE_FIELD_CHARP opaque #define mSCRIPT_TYPE_FIELD_PTR opaque #define mSCRIPT_TYPE_FIELD_TABLE opaque +#define mSCRIPT_TYPE_FIELD_WRAPPER opaque #define mSCRIPT_TYPE_FIELD_S(STRUCT) opaque #define mSCRIPT_TYPE_MS_S32 (&mSTSInt32) @@ -50,6 +52,7 @@ CXX_GUARD_START #define mSCRIPT_TYPE_MS_STR (&mSTString) #define mSCRIPT_TYPE_MS_CHARP (&mSTCharPtr) #define mSCRIPT_TYPE_MS_TABLE (&mSTTable) +#define mSCRIPT_TYPE_MS_WRAPPER (&mSTWrapper) #define mSCRIPT_TYPE_MS_S(STRUCT) (&mSTStruct_ ## STRUCT) #define _mSCRIPT_FIELD_NAME(V) (V)->name @@ -72,9 +75,17 @@ CXX_GUARD_START do { \ struct mScriptValue* _val = mScriptListGetPointer(STACK, mScriptListSize(STACK) - 1); \ if (!(mSCRIPT_TYPE_CMP(TYPE, _val->type))) { \ - return false; \ + if (_val->type == mSCRIPT_TYPE_MS_WRAPPER) { \ + _val = mScriptValueUnwrap(_val); \ + if (!(mSCRIPT_TYPE_CMP(TYPE, _val->type))) { \ + return false; \ + } \ + } else { \ + return false; \ + } \ } \ NAME = _val->value. _mAPPLY(mSCRIPT_TYPE_FIELD_ ## TYPE); \ + mScriptValueDeref(_val); \ mScriptListResize(STACK, -1); \ } while (0) @@ -140,18 +151,30 @@ CXX_GUARD_START _mSCRIPT_CALL(RETURN, FUNCTION, NPARAMS); \ return true; \ } \ - const struct mScriptFunction NAME = { \ - .signature = { \ - .parameters = { \ - .count = NPARAMS, \ - .entries = { _mAPPLY(mSCRIPT_PREFIX_ ## NPARAMS(mSCRIPT_TYPE_MS_, __VA_ARGS__)) } \ + static const struct mScriptType _type_ ## NAME = { \ + .base = mSCRIPT_TYPE_FUNCTION, \ + .details = { \ + .function = { \ + .parameters = { \ + .count = NPARAMS, \ + .entries = { _mAPPLY(mSCRIPT_PREFIX_ ## NPARAMS(mSCRIPT_TYPE_MS_, __VA_ARGS__)) } \ + }, \ + .returnType = { \ + .count = 1, \ + .entries = { mSCRIPT_TYPE_MS_ ## RETURN } \ + }, \ }, \ - .returnType = { \ - .count = 1, \ - .entries = { mSCRIPT_TYPE_MS_ ## RETURN } \ - }, \ - }, \ + } \ + }; \ + static struct mScriptFunction _function_ ## NAME = { \ .call = _binding_ ## NAME \ + }; \ + const struct mScriptValue NAME = { \ + .type = &_type_ ## NAME, \ + .refs = mSCRIPT_VALUE_UNREF, \ + .value = { \ + .opaque = &_function_ ## NAME \ + } \ }; #define mSCRIPT_BIND_VOID_FUNCTION(NAME, FUNCTION, NPARAMS, ...) \ @@ -164,17 +187,29 @@ CXX_GUARD_START _mSCRIPT_CALL_VOID(FUNCTION, NPARAMS); \ return true; \ } \ - const struct mScriptFunction NAME = { \ - .signature = { \ - .parameters = { \ - .count = NPARAMS, \ - .entries = { _mAPPLY(mSCRIPT_PREFIX_ ## NPARAMS(mSCRIPT_TYPE_MS_, __VA_ARGS__)) } \ + static const struct mScriptType _type_ ## NAME = { \ + .base = mSCRIPT_TYPE_FUNCTION, \ + .details = { \ + .function = { \ + .parameters = { \ + .count = NPARAMS, \ + .entries = { _mAPPLY(mSCRIPT_PREFIX_ ## NPARAMS(mSCRIPT_TYPE_MS_, __VA_ARGS__)) } \ + }, \ + .returnType = { \ + .count = 0, \ + }, \ }, \ - .returnType = { \ - .count = 0, \ - }, \ - }, \ + } \ + }; \ + static struct mScriptFunction _function_ ## NAME = { \ .call = _binding_ ## NAME \ + }; \ + const struct mScriptValue NAME = { \ + .type = &_type_ ## NAME, \ + .refs = mSCRIPT_VALUE_UNREF, \ + .value = { \ + .opaque = &_function_ ## NAME \ + } \ }; #define mSCRIPT_MAKE(TYPE, FIELD, VALUE) (struct mScriptValue) { \ @@ -205,6 +240,7 @@ enum { mSCRIPT_TYPE_TUPLE, mSCRIPT_TYPE_LIST, mSCRIPT_TYPE_TABLE, + mSCRIPT_TYPE_WRAPPER }; struct Table; @@ -219,16 +255,18 @@ extern const struct mScriptType mSTFloat64; extern const struct mScriptType mSTString; extern const struct mScriptType mSTCharPtr; extern const struct mScriptType mSTTable; +extern const struct mScriptType mSTWrapper; struct mScriptTypeTuple { size_t count; const struct mScriptType* entries[mSCRIPT_PARAMS_MAX]; + bool variable; }; struct mScriptTypeFunction { struct mScriptTypeTuple parameters; struct mScriptTypeTuple returnType; - // TODO: varargs, kwargs, defaults + // TODO: kwargs, defaults }; struct mScriptValue; @@ -277,7 +315,6 @@ struct mScriptFrame { }; struct mScriptFunction { - struct mScriptTypeFunction signature; bool (*call)(struct mScriptFrame*, void* context); void* context; }; @@ -286,6 +323,9 @@ struct mScriptValue* mScriptValueAlloc(const struct mScriptType* type); void mScriptValueRef(struct mScriptValue* val); void mScriptValueDeref(struct mScriptValue* val); +void mScriptValueWrap(struct mScriptValue* val, struct mScriptValue* out); +struct mScriptValue* mScriptValueUnwrap(struct mScriptValue* val); + struct mScriptValue* mScriptStringCreateFromUTF8(const char* string); bool mScriptTableInsert(struct mScriptValue* table, struct mScriptValue* key, struct mScriptValue* value); diff --git a/src/script/context.c b/src/script/context.c index f8ae22e19..321d2f222 100644 --- a/src/script/context.c +++ b/src/script/context.c @@ -14,9 +14,14 @@ void mScriptContextDeinit(struct mScriptContext* context) { HashTableDeinit(&context->engines); } -bool mScriptInvoke(const struct mScriptFunction* fn, struct mScriptFrame* frame) { - if (!mScriptCoerceFrame(&fn->signature.parameters, &frame->arguments)) { +bool mScriptInvoke(const struct mScriptValue* val, struct mScriptFrame* frame) { + if (val->type->base != mSCRIPT_TYPE_FUNCTION) { return false; } + const struct mScriptTypeFunction* signature = &val->type->details.function; + if (!mScriptCoerceFrame(&signature->parameters, &frame->arguments)) { + return false; + } + const struct mScriptFunction* fn = val->value.opaque; return fn->call(frame, fn->context); } diff --git a/src/script/types.c b/src/script/types.c index ff7cc1e24..e8f1a73a2 100644 --- a/src/script/types.c +++ b/src/script/types.c @@ -140,6 +140,15 @@ const struct mScriptType mSTTable = { .hash = NULL, }; +const struct mScriptType mSTWrapper = { + .base = mSCRIPT_TYPE_WRAPPER, + .size = sizeof(struct mScriptValue), + .name = "wrapper", + .alloc = NULL, + .free = NULL, + .hash = NULL, +}; + DEFINE_VECTOR(mScriptList, struct mScriptValue) void _allocTable(struct mScriptValue* val) { @@ -602,6 +611,36 @@ void mScriptValueDeref(struct mScriptValue* val) { free(val); } +void mScriptValueWrap(struct mScriptValue* value, struct mScriptValue* out) { + if (value->refs == mSCRIPT_VALUE_UNREF) { + memcpy(out, value, sizeof(*out)); + return; + } + out->refs = mSCRIPT_VALUE_UNREF; + switch (value->type->base) { + case mSCRIPT_TYPE_SINT: + case mSCRIPT_TYPE_UINT: + case mSCRIPT_TYPE_FLOAT: + case mSCRIPT_TYPE_WRAPPER: + out->type = value->type; + memcpy(&out->value, &value->value, sizeof(out->value)); + return; + default: + break; + } + + out->type = mSCRIPT_TYPE_MS_WRAPPER; + out->value.opaque = value; + mScriptValueRef(value); +} + +struct mScriptValue* mScriptValueUnwrap(struct mScriptValue* value) { + if (value->type == mSCRIPT_TYPE_MS_WRAPPER) { + return value->value.opaque; + } + return NULL; +} + struct mScriptValue* mScriptStringCreateFromUTF8(const char* string) { struct mScriptValue* val = mScriptValueAlloc(mSCRIPT_TYPE_MS_STR); struct mScriptString* internal = val->value.opaque; @@ -709,7 +748,7 @@ bool mScriptCast(const struct mScriptType* type, const struct mScriptValue* inpu } bool mScriptCoerceFrame(const struct mScriptTypeTuple* types, struct mScriptList* frame) { - if (types->count != mScriptListSize(frame)) { + if (types->count != mScriptListSize(frame) && (!types->variable || mScriptListSize(frame) < types->count)) { return false; } size_t i;