#include #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, apfl_editable_list elist) { 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 }; } apfl_list list = apfl_list_incref(result.value.list); apfl_value_deinit(&result.value); if (!apfl_editable_list_append_list(elist, list)) { return fatal(); } 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, apfl_editable_list elist) { 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, elist); 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_editable_list_append(elist, apfl_value_move(&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) { apfl_editable_list elist = apfl_editable_list_new(); if (elist == NULL) { return fatal(); } struct apfl_result result = evaluate_expr_list_into_list(ctx, list, elist); if (result.type != APFL_RESULT_OK) { apfl_editable_list_destroy(elist); return result; } apfl_list out = apfl_editable_list_finalize(elist); if (out == NULL) { return fatal(); } 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; }