changeset 73:7a5caf93cdc2

expr: Implement yexpr_copy
author Lewin Bormann <lbo@spheniscida.de>
date Sun, 25 Aug 2019 18:45:46 +0200
parents af4431b0fac0
children d5330e2b1488
files src/expr.c src/expr.h src/expr_test.c
diffstat 3 files changed, 74 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/src/expr.c	Sun Aug 25 18:45:20 2019 +0200
+++ b/src/expr.c	Sun Aug 25 18:45:46 2019 +0200
@@ -30,6 +30,7 @@
         case YEXPR_BUILTIN:
             break;
         // External values:
+        case YEXPR_EXCEPTION:
         case YEXPR_STRING:
             ystr_destroy(&v->value.str);
             break;
@@ -50,6 +51,47 @@
     memset(v, 0, sizeof(yexpr_t));
 }
 
+yexpr_t yexpr_copy(yexpr_t* orig) {
+    yexpr_t copy = yexpr_new();
+    copy.typ = orig->typ;
+    switch (orig->typ) {
+        // Cases where the value is internal to the yexpr_t value:
+        case YEXPR_UNDEF:
+        case YEXPR_NUMBER:
+        case YEXPR_ATOM:
+        case YEXPR_BUILTIN:
+            copy = *orig;
+            break;
+        // External values:
+        case YEXPR_EXCEPTION:
+        case YEXPR_STRING:
+            copy = *orig;
+            ystr_t strcopy = ystr_new(ystr_str(&orig->value.str));
+            copy.value.str = strcopy;
+            break;
+        case YEXPR_REF:
+            // TODO: maybe reference-count the references?
+            copy = *orig;
+            copy.value.ref = yvalue_clone(&orig->value.ref);
+            break;
+        case YEXPR_LIST:
+            // Recursively copy list...
+            yvec_init(&copy.value.list, orig->value.list.size, orig->value.list.len);
+            yvec_resize(&copy.value.list, orig->value.list.len);
+#define _list (&orig->value.list)
+#define _newlist (&copy.value.list)
+            for (size_t i = 0; i < _list->len; i++)
+                *YVEC_AT(_newlist, i, yexpr_t) = yexpr_copy(YVEC_AT(_list, i, yexpr_t));
+#undef _list
+#undef _newlist
+            break;
+        default:
+            assert(false /* handle all cases!! */);
+    }
+
+    return copy;
+}
+
 static const size_t INITIAL_LIST_SIZE = 4;
 
 void yexpr_set_number(yexpr_t* v, long long n) {
@@ -94,6 +136,12 @@
     v->value.list = vec;
 }
 
+void yexpr_set_exception(yexpr_t* v, ystr_t message) {
+    yexpr_destroy(v);
+    v->typ = YEXPR_EXCEPTION;
+    v->value.str = message;
+}
+
 void yexpr_append_value(yexpr_t* v, yexpr_t new_val) {
     assert(v->typ == YEXPR_UNDEF || v->typ == YEXPR_LIST);
 
@@ -120,6 +168,10 @@
 
 ystr_t yexpr_debug_str(yexpr_t* expr) {
     ystr_t tmp = ystr_new(NULL), tmp2;
+    if (expr == NULL) {
+        ystr_set(&tmp, "NULL");
+        return tmp;
+    }
     switch (expr->typ) {
         case YEXPR_UNDEF:
             ystr_build(&tmp, "<undef>");
@@ -153,6 +205,9 @@
             }
             ystr_build(&tmp, ")");
             break;
+        case YEXPR_EXCEPTION:
+            ystr_build(&tmp, "EXCEPTION<%s>", ystr_str(&expr->value.str));
+            break;
         default:
             assert(false /* Unhandled YEXPR_TYPE */);
     }
--- a/src/expr.h	Sun Aug 25 18:45:20 2019 +0200
+++ b/src/expr.h	Sun Aug 25 18:45:46 2019 +0200
@@ -29,6 +29,11 @@
 void yexpr_destroy(yexpr_t* v);
 
 /**
+ * Return a deep copy of `orig`. References in `orig` are resolved and copied as well.
+ */
+yexpr_t yexpr_copy(yexpr_t* orig);
+
+/**
  * Initialize a yexpr_t with a number.
  */
 void yexpr_set_number(yexpr_t* v, long long n);
@@ -71,6 +76,12 @@
 void yexpr_set_list(yexpr_t* v, yvec_t vec);
 
 /**
+ * Set the value of `v` to the given string and mark it as exception. `v` owns
+ * the message afterwards.
+ */
+void yexpr_set_exception(yexpr_t* v, ystr_t message);
+
+/**
  * Initialize a yexpr_t value if not yet done and append another value to it.
  *
  * Invariants: `v` must be of type `YEXPR_LIST` or `YEXPR_UNDEF`.
--- a/src/expr_test.c	Sun Aug 25 18:45:20 2019 +0200
+++ b/src/expr_test.c	Sun Aug 25 18:45:46 2019 +0200
@@ -75,6 +75,14 @@
     yexpr_destroy(&expr);
     expr = yexpr_new();
 
+    // Test exception.
+    ystr_t message = ystr_new("some error happened");
+    yexpr_set_exception(&expr, message);
+    yexpr_debug(&expr);
+    fputs("\n", stderr);
+    yexpr_destroy(&expr);
+    expr = yexpr_new();
+
     // Test list.
     yexpr_t src[3] = {yexpr_new(), yexpr_new(), yexpr_new()};
     yexpr_set_number(&src[0], 123);