Added line numbers to debug and error output.
This commit is contained in:
parent
1958850d87
commit
6b14c2776e
6 changed files with 52 additions and 3 deletions
|
|
@ -12,9 +12,9 @@
|
||||||
// Objects as maps: nested fields, methods with explicit self
|
// Objects as maps: nested fields, methods with explicit self
|
||||||
|
|
||||||
// A method to move a 2D point by dx, dy
|
// A method to move a 2D point by dx, dy
|
||||||
fun move(self, dx, dy)
|
fun move(p, x, y)
|
||||||
self["x"] = self["x"] + dx
|
p["x"] = p["x"] + x
|
||||||
self["y"] = self["y"] + dy
|
p["y"] = p["y"] + y
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
// Create a point directly and inspect fields
|
// Create a point directly and inspect fields
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,8 @@ typedef enum {
|
||||||
OP_PRINT,
|
OP_PRINT,
|
||||||
OP_HALT,
|
OP_HALT,
|
||||||
|
|
||||||
|
OP_LINE, // operand = source line number (debug marker)
|
||||||
|
|
||||||
// add after existing opcodes
|
// add after existing opcodes
|
||||||
OP_MOD, // a % b
|
OP_MOD, // a % b
|
||||||
OP_AND, // logical AND
|
OP_AND, // logical AND
|
||||||
|
|
|
||||||
|
|
@ -1736,6 +1736,13 @@ static void parse_block(Bytecode *bc, const char *src, size_t len, size_t *pos,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* at same indent -> parse statement */
|
/* 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")) {
|
if (starts_with(src, len, *pos, "fun")) {
|
||||||
/* parse header: fun name(arg, ...) */
|
/* parse header: fun name(arg, ...) */
|
||||||
*pos += 3;
|
*pos += 3;
|
||||||
|
|
|
||||||
32
src/vm.c
32
src/vm.c
|
|
@ -16,6 +16,34 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
/* 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):
|
Opcode case include index (vm_case_*.inc):
|
||||||
|
|
@ -178,6 +206,8 @@ void vm_print_output(VM *vm) {
|
||||||
void vm_run(VM *vm, Bytecode *entry) {
|
void vm_run(VM *vm, Bytecode *entry) {
|
||||||
/* reset instruction count for this run */
|
/* reset instruction count for this run */
|
||||||
vm->instr_count = 0;
|
vm->instr_count = 0;
|
||||||
|
vm->current_line = 1;
|
||||||
|
g_active_vm = vm;
|
||||||
|
|
||||||
/* start with entry frame (no args) */
|
/* start with entry frame (no args) */
|
||||||
vm_push_frame(vm, entry, 0, NULL);
|
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/strings/substr.c"
|
||||||
|
|
||||||
#include "vm/len.c"
|
#include "vm/len.c"
|
||||||
|
#include "vm/line.c"
|
||||||
#include "vm/print.c"
|
#include "vm/print.c"
|
||||||
#include "vm/to_number.c"
|
#include "vm/to_number.c"
|
||||||
#include "vm/to_string.c"
|
#include "vm/to_string.c"
|
||||||
|
|
@ -283,4 +314,5 @@ void vm_run(VM *vm, Bytecode *entry) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
g_active_vm = NULL;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
3
src/vm.h
3
src/vm.h
|
|
@ -32,6 +32,7 @@ static const char *opcode_names[] = {
|
||||||
"LOAD_GLOBAL","STORE_GLOBAL","ADD","SUB","MUL","DIV",
|
"LOAD_GLOBAL","STORE_GLOBAL","ADD","SUB","MUL","DIV",
|
||||||
"LT","LTE","GT","GTE","EQ","NEQ","POP","JUMP",
|
"LT","LTE","GT","GTE","EQ","NEQ","POP","JUMP",
|
||||||
"JUMP_IF_FALSE","CALL","RETURN","PRINT","HALT",
|
"JUMP_IF_FALSE","CALL","RETURN","PRINT","HALT",
|
||||||
|
"LINE",
|
||||||
"MOD","AND","OR","NOT","DUP","SWAP",
|
"MOD","AND","OR","NOT","DUP","SWAP",
|
||||||
"MAKE_ARRAY","INDEX_GET","INDEX_SET",
|
"MAKE_ARRAY","INDEX_GET","INDEX_SET",
|
||||||
"LEN","PUSH","APOP","SET","INSERT","REMOVE","SLICE",
|
"LEN","PUSH","APOP","SET","INSERT","REMOVE","SLICE",
|
||||||
|
|
@ -63,6 +64,8 @@ typedef struct {
|
||||||
int output_count;
|
int output_count;
|
||||||
|
|
||||||
long long instr_count; // executed instructions in the last vm_run
|
long long instr_count; // executed instructions in the last vm_run
|
||||||
|
|
||||||
|
int current_line; // last executed source line (debug)
|
||||||
} VM;
|
} VM;
|
||||||
|
|
||||||
// initialize VM (zero state)
|
// initialize VM (zero state)
|
||||||
|
|
|
||||||
5
src/vm/line.c
Normal file
5
src/vm/line.c
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
case OP_LINE: {
|
||||||
|
/* operand holds the source line number */
|
||||||
|
vm->current_line = inst.operand;
|
||||||
|
break;
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue