X-Git-Url: http://nitlanguage.org diff --git a/src/loader.nit b/src/loader.nit index 56b7058..c0891a1 100644 --- a/src/loader.nit +++ b/src/loader.nit @@ -15,6 +15,26 @@ # limitations under the License. # Loading of Nit source files +# +# The loader takes care of looking for module and projects in the file system, and the associated case of errors. +# The loading requires several steps: +# +# Identify: create an empty model entity associated to a name or a file path. +# Identification is used for instance when names are given in the command line. +# See `identify_module` and `identify_group`. +# +# Scan: visit directories and identify their contents. +# Scanning is done to enable the searching of modules in projects. +# See `scan_group` and `scan_full`. +# +# Parse: load the AST and associate it with the model entity. +# See `MModule::parse`. +# +# Import: means recursively load modules imported by a module. +# See `build_module_importation`. +# +# Load: means doing the full sequence: identify, parse and import. +# See `ModelBuilder::parse`, `ModelBuilder::parse_full`, `MModule::load` `ModelBuilder::load_module. module loader import modelbuilder_base @@ -22,13 +42,13 @@ import ini redef class ToolContext # Option --path - var opt_path = new OptionArray("Set include path for loaders (may be used more than once)", "-I", "--path") + var opt_path = new OptionArray("Add an additional include path (may be used more than once)", "-I", "--path") # Option --only-metamodel var opt_only_metamodel = new OptionBool("Stop after meta-model processing", "--only-metamodel") # Option --only-parse - var opt_only_parse = new OptionBool("Only proceed to parse step of loaders", "--only-parse") + var opt_only_parse = new OptionBool("Only proceed to parse files", "--only-parse") redef init do @@ -84,7 +104,7 @@ redef class ModelBuilder if toolcontext.opt_only_parse.value then self.toolcontext.info("*** ONLY PARSE...", 1) - exit(0) + self.toolcontext.quit end return mmodules.to_a @@ -110,6 +130,7 @@ redef class ModelBuilder if stat != null and stat.is_dir then self.toolcontext.info("look in directory {a}", 2) var fs = a.files + alpha_comparator.sort(fs) # Try each entry as a group or a module for f in fs do var af = a/f @@ -131,6 +152,11 @@ redef class ModelBuilder var mmodule = identify_module(a) if mmodule == null then + if a.file_exists then + toolcontext.error(null, "Error: `{a}` is not a Nit source file.") + else + toolcontext.error(null, "Error: cannot find module `{a}`.") + end continue end @@ -173,7 +199,7 @@ redef class ModelBuilder if toolcontext.opt_only_parse.value then self.toolcontext.info("*** ONLY PARSE...", 1) - exit(0) + self.toolcontext.quit end return mmodules.to_a @@ -217,7 +243,9 @@ redef class ModelBuilder end end - var candidate = search_module_in_paths(anode.hot_location, name, lookpaths) + var loc = null + if anode != null then loc = anode.hot_location + var candidate = search_module_in_paths(loc, name, lookpaths) if candidate == null then if mgroup != null then @@ -505,12 +533,12 @@ redef class ModelBuilder return mdoc end - # Force the identification of all ModulePath of the group and sub-groups in the file system. + # Force the identification of all MModule of the group and sub-groups in the file system. # # When a group is scanned, its sub-groups hierarchy is filled (see `MGroup::in_nesting`) - # and the potential modules (and nested modules) are identified (see `MGroup::module_paths`). + # and the potential modules (and nested modules) are identified (see `MGroup::modules`). # - # Basically, this recursively call `get_mgroup` and `identify_file` on each directory entry. + # Basically, this recursively call `identify_group` and `identify_module` on each directory entry. # # No-op if the group was already scanned (see `MGroup::scanned`). fun scan_group(mgroup: MGroup) do @@ -519,7 +547,9 @@ redef class ModelBuilder var p = mgroup.filepath # a virtual group has nothing to scan if p == null then return - for f in p.files do + var files = p.files + alpha_comparator.sort(files) + for f in files do var fp = p/f var g = identify_group(fp) # Recursively scan for groups of the same package @@ -538,6 +568,10 @@ redef class ModelBuilder # Try to load a module AST using a path. # Display an error if there is a problem (IO / lexer / parser) and return null + # + # The AST is loaded as is total independence of the model and its entities. + # + # AST are not cached or reused thus a new AST is returned on success. fun load_module_ast(filename: String): nullable AModule do if not filename.has_suffix(".nit") then @@ -623,6 +657,7 @@ redef class ModelBuilder var mmodule = new MModule(model, mgroup, mod_name, nmodule.location) nmodule.mmodule = mmodule nmodules.add(nmodule) + parsed_modules.add mmodule self.mmodule2nmodule[mmodule] = nmodule if parent!= null then @@ -681,8 +716,6 @@ redef class ModelBuilder var mdoc = ndoc.to_mdoc mmodule.mdoc = mdoc mdoc.original_mentity = mmodule - 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 @@ -769,7 +802,10 @@ redef class ModelBuilder # Analyze the module importation and fill the module_importation_hierarchy # - # Unless you used `load_module`, the importation is already done and this method does a no-op. + # If the importation was already done (`nmodule.is_importation_done`), this method does a no-op. + # + # REQUIRE `nmodule.mmodule != null` + # ENSURE `nmodule.is_importation_done` fun build_module_importation(nmodule: AModule) do if nmodule.is_importation_done then return