org.eclipse.xtext.formatting2.regionaccess.internal.AbstractSemanticRegionsFinder.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.xtext.formatting2.regionaccess.internal.AbstractSemanticRegionsFinder.java

Source

/*******************************************************************************
 * Copyright (c) 2015 itemis AG (http://www.itemis.eu) and others.
 * 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
 *******************************************************************************/
package org.eclipse.xtext.formatting2.regionaccess.internal;

import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

import org.eclipse.emf.ecore.EAttribute;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.xtext.AbstractElement;
import org.eclipse.xtext.AbstractRule;
import org.eclipse.xtext.Assignment;
import org.eclipse.xtext.CompoundElement;
import org.eclipse.xtext.CrossReference;
import org.eclipse.xtext.GrammarUtil;
import org.eclipse.xtext.Keyword;
import org.eclipse.xtext.RuleCall;
import org.eclipse.xtext.XtextPackage;
import org.eclipse.xtext.formatting2.regionaccess.ISemanticRegion;
import org.eclipse.xtext.formatting2.regionaccess.ISemanticRegionsFinder;
import org.eclipse.xtext.grammaranalysis.impl.GrammarElementTitleSwitch;
import org.eclipse.xtext.xbase.lib.Pair;

import com.google.common.base.Joiner;
import com.google.common.base.Preconditions;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableList.Builder;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;

/**
 * @author Moritz Eysholdt - Initial contribution and API
 */
public abstract class AbstractSemanticRegionsFinder implements ISemanticRegionsFinder {

    protected static class FeaturePredicate implements Predicate<ISemanticRegion> {

        private final String name;
        private final EClass type;

        public FeaturePredicate(EStructuralFeature feature) {
            this.name = feature.getName();
            this.type = feature.getEContainingClass();
        }

        @Override
        public boolean apply(ISemanticRegion input) {
            if (input == null)
                return false;
            EObject element = input.getGrammarElement();
            Assignment assignment = GrammarUtil.containingAssignment(element);
            if (assignment == null || !name.equals(assignment.getFeature()))
                return false;
            EObject semanticElement = input.getSemanticElement();
            return type.isInstance(semanticElement);
        }

    }

    protected static class GrammarElementPredicate implements Predicate<ISemanticRegion> {
        private final EObject grammarElement;

        public GrammarElementPredicate(EObject grammarElement) {
            super();
            this.grammarElement = grammarElement;
        }

        @Override
        public boolean apply(ISemanticRegion input) {
            if (input == null)
                return false;
            return input.getGrammarElement() == grammarElement;
        }

        @Override
        public String toString() {
            String string = new GrammarElementTitleSwitch().showRule().showQualified().doSwitch(grammarElement);
            return "Predicate[" + string + "]";
        }

    }

    protected static class GrammarElementsPredicate implements Predicate<ISemanticRegion> {
        private final Set<? extends EObject> grammarElements;

        public GrammarElementsPredicate(Set<? extends EObject> grammarElements) {
            super();
            this.grammarElements = grammarElements;
        }

        @Override
        public boolean apply(ISemanticRegion input) {
            if (input == null)
                return false;
            return grammarElements.contains(input.getGrammarElement());
        }

        @Override
        public String toString() {
            List<String> strings = Lists.newArrayList();
            GrammarElementTitleSwitch toString = new GrammarElementTitleSwitch().showRule().showQualified();
            for (EObject ele : grammarElements)
                strings.add(toString.doSwitch(ele));
            return "Predicate[" + Joiner.on(", ").join(strings) + "]";
        }
    }

    protected static class KeywordPredicate implements Predicate<ISemanticRegion> {
        private final String keyword;

        public KeywordPredicate(String keyword) {
            super();
            this.keyword = keyword;
        }

        @Override
        public boolean apply(ISemanticRegion input) {
            if (input == null)
                return false;
            EObject element = input.getGrammarElement();
            return element instanceof Keyword && keyword.equals(((Keyword) element).getValue());
        }

        @Override
        public String toString() {
            return "Predicate[" + keyword + "]";
        }
    }

    protected static class KeywordsPredicate implements Predicate<ISemanticRegion> {
        private final Set<String> keywords;

        public KeywordsPredicate(Set<String> keywords) {
            super();
            this.keywords = keywords;
        }

        @Override
        public boolean apply(ISemanticRegion input) {
            if (input == null)
                return false;
            EObject element = input.getGrammarElement();
            return element instanceof Keyword && keywords.contains(((Keyword) element).getValue());
        }

        @Override
        public String toString() {
            return "Predicate[" + Joiner.on(", ").join(keywords) + "]";
        }
    }

    protected static class RulePredicate implements Predicate<ISemanticRegion> {
        private final AbstractRule rule;

        public RulePredicate(AbstractRule rule) {
            super();
            this.rule = rule;
        }

        @Override
        public boolean apply(ISemanticRegion input) {
            if (input == null)
                return false;
            EObject element = input.getGrammarElement();
            return element instanceof RuleCall && ((RuleCall) element).getRule() == rule;
        }

        @Override
        public String toString() {
            return "Predicate[" + rule.getName() + "]";
        }
    }

    protected static class RulesPredicate implements Predicate<ISemanticRegion> {
        private final Set<AbstractRule> rules;

        public RulesPredicate(Set<AbstractRule> rules) {
            super();
            this.rules = rules;
        }

        @Override
        public boolean apply(ISemanticRegion input) {
            if (input == null)
                return false;
            EObject element = input.getGrammarElement();
            return element instanceof RuleCall && rules.contains(((RuleCall) element).getRule());
        }

        @Override
        public String toString() {
            List<String> strings = Lists.newArrayList();
            for (AbstractRule rule : rules)
                strings.add(rule.getName());
            return "Predicate[" + Joiner.on(", ").join(strings) + "]";
        }
    }

    protected void assertNoContainment(EStructuralFeature feat) {
        if (!(feat instanceof EAttribute) && !(feat instanceof EReference && !((EReference) feat).isContainment()))
            throw new IllegalStateException("Only EAttributes and CrossReferences allowed.");
    }

    protected void assertNoEObjectRule(AbstractRule rule) {
        if (GrammarUtil.isEObjectRule(rule))
            throw new IllegalStateException("Only Enum, Datatype and Terminal Rule Calls allowed.");
    }

    protected void assertNoEObjectRuleCall(RuleCall ruleCall) {
        assertNoEObjectRule(ruleCall.getRule());
    }

    @Override
    public ISemanticRegion assignment(Assignment assignment) {
        return findFirst(createPredicate(assignment));
    }

    @Override
    public List<ISemanticRegion> assignments(Assignment... assignments) {
        return findAll(createPredicate(assignments));
    }

    protected void collectMatchableElements(AbstractElement ele, Collection<AbstractElement> result) {
        switch (ele.eClass().getClassifierID()) {
        case XtextPackage.RULE_CALL:
            assertNoEObjectRuleCall((RuleCall) ele);
        case XtextPackage.KEYWORD:
            result.add(ele);
            break;
        case XtextPackage.CROSS_REFERENCE:
            collectMatchableElements(((CrossReference) ele).getTerminal(), result);
            break;
        case XtextPackage.ASSIGNMENT:
            collectMatchableElements(((Assignment) ele).getTerminal(), result);
            break;
        case XtextPackage.ALTERNATIVES:
        case XtextPackage.GROUP:
        case XtextPackage.UNORDERED_GROUP:
            for (AbstractElement child : ((CompoundElement) ele).getElements())
                collectMatchableElements(child, result);
            break;
        }
    }

    protected Predicate<ISemanticRegion> createPredicate(AbstractElement ele) {
        switch (ele.eClass().getClassifierID()) {
        case XtextPackage.RULE_CALL:
            assertNoEObjectRuleCall((RuleCall) ele);
        case XtextPackage.KEYWORD:
            return new GrammarElementPredicate(ele);
        }
        return createPredicate(new AbstractElement[] { ele });
    }

    protected Predicate<ISemanticRegion> createPredicate(AbstractElement... ele) {
        Set<AbstractElement> result = Sets.newHashSet();
        for (AbstractElement e : ele)
            collectMatchableElements(e, result);
        switch (result.size()) {
        case 0:
            return Predicates.alwaysFalse();
        case 1:
            return new GrammarElementPredicate(result.iterator().next());
        default:
            return new GrammarElementsPredicate(result);
        }
    }

    @Override
    public ISemanticRegion crossRef(CrossReference crossReference) {
        return findFirst(createPredicate(crossReference));
    }

    @Override
    public List<ISemanticRegion> crossRefs(CrossReference... crossReferences) {
        return findAll(createPredicate(crossReferences));
    }

    @Override
    public ISemanticRegion element(AbstractElement element) {
        return findFirst(createPredicate(element));
    }

    @Override
    public List<ISemanticRegion> elements(AbstractElement... elements) {
        return findAll(createPredicate(elements));
    }

    @Override
    public ISemanticRegion feature(EStructuralFeature feature) {
        assertNoContainment(feature);
        return findFirst(new FeaturePredicate(feature));
    }

    @Override
    public List<ISemanticRegion> features(EStructuralFeature... features) {
        Set<Predicate<ISemanticRegion>> predicates = Sets.newHashSet();
        for (int i = 0; i < features.length; i++) {
            EStructuralFeature feat = features[i];
            assertNoContainment(feat);
            predicates.add(new FeaturePredicate(feat));
        }
        return findAll(Predicates.or(predicates));
    }

    protected abstract ImmutableList<ISemanticRegion> findAll(Predicate<ISemanticRegion> predicate);

    protected abstract ISemanticRegion findFirst(Predicate<ISemanticRegion> predicate);

    @Override
    public ISemanticRegion keyword(Keyword keyword) {
        return findFirst(createPredicate(keyword));
    }

    @Override
    public ISemanticRegion keyword(String keyword) {
        return findFirst(new KeywordPredicate(keyword));
    }

    @Override
    public List<Pair<ISemanticRegion, ISemanticRegion>> keywordPairs(Keyword kw1, Keyword kw2) {
        Preconditions.checkNotNull(kw1);
        Preconditions.checkNotNull(kw2);
        Preconditions.checkArgument(kw1 != kw2);
        Predicate<ISemanticRegion> p1 = createPredicate(kw1);
        Predicate<ISemanticRegion> p2 = createPredicate(kw2);
        List<ISemanticRegion> all = findAll(Predicates.or(p1, p2));
        Builder<Pair<ISemanticRegion, ISemanticRegion>> result = ImmutableList.builder();
        LinkedList<ISemanticRegion> stack = new LinkedList<ISemanticRegion>();
        for (ISemanticRegion region : all) {
            if (p1.apply(region))
                stack.push(region);
            else if (!stack.isEmpty())
                result.add(Pair.of(stack.pop(), region));
        }
        return result.build();
    }

    @Override
    public List<Pair<ISemanticRegion, ISemanticRegion>> keywordPairs(String kw1, String kw2) {
        Preconditions.checkNotNull(kw1);
        Preconditions.checkNotNull(kw2);
        Preconditions.checkArgument(!kw1.equals(kw2));
        Predicate<ISemanticRegion> p1 = new KeywordPredicate(kw1);
        Predicate<ISemanticRegion> p2 = new KeywordPredicate(kw2);
        List<ISemanticRegion> all = findAll(Predicates.or(p1, p2));
        Builder<Pair<ISemanticRegion, ISemanticRegion>> result = ImmutableList.builder();
        LinkedList<ISemanticRegion> stack = new LinkedList<ISemanticRegion>();
        for (ISemanticRegion region : all) {
            if (p1.apply(region))
                stack.push(region);
            else {
                AbstractRule regionRule = GrammarUtil.containingRule(region.getGrammarElement());
                while (!stack.isEmpty()) {
                    ISemanticRegion candidate = stack.pop();
                    if (region.getSemanticElement() == candidate.getSemanticElement()) {
                        AbstractRule candidateRule = GrammarUtil.containingRule(candidate.getGrammarElement());
                        if (regionRule == candidateRule) {
                            result.add(Pair.of(candidate, region));
                            break;
                        }
                    }
                }
            }
        }
        return result.build();
    }

    @Override
    public List<ISemanticRegion> keywords(Keyword... keywords) {
        return findAll(createPredicate(keywords));
    }

    @Override
    public List<ISemanticRegion> keywords(String... keywords) {
        Predicate<ISemanticRegion> predicate;
        if (keywords.length == 1)
            predicate = new KeywordPredicate(keywords[0]);
        else
            predicate = new KeywordsPredicate(Sets.newHashSet(keywords));
        return findAll(predicate);
    }

    @Override
    public ISemanticRegion ruleCall(RuleCall ruleCall) {
        return findFirst(createPredicate(ruleCall));
    }

    @Override
    public List<ISemanticRegion> ruleCalls(RuleCall... ruleCalls) {
        return findAll(createPredicate(ruleCalls));
    }

    @Override
    public List<ISemanticRegion> ruleCallsTo(AbstractRule... rules) {
        for (int i = 0; i < rules.length; i++)
            assertNoEObjectRule(rules[i]);
        Predicate<ISemanticRegion> predicate;
        if (rules.length == 1)
            predicate = new RulePredicate(rules[0]);
        else
            predicate = new RulesPredicate(Sets.newHashSet(rules));
        return findAll(predicate);
    }

    @Override
    public ISemanticRegion ruleCallTo(AbstractRule rule) {
        assertNoEObjectRule(rule);
        return findFirst(new RulePredicate(rule));
    }

}