Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Flecs script expression refactor #1461

Merged
merged 83 commits into from
Dec 15, 2024
Merged
Changes from 1 commit
Commits
Show all changes
83 commits
Select commit Hold shift + click to select a range
5126d70
Initial commit for new expression parser
SanderMertens Nov 19, 2024
0ea2081
Implement type visitor for binary expressions
SanderMertens Nov 21, 2024
2b256c7
Implement type visitor for remaining nodes
SanderMertens Nov 22, 2024
8e5c023
Add unary expression
SanderMertens Nov 22, 2024
ec80c7e
Implement folding for unary and binary expressions
SanderMertens Nov 22, 2024
9955a1c
Implement cast expressions
SanderMertens Nov 22, 2024
ba89187
Move expression implementation to its own folder
SanderMertens Nov 22, 2024
d09a176
Fix folding issues
SanderMertens Nov 25, 2024
eb88440
Fix issues with operator precedence
SanderMertens Nov 26, 2024
98452a5
Implement initializer expressions
SanderMertens Nov 26, 2024
ba96e9b
Add multiline string support
SanderMertens Nov 27, 2024
fe06af4
Don't use static offsets for opaque types
SanderMertens Nov 27, 2024
7e24df7
Implement basic expression eval runtime
SanderMertens Nov 27, 2024
57a55c6
Remove legacy expr implementation
SanderMertens Nov 27, 2024
fc5eacb
Implement unary expression support for runtime
SanderMertens Nov 27, 2024
cf06dcd
Implement initializer expression support for runtime
SanderMertens Nov 27, 2024
20f61fd
Implement element expression support for runtime
SanderMertens Nov 28, 2024
69c3c32
Implement accessing elements of inline array
SanderMertens Nov 28, 2024
316274f
Implement component expressions for runtime
SanderMertens Nov 29, 2024
4a2d67e
Implement basic function support for scripts
SanderMertens Nov 30, 2024
5593603
Implement expression AST cleanup
SanderMertens Dec 2, 2024
2d8ae6c
Implement support for dynamic initializers
SanderMertens Dec 3, 2024
b1a7622
Improve management of non-trivial temporary values
SanderMertens Dec 3, 2024
84f8953
Implement deducing variable name from initializer member
SanderMertens Dec 3, 2024
054c16e
Fix issue with array initializers
SanderMertens Dec 3, 2024
f79b635
Implement separate public functions for parsing/evaluating expressions
SanderMertens Dec 3, 2024
d77ab97
Add tests that ensure expr parser stops at right location
SanderMertens Dec 4, 2024
5e71055
Integrate script and expression parsers
SanderMertens Dec 4, 2024
964e9f1
Fix warnings
SanderMertens Dec 4, 2024
739d17d
Implement expression stack for runtime
SanderMertens Dec 5, 2024
9855d8e
Implement reusable script runtime object
SanderMertens Dec 5, 2024
30b077e
Fix more warnings
SanderMertens Dec 5, 2024
b39b108
Make expression folding optional
SanderMertens Dec 5, 2024
503acf3
Fix query parser regression
SanderMertens Dec 5, 2024
5a0b04d
Fix more warnings
SanderMertens Dec 5, 2024
b40290c
Fix script memory mgmt issues, extend allocator with more debug info
SanderMertens Dec 6, 2024
b3de49c
Unquarantine expression error checking tests
SanderMertens Dec 6, 2024
97eb5f1
Implement support for function arguments
SanderMertens Dec 6, 2024
47488bb
Implement flecs script math functions
SanderMertens Dec 7, 2024
b4e6acc
Add section on expressions to Flecs Script manual
SanderMertens Dec 7, 2024
d942964
Add flecs script examples
SanderMertens Dec 8, 2024
9917e11
Implement ability to specify variables and runtime to ecs_script_eval
SanderMertens Dec 8, 2024
d32da97
Improve naming of script API
SanderMertens Dec 8, 2024
6979e39
Add more script examples
SanderMertens Dec 8, 2024
7540b5c
Fix template instantiation issue while world is deferred
SanderMertens Dec 8, 2024
ffe3e6d
Allow for infinitely nested observer events
SanderMertens Dec 9, 2024
a541def
Fix issues with parsing initializers
SanderMertens Dec 9, 2024
12860bf
Fix issue where value of component defined in script was freed after …
SanderMertens Dec 9, 2024
bf5183d
Fix issue where suspending/resuming readonly mode could corrupt stack…
SanderMertens Dec 9, 2024
cdf08df
Allow for trailing commas in collection initializers
SanderMertens Dec 9, 2024
b4bcd63
Fix issues with template variable hosting
SanderMertens Dec 9, 2024
bd75cf6
Implement detection of invalid components in with scope, allow for N …
SanderMertens Dec 10, 2024
8104954
Fix operator precedence issue, ensure Template pair is always a tag
SanderMertens Dec 10, 2024
b57c2af
Fix issue with using ecs_entity_desc_t::set while deferring is suspended
SanderMertens Dec 10, 2024
c3a2450
Implement folding of const variables
SanderMertens Dec 10, 2024
74625ff
Improve type inferencing in boolean expressions
SanderMertens Dec 11, 2024
be4e736
Fix illegal memory access in ecs_add_path_w_sep
SanderMertens Dec 11, 2024
0bddcc6
Remove unused ecs_stage_t::parser_tokens member
SanderMertens Dec 11, 2024
99bc073
Add reusable script runtime to stage, reduce allocations during templ…
SanderMertens Dec 11, 2024
f86e608
Fix memory leaks from casting non-trivial values
SanderMertens Dec 11, 2024
3f9c4bf
Fix leaks when using FLECS_USE_OS_ALLOC
SanderMertens Dec 11, 2024
61c5088
Fix issue where code was accessing world->flags on stage object
SanderMertens Dec 11, 2024
ad1d496
Implement ability to define global script variables
SanderMertens Dec 12, 2024
4388be9
Reimplement string interpolation for expression parser
SanderMertens Dec 13, 2024
bb99459
Implement support for entity name expressions
SanderMertens Dec 13, 2024
8b7c330
Implement support for for range loops
SanderMertens Dec 13, 2024
c439fe2
Add flecs.script.math.abs
SanderMertens Dec 13, 2024
9e10fc5
Fix issue with mod operator, check for division by zero
SanderMertens Dec 14, 2024
976ae68
Fix issue with reporting errors that contain format characters
SanderMertens Dec 14, 2024
0e1757f
Implement divide by zero detection in fold visitor
SanderMertens Dec 14, 2024
4f91998
Implement improved error checking for templates
SanderMertens Dec 14, 2024
c632d56
Improve type conversion error messages
SanderMertens Dec 14, 2024
0d1dc4f
Fix issue with templates that contain expressions with self references
SanderMertens Dec 14, 2024
5b5c27d
Fix issue where global with was applied to template code
SanderMertens Dec 14, 2024
75efeaf
Fix issue with for loops in templates
SanderMertens Dec 14, 2024
5deb1cb
Fix issues with parsing binary expressions without spaces
SanderMertens Dec 14, 2024
5d6b849
Fix memory leaks
SanderMertens Dec 14, 2024
8dad0d8
Fix fuzzing errors
SanderMertens Dec 14, 2024
b9f0d4b
Fix memory leaks in meta cursor string conversions
SanderMertens Dec 14, 2024
a65b71c
Fix warnings, add typos exception for Fuzzing.c
SanderMertens Dec 15, 2024
a977d43
Fix access to uninitialized ecs_cmd_t::id field
SanderMertens Dec 15, 2024
308a728
Add more sections to script manual
SanderMertens Dec 15, 2024
0051026
Add more builtin script functions, add documentation on builtin funct…
SanderMertens Dec 15, 2024
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
Prev Previous commit
Next Next commit
Implement support for entity name expressions
SanderMertens committed Dec 13, 2024

Verified

This commit was signed with the committer’s verified signature.
SanderMertens Sander Mertens
commit bb99459e685f8f9a84929019e4bfb3c568861f67
111 changes: 99 additions & 12 deletions distr/flecs.c
Original file line number Diff line number Diff line change
@@ -4729,6 +4729,7 @@ struct ecs_script_entity_t {
bool name_is_var;
bool kind_w_expr;
ecs_script_scope_t *scope;
ecs_expr_node_t *name_expr;

// Populated during eval
ecs_script_entity_t *parent;
@@ -4800,7 +4801,8 @@ ecs_script_scope_t* flecs_script_insert_scope(

ecs_script_entity_t* flecs_script_insert_entity(
ecs_script_parser_t *parser,
const char *name);
const char *name,
bool name_is_expr);

ecs_script_pair_scope_t* flecs_script_insert_pair_scope(
ecs_script_parser_t *parser,
@@ -54953,7 +54955,8 @@ ecs_script_scope_t* flecs_script_insert_scope(

ecs_script_entity_t* flecs_script_insert_entity(
ecs_script_parser_t *parser,
const char *name)
const char *name,
bool name_is_expr)
{
ecs_script_scope_t *scope = parser->scope;
ecs_assert(scope != NULL, ECS_INTERNAL_ERROR, NULL);
@@ -54967,12 +54970,24 @@ ecs_script_entity_t* flecs_script_insert_entity(

result->name = name;

if (name_is_expr) {
parser->significant_newline = false;
result->name_expr = (ecs_expr_node_t*)
flecs_expr_interpolated_string(parser, name);
if (!result->name_expr) {
goto error;
}
parser->significant_newline = true;
}

ecs_script_scope_t *entity_scope = flecs_script_scope_new(parser);
ecs_assert(entity_scope != NULL, ECS_INTERNAL_ERROR, NULL);
result->scope = entity_scope;

flecs_ast_append(parser, scope->stmts, ecs_script_entity_t, result);
return result;
error:
return NULL;
}

static
@@ -56098,7 +56113,7 @@ const char* flecs_script_comma_expr(
if (is_base_list) {
flecs_script_insert_pair_tag(parser, "IsA", Token(0));
} else {
flecs_script_insert_entity(parser, Token(0));
flecs_script_insert_entity(parser, Token(0), false);
}

LookAhead_1(',',
@@ -56256,8 +56271,12 @@ const char* flecs_script_stmt(
{
ParserBegin;

bool name_is_expr_0 = false;
bool name_is_expr_1 = false;

Parse(
case EcsTokIdentifier: goto identifier;
case EcsTokString: goto string_name;
case '{': return flecs_script_scope(parser,
flecs_script_insert_scope(parser), pos);
case '(': goto paren;
@@ -56272,6 +56291,15 @@ const char* flecs_script_stmt(
EcsTokEndOfStatement: EndOfRule;
);

string_name:
/* If this is an interpolated string, we need to evaluate it as expression
* at evaluation time. Otherwise we can just use the string as name. The
* latter is useful if an entity name contains special characters that are
* not allowed in identifier tokens. */
if (flecs_string_is_interpolated(Token(0))) {
name_is_expr_0 = true;
}

identifier: {
// enterprise } (end of scope)
LookAhead_1('}',
@@ -56283,12 +56311,16 @@ identifier: {
case '{': {
return flecs_script_scope(parser,
flecs_script_insert_entity(
parser, Token(0))->scope, pos);
parser, Token(0), name_is_expr_0)->scope, pos);
}

// Red,
case ',': {
flecs_script_insert_entity(parser, Token(0));
if (name_is_expr_0) {
Error("expression not allowed as entity name here");
}

flecs_script_insert_entity(parser, Token(0), false);
pos = flecs_script_comma_expr(parser, pos, false);
EndOfRule;
}
@@ -56300,7 +56332,7 @@ identifier: {
pos = lookahead;
return flecs_script_scope(parser,
flecs_script_insert_entity(
parser, Token(0))->scope, pos);
parser, Token(0), name_is_expr_0)->scope, pos);
)

goto insert_tag;
@@ -56330,6 +56362,11 @@ identifier: {
case EcsTokIdentifier: {
goto identifier_identifier;
}

// Spaceship "enterprise"
case EcsTokString: {
goto identifier_string;
}
)
}

@@ -56647,7 +56684,7 @@ identifier_colon: {
// enterprise : SpaceShip
Parse_1(EcsTokIdentifier, {
ecs_script_entity_t *entity = flecs_script_insert_entity(
parser, Token(0));
parser, Token(0), name_is_expr_0);

Scope(entity->scope,
flecs_script_insert_pair_tag(parser, "IsA", Token(2));
@@ -56673,7 +56710,7 @@ identifier_colon: {
// x =
identifier_assign: {
ecs_script_entity_t *entity = flecs_script_insert_entity(
parser, Token(0));
parser, Token(0), name_is_expr_0);

// x = Position:
LookAhead_2(EcsTokIdentifier, ':',
@@ -56711,9 +56748,15 @@ identifier_assign: {
}

// Spaceship enterprise
identifier_string: {
if (flecs_string_is_interpolated(Token(1))) {
name_is_expr_1 = true;
}
}

identifier_identifier: {
ecs_script_entity_t *entity = flecs_script_insert_entity(
parser, Token(1));
parser, Token(1), name_is_expr_1);
entity->kind = Token(0);

// Spaceship enterprise :
@@ -56761,7 +56804,7 @@ identifier_paren: {
// SpaceShip(expr)\n
EcsTokEndOfStatement: {
ecs_script_entity_t *entity = flecs_script_insert_entity(
parser, NULL);
parser, NULL, false);

Scope(entity->scope,
ecs_script_component_t *comp =
@@ -56775,7 +56818,7 @@ identifier_paren: {
// SpaceShip(expr) {
case '{': {
ecs_script_entity_t *entity = flecs_script_insert_entity(
parser, NULL);
parser, NULL, false);

Scope(entity->scope,
ecs_script_component_t *comp =
@@ -60554,7 +60597,48 @@ int flecs_script_eval_entity(
return 0;
}

node->eval = flecs_script_create_entity(v, node->name);
ecs_expr_node_t *name_expr = node->name_expr;
if (name_expr) {
ecs_script_t *script = &v->base.script->pub;
ecs_expr_eval_desc_t desc = {
.name = script->name,
.lookup_action = flecs_script_find_entity_action,
.lookup_ctx = v,
.vars = v->vars,
.type = ecs_id(ecs_string_t),
.runtime = v->r
};

if (!name_expr->type_info) {
if (flecs_expr_visit_type(script, name_expr, &desc)) {
return -1;
}

if (flecs_expr_visit_fold(script, &node->name_expr, &desc)) {
return -1;
}

name_expr = node->name_expr;
}

ecs_value_t value = { .type = ecs_id(ecs_string_t) };
if (flecs_expr_visit_eval(script, name_expr, &desc, &value)) {
return -1;
}

char *name = *(char**)value.ptr;
if (!name) {
flecs_script_eval_error(v, node, "failed to evaluate entity name");
return -1;
}

node->eval = flecs_script_create_entity(v, name);

ecs_value_free(script->world, value.type, value.ptr);
} else {
node->eval = flecs_script_create_entity(v, node->name);
}

node->parent = v->entity;

if (v->template_entity) {
@@ -61444,6 +61528,9 @@ void flecs_script_entity_free(
ecs_script_entity_t *node)
{
flecs_script_scope_free(v, node->scope);
if (node->name_expr) {
flecs_expr_visit_free(&v->script->pub, node->name_expr);
}
}

static
15 changes: 14 additions & 1 deletion src/addons/script/ast.c
Original file line number Diff line number Diff line change
@@ -57,7 +57,8 @@ ecs_script_scope_t* flecs_script_insert_scope(

ecs_script_entity_t* flecs_script_insert_entity(
ecs_script_parser_t *parser,
const char *name)
const char *name,
bool name_is_expr)
{
ecs_script_scope_t *scope = parser->scope;
ecs_assert(scope != NULL, ECS_INTERNAL_ERROR, NULL);
@@ -71,12 +72,24 @@ ecs_script_entity_t* flecs_script_insert_entity(

result->name = name;

if (name_is_expr) {
parser->significant_newline = false;
result->name_expr = (ecs_expr_node_t*)
flecs_expr_interpolated_string(parser, name);
if (!result->name_expr) {
goto error;
}
parser->significant_newline = true;
}

ecs_script_scope_t *entity_scope = flecs_script_scope_new(parser);
ecs_assert(entity_scope != NULL, ECS_INTERNAL_ERROR, NULL);
result->scope = entity_scope;

flecs_ast_append(parser, scope->stmts, ecs_script_entity_t, result);
return result;
error:
return NULL;
}

static
4 changes: 3 additions & 1 deletion src/addons/script/ast.h
Original file line number Diff line number Diff line change
@@ -77,6 +77,7 @@ struct ecs_script_entity_t {
bool name_is_var;
bool kind_w_expr;
ecs_script_scope_t *scope;
ecs_expr_node_t *name_expr;

// Populated during eval
ecs_script_entity_t *parent;
@@ -148,7 +149,8 @@ ecs_script_scope_t* flecs_script_insert_scope(

ecs_script_entity_t* flecs_script_insert_entity(
ecs_script_parser_t *parser,
const char *name);
const char *name,
bool name_is_expr);

ecs_script_pair_scope_t* flecs_script_insert_pair_scope(
ecs_script_parser_t *parser,
46 changes: 37 additions & 9 deletions src/addons/script/parser.c
Original file line number Diff line number Diff line change
@@ -80,7 +80,7 @@ const char* flecs_script_comma_expr(
if (is_base_list) {
flecs_script_insert_pair_tag(parser, "IsA", Token(0));
} else {
flecs_script_insert_entity(parser, Token(0));
flecs_script_insert_entity(parser, Token(0), false);
}

LookAhead_1(',',
@@ -238,8 +238,12 @@ const char* flecs_script_stmt(
{
ParserBegin;

bool name_is_expr_0 = false;
bool name_is_expr_1 = false;

Parse(
case EcsTokIdentifier: goto identifier;
case EcsTokString: goto string_name;
case '{': return flecs_script_scope(parser,
flecs_script_insert_scope(parser), pos);
case '(': goto paren;
@@ -254,6 +258,15 @@ const char* flecs_script_stmt(
EcsTokEndOfStatement: EndOfRule;
);

string_name:
/* If this is an interpolated string, we need to evaluate it as expression
* at evaluation time. Otherwise we can just use the string as name. The
* latter is useful if an entity name contains special characters that are
* not allowed in identifier tokens. */
if (flecs_string_is_interpolated(Token(0))) {
name_is_expr_0 = true;
}

identifier: {
// enterprise } (end of scope)
LookAhead_1('}',
@@ -265,12 +278,16 @@ identifier: {
case '{': {
return flecs_script_scope(parser,
flecs_script_insert_entity(
parser, Token(0))->scope, pos);
parser, Token(0), name_is_expr_0)->scope, pos);
}

// Red,
case ',': {
flecs_script_insert_entity(parser, Token(0));
if (name_is_expr_0) {
Error("expression not allowed as entity name here");
}

flecs_script_insert_entity(parser, Token(0), false);
pos = flecs_script_comma_expr(parser, pos, false);
EndOfRule;
}
@@ -282,7 +299,7 @@ identifier: {
pos = lookahead;
return flecs_script_scope(parser,
flecs_script_insert_entity(
parser, Token(0))->scope, pos);
parser, Token(0), name_is_expr_0)->scope, pos);
)

goto insert_tag;
@@ -312,6 +329,11 @@ identifier: {
case EcsTokIdentifier: {
goto identifier_identifier;
}

// Spaceship "enterprise"
case EcsTokString: {
goto identifier_string;
}
)
}

@@ -629,7 +651,7 @@ identifier_colon: {
// enterprise : SpaceShip
Parse_1(EcsTokIdentifier, {
ecs_script_entity_t *entity = flecs_script_insert_entity(
parser, Token(0));
parser, Token(0), name_is_expr_0);

Scope(entity->scope,
flecs_script_insert_pair_tag(parser, "IsA", Token(2));
@@ -655,7 +677,7 @@ identifier_colon: {
// x =
identifier_assign: {
ecs_script_entity_t *entity = flecs_script_insert_entity(
parser, Token(0));
parser, Token(0), name_is_expr_0);

// x = Position:
LookAhead_2(EcsTokIdentifier, ':',
@@ -693,9 +715,15 @@ identifier_assign: {
}

// Spaceship enterprise
identifier_string: {
if (flecs_string_is_interpolated(Token(1))) {
name_is_expr_1 = true;
}
}

identifier_identifier: {
ecs_script_entity_t *entity = flecs_script_insert_entity(
parser, Token(1));
parser, Token(1), name_is_expr_1);
entity->kind = Token(0);

// Spaceship enterprise :
@@ -743,7 +771,7 @@ identifier_paren: {
// SpaceShip(expr)\n
EcsTokEndOfStatement: {
ecs_script_entity_t *entity = flecs_script_insert_entity(
parser, NULL);
parser, NULL, false);

Scope(entity->scope,
ecs_script_component_t *comp =
@@ -757,7 +785,7 @@ identifier_paren: {
// SpaceShip(expr) {
case '{': {
ecs_script_entity_t *entity = flecs_script_insert_entity(
parser, NULL);
parser, NULL, false);

Scope(entity->scope,
ecs_script_component_t *comp =
43 changes: 42 additions & 1 deletion src/addons/script/visit_eval.c
Original file line number Diff line number Diff line change
@@ -469,7 +469,48 @@ int flecs_script_eval_entity(
return 0;
}

node->eval = flecs_script_create_entity(v, node->name);
ecs_expr_node_t *name_expr = node->name_expr;
if (name_expr) {
ecs_script_t *script = &v->base.script->pub;
ecs_expr_eval_desc_t desc = {
.name = script->name,
.lookup_action = flecs_script_find_entity_action,
.lookup_ctx = v,
.vars = v->vars,
.type = ecs_id(ecs_string_t),
.runtime = v->r
};

if (!name_expr->type_info) {
if (flecs_expr_visit_type(script, name_expr, &desc)) {
return -1;
}

if (flecs_expr_visit_fold(script, &node->name_expr, &desc)) {
return -1;
}

name_expr = node->name_expr;
}

ecs_value_t value = { .type = ecs_id(ecs_string_t) };
if (flecs_expr_visit_eval(script, name_expr, &desc, &value)) {
return -1;
}

char *name = *(char**)value.ptr;
if (!name) {
flecs_script_eval_error(v, node, "failed to evaluate entity name");
return -1;
}

node->eval = flecs_script_create_entity(v, name);

ecs_value_free(script->world, value.type, value.ptr);
} else {
node->eval = flecs_script_create_entity(v, node->name);
}

node->parent = v->entity;

if (v->template_entity) {
3 changes: 3 additions & 0 deletions src/addons/script/visit_free.c
Original file line number Diff line number Diff line change
@@ -41,6 +41,9 @@ void flecs_script_entity_free(
ecs_script_entity_t *node)
{
flecs_script_scope_free(v, node->scope);
if (node->name_expr) {
flecs_expr_visit_free(&v->script->pub, node->name_expr);
}
}

static
12 changes: 11 additions & 1 deletion test/script/project.json
Original file line number Diff line number Diff line change
@@ -277,7 +277,17 @@
"assign_call_scoped_func_w_using",
"eval_w_vars",
"eval_w_runtime",
"component_in_entity_in_with_scope"
"component_in_entity_in_with_scope",
"entity_w_string_name",
"entity_w_interpolated_name",
"entity_w_interpolated_name_w_var",
"entity_w_string_name_w_inherit",
"entity_w_string_name_w_inherit_scope",
"entity_w_string_name_w_kind",
"entity_w_string_name_w_kind_value",
"entity_w_string_name_w_kind_scope",
"entity_w_string_name_w_kind_value_scope",
"entity_w_interpolated_name_w_var_in_scope"
]
}, {
"id": "Template",
196 changes: 196 additions & 0 deletions test/script/src/Eval.c
Original file line number Diff line number Diff line change
@@ -8837,3 +8837,199 @@ void Eval_component_in_entity_in_with_scope(void) {

ecs_fini(world);
}

void Eval_entity_w_string_name(void) {
ecs_world_t *world = ecs_init();

const char *expr =
HEAD "\"e\" { }";

test_assert(ecs_script_run(world, NULL, expr) == 0);

ecs_entity_t e = ecs_lookup(world, "e");
test_assert(e != 0);

ecs_fini(world);
}

void Eval_entity_w_interpolated_name(void) {
ecs_world_t *world = ecs_init();

const char *expr =
HEAD "\"e_{10 + 20}\" { }";

test_assert(ecs_script_run(world, NULL, expr) == 0);

ecs_entity_t e = ecs_lookup(world, "e_30");
test_assert(e != 0);

ecs_fini(world);
}

void Eval_entity_w_interpolated_name_w_var(void) {
ecs_world_t *world = ecs_init();

const char *expr =
HEAD "const i = 10"
LINE "\"e_{$i + 20}\" { }";

test_assert(ecs_script_run(world, NULL, expr) == 0);

ecs_entity_t e = ecs_lookup(world, "e_30");
test_assert(e != 0);

ecs_fini(world);
}

void Eval_entity_w_string_name_w_inherit(void) {
ecs_world_t *world = ecs_init();

ECS_TAG(world, Foo);

const char *expr =
HEAD "\"e_{10 + 20}\" : Foo";

test_assert(ecs_script_run(world, NULL, expr) == 0);

ecs_entity_t e = ecs_lookup(world, "e_30");
test_assert(e != 0);
test_assert(ecs_has_pair(world, e, EcsIsA, Foo));

ecs_fini(world);
}

void Eval_entity_w_string_name_w_inherit_scope(void) {
ecs_world_t *world = ecs_init();

ECS_TAG(world, Foo);

const char *expr =
HEAD "\"e_{10 + 20}\" : Foo { }";

test_assert(ecs_script_run(world, NULL, expr) == 0);

ecs_entity_t e = ecs_lookup(world, "e_30");
test_assert(e != 0);
test_assert(ecs_has_pair(world, e, EcsIsA, Foo));

ecs_fini(world);
}

void Eval_entity_w_string_name_w_kind(void) {
ecs_world_t *world = ecs_init();

ecs_entity_t ecs_id(Position) = ecs_struct(world, {
.entity = ecs_entity(world, {.name = "Position"}),
.members = {
{"x", ecs_id(ecs_f32_t)},
{"y", ecs_id(ecs_f32_t)}
}
});

const char *expr =
HEAD "Position \"e_{10 + 20}\"";

test_assert(ecs_script_run(world, NULL, expr) == 0);

ecs_entity_t e = ecs_lookup(world, "e_30");
test_assert(e != 0);
test_assert(ecs_has(world, e, Position));

ecs_fini(world);
}

void Eval_entity_w_string_name_w_kind_value(void) {
ecs_world_t *world = ecs_init();

ecs_entity_t ecs_id(Position) = ecs_struct(world, {
.entity = ecs_entity(world, {.name = "Position"}),
.members = {
{"x", ecs_id(ecs_f32_t)},
{"y", ecs_id(ecs_f32_t)}
}
});

const char *expr =
HEAD "Position \"e_{10 + 20}\"(10, 20)";

test_assert(ecs_script_run(world, NULL, expr) == 0);

ecs_entity_t e = ecs_lookup(world, "e_30");
test_assert(e != 0);
test_assert(ecs_has(world, e, Position));

const Position *p = ecs_get(world, e, Position);
test_assert(p != NULL);
test_int(p->x, 10);
test_int(p->y, 20);

ecs_fini(world);
}

void Eval_entity_w_string_name_w_kind_scope(void) {
ecs_world_t *world = ecs_init();

ecs_entity_t ecs_id(Position) = ecs_struct(world, {
.entity = ecs_entity(world, {.name = "Position"}),
.members = {
{"x", ecs_id(ecs_f32_t)},
{"y", ecs_id(ecs_f32_t)}
}
});

const char *expr =
HEAD "Position \"e_{10 + 20}\" { }";

test_assert(ecs_script_run(world, NULL, expr) == 0);

ecs_entity_t e = ecs_lookup(world, "e_30");
test_assert(e != 0);
test_assert(ecs_has(world, e, Position));

ecs_fini(world);
}

void Eval_entity_w_string_name_w_kind_value_scope(void) {
ecs_world_t *world = ecs_init();

ecs_entity_t ecs_id(Position) = ecs_struct(world, {
.entity = ecs_entity(world, {.name = "Position"}),
.members = {
{"x", ecs_id(ecs_f32_t)},
{"y", ecs_id(ecs_f32_t)}
}
});

const char *expr =
HEAD "Position \"e_{10 + 20}\"(10, 20) { }";

test_assert(ecs_script_run(world, NULL, expr) == 0);

ecs_entity_t e = ecs_lookup(world, "e_30");
test_assert(e != 0);
test_assert(ecs_has(world, e, Position));

const Position *p = ecs_get(world, e, Position);
test_assert(p != NULL);
test_int(p->x, 10);
test_int(p->y, 20);

ecs_fini(world);
}

void Eval_entity_w_interpolated_name_w_var_in_scope(void) {
ecs_world_t *world = ecs_init();

const char *expr =
HEAD "parent {"
LINE " const i = 10"
LINE " \"e_{$i + 20}\" { }"
LINE "}";

test_assert(ecs_script_run(world, NULL, expr) == 0);

ecs_entity_t e = ecs_lookup(world, "parent.e_30");
test_assert(e != 0);

ecs_fini(world);
}
52 changes: 51 additions & 1 deletion test/script/src/main.c
Original file line number Diff line number Diff line change
@@ -274,6 +274,16 @@ void Eval_assign_call_scoped_func_w_using(void);
void Eval_eval_w_vars(void);
void Eval_eval_w_runtime(void);
void Eval_component_in_entity_in_with_scope(void);
void Eval_entity_w_string_name(void);
void Eval_entity_w_interpolated_name(void);
void Eval_entity_w_interpolated_name_w_var(void);
void Eval_entity_w_string_name_w_inherit(void);
void Eval_entity_w_string_name_w_inherit_scope(void);
void Eval_entity_w_string_name_w_kind(void);
void Eval_entity_w_string_name_w_kind_value(void);
void Eval_entity_w_string_name_w_kind_scope(void);
void Eval_entity_w_string_name_w_kind_value_scope(void);
void Eval_entity_w_interpolated_name_w_var_in_scope(void);

// Testsuite 'Template'
void Template_template_no_scope(void);
@@ -1849,6 +1859,46 @@ bake_test_case Eval_testcases[] = {
{
"component_in_entity_in_with_scope",
Eval_component_in_entity_in_with_scope
},
{
"entity_w_string_name",
Eval_entity_w_string_name
},
{
"entity_w_interpolated_name",
Eval_entity_w_interpolated_name
},
{
"entity_w_interpolated_name_w_var",
Eval_entity_w_interpolated_name_w_var
},
{
"entity_w_string_name_w_inherit",
Eval_entity_w_string_name_w_inherit
},
{
"entity_w_string_name_w_inherit_scope",
Eval_entity_w_string_name_w_inherit_scope
},
{
"entity_w_string_name_w_kind",
Eval_entity_w_string_name_w_kind
},
{
"entity_w_string_name_w_kind_value",
Eval_entity_w_string_name_w_kind_value
},
{
"entity_w_string_name_w_kind_scope",
Eval_entity_w_string_name_w_kind_scope
},
{
"entity_w_string_name_w_kind_value_scope",
Eval_entity_w_string_name_w_kind_value_scope
},
{
"entity_w_interpolated_name_w_var_in_scope",
Eval_entity_w_interpolated_name_w_var_in_scope
}
};

@@ -3879,7 +3929,7 @@ static bake_test_suite suites[] = {
"Eval",
NULL,
NULL,
265,
275,
Eval_testcases
},
{