From 9f4e10da9df486b4c048ec2fedbe28491059b739 Mon Sep 17 00:00:00 2001 From: ubq323 Date: Wed, 3 Jul 2024 11:52:13 +0100 Subject: add defn form --- com.c | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) (limited to 'com.c') diff --git a/com.c b/com.c index dbf07a4..19ea302 100644 --- a/com.c +++ b/com.c @@ -529,6 +529,40 @@ void fn_form(Compiler *C, AstVec l, Op _, int flags) { compile_byte(C, compile_constant(C, VAL_OBJ(func))); } +void defn_form(Compiler *C, AstVec l, Op _, int flags) { + // todo: reduce redundancy + CHECK(l.vals[1].ty == AST_LIST, "defns first arg must be list"); + AstVec blist = l.vals[1].as.list; + CHECK(blist.len > 0, "defn needs at least a function name"); + CHECK(blist.len <= 256, "maximum 255 args for function"); + CHECK(flags & F_toplevel, "defn only allowed at toplevel"); + uint8_t arity = blist.len - 1; + + CHECK(blist.vals[0].ty == AST_IDENT, "func name must be ident"); + char *fname = blist.vals[0].as.str; + + ObjFunc *func = objfunc_new(C->S, arity); + Compiler subcompiler = compiler_new(C, &func->ch); + Compiler *SC = &subcompiler; + begin_scope(SC); + SC->stack_cur ++; + declare_local(SC, fname); + for (int i = 0; i < arity; i++) { + AstNode argname = blist.vals[i+1]; + CHECK(argname.ty == AST_IDENT, "arg name must be identifier"); + SC->stack_cur ++; + declare_local(SC, argname.as.str); + } + compile_body(SC, l, 2, F_tail); + end_scope(SC); + compile_opcode(SC, OP_RET); + + compile_opcode(C, OP_LOADK); + compile_byte(C, compile_constant(C, VAL_OBJ(func))); + declare_local(C, fname); + compile_opcode(C, OP_NIL); +} + typedef struct { char *name; int min_params; @@ -547,6 +581,7 @@ static BuiltinForm builtin_forms[] = { { "fn", 2, true, fn_form, 0 }, { "let", 2, true, let_form, 0 }, { "def", 2, false, def_form, 0 }, + { "defn", 2, true, defn_form, 0 }, #define ARITH_OP(str, op) \ { str, 2, false, arith_form, op }, ARITH_OP("+", OP_ADD) -- cgit v1.2.3