compiler: improve module import error messages

pull/2257/head
joe-conigliaro 2019-10-08 10:32:12 +11:00 committed by Alexander Medvednikov
parent 64349b5006
commit 9defbf989d
4 changed files with 44 additions and 24 deletions

View File

@ -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)
}
}
}

View File

@ -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

View File

@ -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

View File

@ -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 {