org.eclipse.incquery.patternlanguage.helper.CorePatternLanguageHelper.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.incquery.patternlanguage.helper.CorePatternLanguageHelper.java

Source

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

}