Skip to content

Commit 754e5ce

Browse files
[json] Add support for deserializing array element expressions (#2031)
1 parent e2751ab commit 754e5ce

File tree

5 files changed

+277
-28
lines changed

5 files changed

+277
-28
lines changed

distr/flecs.c

Lines changed: 98 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -55737,6 +55737,7 @@ int ecs_meta_from_desc(
5573755737
* @brief API for reading and assigning values of runtime types with reflection.
5573855738
*/
5573955739

55740+
#include <ctype.h>
5574055741
#include <inttypes.h>
5574155742

5574255743
#ifdef FLECS_META
@@ -56159,7 +56160,7 @@ const char* flecs_meta_parse_member(
5615956160
const char *ptr;
5616056161
char ch;
5616156162
for (ptr = start; (ch = *ptr); ptr ++) {
56162-
if (ch == '.') {
56163+
if (ch == '.' || ch == '[') {
5616356164
break;
5616456165
}
5616556166
}
@@ -56171,11 +56172,47 @@ const char* flecs_meta_parse_member(
5617156172

5617256173
ecs_os_memcpy(token_out, start, len);
5617356174
token_out[len] = '\0';
56174-
if (ch == '.') {
56175+
56176+
return ptr;
56177+
}
56178+
56179+
static
56180+
const char* flecs_meta_parse_elem(
56181+
const char *start,
56182+
int32_t *elem_out)
56183+
{
56184+
if (start[0] != '[') {
56185+
ecs_err("expected '[' in member expression");
56186+
return NULL;
56187+
}
56188+
56189+
start ++;
56190+
if (!isdigit((unsigned char)start[0])) {
56191+
ecs_err("expected array index in member expression");
56192+
return NULL;
56193+
}
56194+
56195+
int32_t elem = 0;
56196+
const char *ptr = start;
56197+
char ch;
56198+
while ((ch = ptr[0]) && ch != ']') {
56199+
if (!isdigit((unsigned char)ch)) {
56200+
ecs_err("invalid array index in member expression");
56201+
return NULL;
56202+
}
56203+
56204+
elem *= 10;
56205+
elem += ch - '0';
5617556206
ptr ++;
5617656207
}
5617756208

56178-
return ptr;
56209+
if (ptr[0] != ']') {
56210+
ecs_err("missing ']' in member expression");
56211+
return NULL;
56212+
}
56213+
56214+
elem_out[0] = elem;
56215+
return ptr + 1;
5617956216
}
5618056217

5618156218
static
@@ -56188,33 +56225,68 @@ int flecs_meta_dotmember(
5618856225
flecs_cursor_restore_scope(cursor, cur_scope);
5618956226

5619056227
int16_t prev_depth = cursor->depth;
56191-
int dotcount = 0;
56228+
bool moved = false;
5619256229

5619356230
char token[ECS_MAX_TOKEN_SIZE];
5619456231
const char *ptr = name;
56195-
while ((ptr = flecs_meta_parse_member(ptr, token))) {
56196-
if (dotcount) {
56197-
ecs_meta_push(cursor);
56232+
while (ptr[0]) {
56233+
if (ptr[0] != '[') {
56234+
ptr = flecs_meta_parse_member(ptr, token);
56235+
if (!ptr) {
56236+
goto error;
56237+
}
56238+
56239+
if (moved) {
56240+
if (ecs_meta_push(cursor) != 0) {
56241+
goto error;
56242+
}
56243+
}
56244+
56245+
if (flecs_meta_member(cursor, token, try)) {
56246+
goto error;
56247+
}
56248+
56249+
moved = true;
5619856250
}
5619956251

56200-
if (flecs_meta_member(cursor, token, try)) {
56201-
goto error;
56252+
while (ptr[0] == '[') {
56253+
int32_t elem;
56254+
56255+
if (ecs_meta_push(cursor) != 0) {
56256+
goto error;
56257+
}
56258+
56259+
ptr = flecs_meta_parse_elem(ptr, &elem);
56260+
if (!ptr) {
56261+
goto error;
56262+
}
56263+
56264+
if (ecs_meta_elem(cursor, elem) != 0) {
56265+
goto error;
56266+
}
56267+
56268+
moved = true;
5620256269
}
5620356270

56204-
if (!ptr[0]) {
56205-
break;
56271+
if (ptr[0] == '.') {
56272+
ptr ++;
56273+
continue;
5620656274
}
5620756275

56208-
dotcount ++;
56276+
if (ptr[0] != '\0') {
56277+
ecs_err("invalid token '%c' in member expression", ptr[0]);
56278+
goto error;
56279+
}
5620956280
}
5621056281

5621156282
cur_scope = flecs_cursor_get_scope(cursor);
56212-
if (dotcount) {
56283+
if (moved && (cursor->depth != prev_depth)) {
5621356284
cur_scope->prev_depth = prev_depth;
5621456285
}
5621556286

5621656287
return 0;
5621756288
error:
56289+
cursor->depth = prev_depth;
5621856290
return -1;
5621956291
}
5622056292

@@ -56426,6 +56498,19 @@ bool ecs_meta_is_collection(
5642656498
const ecs_meta_cursor_t *cursor)
5642756499
{
5642856500
ecs_meta_scope_t *scope = flecs_cursor_get_scope(cursor);
56501+
56502+
/* If the scope was reached through dotmember with array indexing, the
56503+
* current scope can still be the collection that contains the selected
56504+
* element. In that case, report whether the selected element is a
56505+
* collection, not whether its parent container is. */
56506+
if (scope->prev_depth && scope->is_collection) {
56507+
ecs_meta_op_t *op = flecs_cursor_get_op(scope);
56508+
return op->kind == EcsOpPushArray ||
56509+
op->kind == EcsOpPushVector ||
56510+
op->kind == EcsOpOpaqueArray ||
56511+
op->kind == EcsOpOpaqueVector;
56512+
}
56513+
5642956514
return scope->is_collection;
5643056515
}
5643156516

src/addons/meta/cursor.c

Lines changed: 98 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
*/
55

66
#include "meta.h"
7+
#include <ctype.h>
78
#include <inttypes.h>
89

910
#ifdef FLECS_META
@@ -427,7 +428,7 @@ const char* flecs_meta_parse_member(
427428
const char *ptr;
428429
char ch;
429430
for (ptr = start; (ch = *ptr); ptr ++) {
430-
if (ch == '.') {
431+
if (ch == '.' || ch == '[') {
431432
break;
432433
}
433434
}
@@ -439,11 +440,47 @@ const char* flecs_meta_parse_member(
439440

440441
ecs_os_memcpy(token_out, start, len);
441442
token_out[len] = '\0';
442-
if (ch == '.') {
443+
444+
return ptr;
445+
}
446+
447+
static
448+
const char* flecs_meta_parse_elem(
449+
const char *start,
450+
int32_t *elem_out)
451+
{
452+
if (start[0] != '[') {
453+
ecs_err("expected '[' in member expression");
454+
return NULL;
455+
}
456+
457+
start ++;
458+
if (!isdigit((unsigned char)start[0])) {
459+
ecs_err("expected array index in member expression");
460+
return NULL;
461+
}
462+
463+
int32_t elem = 0;
464+
const char *ptr = start;
465+
char ch;
466+
while ((ch = ptr[0]) && ch != ']') {
467+
if (!isdigit((unsigned char)ch)) {
468+
ecs_err("invalid array index in member expression");
469+
return NULL;
470+
}
471+
472+
elem *= 10;
473+
elem += ch - '0';
443474
ptr ++;
444475
}
445476

446-
return ptr;
477+
if (ptr[0] != ']') {
478+
ecs_err("missing ']' in member expression");
479+
return NULL;
480+
}
481+
482+
elem_out[0] = elem;
483+
return ptr + 1;
447484
}
448485

449486
static
@@ -456,33 +493,68 @@ int flecs_meta_dotmember(
456493
flecs_cursor_restore_scope(cursor, cur_scope);
457494

458495
int16_t prev_depth = cursor->depth;
459-
int dotcount = 0;
496+
bool moved = false;
460497

461498
char token[ECS_MAX_TOKEN_SIZE];
462499
const char *ptr = name;
463-
while ((ptr = flecs_meta_parse_member(ptr, token))) {
464-
if (dotcount) {
465-
ecs_meta_push(cursor);
500+
while (ptr[0]) {
501+
if (ptr[0] != '[') {
502+
ptr = flecs_meta_parse_member(ptr, token);
503+
if (!ptr) {
504+
goto error;
505+
}
506+
507+
if (moved) {
508+
if (ecs_meta_push(cursor) != 0) {
509+
goto error;
510+
}
511+
}
512+
513+
if (flecs_meta_member(cursor, token, try)) {
514+
goto error;
515+
}
516+
517+
moved = true;
466518
}
467519

468-
if (flecs_meta_member(cursor, token, try)) {
469-
goto error;
520+
while (ptr[0] == '[') {
521+
int32_t elem;
522+
523+
if (ecs_meta_push(cursor) != 0) {
524+
goto error;
525+
}
526+
527+
ptr = flecs_meta_parse_elem(ptr, &elem);
528+
if (!ptr) {
529+
goto error;
530+
}
531+
532+
if (ecs_meta_elem(cursor, elem) != 0) {
533+
goto error;
534+
}
535+
536+
moved = true;
470537
}
471538

472-
if (!ptr[0]) {
473-
break;
539+
if (ptr[0] == '.') {
540+
ptr ++;
541+
continue;
474542
}
475543

476-
dotcount ++;
544+
if (ptr[0] != '\0') {
545+
ecs_err("invalid token '%c' in member expression", ptr[0]);
546+
goto error;
547+
}
477548
}
478549

479550
cur_scope = flecs_cursor_get_scope(cursor);
480-
if (dotcount) {
551+
if (moved && (cursor->depth != prev_depth)) {
481552
cur_scope->prev_depth = prev_depth;
482553
}
483554

484555
return 0;
485556
error:
557+
cursor->depth = prev_depth;
486558
return -1;
487559
}
488560

@@ -694,6 +766,19 @@ bool ecs_meta_is_collection(
694766
const ecs_meta_cursor_t *cursor)
695767
{
696768
ecs_meta_scope_t *scope = flecs_cursor_get_scope(cursor);
769+
770+
/* If the scope was reached through dotmember with array indexing, the
771+
* current scope can still be the collection that contains the selected
772+
* element. In that case, report whether the selected element is a
773+
* collection, not whether its parent container is. */
774+
if (scope->prev_depth && scope->is_collection) {
775+
ecs_meta_op_t *op = flecs_cursor_get_op(scope);
776+
return op->kind == EcsOpPushArray ||
777+
op->kind == EcsOpPushVector ||
778+
op->kind == EcsOpOpaqueArray ||
779+
op->kind == EcsOpOpaqueVector;
780+
}
781+
697782
return scope->is_collection;
698783
}
699784

test/meta/project.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -561,6 +561,8 @@
561561
"struct_struct_i32_i32_array_3",
562562
"struct_w_array_type_i32_i32",
563563
"struct_w_2_array_type_i32_i32",
564+
"struct_w_array_member_i32",
565+
"struct_w_array_member_struct",
564566
"struct_w_nested_member_i32",
565567
"struct_w_2_nested_members_i32",
566568
"struct_w_nested_members_struct",

0 commit comments

Comments
 (0)