summaryrefslogtreecommitdiff
path: root/uscript
diff options
context:
space:
mode:
Diffstat (limited to 'uscript')
-rw-r--r--uscript/parser.c39
-rw-r--r--uscript/us_debug.c3
-rw-r--r--uscript/val.c25
-rw-r--r--uscript/val.h10
-rw-r--r--uscript/vm.c62
-rw-r--r--uscript/xbytecode.h3
6 files changed, 141 insertions, 1 deletions
diff --git a/uscript/parser.c b/uscript/parser.c
index 857fad3..404e5e5 100644
--- a/uscript/parser.c
+++ b/uscript/parser.c
@@ -346,6 +346,29 @@ void parse_literal(struct parser *p)
}
static
+void parse_arr(struct parser *p)
+{
+ int arr_len = 0;
+ if (p->cur.kind != ']') {
+ do {
+ if (p->cur.kind == ']')
+ break;
+ expr(p);
+ arr_len++;
+ } while (consume(p, ','));
+ }
+
+ expect(p, ']', "unterminated array literal");
+
+ if (arr_len > UINT8_MAX) {
+ show_error(p, p->prev, "too many literals the array (max 255)");
+ }
+
+ parser_add_byte(p, BC_ARR);
+ parser_add_byte(p, (u8)arr_len);
+}
+
+static
void parse_ident(struct parser *p)
{
struct token ident = p->prev;
@@ -439,12 +462,26 @@ void parse_call(struct parser *p)
}
static
+void parse_index(struct parser *p)
+{
+ expr(p);
+ expect(p, ']', "expected ']'");
+
+ if (consume(p, '=')) {
+ expr(p);
+ parser_add_byte(p, BC_SET_INDEX);
+ } else {
+ parser_add_byte(p, BC_GET_INDEX);
+ }
+}
+
+static
struct expr expressions[] = {
['('] = {parse_grouping, parse_call, PREC_CALL},
[')'] = {NULL, NULL, PREC_NONE},
['{'] = {NULL, NULL, PREC_NONE},
['}'] = {NULL, NULL, PREC_NONE},
- ['['] = {NULL, NULL, PREC_NONE},
+ ['['] = {parse_arr, parse_index, PREC_CALL},
[']'] = {NULL, NULL, PREC_NONE},
[','] = {NULL, NULL, PREC_NONE},
[';'] = {NULL, NULL, PREC_NONE},
diff --git a/uscript/us_debug.c b/uscript/us_debug.c
index 8d5dfe3..d31669b 100644
--- a/uscript/us_debug.c
+++ b/uscript/us_debug.c
@@ -42,6 +42,7 @@ int print_instruction(struct us_proto *proto, int idx)
);
return idx + 2 + upvalc * 2;
}
+ case BC_ARR:
case BC_SET_UPVAL:
case BC_GET_UPVAL:
case BC_SET_LOCAL:
@@ -82,6 +83,8 @@ int print_instruction(struct us_proto *proto, int idx)
case BC_TRUE:
case BC_FALSE:
case BC_ZILCH:
+ case BC_GET_INDEX:
+ case BC_SET_INDEX:
case BC_POP:
case BC_POP_UPVAL:
case BC_ADD:
diff --git a/uscript/val.c b/uscript/val.c
index d713645..6b2fa9b 100644
--- a/uscript/val.c
+++ b/uscript/val.c
@@ -8,6 +8,7 @@
#define STR_NUM_FMT "%g"
#define STR_FUNC_FMT "<func %s: %p>"
+#define STR_ARR_FMT "<arr: %p>"
static
void init_obj(struct us_val val, struct us_obj *obj)
@@ -37,6 +38,14 @@ struct us_str *copy_str(const char *chars, int len)
return take_str(copy, len);
}
+struct us_arr *create_arr(void)
+{
+ struct us_arr *arr = mem_alloc(sizeof(struct us_arr));
+ arr->e = da_create(struct us_val, 0);
+ init_obj(wrap_arr(arr), &arr->header);
+ return arr;
+}
+
struct us_proto *create_proto(struct us_str *name)
{
struct us_proto *proto = mem_alloc(sizeof(struct us_proto));
@@ -78,6 +87,12 @@ void free_val(struct us_val v)
mem_free(str);
break;
}
+ case VAL_ARR: {
+ struct us_arr *arr = get_arr(v);
+ da_free(arr->e);
+ mem_free(arr);
+ break;
+ }
case VAL_PROTO: {
struct us_proto *proto = get_proto(v);
da_free(proto->bytecode);
@@ -123,6 +138,7 @@ bool vals_eql(struct us_val a, struct us_val b)
return a_str->len == b_str->len &&
memcmp(a_str->chars, b_str->chars, a_str->len) == 0;
}
+ case VAL_ARR:
case VAL_FUNC:
case VAL_UPVAL:
case VAL_PROTO: return get_obj(a) == get_obj(b);
@@ -171,6 +187,15 @@ char *val_to_str(struct us_val v, int *len_out)
*len_out = us_str->len;
return str;
}
+ case VAL_ARR: {
+ const struct us_arr *arr = get_arr(v);
+ int len = snprintf(NULL, 0, STR_ARR_FMT, (void*)arr);
+ char *str = mem_alloc(sizeof(char) * (len + 1));
+ snprintf(str, len + 1, STR_ARR_FMT, (void*)arr);
+ if (len_out)
+ *len_out = len;
+ return str;
+ }
case VAL_PROTO: {
const struct us_proto *proto = get_proto(v);
int len = snprintf(
diff --git a/uscript/val.h b/uscript/val.h
index 1c314e4..4a30880 100644
--- a/uscript/val.h
+++ b/uscript/val.h
@@ -7,6 +7,7 @@
#define get_bool(v) (v.dat.boolean)
#define get_obj(v) (v.dat.obj)
#define get_str(v) (v.dat.str)
+#define get_arr(v) (v.dat.arr)
#define get_proto(v) (v.dat.proto)
#define get_func(v) (v.dat.func)
#define get_upval(v) (v.dat.upval)
@@ -15,6 +16,7 @@
#define create_bool(b) ((struct us_val){.type=VAL_BOOL, .dat={.boolean=(b)}})
#define create_zilch() ((struct us_val){.type=VAL_ZILCH, .dat={.number=0}})
#define wrap_str(o) ((struct us_val){.type=VAL_STR, .dat={.str=(o)}})
+#define wrap_arr(o) ((struct us_val){.type=VAL_ARR, .dat={.arr=(o)}})
#define wrap_proto(o) ((struct us_val){.type=VAL_PROTO, .dat={.proto=(o)}})
#define wrap_func(o) ((struct us_val){.type=VAL_FUNC, .dat={.func=(o)}})
#define wrap_upval(o) ((struct us_val){.type=VAL_UPVAL, .dat={.upval=(o)}})
@@ -30,6 +32,7 @@ enum val_type {
// Do not place any new object types before VAL_STR. Object types are
// detected by doing a comparison with VAL_STR. See val_is_obj().
VAL_STR,
+ VAL_ARR,
VAL_PROTO,
VAL_FUNC,
VAL_UPVAL,
@@ -42,6 +45,7 @@ struct us_val {
bool boolean;
struct us_obj *obj;
struct us_str *str;
+ struct us_arr *arr;
struct us_proto *proto;
struct us_func *func;
struct us_upval *upval;
@@ -60,6 +64,11 @@ struct us_str {
size_t len;
};
+struct us_arr {
+ struct us_obj header;
+ struct us_val *e; // dyn_arr
+};
+
struct us_proto {
struct us_obj header;
const struct us_str *name;
@@ -87,6 +96,7 @@ struct us_upval {
struct us_str *take_str(char *chars, int len);
struct us_str *copy_str(const char *chars, int len);
+struct us_arr *create_arr(void);
struct us_proto *create_proto(struct us_str *name);
struct us_func *create_func(struct us_proto *proto);
struct us_upval *create_upval(struct us_val *val);
diff --git a/uscript/vm.c b/uscript/vm.c
index f9f1fe6..7a617dd 100644
--- a/uscript/vm.c
+++ b/uscript/vm.c
@@ -132,6 +132,22 @@ void us_exec(struct us_func *func)
case BC_FALSE: vm_push(create_bool(false)); break;
case BC_TRUE: vm_push(create_bool(true)); break;
case BC_ZILCH: vm_push(create_zilch()); break;
+ case BC_ARR: {
+ struct us_arr *arr = create_arr();
+ u8 arr_len = read_byte();
+ // elements are in reverse order, so we add them in the
+ // correct order, and pop them all off at the end
+ for (u8 i = 0; i < arr_len; i++) {
+ da_append(
+ struct us_val,
+ &arr->e,
+ *(vm.stacktop - arr_len + i)
+ );
+ }
+ vm.stacktop -= arr_len;
+ vm_push(wrap_arr(arr));
+ break;
+ }
case BC_SET_LOCAL:
vm.cf->stackbot[read_byte()] = vm_peek();
break;
@@ -144,6 +160,52 @@ void us_exec(struct us_func *func)
case BC_SET_UPVAL:
*func->upvals[read_byte()]->loc = vm_peek();
break;
+ case BC_SET_INDEX: {
+ struct us_val set_val = vm_pop();
+ struct us_val idx_val = vm_pop();
+ struct us_val arr_val = vm_pop();
+ if (idx_val.type != VAL_NUM)
+ log_fatal(1, "index type must be number");
+ if (arr_val.type != VAL_ARR)
+ log_fatal(1, "only arrays can be indexed");
+ int idx = (int)get_num(idx_val);
+ struct us_arr *arr = get_arr(arr_val);
+ if (idx < 0)
+ idx += da_len(arr->e);
+ if (idx < 0 || idx >= da_len(arr->e)) {
+ log_fatal(
+ 1,
+ "index out of range (%d/%d)",
+ idx,
+ da_len(arr->e) - 1
+ );
+ }
+ arr->e[idx] = set_val;
+ vm_push(set_val);
+ break;
+ }
+ case BC_GET_INDEX: {
+ struct us_val idx_val = vm_pop();
+ struct us_val arr_val = vm_pop();
+ if (idx_val.type != VAL_NUM)
+ log_fatal(1, "index type must be number");
+ if (arr_val.type != VAL_ARR)
+ log_fatal(1, "only arrays can be indexed");
+ int idx = (int)get_num(idx_val);
+ struct us_arr *arr = get_arr(arr_val);
+ if (idx < 0)
+ idx += da_len(arr->e);
+ if (idx < 0 || idx >= da_len(arr->e)) {
+ log_fatal(
+ 1,
+ "index out of range (%d/%d)",
+ idx,
+ da_len(arr->e) - 1
+ );
+ }
+ vm_push(arr->e[idx]);
+ break;
+ }
case BC_POP_UPVAL:
close_upvals(vm.stacktop - 1);
vm_pop();
diff --git a/uscript/xbytecode.h b/uscript/xbytecode.h
index 4372ea5..16ad7a3 100644
--- a/uscript/xbytecode.h
+++ b/uscript/xbytecode.h
@@ -4,10 +4,13 @@ BC(SMALL_INT)
BC(FALSE)
BC(TRUE)
BC(ZILCH)
+BC(ARR)
BC(GET_LOCAL)
BC(SET_LOCAL)
BC(GET_UPVAL)
BC(SET_UPVAL)
+BC(GET_INDEX)
+BC(SET_INDEX)
BC(POP)
BC(POP_UPVAL)
BC(ADD)