195 lines
4.4 KiB
C
195 lines
4.4 KiB
C
#include <fx/macros.h>
|
|
#include <fx/reflection/function.h>
|
|
#include <fx/string.h>
|
|
#include <fx/value.h>
|
|
#include <platform/callvm.h>
|
|
|
|
struct fx_function_p {
|
|
char *func_name;
|
|
fx_function_flags func_flags;
|
|
fx_function_impl func_impl;
|
|
fx_value_type func_return_type;
|
|
fx_value_type *func_arg_types;
|
|
/* number of explicit arguments that the function takes.
|
|
* if the FX_FUNCTION_F_VARARG flag is set, the function supports a
|
|
* variable number of arguments, which may be handled differently by the
|
|
* ABI */
|
|
size_t func_nr_args;
|
|
|
|
fx_value *func_bound_args;
|
|
size_t func_nr_bound_args, func_max_bound_args;
|
|
};
|
|
|
|
/*** PRIVATE FUNCTIONS ********************************************************/
|
|
|
|
static fx_status function_bind(
|
|
struct fx_function_p *func,
|
|
fx_value *args,
|
|
size_t nr_args)
|
|
{
|
|
if (func->func_nr_bound_args) {
|
|
fx_value_unset_array(
|
|
func->func_bound_args,
|
|
func->func_nr_bound_args);
|
|
}
|
|
|
|
if (!args || !nr_args) {
|
|
func->func_nr_bound_args = 0;
|
|
return FX_SUCCESS;
|
|
}
|
|
|
|
if (nr_args > func->func_max_bound_args) {
|
|
fx_value *buf = realloc(
|
|
func->func_bound_args,
|
|
nr_args * sizeof *buf);
|
|
if (!buf) {
|
|
return FX_ERR_NO_MEMORY;
|
|
}
|
|
|
|
func->func_bound_args = buf;
|
|
func->func_max_bound_args = nr_args;
|
|
}
|
|
|
|
fx_value_copy_array(func->func_bound_args, args, nr_args);
|
|
func->func_nr_bound_args = nr_args;
|
|
|
|
return FX_SUCCESS;
|
|
}
|
|
|
|
static fx_status function_invoke(
|
|
const struct fx_function_p *func,
|
|
const fx_value *args,
|
|
size_t nr_args,
|
|
fx_value *return_value)
|
|
{
|
|
size_t total_args = nr_args + func->func_nr_bound_args;
|
|
|
|
if (total_args < func->func_nr_args) {
|
|
return FX_ERR_INVALID_ARGUMENT;
|
|
}
|
|
|
|
if (total_args > func->func_nr_args
|
|
&& !(func->func_flags & FX_FUNCTION_F_VARARG)) {
|
|
return FX_ERR_INVALID_ARGUMENT;
|
|
}
|
|
|
|
size_t nr_fixed_args = func->func_nr_args;
|
|
size_t nr_var_args = total_args - nr_fixed_args;
|
|
|
|
struct callvm vm = {0};
|
|
callvm_reset(&vm, nr_fixed_args);
|
|
|
|
for (size_t i = 0; i < func->func_nr_bound_args; i++) {
|
|
const fx_value *arg = &func->func_bound_args[i];
|
|
callvm_push(&vm, arg);
|
|
}
|
|
|
|
for (size_t i = 0; i < nr_args; i++) {
|
|
const fx_value *arg = &args[i];
|
|
callvm_push(&vm, arg);
|
|
}
|
|
|
|
*return_value = callvm_invoke(
|
|
&vm,
|
|
func->func_impl,
|
|
func->func_return_type);
|
|
|
|
callvm_reset(&vm, 0);
|
|
return FX_SUCCESS;
|
|
}
|
|
|
|
/*** PUBLIC FUNCTIONS
|
|
* *********************************************************/
|
|
|
|
FX_API fx_function *fx_function_create(
|
|
const char *name,
|
|
fx_function_flags flags,
|
|
fx_function_impl impl,
|
|
const fx_value_type *args,
|
|
size_t nr_args,
|
|
fx_value_type return_type)
|
|
{
|
|
fx_function *func = fx_object_create(FX_REFLECTION_TYPE_FUNCTION);
|
|
if (!func) {
|
|
return NULL;
|
|
}
|
|
|
|
struct fx_function_p *p = fx_object_get_private(
|
|
func,
|
|
FX_REFLECTION_TYPE_FUNCTION);
|
|
|
|
p->func_name = fx_strdup(name);
|
|
p->func_flags = flags;
|
|
p->func_impl = impl;
|
|
p->func_nr_args = nr_args;
|
|
p->func_return_type = return_type;
|
|
p->func_arg_types = calloc(nr_args, sizeof *args);
|
|
for (size_t i = 0; i < nr_args; i++) {
|
|
p->func_arg_types[i] = args[i];
|
|
}
|
|
|
|
return func;
|
|
}
|
|
|
|
fx_status fx_function_bind(fx_function *func, fx_value *args, size_t nr_args)
|
|
{
|
|
FX_CLASS_DISPATCH_STATIC(
|
|
FX_REFLECTION_TYPE_FUNCTION,
|
|
function_bind,
|
|
func,
|
|
args,
|
|
nr_args);
|
|
}
|
|
|
|
fx_status fx_function_invoke(
|
|
const fx_function *func,
|
|
const fx_value *args,
|
|
size_t nr_args,
|
|
fx_value *return_value)
|
|
{
|
|
FX_CLASS_DISPATCH_STATIC(
|
|
FX_REFLECTION_TYPE_FUNCTION,
|
|
function_invoke,
|
|
func,
|
|
args,
|
|
nr_args,
|
|
return_value);
|
|
}
|
|
|
|
/*** VIRTUAL FUNCTIONS
|
|
* ********************************************************/
|
|
|
|
static void function_init(fx_object *obj, void *priv)
|
|
{
|
|
}
|
|
|
|
static void function_fini(fx_object *obj, void *priv)
|
|
{
|
|
struct fx_function_p *p = priv;
|
|
if (p->func_name) {
|
|
free(p->func_name);
|
|
}
|
|
|
|
if (p->func_arg_types) {
|
|
free(p->func_arg_types);
|
|
}
|
|
}
|
|
|
|
/*** CLASS DEFINITION
|
|
* *********************************************************/
|
|
|
|
FX_TYPE_CLASS_BEGIN(fx_function)
|
|
FX_TYPE_VTABLE_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
|
|
FX_INTERFACE_ENTRY(to_string) = NULL;
|
|
FX_TYPE_VTABLE_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
|
|
FX_TYPE_CLASS_END(fx_function)
|
|
|
|
FX_TYPE_DEFINITION_BEGIN(fx_function)
|
|
FX_TYPE_ID(0x09e40174, 0x7443, 0x486e, 0xad21, 0xcc9374762e7e);
|
|
FX_TYPE_NAME("fx.reflection.function");
|
|
FX_TYPE_CLASS(fx_function_class);
|
|
FX_TYPE_INSTANCE_PRIVATE(struct fx_function_p);
|
|
FX_TYPE_INSTANCE_INIT(function_init);
|
|
FX_TYPE_INSTANCE_FINI(function_fini);
|
|
FX_TYPE_DEFINITION_END(fx_function)
|