/******************************************************************************* * Copyright (c) 2010-2012, 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: * Zoltan Ujhelyi - initial API and implementation *******************************************************************************/ package org.eclipse.incquery.patternlanguage.helper; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import org.eclipse.emf.common.util.EList; import org.eclipse.emf.common.util.TreeIterator; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.util.EcoreUtil; import org.eclipse.incquery.patternlanguage.patternLanguage.AggregatedValue; import org.eclipse.incquery.patternlanguage.patternLanguage.Annotation; import org.eclipse.incquery.patternlanguage.patternLanguage.AnnotationParameter; import org.eclipse.incquery.patternlanguage.patternLanguage.CompareConstraint; import org.eclipse.incquery.patternlanguage.patternLanguage.Constraint; import org.eclipse.incquery.patternlanguage.patternLanguage.Modifiers; import org.eclipse.incquery.patternlanguage.patternLanguage.ParameterRef; import org.eclipse.incquery.patternlanguage.patternLanguage.PathExpressionConstraint; import org.eclipse.incquery.patternlanguage.patternLanguage.PathExpressionHead; import org.eclipse.incquery.patternlanguage.patternLanguage.Pattern; import org.eclipse.incquery.patternlanguage.patternLanguage.PatternBody; import org.eclipse.incquery.patternlanguage.patternLanguage.PatternCall; import org.eclipse.incquery.patternlanguage.patternLanguage.PatternCompositionConstraint; import org.eclipse.incquery.patternlanguage.patternLanguage.PatternLanguageFactory; import org.eclipse.incquery.patternlanguage.patternLanguage.PatternModel; import org.eclipse.incquery.patternlanguage.patternLanguage.ValueReference; import org.eclipse.incquery.patternlanguage.patternLanguage.Variable; import org.eclipse.incquery.patternlanguage.patternLanguage.VariableReference; import org.eclipse.incquery.patternlanguage.patternLanguage.VariableValue; import org.eclipse.xtext.xbase.XExpression; import com.google.common.base.Function; import com.google.common.base.Preconditions; import com.google.common.base.Predicate; import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.Collections2; import com.google.common.collect.Iterables; import com.google.common.collect.ListMultimap; public final class CorePatternLanguageHelper { private CorePatternLanguageHelper() { } /** * Returns the name of the pattern, qualified by package name. */ public static String getFullyQualifiedName(Pattern p) { if (p == null) { throw new IllegalArgumentException("No pattern specified for getFullyQualifiedName"); } PatternModel patternModel = (PatternModel) p.eContainer(); String packageName = (patternModel == null) ? null : patternModel.getPackageName(); if (packageName == null || packageName.isEmpty()) { return p.getName(); } else { return packageName + "." + p.getName(); } // TODO ("local pattern?") } /** * Returns true if the pattern has a private modifier, false otherwise. * * @param pattern * @return */ public static boolean isPrivate(Pattern pattern) { boolean isPrivate = false; for (Modifiers mod : pattern.getModifiers()) { if (mod.isPrivate()) { isPrivate = true; } } return isPrivate; } /** * Returns the parameter of a pattern by name * * @param pattern * @param name * @return the requested parameter of the pattern, or null if none exists * @since 0.7.0 */ public static Variable getParameterByName(final Pattern pattern, final String name) { return Iterables.find(pattern.getParameters(), new Predicate<Variable>() { @Override public boolean apply(Variable variable) { return name.equals(variable.getName()); } }, null); } /** Compiles a map for name-based lookup of symbolic parameter positions. */ public static Map<String, Integer> getParameterPositionsByName(Pattern pattern) { HashMap<String, Integer> posMapping = new HashMap<String, Integer>(); int parameterPosition = 0; for (Variable parameter : pattern.getParameters()) { posMapping.put(parameter.getName(), parameterPosition++); } return posMapping; } /** Finds all pattern variables referenced from the given XExpression. */ public static Set<Variable> getReferencedPatternVariablesOfXExpression(XExpression xExpression) { Set<Variable> result = new HashSet<Variable>(); if (xExpression != null) { TreeIterator<EObject> eAllContents = xExpression.eAllContents(); while (eAllContents.hasNext()) { EObject expression = eAllContents.next(); EList<EObject> eCrossReferences = expression.eCrossReferences(); for (EObject eObject : eCrossReferences) { if (eObject instanceof Variable && !EcoreUtil.isAncestor(xExpression, eObject)) { result.add((Variable) eObject); } } } } return result; } public static EList<Variable> getAllVariablesInBody(PatternBody body, EList<Variable> previous) { EList<Variable> variables = previous; HashMap<String, Variable> parameterMap = new HashMap<String, Variable>(); EList<Variable> parameters = ((Pattern) body.eContainer()).getParameters(); for (Variable var : variables) { parameterMap.put(var.getName(), var); } for (Variable var : parameters) { if (!parameterMap.containsKey(var.getName())) { // Creating a new paramater ref variable ParameterRef refVar = initializeParameterRef(var); parameterMap.put(var.getName(), refVar); variables.add(refVar); } } int unnamedCounter = 0; for (Constraint constraint : body.getConstraints()) { Iterator<EObject> it = constraint.eAllContents(); while (it.hasNext()) { EObject obj = it.next(); if (obj instanceof VariableReference) { VariableReference varRef = (VariableReference) obj; String varName = varRef.getVar(); if ("_".equals(varName)) { varName = String.format("_<%d>", unnamedCounter); unnamedCounter++; } Variable var; if (parameterMap.containsKey(varName)) { var = parameterMap.get(varName); } else { var = initializeLocalVariable(varName); variables.add(var); parameterMap.put(varName, var); } varRef.setVariable(var); } } } return variables; } /** * @param varName * @return */ private static Variable initializeLocalVariable(String varName) { Variable decl; decl = PatternLanguageFactory.eINSTANCE.createVariable(); decl.setName(varName); return decl; } /** * @param var * @return */ private static ParameterRef initializeParameterRef(Variable var) { ParameterRef refVar = PatternLanguageFactory.eINSTANCE.createParameterRef(); refVar.setName(var.getName()); // refVar.setType(var.getType()); refVar.setReferredParam(var); return refVar; } /** Finds all patterns referenced from the given pattern. */ public static Set<Pattern> getReferencedPatterns(Pattern sourcePattern) { Set<Pattern> result = new HashSet<Pattern>(); TreeIterator<EObject> eAllContents = sourcePattern.eAllContents(); while (eAllContents.hasNext()) { EObject element = eAllContents.next(); if (element instanceof PatternCall) { PatternCall call = (PatternCall) element; final Pattern patternRef = call.getPatternRef(); if (patternRef != null) { result.add(patternRef); } } } return result; } private static class AnnotationNameFilter implements Predicate<Annotation> { private final String name; public AnnotationNameFilter(String name) { this.name = name; } @Override public boolean apply(Annotation annotation) { return name.equals(annotation.getName()); } } /** * Returns the first annotation of a given name from a pattern. This method ignores multiple defined annotations by * the same name. For getting a filtered collections of annotations, see * {@link #getAnnotationsByName(Pattern, String)} * * @param pattern * the pattern instance * @param name * the name of the annotation to return * @returns the first annotation or null if no such annotation exists * @since 0.7.0 */ public static Annotation getFirstAnnotationByName(Pattern pattern, String name) { return Iterables.find(pattern.getAnnotations(), new AnnotationNameFilter(name), null); } /** * Returns the collection of annotations of a pattern by a name. For getting the first annotations by name, see * {@link #getAnnotationByName(Pattern, String)} * * @param pattern * the pattern instance * @param name * the name of the annotation to return * @returns a non-null, but possibly empty collection of annotations * @since 0.7.0 */ public static Collection<Annotation> getAnnotationsByName(Pattern pattern, String name) { return Collections2.filter(pattern.getAnnotations(), new AnnotationNameFilter(name)); } public static ListMultimap<String, ValueReference> getAnnotationParameters(Annotation annotation) { ListMultimap<String, ValueReference> parameterMap = ArrayListMultimap.create(); for (AnnotationParameter param : annotation.getParameters()) { parameterMap.put(param.getName(), param.getValue()); } return parameterMap; } /** * Returns all annotation parameters with a selected name * * @param annotation * @param parameterName * @return a lazy collection of annotation parameters with the selected name. May be empty, but is never null. */ public static Collection<ValueReference> getAnnotationParameters(final Annotation annotation, final String parameterName) { return Collections2.transform( Collections2.filter(annotation.getParameters(), new Predicate<AnnotationParameter>() { @Override public boolean apply(AnnotationParameter parameter) { Preconditions.checkArgument(parameter != null); return parameter.getName().equals(parameterName); } }), new Function<AnnotationParameter, ValueReference>() { @Override public ValueReference apply(AnnotationParameter parameter) { Preconditions.checkArgument(parameter != null); return parameter.getValue(); } }); } /** * Returns the first annotation parameter with a selected name. * * @param annotation * @param parameterName * @return the annotation with the selected name, or null if no such annotation exists. */ public static ValueReference getFirstAnnotationParameter(final Annotation annotation, final String parameterName) { Collection<ValueReference> parameters = getAnnotationParameters(annotation, parameterName); return (!parameters.isEmpty()) ? parameters.iterator().next() : null; } /** * @param valueReference * @return all variables from the ValueReference object. (Either referenced directly, or referenced throught an * AggregatedValue.) */ public static Set<Variable> getVariablesFromValueReference(ValueReference valueReference) { Set<Variable> resultSet = new HashSet<Variable>(); if (valueReference != null) { if (valueReference instanceof VariableValue) { resultSet.add(((VariableValue) valueReference).getValue().getVariable()); } else if (valueReference instanceof AggregatedValue) { AggregatedValue aggregatedValue = (AggregatedValue) valueReference; for (ValueReference valueReferenceInner : aggregatedValue.getCall().getParameters()) { for (Variable variable : getVariablesFromValueReference(valueReferenceInner)) { resultSet.add(variable); } } } } return resultSet; } /** * @param patternBody * @return A list of variables, which are running/unnamed variables in the pattern body. These variables' name * starts with the "_" prefix, and can be found in find, count find calls. */ public static List<Variable> getUnnamedRunningVariables(PatternBody patternBody) { List<Variable> resultList = new ArrayList<Variable>(); for (Constraint constraint : patternBody.getConstraints()) { if (constraint instanceof CompareConstraint) { // Just from aggregated elements CompareConstraint compareConstraint = (CompareConstraint) constraint; ValueReference leftValueReference = compareConstraint.getLeftOperand(); ValueReference rightValueReference = compareConstraint.getRightOperand(); resultList.addAll(getUnnamedVariablesFromValueReference(leftValueReference, true)); resultList.addAll(getUnnamedVariablesFromValueReference(rightValueReference, true)); } else if (constraint instanceof PatternCompositionConstraint) { // All from here, aggregates and normal running variables PatternCompositionConstraint patternCompositionConstraint = (PatternCompositionConstraint) constraint; for (ValueReference valueReference : patternCompositionConstraint.getCall().getParameters()) { resultList.addAll(getUnnamedVariablesFromValueReference(valueReference, false)); } } else if (constraint instanceof PathExpressionConstraint) { // Just from aggregated elements PathExpressionConstraint pathExpressionConstraint = (PathExpressionConstraint) constraint; PathExpressionHead pathExpressionHead = pathExpressionConstraint.getHead(); ValueReference valueReference = pathExpressionHead.getDst(); resultList.addAll(getUnnamedVariablesFromValueReference(valueReference, true)); } } return resultList; } private static Set<Variable> getUnnamedVariablesFromValueReference(ValueReference valueReference, boolean onlyFromAggregatedValues) { Set<Variable> resultSet = new HashSet<Variable>(); if (valueReference != null) { if (valueReference instanceof VariableValue) { Variable variable = ((VariableValue) valueReference).getValue().getVariable(); if (variable.getName().startsWith("_") && !onlyFromAggregatedValues) { resultSet.add(variable); } } else if (valueReference instanceof AggregatedValue) { AggregatedValue aggregatedValue = (AggregatedValue) valueReference; for (ValueReference valueReferenceInner : aggregatedValue.getCall().getParameters()) { for (Variable variable : getUnnamedVariablesFromValueReference(valueReferenceInner, false)) { if (variable.getName().startsWith("_")) { resultSet.add(variable); } } } } } return resultSet; } }