Mercurial > lbo > hg > ylisp
changeset 94:d6afe40a6784
eval: Functionality to evaluate lists of expressions; support in_place better
(the second is needed by the first)
author | Lewin Bormann <lbo@spheniscida.de> |
---|---|
date | Mon, 26 Aug 2019 17:00:08 +0200 |
parents | aadc11bdfdc4 |
children | 4967652fcbf5 |
files | src/eval.c src/eval.h |
diffstat | 2 files changed, 37 insertions(+), 1 deletions(-) [+] |
line wrap: on
line diff
--- a/src/eval.c Mon Aug 26 16:59:28 2019 +0200 +++ b/src/eval.c Mon Aug 26 17:00:08 2019 +0200 @@ -8,14 +8,25 @@ yexpr_t yeval_call_func(yvalue_t* ref, yexpr_t* call) { return yexpr_new(); } +yexpr_t yeval_list_return_last(yeval_state_t* state, yvec_t* list, size_t off) { + if (list->len - off == 0) return yexpr_new(); + assert(list->size == sizeof(yexpr_t)); + for (size_t i = off; i < list->len; i++) { + yeval(state, YVEC_AT(list, i, yexpr_t), true); + } + return yeval(state, YVEC_AT(list, list->len - 1, yexpr_t), false); +} + yexpr_t yeval(yeval_state_t* state, yexpr_t* expr, bool in_place) { yexpr_t result; + if (in_place) result = yexpr_new(); switch (expr->typ) { case YEXPR_ATOM: case YEXPR_NUMBER: case YEXPR_STRING: case YEXPR_EXCEPTION: case YEXPR_BUILTIN: + if (in_place) break; // values can't have side effects // Flat copy is enough. return *expr; case YEXPR_REF: @@ -24,6 +35,7 @@ nothing(); yvalue_t* val = yvalue_get(expr->value.ref); if (val->typ == YVALUE_EXPR) { + if (in_place) break; // values can't have side effects result = yexpr_copy(&val->value.expr); return result; } else if (val->typ == YVALUE_FUNC) { @@ -34,6 +46,7 @@ case YEXPR_LIST: // Is empty list? if (expr->value.list.len == 0) { + if (in_place) break; result = *expr; result.value.list = yvec_clone(&expr->value.list); return result; @@ -53,6 +66,10 @@ // Call function. if (val->typ == YVALUE_FUNC) { result = yeval_call_func(val, expr); + if (in_place) { + yexpr_destroy(&result); + return result; + } return result; } else if (val->typ == YVALUE_EXPR) { // resolve as normal below; this seems to be a "data list". @@ -60,11 +77,23 @@ assert(val->typ == YVALUE_FUNC || val->typ == YVALUE_EXPR); } } + + // Don't store results + if (in_place) { + for (size_t i = 0; i < result.value.list.len; i++) { + yexpr_t* elem = YVEC_AT(&result.value.list, i, yexpr_t); + yexpr_t elem_result = + yeval(state, elem, /* in_place= */ true); + yexpr_destroy(&elem_result); + } + return result; + } + result = *expr; result.value.list = yvec_clone(&expr->value.list); for (size_t i = 0; i < result.value.list.len; i++) { yexpr_t* elem = YVEC_AT(&result.value.list, i, yexpr_t); - yexpr_t elem_result = yeval(state, elem, false); + yexpr_t elem_result = yeval(state, elem, /* in_place= */ false); *elem = elem_result; } return result;
--- a/src/eval.h Mon Aug 26 16:59:28 2019 +0200 +++ b/src/eval.h Mon Aug 26 17:00:08 2019 +0200 @@ -24,6 +24,13 @@ } yeval_state_t; /** + * @brief Evaluate a list of expressions starting at off, but only return the last one. Used to + * run functions or other constructs that evaluate expressions for their + * side-effects. + */ +yexpr_t yeval_list_return_last(yeval_state_t* state, yvec_t* list, size_t off); + +/** * @brief The core of ylisp: Evaluate an expression, resulting in a new * expression. *