Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
140 changes: 136 additions & 4 deletions distr/flecs.c
Original file line number Diff line number Diff line change
Expand Up @@ -51881,6 +51881,7 @@ typedef struct ecs_script_user_function_t {
ecs_script_t *script;
ecs_script_function_node_t *node;
ecs_vec_t refs;
ecs_vec_t using;
} ecs_script_user_function_t;

void flecs_script_user_function_callback(
Expand Down Expand Up @@ -68974,6 +68975,127 @@ ecs_entity_t ecs_method_init(
return 0;
}

static
int flecs_script_function_call(
ecs_world_t *world,
ecs_entity_t function,
const struct ecs_script_function_t *f,
const ecs_value_t *instance,
int32_t argc,
const ecs_value_t *argv,
ecs_value_t *result)
{
ecs_check(f != NULL, ECS_INVALID_PARAMETER,
"entity is not a script function or method");
ecs_check(f->callback != NULL, ECS_UNSUPPORTED,
"vector functions cannot be called directly");
ecs_check(argc >= 0, ECS_INVALID_PARAMETER, NULL);
ecs_check(argc == ecs_vec_count(&f->params), ECS_INVALID_PARAMETER,
"expected %d arguments, got %d", ecs_vec_count(&f->params), argc);
ecs_check(!argc || argv != NULL, ECS_INVALID_PARAMETER, NULL);
ecs_check(result != NULL, ECS_INVALID_PARAMETER, NULL);

const ecs_script_parameter_t *params = ecs_vec_first(&f->params);
(void)params;
int32_t i;
for (i = 0; i < argc; i ++) {
ecs_check(argv[i].type == params[i].type, ECS_INVALID_PARAMETER,
"type of argument %d does not match parameter type", i);
ecs_check(argv[i].ptr != NULL, ECS_INVALID_PARAMETER, NULL);
}

if (instance) {
ecs_check(instance->type == ecs_get_parent(world, function),
ECS_INVALID_PARAMETER,
"instance type does not match method type");
ecs_check(instance->ptr != NULL, ECS_INVALID_PARAMETER, NULL);
}

ecs_check(!result->type || result->type == f->return_type,
ECS_INVALID_PARAMETER, "result type does not match function return type");

bool result_allocated = false;
if (!result->ptr) {
*result = ecs_value_new(world, f->return_type);
ecs_check(result->ptr != NULL, ECS_INVALID_PARAMETER,
"function return type is not a valid value type");
result_allocated = true;
} else if (!result->type) {
result->type = f->return_type;
}

const ecs_value_t *call_argv = argv;
if (instance) {
ecs_value_t *method_argv = ecs_os_alloca_n(ecs_value_t, argc + 1);
method_argv[0] = *instance;
if (argc) {
ecs_os_memcpy_n(&method_argv[1], argv, ecs_value_t, argc);
}
call_argv = method_argv;
}

ecs_function_ctx_t ctx = {
.world = world,
.function = function,
.ctx = f->ctx
};

ecs_script_runtime_t *runtime = flecs_script_runtime_get(world);
runtime->error = false;
f->callback(&ctx, argc, call_argv, result);
if (runtime->error) {
runtime->error = false;
if (result_allocated) {
ecs_value_fini(world, result);
}
goto error;
}

return 0;
error:
return -1;
}

int ecs_function_call(
ecs_world_t *world,
ecs_entity_t function,
int32_t argc,
const ecs_value_t *argv,
ecs_value_t *result)
{
ecs_world_t *real_world = world;
flecs_stage_from_world(&real_world);
ecs_check(function != 0, ECS_INVALID_PARAMETER, NULL);

const EcsScriptFunction *f = ecs_get(
real_world, function, EcsScriptFunction);
return flecs_script_function_call(
world, function, f, NULL, argc, argv, result);
error:
return -1;
}

int ecs_method_call(
ecs_world_t *world,
ecs_entity_t method,
const ecs_value_t *instance,
int32_t argc,
const ecs_value_t *argv,
ecs_value_t *result)
{
ecs_world_t *real_world = world;
flecs_stage_from_world(&real_world);
ecs_check(method != 0, ECS_INVALID_PARAMETER, NULL);
ecs_check(instance != NULL, ECS_INVALID_PARAMETER, NULL);

const EcsScriptMethod *f = ecs_get(
real_world, method, EcsScriptMethod);
return flecs_script_function_call(
world, method, f, instance, argc, argv, result);
error:
return -1;
}

void flecs_function_import(
ecs_world_t *world)
{
Expand Down Expand Up @@ -76713,10 +76835,12 @@ void flecs_script_user_function_callback(
ecs_value_t *result)
{
ecs_world_t *world = ctx->world;
ecs_world_t *real_world = world;
flecs_stage_from_world(&real_world);
bool failed = false;

const EcsScriptFunction *fcomp = ecs_get(
world, ctx->function, EcsScriptFunction);
real_world, ctx->function, EcsScriptFunction);
if (!fcomp || !fcomp->binding_ctx) {
ecs_err("script function entity is missing binding context");
flecs_script_runtime_get(world)->error = true;
Expand All @@ -76732,25 +76856,31 @@ void flecs_script_user_function_callback(
flecs_script_eval_visit_init(impl, &v, &desc);

ecs_allocator_t *a = &v.r->allocator;
int32_t using_count = ecs_vec_count(&uf->using);
ecs_entity_t *using = ecs_vec_first(&uf->using);
for (int32_t u = 0; u < using_count; u ++) {
ecs_vec_append_t(a, &v.r->using, ecs_entity_t)[0] = using[u];
}

v.vars = flecs_script_vars_push(v.vars, &v.r->stack, a);

int32_t i, param_count = ecs_vec_count(&node->params);
ecs_script_fn_param_t *params = ecs_vec_first(&node->params);

for (i = 0; i < argc && i < param_count; i ++) {
const ecs_type_info_t *ti = ecs_get_type_info(world, argv[i].type);
const ecs_type_info_t *ti = ecs_get_type_info(
real_world, argv[i].type);
ecs_script_var_t *var = ecs_script_vars_declare(
v.vars, params[i].name);
var->value.type = argv[i].type;
var->type_info = ti;
var->is_const = true;

if (ti) {
var->value.ptr = flecs_stack_calloc(
&v.r->stack, ti->size, ti->alignment);
flecs_type_info_ctor(var->value.ptr, 1, ti);
ecs_ptr_copy_w_type_info(
world, ti, var->value.ptr, argv[i].ptr);
real_world, ti, var->value.ptr, argv[i].ptr);
} else {
var->value.ptr = argv[i].ptr;
}
Expand Down Expand Up @@ -76788,6 +76918,7 @@ void flecs_script_user_function_ctx_free(
ecs_script_free(uf->script);
}
ecs_vec_fini_t(NULL, &uf->refs, ecs_script_ref_t);
ecs_vec_fini_t(NULL, &uf->using, ecs_entity_t);
ecs_os_free(uf);
}

Expand Down Expand Up @@ -76999,6 +77130,7 @@ int flecs_script_eval_function(
v->base.script->refcount ++;
uf->node = node;
uf->refs = fn_refs;
uf->using = ecs_vec_copy_t(NULL, &v->r->using, ecs_entity_t);

EcsScriptFunction *fcomp = ecs_ensure(world, fn_entity, EcsScriptFunction);
if (fcomp->binding_ctx && fcomp->binding_ctx_free) {
Expand Down
17 changes: 17 additions & 0 deletions distr/flecs.h
Original file line number Diff line number Diff line change
Expand Up @@ -17549,6 +17549,14 @@ ecs_entity_t ecs_function_init(
#define ecs_function(world, ...)\
ecs_function_init(world, &(ecs_function_desc_t)__VA_ARGS__)

FLECS_API
int ecs_function_call(
ecs_world_t *world,
ecs_entity_t function,
int32_t argc,
const ecs_value_t *argv,
ecs_value_t *result);

/** Create new method.
* This operation creates a new method that can be called from a script. A
* method is like a function, except that it can be called on every instance of
Expand All @@ -17569,6 +17577,15 @@ ecs_entity_t ecs_method_init(
#define ecs_method(world, ...)\
ecs_method_init(world, &(ecs_function_desc_t)__VA_ARGS__)

FLECS_API
int ecs_method_call(
ecs_world_t *world,
ecs_entity_t method,
const ecs_value_t *instance,
int32_t argc,
const ecs_value_t *argv,
ecs_value_t *result);

/* Value serialization */

/** Serialize value into expression string.
Expand Down
17 changes: 17 additions & 0 deletions include/flecs/addons/script.h
Original file line number Diff line number Diff line change
Expand Up @@ -843,6 +843,14 @@ ecs_entity_t ecs_function_init(
#define ecs_function(world, ...)\
ecs_function_init(world, &(ecs_function_desc_t)__VA_ARGS__)

FLECS_API
int ecs_function_call(
ecs_world_t *world,
ecs_entity_t function,
int32_t argc,
const ecs_value_t *argv,
ecs_value_t *result);

/** Create new method.
* This operation creates a new method that can be called from a script. A
* method is like a function, except that it can be called on every instance of
Expand All @@ -863,6 +871,15 @@ ecs_entity_t ecs_method_init(
#define ecs_method(world, ...)\
ecs_method_init(world, &(ecs_function_desc_t)__VA_ARGS__)

FLECS_API
int ecs_method_call(
ecs_world_t *world,
ecs_entity_t method,
const ecs_value_t *instance,
int32_t argc,
const ecs_value_t *argv,
ecs_value_t *result);


/* Value serialization */

Expand Down
121 changes: 121 additions & 0 deletions src/addons/script/function.c
Original file line number Diff line number Diff line change
Expand Up @@ -375,6 +375,127 @@ ecs_entity_t ecs_method_init(
return 0;
}

static
int flecs_script_function_call(
ecs_world_t *world,
ecs_entity_t function,
const struct ecs_script_function_t *f,
const ecs_value_t *instance,
int32_t argc,
const ecs_value_t *argv,
ecs_value_t *result)
{
ecs_check(f != NULL, ECS_INVALID_PARAMETER,
"entity is not a script function or method");
ecs_check(f->callback != NULL, ECS_UNSUPPORTED,
"vector functions cannot be called directly");
ecs_check(argc >= 0, ECS_INVALID_PARAMETER, NULL);
ecs_check(argc == ecs_vec_count(&f->params), ECS_INVALID_PARAMETER,
"expected %d arguments, got %d", ecs_vec_count(&f->params), argc);
ecs_check(!argc || argv != NULL, ECS_INVALID_PARAMETER, NULL);
ecs_check(result != NULL, ECS_INVALID_PARAMETER, NULL);

const ecs_script_parameter_t *params = ecs_vec_first(&f->params);
(void)params;
int32_t i;
for (i = 0; i < argc; i ++) {
ecs_check(argv[i].type == params[i].type, ECS_INVALID_PARAMETER,
"type of argument %d does not match parameter type", i);
ecs_check(argv[i].ptr != NULL, ECS_INVALID_PARAMETER, NULL);
}

if (instance) {
ecs_check(instance->type == ecs_get_parent(world, function),
ECS_INVALID_PARAMETER,
"instance type does not match method type");
ecs_check(instance->ptr != NULL, ECS_INVALID_PARAMETER, NULL);
}

ecs_check(!result->type || result->type == f->return_type,
ECS_INVALID_PARAMETER, "result type does not match function return type");

bool result_allocated = false;
if (!result->ptr) {
*result = ecs_value_new(world, f->return_type);
ecs_check(result->ptr != NULL, ECS_INVALID_PARAMETER,
"function return type is not a valid value type");
result_allocated = true;
} else if (!result->type) {
result->type = f->return_type;
}

const ecs_value_t *call_argv = argv;
if (instance) {
ecs_value_t *method_argv = ecs_os_alloca_n(ecs_value_t, argc + 1);
method_argv[0] = *instance;
if (argc) {
ecs_os_memcpy_n(&method_argv[1], argv, ecs_value_t, argc);
}
call_argv = method_argv;
}

ecs_function_ctx_t ctx = {
.world = world,
.function = function,
.ctx = f->ctx
};

ecs_script_runtime_t *runtime = flecs_script_runtime_get(world);
runtime->error = false;
f->callback(&ctx, argc, call_argv, result);
if (runtime->error) {
runtime->error = false;
if (result_allocated) {
ecs_value_fini(world, result);
}
goto error;
}

return 0;
error:
return -1;
}

int ecs_function_call(
ecs_world_t *world,
ecs_entity_t function,
int32_t argc,
const ecs_value_t *argv,
ecs_value_t *result)
{
ecs_world_t *real_world = world;
flecs_stage_from_world(&real_world);
ecs_check(function != 0, ECS_INVALID_PARAMETER, NULL);

const EcsScriptFunction *f = ecs_get(
real_world, function, EcsScriptFunction);
return flecs_script_function_call(
world, function, f, NULL, argc, argv, result);
error:
return -1;
}

int ecs_method_call(
ecs_world_t *world,
ecs_entity_t method,
const ecs_value_t *instance,
int32_t argc,
const ecs_value_t *argv,
ecs_value_t *result)
{
ecs_world_t *real_world = world;
flecs_stage_from_world(&real_world);
ecs_check(method != 0, ECS_INVALID_PARAMETER, NULL);
ecs_check(instance != NULL, ECS_INVALID_PARAMETER, NULL);

const EcsScriptMethod *f = ecs_get(
real_world, method, EcsScriptMethod);
return flecs_script_function_call(
world, method, f, instance, argc, argv, result);
error:
return -1;
}

void flecs_function_import(
ecs_world_t *world)
{
Expand Down
1 change: 1 addition & 0 deletions src/addons/script/script.h
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ typedef struct ecs_script_user_function_t {
ecs_script_t *script;
ecs_script_function_node_t *node;
ecs_vec_t refs;
ecs_vec_t using;
} ecs_script_user_function_t;

void flecs_script_user_function_callback(
Expand Down
Loading
Loading