Fixed try/catch to run finally again. exit() in catch if you want to stop execution. (0.37.62)
This commit is contained in:
parent
6648fa1e27
commit
869d68b992
4 changed files with 43 additions and 5 deletions
32
src/vm.c
32
src/vm.c
|
|
@ -235,6 +235,38 @@ static void fun_vm_exit(int code) {
|
|||
/* Redirect exit inside this TU (affects included opcode handlers) */
|
||||
#define exit(code) fun_vm_exit(code)
|
||||
|
||||
/* Forward decl for stack push used by vm_raise_error */
|
||||
static void push_value(VM *vm, Value v);
|
||||
|
||||
/* Raise a runtime error that respects try/catch/finally semantics.
|
||||
* If a handler is installed for the current frame, jump to it and push
|
||||
* an error string for the catch clause. Otherwise, print and stop VM. */
|
||||
void vm_raise_error(VM *vm, const char *msg) {
|
||||
if (!vm || vm->fp < 0) {
|
||||
fprintf(stderr, "Runtime error: %s\n", msg ? msg : "<error>");
|
||||
return;
|
||||
}
|
||||
Frame *f = &vm->frames[vm->fp];
|
||||
if (f->try_sp >= 0) {
|
||||
char buf[256];
|
||||
if (msg) {
|
||||
snprintf(buf, sizeof(buf), "Runtime error: %s", msg);
|
||||
} else {
|
||||
snprintf(buf, sizeof(buf), "Runtime error");
|
||||
}
|
||||
/* push error value and transfer control to handler target */
|
||||
Value err = make_string(buf);
|
||||
push_value(vm, err);
|
||||
int try_idx = f->try_stack[f->try_sp--];
|
||||
int target = f->fn->instructions[try_idx].operand;
|
||||
f->ip = target;
|
||||
return;
|
||||
}
|
||||
/* No handler: print annotated message and terminate VM */
|
||||
fprintf(stderr, "Runtime error: %s\n", msg ? msg : "<error>");
|
||||
vm->fp = -1; /* stop execution */
|
||||
}
|
||||
|
||||
/*
|
||||
Opcode case include index (vm_case_*.inc):
|
||||
- Core/stack/frame:
|
||||
|
|
|
|||
6
src/vm.h
6
src/vm.h
|
|
@ -122,6 +122,12 @@ void vm_dump_globals(VM *vm);
|
|||
// run entry Bytecode (pushes first frame)
|
||||
void vm_run(VM *vm, Bytecode *entry);
|
||||
|
||||
/* Raise a runtime error that respects try/catch/finally.
|
||||
* If a try handler is active in the current frame, control jumps to it
|
||||
* with an error string pushed on the stack. Otherwise, prints the error
|
||||
* (annotated with location) and terminates execution. */
|
||||
void vm_raise_error(VM *vm, const char *msg);
|
||||
|
||||
/* --- Debugger API --- */
|
||||
void vm_debug_reset(VM *vm);
|
||||
int vm_debug_add_breakpoint(VM *vm, const char *file, int line); // returns id >=0 or -1
|
||||
|
|
|
|||
|
|
@ -40,8 +40,8 @@ case OP_DIV: {
|
|||
double da = (a.type == VAL_FLOAT) ? a.d : (double)a.i;
|
||||
double db = (b.type == VAL_FLOAT) ? b.d : (double)b.i;
|
||||
if (db == 0.0) {
|
||||
fprintf(stderr, "Runtime error: division by zero\n");
|
||||
exit(1);
|
||||
vm_raise_error(vm, "division by zero");
|
||||
break;
|
||||
}
|
||||
Value res = make_float(da / db);
|
||||
free_value(a);
|
||||
|
|
@ -49,8 +49,8 @@ case OP_DIV: {
|
|||
push_value(vm, res);
|
||||
} else {
|
||||
if (b.i == 0) {
|
||||
fprintf(stderr, "Runtime error: division by zero\n");
|
||||
exit(1);
|
||||
vm_raise_error(vm, "division by zero");
|
||||
break;
|
||||
}
|
||||
Value res = make_int(a.i / b.i);
|
||||
free_value(a);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue