/*
* Copyright 2003-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package jetbrains.mps.lang.dataFlow.framework;
import jetbrains.mps.lang.dataFlow.DataFlowBuilderContext;
import jetbrains.mps.lang.smodel.generator.smodelAdapter.SNodeOperations;
import jetbrains.mps.logging.Logger;
import jetbrains.mps.smodel.SModelOperations;
import jetbrains.mps.smodel.language.LanguageRegistry;
import jetbrains.mps.smodel.language.LanguageRuntime;
import org.apache.log4j.LogManager;
import org.jetbrains.mps.openapi.language.SAbstractConcept;
import org.jetbrains.mps.openapi.language.SLanguage;
import org.jetbrains.mps.openapi.model.SModel;
import org.jetbrains.mps.openapi.model.SNode;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.stream.Stream;
/**
* @author simon
*/
public class AnalyzerRules {
private static Logger LOG = Logger.wrap(LogManager.getLogger(AnalyzerRules.class));
private List<DataFlowConstructor> myRules = new LinkedList<DataFlowConstructor>();
private String myAnalyzerId;
private final List<SNode> myNodesToApply;
private final Program myProgram;
private ProgramBuilderContext myContext;
public AnalyzerRules(String analyzerId, SNode nodeToApply, Program program) {
this(analyzerId, Collections.singletonList(nodeToApply), program, new ProgramBuilderContextImpl(Collections.emptyList()));
}
public AnalyzerRules(String analyzerId, Collection<SNode> nodesToApply, Program program, ProgramBuilderContext context) {
myNodesToApply = new ArrayList<SNode>();
myNodesToApply.addAll(nodesToApply);
myProgram = program;
myAnalyzerId = analyzerId;
myContext = context;
}
public void apply() {
if (myNodesToApply.isEmpty()) {
return;
}
SNode first = myNodesToApply.iterator().next();
SModel model = first.getModel();
if (model == null) {
LOG.warning("Checking node which is not attached to the model: " + first.getPresentation() + " " + first.getNodeId());
return;
}
// XXX could I demand here that model has to be attached to a repository, so that I can use one to obtain LanguageRegistry?
for (SLanguage language : SModelOperations.getAllLanguageImports(model)) {
LanguageRuntime languageRuntime = LanguageRegistry.getInstance().getLanguage(language);
if (languageRuntime == null) {
continue;
}
DataFlowAspectDescriptor aspect = languageRuntime.getAspect(DataFlowAspectDescriptor.class);
if (aspect == null) {
continue;
}
for (DataFlowConstructor rule : aspect.getConstructors(myAnalyzerId)) {
myRules.add(rule);
}
}
Set<SNode> descendants = new LinkedHashSet<SNode>();
for (SNode myNodeToApply : myNodesToApply) {
descendants.addAll(SNodeOperations.getNodeDescendants(myNodeToApply, null, false, new SAbstractConcept[]{}));
}
for (SNode descendant : descendants) {
getRules(descendant).forEach(rule -> rule.performActions(myProgram, descendant));
}
}
private Stream<DataFlowConstructor> getRules(SNode node) {
return myRules.stream().filter(rule -> {
Collection<IDataFlowModeId> modes = rule.getModes();
return (modes.isEmpty() || modes.stream().anyMatch(mode -> myContext.getBuilderModes().contains(mode))) && rule.isApplicable(node);
});
}
}