#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_value evaluate_constant(struct apfl_expr_const *constant) { struct apfl_refcounted_string *rcstring; switch (constant->type) { case APFL_EXPR_CONST_NIL: return (struct apfl_value) { .type = APFL_VALUE_NIL, }; case APFL_EXPR_CONST_BOOLEAN: return (struct apfl_value) { .type = APFL_VALUE_BOOLEAN, .boolean = constant->boolean, }; case APFL_EXPR_CONST_STRING: rcstring = apfl_string_move_into_new_refcounted(&constant->string); assert(rcstring != NULL); // TODO: This can fail! return (struct apfl_value) { .type = APFL_VALUE_STRING, .string = rcstring, }; case APFL_EXPR_CONST_NUMBER: return (struct apfl_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 (struct apfl_result) { .type = APFL_RESULT_ERR_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 (struct apfl_result) { .type = APFL_RESULT_ERR_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 (struct apfl_result) { .type = APFL_RESULT_ERR_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 (struct apfl_result) { .type = APFL_RESULT_ERR_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(apfl_ctx ctx, struct apfl_expr *expr) { (void)ctx; switch (expr->type) { case APFL_EXPR_CONSTANT: return (struct apfl_result) { .type = APFL_RESULT_OK, .value = evaluate_constant(&expr->constant), }; case APFL_EXPR_LIST: return evaluate_list(ctx, &expr->list); case APFL_EXPR_VAR: case APFL_EXPR_CALL: case APFL_EXPR_DICT: 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; }