From 6b14c2776efc66cbc1f1606d94759f7b33c1dd07 Mon Sep 17 00:00:00 2001 From: hanez Date: Tue, 16 Sep 2025 11:23:42 +0200 Subject: [PATCH] Added line numbers to debug and error output. --- examples/objects_more.fun | 6 +++--- src/bytecode.h | 2 ++ src/parser.c | 7 +++++++ src/vm.c | 32 ++++++++++++++++++++++++++++++++ src/vm.h | 3 +++ src/vm/line.c | 5 +++++ 6 files changed, 52 insertions(+), 3 deletions(-) create mode 100644 src/vm/line.c diff --git a/examples/objects_more.fun b/examples/objects_more.fun index 05a7b39..69a00b6 100755 --- a/examples/objects_more.fun +++ b/examples/objects_more.fun @@ -12,9 +12,9 @@ // Objects as maps: nested fields, methods with explicit self // A method to move a 2D point by dx, dy -fun move(self, dx, dy) - self["x"] = self["x"] + dx - self["y"] = self["y"] + dy +fun move(p, x, y) + p["x"] = p["x"] + x + p["y"] = p["y"] + y return 0 // Create a point directly and inspect fields diff --git a/src/bytecode.h b/src/bytecode.h index a076625..df2e44a 100644 --- a/src/bytecode.h +++ b/src/bytecode.h @@ -46,6 +46,8 @@ typedef enum { OP_PRINT, OP_HALT, + OP_LINE, // operand = source line number (debug marker) + // add after existing opcodes OP_MOD, // a % b OP_AND, // logical AND diff --git a/src/parser.c b/src/parser.c index 63cf6da..82dac43 100644 --- a/src/parser.c +++ b/src/parser.c @@ -1736,6 +1736,13 @@ static void parse_block(Bytecode *bc, const char *src, size_t len, size_t *pos, } /* at same indent -> parse statement */ + /* Insert a line marker for better runtime error reporting */ + { + int stmt_line = 1, stmt_col = 1; + calc_line_col(src, len, line_start, &stmt_line, &stmt_col); + bytecode_add_instruction(bc, OP_LINE, stmt_line); + } + if (starts_with(src, len, *pos, "fun")) { /* parse header: fun name(arg, ...) */ *pos += 3; diff --git a/src/vm.c b/src/vm.c index d323fe3..7e48b31 100644 --- a/src/vm.c +++ b/src/vm.c @@ -16,6 +16,34 @@ #include #include #include +#include + +/* Track the currently running VM to annotate error messages */ +static VM *g_active_vm = NULL; + +/* fprintf wrapper that appends source line info for stderr messages */ +static int fun_vm_vfprintf(FILE *stream, const char *fmt, va_list ap) { + int written = vfprintf(stream, fmt, ap); + if (stream == stderr && g_active_vm && g_active_vm->current_line > 0) { + /* If original message didn't end with newline, add a space first */ + if (written > 0) { + /* best-effort: do not attempt to inspect fmt string fully; just append line info */ + } + fprintf(stream == stderr ? stderr : stream, " (line %d)\n", g_active_vm->current_line); + } + return written; +} + +static int fun_vm_fprintf(FILE *stream, const char *fmt, ...) { + va_list ap; + va_start(ap, fmt); + int r = fun_vm_vfprintf(stream, fmt, ap); + va_end(ap); + return r; +} + +/* Redirect fprintf within this translation unit so opcode handlers use our wrapper */ +#define fprintf fun_vm_fprintf /* Opcode case include index (vm_case_*.inc): @@ -178,6 +206,8 @@ void vm_print_output(VM *vm) { void vm_run(VM *vm, Bytecode *entry) { /* reset instruction count for this run */ vm->instr_count = 0; + vm->current_line = 1; + g_active_vm = vm; /* start with entry frame (no args) */ vm_push_frame(vm, entry, 0, NULL); @@ -266,6 +296,7 @@ void vm_run(VM *vm, Bytecode *entry) { #include "vm/strings/substr.c" #include "vm/len.c" + #include "vm/line.c" #include "vm/print.c" #include "vm/to_number.c" #include "vm/to_string.c" @@ -283,4 +314,5 @@ void vm_run(VM *vm, Bytecode *entry) { break; } } + g_active_vm = NULL; } diff --git a/src/vm.h b/src/vm.h index 31143c6..6968711 100644 --- a/src/vm.h +++ b/src/vm.h @@ -32,6 +32,7 @@ static const char *opcode_names[] = { "LOAD_GLOBAL","STORE_GLOBAL","ADD","SUB","MUL","DIV", "LT","LTE","GT","GTE","EQ","NEQ","POP","JUMP", "JUMP_IF_FALSE","CALL","RETURN","PRINT","HALT", + "LINE", "MOD","AND","OR","NOT","DUP","SWAP", "MAKE_ARRAY","INDEX_GET","INDEX_SET", "LEN","PUSH","APOP","SET","INSERT","REMOVE","SLICE", @@ -63,6 +64,8 @@ typedef struct { int output_count; long long instr_count; // executed instructions in the last vm_run + + int current_line; // last executed source line (debug) } VM; // initialize VM (zero state) diff --git a/src/vm/line.c b/src/vm/line.c new file mode 100644 index 0000000..d783d21 --- /dev/null +++ b/src/vm/line.c @@ -0,0 +1,5 @@ +case OP_LINE: { + /* operand holds the source line number */ + vm->current_line = inst.operand; + break; +}