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();
}
}
}