summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile4
-rw-r--r--com.c3
-rw-r--r--lib.c44
-rw-r--r--lib.h8
-rw-r--r--util.h2
-rw-r--r--val.c5
-rw-r--r--val.h7
-rw-r--r--vm.c32
8 files changed, 89 insertions, 16 deletions
diff --git a/Makefile b/Makefile
index 6a04158..f1d189a 100644
--- a/Makefile
+++ b/Makefile
@@ -1,5 +1,5 @@
-CS=ast.c com.c dis.c ht.c mem.c prs.c state.c val.c vm.c
-HS=ast.h chunk.h com.h dis.h ht.h mem.h prs.h state.h util.h val.h vm.h
+CS=ast.c com.c dis.c ht.c lib.c mem.c prs.c state.c val.c vm.c
+HS=ast.h chunk.h com.h dis.h ht.h lib.h mem.h prs.h state.h util.h val.h vm.h
CFLAGS=$(EXTRA_CFLAGS) -g -O3 -lm -Wall -Wpedantic -Werror=implicit-function-declaration
bth: $(CS) $(HS) Makefile
diff --git a/com.c b/com.c
index 73d7e46..fcb4fdf 100644
--- a/com.c
+++ b/com.c
@@ -8,6 +8,7 @@
#include "ast.h"
#include "util.h"
#include "prs.h"
+#include "lib.h"
#define BYTECODE(C) (C->ch->bc)
@@ -517,6 +518,8 @@ int main(int argc, char **argv) {
th.ch = &ch;
S->th = &th;
+ load_stdlib(S);
+
return runvm(S);
}
#undef CHECK
diff --git a/lib.c b/lib.c
new file mode 100644
index 0000000..fe87abf
--- /dev/null
+++ b/lib.c
@@ -0,0 +1,44 @@
+#include <time.h>
+
+#include "lib.h"
+#include "state.h"
+#include "val.h"
+#include "util.h"
+
+static Val fn_clock(State *S, int nargs, Val *args) {
+ return VAL_NUM((double)clock() / CLOCKS_PER_SEC);
+}
+
+static Val fn_write(State *S, int nargs, Val *args) {
+ CHECK(nargs>0, "need 1 arg to write");
+ print_val(args[0]);
+ return VAL_NIL;
+}
+static Val fn_say(State *S, int nargs, Val *args) {
+ CHECK(nargs>0, "need 1 arg to say");
+ println_val(args[0]);
+ return VAL_NIL;
+}
+
+
+
+
+typedef struct {
+ char *name;
+ CFunc func;
+} BuiltinFunc;
+static BuiltinFunc builtin_funcs[] = {
+ { "clock", fn_clock },
+ { "say", fn_say },
+ { "write", fn_write },
+ { 0 },
+};
+
+void load_stdlib(State *S) {
+ for (BuiltinFunc *b = builtin_funcs; b->name != NULL; b++) {
+ ObjString *oname = objstring_copy_cstr(S, b->name);
+ ht_put(S, &S->globals, oname, VAL_CFUNC(b->func));
+ }
+}
+
+
diff --git a/lib.h b/lib.h
new file mode 100644
index 0000000..a82dbd9
--- /dev/null
+++ b/lib.h
@@ -0,0 +1,8 @@
+#ifndef _lib_h
+#define _lib_h
+
+#include "state.h"
+
+void load_stdlib(State *S);
+
+#endif
diff --git a/util.h b/util.h
index b0f2658..7cbfa44 100644
--- a/util.h
+++ b/util.h
@@ -1,6 +1,8 @@
#ifndef _util_h
#define _util_h
+#include <stdio.h>
+
#define CHECK(cond, ...) do { if (!(cond)) { fprintf(stderr, __VA_ARGS__); exit(1); } } while(0)
#define ERROR(...) CHECK(false, __VA_ARGS__)
diff --git a/val.c b/val.c
index ec200d3..7c8b25a 100644
--- a/val.c
+++ b/val.c
@@ -76,6 +76,9 @@ void print_val(Val v) {
break;
}
break;
+ case TY_CFUNC:
+ printf("[cfunc]");
+ break;
}
}
@@ -98,6 +101,7 @@ bool val_equal(Val a, Val b) {
case TY_NUM: return AS_NUM(a) == AS_NUM(b);
case TY_BOOL: return AS_BOOL(a) == AS_BOOL(b);
case TY_OBJ: return AS_OBJ(a) == AS_OBJ(b);
+ case TY_CFUNC: return AS_CFUNC(a) == AS_CFUNC(b);
default: return false;
}
}
@@ -114,6 +118,7 @@ const char *typename_str(Val v) {
case OTY_FUNC: return "Func";
}
break;
+ case TY_CFUNC: return "cfunc";
}
return "???";
}
diff --git a/val.h b/val.h
index 4ee76d2..90b60f2 100644
--- a/val.h
+++ b/val.h
@@ -7,13 +7,16 @@
typedef struct _val Val;
typedef struct _obj Obj;
+typedef struct _state State;
+typedef Val (*CFunc)(State *S, int nargs, Val *args);
typedef enum {
TY_NIL,
TY_NUM,
TY_BOOL,
TY_OBJ,
+ TY_CFUNC,
} ValTy;
typedef struct _val {
@@ -22,6 +25,7 @@ typedef struct _val {
double d;
bool b;
Obj *o;
+ CFunc f;
} as;
} Val;
@@ -71,6 +75,7 @@ ObjFunc *objfunc_new(State *S, uint8_t arity);
#define IS_NUM(x) (x.ty == TY_NUM)
#define IS_BOOL(x) (x.ty == TY_BOOL)
#define IS_OBJ(x) (x.ty == TY_OBJ)
+#define IS_CFUNC(x) (x.ty == TY_CFUNC)
#define IS_STRING(x) (is_obj_ty((x), OTY_STRING))
#define IS_FUNC(x) (is_obj_ty((x), OTY_FUNC))
@@ -78,6 +83,7 @@ ObjFunc *objfunc_new(State *S, uint8_t arity);
#define AS_NUM(x) (x.as.d)
#define AS_BOOL(x) (x.as.b)
#define AS_OBJ(x) (x.as.o)
+#define AS_CFUNC(x) (x.as.f)
#define AS_STRING(x) ((ObjString*)AS_OBJ(x))
#define AS_CSTRING(x) (AS_STRING(x)->d)
@@ -89,6 +95,7 @@ ObjFunc *objfunc_new(State *S, uint8_t arity);
#define VAL_TRUE VAL_BOOL(1)
#define VAL_FALSE VAL_BOOL(0)
#define VAL_OBJ(x) ((Val){.ty=TY_OBJ, .as.o=(Obj*)(x) })
+#define VAL_CFUNC(x) ((Val){.ty=TY_CFUNC, .as.f=(CFunc)(x)})
static inline bool is_obj_ty(Val v, ObjTy t) {
return IS_OBJ(v) && (AS_OBJ(v)->oty == t);
diff --git a/vm.c b/vm.c
index a5ffbc6..34660de 100644
--- a/vm.c
+++ b/vm.c
@@ -184,21 +184,25 @@ int runvm(State *S) {
uint8_t len = RBYTE();
Val callee = PEEKN(len);
- if (!IS_FUNC(callee)) {
- fprintf(stderr,"can only call functions");
- exit(1);
- }
- ObjFunc *func = AS_FUNC(callee);
-
- StackFrame *sf = &th->rstack[th->rsp++];
- sf->ip = th->ip;
- sf->ch = th->ch;
- sf->fp = th->fp;
-
- th->ip = 0;
- th->ch = &func->ch;
- th->fp = th->sp - len;
+ if (IS_FUNC(callee)) {
+ ObjFunc *func = AS_FUNC(callee);
+
+ StackFrame *sf = &th->rstack[th->rsp++];
+ sf->ip = th->ip;
+ sf->ch = th->ch;
+ sf->fp = th->fp;
+
+ th->ip = 0;
+ th->ch = &func->ch;
+ th->fp = th->sp - len;
+ } else if (IS_CFUNC(callee)) {
+ int nargs = len - 1;
+ Val *firstarg = &th->stack[th->sp - nargs];
+ Val res = AS_CFUNC(callee)(S, len - 1, firstarg);
+ th->sp -= len;
+ PUSH(res);
+ }
break;
}