From: Jean Privat Date: Tue, 21 Jul 2015 18:10:09 +0000 (-0400) Subject: loader: basic implementation of conditional importations X-Git-Tag: v0.7.7~16^2~7 X-Git-Url: http://nitlanguage.org loader: basic implementation of conditional importations Signed-off-by: Jean Privat --- diff --git a/src/frontend/check_annotation.nit b/src/frontend/check_annotation.nit index eb05a14..d640ac2 100644 --- a/src/frontend/check_annotation.nit +++ b/src/frontend/check_annotation.nit @@ -76,6 +76,8 @@ private class CheckAnnotationPhase var primtives_annotations_list = """ new_annotation +conditional + deprecated fixed lazy diff --git a/src/loader.nit b/src/loader.nit index 75570ba..153bf9f 100644 --- a/src/loader.nit +++ b/src/loader.nit @@ -720,6 +720,10 @@ redef class ModelBuilder var stdimport = true var imported_modules = new Array[MModule] for aimport in nmodule.n_imports do + # Do not imports conditional + var atconditionals = aimport.get_annotations("conditional") + if atconditionals.not_empty then continue + stdimport = false if not aimport isa AStdImport then continue @@ -766,9 +770,56 @@ redef class ModelBuilder mmodule.set_visibility_for(sup, public_visibility) end end - self.toolcontext.info("{mmodule} imports {imported_modules.join(", ")}", 3) + + # Declare conditional importation + for aimport in nmodule.n_imports do + if not aimport isa AStdImport then continue + var atconditionals = aimport.get_annotations("conditional") + if atconditionals.is_empty then continue + + var suppath = seach_module_by_amodule_name(aimport.n_name, mmodule.mgroup) + if suppath == null then continue # skip error + + for atconditional in atconditionals do + var nargs = atconditional.n_args + if nargs.is_empty then + error(atconditional, "Syntax Error: `conditional` expects module identifiers as arguments.") + continue + end + + # The rule + var rule = new Array[Object] + + # First element is the goal, thus + rule.add suppath + + # Second element is the first condition, that is to be a client of the current module + rule.add mmodule + + # Other condition are to be also a client of each modules indicated as arguments of the annotation + for narg in nargs do + var id = narg.as_id + if id == null then + error(narg, "Syntax Error: `conditional` expects module identifier as arguments.") + continue + end + + var mp = search_mmodule_by_name(narg, mmodule.mgroup, id) + if mp == null then continue + + rule.add mp + end + + conditional_importations.add rule + end + end + mmodule.set_imported_mmodules(imported_modules) + apply_conditional_importations(mmodule) + + self.toolcontext.info("{mmodule} imports {mmodule.in_importation.direct_greaters.join(", ")}", 3) + # Force standard to be public if imported for sup in mmodule.in_importation.greaters do if sup.name == "standard" then @@ -789,6 +840,72 @@ redef class ModelBuilder end end + # Global list of conditional importation rules. + # + # Each rule is a "Horn clause"-like sequence of modules. + # It means that the first module is the module to automatically import. + # The remaining modules are the conditions of the rule. + # + # Each module is either represented by a MModule (if the module is already loaded) + # or by a ModulePath (if the module is not yet loaded). + # + # Rules are declared by `build_module_importation` and are applied by `apply_conditional_importations` + # (and `build_module_importation` that calls it). + # + # TODO (when the loader will be rewritten): use a better representation and move up rules in the model. + private var conditional_importations = new Array[SequenceRead[Object]] + + # Extends the current importations according to imported rules about conditional importation + fun apply_conditional_importations(mmodule: MModule) + do + # Because a conditional importation may cause additional conditional importation, use a fixed point + # The rules are checked naively because we assume that it does not worth to be optimized + var check_conditional_importations = true + while check_conditional_importations do + check_conditional_importations = false + + for ci in conditional_importations do + # Check conditions + for i in [1..ci.length[ do + var rule_element = ci[i] + # An element of a rule is either a MModule or a ModulePath + # We need the mmodule to resonate on the importation + var m + if rule_element isa MModule then + m = rule_element + else if rule_element isa ModulePath then + m = rule_element.mmodule + # Is loaded? + if m == null then continue label + else + abort + end + # Is imported? + if not mmodule.in_importation.greaters.has(m) then continue label + end + # Still here? It means that all conditions modules are loaded and imported + + # Identify the module to automatically import + var suppath = ci.first.as(ModulePath) + var sup = load_module_path(suppath) + if sup == null then continue + + # Do nothing if already imported + if mmodule.in_importation.greaters.has(sup) then continue label + + # Import it + self.toolcontext.info("{mmodule} conditionally imports {sup}", 3) + # TODO visibility rules (currently always public) + mmodule.set_visibility_for(sup, public_visibility) + # TODO linearization rules (currently added at the end in the order of the rules) + mmodule.set_imported_mmodules([sup]) + + # Prepare to reapply the rules + check_conditional_importations = true + end label + end + end + # All the loaded modules var nmodules = new Array[AModule]