compiler: handle a panic when an error is produced, but source == ''

pull/4639/head
Delyan Angelov 2020-04-28 16:12:57 +03:00
parent 8ea087f957
commit 7924b4d77c
1 changed files with 92 additions and 72 deletions

View File

@ -13,24 +13,24 @@ import v.token
// NB: using only the filename may lead to inability of IDE/editors // NB: using only the filename may lead to inability of IDE/editors
// to find the source file, when the IDE has a different working folder than // to find the source file, when the IDE has a different working folder than
// v itself. // v itself.
// error_context_before - how many lines of source context to print before the pointer line
// error_context_after - ^^^ same, but after
const ( const (
error_context_before = 2 // how many lines of source context to print before the pointer line error_context_before = 2
error_context_after = 2 // ^^^ same, but after error_context_after = 2
) )
// emanager.support_color - should the error and other messages
// have ANSI terminal escape color codes in them.
// By default, v tries to autodetect, if the terminal supports colors.
// Use -color and -nocolor options to override the detection decision.
pub const ( pub const (
emanager = new_error_manager() emanager = new_error_manager()
) )
//
pub struct EManager { pub struct EManager {
pub mut: pub mut:
support_color bool // should the error and other messages support_color bool
// have ANSI terminal escape color codes in them.
// By default, v tries to autodetect, if the terminal supports colors.
// Use -color and -nocolor options to override the detection decision.
} }
pub fn (e &EManager) set_support_color(b bool) { pub fn (e &EManager) set_support_color(b bool) {
@ -38,10 +38,13 @@ pub fn (e &EManager) set_support_color(b bool) {
} }
pub fn new_error_manager() &EManager { pub fn new_error_manager() &EManager {
return &EManager{ support_color: term.can_show_color_on_stderr() } return &EManager{
support_color: term.can_show_color_on_stderr()
}
} }
pub fn formatted_error(kind string /*error or warn*/, emsg string, filepath string, pos token.Position) string { // formatted_error - `kind` may be 'error' or 'warn'
pub fn formatted_error(kind, emsg, filepath string, pos token.Position) string {
mut path := filepath mut path := filepath
verror_paths_override := os.getenv('VERROR_PATHS') verror_paths_override := os.getenv('VERROR_PATHS')
if verror_paths_override == 'absolute' { if verror_paths_override == 'absolute' {
@ -55,20 +58,43 @@ pub fn formatted_error(kind string /*error or warn*/, emsg string, filepath stri
} }
// //
mut source_context := '' mut source_context := ''
source := util.read_file(filepath) or { '' } source := read_file(filepath) or {
source_lines := source.split_into_lines() ''
mut p := util.imax(0, util.imin(source.len -1, pos.pos)) }
mut p := imax(0, imin(source.len - 1, pos.pos))
if source.len > 0 {
for ; p >= 0; p-- { for ; p >= 0; p-- {
if source[p] == `\r` || source[p] == `\n` { if source[p] == `\r` || source[p] == `\n` {
break break
} }
} }
column := util.imax(0, pos.pos - p - 1) }
column := imax(0, pos.pos - p - 1)
position := '${path}:${pos.line_nr+1}:${util.imax(1,column+1)}:' position := '${path}:${pos.line_nr+1}:${util.imax(1,column+1)}:'
source_context += source_context(source, column, pos).join('\n')
final_position := if emanager.support_color { term.bold(position) } else { position }
mut final_kind := kind
if emanager.support_color {
final_kind = if kind.contains('error') {
term.bold(term.red(kind))
} else {
term.bold(term.bright_blue(kind))
}
}
final_msg := emsg // if emanager.support_color { term.bold(emsg) } else { emsg }
final_context := if source_context.len > 0 { '\n$source_context' } else { '' }
// //
bline := util.imax(0, pos.line_nr - error_context_before) return '$final_position $final_kind $final_msg $final_context'.trim_space()
aline := util.imin(source_lines.len-1, pos.line_nr + error_context_after) }
pub fn source_context(source string, column int, pos token.Position) []string {
mut clines := []string{} mut clines := []string{}
if source.len == 0 {
return clines
}
source_lines := source.split_into_lines()
bline := imax(0, pos.line_nr - error_context_before)
aline := imax(0, imin(source_lines.len - 1, pos.line_nr + error_context_after))
tab_spaces := ' ' tab_spaces := ' '
for iline := bline; iline <= aline; iline++ { for iline := bline; iline <= aline; iline++ {
sline := source_lines[iline] sline := source_lines[iline]
@ -84,13 +110,17 @@ pub fn formatted_error(kind string /*error or warn*/, emsg string, filepath stri
// where it is needed. That is the reason we can not just // where it is needed. That is the reason we can not just
// use strings.repeat(` `, col) to form it. // use strings.repeat(` `, col) to form it.
mut pointerline := []string{} mut pointerline := []string{}
for i, c in sline { for i, bchar in sline {
if i < column { if i < column {
mut x := c mut x := bchar
if x == `\t` { if x == `\t` {
pointerline << tab_spaces pointerline << tab_spaces
} else { } else {
x = if x.is_space() { c } else { ` ` } x = if x.is_space() {
bchar
} else {
` `
}
pointerline << x.str() pointerline << x.str()
} }
continue continue
@ -99,37 +129,27 @@ pub fn formatted_error(kind string /*error or warn*/, emsg string, filepath stri
max_len := sline.len - pointerline.len // rest of the line max_len := sline.len - pointerline.len // rest of the line
len := if pos.len > max_len { max_len } else { pos.len } len := if pos.len > max_len { max_len } else { pos.len }
underline := '~'.repeat(len) underline := '~'.repeat(len)
pointerline << if emanager.support_color { term.bold(term.blue(underline)) } else { underline } pointerline << if emanager.support_color {
term.bold(term.blue(underline))
} else { } else {
pointerline << if emanager.support_color { term.bold(term.blue('^')) } else { '^' } underline
}
} else {
pointerline << if emanager.support_color {
term.bold(term.blue('^'))
} else {
'^'
}
} }
break break
} }
clines << ' ' + pointerline.join('') clines << ' ' + pointerline.join('')
} }
} }
source_context += clines.join('\n') return clines
//
final_position := if emanager.support_color {
term.bold(position)
} else {
position
}
mut final_kind := kind
if emanager.support_color {
final_kind = if kind.contains('error') {
term.bold(term.red(kind))
}else{
term.bold(term.bright_blue(kind))
}
}
final_msg := emsg // if emanager.support_color { term.bold(emsg) } else { emsg }
final_context := if source_context.len > 0 { '\n$source_context' } else { '' }
//
return '$final_position $final_kind $final_msg $final_context'.trim_space()
} }
pub fn verror(kind string, s string) { pub fn verror(kind, s string) {
if emanager.support_color { if emanager.support_color {
eprintln(term.bold(term.red(kind)) + ': $s') eprintln(term.bold(term.red(kind)) + ': $s')
} else { } else {