#include #include #include "common.h" #include "value.h" #include "lexer.h" #include "mempool.h" MEMPOOL_GENERATE(value, struct value, 64) #define NOT_IMPLEMENTED() die("Not Implemented. ABORTING") const char * const value_type_string[] = { VALUE_TYPES(TO_STRING) }; #define VALUE(_value) (_value)->value #define FN(fn, ...) return fn(buf, buf_sz, __VA_ARGS__) #define VALUE_STRING_TABLE(X, v, buf, buf_sz) \ X(VALUE_NIL, FN(snprintf, "(nil)")) \ X(VALUE_ATOM, FN(snprintf, "%s", vvalue_atom(v))) \ X(VALUE_STR, FN(snprintf, "%s", vvalue_str(v))) \ X(VALUE_INT, FN(snprintf, "%d", vvalue_num(v))) \ X(VALUE_CONS, FN(cons_print, &vvalue_cons(v))) \ X(VALUE_PROC, FN(proc_print, &vvalue_proc(v))) \ X(VALUE_MACRO, FN(proc_print, &vvalue_proc(v))) \ X(VALUE_PROC_BUILTIN, \ FN(snprintf, "%p", *(void **)&vvalue_proc_builtin(v).proc)) #define NOREFS(value) (value_dec_refs(value) == 0) #define VALUE_DESTROY_TABLE(X, v) \ X(VALUE_NIL, (void)NOREFS(v)) \ X(VALUE_ATOM, if(NOREFS(v)) free(vvalue_atom(v))) \ X(VALUE_STR, if(NOREFS(v)) free(vvalue_str(v))) \ X(VALUE_INT, (void)NOREFS(v)) \ X(VALUE_CONS, (void)NOREFS(v); \ value_destroy(vvalue_cons(v).left); \ value_destroy(vvalue_cons(v).right)) \ X(VALUE_PROC, if(NOREFS(v)) proc_destroy(&vvalue_proc(v))) \ X(VALUE_MACRO, if(NOREFS(v)) proc_destroy(&vvalue_proc(v))) \ X(VALUE_PROC_BUILTIN, (void)NOREFS(v)) #define CREATE(vtype, value) return value_create(vtype, value) #define VALUE_FROM_TOKEN_TABLE(X, t) \ X(TOKEN_INT, CREATE(VALUE_INT, &t->value.num)) \ X(TOKEN_STR, \ char *str = str_alloc_copy(t->value.str); \ CREATE(VALUE_STR, &str)) \ X(TOKEN_ID, \ char *atom = str_alloc_copy(t->value.id); \ CREATE(VALUE_ATOM, &atom)) #define CASE_APPLY(vtype, apply) \ case vtype: ; apply; break; #define VALUE_MEMBER_TABLE(X) \ X(VALUE_ATOM, atom) \ X(VALUE_STR, str) \ X(VALUE_INT, num) \ X(VALUE_CONS, cons) \ X(VALUE_PROC, proc) \ X(VALUE_MACRO, proc) \ X(VALUE_PROC_BUILTIN, proc_builtin) // #define value_alloc() malloc(sizeof(struct value)) // #define value_dealloc(v) free(v) #define value_alloc() value_mempool_allocate() #define value_free(v) value_mempool_free(v) static char *str_alloc_copy(char *src); static int cons_print(char *buf, size_t buf_sz, struct cons *cons); static int proc_print(char *buf, size_t buf_sz, struct proc *proc); static void proc_destroy(struct proc *proc); #define MEMBER_COPY(vtype, member) \ case vtype: memcpy(&vvalue_##member(_value), value, \ sizeof(vvalue_##member(_value))); \ break; value_t value_create(enum value_type type, void *value) { value_t _value = value_alloc(); value_set_type(_value, type); switch(type) { VALUE_MEMBER_TABLE(MEMBER_COPY); default: break; } value_set_refs(_value, 1); return _value; } void value_destroy(value_t value) { if(!value) return; switch(value->type) { VALUE_DESTROY_TABLE(CASE_APPLY, value); } if(vvalue_refs(value) == 0) value_free(value); } value_t value_from_token(struct token *token) { switch(token->type) { VALUE_FROM_TOKEN_TABLE(CASE_APPLY, token) default: err("Cannot turn token '%s' to a value", token_type_string[token->type]); return VALUE_EMPTY; } } value_t value_copy(value_t value) { if(!value) return value; value_inc_refs(value); if(vvalue_type(value) == VALUE_CONS) { value_copy(vvalue_cons(value).left); value_copy(vvalue_cons(value).right); } return value; } int value_string(value_t value, size_t buf_sz, char *buf) { if(!value) return snprintf(buf, buf_sz, "(empty)"); switch(value->type) { VALUE_STRING_TABLE(CASE_APPLY, value, buf, buf_sz) } return 0; } static char *str_alloc_copy(char *src) { if(!src) return src; size_t len = strlen(src) + 1; return memcpy(malloc(len), src, len); } static int cons_print(char *buf, size_t buf_sz, struct cons *cons) { #define HAS_SPACE if(offset < buf_sz) #define SET_CHAR(ch) HAS_SPACE { buf[offset++] = ch; } #define SET_VALUE_STRING(v) \ HAS_SPACE { \ offset += value_string(v, buf_sz-offset, buf+offset); \ } /*else { \ offset += value_string(v, 0, NULL); \ } */ size_t offset = 0; SET_CHAR('('); SET_VALUE_STRING(cons->left); value_t right = cons->right; while(vvalue_type(right) == VALUE_CONS) { SET_CHAR(' '); SET_VALUE_STRING(right->value.cons.left); right = right->value.cons.right; } if(vvalue_type(right) != VALUE_NIL) { SET_CHAR(' '); SET_CHAR('.'); SET_CHAR(' '); SET_VALUE_STRING(right); } SET_CHAR(')'); SET_CHAR('\0') else { if(buf_sz == 0) goto exit; char str[] = "...)"; if(buf_sz <= sizeof(str)) { buf[0] = '\0'; goto exit; } memcpy(buf+buf_sz - sizeof(str), str, sizeof(str)); } exit: return (int)offset-1; // -1 because of \0 } static int proc_print(char *buf, size_t buf_sz, struct proc *proc) { return 0; (void)buf; (void)buf_sz; (void)proc; NOT_IMPLEMENTED(); } static void proc_destroy(struct proc *proc) { for(size_t i = 0; i < proc->argc; i++) value_destroy(proc->arg_keys[i]); free(proc->arg_keys); toklist_destroy(proc->body); env_destroy(proc->parent_env); }