diff --git a/builtins.c b/builtins.c index c229628..2ec8fbf 100644 --- a/builtins.c +++ b/builtins.c @@ -1,27 +1,39 @@ #include "lisp.h" -Node *lisp_function_addition(Nodes *args, Scopes *scopes) { - UNUSED(scopes); - - if (args->count != 2) { - printf("'+' expects two arguments!\n"); - return NULL; +#define func_arithmetic_ex(name, operator, operator_name) \ + Node *name(Nodes *args, Scopes *scopes) { \ + UNUSED(scopes); \ + if (args->count != 2) { \ + puts("'" operator_name "' expects two arguments!\n"); \ + return NULL; \ + } \ + 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; \ + } \ + 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; \ } +#define func_arithmetic(name, operator) \ + func_arithmetic_ex(name, operator, #operator) - if (args->items[0].kind != NODE_KIND_NUMBER || - args->items[1].kind != NODE_KIND_NUMBER) { - printf("'+' can only add numbers, you specified something else!\n"); - return NULL; - } - - Node *node = malloc(sizeof(Node)); - node->kind = NODE_KIND_NUMBER; - - intptr_t a = args->items[0].as_number; - intptr_t b = args->items[1].as_number; - node->as_number = a + b; - return node; -} +func_arithmetic(lisp_function_add, +); +func_arithmetic(lisp_function_sub, -); +func_arithmetic(lisp_function_div, /); +func_arithmetic(lisp_function_mul, *); +func_arithmetic(lisp_function_mod, %); +func_arithmetic_ex(lisp_function_eq, ==, "="); +func_arithmetic(lisp_function_lt, <); +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) { if (args->count != 1) { @@ -111,3 +123,21 @@ Node *lisp_function_isnull(Nodes *args, Scopes *scopes) { node->as_number = args->items[0].as_list->count == 0 ? 1 : 0; return node; } + +Node *lisp_function_builtins(Nodes *args, Scopes *scopes) { + if (args->count != 0) { + printf("'builtins' expects no arguments!\n"); + return NULL; + } + + Node *node = malloc(sizeof(Node)); + node->kind = NODE_KIND_LIST; + + Scope global_scope = nob_da_first(scopes); + Nodes *nodes = malloc(sizeof(Node)); + nob_da_foreach(ScopeObject, scope_object, &global_scope) { + nob_da_append(nodes, scope_object->node); + } + node->as_list = nodes; + return node; +} diff --git a/lisp.c b/lisp.c index ee61f40..d354eed 100644 --- a/lisp.c +++ b/lisp.c @@ -25,14 +25,36 @@ static void scope_add_function(Scope *scope, const char *name, nob_da_append(scope, obj); } +static bool node_is_true(Node node) { + switch (node.kind) { + case NODE_KIND_NUMBER: + return node.as_number != 0; + case NODE_KIND_LIST: + return node.as_list->count > 0; + default: + return true; + } +} + void build_scopes(Scopes *scopes) { // clang-format off - scope_add_function(&globalScope, "+", lisp_function_addition); + scope_add_function(&globalScope, "+", lisp_function_add); + scope_add_function(&globalScope, "-", lisp_function_sub); + scope_add_function(&globalScope, "/", lisp_function_div); + scope_add_function(&globalScope, "*", lisp_function_mul); + scope_add_function(&globalScope, "%", lisp_function_mod); + scope_add_function(&globalScope, "=", lisp_function_eq); + scope_add_function(&globalScope, "<", lisp_function_lt); + scope_add_function(&globalScope, ">", lisp_function_gt); + scope_add_function(&globalScope, "<=", lisp_function_lt_eq); + scope_add_function(&globalScope, ">=", lisp_function_gt_eq); + scope_add_function(&globalScope, "println", lisp_function_println); scope_add_function(&globalScope, "list", lisp_function_list); scope_add_function(&globalScope, "append", lisp_function_append); scope_add_function(&globalScope, "length", lisp_function_length); scope_add_function(&globalScope, "null?", lisp_function_isnull); + scope_add_function(&globalScope, "builtins", lisp_function_builtins); // clang-format on nob_da_append(scopes, globalScope); @@ -216,21 +238,34 @@ Node *eval(Node *node, Scopes *scopes) { return node; Node *head = &children->items[0]; - Node *func_node = eval(head, scopes); + if (head->kind != NODE_KIND_SYMBOL) + return node; Nodes *args = malloc(sizeof(Nodes)); for (size_t i = 1; i < children->count; i++) { nob_da_append(args, *eval(&children->items[i], scopes)); } - if (func_node->kind == NODE_KIND_FUNCTION) { - return func_node->as_function.apply(args, scopes); - } + 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; + printf("Not a function: '"); + node_print(*func_node); + printf("'\n"); + return NULL; + } } default: UNREACHABLE(""); diff --git a/lisp.h b/lisp.h index 53f6b78..3f6be09 100644 --- a/lisp.h +++ b/lisp.h @@ -80,11 +80,23 @@ Node *parse(Tokens *tokens); Node *eval(Node *node, Scopes *scopes); // builtins -Node *lisp_function_addition(Nodes *args, Scopes *scopes); +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); + +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); + 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); #endif // LISP_H