apfl/src/eval.c

261 lines
6.3 KiB
C
Raw Normal View History

#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);
}
static struct apfl_result
fatal(void)
{
return (struct apfl_result) { .type = APFL_RESULT_ERR_FATAL };
}
static struct apfl_result
evaluate_constant(struct apfl_expr_const *constant)
{
apfl_refcounted_string rcstring;
switch (constant->type) {
case APFL_EXPR_CONST_NIL:
return (struct apfl_result) {
.type = APFL_RESULT_OK,
.value = {
.type = APFL_VALUE_NIL,
},
};
case APFL_EXPR_CONST_BOOLEAN:
return (struct apfl_result) {
.type = APFL_RESULT_OK,
.value = {
.type = APFL_VALUE_BOOLEAN,
.boolean = constant->boolean,
},
};
case APFL_EXPR_CONST_STRING:
rcstring = apfl_string_move_into_new_refcounted(&constant->string);
if (rcstring == NULL) {
return fatal();
}
return (struct apfl_result) {
.type = APFL_RESULT_OK,
.value = {
.type = APFL_VALUE_STRING,
.string = rcstring,
},
};
case APFL_EXPR_CONST_NUMBER:
return (struct apfl_result) {
.type = APFL_RESULT_OK,
.value = {
.type = APFL_VALUE_NUMBER,
.number = constant->number,
},
};
}
assert(false);
}
static struct apfl_result
evaluate_list_expr_to_list(apfl_ctx ctx, struct apfl_expr *expr, struct apfl_list *out)
{
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 };
}
struct apfl_list *list = result.value.list;
if (!apfl_resizable_ensure_cap_for_more_elements(
sizeof(struct apfl_value),
(void **)&out->items,
out->len,
&out->cap,
list->len
)) {
apfl_value_deinit(&result.value);
return fatal();
}
for (size_t i = 0; i < list->len; i++) {
if (!apfl_value_copy(&out->items[out->len], list->items[i])) {
apfl_value_deinit(&result.value);
return fatal();
}
out->len++;
}
apfl_value_deinit(&result.value);
return (struct apfl_result) { .type = APFL_RESULT_OK, .value.type = APFL_VALUE_NIL };
}
static struct apfl_result
evaluate_expr_list_into_list(apfl_ctx ctx, struct apfl_expr_list *list, struct apfl_list *out)
{
for (size_t i = 0; i < list->len; i++) {
struct apfl_expr_list_item *item = &list->items[i];
if (item->expand) {
struct apfl_result result = evaluate_list_expr_to_list(ctx, item->expr, out);
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;
}
if (!apfl_resizable_append(
sizeof(struct apfl_value),
(void **)&out->items,
&out->len,
&out->cap,
&result.value,
1
)) {
apfl_value_deinit(&result.value);
return fatal();
}
}
}
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)
{
struct apfl_list *out = apfl_list_new();
if (out == NULL) {
return fatal();
}
struct apfl_result result = evaluate_expr_list_into_list(ctx, list, out);
if (result.type != APFL_RESULT_OK) {
DESTROY(out, apfl_list_deinit);
return result;
}
return (struct apfl_result) {
.type = APFL_RESULT_OK,
.value = {
.type = APFL_VALUE_LIST,
.list = out,
},
};
}
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,
},
};
}
static struct apfl_result
evaluate(apfl_ctx ctx, struct apfl_expr *expr)
{
switch (expr->type) {
case APFL_EXPR_CONSTANT:
return evaluate_constant(&expr->constant);
case APFL_EXPR_LIST:
return evaluate_list(ctx, &expr->list);
case APFL_EXPR_DICT:
return evaluate_dict(ctx, &expr->dict);
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
}
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;
}