#include "lisp.h" 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; } } int special_form_if(Nodes args, Scopes *scopes, Node *result) { if (args.count != 3) { printf("'if' expects three arguments!\n"); return 1; } Node condition = {0}; int ret = eval_one(args.items[0 + 1], scopes, &condition); if (ret != 0) { return ret; } if (node_is_true(condition)) { ret = eval_one(args.items[1], scopes, result); } else { ret = eval_one(args.items[2], scopes, result); } return ret; } int special_form_define(Nodes args, Scopes *scopes, Node *result) { if (args.count != 2) { printf("'define' expects two arguments!\n"); return 1; } Node name_node = args.items[0]; if (name_node.kind != NODE_KIND_SYMBOL) { printf("First argument of 'define' must be a symbol!\n"); return 1; } Node value = {0}; int ret = eval_one(args.items[1], scopes, &value); if (ret != 0) { return ret; } Scope *global_scope = nob_da_first(scopes); nob_da_foreach(ScopeObject, scope_object, global_scope) { if (nob_sv_eq(scope_object->name, name_node.as_symbol)) { scope_object->node = value; *result = args.items[0]; return 0; } } ScopeObject obj = (ScopeObject){.name = name_node.as_symbol, .node = value}; nob_da_append(global_scope, obj); *result = args.items[0]; return 0; } int special_form_let(Nodes args, Scopes *scopes, Node *result) { if (args.count != 2) { printf("'let' expects two arguments!\n"); return 1; } Node definitions = args.items[0]; if (definitions.kind != NODE_KIND_LIST) { printf("First argument of 'let' must be a list!\n"); return 1; } Node expression = args.items[1]; if (expression.kind != NODE_KIND_LIST) { printf("Second argument of 'let' must be a list!\n"); return 1; } // it's fine to allocate this on the stack because we will throw // it off the scope stack after parsing 'let' anyways therefore // it'll outlive the recursive call Scope scope = {0}; nob_da_foreach(Node, def, definitions.as_list) { if (def->kind != NODE_KIND_LIST || def->as_list->count != 2 || def->as_list->items[0].kind != NODE_KIND_SYMBOL) { printf("'let' expects a list of key-value pairs, e.g. " "'(let ((x 42) (y 2)) (+ x y))'\n"); return 1; } Node key = def->as_list->items[0]; Node value_node = def->as_list->items[1]; Node value = {0}; int ret = eval_one(value_node, scopes, &value); if (ret != 0) return ret; ScopeObject obj = (ScopeObject){.name = key.as_symbol, .node = value}; nob_da_append(&scope, obj); } Node expression_value = {0}; { nob_da_append(scopes, &scope); int ret = eval_one(expression, scopes, &expression_value); if (ret != 0) { return ret; } UNUSED(nob_da_pop(scopes)); } *result = expression_value; return 0; } int special_form_lambda(Nodes args, Scopes *scopes, Node *result) { UNUSED(scopes); if (args.count != 2) { printf("'lambda' expects two argument!\n"); return 1; } Node params = args.items[0]; if (params.kind != NODE_KIND_LIST) { printf("'lambda' expects a list of parameters as the first " "argument!\n"); return 1; } nob_da_foreach(Node, node, params.as_list) { if (node->kind != NODE_KIND_SYMBOL) { printf("'lambda' expects a list of symbols " "(parameters) as " "the " "first argument!\n"); return 1; } } result->kind = NODE_KIND_LAMBDA; Nodes *params_list = malloc(sizeof(Nodes)); if (params_list == NULL) { printf("Failed to allocate memory, something is really " "wrong!\n"); return 1; } memcpy(params_list, params.as_list, sizeof(Nodes)); result->as_lambda.params = params_list; Node *body = malloc(sizeof(Node)); if (body == NULL) { printf("Failed to allocate memory, something is really " "wrong!\n"); return 1; } memcpy(body, &args.items[1], sizeof(Node)); result->as_lambda.body = body; return 0; }