From 9defbf989d2ea4d18632cc8b8e6036991403eddb Mon Sep 17 00:00:00 2001 From: joe-conigliaro Date: Tue, 8 Oct 2019 10:32:12 +1100 Subject: [PATCH] compiler: improve module import error messages --- compiler/main.v | 41 +++++++++++++++++++++++++++-------------- compiler/modules.v | 4 ++-- compiler/parser.v | 3 ++- compiler/table.v | 20 +++++++++++++------- 4 files changed, 44 insertions(+), 24 deletions(-) diff --git a/compiler/main.v b/compiler/main.v index 7b1c2b616f..14b7dd3c2c 100644 --- a/compiler/main.v +++ b/compiler/main.v @@ -216,21 +216,28 @@ fn (v mut V) add_parser(parser Parser) { v.parsers << parser } -// find existing parser or create new one. returns v.parsers index -fn (v mut V) parse(file string, pass Pass) int { - //println('parse($file, $pass)') +fn (v &V) get_file_parser_index(file string) ?int { for i, p in v.parsers { if os.realpath(p.file_path) == os.realpath(file) { - v.parsers[i].parse(pass) - //if v.parsers[i].pref.autofree { v.parsers[i].scanner.text.free() free(v.parsers[i].scanner) } return i } } - mut p := v.new_parser_from_file(file) - p.parse(pass) - //if p.pref.autofree { p.scanner.text.free() free(p.scanner) } - v.add_parser(p) - return v.parsers.len-1 + return error('parser for "$file" not found') +} + +// find existing parser or create new one. returns v.parsers index +fn (v mut V) parse(file string, pass Pass) int { + //println('parse($file, $pass)') + pidx := v.get_file_parser_index(file) or { + mut p := v.new_parser_from_file(file) + p.parse(pass) + //if p.pref.autofree { p.scanner.text.free() free(p.scanner) } + v.add_parser(p) + return v.parsers.len-1 + } + v.parsers[pidx].parse(pass) + //if v.parsers[i].pref.autofree { v.parsers[i].scanner.text.free() free(v.parsers[i].scanner) } + return pidx } @@ -622,7 +629,8 @@ fn (v mut V) add_v_files_to_compile() { // continue // } // standard module - vfiles := v.v_files_from_dir(v.find_module_path(mod)) + mod_path := v.find_module_path(mod) or { verror(err) break } + vfiles := v.v_files_from_dir(mod_path) for file in vfiles { v.files << file } @@ -694,10 +702,15 @@ fn (v mut V) parse_lib_imports() { for _, fit in v.table.file_imports { if fit.file_path in done_fits { continue } for _, mod in fit.imports { - import_path := v.find_module_path(mod) + import_path := v.find_module_path(mod) or { + pidx := v.get_file_parser_index(fit.file_path) or { verror(err) break } + v.parsers[pidx].error_with_token_index('cannot import module "$mod" (not found)', fit.get_import_tok_idx(mod)) + break + } vfiles := v.v_files_from_dir(import_path) if vfiles.len == 0 { - verror('cannot import module $mod (no .v files in "$import_path")') + pidx := v.get_file_parser_index(fit.file_path) or { verror(err) break } + v.parsers[pidx].error_with_token_index('cannot import module "$mod" (no .v files in "$import_path")', fit.get_import_tok_idx(mod)) } // Add all imports referenced by these libs for file in vfiles { @@ -706,7 +719,7 @@ fn (v mut V) parse_lib_imports() { done_imports << file p_mod := v.parsers[pid].import_table.module_name if p_mod != mod { - verror('bad module name: $file was imported as `$mod` but it is defined as module `$p_mod`') + v.parsers[pid].error_with_token_index('bad module definition: $fit.file_path imports module "$mod" but $file is defined as module `$p_mod`', 1) } } } diff --git a/compiler/modules.v b/compiler/modules.v index 7fd5e251a5..b47e06a60c 100644 --- a/compiler/modules.v +++ b/compiler/modules.v @@ -42,7 +42,7 @@ fn (v &V) module_path(mod string) string { // 'strings' => 'VROOT/vlib/strings' // 'installed_mod' => '~/.vmodules/installed_mod' // 'local_mod' => '/path/to/current/dir/local_mod' -fn (v &V) find_module_path(mod string) string { +fn (v &V) find_module_path(mod string) ?string { mod_path := v.module_path(mod) // First check for local modules in the same directory mut import_path := os.getwd() + '${os.PathSeparator}$mod_path' @@ -55,7 +55,7 @@ fn (v &V) find_module_path(mod string) string { if !os.dir_exists(import_path) { import_path = '$v_modules_path${os.PathSeparator}$mod_path' if !os.dir_exists(import_path){ - verror('module "$mod" not found') + return error('module "$mod" not found') } } return import_path diff --git a/compiler/parser.v b/compiler/parser.v index e8460b037e..ff2bf4c7fe 100644 --- a/compiler/parser.v +++ b/compiler/parser.v @@ -437,6 +437,7 @@ fn (p mut Parser) import_statement() { if p.peek() == .number { // && p.scanner.text[p.scanner.pos + 1] == `.` { p.error('bad import format. module/submodule names cannot begin with a number') } + import_tok_idx := p.token_idx-1 mut mod := p.check_name().trim_space() mut mod_alias := mod // submodule support @@ -457,7 +458,7 @@ fn (p mut Parser) import_statement() { mod_alias = p.check_name() } // add import to file scope import table - p.import_table.register_alias(mod_alias, mod) + p.import_table.register_alias(mod_alias, mod, import_tok_idx) // Make sure there are no duplicate imports if mod in p.table.imports { return diff --git a/compiler/table.v b/compiler/table.v index 1a4f360173..14f588bda7 100644 --- a/compiler/table.v +++ b/compiler/table.v @@ -53,10 +53,11 @@ mut: // Holds import information scoped to the parsed file struct FileImportTable { mut: - module_name string - file_path string - imports map[string]string // alias => module - used_imports []string // alias + module_name string + file_path string + imports map[string]string // alias => module + used_imports []string // alias + import_tok_idx map[string]int // module => idx } enum AccessMod { @@ -896,11 +897,11 @@ fn (fit &FileImportTable) known_import(mod string) bool { return mod in fit.imports || fit.is_aliased(mod) } -fn (fit mut FileImportTable) register_import(mod string) { - fit.register_alias(mod, mod) +fn (fit mut FileImportTable) register_import(mod string, tok_idx int) { + fit.register_alias(mod, mod, tok_idx) } -fn (fit mut FileImportTable) register_alias(alias string, mod string) { +fn (fit mut FileImportTable) register_alias(alias string, mod string, tok_idx int) { // NOTE: come back here // if alias in fit.imports && fit.imports[alias] == mod {} if alias in fit.imports && fit.imports[alias] != mod { @@ -919,6 +920,11 @@ fn (fit mut FileImportTable) register_alias(alias string, mod string) { } } fit.imports[alias] = mod + fit.import_tok_idx[mod] = tok_idx +} + +fn (fit &FileImportTable) get_import_tok_idx(mod string) int { + return fit.import_tok_idx[mod] } fn (fit &FileImportTable) known_alias(alias string) bool {