diff --git a/src/apfl.h b/src/apfl.h index 80be656..f6f1468 100644 --- a/src/apfl.h +++ b/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; diff --git a/src/eval.c b/src/eval.c index 41bcf26..12b3fd1 100644 --- a/src/eval.c +++ b/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 } diff --git a/src/value.c b/src/value.c index 20d3802..bba8eaa 100644 --- a/src/value.c +++ b/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) {