summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--chunk.h25
-rw-r--r--com.c44
-rw-r--r--com.h18
-rw-r--r--dis.c11
-rw-r--r--val.c6
-rw-r--r--val.h1
6 files changed, 98 insertions, 7 deletions
diff --git a/chunk.h b/chunk.h
new file mode 100644
index 0000000..afefda0
--- /dev/null
+++ b/chunk.h
@@ -0,0 +1,25 @@
+#ifndef _chunk_h
+#define _chunk_h
+
+typedef struct _chunk Chunk;
+typedef struct _compiler Compiler;
+typedef struct _state State;
+
+
+struct _chunk {
+ struct {
+ size_t len;
+ size_t cap;
+ uint8_t *d;
+ } bc;
+ struct {
+ size_t len;
+ size_t cap;
+ Val *d;
+ } consts;
+};
+Chunk chunk_new(State *S);
+size_t chunk_wbc(Compiler *C, uint8_t byte);
+size_t chunk_wconst(Compiler *C, Val v);
+
+#endif
diff --git a/com.c b/com.c
index 4f377ce..92f0d80 100644
--- a/com.c
+++ b/com.c
@@ -27,7 +27,16 @@ Chunk chunk_new(State *S) {
return (Chunk){ 0 };
}
+Compiler compiler_new(Compiler *outer, Chunk *ch) {
+ return (Compiler){
+ .S = outer->S,
+ .ch = ch,
+ };
+}
+
+
size_t chunk_wbc(Compiler *C, uint8_t byte) {
+ printf("\t%p %hd\n",C, byte);
Chunk *ch = C->ch;
if (ch->bc.len == ch->bc.cap) {
size_t newsz = (ch->bc.cap == 0 ? 8 : ch->bc.cap * 2);
@@ -76,7 +85,7 @@ void single_form(Compiler *C, AstVec l, Op op) {
chunk_wbc(C, op);
}
-void set_form(Compiler *C, AstVec l, Op op) {
+void set_form(Compiler *C, AstVec l, Op _) {
AstNode ident = l.vals[1];
if (ident.ty != AST_IDENT) {
fprintf(stderr, "set's first argument must be identifier");
@@ -88,7 +97,7 @@ void set_form(Compiler *C, AstVec l, Op op) {
chunk_wbc(C, chunk_wconst(C, VAL_OBJ(o)));
}
-void do_form(Compiler *C, AstVec l, Op op) {
+void do_form(Compiler *C, AstVec l, Op _) {
for (int i = 1; i < l.len - 1; i++) {
compile_node(C, l.vals[i]);
chunk_wbc(C, OP_DROP);
@@ -96,7 +105,7 @@ void do_form(Compiler *C, AstVec l, Op op) {
compile_node(C, l.vals[l.len - 1]);
}
-void if_form(Compiler *C, AstVec l, Op op) {
+void if_form(Compiler *C, AstVec l, Op _) {
// (if cond if-true if-false)
// cond
// 0branch ->A
@@ -118,7 +127,7 @@ void if_form(Compiler *C, AstVec l, Op op) {
patch(C, ph_b, dest_b - ph_b - 2);
}
-void while_form(Compiler *C, AstVec l, Op op) {
+void while_form(Compiler *C, AstVec l, Op _) {
// (while cond body ...)
// A:
// cond
@@ -150,9 +159,29 @@ void arith_form(Compiler *C, AstVec l, Op op) {
chunk_wbc(C, op);
}
-// void fn_form(Compiler *C, AstVec l, Op op) {
-// Compiler subcompiler = compiler_new(C);
-
+void fn_form(Compiler *C, AstVec l, Op op) {
+ // (fn (arg arg arg) body ...)
+ if (l.vals[1].ty != AST_LIST) {
+ fprintf(stderr, "fn's first argument must be list");
+ exit(1);
+ }
+ AstVec arglist = l.vals[1].as.list;
+
+ ObjFunc *func = objfunc_new(C->S);
+ Compiler subcompiler = compiler_new(C, &func->chunk);
+
+ for (int i = 2; i < l.len - 1; i++) {
+ compile_node(&subcompiler, l.vals[i]);
+ chunk_wbc(&subcompiler, OP_DROP);
+ }
+ compile_node(&subcompiler, l.vals[l.len-1]);
+ chunk_wbc(&subcompiler, OP_RET);
+
+ chunk_wbc(C, OP_LOADK);
+ chunk_wbc(C, chunk_wconst(C, VAL_OBJ(func)));
+}
+
+
static BuiltinForm builtin_forms[] = {
{ "puts", 1, false, single_form, OP_PUTS },
@@ -161,6 +190,7 @@ static BuiltinForm builtin_forms[] = {
{ "do", 1, true, do_form, 0 },
{ "if", 3, false, if_form, 0 },
{ "while", 2, true, while_form, 0 },
+ { "fn", 2, true, fn_form, 0 },
#define ARITH_OP(str, op) \
{ str, 2, false, arith_form, op },
ARITH_OP("+", OP_ADD)
diff --git a/com.h b/com.h
new file mode 100644
index 0000000..f08769e
--- /dev/null
+++ b/com.h
@@ -0,0 +1,18 @@
+#ifndef _com_h
+#define _com_h
+
+typedef struct _compiler Compiler;
+
+#include "state.h"
+#include "chunk.h"
+
+
+struct _compiler {
+ State *S;
+ Chunk *ch;
+};
+Compiler compiler_new(Compiler *outer, Chunk *ch);
+
+#define BYTECODE(C) (C->ch->bc)
+
+#endif
diff --git a/dis.c b/dis.c
index ba0e1db..5097b05 100644
--- a/dis.c
+++ b/dis.c
@@ -87,6 +87,17 @@ void disasm_chunk(Chunk *ch) {
}
}
+ printf("\n");
+
+ for (uint8_t cix = 0; cix < ch->consts.len; cix++) {
+ Val c = ch->consts.d[cix];
+ if (IS_FUNC(c)) {
+ printf("const %d is function:\n", cix);
+ disasm_chunk(&AS_FUNC(c)->chunk);
+ }
+ }
+
+
}
diff --git a/val.c b/val.c
index ec3e636..621b073 100644
--- a/val.c
+++ b/val.c
@@ -47,6 +47,12 @@ static ObjString *objstring_create(State *S, char *src, size_t len, uint32_t has
return o;
}
+ObjFunc *objfunc_new(State *S) {
+ ObjFunc *o = NEW_OBJ(S, ObjFunc, OTY_FUNC);
+ o->chunk = chunk_new(S);
+ return o;
+}
+
void print_val(Val v) {
switch (v.ty) {
diff --git a/val.h b/val.h
index e4227a4..c71e419 100644
--- a/val.h
+++ b/val.h
@@ -72,6 +72,7 @@ ObjFunc *objfunc_new(State *S);
#define IS_OBJ(x) (x.ty == TY_OBJ)
#define IS_STRING(x) (is_obj_ty((x), OTY_STRING))
+#define IS_FUNC(x) (is_obj_ty((x), OTY_FUNC))
#define AS_NUM(x) (x.as.d)
#define AS_BOOL(x) (x.as.b)