diff options
author | kartofen <mladenovnasko0@gmail.com> | 2024-08-23 19:55:13 +0300 |
---|---|---|
committer | kartofen <mladenovnasko0@gmail.com> | 2024-08-23 19:55:13 +0300 |
commit | 68a62ad356603d64d537e231f06b5d9445e79abe (patch) | |
tree | 3682d6b607fed96eafaf7e218d85a03fbc71d914 /src/value.c |
usefull commit message
Diffstat (limited to 'src/value.c')
-rw-r--r-- | src/value.c | 159 |
1 files changed, 159 insertions, 0 deletions
diff --git a/src/value.c b/src/value.c new file mode 100644 index 0000000..233b83c --- /dev/null +++ b/src/value.c @@ -0,0 +1,159 @@ +#include <stdlib.h> +#include <string.h> + +#include "common.h" +#include "value.h" +#include "lexer.h" + +// TODO: +// - create VALUE_MANAGE_TABLE which manages +// both creation and destruction +// - check the buffer size in cons creation + +// FIX: +// - remove warning for void pointer cast at line 30 + +#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, ...) 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", VALUE(v).atom)) \ + X(VALUE_STR, FN(snprintf, "%s", VALUE(v).str)) \ + X(VALUE_INT, FN(snprintf, "%d", VALUE(v).num)) \ + X(VALUE_CONS, FN(cons_print, &VALUE(v).cons)) \ + X(VALUE_PROC, FN(proc_print, &VALUE(v).proc)) \ + X(VALUE_PROC_BUILTIN, \ + FN(snprintf, "%p", *(void **)&VALUE(v).proc_builtin.proc)) + +#define DR(value) (--(value)->refs == 0) +#define VALUE_DESTROY_TABLE(X, v) \ + X(VALUE_NIL, (void)DR(v)) \ + X(VALUE_ATOM, if(DR(v)) free(VALUE(v).atom)) \ + X(VALUE_STR, if(DR(v)) free(VALUE(v).str)) \ + X(VALUE_INT, (void)DR(v)) \ + X(VALUE_CONS, (void)DR(v); \ + value_destroy(VALUE(v).cons.left); \ + value_destroy(VALUE(v).cons.right)) \ + X(VALUE_PROC, if(DR(v)) proc_destroy(&VALUE(v).proc)) \ + X(VALUE_PROC_BUILTIN, (void)DR(v)) + +#define CASE_RETURN_APPLY(vtype, apply) \ + case vtype: return apply; +#define CASE_APPLY_BREAK(vtype, apply) \ + case vtype: apply; break; + +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 value_t proc_create(...); +static void proc_destroy(struct proc *proc); + +value_t value_create(enum value_type type, void *value) +{ + value_t _value = malloc(sizeof(*_value)); + _value->type = type; + if(value != NULL) + _value->value = *(union value_union *)value; + _value->refs = 1; + + return _value; +} + +void value_destroy(value_t value) +{ + if(!value) return; + + switch(value->type) { + VALUE_DESTROY_TABLE(CASE_APPLY_BREAK, value); + } + + if(value->refs == 0) + free(value); +} + +#define STR_ALLOC_COPY(dest, str) do { \ + size_t len = strlen(str) + 1; \ + dest = malloc(len); \ + memcpy((dest), (str), len); \ + } while(0) + +value_t value_from_token(struct token *token) +{ + switch(token->type) + { + case TOKEN_ID: ; + char *atom = NULL; + STR_ALLOC_COPY(atom, token->value.id); + return value_create(VALUE_ATOM, &atom); + case TOKEN_STR: ; + char *str = NULL; + STR_ALLOC_COPY(str, token->value.str); + return value_create(VALUE_STR, &str); + case TOKEN_INT: + return value_create(VALUE_INT, &token->value); + 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->refs++; + + if(value->type == VALUE_CONS) { + value_copy(value->value.cons.left); + value_copy(value->value.cons.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_RETURN_APPLY, value, buf, buf_sz) + } + + return 0; +} + +static int cons_print(char *buf, size_t buf_sz, struct cons *cons) +{ + // TODO: check for size and off by one errors + int offset = 0; + buf[offset++] = '('; + offset += value_string(cons->left, buf_sz-offset, buf+offset); + buf[offset++] = ' '; + buf[offset++] = '.'; + buf[offset++] = ' '; + offset += value_string(cons->right, buf_sz-offset, buf+offset); + buf[offset++] = ')'; + + return offset; +} + +static int proc_print(char *buf, size_t buf_sz, struct proc *proc) +{ + (void)buf; (void)buf_sz; + (void)proc; + NOT_IMPLEMENTED(); +} + +static void proc_destroy(struct proc *proc) +{ + (void)proc; + NOT_IMPLEMENTED(); +} |