diff --git a/lisp.c b/lisp.c index bdec395..d8b89e4 100644 --- a/lisp.c +++ b/lisp.c @@ -99,6 +99,8 @@ void node_print(Node node) { Nob_String_View func_name = node.as_function.name; printf(SV_Fmt, SV_Arg(func_name)); } break; + default: + UNREACHABLE("Unknown node type"); } } @@ -357,6 +359,67 @@ int eval_one(Node input, Scopes *scopes, Node *result) { return 0; } + if (nob_sv_eq(head.as_symbol, + (Nob_String_View){.count = 3, .data = "let"})) { + if (children->count != 2 + 1) { + printf("'let' expects two arguments!\n"); + return 1; + } + + Node definitions = children->items[0 + 1]; + if (definitions.kind != NODE_KIND_LIST) { + printf("First argument of 'let' must be a list!\n"); + return 1; + } + + Node expression = children->items[1 + 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; + } + Nodes args = {0}; for (size_t i = 1; i < children->count; i++) { Node n = {0};