From 8ec82a66e0332f8df9aa051ecfab45fb27b68de3 Mon Sep 17 00:00:00 2001 From: Tim Teichmann Date: Tue, 21 Jul 2026 19:18:53 +0200 Subject: [PATCH] WIP: refactor api --- builtins.c | 89 ++++++++++++------------- lisp.c | 190 +++++++++++++++++++++++++++++++++++++---------------- lisp.h | 44 +++++++------ main.c | 22 +++++-- 4 files changed, 214 insertions(+), 131 deletions(-) diff --git a/builtins.c b/builtins.c index 2ec8fbf..01a464b 100644 --- a/builtins.c +++ b/builtins.c @@ -1,26 +1,26 @@ #include "lisp.h" #define func_arithmetic_ex(name, operator, operator_name) \ - Node *name(Nodes *args, Scopes *scopes) { \ + int name(Nodes *args, Scopes *scopes, Node *result) { \ UNUSED(scopes); \ if (args->count != 2) { \ puts("'" operator_name "' expects two arguments!\n"); \ - return NULL; \ + return 1; \ } \ if (args->items[0].kind != NODE_KIND_NUMBER || \ args->items[1].kind != NODE_KIND_NUMBER) { \ puts("'" operator_name \ "' only works on numbers, you specified something " \ "else!\n"); \ - return NULL; \ + return 1; \ } \ - Node *node = malloc(sizeof(Node)); \ - node->kind = NODE_KIND_NUMBER; \ long long a = args->items[0].as_number; \ long long b = args->items[1].as_number; \ - node->as_number = a operator b; \ - return node; \ + result->as_number = a operator b; \ + result->kind = NODE_KIND_NUMBER; \ + return 0; \ } + #define func_arithmetic(name, operator) \ func_arithmetic_ex(name, operator, #operator) @@ -35,46 +35,43 @@ func_arithmetic(lisp_function_gt, >); func_arithmetic(lisp_function_lt_eq, <=); func_arithmetic(lisp_function_gt_eq, >=); -Node *lisp_function_println(Nodes *args, Scopes *scopes) { +int lisp_function_println(Nodes *args, Scopes *scopes, Node *result) { if (args->count != 1) { printf("'+' expects one argument!\n"); - return NULL; + return 0; } - Node *result = eval(&args->items[0], scopes); + eval_one(args->items[0], scopes, result); node_print(*result); printf("\n"); - return result; + return 1; } -Node *lisp_function_list(Nodes *args, Scopes *scopes) { +int lisp_function_list(Nodes *args, Scopes *scopes, Node *result) { UNUSED(scopes); - Node *node = malloc(sizeof(Node)); - node->kind = NODE_KIND_LIST; - node->as_list = args; - return node; + result->kind = NODE_KIND_LIST; + result->as_list = args; + return 0; } -Node *lisp_function_append(Nodes *args, Scopes *scopes) { +int lisp_function_append(Nodes *args, Scopes *scopes, Node *result) { UNUSED(scopes); if (args->count != 2) { printf("'append' expects two arguments!\n"); - return NULL; + return 1; } - Node *node = malloc(sizeof(Node)); - node->kind = NODE_KIND_LIST; - if (args->items[0].kind != NODE_KIND_LIST || args->items[1].kind != NODE_KIND_LIST) { printf("'append' can only append two lists!\n"); - return NULL; + return 1; } Nodes *nodes = malloc(sizeof(Nodes)); + memset(nodes, 0, sizeof(Nodes)); Nodes *a = args->items[0].as_list; nob_da_append_many(nodes, a->items, a->count); @@ -82,62 +79,60 @@ Node *lisp_function_append(Nodes *args, Scopes *scopes) { Nodes *b = args->items[1].as_list; nob_da_append_many(nodes, b->items, b->count); - node->as_list = nodes; - return node; + result->as_list = nodes; + result->kind = NODE_KIND_LIST; + return 0; } -Node *lisp_function_length(Nodes *args, Scopes *scopes) { +int lisp_function_length(Nodes *args, Scopes *scopes, Node *result) { UNUSED(scopes); if (args->count != 1) { printf("'length' expects one argument!\n"); - return NULL; + return 1; } if (args->items[0].kind != NODE_KIND_LIST) { printf("'length' can only be used on lists!\n"); - return NULL; + return 1; } - Node *node = malloc(sizeof(Node)); - node->kind = NODE_KIND_NUMBER; - node->as_number = args->items[0].as_list->count; - return node; + result->kind = NODE_KIND_NUMBER; + result->as_number = args->items[0].as_list->count; + return 0; } -Node *lisp_function_isnull(Nodes *args, Scopes *scopes) { +int lisp_function_isnull(Nodes *args, Scopes *scopes, Node *result) { UNUSED(scopes); if (args->count != 1) { printf("'null?' expects one argument!\n"); - return NULL; + return 1; } if (args->items[0].kind != NODE_KIND_LIST) { printf("'null?' can only be used on lists!\n"); - return NULL; + return 1; } - Node *node = malloc(sizeof(Node)); - node->kind = NODE_KIND_NUMBER; - node->as_number = args->items[0].as_list->count == 0 ? 1 : 0; - return node; + result->kind = NODE_KIND_NUMBER; + result->as_number = args->items[0].as_list->count == 0 ? 1 : 0; + return 0; } -Node *lisp_function_builtins(Nodes *args, Scopes *scopes) { +int lisp_function_builtins(Nodes *args, Scopes *scopes, Node *result) { if (args->count != 0) { printf("'builtins' expects no arguments!\n"); - return NULL; + return 1; } - Node *node = malloc(sizeof(Node)); - node->kind = NODE_KIND_LIST; - - Scope global_scope = nob_da_first(scopes); + Scope *global_scope = nob_da_first(scopes); Nodes *nodes = malloc(sizeof(Node)); - nob_da_foreach(ScopeObject, scope_object, &global_scope) { + nob_da_foreach(ScopeObject, scope_object, global_scope) { nob_da_append(nodes, scope_object->node); } - node->as_list = nodes; - return node; + + result->as_list = nodes; + result->kind = NODE_KIND_LIST; + return 0; } diff --git a/lisp.c b/lisp.c index d354eed..826a6b2 100644 --- a/lisp.c +++ b/lisp.c @@ -2,17 +2,18 @@ static Scope globalScope = {0}; -static Node *scope_lookup(Scopes *scopes, Nob_String_View name) { - nob_da_foreach(Scope, scope, scopes) { - nob_da_foreach(ScopeObject, scopeObject, scope) { +static int scope_lookup(Scopes *scopes, Nob_String_View name, Node *result) { + nob_da_foreach(Scope *, scope, scopes) { + nob_da_foreach(ScopeObject, scopeObject, *scope) { if (nob_sv_eq(name, scopeObject->name)) { - return &scopeObject->node; + *result = scopeObject->node; + return 0; } } } printf("Undefined symbol: '" SV_Fmt "'!\n", SV_Arg(name)); - return NULL; + return 1; } static void scope_add_function(Scope *scope, const char *name, @@ -57,7 +58,7 @@ void build_scopes(Scopes *scopes) { scope_add_function(&globalScope, "builtins", lisp_function_builtins); // clang-format on - nob_da_append(scopes, globalScope); + nob_da_append(scopes, &globalScope); } const char *token_kind_name(TokenKind kind) { @@ -157,51 +158,47 @@ void tokenize(Nob_String_View content, Tokens *tokens) { } } -Node *parse(Tokens *tokens) { - if (tokens->count == 0) { +int parse_one(Tokens *tokens, Node *node) { + if (tokens == NULL || node == NULL || tokens->count == 0) { printf("unexpected end of input"); - return NULL; + return 1; } Token tok = tokens->items[0]; tokens->items++; tokens->count--; - Node *node = malloc(sizeof(Node)); - if (tok.kind == TOKEN_KIND_PAR_LEFT) { + switch (tok.kind) { + case TOKEN_KIND_PAR_LEFT: { Nodes *nodes = malloc(sizeof(Nodes)); memset(nodes, 0, sizeof(Nodes)); while (true) { if (tokens->count == 0) { printf("expected closing ')'"); - return NULL; + return 1; } if (tokens->items[0].kind == TOKEN_KIND_PAR_RIGHT) { tokens->items++; tokens->count--; + + if (tokens->count > 0) { + } break; } - Node *node = parse(tokens); - if (node == NULL) - return NULL; - + parse_one(tokens, node); nob_da_append(nodes, *node); } node->kind = NODE_KIND_LIST; node->as_list = nodes; - return node; - } - - if (tok.kind == TOKEN_KIND_PAR_RIGHT) { + } break; + case TOKEN_KIND_PAR_RIGHT: { printf("unexpected ')'"); - return NULL; + return 1; } - - switch (tok.kind) { case TOKEN_KIND_NUMBER: { long long num = strtoll(tok.data.data, NULL, 10); // TODO: @@ -219,56 +216,135 @@ Node *parse(Tokens *tokens) { UNREACHABLE(""); } break; } - return node; + return 0; } -Node *eval(Node *node, Scopes *scopes) { - if (node == NULL || scopes == NULL) - return NULL; +void parse(Tokens *tokens, Nodes *nodes) { + if (nodes == NULL) + return; - switch (node->kind) { + for (size_t i = 0; i < tokens->count; i++) { + if (tokens->items[i].kind == TOKEN_KIND_PAR_LEFT) { + size_t sub_size = tokens->count - i; + Tokens toks = {.count = sub_size, + .capacity = sub_size, + .items = tokens->items + i}; + Node result = {0}; + parse_one(&toks, &result); + nob_da_append(nodes, result); + } + } +} + +int eval_one(Node input, Scopes *scopes, Node *result) { + if (scopes == NULL || result == NULL) + return 1; + + switch (input.kind) { case NODE_KIND_NUMBER: - return node; + *result = input; + return 0; case NODE_KIND_SYMBOL: { - return scope_lookup(scopes, node->as_symbol); + return scope_lookup(scopes, input.as_symbol, result); } case NODE_KIND_LIST: { - Nodes *children = node->as_list; - if (children->count == 0) - return node; + Nodes *children = input.as_list; + if (children->count == 0) { + *result = input; + return 0; + } - Node *head = &children->items[0]; - if (head->kind != NODE_KIND_SYMBOL) - return node; + Node head = children->items[0]; + if (head.kind != NODE_KIND_SYMBOL) { + *result = input; + return 0; + } + + if (nob_sv_eq(head.as_symbol, + (Nob_String_View){.count = 2, .data = "if"})) { + if (children->count != 3 + 1) { + printf("'if' expects three arguments!\n"); + return 1; + } + + Node condition = {0}; + eval_one(children->items[0 + 1], scopes, &condition); + + if (node_is_true(condition)) { + eval_one(children->items[1 + 1], scopes, result); + } else { + eval_one(children->items[2 + 1], scopes, result); + } + return 0; + } + + if (nob_sv_eq(head.as_symbol, + (Nob_String_View){.count = 6, .data = "define"})) { + if (children->count != 2 + 1) { + printf("'define' expects two arguments!\n"); + return 1; + } + Node name_node = children->items[0 + 1]; + if (name_node.kind != NODE_KIND_SYMBOL) { + printf("First argument of 'define' must be a symbol!\n"); + return 1; + } + + Node value = {0}; + eval_one(children->items[1 + 1], scopes, &value); + + nob_da_foreach(ScopeObject, scope_object, &globalScope) { + if (nob_sv_eq(scope_object->name, name_node.as_symbol)) { + scope_object->node = value; + result = &children->items[0 + 1]; + return 0; + } + } + + ScopeObject obj = + (ScopeObject){.name = name_node.as_symbol, .node = value}; + nob_da_append(&globalScope, obj); + result = &children->items[0 + 1]; + return 0; + } Nodes *args = malloc(sizeof(Nodes)); for (size_t i = 1; i < children->count; i++) { - nob_da_append(args, *eval(&children->items[i], scopes)); + Node n = {0}; + eval_one(children->items[i], scopes, &n); + nob_da_append(args, n); } - if (nob_sv_eq(head->as_symbol, - (Nob_String_View){.count = 2, .data = "if"})) { - if (args->count != 3) { - printf("'if' expects three arguments!\n"); - return NULL; - } - Node *condition = eval(&args->items[0], scopes); - return node_is_true(*condition) ? eval(&args->items[1], scopes) - : eval(&args->items[2], scopes); - } else { - Node *func_node = eval(head, scopes); - if (func_node->kind == NODE_KIND_FUNCTION) { - return func_node->as_function.apply(args, scopes); - } - - printf("Not a function: '"); - node_print(*func_node); - printf("'\n"); - return NULL; + Node func_node = {0}; + int ret = eval_one(head, scopes, &func_node); + if (ret != 0) { + return ret; } + + if (func_node.kind == NODE_KIND_FUNCTION) { + func_node.as_function.apply(args, scopes, result); + return 0; + } + + printf("Not a function: '"); + node_print(func_node); + printf("'\n"); + return 1; } default: UNREACHABLE(""); } - return NULL; + return 0; +} + +int eval(Nodes *inputs, Scopes *scopes, Nodes *results) { + nob_da_foreach(Node, input, inputs) { + Node result = {0}; + int ret = 0; + if ((ret = eval_one(*input, scopes, &result)) != 0) { + return ret; + } + nob_da_append(results, result); + } + return 0; } diff --git a/lisp.h b/lisp.h index 3f6be09..873ef14 100644 --- a/lisp.h +++ b/lisp.h @@ -32,7 +32,7 @@ typedef struct s_Node Node; typedef struct s_Nodes Nodes; typedef struct s_Scopes Scopes; -typedef Node *(*LispFunction)(Nodes *args, Scopes *scopes); +typedef int (*LispFunction)(Nodes *args, Scopes *scopes, Node *result); struct s_Node { NodeKind kind; @@ -66,7 +66,7 @@ typedef struct s_Scope { } Scope; struct s_Scopes { - Scope *items; + Scope **items; size_t count; size_t capacity; }; @@ -76,27 +76,31 @@ void node_print(Node node); void build_scopes(Scopes *scopes); void tokenize(Nob_String_View content, Tokens *tokens); -Node *parse(Tokens *tokens); -Node *eval(Node *node, Scopes *scopes); + +int parse_one(Tokens *tokens, Node *node); +void parse(Tokens *tokens, Nodes *nodes); + +int eval_one(Node input, Scopes *scopes, Node *result); +int eval(Nodes *inputs, Scopes *scopes, Nodes *results); // builtins -Node *lisp_function_add(Nodes *args, Scopes *scopes); -Node *lisp_function_sub(Nodes *args, Scopes *scopes); -Node *lisp_function_div(Nodes *args, Scopes *scopes); -Node *lisp_function_mul(Nodes *args, Scopes *scopes); -Node *lisp_function_mod(Nodes *args, Scopes *scopes); +int lisp_function_add(Nodes *args, Scopes *scopes, Node *result); +int lisp_function_sub(Nodes *args, Scopes *scope, Node *result); +int lisp_function_div(Nodes *args, Scopes *scope, Node *result); +int lisp_function_mul(Nodes *args, Scopes *scope, Node *result); +int lisp_function_mod(Nodes *args, Scopes *scope, Node *result); -Node *lisp_function_eq(Nodes *args, Scopes *scopes); -Node *lisp_function_lt(Nodes *args, Scopes *scopes); -Node *lisp_function_gt(Nodes *args, Scopes *scopes); -Node *lisp_function_lt_eq(Nodes *args, Scopes *scopes); -Node *lisp_function_gt_eq(Nodes *args, Scopes *scopes); +int lisp_function_eq(Nodes *args, Scopes *scope, Node *result); +int lisp_function_lt(Nodes *args, Scopes *scope, Node *result); +int lisp_function_gt(Nodes *args, Scopes *scope, Node *result); +int lisp_function_lt_eq(Nodes *args, Scopes *scope, Node *result); +int lisp_function_gt_eq(Nodes *args, Scopes *scope, Node *result); -Node *lisp_function_println(Nodes *args, Scopes *scopes); -Node *lisp_function_list(Nodes *args, Scopes *scopes); -Node *lisp_function_append(Nodes *args, Scopes *scopes); -Node *lisp_function_length(Nodes *args, Scopes *scopes); -Node *lisp_function_isnull(Nodes *args, Scopes *scopes); -Node *lisp_function_builtins(Nodes *args, Scopes *scopes); +int lisp_function_println(Nodes *args, Scopes *scopes, Node *result); +int lisp_function_list(Nodes *args, Scopes *scopes, Node *result); +int lisp_function_append(Nodes *args, Scopes *scope, Node *result); +int lisp_function_length(Nodes *args, Scopes *scope, Node *result); +int lisp_function_isnull(Nodes *args, Scopes *scope, Node *result); +int lisp_function_builtins(Nodes *args, Scopes *scopes, Node *result); #endif // LISP_H diff --git a/main.c b/main.c index 763ddca..220c2f7 100644 --- a/main.c +++ b/main.c @@ -40,14 +40,22 @@ int main(int argc, char **argv) { Scopes scopes = {0}; build_scopes(&scopes); - Node *result = parse(&tokens); - if (result == NULL) - return 1; + Nodes result = {0}; + parse(&tokens, &result); - result = eval(result, &scopes); - printf("= "); - node_print(*result); - printf("\n"); +#if 0 + nob_da_foreach(Node, node, &result) { + node_print(*node); + printf("\n"); + } +#endif + + Nodes evaluated = {0}; + int ret = eval(&result, &scopes, &evaluated); + nob_da_foreach(Node, node, &evaluated) { + node_print(*node); + printf("\n"); + } return 0; }