diff options
Diffstat (limited to 'com.c')
-rw-r--r-- | com.c | 35 |
1 files changed, 35 insertions, 0 deletions
@@ -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) |