summaryrefslogtreecommitdiff
path: root/com.c
diff options
context:
space:
mode:
authorubq323 <ubq323@ubq323.website>2024-07-03 11:52:13 +0100
committerubq323 <ubq323@ubq323.website>2024-07-03 11:52:13 +0100
commit9f4e10da9df486b4c048ec2fedbe28491059b739 (patch)
treef963a20550c8455e0b0d53b7c7067b6fa4ea6782 /com.c
parent70c782292f48358fc4d3ac3874ac1951b405de48 (diff)
add defn form
Diffstat (limited to 'com.c')
-rw-r--r--com.c35
1 files changed, 35 insertions, 0 deletions
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)