Implement evaluating container member access
This commit is contained in:
parent
0384875ef3
commit
721d2d2d21
3 changed files with 140 additions and 8 deletions
24
src/apfl.h
24
src/apfl.h
|
|
@ -508,15 +508,9 @@ enum apfl_value_type {
|
|||
struct apfl_list_data;
|
||||
typedef struct apfl_list_data *apfl_list;
|
||||
|
||||
apfl_list apfl_list_incref(apfl_list);
|
||||
void apfl_list_unref(apfl_list);
|
||||
|
||||
struct apfl_dict_data;
|
||||
typedef struct apfl_dict_data *apfl_dict;
|
||||
|
||||
apfl_dict apfl_dict_incref(apfl_dict);
|
||||
void apfl_dict_unref(apfl_dict);
|
||||
|
||||
struct apfl_value {
|
||||
enum apfl_value_type type;
|
||||
union {
|
||||
|
|
@ -528,12 +522,30 @@ struct apfl_value {
|
|||
};
|
||||
};
|
||||
|
||||
|
||||
bool apfl_value_eq(const struct apfl_value, const struct apfl_value);
|
||||
struct apfl_value apfl_value_move(struct apfl_value *src);
|
||||
struct apfl_value apfl_value_incref(struct apfl_value);
|
||||
void apfl_value_print(struct apfl_value, FILE *);
|
||||
void apfl_value_deinit(struct apfl_value *);
|
||||
|
||||
enum apfl_value_get_item_result {
|
||||
APFL_VALUE_GET_ITEM_OK,
|
||||
APFL_VALUE_GET_ITEM_KEY_DOESNT_EXIST,
|
||||
APFL_VALUE_GET_ITEM_NOT_A_CONTAINER,
|
||||
APFL_VALUE_GET_ITEM_WRONG_KEY_TYPE,
|
||||
};
|
||||
|
||||
enum apfl_value_get_item_result apfl_value_get_item(struct apfl_value container, struct apfl_value key, struct apfl_value *out);
|
||||
|
||||
apfl_list apfl_list_incref(apfl_list);
|
||||
bool apfl_list_get_item(apfl_list, size_t index, struct apfl_value *out);
|
||||
void apfl_list_unref(apfl_list);
|
||||
|
||||
apfl_dict apfl_dict_incref(apfl_dict);
|
||||
bool apfl_dict_get_item(apfl_dict, struct apfl_value key, struct apfl_value *out);
|
||||
void apfl_dict_unref(apfl_dict);
|
||||
|
||||
struct apfl_editable_list_data;
|
||||
typedef struct apfl_editable_list_data *apfl_editable_list;
|
||||
|
||||
|
|
|
|||
65
src/eval.c
65
src/eval.c
|
|
@ -209,6 +209,65 @@ evaluate_dict(apfl_ctx ctx, struct apfl_expr_dict *dict)
|
|||
};
|
||||
}
|
||||
|
||||
static struct apfl_result
|
||||
evaluate_dot(apfl_ctx ctx, struct apfl_expr_dot *dot)
|
||||
{
|
||||
struct apfl_result result;
|
||||
|
||||
result = evaluate(ctx, dot->lhs);
|
||||
if (result.type != APFL_RESULT_OK) {
|
||||
return result;
|
||||
}
|
||||
struct apfl_value lhs = result.value;
|
||||
|
||||
apfl_refcounted_string rcstring = apfl_string_move_into_new_refcounted(&dot->rhs);
|
||||
if (rcstring == NULL) {
|
||||
return fatal();
|
||||
}
|
||||
struct apfl_value key = (struct apfl_value) {
|
||||
.type = APFL_VALUE_STRING,
|
||||
.string = rcstring,
|
||||
};
|
||||
|
||||
struct apfl_value out;
|
||||
if (apfl_value_get_item(apfl_value_move(&lhs), apfl_value_move(&key), &out) == APFL_VALUE_GET_ITEM_OK) {
|
||||
return (struct apfl_result) {
|
||||
.type = APFL_RESULT_OK,
|
||||
.value = out,
|
||||
};
|
||||
} else {
|
||||
return (struct apfl_result) { .type = APFL_RESULT_ERR }; // TODO: Describe error
|
||||
}
|
||||
}
|
||||
|
||||
static struct apfl_result
|
||||
evaluate_at(apfl_ctx ctx, struct apfl_expr_at *at)
|
||||
{
|
||||
struct apfl_result result;
|
||||
|
||||
result = evaluate(ctx, at->lhs);
|
||||
if (result.type != APFL_RESULT_OK) {
|
||||
return result;
|
||||
}
|
||||
struct apfl_value lhs = result.value;
|
||||
|
||||
result = evaluate(ctx, at->rhs);
|
||||
if (result.type != APFL_RESULT_OK) {
|
||||
apfl_value_deinit(&lhs);
|
||||
return result;
|
||||
}
|
||||
struct apfl_value rhs = result.value;
|
||||
|
||||
struct apfl_value out;
|
||||
if (apfl_value_get_item(apfl_value_move(&lhs), apfl_value_move(&rhs), &out) == APFL_VALUE_GET_ITEM_OK) {
|
||||
return (struct apfl_result) {
|
||||
.type = APFL_RESULT_OK,
|
||||
.value = out,
|
||||
};
|
||||
} else {
|
||||
return (struct apfl_result) { .type = APFL_RESULT_ERR }; // TODO: Describe error
|
||||
}
|
||||
}
|
||||
|
||||
static struct apfl_result
|
||||
evaluate(apfl_ctx ctx, struct apfl_expr *expr)
|
||||
|
|
@ -220,13 +279,15 @@ evaluate(apfl_ctx ctx, struct apfl_expr *expr)
|
|||
return evaluate_list(ctx, &expr->list);
|
||||
case APFL_EXPR_DICT:
|
||||
return evaluate_dict(ctx, &expr->dict);
|
||||
case APFL_EXPR_DOT:
|
||||
return evaluate_dot(ctx, &expr->dot);
|
||||
case APFL_EXPR_AT:
|
||||
return evaluate_at(ctx, &expr->at);
|
||||
case APFL_EXPR_VAR:
|
||||
case APFL_EXPR_CALL:
|
||||
case APFL_EXPR_SIMPLE_FUNC:
|
||||
case APFL_EXPR_COMPLEX_FUNC:
|
||||
case APFL_EXPR_ASSIGNMENT:
|
||||
case APFL_EXPR_DOT:
|
||||
case APFL_EXPR_AT:
|
||||
break; // Not implemented yet
|
||||
}
|
||||
|
||||
|
|
|
|||
59
src/value.c
59
src/value.c
|
|
@ -601,6 +601,65 @@ ok:
|
|||
value->type = APFL_VALUE_NIL;
|
||||
}
|
||||
|
||||
bool
|
||||
apfl_list_get_item(apfl_list list, size_t index, struct apfl_value *out)
|
||||
{
|
||||
if (index >= list->len) {
|
||||
apfl_list_unref(list);
|
||||
return false;
|
||||
}
|
||||
|
||||
*out = apfl_value_incref(list->items[index]);
|
||||
apfl_list_unref(list);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
apfl_dict_get_item(apfl_dict dict, struct apfl_value key, struct apfl_value *out)
|
||||
{
|
||||
bool ok = apfl_hashmap_get(dict->map, &key, out);
|
||||
apfl_dict_unref(dict);
|
||||
apfl_value_deinit(&key);
|
||||
return ok;
|
||||
}
|
||||
|
||||
static enum apfl_value_get_item_result
|
||||
get_item(/*borrowed*/ struct apfl_value container, /*borrowed*/ struct apfl_value key, struct apfl_value *out)
|
||||
{
|
||||
if (container.type == APFL_VALUE_LIST) {
|
||||
if (key.type != APFL_VALUE_NUMBER) {
|
||||
return APFL_VALUE_GET_ITEM_WRONG_KEY_TYPE;
|
||||
}
|
||||
|
||||
return apfl_list_get_item(
|
||||
apfl_list_incref(container.list),
|
||||
(size_t)key.number,
|
||||
out
|
||||
)
|
||||
? APFL_VALUE_GET_ITEM_OK
|
||||
: APFL_VALUE_GET_ITEM_KEY_DOESNT_EXIST;
|
||||
} else if (container.type == APFL_VALUE_DICT) {
|
||||
return apfl_dict_get_item(
|
||||
apfl_dict_incref(container.dict),
|
||||
apfl_value_incref(key),
|
||||
out
|
||||
)
|
||||
? APFL_VALUE_GET_ITEM_OK
|
||||
: APFL_VALUE_GET_ITEM_KEY_DOESNT_EXIST;
|
||||
} else {
|
||||
return APFL_VALUE_GET_ITEM_NOT_A_CONTAINER;
|
||||
}
|
||||
}
|
||||
|
||||
enum apfl_value_get_item_result
|
||||
apfl_value_get_item(struct apfl_value container, struct apfl_value key, struct apfl_value *out)
|
||||
{
|
||||
enum apfl_value_get_item_result result = get_item(container, key, out);
|
||||
apfl_value_deinit(&container);
|
||||
apfl_value_deinit(&key);
|
||||
return result;
|
||||
}
|
||||
|
||||
static apfl_hash
|
||||
value_hash(const struct apfl_value value)
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in a new issue