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
 | ||||
| // to find the source file, when the IDE has a different working folder than
 | ||||
| // v itself.
 | ||||
| 
 | ||||
| // error_context_before - how many lines of source context to print before the pointer line
 | ||||
| // error_context_after - ^^^ same, but after
 | ||||
| const ( | ||||
| 	error_context_before = 2 // how many lines of source context to print before the pointer line
 | ||||
| 	error_context_after = 2 // ^^^ same, but after
 | ||||
| 	error_context_before = 2 | ||||
| 	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 ( | ||||
| 	emanager = new_error_manager() | ||||
| ) | ||||
| 
 | ||||
| //
 | ||||
| 
 | ||||
| pub struct EManager { | ||||
| pub mut: | ||||
| 	support_color bool // 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.
 | ||||
| 	support_color 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 { | ||||
| 	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 | ||||
| 	verror_paths_override := os.getenv('VERROR_PATHS') | ||||
| 	if verror_paths_override == 'absolute' { | ||||
| 		path = os.real_path( path ) | ||||
| 	}else{ | ||||
| 		path = os.real_path(path) | ||||
| 	} else { | ||||
| 		// Get relative path
 | ||||
| 		workdir := os.getwd() + os.path_separator | ||||
| 		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 := '' | ||||
| 	source := util.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-- { | ||||
| 		if source[p] == `\r` || source[p] == `\n` { | ||||
| 			break | ||||
| 		} | ||||
| 	source := read_file(filepath) or { | ||||
| 		'' | ||||
| 	} | ||||
| 	column := util.imax(0, pos.pos - p - 1) | ||||
| 	position := '${path}:${pos.line_nr+1}:${util.imax(1,column+1)}:' | ||||
| 	//
 | ||||
| 	bline := util.imax(0, pos.line_nr - error_context_before) | ||||
| 	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 { '^' } | ||||
| 				} | ||||
| 	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` { | ||||
| 				break | ||||
| 			} | ||||
| 			clines << '       ' + pointerline.join('') | ||||
| 		} | ||||
| 	} | ||||
| 	source_context += clines.join('\n') | ||||
| 	//
 | ||||
| 	final_position := if emanager.support_color { | ||||
| 		term.bold(position) | ||||
| 	} else { | ||||
| 		position | ||||
| 	} | ||||
| 	column := imax(0, pos.pos - p - 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{ | ||||
| 		} else { | ||||
| 			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() | ||||
| } | ||||
| 
 | ||||
| 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 { | ||||
| 		eprintln( term.bold(term.red(kind)) + ': $s' ) | ||||
| 	}else{ | ||||
| 		eprintln(term.bold(term.red(kind)) + ': $s') | ||||
| 	} else { | ||||
| 		eprintln('${kind}: $s') | ||||
| 	} | ||||
| 	exit(1) | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue