mirror of https://github.com/mgba-emu/mgba.git
Scripting: Rework functions; add wrapper type for stack references
This commit is contained in:
parent
c507157ab8
commit
512572769e
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue