compiler: print the offending source line on error
parent
7fc678c961
commit
0ade45db08
|
@ -109,6 +109,10 @@ fn (v mut V) new_parser(path string) Parser {
|
|||
|
||||
}
|
||||
|
||||
if p.pref.is_repl {
|
||||
p.scanner.should_print_line_on_error = false
|
||||
}
|
||||
|
||||
v.cgen.line_directives = v.pref.is_debuggable
|
||||
v.cgen.file = path
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@ mut:
|
|||
fmt_line_empty bool
|
||||
prev_tok Token
|
||||
fn_name string // needed for @FN
|
||||
should_print_line_on_error bool
|
||||
}
|
||||
|
||||
fn new_scanner(file_path string) &Scanner {
|
||||
|
@ -54,6 +55,7 @@ fn new_scanner(file_path string) &Scanner {
|
|||
file_path: file_path
|
||||
text: text
|
||||
fmt_out: strings.new_builder(1000)
|
||||
should_print_line_on_error: true
|
||||
}
|
||||
|
||||
return scanner
|
||||
|
@ -580,32 +582,70 @@ fn (s mut Scanner) scan() ScanRes {
|
|||
}
|
||||
|
||||
fn (s &Scanner) find_current_line_start_position() int {
|
||||
if s.pos >= s.text.len {
|
||||
return s.pos
|
||||
}
|
||||
if s.pos >= s.text.len { return s.pos }
|
||||
mut linestart := s.pos
|
||||
for {
|
||||
if linestart <= 0 {break}
|
||||
if s.text[linestart] == 10 || s.text[linestart] == 13 { break }
|
||||
if linestart <= 0 {
|
||||
linestart = 1
|
||||
break
|
||||
}
|
||||
if s.text[linestart] == 10 || s.text[linestart] == 13 {
|
||||
linestart++
|
||||
break
|
||||
}
|
||||
linestart--
|
||||
}
|
||||
return linestart
|
||||
}
|
||||
|
||||
fn (s &Scanner) find_current_line_end_position() int {
|
||||
if s.pos >= s.text.len { return s.pos }
|
||||
mut lineend := s.pos
|
||||
for {
|
||||
if lineend >= s.text.len {
|
||||
lineend = s.text.len
|
||||
break
|
||||
}
|
||||
if s.text[lineend] == 10 || s.text[lineend] == 13 {
|
||||
break
|
||||
}
|
||||
lineend++
|
||||
}
|
||||
return lineend
|
||||
}
|
||||
|
||||
fn (s &Scanner) current_column() int {
|
||||
return s.pos - s.find_current_line_start_position()
|
||||
}
|
||||
|
||||
fn (s &Scanner) error(msg string) {
|
||||
linestart := s.find_current_line_start_position()
|
||||
lineend := s.find_current_line_end_position()
|
||||
column := s.pos - linestart
|
||||
if s.should_print_line_on_error {
|
||||
line := s.text.substr( linestart, lineend )
|
||||
// The pointerline should have the same spaces/tabs as the offending
|
||||
// line, so that it prints the ^ character exactly on the *same spot*
|
||||
// where it is needed. That is the reason we can not just
|
||||
// use strings.repeat(` `, column) to form it.
|
||||
pointerline := line.clone()
|
||||
mut pl := pointerline.str
|
||||
for i,c in line {
|
||||
pl[i] = ` `
|
||||
if i == column { pl[i] = `^` }
|
||||
else if c.is_space() { pl[i] = c }
|
||||
}
|
||||
println(line)
|
||||
println(pointerline)
|
||||
}
|
||||
fullpath := os.realpath( s.file_path )
|
||||
column := s.current_column()
|
||||
// The filepath:line:col: format is the default C compiler
|
||||
// error output format. It allows editors and IDE's like
|
||||
// emacs to quickly find the errors in the output
|
||||
// and jump to their source with a keyboard shortcut.
|
||||
// Using only the filename leads to inability of IDE/editors
|
||||
// to find the source file, when it is in another folder.
|
||||
println('${fullpath}:${s.line_nr + 1}:$column: $msg')
|
||||
println('${fullpath}:${s.line_nr + 1}:${column+1}: $msg')
|
||||
exit(1)
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue