return mmodules.to_a
end
+ # Load recursively all modules of the group `mgroup`.
+ # See `parse` for details.
+ fun parse_group(mgroup: MGroup): Array[MModule]
+ do
+ var res = new Array[MModule]
+ visit_group(mgroup)
+ for mg in mgroup.in_nesting.smallers do
+ for mp in mg.module_paths do
+ var nmodule = self.load_module(mp.filepath)
+ if nmodule == null then continue # Skip error
+ # Load imported module
+ build_module_importation(nmodule)
+
+ res.add(nmodule.mmodule.as(not null))
+ end
+ end
+ return res
+ end
+
+ # Load a bunch of modules and groups.
+ # Each name can be a module or a group.
+ # If it is a group then recursively all its modules are parsed.
+ # See `parse` for details.
+ fun parse_full(names: Sequence[String]): Array[MModule]
+ do
+ var time0 = get_time
+ # Parse and recursively load
+ self.toolcontext.info("*** PARSE ***", 1)
+ var mmodules = new ArraySet[MModule]
+ for a in names do
+ var mgroup = self.get_mgroup(a)
+ if mgroup != null then
+ mmodules.add_all parse_group(mgroup)
+ continue
+ end
+ var nmodule = self.load_module(a)
+ if nmodule == null then continue # Skip error
+ # Load imported module
+ build_module_importation(nmodule)
+
+ mmodules.add(nmodule.mmodule.as(not null))
+ end
+ var time1 = get_time
+ self.toolcontext.info("*** END PARSE: {time1-time0} ***", 2)
+
+ self.toolcontext.check_errors
+
+ if toolcontext.opt_only_parse.value then
+ self.toolcontext.info("*** ONLY PARSE...", 1)
+ exit(0)
+ end
+
+ return mmodules.to_a
+ end
+
# The list of directories to search for top level modules
# The list is initially set with:
#
# Return the mgroup associated to a directory path.
# If the directory is not a group null is returned.
+ #
+ # Note: `paths` is also used to look for mgroups
fun get_mgroup(dirpath: String): nullable MGroup
do
+ if not dirpath.file_exists then do
+ for p in paths do
+ var try = p / dirpath
+ if try.file_exists then
+ dirpath = try
+ break label
+ end
+ end
+ return null
+ end label
+
var rdp = module_absolute_path(dirpath)
if mgroups.has_key(rdp) then
return mgroups[rdp]
var readme = dirpath2.join_path("README.md")
if not readme.file_exists then readme = dirpath2.join_path("README")
if readme.file_exists then
- var mdoc = new MDoc
- var s = new IFStream.open(readme)
- while not s.eof do
- mdoc.content.add(s.read_line)
- end
+ var mdoc = load_markdown(readme)
mgroup.mdoc = mdoc
mdoc.original_mentity = mgroup
end
return mgroup
end
+ # Load a markdown file as a documentation object
+ fun load_markdown(filepath: String): MDoc
+ do
+ var mdoc = new MDoc(new Location(new SourceFile.from_string(filepath, ""),0,0,0,0))
+ var s = new FileReader.open(filepath)
+ while not s.eof do
+ mdoc.content.add(s.read_line)
+ end
+ return mdoc
+ end
+
# Force the identification of all ModulePath of the group and sub-groups.
fun visit_group(mgroup: MGroup) do
var p = mgroup.filepath
self.toolcontext.info("load module {filename}", 2)
# Load the file
- var file = new IFStream.open(filename)
+ var file = new FileReader.open(filename)
var lexer = new Lexer(new SourceFile(filename, file))
var parser = new Parser(lexer)
var tree = parser.parse
return nmodule
end
+ # Remove Nit source files from a list of arguments.
+ #
+ # Items of `args` that can be loaded as a nit file will be removed from `args` and returned.
+ fun filter_nit_source(args: Array[String]): Array[String]
+ do
+ var keep = new Array[String]
+ var res = new Array[String]
+ for a in args do
+ var l = identify_file(a)
+ if l == null then
+ keep.add a
+ else
+ res.add a
+ end
+ end
+ args.clear
+ args.add_all(keep)
+ return res
+ 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.
# Look for the module
var file = identify_file(filename)
if file == null then
- toolcontext.error(null, "Error: cannot find module `{filename}`.")
+ if filename.file_exists then
+ toolcontext.error(null, "Error: `{filename}` is not a Nit source file.")
+ else
+ toolcontext.error(null, "Error: cannot find module `{filename}`.")
+ end
return null
end
end
end
+ # Check for conflicting module names in the project
+ if mgroup != null then
+ var others = model.get_mmodules_by_name(mod_name)
+ if others != null then for other in others do
+ if other.mgroup!= null and other.mgroup.mproject == mgroup.mproject then
+ var node: ANode
+ if decl == null then node = nmodule else node = decl.n_name
+ error(node, "Error: A module named `{other.full_name}` already exists at {other.location}")
+ break
+ end
+ end
+ end
+
# Create the module
var mmodule = new MModule(model, mgroup, mod_name, nmodule.location)
nmodule.mmodule = mmodule
nmodules.add(nmodule)
self.mmodule2nmodule[mmodule] = nmodule
+ var source = nmodule.location.file
+ if source != null then
+ assert source.mmodule == null
+ source.mmodule = mmodule
+ end
+
if decl != null then
+ # Extract documentation
var ndoc = decl.n_doc
if ndoc != null then
var mdoc = ndoc.to_mdoc
else
advice(decl, "missing-doc", "Documentation warning: Undocumented module `{mmodule}`")
end
+ # Is the module a test suite?
+ mmodule.is_test_suite = not decl.get_annotations("test_suite").is_empty
end
return mmodule
end
+redef class SourceFile
+ # Associated mmodule, once created
+ var mmodule: nullable MModule = null
+end
+
redef class AStdImport
# The imported module once determined
var mmodule: nullable MModule = null