summaryrefslogtreecommitdiff
path: root/com.c
diff options
context:
space:
mode:
Diffstat (limited to 'com.c')
-rw-r--r--com.c189
1 files changed, 116 insertions, 73 deletions
diff --git a/com.c b/com.c
index c68e663..3e97c55 100644
--- a/com.c
+++ b/com.c
@@ -2,28 +2,62 @@
#include <string.h>
#include <stdio.h>
-#include "vm.h"
-#include "ast.h"
-#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);
+#include "com.h"
+
+#define BYTECODE(C) (C->ch->bc)
+
+static size_t placeholder(Compiler *C) {
+ size_t old_ix = BYTECODE(C).len;
+ chunk_wbc(C, 0x00);
+ chunk_wbc(C, 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 patch(Compiler *C, size_t addr, uint16_t val) {
+ BYTECODE(C).d[addr] = val & 0xff;
+ BYTECODE(C).d[addr+1] = (val & 0xff00) >> 8;
+}
+
+
+Chunk chunk_new(State *S) {
+ return (Chunk){ 0 };
+}
+
+size_t chunk_wbc(Compiler *C, uint8_t byte) {
+ Chunk *ch = C->ch;
+ if (ch->bc.len == ch->bc.cap) {
+ size_t newsz = (ch->bc.cap == 0 ? 8 : ch->bc.cap * 2);
+ ch->bc.d = RENEW_ARR(C->S, ch->bc.d, uint8_t, ch->bc.cap, newsz);
+ ch->bc.cap = newsz;
+ }
+ size_t ix = ch->bc.len;
+ ch->bc.d[ix] = byte;
+ ch->bc.len ++;
+ return ix;
}
+size_t chunk_wconst(Compiler *C, Val v) {
+ Chunk *ch = C->ch;
+ for (int i = 0; i < ch->consts.len; i ++)
+ if (val_equal(v, ch->consts.d[i])) return i;
+
+ if (ch->consts.len == ch->consts.cap) {
+ size_t newsz = (ch->consts.cap == 0 ? 8 : ch->consts.cap *2);
+ ch->consts.d = RENEW_ARR(C->S, ch->consts.d, Val, ch->consts.cap, newsz);
+ ch->consts.cap = newsz;
+ }
+ size_t ix = ch->consts.len;
+ ch->consts.d[ix] = v;
+ ch->consts.len ++;
+ return ix;
+}
-static void compile_node(State *S, Chunk *ch, AstNode a);
-typedef void (*form_compiler)(State *S, Chunk *ch, AstVec l, Op op);
+
+static void compile_node(Compiler *C, AstNode a);
+
+typedef void (*form_compiler)(Compiler *C, AstVec l, Op op);
typedef struct {
char *name;
int min_params;
@@ -33,32 +67,32 @@ typedef struct {
} BuiltinForm;
-void single_form(State *S, Chunk *ch, AstVec l, Op op) {
- compile_node(S, ch, l.vals[1]);
- chunk_wbc(S, ch, op);
+void single_form(Compiler *C, AstVec l, Op op) {
+ compile_node(C, l.vals[1]);
+ chunk_wbc(C, op);
}
-void set_form(State *S, Chunk *ch, AstVec l, Op op) {
+void set_form(Compiler *C, AstVec l, Op op) {
AstNode ident = l.vals[1];
if (ident.ty != AST_IDENT) {
fprintf(stderr, "set's first argument must be identifier");
exit(1);
}
- 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)));
+ ObjString *o = objstring_copy_cstr(C->S, ident.as.str);
+ compile_node(C, l.vals[2]);
+ chunk_wbc(C, OP_SETGLOBAL);
+ chunk_wbc(C, chunk_wconst(C, VAL_OBJ(o)));
}
-void do_form(State *S, Chunk *ch, AstVec l, Op op) {
+void do_form(Compiler *C, AstVec l, Op op) {
for (int i = 1; i < l.len - 1; i++) {
- compile_node(S, ch, l.vals[i]);
- chunk_wbc(S, ch, OP_DROP);
+ compile_node(C, l.vals[i]);
+ chunk_wbc(C, OP_DROP);
}
- compile_node(S, ch, l.vals[l.len - 1]);
+ compile_node(C, l.vals[l.len - 1]);
}
-void if_form(State *S, Chunk *ch, AstVec l, Op op) {
+void if_form(Compiler *C, AstVec l, Op op) {
// (if cond if-true if-false)
// cond
// 0branch ->A
@@ -66,21 +100,21 @@ void if_form(State *S, Chunk *ch, AstVec l, Op op) {
// skip ->B
// A: if-false
// B:
- compile_node(S, ch, l.vals[1]);
- chunk_wbc(S, ch, OP_0BRANCH);
- size_t ph_a = placeholder(S, ch);
- compile_node(S, ch, l.vals[2]);
- chunk_wbc(S, ch, OP_SKIP);
- size_t ph_b = placeholder(S, ch);
- size_t dest_a = ch->bc.len;
- compile_node(S, ch, l.vals[3]);
- size_t dest_b = ch->bc.len;
-
- patch(S, ch, ph_a, dest_a - ph_a - 2);
- patch(S, ch, ph_b, dest_b - ph_b - 2);
+ compile_node(C, l.vals[1]);
+ chunk_wbc(C, OP_0BRANCH);
+ size_t ph_a = placeholder(C);
+ compile_node(C, l.vals[2]);
+ chunk_wbc(C, OP_SKIP);
+ size_t ph_b = placeholder(C);
+ size_t dest_a = BYTECODE(C).len;
+ compile_node(C, l.vals[3]);
+ size_t dest_b = BYTECODE(C).len;
+
+ patch(C, ph_a, dest_a - ph_a - 2);
+ patch(C, ph_b, dest_b - ph_b - 2);
}
-void while_form(State *S, Chunk *ch, AstVec l, Op op) {
+void while_form(Compiler *C, AstVec l, Op op) {
// (while cond body ...)
// A:
// cond
@@ -89,27 +123,27 @@ void while_form(State *S, Chunk *ch, AstVec l, Op op) {
// 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);
+ size_t dest_a = BYTECODE(C).len;
+ compile_node(C, l.vals[1]);
+ chunk_wbc(C, OP_0BRANCH);
+ size_t ph_b = placeholder(C);
for (int i = 2; i < l.len; i++) {
- compile_node(S, ch, l.vals[i]);
- chunk_wbc(S, ch, OP_DROP);
+ compile_node(C, l.vals[i]);
+ chunk_wbc(C, 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);
+ chunk_wbc(C, OP_REDO);
+ size_t ph_a = placeholder(C);
+ size_t dest_b = BYTECODE(C).len;
+ chunk_wbc(C, OP_NIL);
- patch(S, ch, ph_a, ph_a - dest_a + 2);
- patch(S, ch, ph_b, dest_b - ph_b - 2);
+ patch(C, ph_a, ph_a - dest_a + 2);
+ patch(C, ph_b, dest_b - ph_b - 2);
}
-void arith_form(State *S, Chunk *ch, AstVec l, Op op) {
- compile_node(S, ch, l.vals[1]);
- compile_node(S, ch, l.vals[2]);
- chunk_wbc(S, ch, op);
+void arith_form(Compiler *C, AstVec l, Op op) {
+ compile_node(C, l.vals[1]);
+ compile_node(C, l.vals[2]);
+ chunk_wbc(C, op);
}
static BuiltinForm builtin_forms[] = {
@@ -143,7 +177,7 @@ static BuiltinIdent builtin_idents[] = {
{ 0 },
};
-static void compile_node(State *S, Chunk *ch, AstNode a) {
+static void compile_node(Compiler *C, AstNode a) {
switch (a.ty) {
case AST_IDENT:;
char *ident = a.as.str;
@@ -155,22 +189,22 @@ static void compile_node(State *S, Chunk *ch, AstNode a) {
}
}
if (found_builtin != NULL) {
- chunk_wbc(S, ch, found_builtin->op);
+ chunk_wbc(C, found_builtin->op);
} else {
// read global variable
- 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)));
+ ObjString *o = objstring_copy_cstr(C->S, a.as.str);
+ chunk_wbc(C, OP_GETGLOBAL);
+ chunk_wbc(C, chunk_wconst(C, VAL_OBJ(o)));
}
break;
case AST_NUM:
- chunk_wbc(S, ch, OP_LOADK);
- chunk_wbc(S, ch, chunk_wconst(S, ch, VAL_NUM(a.as.num)));
+ chunk_wbc(C, OP_LOADK);
+ chunk_wbc(C, chunk_wconst(C, VAL_NUM(a.as.num)));
break;
case AST_STRING: {
- 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)));
+ ObjString *o = objstring_copy_cstr(C->S, a.as.str);
+ chunk_wbc(C, OP_LOADK);
+ chunk_wbc(C, chunk_wconst(C, VAL_OBJ(o)));
break;
}
case AST_LIST: {
@@ -179,6 +213,7 @@ static void compile_node(State *S, Chunk *ch, AstNode a) {
#define CK(cond, msg) if (!(cond)) { fputs(msg "\n", stderr); exit(1); }
CK(l.len > 0, "can't handle empty list");
CK(l.vals[0].ty == AST_IDENT, "can only call ops");
+ #undef CK
char *head = l.vals[0].as.str;
@@ -201,7 +236,7 @@ static void compile_node(State *S, Chunk *ch, AstNode a) {
exit(1);
}
- form->action(S, ch, l, form->op);
+ form->action(C, l, form->op);
} else {
fprintf(stderr, "unknown form %s\n", head);
exit(1);
@@ -215,10 +250,7 @@ static void compile_node(State *S, Chunk *ch, AstNode a) {
int main(int argc, char **argv) {
State st = state_new();
State *S = &st;
- Thread th = thread_new(S);
- st.th = &th;
Chunk ch = chunk_new(S);
- th.ch = &ch;
S->do_disasm = (argc > 1 && 0 == strcmp(argv[1], "-l"));
@@ -234,10 +266,21 @@ int main(int argc, char **argv) {
ht_put(S, &st.globals, o3, VAL_NUM(3));
AstNode an = read();
- compile_node(S, &ch, an);
- chunk_wbc(S, &ch, OP_PUTS);
- chunk_wbc(S, &ch, OP_RET);
+ Compiler com = (Compiler){
+ .S = S,
+ .ch = &ch,
+ };
+ Compiler *C = &com;
+ compile_node(C, an);
+
+
+ chunk_wbc(C, OP_PUTS);
+ chunk_wbc(C, OP_RET);
+
+ Thread th = thread_new(S);
+ th.ch = &ch;
+ S->th = &th;
return runvm(S);
}