aboutsummaryrefslogtreecommitdiff
path: root/src/value.c
blob: 233b83cb92b4795028af39c818516639689bb861 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
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();
}