summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoriamcheeseman <[email protected]>2026-04-16 16:13:52 -0400
committeriamcheeseman <[email protected]>2026-04-16 16:13:52 -0400
commiteb0e4255e9eb878b7a17830b5be06a71add3b34e (patch)
tree2714b598f43518348300f5dd5eedc2e5bd92a847
parent7663596a72347d8dab936c6503002d95149c04c9 (diff)
microscript: better runtime errors
-rw-r--r--uscript/uscript.c6
-rw-r--r--uscript/uscript.h1
-rw-r--r--uscript/val.h3
-rw-r--r--uscript/vm.c77
4 files changed, 56 insertions, 31 deletions
diff --git a/uscript/uscript.c b/uscript/uscript.c
index 02dc69e..008bcbe 100644
--- a/uscript/uscript.c
+++ b/uscript/uscript.c
@@ -58,7 +58,7 @@ void core_range_next(int argc)
void core_range(int argc)
{
if (vm_get(1).type != VAL_NUM || vm_get(2).type != VAL_NUM)
- log_fatal(1, "core:range expected two numbers");
+ us_err("core:range expected two numbers");
struct us_str *str = copy_str("rangenext", -1);
struct us_cfunc *cfunc = create_cfunc(str, core_range_next, 0);
@@ -74,7 +74,7 @@ void arr_add(int argc)
(void)argc;
if (vm_get(0).type != VAL_ARR)
- log_fatal(1, "arr:add expected an array");
+ us_err("arr:add expected an array");
struct us_arr *arr = get_arr(vm_get(0));
da_append(struct us_val, &arr->e, vm_get(1));
@@ -105,7 +105,7 @@ void arr_iter(int argc)
(void)argc;
if (vm_get(0).type != VAL_ARR)
- log_fatal(1, "arr:iter expected an array");
+ us_err("arr:iter expected an array");
struct us_str *str = copy_str("arr:iternext", -1);
struct us_cfunc *cfunc = create_cfunc(str, arr_iter_next, 0);
diff --git a/uscript/uscript.h b/uscript/uscript.h
index a7efced..1973c7d 100644
--- a/uscript/uscript.h
+++ b/uscript/uscript.h
@@ -12,6 +12,7 @@ void us_load_file(const char *file);
void us_load_src(const char *src);
void us_exec(struct us_func *func);
+void us_err(const char *msg, ...);
void us_set_cfunc(const char *c_name, us_cfunc_sig c, int argc);
diff --git a/uscript/val.h b/uscript/val.h
index 8ea91dd..5deb64c 100644
--- a/uscript/val.h
+++ b/uscript/val.h
@@ -83,7 +83,8 @@ struct us_proto {
const struct us_str *name;
struct us_val constants[UINT8_MAX];
u8 *bytecode; // dyn_arr
- int* upval_locs;
+ int *lines; // dyn_arr
+ int *upval_locs;
int upvalc;
int argc;
bool is_variadic;
diff --git a/uscript/vm.c b/uscript/vm.c
index 9fbd8c0..c381112 100644
--- a/uscript/vm.c
+++ b/uscript/vm.c
@@ -1,6 +1,7 @@
#include "vm.h"
#include <math.h>
+#include <stdarg.h>
#include <string.h>
#include "dyn_arr.h"
@@ -14,6 +15,7 @@ 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.cf->stackbot = NULL;
vm.stacktop = vm.stack;
}
@@ -28,6 +30,32 @@ void deinit_vm(void)
da_free(vm.gstack);
}
+void us_err(const char *msg, ...)
+{
+ va_list args;
+ va_start(args, msg);
+ vfprintf(stderr, msg, args);
+ va_end(args);
+ putc('\n', stderr);
+
+ for (struct call_frame *cf = vm.cf; vm.cf > vm.cf_stack; cf--) {
+ if (!cf->stackbot)
+ break;
+ if (cf->func.type == VAL_FUNC) {
+ struct us_func *func = get_func(cf->func);
+ fprintf(stderr, "\tby %s()\n", func->proto->name->chars);
+ } else if (cf->func.type == VAL_CFUNC) {
+ struct us_cfunc *cfunc = get_cfunc(cf->func);
+ fprintf(stderr, "\tby [c] %s()\n", cfunc->name->chars);
+ } else {
+ fprintf(stderr, "\tunknown\n");
+ }
+ }
+
+ // TODO: Replace with a longjmp
+ exit(1);
+}
+
static
bool as_bool(struct us_val v)
{
@@ -76,14 +104,13 @@ void index_val(struct us_val idx_val, struct us_val idxee_val)
switch (idxee_val.type) {
case VAL_ARR: {
if (idx_val.type != VAL_NUM)
- log_fatal(1, "arrays must be indexed by numbers");
+ us_err("arrays must be indexed by numbers");
int idx = (int)get_num(idx_val);
struct us_arr *arr = get_arr(idxee_val);
if (idx < 0)
idx += da_len(arr->e);
if (idx < 0 || idx >= da_len(arr->e)) {
- log_fatal(
- 1,
+ us_err(
"index out of range (%d/%d)",
idx,
da_len(arr->e) - 1
@@ -94,14 +121,13 @@ void index_val(struct us_val idx_val, struct us_val idxee_val)
}
case VAL_STR: {
if (idx_val.type != VAL_NUM)
- log_fatal(1, "strings must be indexed by numbers");
+ us_err("strings must be indexed by numbers");
int idx = (int)get_num(idx_val);
struct us_str *str = get_str(idxee_val);
if (idx < 0)
idx += str->len;
if (idx < 0 || (size_t)idx >= str->len) {
- log_fatal(
- 1,
+ us_err(
"index out of range (%d/%d)",
idx,
str->len - 1
@@ -111,7 +137,7 @@ void index_val(struct us_val idx_val, struct us_val idxee_val)
break;
}
default:
- log_fatal(1, "cannot index that value");
+ us_err("cannot index that value");
break;
}
}
@@ -123,8 +149,7 @@ void call_val(struct us_val callee, int argc)
case VAL_FUNC: {
struct us_func *func = get_func(callee);
if (argc != func->proto->argc) {
- log_fatal(
- 1,
+ us_err(
"wrong number of arguments to '%s()' (%d/%d)",
func->proto->name->chars,
argc,
@@ -137,8 +162,7 @@ void call_val(struct us_val callee, int argc)
case VAL_CFUNC: {
struct us_cfunc *cfunc = get_cfunc(callee);
if (argc != cfunc->argc) {
- log_fatal(
- 1,
+ us_err(
"wrong number of arguments to '%s()' (%d/%d)",
cfunc->name->chars,
argc,
@@ -157,7 +181,7 @@ void call_val(struct us_val callee, int argc)
break;
}
default:
- log_fatal(1, "cannot call that value");
+ us_err("cannot call that value");
break;
}
}
@@ -276,16 +300,15 @@ void us_exec(struct us_func *func)
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");
+ us_err("index type must be number");
if (arr_val.type != VAL_ARR)
- log_fatal(1, "only arrays can be indexed");
+ us_err("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,
+ us_err(
"index out of range (%d/%d)",
idx,
da_len(arr->e) - 1
@@ -304,7 +327,7 @@ void us_exec(struct us_func *func)
struct us_val b = vm_pop();
struct us_val a = vm_pop();
if (b.type != VAL_NUM || a.type != VAL_NUM)
- log_fatal(1, "Invalid operands");
+ us_err("Invalid operands");
vm_push(create_num(get_num(a) + get_num(b)));
break;
}
@@ -312,7 +335,7 @@ void us_exec(struct us_func *func)
struct us_val b = vm_pop();
struct us_val a = vm_pop();
if (b.type != VAL_NUM || a.type != VAL_NUM)
- log_fatal(1, "Invalid operands");
+ us_err("Invalid operands");
vm_push(create_num(get_num(a) - get_num(b)));
break;
}
@@ -320,7 +343,7 @@ void us_exec(struct us_func *func)
struct us_val b = vm_pop();
struct us_val a = vm_pop();
if (b.type != VAL_NUM || a.type != VAL_NUM)
- log_fatal(1, "Invalid operands");
+ us_err("Invalid operands");
vm_push(create_num(get_num(a) * get_num(b)));
break;
}
@@ -328,7 +351,7 @@ void us_exec(struct us_func *func)
struct us_val b = vm_pop();
struct us_val a = vm_pop();
if (b.type != VAL_NUM || a.type != VAL_NUM)
- log_fatal(1, "Invalid operands");
+ us_err("Invalid operands");
vm_push(create_num(get_num(a) / get_num(b)));
break;
}
@@ -336,7 +359,7 @@ void us_exec(struct us_func *func)
struct us_val b = vm_pop();
struct us_val a = vm_pop();
if (b.type != VAL_NUM || a.type != VAL_NUM)
- log_fatal(1, "Invalid operands");
+ us_err("Invalid operands");
vm_push(create_num(fmod(get_num(a), get_num(b))));
break;
}
@@ -344,7 +367,7 @@ void us_exec(struct us_func *func)
struct us_val b = vm_pop();
struct us_val a = vm_pop();
if (b.type != VAL_NUM || a.type != VAL_NUM)
- log_fatal(1, "Invalid operands");
+ us_err("Invalid operands");
vm_push(create_bool(get_num(a) > get_num(b)));
break;
}
@@ -352,7 +375,7 @@ void us_exec(struct us_func *func)
struct us_val b = vm_pop();
struct us_val a = vm_pop();
if (b.type != VAL_NUM || a.type != VAL_NUM)
- log_fatal(1, "Invalid operands");
+ us_err("Invalid operands");
vm_push(create_bool(get_num(a) >= get_num(b)));
break;
}
@@ -360,7 +383,7 @@ void us_exec(struct us_func *func)
struct us_val b = vm_pop();
struct us_val a = vm_pop();
if (b.type != VAL_NUM || a.type != VAL_NUM)
- log_fatal(1, "Invalid operands");
+ us_err("Invalid operands");
vm_push(create_bool(get_num(a) < get_num(b)));
break;
}
@@ -368,14 +391,14 @@ void us_exec(struct us_func *func)
struct us_val b = vm_pop();
struct us_val a = vm_pop();
if (b.type != VAL_NUM || a.type != VAL_NUM)
- log_fatal(1, "Invalid operands");
+ us_err("Invalid operands");
vm_push(create_bool(get_num(a) <= get_num(b)));
break;
}
case BC_NEG: {
struct us_val a = vm_pop();
if (a.type != VAL_NUM)
- log_fatal(1, "Invalid operand");
+ us_err("Invalid operand");
vm_push(create_num(-get_num(a)));
break;
}
@@ -436,7 +459,7 @@ void us_exec(struct us_func *func)
return;
}
default:
- log_fatal(1, "unhandled instruction %d", instruction);
+ us_err("unhandled instruction %d", instruction);
break;
}
}