package jetbrains.mps.make.script; /*Generated by MPS */ import org.apache.log4j.Logger; import org.apache.log4j.LogManager; import java.util.Set; import jetbrains.mps.make.facet.IFacet; import jetbrains.mps.internal.collections.runtime.SetSequence; import java.util.HashSet; import jetbrains.mps.make.facet.ITarget; import java.util.List; import jetbrains.mps.internal.make.runtime.script.ValidationError; import jetbrains.mps.internal.collections.runtime.ListSequence; import java.util.ArrayList; import jetbrains.mps.internal.collections.runtime.Sequence; import java.util.Map; import jetbrains.mps.internal.make.runtime.script.InvalidScript; import jetbrains.mps.internal.collections.runtime.MapSequence; import java.util.HashMap; import jetbrains.mps.internal.make.runtime.script.TargetRange; import jetbrains.mps.internal.make.runtime.script.Script; import jetbrains.mps.make.facet.FacetRegistry; import jetbrains.mps.internal.collections.runtime.ITranslator2; import jetbrains.mps.internal.collections.runtime.IMapping; import jetbrains.mps.internal.make.runtime.util.GraphAnalyzer; import jetbrains.mps.internal.collections.runtime.ISelector; public class ScriptBuilder { private static Logger LOG = LogManager.getLogger(ScriptBuilder.class); private Set<IFacet.Name> facets = SetSequence.fromSet(new HashSet<IFacet.Name>()); private Set<ITarget.Name> requestedTargets = SetSequence.fromSet(new HashSet<ITarget.Name>()); private ITarget.Name finalTarget; private ITarget.Name startingTarget; private List<ValidationError> errors = ListSequence.fromList(new ArrayList<ValidationError>()); public ScriptBuilder() { } public ScriptBuilder withFacetName(IFacet.Name facetName) { SetSequence.fromSet(facets).addElement(facetName); return this; } public ScriptBuilder withFacetNames(IFacet.Name... facetNames) { return withFacetNames(Sequence.fromArray(facetNames)); } public ScriptBuilder withFacetNames(Iterable<IFacet.Name> facetNames) { SetSequence.fromSet(facets).addSequence(Sequence.fromIterable(facetNames)); return this; } public ScriptBuilder withAuxTarget(ITarget.Name targetName) { if (targetName == null) { throw new NullPointerException(); } SetSequence.fromSet(requestedTargets).addElement(targetName); return this; } public ScriptBuilder withStartingTarget(ITarget.Name targetName) { if (targetName == null) { throw new NullPointerException(); } SetSequence.fromSet(requestedTargets).addElement(targetName); this.startingTarget = targetName; return this; } public ScriptBuilder withFinalTarget(ITarget.Name targetName) { if (targetName == null) { throw new NullPointerException(); } SetSequence.fromSet(requestedTargets).addElement(targetName); this.finalTarget = targetName; return this; } public IScript toScript() { Map<IFacet.Name, IFacet> facetsView = collectFacets(); if (ListSequence.fromList(errors).isNotEmpty()) { return new InvalidScript(errors); } final Map<IFacet.Name, ScriptBuilder.FacetRefs> refs = MapSequence.fromMap(new HashMap<IFacet.Name, ScriptBuilder.FacetRefs>()); this.collectRefs(refs, facetsView); if (ListSequence.fromList(errors).isNotEmpty()) { return new InvalidScript(errors); } Iterable<IFacet.Name> sortedFacets = this.toposortByExtended(refs, facetsView); if (ListSequence.fromList(errors).isNotEmpty()) { return new InvalidScript(errors); } TargetRange tr = new TargetRange(); this.collectTargets(sortedFacets, tr, facetsView); if (ListSequence.fromList(errors).isNotEmpty()) { return new InvalidScript(errors); } Script sc = new Script(tr, finalTarget, startingTarget); sc.validate(); return sc; } private Map<IFacet.Name, IFacet> collectFacets() { Map<IFacet.Name, IFacet> facetsView = MapSequence.fromMap(new HashMap<IFacet.Name, IFacet>()); for (IFacet.Name fn : SetSequence.fromSet(facets)) { IFacet fct = FacetRegistry.getInstance().lookup(fn); if (fct != null) { MapSequence.fromMap(facetsView).put(fn, fct); } else { String msg = "facet not found: " + fn; error(fn, msg); } } if (SetSequence.fromSet(facets).isEmpty()) { error(null, "No make facets found, nothing to make. This may have been caused by a language module failed to load."); } return facetsView; } private void collectTargets(Iterable<IFacet.Name> sortedFacets, TargetRange tr, final Map<IFacet.Name, IFacet> facetsView) { List<ITarget> allTargets = ListSequence.fromList(Sequence.fromIterable(sortedFacets).translate(new ITranslator2<IFacet.Name, ITarget>() { public Iterable<ITarget> translate(IFacet.Name fname) { return MapSequence.fromMap(facetsView).get(fname).targets(); } }).toListSequence()).reversedList(); for (ITarget trg : ListSequence.fromList(allTargets)) { if (SetSequence.fromSet(requestedTargets).contains(trg.getName())) { tr.addTarget(trg); } } for (ITarget.Name tn : SetSequence.fromSet(requestedTargets)) { if (!(tr.hasTarget(tn))) { error(tn, "target not found: " + tn); } } if (ListSequence.fromList(errors).isNotEmpty()) { return; } tr.addRelatedPrecursors(Sequence.fromIterable(MapSequence.fromMap(facetsView).values()).translate(new ITranslator2<IFacet, ITarget>() { public Iterable<ITarget> translate(IFacet fct) { return fct.targets(); } })); } private void collectRefs(final Map<IFacet.Name, ScriptBuilder.FacetRefs> refs, Map<IFacet.Name, IFacet> facetsView) { for (IFacet fct : Sequence.fromIterable(MapSequence.fromMap(facetsView).values())) { ScriptBuilder.FacetRefs facetRefs = new ScriptBuilder.FacetRefs(facetsView); facetRefs.collect(fct); MapSequence.fromMap(refs).put(fct.getName(), facetRefs); } } private Iterable<IFacet.Name> toposortByExtended(final Map<IFacet.Name, ScriptBuilder.FacetRefs> refs, Map<IFacet.Name, IFacet> facetsView) { for (IMapping<IFacet.Name, ScriptBuilder.FacetRefs> m : SetSequence.fromSet(MapSequence.fromMap(refs).mappingsSet())) { IFacet fct = MapSequence.fromMap(facetsView).get(m.key()); for (IFacet ex : ListSequence.fromList(m.value().extended)) { ListSequence.fromList(MapSequence.fromMap(refs).get(ex.getName()).extendedBy).addElement(fct); } } GraphAnalyzer<IFacet.Name> ga = new GraphAnalyzer<IFacet.Name>() { @Override public Iterable<IFacet.Name> forwardEdges(IFacet.Name v) { return ListSequence.fromList(MapSequence.fromMap(refs).get(v).extendedBy).select(new ISelector<IFacet, IFacet.Name>() { public IFacet.Name select(IFacet f) { return f.getName(); } }); } @Override public Iterable<IFacet.Name> backwardEdges(IFacet.Name v) { return ListSequence.fromList(MapSequence.fromMap(refs).get(v).extended).select(new ISelector<IFacet, IFacet.Name>() { public IFacet.Name select(IFacet f) { return f.getName(); } }); } @Override public Iterable<IFacet.Name> vertices() { return MapSequence.fromMap(refs).keySet(); } }; for (List<IFacet.Name> cyc : ListSequence.fromList(ga.findCycles())) { error(null, "found cycle: " + cyc); } return ga.topologicalSort(); } private void error(Object o, String message) { LOG.debug(message); ListSequence.fromList(this.errors).addElement(new ValidationError(o, message)); } private class FacetRefs { /*package*/ List<IFacet> extended = ListSequence.fromList(new ArrayList<IFacet>()); /*package*/ List<IFacet> extendedBy = ListSequence.fromList(new ArrayList<IFacet>()); /*package*/ List<IFacet> required = ListSequence.fromList(new ArrayList<IFacet>()); /*package*/ List<IFacet> optional = ListSequence.fromList(new ArrayList<IFacet>()); private Map<IFacet.Name, IFacet> facetsView; public FacetRefs(Map<IFacet.Name, IFacet> facetsView) { this.facetsView = facetsView; } public void collect(IFacet fct) { for (IFacet.Name req : Sequence.fromIterable(fct.extended())) { addIfExists(fct, req, extended, true); } for (IFacet.Name req : Sequence.fromIterable(fct.required())) { addIfExists(fct, req, required, true); } for (IFacet.Name opt : Sequence.fromIterable(fct.optional())) { addIfExists(fct, opt, optional, false); } } private void addIfExists(IFacet requestor, IFacet.Name requestee, List<IFacet> destination, boolean required) { IFacet f = MapSequence.fromMap(facetsView).get(requestee); if (f != null) { ListSequence.fromList(destination).addElement(f); } else { if (required) { String msg = "not found required facet: " + requestee; error(requestor.getName(), msg); } else { LOG.debug("not found optional facet: " + requestee + " for facet " + requestor.getName()); } } } } }