From fc4f3661622883beebf3c72badd80195a0bf5ad3 Mon Sep 17 00:00:00 2001 From: Sander Mertens Date: Thu, 21 Dec 2023 14:43:43 -0800 Subject: [PATCH] Fix issue with parsing newlines in query strings --- flecs.c | 20 +++++---- flecs.h | 3 +- include/flecs/addons/parser.h | 3 +- src/addons/meta/cursor.c | 2 +- src/addons/parser.c | 10 +++-- src/addons/plecs.c | 2 +- src/entity.c | 4 +- src/filter.c | 2 +- test/addons/project.json | 2 + test/addons/src/Parser.c | 79 +++++++++++++++++++++++++++++++++++ test/addons/src/main.c | 12 +++++- 11 files changed, 120 insertions(+), 19 deletions(-) diff --git a/flecs.c b/flecs.c index 73a3b545b7..24d8e6cbd2 100644 --- a/flecs.c +++ b/flecs.c @@ -4779,7 +4779,7 @@ ecs_table_t *flecs_traverse_from_expr( const char *ptr = expr; if (ptr) { ecs_term_t term = {0}; - while (ptr[0] && (ptr = ecs_parse_term(world, name, expr, ptr, &term, NULL))){ + while (ptr[0] && (ptr = ecs_parse_term(world, name, expr, ptr, &term, NULL, false))){ if (!ecs_term_is_initialized(&term)) { break; } @@ -4842,7 +4842,7 @@ void flecs_defer_from_expr( const char *ptr = expr; if (ptr) { ecs_term_t term = {0}; - while (ptr[0] && (ptr = ecs_parse_term(world, name, expr, ptr, &term, NULL))) { + while (ptr[0] && (ptr = ecs_parse_term(world, name, expr, ptr, &term, NULL, false))) { if (!ecs_term_is_initialized(&term)) { break; } @@ -11318,7 +11318,7 @@ ecs_filter_t* ecs_filter_init( } while (ptr[0] && - (ptr = ecs_parse_term(world, name, expr, ptr, &term, extra_args))) + (ptr = ecs_parse_term(world, name, expr, ptr, &term, extra_args, true))) { if (!ecs_term_is_initialized(&term)) { break; @@ -30869,7 +30869,6 @@ const char* flecs_parse_annotation( ptr = ecs_parse_ws(ptr); if (ptr[0] != TOK_BRACKET_CLOSE) { - printf("errr\n"); ecs_parser_error(name, sig, column, "expected ]"); return NULL; } @@ -31472,7 +31471,8 @@ char* ecs_parse_term( const char *expr, const char *ptr, ecs_term_t *term, - ecs_term_id_t *extra_args) + ecs_term_id_t *extra_args, + bool allow_newline) { ecs_check(world != NULL, ECS_INVALID_PARAMETER, NULL); ecs_check(ptr != NULL, ECS_INVALID_PARAMETER, NULL); @@ -31623,7 +31623,11 @@ char* ecs_parse_term( term->id_flags = 0; } - ptr = ecs_parse_ws(ptr); + if (allow_newline) { + ptr = ecs_parse_ws_eol(ptr); + } else { + ptr = ecs_parse_ws(ptr); + } return ECS_CONST_CAST(char*, ptr); error: @@ -33346,7 +33350,7 @@ const char *plecs_parse_plecs_term( decl_id = state->last_predicate; } - ptr = ecs_parse_term(world, name, expr, ptr, &term, NULL); + ptr = ecs_parse_term(world, name, expr, ptr, &term, NULL, false); if (!ptr) { return NULL; } @@ -55679,7 +55683,7 @@ int ecs_meta_set_string( ecs_id_t id = 0; #ifdef FLECS_PARSER ecs_term_t term = {0}; - if (ecs_parse_term(cursor->world, NULL, value, value, &term, NULL)) { + if (ecs_parse_term(cursor->world, NULL, value, value, &term, NULL, false)) { if (ecs_term_finalize(cursor->world, &term)) { ecs_term_fini(&term); goto error; diff --git a/flecs.h b/flecs.h index 15df54eab0..75712ec70e 100644 --- a/flecs.h +++ b/flecs.h @@ -15395,7 +15395,8 @@ char* ecs_parse_term( const char *expr, const char *ptr, ecs_term_t *term_out, - ecs_term_id_t *extra_args); + ecs_term_id_t *extra_args, + bool allow_newline); #ifdef __cplusplus } diff --git a/include/flecs/addons/parser.h b/include/flecs/addons/parser.h index b4a8d7c693..77efe21c22 100644 --- a/include/flecs/addons/parser.h +++ b/include/flecs/addons/parser.h @@ -118,7 +118,8 @@ char* ecs_parse_term( const char *expr, const char *ptr, ecs_term_t *term_out, - ecs_term_id_t *extra_args); + ecs_term_id_t *extra_args, + bool allow_newline); #ifdef __cplusplus } diff --git a/src/addons/meta/cursor.c b/src/addons/meta/cursor.c index 1f70020087..69f23de8a3 100644 --- a/src/addons/meta/cursor.c +++ b/src/addons/meta/cursor.c @@ -1368,7 +1368,7 @@ int ecs_meta_set_string( ecs_id_t id = 0; #ifdef FLECS_PARSER ecs_term_t term = {0}; - if (ecs_parse_term(cursor->world, NULL, value, value, &term, NULL)) { + if (ecs_parse_term(cursor->world, NULL, value, value, &term, NULL, false)) { if (ecs_term_finalize(cursor->world, &term)) { ecs_term_fini(&term); goto error; diff --git a/src/addons/parser.c b/src/addons/parser.c index 829b837ca0..ca5bd56b2f 100644 --- a/src/addons/parser.c +++ b/src/addons/parser.c @@ -359,7 +359,6 @@ const char* flecs_parse_annotation( ptr = ecs_parse_ws(ptr); if (ptr[0] != TOK_BRACKET_CLOSE) { - printf("errr\n"); ecs_parser_error(name, sig, column, "expected ]"); return NULL; } @@ -962,7 +961,8 @@ char* ecs_parse_term( const char *expr, const char *ptr, ecs_term_t *term, - ecs_term_id_t *extra_args) + ecs_term_id_t *extra_args, + bool allow_newline) { ecs_check(world != NULL, ECS_INVALID_PARAMETER, NULL); ecs_check(ptr != NULL, ECS_INVALID_PARAMETER, NULL); @@ -1113,7 +1113,11 @@ char* ecs_parse_term( term->id_flags = 0; } - ptr = ecs_parse_ws(ptr); + if (allow_newline) { + ptr = ecs_parse_ws_eol(ptr); + } else { + ptr = ecs_parse_ws(ptr); + } return ECS_CONST_CAST(char*, ptr); error: diff --git a/src/addons/plecs.c b/src/addons/plecs.c index 94841564f2..140fa546d4 100644 --- a/src/addons/plecs.c +++ b/src/addons/plecs.c @@ -1711,7 +1711,7 @@ const char *plecs_parse_plecs_term( decl_id = state->last_predicate; } - ptr = ecs_parse_term(world, name, expr, ptr, &term, NULL); + ptr = ecs_parse_term(world, name, expr, ptr, &term, NULL, false); if (!ptr) { return NULL; } diff --git a/src/entity.c b/src/entity.c index cd532f37b2..cd81f0a67c 100644 --- a/src/entity.c +++ b/src/entity.c @@ -1376,7 +1376,7 @@ ecs_table_t *flecs_traverse_from_expr( const char *ptr = expr; if (ptr) { ecs_term_t term = {0}; - while (ptr[0] && (ptr = ecs_parse_term(world, name, expr, ptr, &term, NULL))){ + while (ptr[0] && (ptr = ecs_parse_term(world, name, expr, ptr, &term, NULL, false))){ if (!ecs_term_is_initialized(&term)) { break; } @@ -1439,7 +1439,7 @@ void flecs_defer_from_expr( const char *ptr = expr; if (ptr) { ecs_term_t term = {0}; - while (ptr[0] && (ptr = ecs_parse_term(world, name, expr, ptr, &term, NULL))) { + while (ptr[0] && (ptr = ecs_parse_term(world, name, expr, ptr, &term, NULL, false))) { if (!ecs_term_is_initialized(&term)) { break; } diff --git a/src/filter.c b/src/filter.c index feced806d2..66d5d68d9c 100644 --- a/src/filter.c +++ b/src/filter.c @@ -1537,7 +1537,7 @@ ecs_filter_t* ecs_filter_init( } while (ptr[0] && - (ptr = ecs_parse_term(world, name, expr, ptr, &term, extra_args))) + (ptr = ecs_parse_term(world, name, expr, ptr, &term, extra_args, true))) { if (!ecs_term_is_initialized(&term)) { break; diff --git a/test/addons/project.json b/test/addons/project.json index c4860aeb7e..e1699caf99 100644 --- a/test/addons/project.json +++ b/test/addons/project.json @@ -238,6 +238,8 @@ "query_scope_unbalanced", "query_not_scope", "query_empty_scope", + "query_scope_newline_after_open", + "query_scope_newline_after_close", "override_tag", "override_pair", "pair_3_args", diff --git a/test/addons/src/Parser.c b/test/addons/src/Parser.c index b01377fa2b..347c41bf8d 100644 --- a/test/addons/src/Parser.c +++ b/test/addons/src/Parser.c @@ -5314,6 +5314,84 @@ void Parser_query_empty_scope(void) { ecs_fini(world); } +void Parser_query_scope_newline_after_open(void) { + ecs_world_t *world = ecs_mini(); + + ECS_TAG(world, TagA); + ECS_TAG(world, TagB); + + ecs_filter_t f = ECS_FILTER_INIT; + test_assert(NULL != ecs_filter_init(world, &(ecs_filter_desc_t){ + .storage = &f, + .expr = "TagA, {\nTagB}" + })); + test_int(filter_count(&f), 4); + + ecs_term_t *terms = filter_terms(&f); + test_first(terms[0], TagA, EcsSelf|EcsIsEntity); + test_src(terms[0], EcsThis, EcsSelf|EcsUp|EcsIsVariable); + test_int(terms[0].oper, EcsAnd); + test_int(terms[0].inout, EcsInOutDefault); + + test_first(terms[1], EcsScopeOpen, EcsSelf|EcsIsEntity); + test_src(terms[1], 0, EcsIsEntity); + test_int(terms[1].oper, EcsAnd); + test_int(terms[1].inout, EcsInOutNone); + + test_first(terms[2], TagB, EcsSelf|EcsIsEntity); + test_src(terms[2], EcsThis, EcsSelf|EcsUp|EcsIsVariable); + test_int(terms[2].oper, EcsAnd); + test_int(terms[2].inout, EcsInOutDefault); + + test_first(terms[3], EcsScopeClose, EcsSelf|EcsIsEntity); + test_src(terms[3], 0, EcsIsEntity); + test_int(terms[3].oper, EcsAnd); + test_int(terms[3].inout, EcsInOutNone); + + ecs_filter_fini(&f); + + ecs_fini(world); +} + +void Parser_query_scope_newline_after_close(void) { + ecs_world_t *world = ecs_mini(); + + ECS_TAG(world, TagA); + ECS_TAG(world, TagB); + + ecs_filter_t f = ECS_FILTER_INIT; + test_assert(NULL != ecs_filter_init(world, &(ecs_filter_desc_t){ + .storage = &f, + .expr = "TagA, {TagB\n}" + })); + test_int(filter_count(&f), 4); + + ecs_term_t *terms = filter_terms(&f); + test_first(terms[0], TagA, EcsSelf|EcsIsEntity); + test_src(terms[0], EcsThis, EcsSelf|EcsUp|EcsIsVariable); + test_int(terms[0].oper, EcsAnd); + test_int(terms[0].inout, EcsInOutDefault); + + test_first(terms[1], EcsScopeOpen, EcsSelf|EcsIsEntity); + test_src(terms[1], 0, EcsIsEntity); + test_int(terms[1].oper, EcsAnd); + test_int(terms[1].inout, EcsInOutNone); + + test_first(terms[2], TagB, EcsSelf|EcsIsEntity); + test_src(terms[2], EcsThis, EcsSelf|EcsUp|EcsIsVariable); + test_int(terms[2].oper, EcsAnd); + test_int(terms[2].inout, EcsInOutDefault); + + test_first(terms[3], EcsScopeClose, EcsSelf|EcsIsEntity); + test_src(terms[3], 0, EcsIsEntity); + test_int(terms[3].oper, EcsAnd); + test_int(terms[3].inout, EcsInOutNone); + + ecs_filter_fini(&f); + + ecs_fini(world); +} + void Parser_override_tag(void) { ecs_world_t *world = ecs_mini(); @@ -5659,3 +5737,4 @@ void Parser_pair_3_args_2_terms_this_tgt_implicit_this(void) { ecs_fini(world); } + diff --git a/test/addons/src/main.c b/test/addons/src/main.c index 8ea364c20e..8dd147dadc 100644 --- a/test/addons/src/main.c +++ b/test/addons/src/main.c @@ -233,6 +233,8 @@ void Parser_query_nested_scope_spaces(void); void Parser_query_scope_unbalanced(void); void Parser_query_not_scope(void); void Parser_query_empty_scope(void); +void Parser_query_scope_newline_after_open(void); +void Parser_query_scope_newline_after_close(void); void Parser_override_tag(void); void Parser_override_pair(void); void Parser_pair_3_args(void); @@ -2698,6 +2700,14 @@ bake_test_case Parser_testcases[] = { "query_empty_scope", Parser_query_empty_scope }, + { + "query_scope_newline_after_open", + Parser_query_scope_newline_after_open + }, + { + "query_scope_newline_after_close", + Parser_query_scope_newline_after_close + }, { "override_tag", Parser_override_tag @@ -8766,7 +8776,7 @@ static bake_test_suite suites[] = { "Parser", NULL, NULL, - 235, + 237, Parser_testcases }, {