X-Git-Url: http://nitlanguage.org diff --git a/src/modelbuilder.nit b/src/modelbuilder.nit index dc48ee9..1ae7e45 100644 --- a/src/modelbuilder.nit +++ b/src/modelbuilder.nit @@ -22,11 +22,7 @@ # FIXME add missing error checks module modelbuilder -import parser import model -import poset -import opts -import toolcontext import phase private import more_collections @@ -35,16 +31,16 @@ private import more_collections redef class ToolContext # Option --path - var opt_path: OptionArray = new OptionArray("Set include path for loaders (may be used more than once)", "-I", "--path") + var opt_path = new OptionArray("Set include path for loaders (may be used more than once)", "-I", "--path") # Option --only-metamodel - var opt_only_metamodel: OptionBool = new OptionBool("Stop after meta-model processing", "--only-metamodel") + var opt_only_metamodel = new OptionBool("Stop after meta-model processing", "--only-metamodel") # Option --only-parse - var opt_only_parse: OptionBool = new OptionBool("Only proceed to parse step of loaders", "--only-parse") + var opt_only_parse = new OptionBool("Only proceed to parse step of loaders", "--only-parse") # Option --ignore-visibility - var opt_ignore_visibility: OptionBool = new OptionBool("Do not check, and produce errors, on visibility issues.", "--ignore-visibility") + var opt_ignore_visibility = new OptionBool("Do not check, and produce errors, on visibility issues.", "--ignore-visibility") redef init do @@ -52,11 +48,13 @@ redef class ToolContext option_context.add_option(opt_path, opt_only_parse, opt_only_metamodel, opt_ignore_visibility) end + # The modelbuilder 1-to-1 associated with the toolcontext fun modelbuilder: ModelBuilder do return modelbuilder_real.as(not null) + private var modelbuilder_real: nullable ModelBuilder = null - # Run `process_mainmodule` on all phases - fun run_global_phases(mmodules: Array[MModule]) + # Combine module to make a single one if required. + fun make_main_module(mmodules: Array[MModule]): MModule do assert not mmodules.is_empty var mainmodule @@ -64,9 +62,17 @@ redef class ToolContext mainmodule = mmodules.first else # We need a main module, so we build it by importing all modules - mainmodule = new MModule(modelbuilder.model, null, mmodules.first.name, new Location(null, 0, 0, 0, 0)) + mainmodule = new MModule(modelbuilder.model, null, mmodules.first.name + "-m", new Location(mmodules.first.location.file, 0, 0, 0, 0)) + mainmodule.is_fictive = true mainmodule.set_imported_mmodules(mmodules) end + return mainmodule + end + + # Run `process_mainmodule` on all phases + fun run_global_phases(mmodules: Array[MModule]) + do + var mainmodule = make_main_module(mmodules) for phase in phases_list do if phase.disabled then continue phase.process_mainmodule(mainmodule, mmodules) @@ -119,10 +125,8 @@ class ModelBuilder # Instantiate a modelbuilder for a model and a toolcontext # Important, the options of the toolcontext must be correctly set (parse_option already called) - init(model: Model, toolcontext: ToolContext) + init do - self.model = model - self.toolcontext = toolcontext assert toolcontext.modelbuilder_real == null toolcontext.modelbuilder_real = self @@ -135,10 +139,8 @@ class ModelBuilder end var nit_dir = toolcontext.nit_dir - if nit_dir != null then - var libname = "{nit_dir}/lib" - if libname.file_exists then paths.add(libname) - end + var libname = "{nit_dir}/lib" + if libname.file_exists then paths.add(libname) end # Load a bunch of modules. @@ -219,6 +221,12 @@ class ModelBuilder for mprop in props do if not mtype.has_mproperty(mmodule, mprop) then continue if not mmodule.is_visible(mprop.intro_mclassdef.mmodule, mprop.visibility) then continue + + # new-factories are invisible outside of the class + if mprop isa MMethod and mprop.is_new and (not mtype isa MClassType or mprop.intro_mclassdef.mclass != mtype.mclass) then + continue + end + if res == null then res = mprop continue @@ -276,7 +284,7 @@ class ModelBuilder return res end - private var try_get_mproperty_by_name2_cache: HashMap3[MModule, MType, String, nullable MProperty] = new HashMap3[MModule, MType, String, nullable MProperty] + private var try_get_mproperty_by_name2_cache = new HashMap3[MModule, MType, String, nullable MProperty] # Alias for try_get_mproperty_by_name2(anode, mclassdef.mmodule, mclassdef.mtype, name) @@ -291,7 +299,7 @@ class ModelBuilder # * the NIT_PATH environment variable # * `toolcontext.nit_dir` # Path can be added (or removed) by the client - var paths: Array[String] = new Array[String] + var paths = new Array[String] # Like (an used by) `get_mmodule_by_name` but just return the ModulePath private fun search_mmodule_by_name(anode: ANode, mgroup: nullable MGroup, name: String): nullable ModulePath @@ -474,10 +482,12 @@ class ModelBuilder var pn = rdp.basename(".nit") var mp = dirpath.join_path(pn + ".nit").simplify_path + var dirpath2 = dirpath if not mp.file_exists then if pn == "src" then # With a src directory, the group name is the name of the parent directory - pn = rdp.dirname.basename("") + dirpath2 = rdp.dirname + pn = dirpath2.basename("") else return null end @@ -498,6 +508,17 @@ class ModelBuilder mgroup = new MGroup(pn, parent.mproject, parent) toolcontext.info("found sub group `{mgroup.full_name}` at {dirpath}", 2) end + 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 + mgroup.mdoc = mdoc + mdoc.original_mentity = mgroup + end mgroup.filepath = dirpath mgroups[rdp] = mgroup return mgroup @@ -529,7 +550,6 @@ class ModelBuilder var parser = new Parser(lexer) var tree = parser.parse file.close - var mod_name = filename.basename(".nit") # Handle lexer and parser error var nmodule = tree.n_base @@ -576,20 +596,27 @@ class ModelBuilder return nmodule end - fun load_rt_module(parent: MModule, nmodule: AModule, mod_name: String): nullable AModule + # Injection of a new module without source. + # Used by the interpreted + fun load_rt_module(parent: nullable MModule, nmodule: AModule, mod_name: String): nullable AModule do # Create the module - var mmodule = new MModule(model, parent.mgroup, mod_name, nmodule.location) + + var mgroup = null + if parent != null then mgroup = parent.mgroup + var mmodule = new MModule(model, mgroup, mod_name, nmodule.location) nmodule.mmodule = mmodule nmodules.add(nmodule) self.mmodule2nmodule[mmodule] = nmodule - var imported_modules = new Array[MModule] - - imported_modules.add(parent) - mmodule.set_visibility_for(parent, intrude_visibility) - - mmodule.set_imported_mmodules(imported_modules) + if parent!= null then + var imported_modules = new Array[MModule] + imported_modules.add(parent) + mmodule.set_visibility_for(parent, intrude_visibility) + mmodule.set_imported_mmodules(imported_modules) + else + build_module_importation(nmodule) + end return nmodule end @@ -616,7 +643,13 @@ class ModelBuilder if decl != null then var ndoc = decl.n_doc - if ndoc != null then mmodule.mdoc = ndoc.to_mdoc + if ndoc != null then + var mdoc = ndoc.to_mdoc + mmodule.mdoc = mdoc + mdoc.original_mentity = mmodule + else + advice(decl, "missing-doc", "Documentation warning: Undocumented module `{mmodule}`") + end end return mmodule @@ -671,14 +704,33 @@ class ModelBuilder end self.toolcontext.info("{mmodule} imports {imported_modules.join(", ")}", 3) mmodule.set_imported_mmodules(imported_modules) + + # Force standard to be public if imported + for sup in mmodule.in_importation.greaters do + if sup.name == "standard" then + mmodule.set_visibility_for(sup, public_visibility) + end + end + + # TODO: Correctly check for useless importation + # It is even doable? + var directs = mmodule.in_importation.direct_greaters + for nim in nmodule.n_imports do + if not nim isa AStdImport then continue + var im = nim.mmodule + if im == null then continue + if directs.has(im) then continue + # This generates so much noise that it is simpler to just comment it + #warning(nim, "Warning: possible useless importation of {im}") + end end # All the loaded modules - var nmodules: Array[AModule] = new Array[AModule] + var nmodules = new Array[AModule] # Register the nmodule associated to each mmodule # FIXME: why not refine the `MModule` class with a nullable attribute? - var mmodule2nmodule: HashMap[MModule, AModule] = new HashMap[MModule, AModule] + var mmodule2nmodule = new HashMap[MModule, AModule] # Helper function to display an error on a node. # Alias for `self.toolcontext.error(n.hot_location, text)` @@ -689,17 +741,26 @@ class ModelBuilder # Helper function to display a warning on a node. # Alias for: `self.toolcontext.warning(n.hot_location, text)` - fun warning(n: ANode, text: String) + fun warning(n: ANode, tag, text: String) + do + self.toolcontext.warning(n.hot_location, tag, text) + end + + # Helper function to display an advice on a node. + # Alias for: `self.toolcontext.advice(n.hot_location, text)` + fun advice(n: ANode, tag, text: String) do - self.toolcontext.warning(n.hot_location, text) + self.toolcontext.advice(n.hot_location, tag, text) end # Force to get the primitive method named `name` on the type `recv` or do a fatal error on `n` - fun force_get_primitive_method(n: ANode, name: String, recv: MClass, mmodule: MModule): MMethod + fun force_get_primitive_method(n: nullable ANode, name: String, recv: MClass, mmodule: MModule): MMethod do var res = mmodule.try_get_primitive_method(name, recv) if res == null then - self.toolcontext.fatal_error(n.hot_location, "Fatal Error: {recv} must have a property named {name}.") + var l = null + if n != null then l = n.hot_location + self.toolcontext.fatal_error(l, "Fatal Error: {recv} must have a property named {name}.") abort end return res