package jetbrains.mps.make.dependencies; /*Generated by MPS */ import java.util.Map; import org.jetbrains.mps.openapi.module.SModuleReference; import org.jetbrains.mps.openapi.module.SModule; import jetbrains.mps.internal.collections.runtime.MapSequence; import java.util.HashMap; import jetbrains.mps.smodel.language.LanguageRegistry; import java.util.Set; import jetbrains.mps.internal.collections.runtime.SetSequence; import java.util.HashSet; import jetbrains.mps.internal.collections.runtime.Sequence; import jetbrains.mps.internal.collections.runtime.ITranslator2; import java.util.List; import java.util.Iterator; import jetbrains.mps.internal.collections.runtime.ListSequence; import jetbrains.mps.internal.collections.runtime.ISelector; import jetbrains.mps.internal.collections.runtime.IListSequence; import org.jetbrains.mps.openapi.language.SLanguage; import jetbrains.mps.baseLanguage.closures.runtime.Wrappers; import jetbrains.mps.baseLanguage.closures.runtime.YieldingIterator; import jetbrains.mps.internal.collections.runtime.IMapping; import jetbrains.mps.project.dependency.GlobalModuleDependenciesManager; import jetbrains.mps.internal.collections.runtime.CollectionSequence; import jetbrains.mps.smodel.Generator; import org.jetbrains.mps.openapi.model.SModel; import jetbrains.mps.generator.impl.plan.ModelContentUtil; import jetbrains.mps.smodel.SLanguageHierarchy; import jetbrains.mps.internal.collections.runtime.NotNullWhereFilter; import jetbrains.mps.smodel.language.LanguageRuntime; import jetbrains.mps.smodel.language.GeneratorRuntime; import java.util.LinkedList; import jetbrains.mps.internal.make.runtime.util.GraphAnalyzer; import jetbrains.mps.internal.collections.runtime.IWhereFilter; public class ModulesCluster { private Map<SModuleReference, SModule> modulesView = MapSequence.fromMap(new HashMap<SModuleReference, SModule>()); private Map<SModuleReference, ModulesCluster.ModuleDeps> allDeps = MapSequence.fromMap(new HashMap<SModuleReference, ModulesCluster.ModuleDeps>()); private final LanguageRegistry myLanguageRegistry; public ModulesCluster(Iterable<SModule> mods, LanguageRegistry languageRegistry) { myLanguageRegistry = languageRegistry; addAll(mods); } public void add(SModule mod) { this.primAdd(mod); } public void addAll(Iterable<SModule> mods) { for (SModule mod : mods) { primAdd(mod); } } public void collectRequired(Iterable<SModule> pool) { // XXX pool is identical to initial sequence from cons, modulesView.keyset and allDeps.keyset. Why do I need to pass it here? Set<SModuleReference> allRequired = SetSequence.fromSetWithValues(new HashSet<SModuleReference>(), Sequence.fromIterable(MapSequence.fromMap(allDeps).values()).translate(new ITranslator2<ModulesCluster.ModuleDeps, SModuleReference>() { public Iterable<SModuleReference> translate(ModulesCluster.ModuleDeps dep) { return dep.required; } })); List<SModule> available = Sequence.fromIterable(pool).toListSequence(); int atSize; do { atSize = MapSequence.fromMap(allDeps).count(); for (Iterator<SModule> it = ListSequence.fromList(available).iterator(); it.hasNext();) { SModule mod = it.next(); SModuleReference mr = mod.getModuleReference(); if (SetSequence.fromSet(allRequired).contains(mr)) { primAdd(mod); SetSequence.fromSet(allRequired).addSequence(ListSequence.fromList(MapSequence.fromMap(allDeps).get(mr).required)); it.remove(); } } } while (atSize < MapSequence.fromMap(allDeps).count()); } public Iterable<? extends Iterable<SModule>> buildOrder() { List<List<SModuleReference>> order = new ModulesCluster.ModulesGraph().totalOrder(); Iterable<? extends Iterable<SModuleReference>> compacted = Sequence.fromIterable(this.compact(order)).toListSequence(); return Sequence.fromIterable(compacted).select(new ISelector<Iterable<SModuleReference>, IListSequence<SModule>>() { public IListSequence<SModule> select(Iterable<SModuleReference> cycle) { return Sequence.fromIterable(cycle).select(new ISelector<SModuleReference, SModule>() { public SModule select(SModuleReference mr) { return MapSequence.fromMap(modulesView).get(mr); } }).toListSequence(); } }).toListSequence(); } public Iterable<SLanguage> usedLanguage(SModule m) { // we need used languages to determine build order (in case language/generator module is among those being built) // and also we need these languages to detect facets to activate in build script. Not to build this set twice, re-use once computed assert MapSequence.fromMap(modulesView).containsKey(m.getModuleReference()); return MapSequence.fromMap(allDeps).get(m.getModuleReference()).usedLanguages; } private Iterable<? extends Iterable<SModuleReference>> compact(List<List<SModuleReference>> order) { final Wrappers._T<Iterable<SModuleReference>> prev = new Wrappers._T<Iterable<SModuleReference>>(null); return ListSequence.fromList(order).concat(Sequence.fromIterable(Sequence.<List<SModuleReference>>singleton(null))).translate(new ITranslator2<List<SModuleReference>, Iterable<SModuleReference>>() { public Iterable<Iterable<SModuleReference>> translate(final List<SModuleReference> cycle) { return new Iterable<Iterable<SModuleReference>>() { public Iterator<Iterable<SModuleReference>> iterator() { return new YieldingIterator<Iterable<SModuleReference>>() { private int __CP__ = 0; protected boolean moveToNext() { __loop__: do { __switch__: switch (this.__CP__) { case -1: assert false : "Internal error"; return false; case 2: if (cycle == null) { this.__CP__ = 3; break; } else if (prev.value == null) { this.__CP__ = 6; break; } this.__CP__ = 8; break; case 9: if (ListSequence.fromList(cycle).translate(new ITranslator2<SModuleReference, SModuleReference>() { public Iterable<SModuleReference> translate(SModuleReference mr) { return MapSequence.fromMap(allDeps).get(mr).required; } }).intersect(Sequence.fromIterable(prev.value).translate(new ITranslator2<SModuleReference, SModuleReference>() { public Iterable<SModuleReference> translate(SModuleReference mr) { return MapSequence.fromMap(allDeps).get(mr).dependent; } })).isEmpty()) { this.__CP__ = 10; break; } this.__CP__ = 12; break; case 4: this.__CP__ = 5; this.yield(prev.value); return true; case 13: this.__CP__ = 14; this.yield(prev.value); return true; case 0: this.__CP__ = 2; break; case 3: this.__CP__ = 4; break; case 5: prev.value = null; this.__CP__ = 1; break; case 6: prev.value = ListSequence.fromList(cycle).toListSequence(); this.__CP__ = 1; break; case 8: this.__CP__ = 9; break; case 10: prev.value = Sequence.fromIterable(prev.value).concat(ListSequence.fromList(cycle).toListSequence()); this.__CP__ = 1; break; case 12: this.__CP__ = 13; break; case 14: prev.value = ListSequence.fromList(cycle).toListSequence(); this.__CP__ = 1; break; default: break __loop__; } } while (true); return false; } }; } }; } }); } private void primAdd(SModule mod) { SModuleReference mr = mod.getModuleReference(); if (!(MapSequence.fromMap(modulesView).containsKey(mr))) { MapSequence.fromMap(modulesView).put(mr, mod); updateDeps(mod); } } private void updateDeps(SModule mod) { SModuleReference mr = mod.getModuleReference(); ModulesCluster.ModuleDeps deps = MapSequence.fromMap(allDeps).get(mr); // how come allDeps could have been initilized for the module already? // likely, could drop this == null check, provided the method is private now and the only us is from primAdd, which ensures unique call if (deps == null) { deps = initialModuleDeps(mod); MapSequence.fromMap(allDeps).put(mr, deps); } // if we've already seen modules this one depends from, tell them there's new dependant module for them for (SModuleReference req : deps.required) { if (MapSequence.fromMap(allDeps).containsKey(req)) { ListSequence.fromList(MapSequence.fromMap(allDeps).get(req).dependent).addElement(mr); } } // if we've seen modules that depend from this one, record them in the current module as dependants for (IMapping<SModuleReference, ModulesCluster.ModuleDeps> m : MapSequence.fromMap(allDeps).mappingsSet()) { if (ListSequence.fromList(m.value().required).contains(mr) && !(ListSequence.fromList(deps.dependent).contains(m.key()))) { ListSequence.fromList(deps.dependent).addElement(m.key()); } } } private ModulesCluster.ModuleDeps initialModuleDeps(SModule mod) { ModulesCluster.ModuleDeps rv = new ModulesCluster.ModuleDeps(mod.getModuleReference()); GlobalModuleDependenciesManager depman = new GlobalModuleDependenciesManager(mod); Set<SLanguage> moduleUsedLanguages; Set<SModule> reqmods = SetSequence.fromSet(new HashSet<SModule>()); SetSequence.fromSet(reqmods).addSequence(CollectionSequence.fromCollection(depman.getModules(GlobalModuleDependenciesManager.Deptype.COMPILE))); SetSequence.fromSet(reqmods).addSequence(CollectionSequence.fromCollection(depman.getModules(GlobalModuleDependenciesManager.Deptype.VISIBLE))); Set<SModuleReference> reqs = SetSequence.fromSetWithValues(new HashSet<SModuleReference>(), SetSequence.fromSet(reqmods).select(new ISelector<SModule, SModuleReference>() { public SModuleReference select(SModule m) { return m.getModuleReference(); } })); if (mod instanceof Generator) { Generator generator = (Generator) mod; // FIXME is it true GMDM doesn't recognize generator's source language as COMPILE or VISIBLE dependency? SetSequence.fromSet(reqs).addElement(generator.getSourceLanguage().getModuleReference()); moduleUsedLanguages = SetSequence.fromSet(new HashSet<SLanguage>()); for (SModel m : generator.getModels()) { SetSequence.fromSet(moduleUsedLanguages).addSequence(CollectionSequence.fromCollection(ModelContentUtil.getUsedLanguages(m))); } } else { moduleUsedLanguages = mod.getUsedLanguages(); // XXX ModelContentUtil adds auto-imported and engaged on generation lagnuages as well, shall I use it here, too? // I didn't add them as previous version relied on SModule.getUsedLanguages() collection, which does not include engaged nor auto-imports, and is working for years } Set<SLanguage> allUsedLanguages = new SLanguageHierarchy(myLanguageRegistry, moduleUsedLanguages).getExtended(); SetSequence.fromSet(rv.usedLanguages).addSequence(SetSequence.fromSet(allUsedLanguages)); // if a module of any used language happens to be among modules to build, ensure it's build first... SetSequence.fromSet(reqs).addSequence(SetSequence.fromSet(allUsedLanguages).select(new ISelector<SLanguage, SModuleReference>() { public SModuleReference select(SLanguage it) { return it.getSourceModuleReference(); } }).where(new NotNullWhereFilter<SModuleReference>())); // ...as well its generators for (LanguageRuntime lr : SetSequence.fromSet(allUsedLanguages).select(new ISelector<SLanguage, LanguageRuntime>() { public LanguageRuntime select(SLanguage it) { return myLanguageRegistry.getLanguage(it); } }).where(new NotNullWhereFilter<LanguageRuntime>())) { for (GeneratorRuntime gr : lr.getGenerators()) { SetSequence.fromSet(reqs).addElement(gr.getModuleReference()); } } // XXX perhaps, we shall respect target languages of used languages as well, as they may appear while generating this module. // We need them anyway to build required facets in ModulesClusterizer.allLanguagesToActivateFacets ListSequence.fromList(rv.required).addSequence(SetSequence.fromSet(reqs)); return rv; } /*package*/ static class ModuleDeps { private List<SModuleReference> dependent = ListSequence.fromList(new LinkedList<SModuleReference>()); private List<SModuleReference> required = ListSequence.fromList(new LinkedList<SModuleReference>()); private final Set<SLanguage> usedLanguages = SetSequence.fromSet(new HashSet<SLanguage>()); public ModuleDeps(SModuleReference mod) { ListSequence.fromList(dependent).addElement(mod); ListSequence.fromList(required).addElement(mod); } } public class ModulesGraph extends GraphAnalyzer<SModuleReference> { public ModulesGraph() { } @Override public Iterable<SModuleReference> forwardEdges(SModuleReference v) { return ListSequence.fromList(MapSequence.fromMap(allDeps).get(v).dependent).where(new IWhereFilter<SModuleReference>() { public boolean accept(SModuleReference mod) { return MapSequence.fromMap(allDeps).containsKey(mod); } }); } @Override public Iterable<SModuleReference> backwardEdges(SModuleReference v) { return ListSequence.fromList(MapSequence.fromMap(allDeps).get(v).required).where(new IWhereFilter<SModuleReference>() { public boolean accept(SModuleReference mod) { return MapSequence.fromMap(allDeps).containsKey(mod); } }); } @Override public Iterable<SModuleReference> vertices() { return MapSequence.fromMap(allDeps).keySet(); } } }