compiler: handle a panic when an error is produced, but source == ''
parent
8ea087f957
commit
7924b4d77c
|
@ -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,15 +38,18 @@ 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' {
|
||||||
path = os.real_path( path )
|
path = os.real_path(path)
|
||||||
}else{
|
} else {
|
||||||
// Get relative path
|
// Get relative path
|
||||||
workdir := os.getwd() + os.path_separator
|
workdir := os.getwd() + os.path_separator
|
||||||
if path.starts_with(workdir) {
|
if path.starts_with(workdir) {
|
||||||
|
@ -55,71 +58,26 @@ 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))
|
}
|
||||||
for ; p>=0; p-- {
|
mut p := imax(0, imin(source.len - 1, pos.pos))
|
||||||
|
if source.len > 0 {
|
||||||
|
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')
|
||||||
bline := util.imax(0, pos.line_nr - error_context_before)
|
final_position := if emanager.support_color { term.bold(position) } else { position }
|
||||||
aline := util.imin(source_lines.len-1, pos.line_nr + error_context_after)
|
|
||||||
mut clines := []string{}
|
|
||||||
tab_spaces := ' '
|
|
||||||
for iline := bline; iline <= aline; iline++ {
|
|
||||||
sline := source_lines[iline]
|
|
||||||
mut cline := '${iline+1:5d}| ' + sline.replace('\t', tab_spaces)
|
|
||||||
if iline == pos.line_nr && emanager.support_color {
|
|
||||||
cline = term.red( cline )
|
|
||||||
}
|
|
||||||
clines << cline
|
|
||||||
//
|
|
||||||
if iline == pos.line_nr {
|
|
||||||
// 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(` `, col) to form it.
|
|
||||||
mut pointerline := []string{}
|
|
||||||
for i, c in sline {
|
|
||||||
if i < column {
|
|
||||||
mut x := c
|
|
||||||
if x == `\t` {
|
|
||||||
pointerline << tab_spaces
|
|
||||||
}else{
|
|
||||||
x = if x.is_space() { c } else { ` ` }
|
|
||||||
pointerline << x.str()
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if pos.len > 1 {
|
|
||||||
max_len := sline.len - pointerline.len // rest of the line
|
|
||||||
len := if pos.len > max_len { max_len } else { pos.len }
|
|
||||||
underline := '~'.repeat(len)
|
|
||||||
pointerline << if emanager.support_color { term.bold(term.blue(underline)) } else { underline }
|
|
||||||
}else{
|
|
||||||
pointerline << if emanager.support_color { term.bold(term.blue('^')) } else { '^' }
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
|
||||||
clines << ' ' + pointerline.join('')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
source_context += clines.join('\n')
|
|
||||||
//
|
|
||||||
final_position := if emanager.support_color {
|
|
||||||
term.bold(position)
|
|
||||||
} else {
|
|
||||||
position
|
|
||||||
}
|
|
||||||
mut final_kind := kind
|
mut final_kind := kind
|
||||||
if emanager.support_color {
|
if emanager.support_color {
|
||||||
final_kind = if kind.contains('error') {
|
final_kind = if kind.contains('error') {
|
||||||
term.bold(term.red(kind))
|
term.bold(term.red(kind))
|
||||||
}else{
|
} else {
|
||||||
term.bold(term.bright_blue(kind))
|
term.bold(term.bright_blue(kind))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -129,10 +87,72 @@ pub fn formatted_error(kind string /*error or warn*/, emsg string, filepath stri
|
||||||
return '$final_position $final_kind $final_msg $final_context'.trim_space()
|
return '$final_position $final_kind $final_msg $final_context'.trim_space()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn verror(kind string, s string) {
|
pub fn source_context(source string, column int, pos token.Position) []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 := ' '
|
||||||
|
for iline := bline; iline <= aline; iline++ {
|
||||||
|
sline := source_lines[iline]
|
||||||
|
mut cline := '${iline+1:5d}| ' + sline.replace('\t', tab_spaces)
|
||||||
|
if iline == pos.line_nr && emanager.support_color {
|
||||||
|
cline = term.red(cline)
|
||||||
|
}
|
||||||
|
clines << cline
|
||||||
|
//
|
||||||
|
if iline == pos.line_nr {
|
||||||
|
// 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(` `, col) to form it.
|
||||||
|
mut pointerline := []string{}
|
||||||
|
for i, bchar in sline {
|
||||||
|
if i < column {
|
||||||
|
mut x := bchar
|
||||||
|
if x == `\t` {
|
||||||
|
pointerline << tab_spaces
|
||||||
|
} else {
|
||||||
|
x = if x.is_space() {
|
||||||
|
bchar
|
||||||
|
} else {
|
||||||
|
` `
|
||||||
|
}
|
||||||
|
pointerline << x.str()
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if pos.len > 1 {
|
||||||
|
max_len := sline.len - pointerline.len // rest of the line
|
||||||
|
len := if pos.len > max_len { max_len } else { pos.len }
|
||||||
|
underline := '~'.repeat(len)
|
||||||
|
pointerline << if emanager.support_color {
|
||||||
|
term.bold(term.blue(underline))
|
||||||
|
} else {
|
||||||
|
underline
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
pointerline << if emanager.support_color {
|
||||||
|
term.bold(term.blue('^'))
|
||||||
|
} else {
|
||||||
|
'^'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
clines << ' ' + pointerline.join('')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return clines
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
||||||
eprintln('${kind}: $s')
|
eprintln('${kind}: $s')
|
||||||
}
|
}
|
||||||
exit(1)
|
exit(1)
|
||||||
|
|
Loading…
Reference in New Issue