eval: make the interpreter backtrace more efficient and informative.

Delyan Angelov 2022-04-28 12:31:30 +03:00 committed by Jef Roosens
parent 31bee98607
commit 705e260180
Signed by: Jef Roosens
GPG Key ID: B75D4F293C7052DB
3 changed files with 39 additions and 15 deletions

View File

@ -520,6 +520,7 @@ pub:
attrs []Attr attrs []Attr
ctdefine_idx int = -1 // the index in fn.attrs of `[if xyz]`, when such attribute exists ctdefine_idx int = -1 // the index in fn.attrs of `[if xyz]`, when such attribute exists
pub mut: pub mut:
idx int // index in an external container; can be used to refer to the function in a more efficient way, just by its integer index
params []Param params []Param
stmts []Stmt stmts []Stmt
defer_stmts []DeferStmt defer_stmts []DeferStmt
@ -707,6 +708,7 @@ pub:
is_generated bool // true for `[generated] module xyz` files; turn off notices is_generated bool // true for `[generated] module xyz` files; turn off notices
is_translated bool // true for `[translated] module xyz` files; turn off some checks is_translated bool // true for `[translated] module xyz` files; turn off some checks
pub mut: pub mut:
idx int // index in an external container; can be used to refer to the file in a more efficient way, just by its integer index
path string // absolute path of the source file - '/projects/v/file.v' path string // absolute path of the source file - '/projects/v/file.v'
path_base string // file name - 'file.v' (useful for tracing) path_base string // file name - 'file.v' (useful for tracing)
scope &Scope scope &Scope

View File

@ -19,6 +19,6 @@ pub fn interpret_v(mut b builder.Builder) {
util.timing_start('INTERPRET') util.timing_start('INTERPRET')
mut e := eval.new_eval(b.table, b.pref) mut e := eval.new_eval(b.table, b.pref)
e.eval(b.parsed_files) e.eval(mut b.parsed_files)
util.timing_measure('INTERPRET') util.timing_measure('INTERPRET')
} }

View File

@ -30,28 +30,37 @@ pub mut:
return_values []Object return_values []Object
cur_mod string cur_mod string
cur_file string cur_file string
back_trace []string //
trace_file_paths []string
trace_function_names []string
back_trace []EvalTrace
} }
pub fn (mut e Eval) eval(files []&ast.File) { pub struct EvalTrace {
e.register_symbols(files) fn_idx int
file_idx int
line int
}
pub fn (mut e Eval) eval(mut files []&ast.File) {
e.register_symbols(mut files)
// println(files.map(it.path_base)) // println(files.map(it.path_base))
e.run_func(e.mods['main']['main'] or { ast.EmptyStmt{} } as ast.FnDecl) e.run_func(e.mods['main']['main'] or { ast.EmptyStmt{} } as ast.FnDecl)
} }
// first arg is reciever (if method) // first arg is reciever (if method)
pub fn (mut e Eval) run_func(func ast.FnDecl, _args ...Object) { pub fn (mut e Eval) run_func(func ast.FnDecl, _args ...Object) {
e.back_trace << func.name e.back_trace << EvalTrace{func.idx, func.source_file.idx, func.pos.line_nr}
old_mod := e.cur_mod old_mod := e.cur_mod
e.cur_mod = func.mod
old_file := e.cur_file old_file := e.cur_file
e.cur_mod = func.mod
e.cur_file = func.file e.cur_file = func.file
defer { defer {
e.cur_mod = old_mod e.cur_mod = old_mod
e.cur_file = old_file e.cur_file = old_file
e.back_trace.pop() e.back_trace.pop()
} }
//
mut args := _args.clone() mut args := _args.clone()
if func.params.len != args.len && !func.is_variadic { if func.params.len != args.len && !func.is_variadic {
e.error('mismatched parameter length for $func.name: got `$args.len`, expected `$func.params.len`') e.error('mismatched parameter length for $func.name: got `$args.len`, expected `$func.params.len`')
@ -90,7 +99,7 @@ pub fn (mut e Eval) run_func(func ast.FnDecl, _args ...Object) {
} }
if func.is_method { if func.is_method {
print(e.back_trace) print(e.back_trace)
println(func.receiver.typ - 65536) println(func.receiver.typ.set_nr_muls(0))
e.local_vars[func.receiver.name] = Var{ e.local_vars[func.receiver.name] = Var{
val: args[0] val: args[0]
scope_idx: e.scope_idx scope_idx: e.scope_idx
@ -104,13 +113,19 @@ pub fn (mut e Eval) run_func(func ast.FnDecl, _args ...Object) {
} }
} }
pub fn (mut e Eval) register_symbols(files []&ast.File) { pub fn (mut e Eval) register_symbols(mut files []&ast.File) {
for file in files { for mut file in files {
file.idx = e.trace_file_paths.len
e.trace_file_paths << file.path
// eprintln('registering file: $file.path_base') // eprintln('registering file: $file.path_base')
mod := file.mod.name mod := file.mod.name
e.register_symbol_stmts(file.stmts[1..], mod, file.path) for mut stmt in file.stmts {
if mut stmt is ast.FnDecl {
// eprintln('registered file: $file.path_base') stmt.idx = e.trace_function_names.len
e.trace_function_names << stmt.name
}
}
e.register_symbol_stmts(file.stmts, mod, file.path)
} }
for mod, const_files in e.future_register_consts { for mod, const_files in e.future_register_consts {
e.cur_mod = mod e.cur_mod = mod
@ -133,14 +148,16 @@ pub fn (mut e Eval) register_symbols(files []&ast.File) {
} }
pub fn (mut e Eval) register_symbol_stmts(stmts []ast.Stmt, mod string, file string) { pub fn (mut e Eval) register_symbol_stmts(stmts []ast.Stmt, mod string, file string) {
for stmt in stmts { // first is just module declaration, so ignore for stmt in stmts {
e.register_symbol(stmt, mod, file) e.register_symbol(stmt, mod, file)
} }
} }
pub fn (mut e Eval) register_symbol(stmt ast.Stmt, mod string, file string) { pub fn (mut e Eval) register_symbol(stmt ast.Stmt, mod string, file string) {
match stmt { match stmt {
ast.Module {} ast.Module {
// ignore module declarations for now
}
ast.FnDecl { ast.FnDecl {
// this mess because c error // this mess because c error
x := ast.Stmt(stmt) x := ast.Stmt(stmt)
@ -205,5 +222,10 @@ pub fn (mut e Eval) register_symbol(stmt ast.Stmt, mod string, file string) {
} }
fn (e Eval) error(msg string) { fn (e Eval) error(msg string) {
eprintln('> V interpeter backtrace:')
for idx, t in e.back_trace {
eprintln(' ${e.trace_file_paths[t.file_idx]}:${t.line + 1}:${e.trace_function_names[t.fn_idx]}')
// eprintln('${e.trace_file_paths[t.file_idx]}:${t.line + 1}:$t.fn_idx')
}
util.verror('interpreter', msg) util.verror('interpreter', msg)
} }