From f331192861d8ba02af7fd47f2e0c6d6db7515007 Mon Sep 17 00:00:00 2001 From: ubq323 Date: Thu, 20 Jun 2024 23:26:18 +0100 Subject: add (if cond if-true if-false) builtin --- com.c | 55 +++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 45 insertions(+), 10 deletions(-) (limited to 'com.c') diff --git a/com.c b/com.c index 3d891f7..fef2dab 100644 --- a/com.c +++ b/com.c @@ -7,6 +7,19 @@ #include "read.h" #include "state.h" +static size_t placeholder(State *S, Chunk *ch) { + size_t old_ix = ch->bc.len; + chunk_wbc(S, ch, 0x00); + chunk_wbc(S, ch, 0x00); + return old_ix; +} + +static void patch(State *S, Chunk *ch, size_t addr, uint16_t val) { + ch->bc.d[addr] = val & 0xff; + ch->bc.d[addr+1] = (val & 0xff00) >> 8; +} + + static void compile_node(State *S, Chunk *ch, AstNode a) { switch (a.ty) { case AST_IDENT:; @@ -17,8 +30,7 @@ static void compile_node(State *S, Chunk *ch, AstNode a) { else if (0 == strcmp(ident, "nil")) chunk_wbc(S, ch, OP_NIL); else { // global read - size_t len = strlen(a.as.str); - ObjString *o = objstring_copy(S, a.as.str, len); + ObjString *o = objstring_copy_cstr(S, a.as.str); chunk_wbc(S, ch, OP_GETGLOBAL); chunk_wbc(S, ch, chunk_wconst(S, ch, VAL_OBJ(o))); } @@ -28,8 +40,7 @@ static void compile_node(State *S, Chunk *ch, AstNode a) { chunk_wbc(S, ch, chunk_wconst(S, ch, VAL_NUM(a.as.num))); break; case AST_STRING: { - size_t len = strlen(a.as.str); - ObjString *o = objstring_copy(S, a.as.str, len); + ObjString *o = objstring_copy_cstr(S, a.as.str); chunk_wbc(S, ch, OP_LOADK); chunk_wbc(S, ch, chunk_wconst(S, ch, VAL_OBJ(o))); break; @@ -37,29 +48,53 @@ static void compile_node(State *S, Chunk *ch, AstNode a) { case AST_LIST: { AstVec l = a.as.list; #define CK(cond, msg) if (!(cond)) { puts(msg); exit(1); } + CK(l.len > 0, "can't handle empty list"); CK(l.vals[0].ty == AST_IDENT, "can only call ops"); - if (0 == strcmp(l.vals[0].as.str, "print")) { + char *name = l.vals[0].as.str; + + if (0 == strcmp(name, "print")) { CK(l.len == 2, "print requires exactly 1 argument"); compile_node(S, ch, l.vals[1]); chunk_wbc(S, ch, OP_PRINT); - } else if (0 == strcmp(l.vals[0].as.str, "set")) { + } else if (0 == strcmp(name, "set")) { CK(l.len == 3, "set requires exactly 2 arguments"); AstNode ident = l.vals[1]; CK(ident.ty == AST_IDENT, "set's first argument must be identifier"); - size_t len = strlen(ident.as.str); - ObjString *o = objstring_copy(S, ident.as.str, len); - + ObjString *o = objstring_copy_cstr(S, ident.as.str); compile_node(S, ch, l.vals[2]); chunk_wbc(S, ch, OP_SETGLOBAL); chunk_wbc(S, ch, chunk_wconst(S, ch, VAL_OBJ(o))); - } else if (0 == strcmp(l.vals[0].as.str, "do")) { + } else if (0 == strcmp(name, "do")) { for (int i = 1; i < l.len - 1; i++) { compile_node(S, ch, l.vals[i]); chunk_wbc(S, ch, OP_DROP); } compile_node(S, ch, l.vals[l.len - 1]); + } else if (0 == strcmp(name, "if")) { + CK(l.len == 4, "if requires exactly 3 arguments"); + // (if cond if-true if-false) + // cond + // 0branch ->A + // if-true + // skip ->B + // A: if-false + // B: + compile_node(S, ch, l.vals[1]); + chunk_wbc(S, ch, OP_0BRANCH); + size_t ph1 = 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; + compile_node(S, ch, l.vals[3]); + size_t dest2 = ch->bc.len; + + patch(S, ch, ph1, dest1 - ph1 - 2); + patch(S, ch, ph2, dest2 - ph2 - 2); + + } else { CK(l.len == 3, "can only compile binary ops"); -- cgit v1.2.3