Mercurial > lbo > hg > ylisp
view src/expr.c @ 148:1620bde57dcb
expr: Implement yexpr_equal
author | Lewin Bormann <lbo@spheniscida.de> |
---|---|
date | Tue, 03 Sep 2019 12:16:44 +0200 |
parents | 63650268d006 |
children | 88fec15abdbc |
line wrap: on
line source
#include "expr.h" #include "built-ins.h" #include "value.h" #include "base/str.h" #include "base/vec.h" #include <assert.h> #include <stdio.h> 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) { // Cases where the value is internal to the yexpr_t value: case YEXPR_UNDEF: case YEXPR_NUMBER: case YEXPR_ATOM: case YEXPR_BUILTIN: break; // External values: case YEXPR_EXCEPTION: case YEXPR_STRING: ystr_destroy(&v->value.str); break; case YEXPR_REF: // TODO: maybe reference-count the reference here. yref_destroy(&v->value.ref); 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 break; default: assert(false /* handle all cases!! */); } 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 = yref_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) { yexpr_destroy(v); v->typ = YEXPR_NUMBER; v->value.n = n; } void yexpr_set_builtin(yexpr_t* v, YBUILTIN_TYPE b) { yexpr_destroy(v); v->typ = YEXPR_BUILTIN; v->value.builtin = b; } 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); } void yexpr_set_ref(yexpr_t* v, yref_t ref) { yexpr_destroy(v); v->typ = YEXPR_REF; v->value.ref = ref; } void yexpr_set_list(yexpr_t* v, yvec_t vec) { yexpr_destroy(v); v->typ = YEXPR_LIST; 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); if (v->typ == YEXPR_UNDEF) { v->typ = YEXPR_LIST; yvec_init(&v->value.list, sizeof(yexpr_t), INITIAL_LIST_SIZE); } YVEC_PUSH(&v->value.list, &new_val); } bool yexpr_equal(yexpr_t* a, yexpr_t* b) { if (a->typ != b->typ) return false; switch (a->typ) { case YEXPR_UNDEF: return true; case YEXPR_ATOM: return a->value.atom == b->value.atom; case YEXPR_BUILTIN: return a->value.builtin == b->value.builtin; case YEXPR_NUMBER: return a->value.n == b->value.n; case YEXPR_STRING: case YEXPR_EXCEPTION: return 0 == ystr_cmp(&a->value.str, &b->value.str); case YEXPR_REF: if (yref_eq(&a->value.ref, &b->value.ref)) return true; yvalue_t* aexpr = yvalue_get(a->value.ref); yvalue_t* bexpr = yvalue_get(b->value.ref); if (aexpr->typ != bexpr->typ) return false; return yexpr_equal(&aexpr->value.expr, &bexpr->value.expr); case YEXPR_LIST: if (a->value.list.len != b->value.list.len) return false; for (size_t i = 0; i < a->value.list.len; i++) { if (!yexpr_equal(YVEC_AT(&a->value.list, i, yexpr_t), YVEC_AT(&b->value.list, i, yexpr_t))) return false; } return true; default: assert(false /* missing expression type! */); } } void yexpr_init_or_extend(yexpr_t* expr, yexpr_t arg) { if (expr->typ == YEXPR_UNDEF) { yexpr_append_value(expr, arg); } else if (expr->typ == YEXPR_LIST) { yexpr_append_value(expr, arg); } else { yexpr_t list; yexpr_init(&list); yexpr_append_value(&list, *expr); yexpr_append_value(&list, arg); *expr = list; } } 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>"); break; case YEXPR_NUMBER: ystr_build(&tmp, "%lld", expr->value.n); break; case YEXPR_STRING: ystr_append(&tmp, &expr->value.str); break; case YEXPR_ATOM: ystr_build(&tmp, "%s", yatom_name(expr->value.atom)); break; case YEXPR_REF: tmp2 = yref_debug(&expr->value.ref); ystr_append(&tmp, &tmp2); ystr_destroy(&tmp2); break; case YEXPR_BUILTIN: ystr_build(&tmp, "%s", ybuiltin_name(expr->value.builtin)); break; case YEXPR_LIST: ystr_build(&tmp, "("); yexpr_t* var = YVEC_AT(&expr->value.list, 0, yexpr_t); for (int i = 0; i < expr->value.list.len; var = YVEC_AT(&expr->value.list, ++i, yexpr_t)) { ystr_t sub = yexpr_debug_str(var); ystr_append(&tmp, &sub); ystr_build(&tmp, " "); ystr_destroy(&sub); } ystr_build(&tmp, ")"); break; case YEXPR_EXCEPTION: ystr_build(&tmp, "EXCEPTION<%s>", ystr_str(&expr->value.str)); break; default: assert(false /* Unhandled YEXPR_TYPE */); } return tmp; } void yexpr_debug(yexpr_t* expr) { ystr_t repr = yexpr_debug_str(expr); fputs(ystr_str(&repr), stderr); fputs("\n", stderr); ystr_destroy(&repr); }