2022-01-02 16:19:54 +00:00
|
|
|
#include <assert.h>
|
|
|
|
|
|
|
|
|
|
#include "apfl.h"
|
|
|
|
|
#include "internal.h"
|
|
|
|
|
#include "resizable.h"
|
|
|
|
|
|
|
|
|
|
struct apfl_ctx_data {
|
|
|
|
|
char nothing_here_yet;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static struct apfl_result evaluate(apfl_ctx, struct apfl_expr *);
|
|
|
|
|
|
|
|
|
|
apfl_ctx
|
|
|
|
|
apfl_ctx_new()
|
|
|
|
|
{
|
|
|
|
|
apfl_ctx ctx = ALLOC(struct apfl_ctx_data);
|
|
|
|
|
if (ctx == NULL) {
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ctx;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
apfl_ctx_destroy(apfl_ctx ctx)
|
|
|
|
|
{
|
|
|
|
|
free(ctx);
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-02 20:20:08 +00:00
|
|
|
static struct apfl_result
|
|
|
|
|
fatal(void)
|
|
|
|
|
{
|
|
|
|
|
return (struct apfl_result) { .type = APFL_RESULT_ERR_FATAL };
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static struct apfl_result
|
2022-01-02 16:55:05 +00:00
|
|
|
evaluate_constant(struct apfl_expr_const *constant)
|
2022-01-02 16:19:54 +00:00
|
|
|
{
|
2022-01-04 20:22:46 +00:00
|
|
|
apfl_refcounted_string rcstring;
|
2022-01-02 16:19:54 +00:00
|
|
|
|
2022-01-02 16:55:05 +00:00
|
|
|
switch (constant->type) {
|
2022-01-02 16:19:54 +00:00
|
|
|
case APFL_EXPR_CONST_NIL:
|
2022-01-02 20:20:08 +00:00
|
|
|
return (struct apfl_result) {
|
|
|
|
|
.type = APFL_RESULT_OK,
|
|
|
|
|
.value = {
|
|
|
|
|
.type = APFL_VALUE_NIL,
|
|
|
|
|
},
|
2022-01-02 16:19:54 +00:00
|
|
|
};
|
|
|
|
|
case APFL_EXPR_CONST_BOOLEAN:
|
2022-01-02 20:20:08 +00:00
|
|
|
return (struct apfl_result) {
|
|
|
|
|
.type = APFL_RESULT_OK,
|
|
|
|
|
.value = {
|
|
|
|
|
.type = APFL_VALUE_BOOLEAN,
|
|
|
|
|
.boolean = constant->boolean,
|
|
|
|
|
},
|
2022-01-02 16:19:54 +00:00
|
|
|
};
|
|
|
|
|
case APFL_EXPR_CONST_STRING:
|
2022-01-02 16:55:05 +00:00
|
|
|
rcstring = apfl_string_move_into_new_refcounted(&constant->string);
|
2022-01-02 20:20:08 +00:00
|
|
|
if (rcstring == NULL) {
|
|
|
|
|
return fatal();
|
|
|
|
|
}
|
2022-01-02 16:55:05 +00:00
|
|
|
|
2022-01-02 20:20:08 +00:00
|
|
|
return (struct apfl_result) {
|
|
|
|
|
.type = APFL_RESULT_OK,
|
|
|
|
|
.value = {
|
|
|
|
|
.type = APFL_VALUE_STRING,
|
|
|
|
|
.string = rcstring,
|
|
|
|
|
},
|
2022-01-02 16:19:54 +00:00
|
|
|
};
|
|
|
|
|
case APFL_EXPR_CONST_NUMBER:
|
2022-01-02 20:20:08 +00:00
|
|
|
return (struct apfl_result) {
|
|
|
|
|
.type = APFL_RESULT_OK,
|
|
|
|
|
.value = {
|
|
|
|
|
.type = APFL_VALUE_NUMBER,
|
|
|
|
|
.number = constant->number,
|
|
|
|
|
},
|
2022-01-02 16:19:54 +00:00
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
assert(false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static struct apfl_result
|
2022-01-04 22:11:38 +00:00
|
|
|
evaluate_list_expr_to_list(apfl_ctx ctx, struct apfl_expr *expr, apfl_editable_list elist)
|
2022-01-02 16:19:54 +00:00
|
|
|
{
|
|
|
|
|
struct apfl_result result = evaluate(ctx, expr);
|
|
|
|
|
if (result.type != APFL_RESULT_OK) {
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (result.value.type != APFL_VALUE_LIST) {
|
|
|
|
|
apfl_value_deinit(&result.value);
|
|
|
|
|
return (struct apfl_result) { .type = APFL_RESULT_ERR };
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-04 22:11:38 +00:00
|
|
|
apfl_list list = apfl_list_incref(result.value.list);
|
|
|
|
|
apfl_value_deinit(&result.value);
|
2022-01-02 16:19:54 +00:00
|
|
|
|
2022-01-04 22:11:38 +00:00
|
|
|
if (!apfl_editable_list_append_list(elist, list)) {
|
2022-01-02 20:20:08 +00:00
|
|
|
return fatal();
|
2022-01-02 16:19:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (struct apfl_result) { .type = APFL_RESULT_OK, .value.type = APFL_VALUE_NIL };
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static struct apfl_result
|
2022-01-04 22:11:38 +00:00
|
|
|
evaluate_expr_list_into_list(apfl_ctx ctx, struct apfl_expr_list *list, apfl_editable_list elist)
|
2022-01-02 16:19:54 +00:00
|
|
|
{
|
|
|
|
|
for (size_t i = 0; i < list->len; i++) {
|
|
|
|
|
struct apfl_expr_list_item *item = &list->items[i];
|
|
|
|
|
|
|
|
|
|
if (item->expand) {
|
2022-01-04 22:11:38 +00:00
|
|
|
struct apfl_result result = evaluate_list_expr_to_list(ctx, item->expr, elist);
|
2022-01-02 16:19:54 +00:00
|
|
|
if (result.type != APFL_RESULT_OK) {
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
struct apfl_result result = evaluate(ctx, item->expr);
|
|
|
|
|
if (result.type != APFL_RESULT_OK) {
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-04 22:11:38 +00:00
|
|
|
if (!apfl_editable_list_append(elist, apfl_value_move(&result.value))) {
|
2022-01-02 20:20:08 +00:00
|
|
|
return fatal();
|
2022-01-02 16:19:54 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (struct apfl_result) { .type = APFL_RESULT_OK, .value.type = APFL_VALUE_NIL };
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static struct apfl_result
|
|
|
|
|
evaluate_list(apfl_ctx ctx, struct apfl_expr_list *list)
|
|
|
|
|
{
|
2022-01-04 22:11:38 +00:00
|
|
|
apfl_editable_list elist = apfl_editable_list_new();
|
|
|
|
|
if (elist == NULL) {
|
2022-01-02 20:20:08 +00:00
|
|
|
return fatal();
|
2022-01-02 16:19:54 +00:00
|
|
|
}
|
|
|
|
|
|
2022-01-04 22:11:38 +00:00
|
|
|
struct apfl_result result = evaluate_expr_list_into_list(ctx, list, elist);
|
2022-01-02 16:19:54 +00:00
|
|
|
if (result.type != APFL_RESULT_OK) {
|
2022-01-04 22:11:38 +00:00
|
|
|
apfl_editable_list_destroy(elist);
|
2022-01-02 16:19:54 +00:00
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-04 22:11:38 +00:00
|
|
|
apfl_list out = apfl_editable_list_finalize(elist);
|
|
|
|
|
if (out == NULL) {
|
|
|
|
|
return fatal();
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-02 16:19:54 +00:00
|
|
|
return (struct apfl_result) {
|
|
|
|
|
.type = APFL_RESULT_OK,
|
|
|
|
|
.value = {
|
|
|
|
|
.type = APFL_VALUE_LIST,
|
|
|
|
|
.list = out,
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-04 20:51:44 +00:00
|
|
|
static struct apfl_result
|
|
|
|
|
evaluate_dict(apfl_ctx ctx, struct apfl_expr_dict *dict)
|
|
|
|
|
{
|
|
|
|
|
apfl_editable_dict ed = apfl_editable_dict_new();
|
|
|
|
|
|
|
|
|
|
if (ed == NULL) {
|
|
|
|
|
return fatal();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (size_t i = 0; i < dict->len; i++) {
|
|
|
|
|
struct apfl_result result;
|
|
|
|
|
struct apfl_value key, value;
|
|
|
|
|
|
|
|
|
|
result = evaluate(ctx, dict->items[i].k);
|
|
|
|
|
if (result.type != APFL_RESULT_OK) {
|
|
|
|
|
apfl_editable_dict_destroy(ed);
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
key = result.value;
|
|
|
|
|
|
|
|
|
|
result = evaluate(ctx, dict->items[i].v);
|
|
|
|
|
if (result.type != APFL_RESULT_OK) {
|
|
|
|
|
apfl_editable_dict_destroy(ed);
|
|
|
|
|
apfl_value_deinit(&key);
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
value = result.value;
|
|
|
|
|
|
|
|
|
|
if (!apfl_editable_dict_set(
|
|
|
|
|
ed,
|
|
|
|
|
apfl_value_move(&key),
|
|
|
|
|
apfl_value_move(&value)
|
|
|
|
|
)) {
|
|
|
|
|
apfl_editable_dict_destroy(ed);
|
|
|
|
|
return fatal();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
apfl_dict out = apfl_editable_dict_finalize(ed);
|
|
|
|
|
if (out == NULL) {
|
|
|
|
|
return fatal();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (struct apfl_result) {
|
|
|
|
|
.type = APFL_RESULT_OK,
|
|
|
|
|
.value = {
|
|
|
|
|
.type = APFL_VALUE_DICT,
|
|
|
|
|
.dict = out,
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-04 23:25:41 +00:00
|
|
|
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
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-01-04 20:51:44 +00:00
|
|
|
|
2022-01-02 16:19:54 +00:00
|
|
|
static struct apfl_result
|
|
|
|
|
evaluate(apfl_ctx ctx, struct apfl_expr *expr)
|
|
|
|
|
{
|
|
|
|
|
switch (expr->type) {
|
|
|
|
|
case APFL_EXPR_CONSTANT:
|
2022-01-02 20:20:08 +00:00
|
|
|
return evaluate_constant(&expr->constant);
|
2022-01-02 16:19:54 +00:00
|
|
|
case APFL_EXPR_LIST:
|
|
|
|
|
return evaluate_list(ctx, &expr->list);
|
2022-01-04 20:51:44 +00:00
|
|
|
case APFL_EXPR_DICT:
|
|
|
|
|
return evaluate_dict(ctx, &expr->dict);
|
2022-01-04 23:25:41 +00:00
|
|
|
case APFL_EXPR_DOT:
|
|
|
|
|
return evaluate_dot(ctx, &expr->dot);
|
|
|
|
|
case APFL_EXPR_AT:
|
|
|
|
|
return evaluate_at(ctx, &expr->at);
|
2022-01-02 16:19:54 +00:00
|
|
|
case APFL_EXPR_VAR:
|
|
|
|
|
case APFL_EXPR_CALL:
|
|
|
|
|
case APFL_EXPR_SIMPLE_FUNC:
|
|
|
|
|
case APFL_EXPR_COMPLEX_FUNC:
|
|
|
|
|
case APFL_EXPR_ASSIGNMENT:
|
|
|
|
|
break; // Not implemented yet
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (struct apfl_result) { .type = APFL_RESULT_ERR };
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct apfl_result
|
|
|
|
|
apfl_eval(apfl_ctx ctx, struct apfl_expr expr)
|
|
|
|
|
{
|
|
|
|
|
struct apfl_result result = evaluate(ctx, &expr);
|
|
|
|
|
apfl_expr_deinit(&expr);
|
|
|
|
|
return result;
|
|
|
|
|
}
|