aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarton Bur2014-05-04 21:47:20 (EDT)
committerZoltan Ujhelyi2014-07-08 10:14:31 (EDT)
commitff3932d4de61ba85fada6be41da79d5360768301 (patch)
tree77453b7b2dd34b4a16329b763bd4388216491a83
parent99c99a2fcafbb4dcf8af4b89c303c5a28f2d297f (diff)
downloadorg.eclipse.incquery-ff3932d4de61ba85fada6be41da79d5360768301.zip
org.eclipse.incquery-ff3932d4de61ba85fada6be41da79d5360768301.tar.gz
org.eclipse.incquery-ff3932d4de61ba85fada6be41da79d5360768301.tar.bz2
[431204] Initial version of PBody Flattenerrefs/changes/80/29180/11
Implementation includes a PBody copier implementation. Known limition: recursive calls not supported. Change-Id: Idab73ff775a44c81dcbedc82fd138cafa1e317ee Signed-off-by: Marton Bur <marton.bur@gmail.com>
-rw-r--r--plugins/org.eclipse.incquery.runtime.matchers/src/org/eclipse/incquery/runtime/matchers/psystem/basicenumerables/TypeBinary.java8
-rw-r--r--plugins/org.eclipse.incquery.runtime.matchers/src/org/eclipse/incquery/runtime/matchers/psystem/rewriters/FlattenerCopier.java63
-rw-r--r--plugins/org.eclipse.incquery.runtime.matchers/src/org/eclipse/incquery/runtime/matchers/psystem/rewriters/PBodyCopier.java208
-rw-r--r--plugins/org.eclipse.incquery.runtime.matchers/src/org/eclipse/incquery/runtime/matchers/psystem/rewriters/PQueryFlattener.java347
-rw-r--r--tests/org.eclipse.incquery.testing.core/src/org/eclipse/incquery/testing/core/base/CompareQueryTester.java59
-rw-r--r--tests/org.eclipse.incquery.testing.core/src/org/eclipse/incquery/testing/core/base/DisjunctionBasedQuerySpecification.java142
6 files changed, 827 insertions, 0 deletions
diff --git a/plugins/org.eclipse.incquery.runtime.matchers/src/org/eclipse/incquery/runtime/matchers/psystem/basicenumerables/TypeBinary.java b/plugins/org.eclipse.incquery.runtime.matchers/src/org/eclipse/incquery/runtime/matchers/psystem/basicenumerables/TypeBinary.java
index 3d95576..8f9c54a 100644
--- a/plugins/org.eclipse.incquery.runtime.matchers/src/org/eclipse/incquery/runtime/matchers/psystem/basicenumerables/TypeBinary.java
+++ b/plugins/org.eclipse.incquery.runtime.matchers/src/org/eclipse/incquery/runtime/matchers/psystem/basicenumerables/TypeBinary.java
@@ -56,5 +56,13 @@ public class TypeBinary extends TypeConstraint implements ITypeInfoProviderConst
return result;
}
+ /**
+ * Returns the metamodel context used for creating this constraint
+ * @return the context
+ */
+ public IPatternMatcherContext getContext() {
+ return context;
+ }
+
}
diff --git a/plugins/org.eclipse.incquery.runtime.matchers/src/org/eclipse/incquery/runtime/matchers/psystem/rewriters/FlattenerCopier.java b/plugins/org.eclipse.incquery.runtime.matchers/src/org/eclipse/incquery/runtime/matchers/psystem/rewriters/FlattenerCopier.java
new file mode 100644
index 0000000..77658f0
--- /dev/null
+++ b/plugins/org.eclipse.incquery.runtime.matchers/src/org/eclipse/incquery/runtime/matchers/psystem/rewriters/FlattenerCopier.java
@@ -0,0 +1,63 @@
+/*******************************************************************************
+ * Copyright (c) 2010-2014, Marton Bur, Akos Horvath, Zoltan Ujhelyi, Istvan Rath 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:
+ * Marton Bur - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.incquery.runtime.matchers.psystem.rewriters;
+
+import java.util.List;
+
+import org.eclipse.incquery.runtime.matchers.psystem.PBody;
+import org.eclipse.incquery.runtime.matchers.psystem.PVariable;
+import org.eclipse.incquery.runtime.matchers.psystem.basicdeferred.Equality;
+import org.eclipse.incquery.runtime.matchers.psystem.basicdeferred.ExportedParameter;
+import org.eclipse.incquery.runtime.matchers.psystem.basicenumerables.PositivePatternCall;
+import org.eclipse.incquery.runtime.matchers.psystem.queries.PQuery;
+
+/**
+ * This rewriter class can add new equality constraints to the copied body
+ *
+ * @author Marton Bur
+ *
+ */
+public class FlattenerCopier extends PBodyCopier {
+
+ private List<PositivePatternCall> flattenedCalls;
+ private List<PBody> calledBodies;
+
+ public FlattenerCopier(PQuery query, List<PositivePatternCall> flattenedCalls, List<PBody> calledBodies) {
+ super(query);
+ this.flattenedCalls = flattenedCalls;
+ this.calledBodies = calledBodies;
+ }
+
+ @Override
+ protected void copyPositivePatternCallConstraint(PositivePatternCall positivePatternCall) {
+
+ if(!flattenedCalls.contains(positivePatternCall)){
+ // If the call was not flattened, copy the constraint
+ super.copyPositivePatternCallConstraint(positivePatternCall);
+ } else {
+ for (PBody calledBody : calledBodies) {
+ if(positivePatternCall.getReferredQuery().equals(calledBody.getPattern())){
+ List<ExportedParameter> symbolicParameters = calledBody.getSymbolicParameters();
+ Object[] elements = positivePatternCall.getVariablesTuple().getElements();
+ for (int i = 0; i < elements.length; i++ ) {
+ // Create equality constraints between the caller PositivePatternCall and the corresponding body parameter variables
+ createEqualityConstraint((PVariable) elements[i], symbolicParameters.get(i).getAffectedVariables().iterator().next());
+ }
+ }
+ }
+ }
+ }
+
+ private void createEqualityConstraint(PVariable pVariable1, PVariable pVariable2){
+ new Equality(body, variableMapping.get(pVariable1), variableMapping.get(pVariable2));
+ }
+
+}
diff --git a/plugins/org.eclipse.incquery.runtime.matchers/src/org/eclipse/incquery/runtime/matchers/psystem/rewriters/PBodyCopier.java b/plugins/org.eclipse.incquery.runtime.matchers/src/org/eclipse/incquery/runtime/matchers/psystem/rewriters/PBodyCopier.java
new file mode 100644
index 0000000..129e301
--- /dev/null
+++ b/plugins/org.eclipse.incquery.runtime.matchers/src/org/eclipse/incquery/runtime/matchers/psystem/rewriters/PBodyCopier.java
@@ -0,0 +1,208 @@
+/*******************************************************************************
+ * Copyright (c) 2010-2014, Marton Bur, Akos Horvath, Zoltan Ujhelyi, Istvan Rath 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:
+ * Marton Bur - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.incquery.runtime.matchers.psystem.rewriters;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.incquery.runtime.matchers.psystem.EnumerablePConstraint;
+import org.eclipse.incquery.runtime.matchers.psystem.PBody;
+import org.eclipse.incquery.runtime.matchers.psystem.PConstraint;
+import org.eclipse.incquery.runtime.matchers.psystem.PVariable;
+import org.eclipse.incquery.runtime.matchers.psystem.basicdeferred.Equality;
+import org.eclipse.incquery.runtime.matchers.psystem.basicdeferred.ExportedParameter;
+import org.eclipse.incquery.runtime.matchers.psystem.basicdeferred.ExpressionEvaluation;
+import org.eclipse.incquery.runtime.matchers.psystem.basicdeferred.Inequality;
+import org.eclipse.incquery.runtime.matchers.psystem.basicdeferred.NegativePatternCall;
+import org.eclipse.incquery.runtime.matchers.psystem.basicdeferred.PatternCallBasedDeferred;
+import org.eclipse.incquery.runtime.matchers.psystem.basicdeferred.PatternMatchCounter;
+import org.eclipse.incquery.runtime.matchers.psystem.basicenumerables.BinaryTransitiveClosure;
+import org.eclipse.incquery.runtime.matchers.psystem.basicenumerables.ConstantValue;
+import org.eclipse.incquery.runtime.matchers.psystem.basicenumerables.PositivePatternCall;
+import org.eclipse.incquery.runtime.matchers.psystem.basicenumerables.TypeBinary;
+import org.eclipse.incquery.runtime.matchers.psystem.basicenumerables.TypeUnary;
+import org.eclipse.incquery.runtime.matchers.psystem.queries.PQuery;
+import org.eclipse.incquery.runtime.matchers.tuple.FlatTuple;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+
+/**
+ * This class can create a new PBody for a PQuery. The result body contains a copy of given variables and constraints.
+ *
+ * @author Marton Bur
+ *
+ */
+public class PBodyCopier {
+
+ /**
+ * The created body
+ */
+ PBody body;
+ /**
+ * Mapping between the original and the copied variables
+ */
+ Map<PVariable, PVariable> variableMapping;
+
+
+ public Map<PVariable, PVariable> getVariableMapping() {
+ return variableMapping;
+ }
+
+ public PBodyCopier(PQuery query) {
+ body = new PBody(query);
+ variableMapping = Maps.newHashMap();
+ }
+
+ public void copyVariable(PVariable variable, String newName) {
+ PVariable newPVariable = body.getOrCreateVariableByName(newName);
+ variableMapping.put(variable, newPVariable);
+ }
+
+ public PBody getCopiedBody() {
+ return body;
+ }
+
+ public void copyConstraint(PConstraint constraint) {
+ if (constraint instanceof ExportedParameter) {
+ copyExportedParameterConstraint((ExportedParameter) constraint);
+ } else if (constraint instanceof Equality) {
+ copyEqualityConstraint((Equality) constraint);
+ } else if (constraint instanceof Inequality) {
+ copyInequalityConstraint((Inequality) constraint);
+ } else if (constraint instanceof TypeUnary) {
+ copyTypeUnaryConstraint((TypeUnary) constraint);
+ } else if (constraint instanceof TypeBinary) {
+ copyTypeBinaryConstraint((TypeBinary) constraint);
+ } else if (constraint instanceof ConstantValue) {
+ copyConstantValueConstraint((ConstantValue) constraint);
+ } else if (constraint instanceof PositivePatternCall) {
+ copyPositivePatternCallConstraint((PositivePatternCall) constraint);
+ } else if (constraint instanceof NegativePatternCall) {
+ copyNegativePatternCallConstraint((NegativePatternCall) constraint);
+ } else if (constraint instanceof BinaryTransitiveClosure) {
+ copyBinaryTransitiveClosureConstraint((BinaryTransitiveClosure) constraint);
+ } else if (constraint instanceof PatternMatchCounter) {
+ copyPatternMatchCounterConstraint((PatternMatchCounter) constraint);
+ } else if (constraint instanceof ExpressionEvaluation) {
+ copyExpressionEvaluationConstraint((ExpressionEvaluation) constraint);
+ }
+ }
+
+
+ protected void copyExportedParameterConstraint(ExportedParameter exportedParameter) {
+ PVariable mappedPVariable = variableMapping.get(exportedParameter.getParameterVariable());
+ ExportedParameter newExportedParameter = new ExportedParameter(body, mappedPVariable, exportedParameter.getParameterName());
+ if (body.getSymbolicParameters().size() == 0) {
+ List<ExportedParameter> exportedParameters = Lists.<ExportedParameter> newArrayList();
+ exportedParameters.add(newExportedParameter);
+ body.setExportedParameters(exportedParameters);
+ }
+ else {
+ body.getSymbolicParameters().add(newExportedParameter);
+ }
+ }
+
+ protected void copyEqualityConstraint(Equality equality) {
+ PVariable who = equality.getWho();
+ PVariable withWhom = equality.getWithWhom();
+ new Equality(body, variableMapping.get(who), variableMapping.get(withWhom));
+ }
+
+ protected void copyInequalityConstraint(Inequality inequality) {
+ PVariable who = inequality.getWho();
+ PVariable withWhom = inequality.getWithWhom();
+ new Inequality(body, variableMapping.get(who), variableMapping.get(withWhom));
+ }
+
+ protected void copyTypeUnaryConstraint(TypeUnary typeUnary) {
+ PVariable pVariable = (PVariable) typeUnary.getVariablesTuple().getElements()[0];
+ new TypeUnary(body, variableMapping.get(pVariable), typeUnary.getSupplierKey(), typeUnary.getTypeString());
+ }
+
+ protected void copyTypeBinaryConstraint(TypeBinary typeBinary) {
+ Object[] elements = typeBinary.getVariablesTuple().getElements();
+ PVariable pVariable1 = (PVariable) elements[0];
+ PVariable pVariable2 = (PVariable) elements[1];
+ new TypeBinary(body, typeBinary.getContext(), variableMapping.get(pVariable1), variableMapping.get(pVariable2), typeBinary.getSupplierKey(), typeBinary.getTypeString());
+ }
+
+ protected void copyConstantValueConstraint(ConstantValue constantValue) {
+ PVariable pVariable = (PVariable) constantValue.getVariablesTuple().getElements()[0];
+ new ConstantValue(body, variableMapping.get(pVariable), constantValue.getSupplierKey());
+ }
+
+ protected void copyPositivePatternCallConstraint(PositivePatternCall positivePatternCall) {
+ PVariable[] mappedVariables = extractMappedVariables(positivePatternCall);
+ FlatTuple variablesTuple = new FlatTuple(mappedVariables);
+ new PositivePatternCall(body, variablesTuple, positivePatternCall.getReferredQuery());
+ }
+
+
+ protected void copyNegativePatternCallConstraint(NegativePatternCall negativePatternCall) {
+ PVariable[] mappedVariables = extractMappedVariables(negativePatternCall);
+ FlatTuple variablesTuple = new FlatTuple(mappedVariables);
+ new NegativePatternCall(body, variablesTuple, negativePatternCall.getReferredQuery());
+ }
+
+ protected void copyBinaryTransitiveClosureConstraint(BinaryTransitiveClosure binaryTransitiveClosure) {
+ PVariable[] mappedVariables = extractMappedVariables(binaryTransitiveClosure);
+ FlatTuple variablesTuple = new FlatTuple(mappedVariables);
+ new BinaryTransitiveClosure(body, variablesTuple, binaryTransitiveClosure.getReferredQuery());
+ }
+
+ protected void copyPatternMatchCounterConstraint(PatternMatchCounter patternMatchCounter) {
+ PVariable[] mappedVariables = extractMappedVariables(patternMatchCounter);
+ PVariable mappedResultVariable = variableMapping.get(patternMatchCounter.getResultVariable());
+ FlatTuple variablesTuple = new FlatTuple(mappedVariables);
+ new PatternMatchCounter(body, variablesTuple, patternMatchCounter.getReferredQuery(), mappedResultVariable);
+ }
+
+
+ protected void copyExpressionEvaluationConstraint(ExpressionEvaluation expressionEvaluation) {
+ PVariable mappedOutputVariable = variableMapping.get(expressionEvaluation.getOutputVariable());
+ new ExpressionEvaluation(body, expressionEvaluation.getEvaluator(), mappedOutputVariable);
+ }
+
+
+ /**
+ * For positive pattern calls
+ *
+ * @param positivePatternCall
+ * @return the mapped variables to the pattern's parameters
+ */
+ private PVariable[] extractMappedVariables(EnumerablePConstraint enumerablePConstraint) {
+ Object[] pVariables = enumerablePConstraint.getVariablesTuple().getElements();
+ return mapVariableList(pVariables);
+ }
+
+ /**
+ * For negative and count pattern calls.
+ *
+ * @param patternMatchCounter
+ * @return the mapped variables to the pattern's parameters
+ */
+ private PVariable[] extractMappedVariables(PatternCallBasedDeferred patternCallBasedDeferred) {
+ Object[] pVariables = patternCallBasedDeferred.getActualParametersTuple().getElements();
+ return mapVariableList(pVariables);
+ }
+
+ private PVariable[] mapVariableList(Object[] pVariables) {
+ List<PVariable> list = new ArrayList<PVariable>();
+ for (int i = 0; i < pVariables.length; i++) {
+ PVariable mappedVariable = variableMapping.get((PVariable)pVariables[i]);
+ list.add(mappedVariable);
+ }
+ return list.toArray(new PVariable[0]);
+ }
+
+}
diff --git a/plugins/org.eclipse.incquery.runtime.matchers/src/org/eclipse/incquery/runtime/matchers/psystem/rewriters/PQueryFlattener.java b/plugins/org.eclipse.incquery.runtime.matchers/src/org/eclipse/incquery/runtime/matchers/psystem/rewriters/PQueryFlattener.java
new file mode 100644
index 0000000..e0e3cef
--- /dev/null
+++ b/plugins/org.eclipse.incquery.runtime.matchers/src/org/eclipse/incquery/runtime/matchers/psystem/rewriters/PQueryFlattener.java
@@ -0,0 +1,347 @@
+/*******************************************************************************
+ * Copyright (c) 2010-2014, Marton Bur, Akos Horvath, Zoltan Ujhelyi, Istvan Rath 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:
+ * Marton Bur - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.incquery.runtime.matchers.psystem.rewriters;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.incquery.runtime.matchers.psystem.PBody;
+import org.eclipse.incquery.runtime.matchers.psystem.PConstraint;
+import org.eclipse.incquery.runtime.matchers.psystem.PVariable;
+import org.eclipse.incquery.runtime.matchers.psystem.basicdeferred.ExportedParameter;
+import org.eclipse.incquery.runtime.matchers.psystem.basicenumerables.PositivePatternCall;
+import org.eclipse.incquery.runtime.matchers.psystem.queries.PDisjunction;
+import org.eclipse.incquery.runtime.matchers.psystem.queries.PQuery;
+import org.eclipse.incquery.runtime.matchers.psystem.queries.PQuery.PQueryStatus;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+
+/**
+ * This class holds the flattening logic
+ *
+ * @author Marton Bur
+ *
+ */
+public class PQueryFlattener extends PDisjunctionRewriter {
+
+ // TODO handle recursive pattern calls - check for backward edges in the call graph
+
+ private static final String FLATTENING_ERROR_MESSAGE = "Error occured while flattening";
+
+ @Override
+ public PDisjunction rewrite(PDisjunction disjunction) throws RewriterException {
+ PQuery query = disjunction.getQuery();
+ try {
+ return this.flatten(query);
+ } catch (Exception e) {
+ throw new RewriterException(FLATTENING_ERROR_MESSAGE, null, FLATTENING_ERROR_MESSAGE, query, e);
+ }
+ }
+
+ /**
+ * Flattens a given PQuery.
+ *
+ * @param pQuery
+ * the query to flatten
+ * @return a PDisjunction containing the flattened bodies
+ * @throws Exception
+ */
+ public PDisjunction flatten(PQuery pQuery) throws Exception {
+ return doFlatten(pQuery);
+ }
+
+ /**
+ * This function holds the actual flattening logic for a PQuery
+ *
+ * @param pQuery
+ * to be flattened
+ * @return the flattened bodies of the pQuery
+ * @throws Exception
+ */
+ private PDisjunction doFlatten(PQuery pQuery) throws Exception {
+ Set<PBody> bodies = pQuery.getDisjunctBodies().getBodies();
+ // This stores the flattened bodies; they are disjoint
+ Set<PBody> flattenedBodies = Sets.<PBody>newHashSet();
+ for (PBody pBody : bodies) {
+ // OR connection between the bodies
+ PDisjunction flattenedDisjunction = doFlatten(pBody);
+ flattenedBodies.addAll(flattenedDisjunction.getBodies());
+ }
+ return new PDisjunction(pQuery, flattenedBodies);
+ }
+
+
+ /**
+ * This function holds the actual flattening logic for a PBody
+ *
+ * @param pBody
+ * to be flattened
+ * @return the flattened equivalent of the given pBody
+ * @throws Exception
+ */
+ private PDisjunction doFlatten(PBody pBody) throws Exception {
+
+
+ Set<PConstraint> constraints = pBody.getConstraints();
+
+ // If the received pBody should not be flattened, return it alone.
+ if (!isFlatteningNeeded(constraints)) {
+ return prepareFlatPBody(pBody);
+ }
+
+ // The calls that are flattened
+ List<PositivePatternCall> flattenedCalls = Lists.newArrayList();
+
+ // This point we know the body needs flattening
+ // Flatten each positive pattern call where shouldFlatten() returns true
+ List<PDisjunction> flattenedDisjunctions = Lists.<PDisjunction> newArrayList();
+ for (PConstraint pConstraint : constraints) {
+ if (pConstraint instanceof PositivePatternCall) {
+ PositivePatternCall positivePatternCall = (PositivePatternCall) pConstraint;
+ if (shouldFlatten(positivePatternCall)) {
+ // If the above preconditions meet, do the flattening and return the disjoint bodies
+ PQuery referredQuery = positivePatternCall.getReferredQuery();
+ PDisjunction flattenedDisjunction = doFlatten(referredQuery);
+ flattenedDisjunctions.add(flattenedDisjunction);
+ flattenedCalls.add(positivePatternCall);
+ }
+ }
+ }
+
+ return createFlatPDisjunction(pBody,flattenedDisjunctions,flattenedCalls);
+
+ }
+
+ /**
+ * @param pBody
+ * @param flattenedDisjunctions
+ * @param flattenedCalls
+ * @return
+ */
+ private PDisjunction createFlatPDisjunction(PBody pBody, List<PDisjunction> flattenedDisjunctions, List<PositivePatternCall> flattenedCalls) {
+ PQuery pQuery = pBody.getPattern();
+
+ // The members of this set are sets containing bodies in disjunction
+ Set<List<PBody>> conjunctBodySets = combineBodies(flattenedDisjunctions);
+
+ // The result set containing the merged conjuncted bodies
+ Set<PBody> conjunctedBodies = Sets.<PBody> newHashSet();
+
+ for (List<PBody> bodySet : conjunctBodySets) {
+ FlattenerCopier copier = new FlattenerCopier(pQuery, flattenedCalls, bodySet);
+
+ for (PBody calledBody : bodySet) {
+ // Copy each called body
+ copyBody(calledBody, copier, new HierarchicalName(), new ExportedParameterFilter());
+ }
+
+ // Copy the caller body
+ copyBody(pBody, copier, new SameName());
+
+ PBody copiedBody = copier.getCopiedBody();
+ copiedBody.setStatus(PQueryStatus.OK);
+ conjunctedBodies.add(copiedBody);
+ }
+
+ // Create a new (flattened) PDisjunction referring to the corresponding query and return it
+ return new PDisjunction(pBody.getPattern(),conjunctedBodies);
+ }
+
+ private PDisjunction prepareFlatPBody(PBody pBody) {
+ Set<PBody> bodySet = Sets.newHashSet();
+ // Copy here with hierarchical variable renaming
+ FlattenerCopier flattenerCopier = copyBody(pBody, new HierarchicalName());
+ bodySet.add(flattenerCopier.getCopiedBody());
+ return new PDisjunction(pBody.getPattern(), bodySet);
+ }
+
+ private boolean isFlatteningNeeded(Set<PConstraint> constraints) {
+ // Check if the body contains positive pattern call AND if it should be flattened
+ for (PConstraint pConstraint : constraints) {
+ if (pConstraint instanceof PositivePatternCall) {
+ if(shouldFlatten((PositivePatternCall) pConstraint))
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Combines the elements of the sets together. Puts all newly created bodies under the parent query.
+ *
+ * @param pDisjunctions
+ * the collection of sets; all possible full matchings are created and merged
+ * @return
+ */
+ private Set<List<PBody>> combineBodies(List<PDisjunction> pDisjunctions) {
+ // Note: Sets.cartesianProduct(sets) would also be useful to create matchings
+
+ ArrayList<Set<PBody>> setsToCombine = Lists.newArrayList();
+ Set<List<PBody>> result = Sets.<List<PBody>> newHashSet();
+
+ if (pDisjunctions.size() == 0) {
+ // Do nothing (error handling should happen here?)
+ } else {
+ for (PDisjunction pDisjunction : pDisjunctions) {
+ setsToCombine.add(pDisjunction.getBodies());
+ }
+ // Create matchings between the bodies
+ result = Sets.cartesianProduct(setsToCombine);
+ }
+ return result;
+ }
+
+ /**
+ * Helper function to copy a PBody object. Creates a new copier.
+ *
+ * @param pBody
+ * @param namingTool
+ * @return
+ */
+ private FlattenerCopier copyBody(PBody pBody, INamingTool namingTool) {
+ FlattenerCopier copier = new FlattenerCopier(pBody.getPattern(), Lists.<PositivePatternCall> newArrayList(), Lists.<PBody> newArrayList());
+ copyBody(pBody, copier, namingTool);
+ return copier;
+ }
+
+ /**
+ * Helper function to copy a PBody object. Uses a given copier.
+ *
+ * @param pBody
+ * @param copier
+ * @param namingTool
+ * @return
+ */
+ private void copyBody(PBody pBody, FlattenerCopier copier, INamingTool namingTool) {
+ copyBody(pBody, copier, namingTool, new AllowAllFilter());
+ }
+
+ /**
+ * Helper function to copy a PBody object. Uses a given copier and a filter to copy only specific constraints.
+ *
+ * @param pBody
+ * @param copier
+ * @param namingTool
+ * @return
+ */
+ private void copyBody(PBody pBody, FlattenerCopier copier, INamingTool namingTool, IConstraintFilter filter) {
+
+ // Copy variables
+ Set<PVariable> allVariables = pBody.getAllVariables();
+ for (PVariable pVariable : allVariables) {
+ copier.copyVariable(pVariable, namingTool.createVariableName(pVariable, pBody.getPattern()));
+ }
+
+ // Copy constraints which are not filtered
+ Set<PConstraint> constraints = pBody.getConstraints();
+ for (PConstraint pConstraint : constraints) {
+ if(!filter.filter(pConstraint)){
+ copier.copyConstraint(pConstraint);
+ }
+ }
+ }
+
+ /**
+ * Helper interface to exclude constraints from PBody copy processes
+ *
+ * @author Marton Bur
+ *
+ */
+ private interface IConstraintFilter {
+ /**
+ * Returns true, if the given constraint should be filtered (thus should not be copied)
+ *
+ * @param constraint to check
+ * @return true, if the constraint should be filtered
+ */
+ boolean filter(PConstraint constraint);
+ }
+
+ private class ExportedParameterFilter implements IConstraintFilter{
+
+ @Override
+ public boolean filter(PConstraint constraint) {
+ return constraint instanceof ExportedParameter;
+ }
+
+ }
+
+ private class AllowAllFilter implements IConstraintFilter{
+
+ @Override
+ public boolean filter(PConstraint constraint) {
+ // Nothing is filtered
+ return false;
+ }
+
+ }
+
+ /**
+ * Helper interface to ease the naming of the new variables during flattening
+ *
+ * @author Marton Bur
+ *
+ */
+ private interface INamingTool {
+ /**
+ * Creates a variable name based on a given variable and a given query. It only creates a String, doesn't set
+ * anything.
+ *
+ * @param pVariable
+ * @param query
+ * @return the new variable name as a String
+ */
+ String createVariableName(PVariable pVariable, PQuery query);
+ }
+
+ private class SameName implements INamingTool {
+ @Override
+ public String createVariableName(PVariable pVariable, PQuery query) {
+ return pVariable.getName();
+ }
+ }
+
+ private class HierarchicalName implements INamingTool {
+ @Override
+ public String createVariableName(PVariable pVariable, PQuery query) {
+ return getPQueryName(query) + "_" + pVariable.getName();
+ }
+ }
+
+ /**
+ * Helper function to get the name of a query without qualifier
+ *
+ * @param query
+ * @return the name of the query
+ */
+ private String getPQueryName(PQuery query) {
+ String fullyQualifiedName = query.getFullyQualifiedName();
+ int beginIndex = fullyQualifiedName.lastIndexOf(".") + 1;
+ return fullyQualifiedName.substring(beginIndex);
+ }
+
+ /**
+ * Decides whether the pattern should be flattened or not.
+ *
+ *
+ * @param positivePatternCall
+ * the pattern call
+ * @return true if the call should be flattened
+ */
+ private boolean shouldFlatten(PositivePatternCall positivePatternCall) {
+ boolean shouldFlatten = true;
+ /* TODO implement logic here */
+ return shouldFlatten;
+ }
+
+}
diff --git a/tests/org.eclipse.incquery.testing.core/src/org/eclipse/incquery/testing/core/base/CompareQueryTester.java b/tests/org.eclipse.incquery.testing.core/src/org/eclipse/incquery/testing/core/base/CompareQueryTester.java
new file mode 100644
index 0000000..86924d6
--- /dev/null
+++ b/tests/org.eclipse.incquery.testing.core/src/org/eclipse/incquery/testing/core/base/CompareQueryTester.java
@@ -0,0 +1,59 @@
+/*******************************************************************************
+ * Copyright (c) 2010-2014, Marton Bur, Akos Horvath, Zoltan Ujhelyi, Istvan Rath 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:
+ * Marton Bur - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.incquery.testing.core.base;
+
+import java.util.Collection;
+import java.util.HashSet;
+
+import org.eclipse.incquery.runtime.api.IPatternMatch;
+import org.eclipse.incquery.runtime.api.IQuerySpecification;
+import org.eclipse.incquery.runtime.api.IncQueryEngine;
+import org.eclipse.incquery.runtime.api.IncQueryMatcher;
+import org.eclipse.incquery.runtime.exception.IncQueryException;
+import org.junit.Assert;
+
+import com.google.common.collect.Sets;
+import com.google.common.collect.Sets.SetView;
+
+/**
+ * Helper class for checking the soundness of various pattern matching strategies
+ *
+ * @author Marton Bur
+ *
+ */
+public class CompareQueryTester {
+
+ /**
+ * Comnpares the results of two queries. It is assumed that the queri specifications are equivalent and use the same
+ * match classes
+ */
+ public static void assertQueriesEquivalent(IncQueryEngine engine, IQuerySpecification<?> querySpecification1,
+ IQuerySpecification<?> querySpecification2) throws IncQueryException {
+ // Create a matcher for the original query specification
+ IncQueryMatcher<? extends IPatternMatch> matcher = querySpecification1.getMatcher(engine);
+ // Create a matcher for the flattened query specification
+ IncQueryMatcher<? extends IPatternMatch> flattenedMatcher = querySpecification2.getMatcher(engine);
+
+ Collection<? extends IPatternMatch> allMatches = matcher.getAllMatches();
+ Collection<? extends IPatternMatch> allFlattenedMatches = flattenedMatcher.getAllMatches();
+
+ HashSet<IPatternMatch> allMatchesSet = Sets.newHashSet();
+ allMatchesSet.addAll(allMatches);
+ HashSet<IPatternMatch> allFlattenedMatchesSet = Sets.newHashSet();
+ allFlattenedMatchesSet.addAll(allFlattenedMatches);
+
+ SetView<? extends IPatternMatch> intersection = Sets.intersection(allMatchesSet, allFlattenedMatchesSet);
+ int intersectionSize = intersection.size();
+ int matchesCount = allMatches.size();
+
+ Assert.assertEquals(intersectionSize, matchesCount);
+ }
+}
diff --git a/tests/org.eclipse.incquery.testing.core/src/org/eclipse/incquery/testing/core/base/DisjunctionBasedQuerySpecification.java b/tests/org.eclipse.incquery.testing.core/src/org/eclipse/incquery/testing/core/base/DisjunctionBasedQuerySpecification.java
new file mode 100644
index 0000000..11de89f
--- /dev/null
+++ b/tests/org.eclipse.incquery.testing.core/src/org/eclipse/incquery/testing/core/base/DisjunctionBasedQuerySpecification.java
@@ -0,0 +1,142 @@
+/*******************************************************************************
+ * Copyright (c) 2010-2014, Marton Bur, Akos Horvath, Zoltan Ujhelyi, Istvan Rath 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:
+ * Marton Bur - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.incquery.testing.core.base;
+
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.emf.common.notify.Notifier;
+import org.eclipse.incquery.runtime.api.IPatternMatch;
+import org.eclipse.incquery.runtime.api.IQuerySpecification;
+import org.eclipse.incquery.runtime.api.IncQueryEngine;
+import org.eclipse.incquery.runtime.api.IncQueryMatcher;
+import org.eclipse.incquery.runtime.exception.IncQueryException;
+import org.eclipse.incquery.runtime.matchers.psystem.annotations.PAnnotation;
+import org.eclipse.incquery.runtime.matchers.psystem.queries.PDisjunction;
+import org.eclipse.incquery.runtime.matchers.psystem.queries.PParameter;
+import org.eclipse.incquery.runtime.matchers.psystem.queries.PProblem;
+import org.eclipse.incquery.runtime.matchers.psystem.queries.PQuery;
+
+/**
+ * Customizable query specification.
+ *
+ * @author Marton Bur
+ *
+ */
+public class DisjunctionBasedQuerySpecification implements IQuerySpecification<IncQueryMatcher<? extends IPatternMatch>> {
+
+ private PDisjunction pDisjunction;
+ private IQuerySpecification<?> querySpecifiaction;
+
+ /**
+ * The constructor.
+ *
+ * @param querySpecicifation is the basis of the new query specification
+ * @param pDisjunction the returned PDisjunction instance when the getDisjunctbodes() method is called
+ */
+ public DisjunctionBasedQuerySpecification(
+ IQuerySpecification<?> querySpecicifation, PDisjunction pDisjunction) {
+ this.pDisjunction = pDisjunction;
+ this.querySpecifiaction = querySpecicifation;
+ }
+
+ @Override
+ public String getFullyQualifiedName() {
+ return querySpecifiaction.getFullyQualifiedName();
+ }
+
+ @Override
+ public PDisjunction getDisjunctBodies() {
+ return pDisjunction;
+ }
+
+ @Override
+ public Set<PQuery> getDirectReferredQueries() {
+ return querySpecifiaction.getDirectReferredQueries();
+ }
+
+ @Override
+ public Set<PQuery> getAllReferredQueries() {
+ return querySpecifiaction.getAllReferredQueries();
+ }
+
+ @Override
+ public List<String> getParameterNames() {
+ return querySpecifiaction.getParameterNames();
+ }
+
+ @Override
+ public List<PParameter> getParameters() {
+ return querySpecifiaction.getParameters();
+ }
+
+ @Override
+ public Integer getPositionOfParameter(String parameterName) {
+ return querySpecifiaction.getPositionOfParameter(parameterName);
+ }
+
+ @Override
+ public PQueryStatus getStatus() {
+ return querySpecifiaction.getStatus();
+ }
+
+ @Override
+ public List<PProblem> getPProblems() {
+ return querySpecifiaction.getPProblems();
+ }
+
+ @Override
+ public void checkMutability() throws IllegalStateException {
+ querySpecifiaction.checkMutability();
+ }
+
+ @Override
+ public boolean isMutable() {
+ return querySpecifiaction.isMutable();
+ }
+
+ @Override
+ public List<PAnnotation> getAllAnnotations() {
+ return querySpecifiaction.getAllAnnotations();
+ }
+
+ @Override
+ public List<PAnnotation> getAnnotationsByName(String annotationName) {
+ return querySpecifiaction.getAnnotationsByName(annotationName);
+ }
+
+ @Override
+ public PAnnotation getFirstAnnotationByName(String annotationName) {
+ return querySpecifiaction.getFirstAnnotationByName(annotationName);
+ }
+
+ @Override
+ @Deprecated
+ public IncQueryMatcher<? extends IPatternMatch> getMatcher(Notifier emfRoot) throws IncQueryException {
+ return querySpecifiaction.getMatcher(emfRoot);
+ }
+
+ @Override
+ public IncQueryMatcher<? extends IPatternMatch> getMatcher(IncQueryEngine engine) throws IncQueryException {
+ return querySpecifiaction.getMatcher(engine);
+ }
+
+ @Override
+ public IPatternMatch newEmptyMatch() {
+ return querySpecifiaction.newEmptyMatch();
+ }
+
+ @Override
+ public IPatternMatch newMatch(Object... parameters) {
+ return querySpecifiaction.newMatch(parameters);
+ }
+
+}