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.
  *