#include #include #include #include #include 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 const char *function_get_name(const struct fx_function_p *func) { return func->func_name; } 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_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); if (nr_args == 1 && args[0] == FX_VALUE_TYPE_NONE) { nr_args = 0; } 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; } const char *fx_function_get_name(const fx_function *func) { FX_CLASS_DISPATCH_STATIC_0( FX_REFLECTION_TYPE_FUNCTION, function_get_name, 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)