From ca004156cbb1c525900f444994112fc17b71d63d Mon Sep 17 00:00:00 2001 From: iamcheeseman Date: Tue, 14 Apr 2026 12:44:25 -0400 Subject: microscript: add globals --- uscript/parser.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++---- uscript/us_debug.c | 6 ++++++ uscript/uscript.c | 5 +++++ uscript/vm.c | 19 +++++++++++++++++++ uscript/vm.h | 13 ++++++++++++- uscript/xbytecode.h | 2 ++ 6 files changed, 91 insertions(+), 5 deletions(-) (limited to 'uscript') diff --git a/uscript/parser.c b/uscript/parser.c index 404e5e5..89a8883 100644 --- a/uscript/parser.c +++ b/uscript/parser.c @@ -184,6 +184,21 @@ int find_local(struct func_parser *fp, struct token name) return -1; } +static +int find_global(struct token name) +{ + for (int i = da_len(vm.gstack) - 1; i >= 0; i--) { + struct global global = vm.gstack[i]; + if ( + (size_t)name.len == global.name->len && + memcmp(name.start, global.name->chars, name.len) == 0 + ) + return i; + } + + return -1; +} + static int find_upval(struct parser *p, struct func_parser *fp, struct token name) { @@ -383,6 +398,9 @@ void parse_ident(struct parser *p) } else if ((var = find_upval(p, p->fp, ident)) != -1) { setter = BC_SET_UPVAL; getter = BC_GET_UPVAL; + } else if ((var = find_global(ident)) != -1) { + setter = BC_SET_GLOBAL; + getter = BC_GET_GLOBAL; } if (var == -1) { @@ -396,7 +414,13 @@ void parse_ident(struct parser *p) } else { parser_add_byte(p, getter); } - parser_add_byte(p, (u8)var); + + if (setter == BC_SET_GLOBAL) { + parser_add_byte(p, (var >> 8) & 0xFF); + parser_add_byte(p, var & 0xFF); + } else { + parser_add_byte(p, (u8)var); + } } static @@ -576,7 +600,7 @@ void expr_stat(struct parser *p) } static -void let_stat(struct parser *p) +void var_def_stat(struct parser *p, bool is_global) { do { expect(p, TOKEN_IDENT, "expected variable name"); @@ -587,7 +611,16 @@ void let_stat(struct parser *p) else parser_add_byte(p, BC_ZILCH); - declare_variable(p, name); + if (is_global) { + struct us_str *ident = copy_str(name.start, name.len); + int idx = declare_global(ident); + parser_add_byte(p, BC_SET_GLOBAL); + parser_add_byte(p, (idx >> 8) & 0xFF); + parser_add_byte(p, idx & 0xFF); + parser_add_byte(p, BC_POP); // set global does not pop + } else { + declare_variable(p, name); + } } while (consume(p, ',')); } @@ -824,7 +857,17 @@ static void stat(struct parser *p) { if (consume(p, TOKEN_LET)) { - let_stat(p); + var_def_stat(p, false); + consume(p, ';'); + } else if (consume(p, TOKEN_GLOBAL)) { + if (!p->fp->is_script) { + show_error( + p, + p->cur, + "can only define globals in the outermost scope" + ); + } + var_def_stat(p, true); consume(p, ';'); } else if (consume(p, TOKEN_FUN)) { fun_stat(p); diff --git a/uscript/us_debug.c b/uscript/us_debug.c index 496b191..6b981a4 100644 --- a/uscript/us_debug.c +++ b/uscript/us_debug.c @@ -56,6 +56,12 @@ int print_instruction(struct us_proto *proto, int idx) ); return idx + 2; } + case BC_GET_GLOBAL: + case BC_SET_GLOBAL: { + u16 loc = (u16)(proto->bytecode[idx + 1] << 8) | proto->bytecode[idx + 2]; + fprintf(stderr, "%d\n", loc); + return idx + 3; + } case BC_JMP: case BC_FALSEY_JMP: case BC_LOOP: { diff --git a/uscript/uscript.c b/uscript/uscript.c index 5ec43a1..2b32110 100644 --- a/uscript/uscript.c +++ b/uscript/uscript.c @@ -32,3 +32,8 @@ void us_load_src(const char *src) return; us_exec(create_func(proto)); } + +int us_declare_global(const char *name) +{ + return declare_global(copy_str(name, -1)); +} diff --git a/uscript/vm.c b/uscript/vm.c index 7c2d85e..363912a 100644 --- a/uscript/vm.c +++ b/uscript/vm.c @@ -12,6 +12,7 @@ struct vm vm; void init_vm(void) { vm.objs = da_create(struct us_val, 128); + vm.gstack = da_create(struct global, 128); vm.cf = vm.cf_stack; vm.stacktop = vm.stack; } @@ -23,6 +24,8 @@ void deinit_vm(void) } da_clear(vm.objs); // not needed, but makes me feel better :) da_free(vm.objs); + + da_free(vm.gstack); } static @@ -154,6 +157,12 @@ void us_exec(struct us_func *func) case BC_SET_LOCAL: vm.cf->stackbot[read_byte()] = vm_peek(); break; + case BC_GET_GLOBAL: + vm_push(vm.gstack[read_short(func->proto, &i)].val); + break; + case BC_SET_GLOBAL: + vm.gstack[read_short(func->proto, &i)].val = vm_peek(); + break; case BC_GET_UPVAL: vm_push(*func->upvals[read_byte()]->loc); break; @@ -366,3 +375,13 @@ void us_exec(struct us_func *func) } } } + +int declare_global(struct us_str *name) +{ + int idx = da_len(vm.gstack); + struct global global; + global.name = name; + global.val = create_zilch(); + da_append(struct global, &vm.gstack, global); + return idx; +} diff --git a/uscript/vm.h b/uscript/vm.h index 15c21a0..2911d01 100644 --- a/uscript/vm.h +++ b/uscript/vm.h @@ -11,6 +11,8 @@ #define vm_peek() (vm.stacktop[-1]) #define vm_push(v) (*vm.stacktop++ = (v)) +#define set_global(idx, v) (vm.gstack[idx].val = (v)) + enum bytecode { #define BC(name) BC_##name, #include "xbytecode.h" @@ -22,16 +24,23 @@ struct call_frame { struct us_val *stackbot; }; +struct global { + struct us_str *name; + struct us_val val; +}; + struct vm { struct us_val *objs; struct call_frame cf_stack[MAX_CALL_FRAMES]; struct call_frame *cf; - struct us_val *global_stack; // dyn_arr struct us_val stack[STACK_SIZE]; struct us_val *stacktop; + struct global *gstack; // dynarr + struct global *gstacktop; + struct us_upval *open_upvals; }; @@ -41,4 +50,6 @@ void init_vm(void); void deinit_vm(void); void print_func(struct us_proto *proto); +int declare_global(struct us_str *name); + #endif // __USCRIPT_VM_H__ diff --git a/uscript/xbytecode.h b/uscript/xbytecode.h index 16ad7a3..95f1440 100644 --- a/uscript/xbytecode.h +++ b/uscript/xbytecode.h @@ -7,6 +7,8 @@ BC(ZILCH) BC(ARR) BC(GET_LOCAL) BC(SET_LOCAL) +BC(GET_GLOBAL) +BC(SET_GLOBAL) BC(GET_UPVAL) BC(SET_UPVAL) BC(GET_INDEX) -- cgit v1.3-2-g0d8e