diff --git a/vlib/v/builder/compile.v b/vlib/v/builder/compile.v index 3d99b6779a..ac59121a50 100644 --- a/vlib/v/builder/compile.v +++ b/vlib/v/builder/compile.v @@ -83,12 +83,11 @@ fn (mut b Builder) myfree() { // for file in b.parsed_files { // } unsafe { b.parsed_files.free() } - unsafe { util.cached_read_source_file('') or {} } + util.free_caches() } fn (b &Builder) exit_on_invalid_syntax() { - // clear the source file cache, since it will not be needed anymore - unsafe { util.cached_read_source_file('') or {} } + util.free_caches() // V should exit with an exit code of 1, when there are errors, // even when -silent is passed in combination to -check-syntax: if b.pref.only_check_syntax { diff --git a/vlib/v/util/errors.v b/vlib/v/util/errors.v index ba3b0da33d..4fe25f0377 100644 --- a/vlib/v/util/errors.v +++ b/vlib/v/util/errors.v @@ -83,9 +83,8 @@ pub fn formatted_error(kind string, omsg string, filepath string, pos token.Posi } } // - source := read_file(filepath) or { '' } position := '$path:${pos.line_nr + 1}:${mu.max(1, pos.col + 1)}:' - scontext := source_context(kind, source, pos).join('\n') + scontext := source_file_context(kind, filepath, pos).join('\n') final_position := bold(position) final_kind := bold(color(kind, kind)) final_msg := emsg @@ -94,12 +93,39 @@ pub fn formatted_error(kind string, omsg string, filepath string, pos token.Posi return '$final_position $final_kind $final_msg$final_context'.trim_space() } -pub fn source_context(kind string, source string, pos token.Position) []string { +[heap] +struct LinesCache { +mut: + lines map[string][]string +} + +[unsafe] +pub fn cached_file2sourcelines(path string) []string { + mut static cache := &LinesCache(0) + if isnil(cache) { + cache = &LinesCache{} + } + if path.len == 0 { + unsafe { cache.lines.free() } + unsafe { free(cache) } + cache = &LinesCache(0) + return []string{} + } + if res := cache.lines[path] { + return res + } + source := read_file(path) or { '' } + res := source.split_into_lines() + cache.lines[path] = res + return res +} + +pub fn source_file_context(kind string, filepath string, pos token.Position) []string { mut clines := []string{} - if source.len == 0 { + source_lines := unsafe { cached_file2sourcelines(filepath) } + if source_lines.len == 0 { return clines } - source_lines := source.split_into_lines() bline := mu.max(0, pos.line_nr - util.error_context_before) aline := mu.max(0, mu.min(source_lines.len - 1, pos.line_nr + util.error_context_after)) tab_spaces := ' ' diff --git a/vlib/v/util/util.v b/vlib/v/util/util.v index 593b545bd8..467bd64b5e 100644 --- a/vlib/v/util/util.v +++ b/vlib/v/util/util.v @@ -514,3 +514,11 @@ pub fn find_all_v_files(roots []string) ?[]string { } return files } + +// free_caches knows about all `util` caches and makes sure that they are freed +// if you add another cached unsafe function using static, do not forget to add +// a mechanism to clear its cache, and call it here. +pub fn free_caches() { + unsafe { cached_read_source_file('') or {} } + unsafe { cached_file2sourcelines('') } +}