| /******************************************************************************* |
| * 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);
|
| } |
|
|
| }
|