[util] Add plist support to cexpr

This allows plist objects to be accessed directly from cexpr expressions
using struct.field syntax for dictionary objects and array[index] syntax
for array objects.
This commit is contained in:
Bill Currie 2021-02-04 16:58:13 +09:00
parent 846fcc276c
commit d2536e584f
3 changed files with 114 additions and 0 deletions

View file

@ -132,6 +132,7 @@ extern exprtype_t cexpr_quaternion;
extern exprtype_t cexpr_exprval;
extern exprtype_t cexpr_field;
extern exprtype_t cexpr_function;
extern exprtype_t cexpr_plitem;
extern binop_t cexpr_struct_binops[];
extern binop_t cexpr_struct_pointer_binops[];

View file

@ -56,6 +56,8 @@ static exprval_t *binary_expr (int op, const exprval_t *a, const exprval_t *b,
exprctx_t *context);
static exprval_t *field_expr (const exprval_t *a, const exprval_t *b,
exprctx_t *context);
static exprval_t *index_expr (const exprval_t *a, const exprval_t *b,
exprctx_t *context);
static exprval_t *unary_expr (int op, const exprval_t *val,
exprctx_t *context);
static exprval_t *vector_expr (exprlist_t *list, exprctx_t *context);
@ -126,6 +128,7 @@ uexpr
| '(' expr ')' { $$ = $2; }
| NAME '(' opt_arg_list ')' { $$ = function_expr ($1, $3, context); }
| uexpr '.' field { $$ = field_expr ($1, $3, context); }
| uexpr '[' field ']' { $$ = index_expr ($1, $3, context); }
| '+' uexpr %prec UNARY { $$ = $2; }
| '-' uexpr %prec UNARY { $$ = unary_expr ('-', $2, context); }
| '!' uexpr %prec UNARY { $$ = unary_expr ('!', $2, context); }
@ -237,6 +240,10 @@ field_expr (const exprval_t *a, const exprval_t *b, exprctx_t *context)
binop_t *binop;
exprval_t *result = 0;
if (!a) {
return 0;
}
for (binop = a->type->binops; binop->op; binop++) {
if (binop->op == '.' && binop->other == b->type) {
break;
@ -254,6 +261,29 @@ field_expr (const exprval_t *a, const exprval_t *b, exprctx_t *context)
return result;
}
static exprval_t *
index_expr (const exprval_t *a, const exprval_t *b, exprctx_t *context)
{
binop_t *binop;
exprval_t *result = 0;
for (binop = a->type->binops; binop->op; binop++) {
if (binop->op == '[' && binop->other == b->type) {
break;
}
}
if (!binop->op) {
cexpr_error (context, "invalid index expression: %s.%s",
a->type->name, b->type->name);
result = cexpr_value (&cexpr_int, context);
*(int *) result->value = 0;
} else {
exprval_t c = { 0, &result };
binop->func (a, b, &c, context);
}
return result;
}
static exprval_t *
unary_expr (int op, const exprval_t *val, exprctx_t *context)
{

View file

@ -30,6 +30,7 @@
#include <math.h>
#include "QF/cexpr.h"
#include "QF/cmem.h"
#include "QF/mathlib.h"
#include "QF/qfplist.h"
#include "QF/simd/vec4f.h"
@ -594,6 +595,88 @@ exprtype_t cexpr_function = {
0,
};
static void
plitem_field (const exprval_t *a, const exprval_t *b, exprval_t *c,
exprctx_t *ctx)
{
__auto_type dict = *(plitem_t **) a->value;
__auto_type key = (const char *) b->value;
if (PL_Type (dict) != QFDictionary) {
cexpr_error(ctx, "not a dictionary object");
return;
}
plitem_t *item = PL_ObjectForKey (dict, key);
exprval_t *val = 0;
if (!item) {
cexpr_error (ctx, "key not found: %s", key);
} else {
val = cexpr_value (&cexpr_plitem, ctx);
*(plitem_t **) val->value = item;
}
*(exprval_t **) c->value = val;
}
static void
plitem_index (const exprval_t *a, int index, exprval_t *c,
exprctx_t *ctx)
{
__auto_type array = *(plitem_t **) a->type->data;
if (PL_Type (array) != QFArray) {
cexpr_error(ctx, "not an array object");
return;
}
plitem_t *item = PL_ObjectAtIndex (array, index);
exprval_t *val = 0;
if (!item) {
cexpr_error (ctx, "invalid index: %d", index);
} else {
val = cexpr_value (&cexpr_plitem, ctx);
*(plitem_t **) val->value = item;
}
*(exprval_t **) c->value = val;
}
static void
plitem_int (const exprval_t *a, const exprval_t *b, exprval_t *c,
exprctx_t *ctx)
{
int index = *(int *) a->value;
plitem_index (a, index, c, ctx);
}
static void
plitem_uint (const exprval_t *a, const exprval_t *b, exprval_t *c,
exprctx_t *ctx)
{
int index = *(int *) a->value;
plitem_index (a, index, c, ctx);
}
static void
plitem_size_t (const exprval_t *a, const exprval_t *b, exprval_t *c,
exprctx_t *ctx)
{
int index = *(int *) a->value;
plitem_index (a, index, c, ctx);
}
binop_t plitem_binops[] = {
{ '.', &cexpr_field, &cexpr_plitem, plitem_field },
{ '[', &cexpr_int, &cexpr_plitem, plitem_int },
{ '[', &cexpr_uint, &cexpr_plitem, plitem_uint },
{ '[', &cexpr_size_t, &cexpr_plitem, plitem_size_t },
{}
};
exprtype_t cexpr_plitem = {
"plitem",
sizeof (plitem_t *),
plitem_binops,
0,
};
VISIBLE binop_t *
cexpr_find_cast (exprtype_t *dst_type, exprtype_t *src_type)
{