diff --git a/include/QF/cexpr.h b/include/QF/cexpr.h index 7fa1e04fc..149c320e2 100644 --- a/include/QF/cexpr.h +++ b/include/QF/cexpr.h @@ -87,6 +87,11 @@ typedef struct exprtab_s { struct hashtab_s *tab; } exprtab_t; +typedef struct exprarray_s { + exprtype_t *type; + unsigned size; +} exprarray_t; + typedef struct exprctx_s { exprval_t *result; exprtab_t *symtab; // directly accessible symbols @@ -111,6 +116,8 @@ exprval_t *cexpr_value_reference (exprtype_t *type, void *data, exprctx_t *ctx); int cexpr_eval_string (const char *str, exprctx_t *context); void cexpr_error(exprctx_t *ctx, const char *fmt, ...) __attribute__((format(PRINTF,2,3))); +void cexpr_array_getelement (const exprval_t *a, const exprval_t *b, + exprval_t *c, exprctx_t *ctx); void cexpr_struct_getfield (const exprval_t *a, const exprval_t *b, exprval_t *c, exprctx_t *ctx); void cexpr_struct_pointer_getfield (const exprval_t *a, const exprval_t *b, @@ -137,6 +144,7 @@ extern exprtype_t cexpr_field; extern exprtype_t cexpr_function; extern exprtype_t cexpr_plitem; +extern binop_t cexpr_array_binops[]; extern binop_t cexpr_struct_binops[]; extern binop_t cexpr_struct_pointer_binops[]; diff --git a/libs/util/cexpr-vars.c b/libs/util/cexpr-vars.c index 9b390b523..ec152a00e 100644 --- a/libs/util/cexpr-vars.c +++ b/libs/util/cexpr-vars.c @@ -37,6 +37,29 @@ #include "libs/util/cexpr-parse.h" +VISIBLE void +cexpr_array_getelement (const exprval_t *a, const exprval_t *b, exprval_t *c, + exprctx_t *ctx) +{ + __auto_type array = (exprarray_t *) a->type->data; + unsigned index = *(const unsigned *) b->value; + exprval_t *val = 0; + if (index < array->size) { + val = cmemalloc (ctx->memsuper, sizeof (exprval_t)); + val->type = array->type; + val->value = a->value + array->type->size * index; + } else { + cexpr_error (ctx, "index %d out of bounds for %s", index, + a->type->name); + } + *(exprval_t **) c->value = val; +} + +VISIBLE binop_t cexpr_array_binops[] = { + { '[', &cexpr_int, &cexpr_exprval, cexpr_array_getelement }, + {} +}; + VISIBLE void cexpr_struct_getfield (const exprval_t *a, const exprval_t *b, exprval_t *c, exprctx_t *ctx) diff --git a/libs/util/test/test-cexpr.c b/libs/util/test/test-cexpr.c index a87adaeff..ae1aaaa25 100644 --- a/libs/util/test/test-cexpr.c +++ b/libs/util/test/test-cexpr.c @@ -32,17 +32,31 @@ #include "QF/cmem.h" #include "QF/hash.h" #include "QF/mathlib.h" +#include "QF/va.h" #include "QF/simd/vec4f.h" int a = 5; int b = 6; int c; +int array[4] = { 9, 16, 25, 36 }; vec4f_t point = { 2, 3, 4, 1 }; // a point, so w = 1 vec4f_t normal = { 1, 2, 3, 0 }; // a vector, so w = 0 vec4f_t direction = { 4, 5, 6, 0 }; // a vector, so w = 0 vec4f_t plane; vec4f_t intercept; +exprarray_t int_array_4_data = { + &cexpr_int, + sizeof (array) / sizeof (array[0]), +}; +exprtype_t int_array_4 = { + "int[4]", + 4 * sizeof (int), + cexpr_array_binops, + 0, + &int_array_4_data, +}; + exprtype_t *vector_params[] = { &cexpr_vector, &cexpr_vector, @@ -117,6 +131,7 @@ exprfunc_t double_func[] = { exprsym_t symbols[] = { { "a", &cexpr_int, &a }, { "b", &cexpr_int, &b }, + { "array", &int_array_4, &array }, { "point", &cexpr_vector, &point }, { "normal", &cexpr_vector, &normal }, { "plane", &cexpr_vector, &plane }, @@ -147,6 +162,7 @@ exprctx_t context = { &test_result, &symtab }; #define TEST_BINOP(op) \ do { \ c = -4096; \ + context.result = &test_result; \ cexpr_eval_string ("a " #op " b", &context); \ printf ("c = a %s b -> %d = %d %s %d\n", #op, c, a, #op, b); \ if (c != (a op b)) { \ @@ -154,6 +170,17 @@ exprctx_t context = { &test_result, &symtab }; } \ } while (0) +#define TEST_ARRAY(ind) \ + do { \ + c = -4096; \ + context.result = &test_result; \ + cexpr_eval_string (va (0, "array[%d]", ind), &context); \ + printf ("c = array[%d] -> %d = %d\n", ind, c, array[ind]); \ + if (c != array[ind]) { \ + ret |= 1; \ + } \ + } while (0) + int main(int argc, const char **argv) { @@ -173,6 +200,11 @@ main(int argc, const char **argv) TEST_BINOP (^); TEST_BINOP (%); + TEST_ARRAY (0); + TEST_ARRAY (1); + TEST_ARRAY (2); + TEST_ARRAY (3); + context.result = &plane_result; cexpr_eval_string ("point.wzyx", &context); if (plane[0] != point[3] || plane[1] != point[2]