summaryrefslogtreecommitdiff
path: root/com.c
diff options
context:
space:
mode:
Diffstat (limited to 'com.c')
-rw-r--r--com.c40
1 files changed, 34 insertions, 6 deletions
diff --git a/com.c b/com.c
index fef2dab..cfe4df5 100644
--- a/com.c
+++ b/com.c
@@ -83,17 +83,42 @@ static void compile_node(State *S, Chunk *ch, AstNode a) {
// B:
compile_node(S, ch, l.vals[1]);
chunk_wbc(S, ch, OP_0BRANCH);
- size_t ph1 = placeholder(S, ch);
+ size_t ph_a = placeholder(S, ch);
compile_node(S, ch, l.vals[2]);
chunk_wbc(S, ch, OP_SKIP);
- size_t ph2 = placeholder(S, ch);
- size_t dest1 = ch->bc.len;
+ size_t ph_b = placeholder(S, ch);
+ size_t dest_a = ch->bc.len;
compile_node(S, ch, l.vals[3]);
- size_t dest2 = ch->bc.len;
+ size_t dest_b = ch->bc.len;
- patch(S, ch, ph1, dest1 - ph1 - 2);
- patch(S, ch, ph2, dest2 - ph2 - 2);
+ patch(S, ch, ph_a, dest_a - ph_a - 2);
+ patch(S, ch, ph_b, dest_b - ph_b - 2);
+ } else if (0 == strcmp(name, "while")) {
+ CK(l.len >= 3, "while requires at least 2 arguments");
+ // (while cond body ...)
+ // A:
+ // cond
+ // 0branch ->B
+ // body ....
+ // redo ->A
+ // B:
+ // nil (while loop always returns nil)
+ size_t dest_a = ch->bc.len;
+ compile_node(S, ch, l.vals[1]);
+ chunk_wbc(S, ch, OP_0BRANCH);
+ size_t ph_b = placeholder(S, ch);
+ for (int i = 2; i < l.len; i++) {
+ compile_node(S, ch, l.vals[i]);
+ chunk_wbc(S, ch, OP_DROP);
+ }
+ chunk_wbc(S, ch, OP_REDO);
+ size_t ph_a = placeholder(S, ch);
+ size_t dest_b = ch->bc.len;
+ chunk_wbc(S, ch, OP_NIL);
+
+ patch(S, ch, ph_a, ph_a - dest_a + 2);
+ patch(S, ch, ph_b, dest_b - ph_b - 2);
} else {
@@ -106,6 +131,9 @@ static void compile_node(State *S, Chunk *ch, AstNode a) {
OP('-', OP_SUB)
OP('*', OP_MUL)
OP('/', OP_DIV)
+ OP('=', OP_EQU)
+ OP('<', OP_CMP)
+ OP('%', OP_MOD)
#undef OP
default:
printf("unkown op %s\n",l.vals[0].as.str);