Skip to content

Commit fd595ba

Browse files
committed
Add query DSL feature that expands R(S, T, Q) into R(S, T), R(T, Q)
1 parent 78305c4 commit fd595ba

10 files changed

Lines changed: 350 additions & 40 deletions

File tree

flecs.c

Lines changed: 70 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4746,7 +4746,7 @@ ecs_table_t *flecs_traverse_from_expr(
47464746
const char *ptr = expr;
47474747
if (ptr) {
47484748
ecs_term_t term = {0};
4749-
while (ptr[0] && (ptr = ecs_parse_term(world, name, expr, ptr, &term))){
4749+
while (ptr[0] && (ptr = ecs_parse_term(world, name, expr, ptr, &term, NULL))){
47504750
if (!ecs_term_is_initialized(&term)) {
47514751
break;
47524752
}
@@ -4809,7 +4809,7 @@ void flecs_defer_from_expr(
48094809
const char *ptr = expr;
48104810
if (ptr) {
48114811
ecs_term_t term = {0};
4812-
while (ptr[0] && (ptr = ecs_parse_term(world, name, expr, ptr, &term))){
4812+
while (ptr[0] && (ptr = ecs_parse_term(world, name, expr, ptr, &term, NULL))) {
48134813
if (!ecs_term_is_initialized(&term)) {
48144814
break;
48154815
}
@@ -11053,23 +11053,50 @@ ecs_filter_t* ecs_filter_init(
1105311053
const char *name = NULL;
1105411054
const char *ptr = desc->expr;
1105511055
ecs_term_t term = {0};
11056+
ecs_term_id_t extra_args[ECS_PARSER_MAX_ARGS];
1105611057
int32_t expr_size = 0;
1105711058

11059+
ecs_os_zeromem(extra_args);
11060+
1105811061
if (entity) {
1105911062
name = ecs_get_name(world, entity);
1106011063
}
1106111064

11062-
while (ptr[0] && (ptr = ecs_parse_term(world, name, expr, ptr, &term))){
11065+
while (ptr[0] &&
11066+
(ptr = ecs_parse_term(world, name, expr, ptr, &term, extra_args)))
11067+
{
1106311068
if (!ecs_term_is_initialized(&term)) {
1106411069
break;
1106511070
}
1106611071

11067-
if (expr_count == expr_size) {
11068-
expr_size = expr_size ? expr_size * 2 : 8;
11069-
expr_terms = ecs_os_realloc_n(expr_terms, ecs_term_t, expr_size);
11070-
}
11072+
int32_t arg = 0;
11073+
11074+
do {
11075+
ecs_assert(arg <= ECS_PARSER_MAX_ARGS, ECS_INTERNAL_ERROR, NULL);
11076+
11077+
if (expr_count == expr_size) {
11078+
expr_size = expr_size ? expr_size * 2 : 8;
11079+
expr_terms = ecs_os_realloc_n(expr_terms, ecs_term_t, expr_size);
11080+
}
11081+
11082+
ecs_term_t *expr_term = &expr_terms[expr_count ++];
11083+
*expr_term = term;
11084+
11085+
if (arg) {
11086+
expr_term->src = expr_term[-1].second;
11087+
expr_term->second = extra_args[arg - 1];
11088+
11089+
if (expr_term->first.name != NULL) {
11090+
expr_term->first.name = ecs_os_strdup(
11091+
expr_term->first.name);
11092+
}
11093+
if (expr_term->src.name != NULL) {
11094+
expr_term->src.name = ecs_os_strdup(
11095+
expr_term->src.name);
11096+
}
11097+
}
11098+
} while (ecs_term_id_is_set(&extra_args[arg ++]));
1107111099

11072-
expr_terms[expr_count ++] = term;
1107311100
if (ptr[0] == '\n') {
1107411101
break;
1107511102
}
@@ -30577,15 +30604,24 @@ const char* flecs_parse_arguments(
3057730604
int64_t column,
3057830605
const char *ptr,
3057930606
char *token,
30580-
ecs_term_t *term)
30607+
ecs_term_t *term,
30608+
ecs_term_id_t *extra_args)
3058130609
{
3058230610
(void)column;
3058330611

3058430612
int32_t arg = 0;
3058530613

30614+
if (extra_args) {
30615+
ecs_os_memset_n(extra_args, 0, ecs_term_id_t, ECS_PARSER_MAX_ARGS);
30616+
}
30617+
30618+
if (!term) {
30619+
arg = 2;
30620+
}
30621+
3058630622
do {
3058730623
if (flecs_valid_token_start_char(ptr[0])) {
30588-
if (arg == 2) {
30624+
if ((arg == ECS_PARSER_MAX_ARGS) || (!extra_args && arg == 2)) {
3058930625
ecs_parser_error(name, expr, (ptr - expr),
3059030626
"too many arguments in term");
3059130627
return NULL;
@@ -30602,6 +30638,8 @@ const char* flecs_parse_arguments(
3060230638
term_id = &term->src;
3060330639
} else if (arg == 1) {
3060430640
term_id = &term->second;
30641+
} else {
30642+
term_id = &extra_args[arg - 2];
3060530643
}
3060630644

3060730645
/* If token is a colon, the token is an identifier followed by a
@@ -30643,7 +30681,9 @@ const char* flecs_parse_arguments(
3064330681
if (ptr[0] == TOK_AND) {
3064430682
ptr = ecs_parse_ws(ptr + 1);
3064530683

30646-
term->id_flags = ECS_PAIR;
30684+
if (term) {
30685+
term->id_flags = ECS_PAIR;
30686+
}
3064730687

3064830688
} else if (ptr[0] == TOK_PAREN_CLOSE) {
3064930689
ptr = ecs_parse_ws(ptr + 1);
@@ -30689,7 +30729,8 @@ const char* flecs_parse_term(
3068930729
const ecs_world_t *world,
3069030730
const char *name,
3069130731
const char *expr,
30692-
ecs_term_t *term_out)
30732+
ecs_term_t *term_out,
30733+
ecs_term_id_t *extra_args)
3069330734
{
3069430735
const char *ptr = expr;
3069530736
char token[ECS_MAX_TOKEN_SIZE] = {0};
@@ -30837,7 +30878,7 @@ const char* flecs_parse_term(
3083730878
ptr = ecs_parse_ws(ptr);
3083830879
} else {
3083930880
ptr = flecs_parse_arguments(
30840-
world, name, expr, (ptr - expr), ptr, token, &term);
30881+
world, name, expr, (ptr - expr), ptr, token, &term, extra_args);
3084130882
}
3084230883

3084330884
goto parse_done;
@@ -30955,8 +30996,7 @@ const char* flecs_parse_term(
3095530996
}
3095630997
}
3095730998

30958-
if (ptr[0] == TOK_PAREN_CLOSE) {
30959-
ptr ++;
30999+
if (ptr[0] == TOK_PAREN_CLOSE || ptr[0] == TOK_AND) {
3096031000
goto parse_pair_object;
3096131001
} else {
3096231002
flecs_parser_unexpected_char(name, expr, ptr, ptr[0]);
@@ -30983,6 +31023,17 @@ const char* flecs_parse_term(
3098331023
term.id_flags = ECS_PAIR;
3098431024
}
3098531025

31026+
if (ptr[0] == TOK_AND) {
31027+
ptr = ecs_parse_ws(ptr + 1);
31028+
ptr = flecs_parse_arguments(
31029+
world, name, expr, (ptr - expr), ptr, token, NULL, extra_args);
31030+
if (!ptr) {
31031+
goto error;
31032+
}
31033+
} else {
31034+
ptr ++;
31035+
}
31036+
3098631037
ptr = ecs_parse_ws(ptr);
3098731038
goto parse_done;
3098831039

@@ -31020,7 +31071,8 @@ char* ecs_parse_term(
3102031071
const char *name,
3102131072
const char *expr,
3102231073
const char *ptr,
31023-
ecs_term_t *term)
31074+
ecs_term_t *term,
31075+
ecs_term_id_t *extra_args)
3102431076
{
3102531077
ecs_check(world != NULL, ECS_INVALID_PARAMETER, NULL);
3102631078
ecs_check(ptr != NULL, ECS_INVALID_PARAMETER, NULL);
@@ -31056,7 +31108,7 @@ char* ecs_parse_term(
3105631108
}
3105731109

3105831110
/* Parse next element */
31059-
ptr = flecs_parse_term(world, name, ptr, term);
31111+
ptr = flecs_parse_term(world, name, ptr, term, extra_args);
3106031112
if (!ptr) {
3106131113
goto error;
3106231114
}
@@ -32887,7 +32939,7 @@ const char *plecs_parse_plecs_term(
3288732939
decl_id = state->last_predicate;
3288832940
}
3288932941

32890-
ptr = ecs_parse_term(world, name, expr, ptr, &term);
32942+
ptr = ecs_parse_term(world, name, expr, ptr, &term, NULL);
3289132943
if (!ptr) {
3289232944
return NULL;
3289332945
}

flecs.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15267,6 +15267,9 @@ void ecs_snapshot_free(
1526715267
#ifndef FLECS_PARSER_H
1526815268
#define FLECS_PARSER_H
1526915269

15270+
/** Maximum number of extra arguments in term expression */
15271+
#define ECS_PARSER_MAX_ARGS (16)
15272+
1527015273
#ifdef __cplusplus
1527115274
extern "C" {
1527215275
#endif
@@ -15353,6 +15356,7 @@ const char* ecs_parse_token(
1535315356
* @param expr The expression to parse (optional, improves error logs)
1535415357
* @param ptr The pointer to the current term (must be in expr).
1535515358
* @param term_out Out parameter for the term.
15359+
* @param extra_args Out array for extra args, must be of size ECS_PARSER_MAX_ARGS.
1535615360
* @return pointer to next term if successful, NULL if failed.
1535715361
*/
1535815362
FLECS_API
@@ -15361,7 +15365,8 @@ char* ecs_parse_term(
1536115365
const char *name,
1536215366
const char *expr,
1536315367
const char *ptr,
15364-
ecs_term_t *term_out);
15368+
ecs_term_t *term_out,
15369+
ecs_term_id_t *extra_args);
1536515370

1536615371
#ifdef __cplusplus
1536715372
}

include/flecs/addons/parser.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@
1919
#ifndef FLECS_PARSER_H
2020
#define FLECS_PARSER_H
2121

22+
/** Maximum number of extra arguments in term expression */
23+
#define ECS_PARSER_MAX_ARGS (16)
24+
2225
#ifdef __cplusplus
2326
extern "C" {
2427
#endif
@@ -105,6 +108,7 @@ const char* ecs_parse_token(
105108
* @param expr The expression to parse (optional, improves error logs)
106109
* @param ptr The pointer to the current term (must be in expr).
107110
* @param term_out Out parameter for the term.
111+
* @param extra_args Out array for extra args, must be of size ECS_PARSER_MAX_ARGS.
108112
* @return pointer to next term if successful, NULL if failed.
109113
*/
110114
FLECS_API
@@ -113,7 +117,8 @@ char* ecs_parse_term(
113117
const char *name,
114118
const char *expr,
115119
const char *ptr,
116-
ecs_term_t *term_out);
120+
ecs_term_t *term_out,
121+
ecs_term_id_t *extra_args);
117122

118123
#ifdef __cplusplus
119124
}

src/addons/parser.c

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -487,15 +487,24 @@ const char* flecs_parse_arguments(
487487
int64_t column,
488488
const char *ptr,
489489
char *token,
490-
ecs_term_t *term)
490+
ecs_term_t *term,
491+
ecs_term_id_t *extra_args)
491492
{
492493
(void)column;
493494

494495
int32_t arg = 0;
495496

497+
if (extra_args) {
498+
ecs_os_memset_n(extra_args, 0, ecs_term_id_t, ECS_PARSER_MAX_ARGS);
499+
}
500+
501+
if (!term) {
502+
arg = 2;
503+
}
504+
496505
do {
497506
if (flecs_valid_token_start_char(ptr[0])) {
498-
if (arg == 2) {
507+
if ((arg == ECS_PARSER_MAX_ARGS) || (!extra_args && arg == 2)) {
499508
ecs_parser_error(name, expr, (ptr - expr),
500509
"too many arguments in term");
501510
return NULL;
@@ -512,6 +521,8 @@ const char* flecs_parse_arguments(
512521
term_id = &term->src;
513522
} else if (arg == 1) {
514523
term_id = &term->second;
524+
} else {
525+
term_id = &extra_args[arg - 2];
515526
}
516527

517528
/* If token is a colon, the token is an identifier followed by a
@@ -553,7 +564,9 @@ const char* flecs_parse_arguments(
553564
if (ptr[0] == TOK_AND) {
554565
ptr = ecs_parse_ws(ptr + 1);
555566

556-
term->id_flags = ECS_PAIR;
567+
if (term) {
568+
term->id_flags = ECS_PAIR;
569+
}
557570

558571
} else if (ptr[0] == TOK_PAREN_CLOSE) {
559572
ptr = ecs_parse_ws(ptr + 1);
@@ -599,7 +612,8 @@ const char* flecs_parse_term(
599612
const ecs_world_t *world,
600613
const char *name,
601614
const char *expr,
602-
ecs_term_t *term_out)
615+
ecs_term_t *term_out,
616+
ecs_term_id_t *extra_args)
603617
{
604618
const char *ptr = expr;
605619
char token[ECS_MAX_TOKEN_SIZE] = {0};
@@ -747,7 +761,7 @@ const char* flecs_parse_term(
747761
ptr = ecs_parse_ws(ptr);
748762
} else {
749763
ptr = flecs_parse_arguments(
750-
world, name, expr, (ptr - expr), ptr, token, &term);
764+
world, name, expr, (ptr - expr), ptr, token, &term, extra_args);
751765
}
752766

753767
goto parse_done;
@@ -865,8 +879,7 @@ const char* flecs_parse_term(
865879
}
866880
}
867881

868-
if (ptr[0] == TOK_PAREN_CLOSE) {
869-
ptr ++;
882+
if (ptr[0] == TOK_PAREN_CLOSE || ptr[0] == TOK_AND) {
870883
goto parse_pair_object;
871884
} else {
872885
flecs_parser_unexpected_char(name, expr, ptr, ptr[0]);
@@ -893,6 +906,17 @@ const char* flecs_parse_term(
893906
term.id_flags = ECS_PAIR;
894907
}
895908

909+
if (ptr[0] == TOK_AND) {
910+
ptr = ecs_parse_ws(ptr + 1);
911+
ptr = flecs_parse_arguments(
912+
world, name, expr, (ptr - expr), ptr, token, NULL, extra_args);
913+
if (!ptr) {
914+
goto error;
915+
}
916+
} else {
917+
ptr ++;
918+
}
919+
896920
ptr = ecs_parse_ws(ptr);
897921
goto parse_done;
898922

@@ -930,7 +954,8 @@ char* ecs_parse_term(
930954
const char *name,
931955
const char *expr,
932956
const char *ptr,
933-
ecs_term_t *term)
957+
ecs_term_t *term,
958+
ecs_term_id_t *extra_args)
934959
{
935960
ecs_check(world != NULL, ECS_INVALID_PARAMETER, NULL);
936961
ecs_check(ptr != NULL, ECS_INVALID_PARAMETER, NULL);
@@ -966,7 +991,7 @@ char* ecs_parse_term(
966991
}
967992

968993
/* Parse next element */
969-
ptr = flecs_parse_term(world, name, ptr, term);
994+
ptr = flecs_parse_term(world, name, ptr, term, extra_args);
970995
if (!ptr) {
971996
goto error;
972997
}

src/addons/plecs.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1711,7 +1711,7 @@ const char *plecs_parse_plecs_term(
17111711
decl_id = state->last_predicate;
17121712
}
17131713

1714-
ptr = ecs_parse_term(world, name, expr, ptr, &term);
1714+
ptr = ecs_parse_term(world, name, expr, ptr, &term, NULL);
17151715
if (!ptr) {
17161716
return NULL;
17171717
}

src/entity.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1377,7 +1377,7 @@ ecs_table_t *flecs_traverse_from_expr(
13771377
const char *ptr = expr;
13781378
if (ptr) {
13791379
ecs_term_t term = {0};
1380-
while (ptr[0] && (ptr = ecs_parse_term(world, name, expr, ptr, &term))){
1380+
while (ptr[0] && (ptr = ecs_parse_term(world, name, expr, ptr, &term, NULL))){
13811381
if (!ecs_term_is_initialized(&term)) {
13821382
break;
13831383
}
@@ -1440,7 +1440,7 @@ void flecs_defer_from_expr(
14401440
const char *ptr = expr;
14411441
if (ptr) {
14421442
ecs_term_t term = {0};
1443-
while (ptr[0] && (ptr = ecs_parse_term(world, name, expr, ptr, &term))){
1443+
while (ptr[0] && (ptr = ecs_parse_term(world, name, expr, ptr, &term, NULL))) {
14441444
if (!ecs_term_is_initialized(&term)) {
14451445
break;
14461446
}

0 commit comments

Comments
 (0)