Skip to content

Commit

Permalink
Add query DSL feature that expands R(S, T, Q) into R(S, T), R(T, Q)
Browse files Browse the repository at this point in the history
  • Loading branch information
SanderMertens committed Oct 10, 2023
1 parent 78305c4 commit fd595ba
Show file tree
Hide file tree
Showing 10 changed files with 350 additions and 40 deletions.
88 changes: 70 additions & 18 deletions flecs.c
Original file line number Diff line number Diff line change
Expand Up @@ -4746,7 +4746,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))){
while (ptr[0] && (ptr = ecs_parse_term(world, name, expr, ptr, &term, NULL))){
if (!ecs_term_is_initialized(&term)) {
break;
}
Expand Down Expand Up @@ -4809,7 +4809,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))){
while (ptr[0] && (ptr = ecs_parse_term(world, name, expr, ptr, &term, NULL))) {
if (!ecs_term_is_initialized(&term)) {
break;
}
Expand Down Expand Up @@ -11053,23 +11053,50 @@ ecs_filter_t* ecs_filter_init(
const char *name = NULL;
const char *ptr = desc->expr;
ecs_term_t term = {0};
ecs_term_id_t extra_args[ECS_PARSER_MAX_ARGS];
int32_t expr_size = 0;

ecs_os_zeromem(extra_args);

if (entity) {
name = ecs_get_name(world, entity);
}

while (ptr[0] && (ptr = ecs_parse_term(world, name, expr, ptr, &term))){
while (ptr[0] &&
(ptr = ecs_parse_term(world, name, expr, ptr, &term, extra_args)))
{
if (!ecs_term_is_initialized(&term)) {
break;
}

if (expr_count == expr_size) {
expr_size = expr_size ? expr_size * 2 : 8;
expr_terms = ecs_os_realloc_n(expr_terms, ecs_term_t, expr_size);
}
int32_t arg = 0;

do {
ecs_assert(arg <= ECS_PARSER_MAX_ARGS, ECS_INTERNAL_ERROR, NULL);

if (expr_count == expr_size) {
expr_size = expr_size ? expr_size * 2 : 8;
expr_terms = ecs_os_realloc_n(expr_terms, ecs_term_t, expr_size);
}

ecs_term_t *expr_term = &expr_terms[expr_count ++];
*expr_term = term;

if (arg) {
expr_term->src = expr_term[-1].second;
expr_term->second = extra_args[arg - 1];

if (expr_term->first.name != NULL) {
expr_term->first.name = ecs_os_strdup(
expr_term->first.name);
}
if (expr_term->src.name != NULL) {
expr_term->src.name = ecs_os_strdup(
expr_term->src.name);
}
}
} while (ecs_term_id_is_set(&extra_args[arg ++]));

expr_terms[expr_count ++] = term;
if (ptr[0] == '\n') {
break;
}
Expand Down Expand Up @@ -30577,15 +30604,24 @@ const char* flecs_parse_arguments(
int64_t column,
const char *ptr,
char *token,
ecs_term_t *term)
ecs_term_t *term,
ecs_term_id_t *extra_args)
{
(void)column;

int32_t arg = 0;

if (extra_args) {
ecs_os_memset_n(extra_args, 0, ecs_term_id_t, ECS_PARSER_MAX_ARGS);
}

if (!term) {
arg = 2;
}

do {
if (flecs_valid_token_start_char(ptr[0])) {
if (arg == 2) {
if ((arg == ECS_PARSER_MAX_ARGS) || (!extra_args && arg == 2)) {
ecs_parser_error(name, expr, (ptr - expr),
"too many arguments in term");
return NULL;
Expand All @@ -30602,6 +30638,8 @@ const char* flecs_parse_arguments(
term_id = &term->src;
} else if (arg == 1) {
term_id = &term->second;
} else {
term_id = &extra_args[arg - 2];
}

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

term->id_flags = ECS_PAIR;
if (term) {
term->id_flags = ECS_PAIR;
}

} else if (ptr[0] == TOK_PAREN_CLOSE) {
ptr = ecs_parse_ws(ptr + 1);
Expand Down Expand Up @@ -30689,7 +30729,8 @@ const char* flecs_parse_term(
const ecs_world_t *world,
const char *name,
const char *expr,
ecs_term_t *term_out)
ecs_term_t *term_out,
ecs_term_id_t *extra_args)
{
const char *ptr = expr;
char token[ECS_MAX_TOKEN_SIZE] = {0};
Expand Down Expand Up @@ -30837,7 +30878,7 @@ const char* flecs_parse_term(
ptr = ecs_parse_ws(ptr);
} else {
ptr = flecs_parse_arguments(
world, name, expr, (ptr - expr), ptr, token, &term);
world, name, expr, (ptr - expr), ptr, token, &term, extra_args);
}

goto parse_done;
Expand Down Expand Up @@ -30955,8 +30996,7 @@ const char* flecs_parse_term(
}
}

if (ptr[0] == TOK_PAREN_CLOSE) {
ptr ++;
if (ptr[0] == TOK_PAREN_CLOSE || ptr[0] == TOK_AND) {
goto parse_pair_object;
} else {
flecs_parser_unexpected_char(name, expr, ptr, ptr[0]);
Expand All @@ -30983,6 +31023,17 @@ const char* flecs_parse_term(
term.id_flags = ECS_PAIR;
}

if (ptr[0] == TOK_AND) {
ptr = ecs_parse_ws(ptr + 1);
ptr = flecs_parse_arguments(
world, name, expr, (ptr - expr), ptr, token, NULL, extra_args);
if (!ptr) {
goto error;
}
} else {
ptr ++;
}

ptr = ecs_parse_ws(ptr);
goto parse_done;

Expand Down Expand Up @@ -31020,7 +31071,8 @@ char* ecs_parse_term(
const char *name,
const char *expr,
const char *ptr,
ecs_term_t *term)
ecs_term_t *term,
ecs_term_id_t *extra_args)
{
ecs_check(world != NULL, ECS_INVALID_PARAMETER, NULL);
ecs_check(ptr != NULL, ECS_INVALID_PARAMETER, NULL);
Expand Down Expand Up @@ -31056,7 +31108,7 @@ char* ecs_parse_term(
}

/* Parse next element */
ptr = flecs_parse_term(world, name, ptr, term);
ptr = flecs_parse_term(world, name, ptr, term, extra_args);
if (!ptr) {
goto error;
}
Expand Down Expand Up @@ -32887,7 +32939,7 @@ const char *plecs_parse_plecs_term(
decl_id = state->last_predicate;
}

ptr = ecs_parse_term(world, name, expr, ptr, &term);
ptr = ecs_parse_term(world, name, expr, ptr, &term, NULL);
if (!ptr) {
return NULL;
}
Expand Down
7 changes: 6 additions & 1 deletion flecs.h
Original file line number Diff line number Diff line change
Expand Up @@ -15267,6 +15267,9 @@ void ecs_snapshot_free(
#ifndef FLECS_PARSER_H
#define FLECS_PARSER_H

/** Maximum number of extra arguments in term expression */
#define ECS_PARSER_MAX_ARGS (16)

#ifdef __cplusplus
extern "C" {
#endif
Expand Down Expand Up @@ -15353,6 +15356,7 @@ const char* ecs_parse_token(
* @param expr The expression to parse (optional, improves error logs)
* @param ptr The pointer to the current term (must be in expr).
* @param term_out Out parameter for the term.
* @param extra_args Out array for extra args, must be of size ECS_PARSER_MAX_ARGS.
* @return pointer to next term if successful, NULL if failed.
*/
FLECS_API
Expand All @@ -15361,7 +15365,8 @@ char* ecs_parse_term(
const char *name,
const char *expr,
const char *ptr,
ecs_term_t *term_out);
ecs_term_t *term_out,
ecs_term_id_t *extra_args);

#ifdef __cplusplus
}
Expand Down
7 changes: 6 additions & 1 deletion include/flecs/addons/parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@
#ifndef FLECS_PARSER_H
#define FLECS_PARSER_H

/** Maximum number of extra arguments in term expression */
#define ECS_PARSER_MAX_ARGS (16)

#ifdef __cplusplus
extern "C" {
#endif
Expand Down Expand Up @@ -105,6 +108,7 @@ const char* ecs_parse_token(
* @param expr The expression to parse (optional, improves error logs)
* @param ptr The pointer to the current term (must be in expr).
* @param term_out Out parameter for the term.
* @param extra_args Out array for extra args, must be of size ECS_PARSER_MAX_ARGS.
* @return pointer to next term if successful, NULL if failed.
*/
FLECS_API
Expand All @@ -113,7 +117,8 @@ char* ecs_parse_term(
const char *name,
const char *expr,
const char *ptr,
ecs_term_t *term_out);
ecs_term_t *term_out,
ecs_term_id_t *extra_args);

#ifdef __cplusplus
}
Expand Down
43 changes: 34 additions & 9 deletions src/addons/parser.c
Original file line number Diff line number Diff line change
Expand Up @@ -487,15 +487,24 @@ const char* flecs_parse_arguments(
int64_t column,
const char *ptr,
char *token,
ecs_term_t *term)
ecs_term_t *term,
ecs_term_id_t *extra_args)
{
(void)column;

int32_t arg = 0;

if (extra_args) {
ecs_os_memset_n(extra_args, 0, ecs_term_id_t, ECS_PARSER_MAX_ARGS);
}

if (!term) {
arg = 2;
}

do {
if (flecs_valid_token_start_char(ptr[0])) {
if (arg == 2) {
if ((arg == ECS_PARSER_MAX_ARGS) || (!extra_args && arg == 2)) {
ecs_parser_error(name, expr, (ptr - expr),
"too many arguments in term");
return NULL;
Expand All @@ -512,6 +521,8 @@ const char* flecs_parse_arguments(
term_id = &term->src;
} else if (arg == 1) {
term_id = &term->second;
} else {
term_id = &extra_args[arg - 2];
}

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

term->id_flags = ECS_PAIR;
if (term) {
term->id_flags = ECS_PAIR;
}

} else if (ptr[0] == TOK_PAREN_CLOSE) {
ptr = ecs_parse_ws(ptr + 1);
Expand Down Expand Up @@ -599,7 +612,8 @@ const char* flecs_parse_term(
const ecs_world_t *world,
const char *name,
const char *expr,
ecs_term_t *term_out)
ecs_term_t *term_out,
ecs_term_id_t *extra_args)
{
const char *ptr = expr;
char token[ECS_MAX_TOKEN_SIZE] = {0};
Expand Down Expand Up @@ -747,7 +761,7 @@ const char* flecs_parse_term(
ptr = ecs_parse_ws(ptr);
} else {
ptr = flecs_parse_arguments(
world, name, expr, (ptr - expr), ptr, token, &term);
world, name, expr, (ptr - expr), ptr, token, &term, extra_args);
}

goto parse_done;
Expand Down Expand Up @@ -865,8 +879,7 @@ const char* flecs_parse_term(
}
}

if (ptr[0] == TOK_PAREN_CLOSE) {
ptr ++;
if (ptr[0] == TOK_PAREN_CLOSE || ptr[0] == TOK_AND) {
goto parse_pair_object;
} else {
flecs_parser_unexpected_char(name, expr, ptr, ptr[0]);
Expand All @@ -893,6 +906,17 @@ const char* flecs_parse_term(
term.id_flags = ECS_PAIR;
}

if (ptr[0] == TOK_AND) {
ptr = ecs_parse_ws(ptr + 1);
ptr = flecs_parse_arguments(
world, name, expr, (ptr - expr), ptr, token, NULL, extra_args);
if (!ptr) {
goto error;
}
} else {
ptr ++;
}

ptr = ecs_parse_ws(ptr);
goto parse_done;

Expand Down Expand Up @@ -930,7 +954,8 @@ char* ecs_parse_term(
const char *name,
const char *expr,
const char *ptr,
ecs_term_t *term)
ecs_term_t *term,
ecs_term_id_t *extra_args)
{
ecs_check(world != NULL, ECS_INVALID_PARAMETER, NULL);
ecs_check(ptr != NULL, ECS_INVALID_PARAMETER, NULL);
Expand Down Expand Up @@ -966,7 +991,7 @@ char* ecs_parse_term(
}

/* Parse next element */
ptr = flecs_parse_term(world, name, ptr, term);
ptr = flecs_parse_term(world, name, ptr, term, extra_args);
if (!ptr) {
goto error;
}
Expand Down
2 changes: 1 addition & 1 deletion src/addons/plecs.c
Original file line number Diff line number Diff line change
Expand Up @@ -1711,7 +1711,7 @@ const char *plecs_parse_plecs_term(
decl_id = state->last_predicate;
}

ptr = ecs_parse_term(world, name, expr, ptr, &term);
ptr = ecs_parse_term(world, name, expr, ptr, &term, NULL);
if (!ptr) {
return NULL;
}
Expand Down
4 changes: 2 additions & 2 deletions src/entity.c
Original file line number Diff line number Diff line change
Expand Up @@ -1377,7 +1377,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))){
while (ptr[0] && (ptr = ecs_parse_term(world, name, expr, ptr, &term, NULL))){
if (!ecs_term_is_initialized(&term)) {
break;
}
Expand Down Expand Up @@ -1440,7 +1440,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))){
while (ptr[0] && (ptr = ecs_parse_term(world, name, expr, ptr, &term, NULL))) {
if (!ecs_term_is_initialized(&term)) {
break;
}
Expand Down
Loading

0 comments on commit fd595ba

Please sign in to comment.