Mercurial > lbo > hg > ylisp
changeset 42:9bead1335e42
value: Add test
author | Lewin Bormann <lbo@spheniscida.de> |
---|---|
date | Wed, 21 Aug 2019 13:09:17 +0200 |
parents | a3eac54f2112 |
children | 0efbcd20df2c |
files | src/CMakeLists.txt src/value.c src/value.h src/value_test.c |
diffstat | 4 files changed, 114 insertions(+), 7 deletions(-) [+] |
line wrap: on
line diff
--- a/src/CMakeLists.txt Wed Aug 21 13:08:52 2019 +0200 +++ b/src/CMakeLists.txt Wed Aug 21 13:09:17 2019 +0200 @@ -17,3 +17,8 @@ ADD_EXECUTABLE(atom_test atom_test.c) TARGET_LINK_LIBRARIES(atom_test core gcov) YADD_TEST(atom_test) + +# Value test. +ADD_EXECUTABLE(value_test value_test.c) +TARGET_LINK_LIBRARIES(value_test core gcov) +YADD_TEST(value_test)
--- a/src/value.c Wed Aug 21 13:08:52 2019 +0200 +++ b/src/value.c Wed Aug 21 13:09:17 2019 +0200 @@ -3,6 +3,12 @@ #include <search.h> #include <string.h> +/// An invalid value ID. +const yvalue_id_t YVALUE_INVALID_ID = UINT64_MAX - 1; + +/// Use YVALUE_INSERT in `yvalue_set()` to insert a new value. +const yref_t YVALUE_INSERT = {.typ = YREF_ID, .ref.id = UINT64_MAX - 2}; + // TODO: Adjust when programs are bigger. static const size_t YVALUE_INITIAL_VALUES = 256, YVALUE_MAX_VALUES = 1024; static const yvalue_id_t YVALUE_COUNTER_OFFSET = 0xb0b0b0b0b0; @@ -17,6 +23,10 @@ // 1. Name (char*, heap, owned by hashtable) -> ID (yvalue_id_t) (Hashtable - // slow) // 2. ID (yvalue_id_t) -> Value (yvalue_t) (yvec_t - fast) +// +// Invariants: +// 1. Every symbol has a corresponding place in the value table once it has +// been created. static bool yvalue_table_initialized = false; static struct hsearch_data yvalue_name_table; @@ -25,7 +35,7 @@ // reference-counting in different table) static yvalue_id_t yvalue_counter = YVALUE_COUNTER_OFFSET; -static void yvalue_init_tables(void) { +static inline void yvalue_init_tables(void) { if (yvalue_table_initialized) return; yvalue_table_initialized = true; hcreate_r(YVALUE_MAX_VALUES, &yvalue_name_table); @@ -35,9 +45,11 @@ yvalue_id_t yvalue_resolve_symbol(ystr_t* sym) { if (ystr_len(sym) == 0) return YVALUE_INVALID_ID; yvalue_init_tables(); + const char* sym_s = ystr_str(sym); ENTRY want = {NULL, NULL}; ENTRY* result; + want.key = sym_s; // Valid, key is not modified. hsearch_r(want, FIND, &result, &yvalue_name_table); if (result == NULL) return YVALUE_INVALID_ID; @@ -45,9 +57,17 @@ } yvalue_id_t yvalue_resolve_or_create_symbol(ystr_t* sym) { + yvalue_init_tables(); + yvalue_id_t id = yvalue_resolve_symbol(sym); if (id != YVALUE_INVALID_ID) return id; - yvalue_id_t new_id = yvalue_counter++ - YVALUE_COUNTER_OFFSET; + yvalue_id_t new_id = yvalue_counter++; + + // Create new value entry. + yvalue_t empty; + memset(&empty, 0, sizeof(yvalue_t)); + YVEC_PUSH(&yvalue_table, &empty); + ENTRY new = {.key = strdup(ystr_str(sym)), .data = (void*)new_id}; ENTRY* result; hsearch_r(new, ENTER, &result, &yvalue_name_table); @@ -55,19 +75,25 @@ } bool yvalue_resolve_or_create_ref(yref_t* ref) { + yvalue_init_tables(); + if (ref->typ == YREF_ID) return true; if (ref->typ == YREF_SYM) { yvalue_id_t id = yvalue_resolve_or_create_symbol(&ref->ref.sym); ystr_destroy(&ref->ref.sym); ref->ref.id = id; + ref->typ = YREF_ID; return true; } assert(ref->typ == YREF_ID || ref->typ == YREF_SYM); } yref_t yvalue_set(yref_t ref, yvalue_t* val) { + yvalue_init_tables(); + // ref == YVALUE_INSERT if (ref.typ == YVALUE_INSERT.typ && ref.ref.id == YVALUE_INSERT.ref.id) { + // Unnamed value. ref.ref.id = yvalue_counter++; size_t new_index = YVEC_PUSH(&yvalue_table, val); return ref; @@ -80,6 +106,8 @@ } yvalue_t* yvalue_get(yref_t ref) { + yvalue_init_tables(); + if (ref.typ == YREF_ID) { assert(ref.ref.id <= yvalue_counter); yvalue_t* vp = YVEC_AT(&yvalue_table,
--- a/src/value.h Wed Aug 21 13:08:52 2019 +0200 +++ b/src/value.h Wed Aug 21 13:09:17 2019 +0200 @@ -22,7 +22,10 @@ // See expr.h for definitions of yref_t, yvalue_id_t, YREF_TYPE. /// An invalid value ID. -const yvalue_id_t YVALUE_INVALID_ID = UINT64_MAX - 1; +const yvalue_id_t YVALUE_INVALID_ID; + +/// Use YVALUE_INSERT in `yvalue_set()` to insert a new value. +const yref_t YVALUE_INSERT; enum YVALUE_TYPE { YVALUE_UNDEF = 0, @@ -30,9 +33,6 @@ YVALUE_EXPR = 2, }; -/// Use YVALUE_INSERT in `yvalue_set()` to insert a new value. -const yref_t YVALUE_INSERT = {.typ = YREF_ID, .ref.id = UINT64_MAX - 2}; - /** * @brief A value with a name, stored in the global value table to be referenced * by name or ID. To be used as pointer (not value). @@ -52,7 +52,7 @@ /** * @brief Resolve a symbol to an ID or create a new ID if one doesn't exist - * already. + * already. Also allocates a place in the value table. */ yvalue_id_t yvalue_resolve_or_create_symbol(ystr_t* sym);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/value_test.c Wed Aug 21 13:09:17 2019 +0200 @@ -0,0 +1,74 @@ +#include "value.h" + +#include <assert.h> + +#include <src/base/str.h> +#include <src/expr.h> + +void test_value_create_resolve(void) { + ystr_t sym; + ystr_init(&sym, "vcr_symbol"); + assert(YVALUE_INVALID_ID == yvalue_resolve_symbol(&sym)); + yvalue_id_t id = yvalue_resolve_or_create_symbol(&sym); + assert(YVALUE_INVALID_ID != id); + assert(id == yvalue_resolve_symbol(&sym)); + + ystr_destroy(&sym); +} + +void test_ref_create_resolve(void) { + ystr_t symbol = ystr_new("rcr_symbol"); + ystr_t symbol2; + ystr_copy(&symbol, &symbol2); + yref_t ref = yref_new_str(&symbol); // symbol is now owned by ref. + + yvalue_resolve_or_create_ref(&ref); + assert(YVALUE_INVALID_ID != yvalue_resolve_symbol(&symbol2)); + assert(YREF_ID == ref.typ); + assert(ref.ref.id == yvalue_resolve_symbol(&symbol2)); +} + +void test_value_set(void) { + yexpr_t expr; + expr.typ = YEXPR_NUMBER; + expr.value.n = 12345; + yvalue_t val; + val.typ = YVALUE_EXPR; + val.value.expr = expr; + + // Allocate unnamed ref. + yref_t ref = yvalue_set(YVALUE_INSERT, &val); + assert(YREF_ID == ref.typ); + yvalue_t* got = yvalue_get(ref); + assert(YVALUE_EXPR == got->typ); + assert(YEXPR_NUMBER == got->value.expr.typ); + assert(12345 == got->value.expr.value.n); + + // Use named refs. + ystr_t symbol = ystr_new("vs_symbol"); + ystr_t symbol2 = ystr_new("vs_symbol"); + + val.value.expr.value.n = 12346; + yvalue_id_t id = yvalue_resolve_or_create_symbol(&symbol); + yref_t ref2 = yref_new_id(id); + yref_t ref2b = yvalue_set(ref2, &val); + assert(ref2b.ref.id == ref2.ref.id); + yvalue_t* got2 = yvalue_get(ref2); + assert(12346 == got2->value.expr.value.n); + + // Get symbolically. + yref_t ref3 = yref_new_str(&symbol2); + yvalue_t* got3 = yvalue_get(ref3); + assert(12346 == got2->value.expr.value.n); + + // Get invalid entry. + yref_t ref_invalid = yref_new_c("invalid_entry"); + assert(NULL == yvalue_get(ref_invalid)); + assert(NULL != yvalue_get(ref3)); +} + +int main(int argc, char** argv) { + test_value_create_resolve(); + test_ref_create_resolve(); + test_value_set(); +}