package jetbrains.mps.smodel;
/*Generated by MPS */
import java.util.Set;
import org.jetbrains.mps.openapi.model.SNode;
import java.util.HashSet;
import org.jetbrains.mps.openapi.model.SModel;
import org.jetbrains.mps.openapi.module.SModule;
import java.util.List;
import jetbrains.mps.lang.smodel.generator.smodelAdapter.SModelOperations;
import jetbrains.mps.lang.smodel.generator.smodelAdapter.SNodeOperations;
import jetbrains.mps.smodel.adapter.structure.MetaAdapterFactory;
import jetbrains.mps.lang.smodel.generator.smodelAdapter.SLinkOperations;
import org.jetbrains.mps.openapi.model.SModelReference;
import java.util.function.Predicate;
import java.util.Collections;
/**
* Scanner of a model with {@code ConceptDeclarations}to find cross-model dependencies.
* Much like {@link jetbrains.mps.smodel.ModelDependencyScanner } albeit narrow tailored for structure models and extends relation between Language modules.
*/
public class ConceptDeclarationScanner {
private final Set<SNode> myExternalConcepts = new HashSet<SNode>();
private final Set<SNode> myExternalIfaces = new HashSet<SNode>();
private final Set<SModel> myExtendedModels = new HashSet<SModel>();
private final Set<SModule> myExtendedModules = new HashSet<SModule>();
private boolean myExcludeLangCore = false;
public ConceptDeclarationScanner() {
}
/**
* As long as languages implicitly extend j.m.lang.core, any ConceptDeclaration implies import of
* j.m.lang.core.structure.BaseConcept.
* By default, this scanner gives all cross-model dependencies, including one of {@code BaseConcept}.
* However, generally, there's little use for explicit lang.core import and we can safely omit it.
*
* @return {@code this} for convenience
*/
public ConceptDeclarationScanner omitLangCore() {
myExcludeLangCore = true;
return this;
}
public ConceptDeclarationScanner scan(SModel m) {
List<SNode> roots = SModelOperations.roots(m, null);
for (SNode cd : SNodeOperations.ofConcept(roots, MetaAdapterFactory.getConcept(0xc72da2b97cce4447L, 0x8389f407dc1158b7L, 0xf979ba0450L, "jetbrains.mps.lang.structure.structure.ConceptDeclaration"))) {
SNode ex = SLinkOperations.getTarget(cd, MetaAdapterFactory.getReferenceLink(0xc72da2b97cce4447L, 0x8389f407dc1158b7L, 0xf979ba0450L, 0xf979be93cfL, "extends"));
// ex could be null if no explicit BaseConcept in super
if (ex != null && SNodeOperations.getModel(ex) != m) {
myExternalConcepts.add(ex);
}
for (SNode icd : SLinkOperations.collect(SLinkOperations.getChildren(cd, MetaAdapterFactory.getContainmentLink(0xc72da2b97cce4447L, 0x8389f407dc1158b7L, 0xf979ba0450L, 0x110358d693eL, "implements")), MetaAdapterFactory.getReferenceLink(0xc72da2b97cce4447L, 0x8389f407dc1158b7L, 0x110356fc618L, 0x110356fe029L, "intfc"))) {
if (SNodeOperations.getModel(icd) != m) {
myExternalIfaces.add(icd);
}
}
}
for (SNode icd : SNodeOperations.ofConcept(roots, MetaAdapterFactory.getConcept(0xc72da2b97cce4447L, 0x8389f407dc1158b7L, 0x1103556dcafL, "jetbrains.mps.lang.structure.structure.InterfaceConceptDeclaration"))) {
for (SNode iface : SLinkOperations.collect(SLinkOperations.getChildren(icd, MetaAdapterFactory.getContainmentLink(0xc72da2b97cce4447L, 0x8389f407dc1158b7L, 0x1103556dcafL, 0x110356e9df4L, "extends")), MetaAdapterFactory.getReferenceLink(0xc72da2b97cce4447L, 0x8389f407dc1158b7L, 0x110356fc618L, 0x110356fe029L, "intfc"))) {
if (SNodeOperations.getModel(iface) != m) {
myExternalIfaces.add(iface);
}
}
}
for (SNode cd : myExternalConcepts) {
myExtendedModels.add(SNodeOperations.getModel(cd));
}
// XXX for the time being, consider implements of a CD as 'extends' relation between the languages, although this needs extra consideration
// perhaps, shall not treat CD.implements (but still ICD.extends) as mandatory for 'extends' between languages, as it's common to see marker interfaces
// (like IMainClass) that bring (sometimes huge) dependency hierarchy for no added value.
for (SNode cd : myExternalIfaces) {
myExtendedModels.add(SNodeOperations.getModel(cd));
}
if (myExcludeLangCore) {
// here comes an odd way to deal with missing model-reference expression
final SModelReference langCoreStructureModelRef = new SNodePointer("r:00000000-0000-4000-0000-011c89590288(jetbrains.mps.lang.core.structure)", "1133920641626").getModelReference();
myExtendedModels.removeIf(new Predicate<SModel>() {
public boolean test(SModel m) {
return langCoreStructureModelRef.equals(m.getReference());
}
});
}
for (SModel em : myExtendedModels) {
myExtendedModules.add(em.getModule());
}
return this;
}
public Set<SModel> getDependencyModels() {
return Collections.unmodifiableSet(myExtendedModels);
}
public Set<SModule> getDependencyModules() {
return Collections.unmodifiableSet(myExtendedModules);
}
public Set<SNode> getExternalConcepts() {
return Collections.unmodifiableSet(myExternalConcepts);
}
public Set<SNode> getExternalInterfaces() {
return Collections.unmodifiableSet(myExternalIfaces);
}
}