nitc :: ModelBuilder :: identify_module
This method does what the user expects when giving an argument to a Nit tool.
path
is an existing Nit source file (with the .nit
extension),
then the associated MModule is returnedpath
is a directory (with a /
),
then the MModule of its default module is returned (if any)path
is a simple identifier (eg. digraph
),
then the main module of the package digraph
is searched in paths
and returned.Silently return null
if path
does not exists or cannot be identified.
If null
is returned, last_loader_error
can be set to a specific error message.
On success, it returns a module that is possibly not yet parsed (no AST), or not yet analysed (no importation). If the module was already identified, or loaded, it is returned.
# Identify a source file and load the associated package and groups if required.
#
# This method does what the user expects when giving an argument to a Nit tool.
#
# * If `path` is an existing Nit source file (with the `.nit` extension),
# then the associated MModule is returned
# * If `path` is a directory (with a `/`),
# then the MModule of its default module is returned (if any)
# * If `path` is a simple identifier (eg. `digraph`),
# then the main module of the package `digraph` is searched in `paths` and returned.
#
# Silently return `null` if `path` does not exists or cannot be identified.
# If `null` is returned, `last_loader_error` can be set to a specific error message.
#
# On success, it returns a module that is possibly not yet parsed (no AST), or not yet analysed (no importation).
# If the module was already identified, or loaded, it is returned.
fun identify_module(path: String): nullable MModule
do
last_loader_error = null
# special case for not a nit file
if not path.has_suffix(".nit") then do
# search dirless files in known -I paths
if not path.chars.has('/') then
var res = search_module_in_paths(null, path, self.paths)
if res != null then return res
end
# Found nothing? maybe it is a group...
if path.file_exists then
var mgroup = identify_group(path)
if mgroup != null then
var owner_path = mgroup.filepath.join_path(mgroup.name + ".nit")
if owner_path.file_exists then
path = owner_path
break
end
end
end
# Found nothing? maybe it is a qualified name
if path.chars.has(':') then
var ids = path.split("::")
var g = identify_group(ids.first)
if g != null then
scan_group(g)
var ms = g.mmodules_by_name(ids.last)
# Return exact match
for m in ms do
if m.full_name == path then
return m
end
end
# Where there is only one or two names `foo::bar`
# then accept module that matches `foo::*::bar`
if ids.length <= 2 then
if ms.length == 1 then return ms.first
if ms.length > 1 then
var l = new Array[String]
for m in ms do
var fp = m.filepath
if fp != null then fp = " ({fp})" else fp = ""
l.add "`{m.full_name}`{fp}"
end
last_loader_error = "Error: conflicting module for `{path}`: {l.join(", ")} "
return null
end
end
var bests = new BestDistance[String](path.length / 2)
# We found nothing. But propose something in the package?
for sg in g.mpackage.mgroups do
for m in sg.mmodules do
var d = path.levenshtein_distance(m.full_name)
bests.update(d, m.full_name)
end
end
var last_loader_error = "Error: cannot find module `{path}`."
if bests.best_items.not_empty then
last_loader_error += " Did you mean " + bests.best_items.join(", ", " or ") + "?"
end
self.last_loader_error = last_loader_error
return null
end
end
return null
end
# Does the file exists?
if not path.file_exists then
return null
end
# Fast track, the path is already known
if identified_modules_by_path.has_key(path) then return identified_modules_by_path[path]
var rp = module_absolute_path(path)
if identified_modules_by_path.has_key(rp) then return identified_modules_by_path[rp]
var pn = path.basename(".nit")
# Search for a group
var mgrouppath = path.join_path("..").simplify_path
var mgroup = identify_group(mgrouppath)
if mgroup != null then
var mpackage = mgroup.mpackage
if not mpackage.accept(path) then
mgroup = null
toolcontext.info("module `{path}` excluded from package `{mpackage}`", 2)
end
end
if mgroup == null then
# singleton package
var loc = new Location.opaque_file(path)
var mpackage = new MPackage(pn, model, loc)
mgroup = new MGroup(pn, loc, mpackage, null) # same name for the root group
mpackage.root = mgroup
toolcontext.info("found singleton package `{pn}` at {path}", 2)
# Attach homonymous `ini` file to the package
var inipath = path.dirname / "{pn}.ini"
if inipath.file_exists then
var ini = new IniFile.from_file(inipath)
mpackage.ini = ini
end
end
var loc = new Location.opaque_file(path)
var res = new MModule(model, mgroup, pn, loc)
identified_modules_by_path[rp] = res
identified_modules_by_path[path] = res
identified_modules.add(res)
return res
end
src/loader.nit:355,2--492,4