summaryrefslogtreecommitdiff
path: root/com.c
diff options
context:
space:
mode:
authorubq323 <ubq323@ubq323.website>2024-07-01 20:49:14 +0100
committerubq323 <ubq323@ubq323.website>2024-07-01 21:17:44 +0100
commit629416ffb6e30836f4de4a0f2401ccd66b4ce4a6 (patch)
treecf7c27e0322338abd3291f3a7ac8d2a0e2bbba54 /com.c
parent4571c3cb409808942ecbe353b1ffa6794cabc557 (diff)
add numeric for form
Diffstat (limited to 'com.c')
-rw-r--r--com.c64
1 files changed, 64 insertions, 0 deletions
diff --git a/com.c b/com.c
index 310117a..2c44883 100644
--- a/com.c
+++ b/com.c
@@ -268,6 +268,8 @@ void while_form(Compiler *C, AstVec l, Op _, int flags) {
patch(C, ph_b, dest_b - ph_b - 2);
}
+
+
void arith_form(Compiler *C, AstVec l, Op op, int flags) {
compile_node(C, l.vals[1], 0);
compile_node(C, l.vals[2], 0);
@@ -339,6 +341,67 @@ void let_form(Compiler *C, AstVec l, Op _, int flags) {
end_scope(C);
}
+void for_form(Compiler *C, AstVec l, Op _, int flags) {
+ // (for (x n) ...)
+ CHECK(l.vals[1].ty == AST_LIST, "for needs binding list");
+ AstVec blist = l.vals[1].as.list;
+ CHECK(blist.len == 2, "for binding list must have length 2");
+ CHECK(blist.vals[0].ty == AST_IDENT, "can only bind to ident");
+ char *ivar = blist.vals[0].as.str;
+
+ begin_scope(C);
+
+ compile_opcode(C, OP_LOADK);
+ compile_byte(C, compile_constant(C, VAL_NUM(0)));
+ declare_local(C, ivar);
+ Local *loc = locate_local(C, ivar);
+ int islot = loc->slot;
+
+ compile_node(C, blist.vals[1], 0);
+ declare_local(C, "__max__");
+ loc = locate_local(C, "__max__");
+ int mslot = loc->slot;
+
+ // A
+ // getlocal ivar
+ // getlocal max
+ // cmp
+ // 0branch -> B
+ // body ...
+ // incr ivar
+ // redo -> A
+ // B:
+ // nil
+
+ size_t dest_A = BYTECODE(C).len;
+ compile_opcode(C, OP_GETLOCAL);
+ compile_byte(C, islot);
+ compile_opcode(C, OP_GETLOCAL);
+ compile_byte(C, mslot);
+ compile_opcode(C, OP_CMP);
+ compile_opcode(C, OP_0BRANCH);
+ size_t ph_B = placeholder(C);
+ compile_body(C, l, 2, flags & ~F_tail);
+ compile_opcode(C, OP_DROP);
+ compile_opcode(C, OP_GETLOCAL);
+ compile_byte(C, islot);
+ compile_opcode(C, OP_LOADK);
+ compile_byte(C, compile_constant(C, VAL_NUM(1)));
+ compile_opcode(C, OP_ADD);
+ compile_opcode(C, OP_SETLOCAL);
+ compile_opcode(C, islot);
+ compile_opcode(C, OP_REDO);
+ size_t ph_A = placeholder(C);
+ size_t dest_B = BYTECODE(C).len;
+ compile_opcode(C, OP_NIL);
+
+ patch(C, ph_A , ph_A - dest_A + 2);
+ patch(C, ph_B ,dest_B - ph_B - 2);
+
+ end_scope(C);
+}
+
+
void def_form(Compiler *C, AstVec l, Op _, int flags) {
CHECK(l.vals[1].ty == AST_IDENT, "def's first argument must be ident");
CHECK(flags & F_toplevel, "def only allowed at top level");
@@ -395,6 +458,7 @@ static BuiltinForm builtin_forms[] = {
{ "do", 1, true, do_form, 0 },
{ "if", 3, false, if_form, 0 },
{ "while", 2, true, while_form, 0 },
+ { "for", 2, true, for_form, 0 },
{ "fn", 2, true, fn_form, 0 },
{ "let", 2, true, let_form, 0 },
{ "def", 2, false, def_form, 0 },