Mercurial > lbo > hg > ylisp
changeset 44:6183b0c133bf
expr: Extend yexpr_t interface and add comprehensive tests
author | Lewin Bormann <lbo@spheniscida.de> |
---|---|
date | Wed, 21 Aug 2019 22:43:55 +0200 |
parents | 0efbcd20df2c |
children | 828d3b58f2cf |
files | gen/y.yy src/CMakeLists.txt src/expr.c src/expr.h src/expr_test.c src/value.c |
diffstat | 6 files changed, 185 insertions(+), 30 deletions(-) [+] |
line wrap: on
line diff
--- a/gen/y.yy Wed Aug 21 21:59:11 2019 +0200 +++ b/gen/y.yy Wed Aug 21 22:43:55 2019 +0200 @@ -83,7 +83,7 @@ inner_sexpr: inner_sexpr TOK_ATOM { printf("found atom %s\n", $2); yexpr_t atom; - yexpr_set_atom(&atom, strdup($2)); + yexpr_set_atom_name(&atom, strdup($2)); yexpr_init_or_extend(&$1, atom); $$ = $1; }
--- a/src/CMakeLists.txt Wed Aug 21 21:59:11 2019 +0200 +++ b/src/CMakeLists.txt Wed Aug 21 22:43:55 2019 +0200 @@ -22,3 +22,8 @@ ADD_EXECUTABLE(value_test value_test.c) TARGET_LINK_LIBRARIES(value_test core gcov) YADD_TEST(value_test) + +# Expr test. +ADD_EXECUTABLE(expr_test expr_test.c) +TARGET_LINK_LIBRARIES(expr_test core gcov) +YADD_TEST(expr_test)
--- a/src/expr.c Wed Aug 21 21:59:11 2019 +0200 +++ b/src/expr.c Wed Aug 21 22:43:55 2019 +0200 @@ -8,15 +8,15 @@ #include <stdio.h> yref_t yref_new_id(yvalue_id_t id) { - yref_t ref = { .typ = YREF_ID, .ref.id = id }; + yref_t ref = {.typ = YREF_ID, .ref.id = id}; return ref; } yref_t yref_new_str(ystr_t* sym) { - yref_t ref = { .typ = YREF_SYM, .ref.sym = *sym }; + yref_t ref = {.typ = YREF_SYM, .ref.sym = *sym}; return ref; } yref_t yref_new_c(const char* sym) { - yref_t ref = { .typ = YREF_SYM, .ref.sym = ystr_new(sym) }; + yref_t ref = {.typ = YREF_SYM, .ref.sym = ystr_new(sym)}; return ref; } @@ -25,55 +25,83 @@ if (ref->typ == YREF_SYM) ystr_destroy(&ref->ref.sym); } -void yexpr_set_number(yexpr_t* v, long long n) { - v->typ = YEXPR_NUMBER; - v->value.n = n; -} - -void yexpr_set_str(yexpr_t* v, ystr_t str) { - v->typ = YEXPR_STRING; - v->value.str = str; -} - void yexpr_init(yexpr_t* v) { v->typ = YEXPR_UNDEF; memset(&v->value, 0, sizeof(v->value)); } +yexpr_t yexpr_new(void) { + yexpr_t e; + yexpr_init(&e); + return e; +} + void yexpr_destroy(yexpr_t* v) { if (v == NULL) return; switch (v->typ) { case YEXPR_UNDEF: case YEXPR_NUMBER: case YEXPR_ATOM: - return; + break; case YEXPR_STRING: ystr_destroy(&v->value.str); - return; + break; case YEXPR_REF: // TODO: maybe reference-count the reference here. yref_destroy(&v->value.ref); - return; + break; case YEXPR_LIST: #define list (&v->value.list) for (size_t i = 0; i < list->len; i++) yexpr_destroy(YVEC_AT(list, i, yexpr_t)); yvec_destroy(list); #undef list - return; + break; default: assert(false /* handle all cases!! */); } + memset(v, 0, sizeof(yexpr_t)); +} + +static const size_t INITIAL_LIST_SIZE = 4; + +void yexpr_set_number(yexpr_t* v, long long n) { + yexpr_destroy(v); + v->typ = YEXPR_NUMBER; + v->value.n = n; } -void yexpr_set_atom(yexpr_t* v, const char* atom_name) { +void yexpr_set_str(yexpr_t* v, ystr_t str) { + yexpr_destroy(v); + v->typ = YEXPR_STRING; + v->value.str = str; +} + +void yexpr_set_atom(yexpr_t* v, yatom_t atom) { + yexpr_destroy(v); + v->typ = YEXPR_ATOM; + v->value.atom = atom; +} + +void yexpr_set_atom_name(yexpr_t* v, const char* atom_name) { + yexpr_destroy(v); v->typ = YEXPR_ATOM; v->value.atom = yatom_get_or_add(atom_name); } -static const size_t INITIAL_LIST_SIZE = 4; +void yexpr_set_ref(yexpr_t* v, yref_t ref) { + yexpr_destroy(v); + v->typ = YEXPR_REF; + v->value.ref = ref; +} -void yexpr_add_value(yexpr_t* v, yexpr_t new_val) { +void yexpr_set_list(yexpr_t* v, yvec_t vec) { + yexpr_destroy(v); + v->typ = YEXPR_LIST; + v->value.list = vec; +} + +void yexpr_append_value(yexpr_t* v, yexpr_t new_val) { assert(v->typ == YEXPR_UNDEF || v->typ == YEXPR_LIST); if (v->typ == YEXPR_UNDEF) { @@ -85,14 +113,14 @@ void yexpr_init_or_extend(yexpr_t* expr, yexpr_t arg) { if (expr->typ == YEXPR_UNDEF) { - yexpr_add_value(expr, arg); + yexpr_append_value(expr, arg); } else if (expr->typ == YEXPR_LIST) { - yexpr_add_value(expr, arg); + yexpr_append_value(expr, arg); } else { yexpr_t list; yexpr_init(&list); - yexpr_add_value(&list, *expr); - yexpr_add_value(&list, arg); + yexpr_append_value(&list, *expr); + yexpr_append_value(&list, arg); *expr = list; } } @@ -111,6 +139,16 @@ case YEXPR_ATOM: fprintf(stderr, "%s", yatom_name(expr->value.atom)); break; + case YEXPR_REF: + if (expr->value.ref.typ == YREF_ID) { + fprintf(stderr, "id<%llu>", expr->value.ref.ref.id); + } else if (expr->value.ref.typ == YREF_SYM) { + fprintf(stderr, "id<\"%s\">", + ystr_str(&expr->value.ref.ref.sym)); + } else { + fprintf(stderr, "id<UNINITIALIZED>"); + } + break; case YEXPR_LIST: fprintf(stderr, "("); yexpr_t* var = YVEC_AT(&expr->value.list, 0, yexpr_t);
--- a/src/expr.h Wed Aug 21 21:59:11 2019 +0200 +++ b/src/expr.h Wed Aug 21 22:43:55 2019 +0200 @@ -41,7 +41,8 @@ yref_t yref_new_id(yvalue_id_t id); /** - * Create a new reference to the given symbol. Takes ownership of `sym`, it must not be freed afterwards. + * Create a new reference to the given symbol. Takes ownership of `sym`, it must + * not be freed afterwards. */ yref_t yref_new_str(ystr_t* sym); @@ -94,6 +95,11 @@ void yexpr_init(yexpr_t* v); /** + * Return an initialized yexpr_t. + */ +yexpr_t yexpr_new(void); + +/** * Deallocate all memory occupied by expr and any subexpressions. */ void yexpr_destroy(yexpr_t* v); @@ -111,19 +117,35 @@ void yexpr_set_str(yexpr_t* v, ystr_t str); /** - * Initialize a yexpr_t value with an atom. + * Initialize a yexpr_t with an atom. + */ +void yexpr_set_atom(yexpr_t* v, yatom_t atom); + +/** + * Initialize a yexpr_t value with an atom, referenced by its name. * * Causes a new atom to be created in the atoms table, or an existing one to be * referenced. */ -void yexpr_set_atom(yexpr_t* v, const char* atom_name); +void yexpr_set_atom_name(yexpr_t* v, const char* atom_name); + +/** + * Set the value of `v` to be a reference `ref`. Ownership of `ref` goes to `v`, + * it may not be freed after the call. + */ +void yexpr_set_ref(yexpr_t* v, yref_t ref); + +/** + * Set the value of `v` to the list/vector `vec`. Ownership of `vec` is transferred to `v`; do not destroy `vec`. + */ +void yexpr_set_list(yexpr_t* v, yvec_t vec); /** * 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`. */ -void yexpr_add_value(yexpr_t* v, yexpr_t new_val); +void yexpr_append_value(yexpr_t* v, yexpr_t new_val); /****** helpers for parsing ******/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/expr_test.c Wed Aug 21 22:43:55 2019 +0200 @@ -0,0 +1,89 @@ +#include "expr.h" + +#include <src/value.h> + +void test_expr_set(void) { + yexpr_t expr = yexpr_new(); + + // Test atoms. + yexpr_set_atom_name(&expr, "myatom"); + assert(0 == strcmp("myatom", yatom_name(expr.value.atom))); + yexpr_set_atom(&expr, yatom_get_or_add("myatom2")); + assert(0 == strcmp("myatom2", yatom_name(expr.value.atom))); + yexpr_debug(&expr); + fputs("\n", stderr); + yexpr_destroy(&expr); + expr = yexpr_new(); + + // Test number. + yexpr_set_number(&expr, 12345); + assert(12345 == expr.value.n); + yexpr_debug(&expr); + fputs("\n", stderr); + yexpr_destroy(&expr); + expr = yexpr_new(); + + // Test string. + yexpr_set_str(&expr, ystr_new("hello")); + assert(0 == ystr_cmp_str(&expr.value.str, "hello")); + yexpr_debug(&expr); + fputs("\n", stderr); + yexpr_destroy(&expr); + expr = yexpr_new(); + + // Test refs, symbolic and numeric. + yexpr_set_ref(&expr, yref_new_c("my-ref")); + yexpr_debug(&expr); + fputs("\n", stderr); + yvalue_resolve_or_create_ref(&expr.value.ref); + assert(YREF_ID == expr.value.ref.typ); + 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); + yexpr_set_number(&src[1], 124); + yexpr_set_number(&src[2], 125); + yvec_t vec = YVEC_NEW(src, 3, yexpr_t); + yexpr_set_list(&expr, vec); + assert(124 == (YVEC_AT(&expr.value.list, 1, yexpr_t))->value.n); + + // Test append (first value to end). + yexpr_append_value(&expr, src[0]); + yexpr_append_value(&expr, src[2]); + assert(123 == (YVEC_AT(&expr.value.list, 3, yexpr_t))->value.n); + assert(125 == (YVEC_AT(&expr.value.list, 4, yexpr_t))->value.n); + + yexpr_destroy(&expr); + expr = yexpr_new(); + + // Test init_or_extend. + yexpr_set_number(&expr, 12345); + + yexpr_t src2[3] = {yexpr_new(), yexpr_new(), yexpr_new()}; + yexpr_set_atom_name(&src2[0], "atom1"); + yexpr_set_atom_name(&src2[1], "atom2"); + yexpr_set_atom_name(&src2[2], "atom3"); + yexpr_init_or_extend(&expr, src2[0]); + yexpr_init_or_extend(&expr, src2[2]); + // Expr now contains list of exprs: 12345, atom1, atom3. + yvec_t list = expr.value.list; + assert(12345 == YVEC_AT(&list, 0, yexpr_t)->value.n); + yatom_t got = YVEC_AT(&list, 1, yexpr_t)->value.atom; + assert(yatom_get_or_add("atom1") == got); + got = YVEC_AT(&list, 2, yexpr_t)->value.atom; + assert(yatom_get_or_add("atom3") == got); + + yexpr_debug(&expr); + fputs("\n", stderr); + + yexpr_destroy(&expr); +} + +int main(int argc, char** argv) { + test_expr_set(); + return 0; +}