diff options
Diffstat (limited to 'uscript')
| -rw-r--r-- | uscript/parser.c | 39 | ||||
| -rw-r--r-- | uscript/us_debug.c | 3 | ||||
| -rw-r--r-- | uscript/val.c | 25 | ||||
| -rw-r--r-- | uscript/val.h | 10 | ||||
| -rw-r--r-- | uscript/vm.c | 62 | ||||
| -rw-r--r-- | uscript/xbytecode.h | 3 |
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) |
