compiler: print asserted source line on failure
parent
ee6ec3faf3
commit
ba6cc5df2a
|
@ -96,8 +96,8 @@ fn (s &Scanner) error_with_col(msg string, col int) {
|
|||
eprintln('${fullpath}:${s.line_nr + 1}:${col}: $final_message')
|
||||
|
||||
if s.should_print_line_on_error && s.nlines > 0 {
|
||||
context_start_line := imax(0, (s.line_nr - error_context_before + 1 ))
|
||||
context_end_line := imin(s.nlines-1, (s.line_nr + error_context_after + 1 ))
|
||||
context_start_line := imax(0, (s.line_nr - error_context_before ))
|
||||
context_end_line := imin(s.nlines-1, (s.line_nr + error_context_after + 1 ))
|
||||
for cline := context_start_line; cline < context_end_line; cline++ {
|
||||
line := '${(cline+1):5d}| ' + s.line( cline )
|
||||
coloredline := if cline == s.line_nr && color_on { term.red(line) } else { line }
|
||||
|
@ -132,7 +132,13 @@ fn (s &Scanner) error_with_col(msg string, col int) {
|
|||
[inline] fn imin(a,b int) int { return if a < b { a } else { b } }
|
||||
|
||||
fn (s &Scanner) get_error_filepath() string {
|
||||
if s.should_print_relative_paths_on_error {
|
||||
verror_paths_override := os.getenv('VERROR_PATHS')
|
||||
use_relative_paths := match verror_paths_override {
|
||||
'relative' { true }
|
||||
'absolute' { false }
|
||||
else { s.should_print_relative_paths_on_error }
|
||||
}
|
||||
if use_relative_paths {
|
||||
workdir := os.getwd() + os.path_separator
|
||||
if s.file_path.starts_with(workdir) {
|
||||
return s.file_path.replace( workdir, '')
|
||||
|
@ -246,11 +252,12 @@ fn (s mut Scanner) get_scanner_pos_of_token(t &Token) ScannerPos {
|
|||
/////////////////// s.get_scanner_pos()
|
||||
/////////////////// which just returns a struct, and that works
|
||||
/////////////////// in gcc and clang, but causes the TCC problem.
|
||||
|
||||
|
||||
maxline := imin( s.nlines, tline + 2 * error_context_after)
|
||||
for {
|
||||
prevlinepos = s.pos
|
||||
if s.pos >= s.text.len { break }
|
||||
if s.line_nr > tline { break }
|
||||
if s.line_nr > maxline { break }
|
||||
////////////////////////////////////////
|
||||
if tline == s.line_nr {
|
||||
sptoken = s.get_scanner_pos()
|
||||
|
|
|
@ -648,11 +648,14 @@ pub fn (v &V) get_user_files() []string {
|
|||
// libs, but we dont know which libs need to be added yet
|
||||
mut user_files := []string
|
||||
|
||||
if v.pref.is_test && v.pref.is_stats {
|
||||
user_files << os.join(v.vroot, 'vlib', 'benchmark', 'tests',
|
||||
'always_imported.v')
|
||||
if v.pref.is_test {
|
||||
user_files << os.join(v.vroot,'vlib','compiler','preludes','tests_assertions.v')
|
||||
}
|
||||
|
||||
|
||||
if v.pref.is_test && v.pref.is_stats {
|
||||
user_files << os.join(v.vroot,'vlib','compiler','preludes','tests_with_stats.v')
|
||||
}
|
||||
|
||||
// v volt/slack_test.v: compile all .v files to get the environment
|
||||
// I need to implement user packages! TODO
|
||||
is_test_with_imports := dir.ends_with('_test.v') &&
|
||||
|
|
|
@ -3578,20 +3578,49 @@ fn (p mut Parser) assert_statement() {
|
|||
tmp := p.get_tmp()
|
||||
p.gen('bool $tmp = ')
|
||||
p.check_types(p.bool_expression(), 'bool')
|
||||
nline := p.scanner.line_nr
|
||||
// TODO print "expected: got" for failed tests
|
||||
filename := cescaped_path(p.file_path)
|
||||
p.genln(';
|
||||
\n
|
||||
cfname:=p.cur_fn.name.replace('main__', '')
|
||||
sourceline := p.scanner.line( nline - 1 ).replace('"', '\'')
|
||||
|
||||
if !p.pref.is_test {
|
||||
// an assert used in a normal v program. no fancy formatting
|
||||
p.genln(';\n
|
||||
/// sline: "$sourceline"
|
||||
if (!$tmp) {
|
||||
g_test_fails++;
|
||||
eprintln(tos3("${filename}:${p.scanner.line_nr}: FAILED: ${cfname}()"));
|
||||
eprintln(tos3("Source: $sourceline"));
|
||||
v_panic(tos3("An assertion failed."));
|
||||
return;
|
||||
} else {
|
||||
g_test_oks++;
|
||||
}
|
||||
')
|
||||
return
|
||||
}
|
||||
|
||||
p.genln(';\n
|
||||
if (!$tmp) {
|
||||
println(tos2((byte *)"\\x1B[31mFAILED: $p.cur_fn.name() in $filename:$p.scanner.line_nr\\x1B[0m"));
|
||||
g_test_fails++;
|
||||
main__cb_assertion_failed(
|
||||
tos3("$filename"),
|
||||
$p.scanner.line_nr,
|
||||
tos3("$sourceline"),
|
||||
tos3("$p.cur_fn.name()")
|
||||
);
|
||||
return;
|
||||
// TODO
|
||||
// Maybe print all vars in a test function if it fails?
|
||||
} else {
|
||||
g_test_oks++;
|
||||
//println(tos2((byte *)"\\x1B[32mPASSED: $p.cur_fn.name()\\x1B[0m"));
|
||||
main__cb_assertion_ok(
|
||||
tos3("$filename"),
|
||||
$p.scanner.line_nr,
|
||||
tos3("$sourceline"),
|
||||
tos3("$p.cur_fn.name()")
|
||||
);
|
||||
}
|
||||
|
||||
')
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
module main
|
||||
|
||||
import os
|
||||
import term
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
/// This file will get compiled as part of the main program,
|
||||
/// for a _test.v file.
|
||||
/// The methods defined here are called back by the test program's
|
||||
/// assert statements, on each success/fail. The goal is to make
|
||||
/// customizing the look & feel of the assertions results easier,
|
||||
/// since it is done in normal V code, instead of in embedded C ...
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
fn cb_assertion_failed(filename string, line int, sourceline string, funcname string){
|
||||
color_on := term.can_show_color_on_stderr()
|
||||
use_relative_paths := match os.getenv('VERROR_PATHS') {
|
||||
'absolute' { false }
|
||||
else { true }
|
||||
}
|
||||
final_filename := if use_relative_paths { filename } else { os.realpath( filename ) }
|
||||
final_funcname := funcname.replace('main__','')
|
||||
|
||||
mut fail_message := 'FAILED assertion'
|
||||
if color_on { fail_message = term.bold(term.red(fail_message)) }
|
||||
|
||||
eprintln('$final_filename:$line: $fail_message')
|
||||
eprintln('Function: $final_funcname')
|
||||
eprintln('Source : $sourceline')
|
||||
}
|
||||
|
||||
fn cb_assertion_ok(filename string, line int, sourceline string, funcname string){
|
||||
//do nothing for now on an OK assertion
|
||||
//println('OK ${line:5d}|$sourceline ')
|
||||
}
|
|
@ -236,6 +236,12 @@ fn (s mut Scanner) skip_whitespace() {
|
|||
}
|
||||
}
|
||||
|
||||
fn (s mut Scanner) end_of_file() ScanRes {
|
||||
s.pos = s.text.len
|
||||
s.inc_line_number()
|
||||
return scan_res(.eof, '')
|
||||
}
|
||||
|
||||
fn (s mut Scanner) scan() ScanRes {
|
||||
//if s.line_comment != '' {
|
||||
//s.fgenln('// LC "$s.line_comment"')
|
||||
|
@ -246,7 +252,7 @@ fn (s mut Scanner) scan() ScanRes {
|
|||
}
|
||||
s.started = true
|
||||
if s.pos >= s.text.len {
|
||||
return scan_res(.eof, '')
|
||||
return s.end_of_file()
|
||||
}
|
||||
if !s.inside_string {
|
||||
s.skip_whitespace()
|
||||
|
@ -263,7 +269,7 @@ fn (s mut Scanner) scan() ScanRes {
|
|||
s.skip_whitespace()
|
||||
// end of file
|
||||
if s.pos >= s.text.len {
|
||||
return scan_res(.eof, '')
|
||||
return s.end_of_file()
|
||||
}
|
||||
// handle each char
|
||||
c := s.text[s.pos]
|
||||
|
@ -618,7 +624,7 @@ fn (s mut Scanner) scan() ScanRes {
|
|||
}
|
||||
$if windows {
|
||||
if c == `\0` {
|
||||
return scan_res(.eof, '')
|
||||
return s.end_of_file()
|
||||
}
|
||||
}
|
||||
mut msg := 'invalid character `${c.str()}`'
|
||||
|
@ -626,7 +632,7 @@ fn (s mut Scanner) scan() ScanRes {
|
|||
msg += ', use \' to denote strings'
|
||||
}
|
||||
s.error(msg)
|
||||
return scan_res(.eof, '')
|
||||
return s.end_of_file()
|
||||
}
|
||||
|
||||
fn (s &Scanner) current_column() int {
|
||||
|
@ -804,7 +810,9 @@ fn (s mut Scanner) inc_line_number() {
|
|||
s.last_nl_pos = s.pos
|
||||
s.line_nr++
|
||||
s.line_ends << s.pos
|
||||
s.nlines++
|
||||
if s.line_nr > s.nlines {
|
||||
s.nlines = s.line_nr
|
||||
}
|
||||
}
|
||||
|
||||
fn (s Scanner) line(n int) string {
|
||||
|
|
Loading…
Reference in New Issue