- private var try_get_mproperty_by_name2_cache: HashMap3[MModule, MType, String, nullable MProperty] = new HashMap3[MModule, MType, String, nullable MProperty]
-
-
- # Alias for try_get_mproperty_by_name2(anode, mclassdef.mmodule, mclassdef.mtype, name)
- fun try_get_mproperty_by_name(anode: ANode, mclassdef: MClassDef, name: String): nullable MProperty
- do
- return try_get_mproperty_by_name2(anode, mclassdef.mmodule, mclassdef.bound_mtype, name)
- end
-
- # The list of directories to search for top level modules
- # The list is initially set with :
- # * the toolcontext --path option
- # * the NIT_PATH environment variable
- # * some heuristics including the NIT_DIR environment variable and the progname of the process
- # Path can be added (or removed) by the client
- var paths: Array[String] = new Array[String]
-
- # Get a module by its short name; if required, the module is loaded, parsed and its hierarchies computed.
- # If `mmodule' is set, then the module search starts from it up to the top level (see `paths');
- # if `mmodule' is null then the module is searched in the top level only.
- # If no module exists or there is a name conflict, then an error on `anode' is displayed and null is returned.
- # FIXME: add a way to handle module name conflict
- fun get_mmodule_by_name(anode: ANode, mmodule: nullable MModule, name: String): nullable MModule
- do
- var origmmodule = mmodule
- var modules = model.get_mmodules_by_name(name)
-
- var tries = new Array[String]
-
- var lastmodule = mmodule
- while mmodule != null do
- var dirname = mmodule.location.file.filename.dirname
-
- # Determine the owner
- var owner: nullable MModule
- if dirname.basename("") != mmodule.name then
- owner = mmodule.direct_owner
- else
- owner = mmodule
- end
-
- # First, try the already known nested modules
- if modules != null then
- for candidate in modules do
- if candidate.direct_owner == owner then
- return candidate
- end
- end
- end
-
- # Second, try the directory to find a file
- var try_file = dirname + "/" + name + ".nit"
- tries.add try_file
- if try_file.file_exists then
- var res = self.load_module(owner, try_file.simplify_path)
- if res == null then return null # Forward error
- return res.mmodule.as(not null)
- end
-
- # Third, try if the requested module is itself an owner
- try_file = dirname + "/" + name + "/" + name + ".nit"
- if try_file.file_exists then
- var res = self.load_module(owner, try_file.simplify_path)
- if res == null then return null # Forward error
- return res.mmodule.as(not null)
- end
-
- lastmodule = mmodule
- mmodule = mmodule.direct_owner
- end
-
- if modules != null then
- for candidate in modules do
- if candidate.direct_owner == null then
- return candidate
- end
- end
- end
-
- # Look at some known directories
- var lookpaths = self.paths
-
- # Look in the directory of the last module also (event if not in the path)
- if lastmodule != null then
- var dirname = lastmodule.location.file.filename.dirname
- if dirname.basename("") == lastmodule.name then
- dirname = dirname.dirname
- end
- if not lookpaths.has(dirname) then
- lookpaths = lookpaths.to_a
- lookpaths.add(dirname)
- end
- end
-
- var candidate: nullable String = null
- for dirname in lookpaths do
- var try_file = (dirname + "/" + name + ".nit").simplify_path
- tries.add try_file
- if try_file.file_exists then
- if candidate == null then
- candidate = try_file
- else if candidate != try_file then
- error(anode, "Error: conflicting module file for {name}: {candidate} {try_file}")
- end
- end
- try_file = (dirname + "/" + name + "/" + name + ".nit").simplify_path
- if try_file.file_exists then
- if candidate == null then
- candidate = try_file
- else if candidate != try_file then
- error(anode, "Error: conflicting module file for {name}: {candidate} {try_file}")
- end
- end
- end
- if candidate == null then
- if origmmodule != null then
- error(anode, "Error: cannot find module {name} from {origmmodule}. tried {tries.join(", ")}")
- else
- error(anode, "Error: cannot find module {name}. tried {tries.join(", ")}")
- end
- return null
- end
- var res = self.load_module(mmodule, candidate)
- if res == null then return null # Forward error
- return res.mmodule.as(not null)
- end
-
- # Try to load a module using a path.
- # Display an error if there is a problem (IO / lexer / parser) and return null
- # Note: usually, you do not need this method, use `get_mmodule_by_name` instead.
- fun load_module(owner: nullable MModule, filename: String): nullable AModule
- do
- if not filename.file_exists then
- self.toolcontext.error(null, "Error: file {filename} not found.")
- return null
- end
-
- var x = if owner != null then owner.to_s else "."
- self.toolcontext.info("load module {filename} in {x}", 2)
-
- # Load the file
- var file = new IFStream.open(filename)
- var lexer = new Lexer(new SourceFile(filename, file))
- var parser = new Parser(lexer)
- var tree = parser.parse
- file.close
-
- # Handle lexer and parser error
- var nmodule = tree.n_base
- if nmodule == null then
- var neof = tree.n_eof
- assert neof isa AError
- error(neof, neof.message)
- return null
- end
-
- # Check the module name
- var mod_name = filename.basename(".nit")
- var decl = nmodule.n_moduledecl
- if decl == null then
- #warning(nmodule, "Warning: Missing 'module' keyword") #FIXME: NOT YET FOR COMPATIBILITY
- else
- var decl_name = decl.n_name.n_id.text
- if decl_name != mod_name then
- error(decl.n_name, "Error: module name missmatch; declared {decl_name} file named {mod_name}")
- end
- end
-
- # Create the module
- var mmodule = new MModule(model, owner, mod_name, nmodule.location)
- nmodule.mmodule = mmodule
- nmodules.add(nmodule)
- self.mmodule2nmodule[mmodule] = nmodule
-
- build_module_importation(nmodule)