aboutsummaryrefslogtreecommitdiff
path: root/src/value.c
diff options
context:
space:
mode:
authorkartofen <mladenovnasko0@gmail.com>2024-08-23 19:55:13 +0300
committerkartofen <mladenovnasko0@gmail.com>2024-08-23 19:55:13 +0300
commit68a62ad356603d64d537e231f06b5d9445e79abe (patch)
tree3682d6b607fed96eafaf7e218d85a03fbc71d914 /src/value.c
usefull commit message
Diffstat (limited to 'src/value.c')
-rw-r--r--src/value.c159
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();
+}