summaryrefslogtreecommitdiff
path: root/com.c
diff options
context:
space:
mode:
Diffstat (limited to 'com.c')
-rw-r--r--com.c55
1 files changed, 45 insertions, 10 deletions
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");