Mercurial > lbo > hg > ylisp
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(©.value.list, orig->value.list.size, orig->value.list.len); + yvec_resize(©.value.list, orig->value.list.len); +#define _list (&orig->value.list) +#define _newlist (©.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);