summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorubq323 <ubq323@ubq323.website>2024-06-26 19:27:42 +0100
committerubq323 <ubq323@ubq323.website>2024-06-26 19:27:42 +0100
commit2e62b41072738142dea9f0b5dd5d2d22455c7616 (patch)
treef47ce547de39fb69b02eb70990c9485489f1e574
parent6deeb9630d4b4e7d672ab851dcd4fe3d0d3d2865 (diff)
add arrays, appending, getting length, indexing
-rw-r--r--lib.c24
-rw-r--r--tests/arr1.bth9
-rw-r--r--tests/arr1.out5
-rw-r--r--tests/nilcall.bth1
-rw-r--r--tests/nilcall.out1
-rw-r--r--util.h2
-rw-r--r--val.c54
-rw-r--r--val.h27
-rw-r--r--vm.c12
9 files changed, 125 insertions, 10 deletions
diff --git a/lib.c b/lib.c
index fe87abf..e070bc0 100644
--- a/lib.c
+++ b/lib.c
@@ -21,6 +21,26 @@ static Val fn_say(State *S, int nargs, Val *args) {
}
+// lists
+static Val fn_arr(State *S, int nargs, Val *args) {
+ CHECK(nargs == 0, "need 0 args to arr");
+ ObjArr *o = objarr_new(S);
+ return VAL_OBJ(o);
+}
+static Val fn_append(State *S, int nargs, Val *args) {
+ CHECK(nargs == 2, "need 2 args to append");
+ CHECK(IS_ARR(args[0]), "can only append to arr");
+ ObjArr *a = AS_ARR(args[0]);
+ objarr_append(S, a, args[1]);
+ return args[0];
+}
+static Val fn_len(State *S, int nargs, Val *args) {
+ CHECK(nargs == 1, "need 1 arg to len");
+ CHECK(IS_ARR(args[0]), "can only take length of arr");
+ ObjArr *a = AS_ARR(args[0]);
+ return VAL_NUM(a->len);
+}
+
typedef struct {
@@ -31,6 +51,10 @@ static BuiltinFunc builtin_funcs[] = {
{ "clock", fn_clock },
{ "say", fn_say },
{ "write", fn_write },
+
+ { "arr", fn_arr },
+ { "append", fn_append },
+ { "len", fn_len },
{ 0 },
};
diff --git a/tests/arr1.bth b/tests/arr1.bth
new file mode 100644
index 0000000..0d06759
--- /dev/null
+++ b/tests/arr1.bth
@@ -0,0 +1,9 @@
+(set A (arr))
+(say A)
+(say (len A))
+(append A 10)
+(append A 20)
+(append A 30)
+(say A)
+(say (len A))
+(say (A 1))
diff --git a/tests/arr1.out b/tests/arr1.out
new file mode 100644
index 0000000..3e5e246
--- /dev/null
+++ b/tests/arr1.out
@@ -0,0 +1,5 @@
+[ ]
+0
+[ 10 20 30 ]
+3
+20
diff --git a/tests/nilcall.bth b/tests/nilcall.bth
new file mode 100644
index 0000000..27ff7a2
--- /dev/null
+++ b/tests/nilcall.bth
@@ -0,0 +1 @@
+(nil 4)
diff --git a/tests/nilcall.out b/tests/nilcall.out
new file mode 100644
index 0000000..ba2231b
--- /dev/null
+++ b/tests/nilcall.out
@@ -0,0 +1 @@
+cannot call nil
diff --git a/util.h b/util.h
index 7cbfa44..076393e 100644
--- a/util.h
+++ b/util.h
@@ -3,7 +3,7 @@
#include <stdio.h>
-#define CHECK(cond, ...) do { if (!(cond)) { fprintf(stderr, __VA_ARGS__); exit(1); } } while(0)
+#define CHECK(cond, ...) do { if (!(cond)) { fprintf(stderr, __VA_ARGS__); putchar('\n'); exit(1); } } while(0)
#define ERROR(...) CHECK(false, __VA_ARGS__)
diff --git a/val.c b/val.c
index 7c8b25a..6562daa 100644
--- a/val.c
+++ b/val.c
@@ -3,6 +3,7 @@
#include "val.h"
#include "mem.h"
#include "ht.h"
+#include "util.h"
static ObjString *objstring_create(State*, char*, size_t, uint32_t);
@@ -55,7 +56,40 @@ ObjFunc *objfunc_new(State *S, uint8_t arity) {
}
-void print_val(Val v) {
+ObjArr *objarr_new(State *S) {
+ ObjArr *o = NEW_OBJ(S, ObjArr, OTY_ARR);
+ o->len = 0;
+ o->cap = 0;
+ o->d = NULL;
+ return o;
+}
+
+Val objarr_get(State *S, ObjArr *arr, size_t ix) {
+ CHECK(ix < arr->len, "array index out of bounds");
+ return arr->d[ix];
+}
+void objarr_append(State *S, ObjArr *arr, Val v) {
+ if (arr->len == arr->cap) {
+ size_t newsz = (arr->cap == 0 ? 8 : arr->cap * 2);
+ arr->d = RENEW_ARR(S, arr->d, Val, arr->cap, newsz);
+ arr->cap = newsz;
+ }
+ arr->d[arr->len++] = v;
+}
+void objarr_put(State *S, ObjArr *arr, size_t ix, Val v) {
+ CHECK(ix <= arr->len, "array index out of bounds");
+ if (ix == arr->len) {
+ objarr_append(S, arr, v);
+ } else {
+ arr->d[ix] = v;
+ }
+}
+
+static void print_val_h(Val v, int depth);
+void print_val(Val v) {
+ print_val_h(v, 8);
+}
+static void print_val_h(Val v, int depth) {
switch (v.ty) {
case TY_NIL:
printf("nil");
@@ -72,12 +106,25 @@ void print_val(Val v) {
printf("%s", AS_CSTRING(v));
break;
case OTY_FUNC:
- printf("[function Function]");
+ printf("<func>");
+ break;
+ case OTY_ARR:;
+ ObjArr *a = AS_ARR(v);
+ if (depth <= 0)
+ printf("<arr>");
+ else {
+ printf("[ ");
+ for (int i = 0; i < a->len; i++) {
+ print_val_h(a->d[i], depth-1);
+ printf(" ");
+ }
+ printf("]");
+ }
break;
}
break;
case TY_CFUNC:
- printf("[cfunc]");
+ printf("<cfunc>");
break;
}
}
@@ -116,6 +163,7 @@ const char *typename_str(Val v) {
switch (AS_OBJ(v)->oty) {
case OTY_STRING: return "String";
case OTY_FUNC: return "Func";
+ case OTY_ARR: return "Arr";
}
break;
case TY_CFUNC: return "cfunc";
diff --git a/val.h b/val.h
index 90b60f2..4f77828 100644
--- a/val.h
+++ b/val.h
@@ -41,6 +41,7 @@ bool val_equal(Val a, Val b);
typedef enum {
OTY_STRING,
OTY_FUNC,
+ OTY_ARR,
} ObjTy;
typedef struct _obj {
@@ -53,13 +54,8 @@ typedef struct {
uint32_t hash;
char *d;
} ObjString;
-#include "chunk.h"
-typedef struct {
- Obj obj;
- Chunk ch;
- uint8_t arity;
-} ObjFunc;
+#include "chunk.h"
// Constructs a new objstring from the given C string,
// creating its own fresh copy of the data.
@@ -69,8 +65,25 @@ ObjString *objstring_copy_cstr(State *s, char *str);
// taking ownership of the provided data.
ObjString *objstring_take(State *S, char *src, size_t len);
+typedef struct {
+ Obj obj;
+ Chunk ch;
+ uint8_t arity;
+} ObjFunc;
ObjFunc *objfunc_new(State *S, uint8_t arity);
+typedef struct {
+ Obj obj;
+ size_t len;
+ size_t cap;
+ Val *d;
+} ObjArr;
+
+ObjArr *objarr_new(State *S);
+Val objarr_get(State *S, ObjArr *arr, size_t ix);
+void objarr_append(State *S, ObjArr *arr, Val v);
+void objarr_put(State *S, ObjArr *arr, size_t ix, Val v);
+
#define IS_NIL(x) (x.ty == TY_NIL)
#define IS_NUM(x) (x.ty == TY_NUM)
#define IS_BOOL(x) (x.ty == TY_BOOL)
@@ -79,6 +92,7 @@ ObjFunc *objfunc_new(State *S, uint8_t arity);
#define IS_STRING(x) (is_obj_ty((x), OTY_STRING))
#define IS_FUNC(x) (is_obj_ty((x), OTY_FUNC))
+#define IS_ARR(x) (is_obj_ty((x), OTY_ARR))
#define AS_NUM(x) (x.as.d)
#define AS_BOOL(x) (x.as.b)
@@ -88,6 +102,7 @@ ObjFunc *objfunc_new(State *S, uint8_t arity);
#define AS_STRING(x) ((ObjString*)AS_OBJ(x))
#define AS_CSTRING(x) (AS_STRING(x)->d)
#define AS_FUNC(x) ((ObjFunc*)AS_OBJ(x))
+#define AS_ARR(x) ((ObjArr*)AS_OBJ(x))
#define VAL_NIL ((Val){.ty=TY_NIL})
#define VAL_NUM(x) ((Val){.ty=TY_NUM, .as.d=(x) })
diff --git a/vm.c b/vm.c
index b8fcbd6..679a6a5 100644
--- a/vm.c
+++ b/vm.c
@@ -10,6 +10,7 @@
#include "mem.h"
#include "dis.h"
#include "com.h"
+#include "util.h"
@@ -196,6 +197,17 @@ int runvm(State *S) {
Val res = AS_CFUNC(callee)(S, len - 1, firstarg);
th->sp -= len;
PUSH(res);
+ } else if (IS_ARR(callee)) {
+ ObjArr *arr = AS_ARR(callee);
+ CHECK(len == 2, "can only index arr with single argument");
+ Val vix = PEEK();
+ CHECK(IS_NUM(vix), "can only index numerically");
+ size_t ix = (size_t)AS_NUM(vix);
+ Val res = objarr_get(S, arr, ix);
+ th->sp -= 2;
+ PUSH(res);
+ } else {
+ ERROR("cannot call %s",typename_str(callee));
}
break;
}