refactor: use union instead of void*

This commit is contained in:
2026-07-21 11:28:36 +02:00
parent 5dab1701cd
commit a324252e8c
+46 -49
View File
@@ -34,16 +34,8 @@ typedef enum e_NodeKind {
NODE_KIND_FUNCTION, NODE_KIND_FUNCTION,
} NodeKind; } NodeKind;
typedef struct s_Node { typedef struct s_Node Node;
NodeKind kind; typedef struct s_Nodes Nodes;
void *data;
} Node;
typedef struct s_Nodes {
Node *items;
size_t count;
size_t capacity;
} Nodes;
typedef Node *(*lisp_function_ptr)(Nodes *args); typedef Node *(*lisp_function_ptr)(Nodes *args);
typedef struct s_LispFunction { typedef struct s_LispFunction {
@@ -51,6 +43,22 @@ typedef struct s_LispFunction {
lisp_function_ptr apply; lisp_function_ptr apply;
} LispFunction; } LispFunction;
typedef struct s_Node {
NodeKind kind;
union {
Nob_String_View as_symbol;
Nodes *as_list;
long long as_number;
LispFunction as_function;
};
} Node;
struct s_Nodes {
Node *items;
size_t count;
size_t capacity;
};
Node *lisp_function_addition(Nodes *args) { Node *lisp_function_addition(Nodes *args) {
if (args->count != 2) { if (args->count != 2) {
printf("'+' expects two arguments!\n"); printf("'+' expects two arguments!\n");
@@ -66,13 +74,9 @@ Node *lisp_function_addition(Nodes *args) {
Node *node = malloc(sizeof(Node)); Node *node = malloc(sizeof(Node));
node->kind = NODE_KIND_NUMBER; node->kind = NODE_KIND_NUMBER;
long long *num = malloc(sizeof(long long)); intptr_t a = args->items[0].as_number;
// trust me, this is safe :) intptr_t b = args->items[1].as_number;
long long a = *((long long *)args->items[0].data); node->as_number = a + b;
long long b = *((long long *)args->items[1].data);
*num = a + b;
node->data = num;
return node; return node;
} }
@@ -85,9 +89,7 @@ Node *lisp_function_lookup(Nob_String_View name) {
if (nob_sv_eq(globalScope[i].name, name)) { if (nob_sv_eq(globalScope[i].name, name)) {
Node *node = malloc(sizeof(Node)); Node *node = malloc(sizeof(Node));
node->kind = NODE_KIND_FUNCTION; node->kind = NODE_KIND_FUNCTION;
// taking the reference should be fine because globalScope is in the node->as_function = globalScope[i];
// static memory
node->data = &globalScope[i];
return node; return node;
} }
} }
@@ -200,7 +202,7 @@ Node *parse(Tokens *tokens) {
} }
node->kind = NODE_KIND_LIST; node->kind = NODE_KIND_LIST;
node->data = nodes; node->as_list = nodes;
return node; return node;
} }
@@ -211,18 +213,17 @@ Node *parse(Tokens *tokens) {
switch (tok.kind) { switch (tok.kind) {
case TOKEN_KIND_NUMBER: { case TOKEN_KIND_NUMBER: {
long long *num = malloc(sizeof(long long)); long long num = strtoll(tok.data.data, NULL, 10);
*num = strtoll(tok.data.data, NULL, 10); // TODO:
// - error checking
// - double support
node->kind = NODE_KIND_NUMBER; node->kind = NODE_KIND_NUMBER;
node->data = num; node->as_number = num;
} break; } break;
case TOKEN_KIND_SYMBOL: { case TOKEN_KIND_SYMBOL: {
Nob_String_View *dat = malloc(sizeof(Nob_String_View));
*dat = tok.data;
node->kind = NODE_KIND_SYMBOL; node->kind = NODE_KIND_SYMBOL;
node->data = dat; node->as_symbol = tok.data;
} break; } break;
default: { default: {
UNREACHABLE(""); UNREACHABLE("");
@@ -234,27 +235,25 @@ Node *parse(Tokens *tokens) {
void node_print(Node node) { void node_print(Node node) {
switch (node.kind) { switch (node.kind) {
case NODE_KIND_NUMBER: { case NODE_KIND_NUMBER: {
long long num = *((long long *)node.data); printf("%lld", node.as_number);
printf("%lld", num);
} break; } break;
case NODE_KIND_SYMBOL: { case NODE_KIND_SYMBOL: {
Nob_String_View sv = *((Nob_String_View *)node.data); printf(SV_Fmt, SV_Arg(node.as_symbol));
printf(SV_Fmt, SV_Arg(sv));
} break; } break;
case NODE_KIND_LIST: { case NODE_KIND_LIST: {
Nodes nodes = *((Nodes *)node.data); Nodes *children = node.as_list;
printf("("); printf("(");
for (size_t i = 0; i < nodes.count; i++) { for (size_t i = 0; i < children->count; i++) {
Node node = nodes.items[i]; Node node = children->items[i];
node_print(node); node_print(node);
if (i != nodes.count - 1) { if (i != children->count - 1) {
printf(" "); printf(" ");
} }
} }
printf(")"); printf(")");
} break; } break;
case NODE_KIND_FUNCTION: { case NODE_KIND_FUNCTION: {
LispFunction func = *((LispFunction *)node.data); LispFunction func = node.as_function;
printf(SV_Fmt, SV_Arg(func.name)); printf(SV_Fmt, SV_Arg(func.name));
} break; } break;
} }
@@ -268,30 +267,28 @@ Node *eval(Node *node) {
case NODE_KIND_NUMBER: case NODE_KIND_NUMBER:
return node; return node;
case NODE_KIND_SYMBOL: { case NODE_KIND_SYMBOL: {
// trust me, this is safe :) return lisp_function_lookup(node->as_symbol);
Nob_String_View sv = *((Nob_String_View *)node->data);
return lisp_function_lookup(sv);
} }
case NODE_KIND_LIST: { case NODE_KIND_LIST: {
Nodes children = *((Nodes *)node->data); Nodes *children = node->as_list;
if (children.count == 0) if (children->count == 0)
return node; return node;
Node *head = &children.items[0]; Node *head = &children->items[0];
Node *function = eval(head); Node *func_node = eval(head);
Nodes *args = malloc(sizeof(Nodes)); Nodes *args = malloc(sizeof(Nodes));
for (size_t i = 1; i < children.count; i++) { for (size_t i = 1; i < children->count; i++) {
nob_da_append(args, *eval(&children.items[i])); nob_da_append(args, *eval(&children->items[i]));
} }
if (function->kind == NODE_KIND_FUNCTION) { if (func_node->kind == NODE_KIND_FUNCTION) {
LispFunction func = *((LispFunction *)function->data); LispFunction func = func_node->as_function;
return func.apply(args); return func.apply(args);
} }
printf("Not a function: '"); printf("Not a function: '");
node_print(*function); node_print(*func_node);
printf("'\n"); printf("'\n");
return NULL; return NULL;
} }