blob: b4fd5613637f6cdeea05231ba0ac19927a597ad7 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2004-2008 Akos Horvath, Gergely Varro and Daniel Varro
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Akos Horvath, Gergely Varro - initial API and implementation
*******************************************************************************/
package org.eclipse.viatra2.gtasm.patternmatcher.impl.patternmatcher.internal.callgraph;
import org.eclipse.emf.common.util.EList;
import org.eclipse.viatra2.gtasm.interpreter.exception.ViatraTransformationException;
import org.eclipse.viatra2.gtasm.interpreter.executionEnvironment.IExecutionEnvironment;
import org.eclipse.viatra2.gtasm.interpreter.impl.executionEnvironment.ExecutionEnvironment;
import org.eclipse.viatra2.gtasm.patternmatcher.exceptions.PatternMatcherCompileTimeException;
import org.eclipse.viatra2.gtasm.patternmatcher.impl.patternmatcher.core.PatternBuilder;
import org.eclipse.viatra2.gtasm.patternmatcher.impl.patternmatcher.internal.EdgeType;
import org.eclipse.viatra2.gtasm.patternmatcher.impl.patternmatcher.internal.PatternMatcher;
import org.eclipse.viatra2.gtasm.patternmatcher.impl.patternmatcher.internal.PatternMatcherErrorStrings;
import org.eclipse.viatra2.gtasm.patternmatcher.impl.patternmatcher.internal.VariableID;
import org.eclipse.viatra2.gtasm.patternmatcher.impl.patternmatcher.internal.algorithms.ISearchGraph;
import org.eclipse.viatra2.gtasm.patternmatcher.impl.patternmatcher.internal.callgraph.FlattenedPattern.Pair;
import org.eclipse.viatra2.gtasm.patternmatcher.impl.patternmatcher.internal.operation.CheckOperation;
import org.eclipse.viatra2.gtasm.patternmatcher.impl.patternmatcher.internal.operation.NACCheckOperation;
import org.eclipse.viatra2.gtasm.patternmatcher.impl.patternmatcher.internal.searchgraph.SearchGraphEdge;
import org.eclipse.viatra2.gtasm.patternmatcher.impl.patternmatcher.internal.searchgraph.SearchGraphNode;
import org.eclipse.viatra2.gtasm.patternmatcher.impl.patternmatcher.internal.searchgraph.traceability.EdgeTraceabilityElement;
import org.eclipse.viatra2.gtasm.patternmatcher.impl.patternmatcher.term.ITermHandler;
import org.eclipse.viatra2.gtasm.patternmatcher.patterns.IPatternMatcher;
import org.eclipse.viatra2.gtasm.patternmatcher.patterns.PatternMatcherProvider;
import org.eclipse.viatra2.gtasmmodel.gtasm.metamodel.asm.core.RuntimeAnnotation;
import org.eclipse.viatra2.gtasmmodel.gtasm.metamodel.asm.definitions.Variable;
import org.eclipse.viatra2.gtasmmodel.gtasm.metamodel.asm.terms.GTPatternCall;
import org.eclipse.viatra2.gtasmmodel.gtasm.metamodel.asm.terms.Term;
import org.eclipse.viatra2.gtasmmodel.gtasm.metamodel.asm.terms.VariableReference;
import org.eclipse.viatra2.gtasmmodel.gtasm.metamodel.gt.ContainmentConstraint;
import org.eclipse.viatra2.gtasmmodel.gtasm.metamodel.gt.GTPattern;
import org.eclipse.viatra2.gtasmmodel.gtasm.metamodel.gt.GTPatternBody;
import org.eclipse.viatra2.gtasmmodel.gtasm.metamodel.gt.NonInjectivityConstraint;
import org.eclipse.viatra2.gtasmmodel.gtasm.metamodel.gt.PatternVariable;
import org.eclipse.viatra2.gtasmmodel.gtasm.metamodel.gt.PatternVariableAssignment;
import org.eclipse.viatra2.gtasmmodel.vpm.editmodel.ModelElement;
import org.eclipse.viatra2.core.IModelManager;
import org.eclipse.viatra2.logger.Logger;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
public class BodyNode extends EvenLevelNode implements IFlattenedPatternElement {
private GTPatternBody body;
protected OddLevelNode[] children;
BodyNode(PatternMatcher patternMatcher,
PatternNode parent, GTPatternBody body) throws PatternMatcherCompileTimeException {
super(parent);
this.body = body;
this.children = new OddLevelNode[body.getCalledPatterns().size()];
List<GTPatternCall> patternCalls = body.getCalledPatterns();
for (int i = 0; i < patternCalls.size(); i++) {
GTPatternCall patternCall = patternCalls.get(i);
PatternNode loopClosingNode = causesRecursion(patternCall.getCalledPattern());
if (loopClosingNode == null) {
if(isIncrementallyMatched(patternCall.getCalledPattern()))
{
IExecutionEnvironment executionEnvironment = new ExecutionEnvironment(patternMatcher.getModelManager().getRoot().getModelSpace().getFramework());
try {
IPatternMatcher patternMatcherInc = null;
patternMatcherInc = PatternMatcherProvider.getInstance().getPatternMatcher(executionEnvironment, patternCall.getCalledPattern());
PatternNode child = new PatternNodeIncremental(new PatternMatcherWrapper(patternMatcherInc,
patternMatcher.getLogger(),patternMatcher.getModelManager(),
patternMatcher.getTermHandler())
, this, patternCall);
children[i] = new PatternReferenceNode(this,patternCall,child);
} catch (ViatraTransformationException e) {
// It is a Major bug if an exception is caught here. Means that an already incrementally matched pattern does not have a valid PatternMatcher!
String[] context = {patternCall.getCalledPattern().getName(),e.getMessage()};
throw new PatternMatcherCompileTimeException(
PatternMatcherErrorStrings.INTERNAL_INCREMENTALLY_MATCED_PATTERN_HAS_NO_PATTERNMATCHER
,context
,patternCall);
}
}
else
{
PatternNode child = new PatternNode(patternMatcher, this, patternCall);
children[i] = child.isRoot()
? new PatternReferenceNode(this, patternCall, child) : child;
}
} else {
children[i] = new PatternReferenceNode(this, patternCall, loopClosingNode);
}
}
}
/** Returns true if the input called pattern is incrementally matched
* @param calledPattern The called pattern to be checked
* @return Boolean true if incrementally checked
* @throws PatternMatcherCompileTimeException
*/
private boolean isIncrementallyMatched(GTPattern calledPattern) throws PatternMatcherCompileTimeException{
EList<RuntimeAnnotation> rtAnnotationsMachine = calledPattern.getNamespace().getRuntimeAnnotations();
boolean isMachineIncremental = false;
if (rtAnnotationsMachine != null && rtAnnotationsMachine.size() > 0) {
for (RuntimeAnnotation an: rtAnnotationsMachine) {
if ("@incremental".equals(an.getAnnotationName().toLowerCase()))
{
isMachineIncremental = true;
}
else if ("@localsearch".equals(an.getAnnotationName()
.toLowerCase()))
{
isMachineIncremental = false;
}
}
}
EList<RuntimeAnnotation> rtAnnotationsPattern = calledPattern.getRuntimeAnnotations();
if (rtAnnotationsPattern != null && rtAnnotationsPattern.size() > 0) {
for (RuntimeAnnotation an: rtAnnotationsPattern) {
if ("@incremental".equals(an.getAnnotationName().toLowerCase()))
return true;
if ("@localsearch".equals(an.getAnnotationName()
.toLowerCase()))
return false;
}
}
return isMachineIncremental; //machine default is used
}
protected PatternNode causesRecursion(GTPattern patternToTest) {
return parent.causesRecursion(patternToTest);
}
@Override
protected boolean traverse(PatternVariantIterator token) {
int size = children.length;
assert index == 0 || index == size - 1;
while (index >= 0 && index < size) {
if (children[index].traverse(token)) {
index++;
} else {
children[index].index = 0;
index--;
}
}
boolean result = (index == size);
index--;
return result;
}
public GTPatternBody getBody() {
return body;
}
public VariableID getVariableID(String name) {
return new VariableID(parent.getPattern(), currentLocation, name);
}
public VariableID getVariableID(Variable variable) {
return new VariableID(parent.getPattern(), currentLocation, variable.getName());
}
public VariableID getVariableID(ModelElement element) {
return new VariableID(parent.getPattern(), currentLocation, element.getName());
}
private BodyNode getCallerBody() {
return (BodyNode) parent.getParent();
}
public void addLocalVariables(FlattenedPattern pattern) {
// Handling of local variables
for (Iterator<PatternVariable> iter = body.getLocalVariables().iterator(); iter.hasNext();) {
PatternVariable variable = iter.next();
pattern.addVariable(getVariableID(variable));
}
}
public void addFormalParameters(FlattenedPattern pattern)
throws PatternMatcherCompileTimeException {
if (parent.isRoot()) {
assert body.getHeader() == parent.getPattern();
GTPattern firstPattern = body.getHeader();
List<PatternVariable> formalParameters = firstPattern.getSymParameters();
int numberOfFormalParameters = formalParameters.size();
for (Integer i = 0; i < numberOfFormalParameters; i++) {
// TODO gervarro: name convention for local pattern declarations is missing
pattern.addVariable(getVariableID(formalParameters.get(i)));
}
assert firstPattern.getSymParameters().size() == pattern.getFrameSize();
} else {
// Handling of pattern calls in FlattenedPatterns (i.e., parameter passing)
Integer numberOfActualParameters = parent.getActualParameters().size();
if (numberOfActualParameters == parent.getPattern().getSymParameters().size()) {
for (int j = 0; j < numberOfActualParameters; j++) {
Term actualTerm = parent.getActualParameters().get(j);
PatternVariable formalParameter = (PatternVariable) parent.getPattern().getSymParameters().get(j);
if (actualTerm instanceof VariableReference) {
VariableReference varRef = (VariableReference) actualTerm;
PatternVariable actualParameter = (PatternVariable) varRef.getVariable();
Integer index = pattern.getIndex(getCallerBody().getVariableID(actualParameter));
pattern.setIndex(getVariableID(formalParameter), index);
} else {
// Based on the latest directive of Dani, terms are not allowed in inner pattern calls
String[] context = {""+j, parent.getPattern().getName()};
throw new PatternMatcherCompileTimeException(
PatternMatcherErrorStrings.NO_TERM_IN_PATTERN_CALLS
,context
,actualTerm);
/*
// Term evaluation
Integer index = pattern.addVariable(getVariableID(formalParameter));
TermHandler handler = pattern.getTermHandler();
AbstractTermCheckOperation operation =
handler.getTermEvaluationOperation(parent.pattern, currentLocation, actualTerm, index);
pattern.addPreSearchPlanOperation(operation);
*/
}
}
} else {
String[] context = {parent.getPattern().getName()};
throw new PatternMatcherCompileTimeException(
PatternMatcherErrorStrings.INTERNAL_FORMAL_AND_ACTUAL_PARAMETER_MISMATCH
,context
,parent.getPattern());
}
}
}
public Collection<Pair> processVariableAssignments(FlattenedPattern pattern)
throws PatternMatcherCompileTimeException {
ArrayList<Pair> pairs = null;
List<PatternVariableAssignment> assigments = body.getVariableAssignments();
if (assigments != null) {
pairs = new ArrayList<Pair>();
for (int i = 0; i < assigments.size(); i++) {
VariableID leftID = getVariableID(assigments.get(i).getLeftValue().getVariable());
VariableID rightID = getVariableID(assigments.get(i).getRightValue().getVariable());
int left = pattern.getIndex(leftID);
int right = pattern.getIndex(rightID);
//The variable assignment operation is handled here
SearchGraphNode leftNode = pattern.getSearchGraph().getSearchNodes().get(left);
SearchGraphNode rightNode = pattern.getSearchGraph().getSearchNodes().get(right);
if(leftNode == null)
{
String[] context = {leftID.getFancyName()};
throw new PatternMatcherCompileTimeException(
PatternMatcherErrorStrings.VARIABLE_VARIABLEASSIGMENT_MISSING
,context
,assigments.get(i));
}
if(rightNode == null)
{//Errofull part
String[] context = {rightID.getFancyName()};
throw new PatternMatcherCompileTimeException(
PatternMatcherErrorStrings.VARIABLE_VARIABLEASSIGMENT_MISSING
,context
,assigments.get(i));
}
pairs.add(pattern.addInjectivityExclusionPair(left, right));
//pattern.removeInjectivityInclusionPair(left,right);
SearchGraphEdge edge = new SearchGraphEdge();
SearchGraphEdge invedge = new SearchGraphEdge();
edge.setVPMEdgeType(EdgeType.VARIABLE_ASSIGNMENT);
edge.setOldWeight(ISearchGraph.VARIABLEASSIGNMENT_WEIGHT);
edge.setWeight(ISearchGraph.VARIABLEASSIGNMENT_WEIGHT);
edge.setSourceNode(leftNode);
edge.setTargetNode(rightNode);
edge.setSource(true);
edge.setName(leftNode.getName() +" variable assignment " + rightNode.getName());
invedge.setVPMEdgeType(EdgeType.VARIABLE_ASSIGNMENT);
invedge.setOldWeight(ISearchGraph.VARIABLEASSIGNMENT_WEIGHT);
invedge.setWeight(ISearchGraph.VARIABLEASSIGNMENT_WEIGHT);
invedge.setSourceNode(rightNode);
invedge.setTargetNode(leftNode);
invedge.setSource(false);
invedge.setName(rightNode.getName() +" INVERSE variable assignment " + leftNode.getName());
invedge.setInverseEdge(invedge);
rightNode.addSource(edge);
leftNode.addSource(invedge);
//traceability
EdgeTraceabilityElement edgeTraceability = new EdgeTraceabilityElement(edge,assigments.get(i));
pattern.getSearchGraph().addTraceabilityElement(edge, edgeTraceability);
//source inverse
EdgeTraceabilityElement inverseEdgeTraceability = new EdgeTraceabilityElement(invedge,assigments.get(i));
pattern.getSearchGraph().addTraceabilityElement(invedge, inverseEdgeTraceability);
}
}
return pairs;
}
public Collection<Pair> processInjectivityAssignments(FlattenedPattern pattern)
throws PatternMatcherCompileTimeException {
ArrayList<Pair> pairs= null;
List<NonInjectivityConstraint> constraints = body.getNonInjectivityConstraints();
if (constraints != null) {
pairs = new ArrayList<Pair>();
for (int i = 0; i < constraints.size(); i++) {
VariableID leftID = getVariableID(constraints.get(i).getLeftValue().getVariable());
VariableID rightID = getVariableID(constraints.get(i).getRightValue().getVariable());
int left = pattern.getIndex(leftID);
int right = pattern.getIndex(rightID);
pairs.add(pattern.addInjectivityInclusionPair(left, right));
// pattern.removeInjectivityExclusionPair(left, right); //have to remove from the Exclusion list as it is explicitly defined with the Injectivity assignment
}
}
return pairs;
}
public void generateElementInjectivityConstraints(FlattenedPattern flattenedPattern,
Collection<Pair> localAdditionalExclusionInjectivityPairs,
Collection<Pair> localAdditionalInclusionInjectivityPairs) throws PatternMatcherCompileTimeException {
HashSet<Integer> bodyPatternIndexes = new HashSet<Integer>();
boolean isDistinctMatching = parent.getPattern().isDistinctMatching();
//local variables
for (Iterator<PatternVariable> iter = body.getLocalVariables().iterator(); iter.hasNext();) {
PatternVariable variable = iter.next();
Integer localVariableIndex = flattenedPattern.getIndex(getVariableID(variable));
bodyPatternIndexes.add(localVariableIndex);
}
//symbolic parameters are already attached to their actual invocation parameters
for (Iterator<PatternVariable> iter = parent.getPattern().getSymParameters().iterator(); iter.hasNext();) {
PatternVariable formalParemeter = iter.next();
Integer formalParameterIndex = flattenedPattern.getIndex(getVariableID(formalParemeter));
if(!bodyPatternIndexes.add(formalParameterIndex))
{
String[] context = {formalParameterIndex.toString(),parent.getPattern().getName()};
throw new PatternMatcherCompileTimeException(
PatternMatcherErrorStrings.INTERNAL_BODYNODE_INJECTIVITYCONSTRAINT_ALREADYUSED
,context
,body);
}
}
for(Integer i: bodyPatternIndexes)
for(Integer j: bodyPatternIndexes)
if(i < j)
{if(isDistinctMatching)
{
if(localAdditionalExclusionInjectivityPairs != null
&& !localAdditionalExclusionInjectivityPairs.contains(new Pair(i,j)))
flattenedPattern.addInjectivityInclusionPair(i, j);
}
else
{
if(localAdditionalInclusionInjectivityPairs != null
&& !localAdditionalInclusionInjectivityPairs.contains(new Pair(i,j)))
flattenedPattern.addInjectivityExclusionPair(i, j);
}
}
/* if(localAdditionalExclusionInjectivityPairs != null)
for(Pair p: localAdditionalExclusionInjectivityPairs)
flattenedPattern.removeInjectivityInclusionPair(p.getLeft(), p.getRight());
if(localAdditionalInclusionInjectivityPairs != null)
for(Pair p: localAdditionalInclusionInjectivityPairs)
flattenedPattern.removeInjectivityExclusionPair(p.getLeft(), p.getRight());
*/
/*for (int j = 0; j < parent.pattern.getSymParameters().size(); j++) {
Term actualTerm = parent.actualParameters.get(j);
if (actualTerm instanceof VariableReference) {
VariableReference varRef = (VariableReference) actualTerm;
PatternVariable actualParameter = (PatternVariable) varRef.getVariable();
Integer index = flattenedPattern.getIndex(getCallerBody().getVariableID(actualParameter));
}
}*/
}
public void processCheckExpressions(FlattenedPattern pattern, Logger logger) {
List<Term> checkExpressions = body.getCheckExpressions();
if (checkExpressions != null) {
ITermHandler handler = pattern.getTermHandler();
if (handler != null) {
for (int i = 0; i < checkExpressions.size(); i++) {
CheckOperation operation =
handler.getTermCheckOperation(parent.getPattern(), currentLocation, checkExpressions.get(i));
pattern.addPostSearchPlanOperation(operation);
}
} else {
logger.warning(PatternMatcherErrorStrings.NO_TERM_HANDLER);
}
}
}
public void processNegativeApplicationConditions(FlattenedPattern pattern, Logger logger, IModelManager manager)
throws PatternMatcherCompileTimeException {
List<GTPatternCall> negativeCalls = body.getNegativePatterns();
GTPattern header = body.getHeader();
if (negativeCalls != null && negativeCalls.size() > 0) {
for (int i = 0; i < negativeCalls.size(); i++) {
GTPatternCall call = negativeCalls.get(i);
PatternBuilder builder = new PatternBuilder(logger, manager, pattern.getTermHandler());
IPatternMatcher matcher = builder.construct(call.getCalledPattern());
List<Term> actualTerms = call.getActualParameters();
Collection<Variable> passingVariables = new ArrayList<Variable>();
int[] actualParameterMapping = new int[actualTerms.size()];
for (int j = 0; j < actualTerms.size(); j++) {
Term term = actualTerms.get(j);
if (term instanceof VariableReference) {
VariableReference varRef = (VariableReference) term;
actualParameterMapping[j] =
pattern.getIndex(getVariableID(varRef.getVariable()));
if(header.getSymParameters().contains(varRef.getVariable())) //it is a variable that goes into the NAC call
passingVariables.add(varRef.getVariable());
} else {
String[] context = {""+j,call.getCalledPattern().getName()};
throw new PatternMatcherCompileTimeException(
PatternMatcherErrorStrings.NO_TERM_IN_NAC_CALLS
,context
,call);
}
}
NACCheckOperation operation = new NACCheckOperation(matcher, actualParameterMapping,call,
passingVariables);
pattern.addPostSearchPlanOperation(operation);
}
}
}
public void buildSearchGraph(FlattenedPattern result) throws PatternMatcherCompileTimeException{
try{
result.getSearchGraph().add(this,result);
}catch (PatternMatcherCompileTimeException e) {
throw e.addNewStackElement(this.body);
}
}
public String toString() {
return getClass().getSimpleName() + " " + parent.getPattern().getName() + "_" + currentLocation;
}
public CheckOperation getTermEvaluationOperation(ITermHandler handler, ContainmentConstraint conCons, int resultSlot) {
return handler.getTermEvaluationOperation(parent.getPattern(), currentLocation, conCons, resultSlot);
}
}