All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.eclipse.xtext.scoping.impl.AbstractScope Maven / Gradle / Ivy

There is a newer version: 2.4.3
Show newest version
/*******************************************************************************
 * Copyright (c) 2010 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.scoping.impl;

import static com.google.common.collect.Iterables.*;

import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;

import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.xtext.EcoreUtil2;
import org.eclipse.xtext.naming.QualifiedName;
import org.eclipse.xtext.resource.IEObjectDescription;
import org.eclipse.xtext.scoping.IScope;

import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import com.google.common.collect.Iterators;
import com.google.inject.Provider;

/**
 * 

Base class for custom scope implementations. It supports nesting of scopes * into each other, appropriate shadowing semantics and case sensitive and insensitive * lookup.

* *

Implementors have to provide {@link #getAllLocalElements()}. However, it is recommended * to customize {@link #getLocalElementsByEObject(EObject, URI)} and {@link #getLocalElementsByName(QualifiedName)} * as well.

* * @author Sven Efftinge - Initial contribution and API * @author Sebastian Zarnekow */ public abstract class AbstractScope implements IScope { /** * Lazy iterable with a reasonable {@link #toString()} implementation that supports * shadowing of parents elements by means of filtering. */ protected static class ParentIterable implements Iterable, Predicate { private final AbstractScope scope; private final Provider> provider; private Iterable parentElements; protected ParentIterable(AbstractScope scope, Provider> provider) { this.scope = scope; this.provider = provider; } public Iterator iterator() { if (parentElements == null) { parentElements = provider.get(); } Iterator parentIterator = parentElements.iterator(); Iterator filteredIterator = Iterators.filter(parentIterator, this); return filteredIterator; } public boolean apply(IEObjectDescription input) { return !scope.isShadowed(input); } @Override public String toString() { return Iterables.toString(this); } } private final boolean ignoreCase; private final IScope parent; /** * Creates a new scope with a given parent. * @param parent the parent scope. May not be null. Use {@link IScope#NULLSCOPE NULLSCOPE} instead. * @param ignoreCase whether name lookup and shadowing should be case insensitive or not. */ protected AbstractScope(IScope parent, boolean ignoreCase) { if (parent == null) throw new IllegalArgumentException("parent may not be null. Use IScope.NULLSCOPE instead."); this.parent = parent; this.ignoreCase = ignoreCase; } public IScope getParent() { return parent; } public boolean isIgnoreCase() { return ignoreCase; } public IEObjectDescription getSingleElement(QualifiedName name) { IEObjectDescription result = getSingleLocalElementByName(name); if (result != null) return result; return getParent().getSingleElement(name); } protected IEObjectDescription getSingleLocalElementByName(QualifiedName name) { Iterable result = getLocalElementsByName(name); Iterator iterator = result.iterator(); if (iterator.hasNext()) return iterator.next(); return null; } public Iterable getAllElements() { Iterable localElements = getAllLocalElements(); Iterable parentElements = getParentElements(new Provider>() { public Iterable get() { return getParent().getAllElements(); } }); Iterable result = Iterables.concat(localElements, parentElements); return result; } public Iterable getElements(final QualifiedName name) { Iterable localElements = getLocalElementsByName(name); if (localElements instanceof Collection) { if (((Collection) localElements).isEmpty()) return getParent().getElements(name); } Iterable parentElements = getParentElements(new Provider>() { public Iterable get() { return getParent().getElements(name); } }); Iterable result = Iterables.concat(localElements, parentElements); return result; } public IEObjectDescription getSingleElement(EObject object) { Iterable elements = getElements(object); Iterator iterator = elements.iterator(); if (iterator.hasNext()) { IEObjectDescription result = iterator.next(); return result; } return null; } public Iterable getElements(final EObject object) { final URI uri = EcoreUtil2.getNormalizedURI(object); Iterable localElements = getLocalElementsByEObject(object, uri); Iterable parentElements = getParentElements(new Provider>() { public Iterable get() { return getParent().getElements(object); } }); Iterable result = Iterables.concat(localElements, parentElements); return result; } protected abstract Iterable getAllLocalElements(); protected Iterable getLocalElementsByName(final QualifiedName name) { Iterable localElements = getAllLocalElements(); Iterable result = Iterables.filter(localElements, new Predicate() { public boolean apply(IEObjectDescription input) { if (isIgnoreCase()) { QualifiedName lowerCase = name.toLowerCase(); QualifiedName inputLowerCase = input.getName().toLowerCase(); return lowerCase.equals(inputLowerCase); } else { return name.equals(input.getName()); } } }); return result; } protected Iterable getLocalElementsByEObject(final EObject object, final URI uri) { Iterable localElements = getAllLocalElements(); Iterable result = Iterables.filter(localElements, new Predicate() { public boolean apply(IEObjectDescription input) { if (input.getEObjectOrProxy() == object) return canBeFoundByName(input); if (uri.equals(input.getEObjectURI())) { return canBeFoundByName(input); } return false; } public boolean canBeFoundByName(IEObjectDescription input) { IEObjectDescription lookUp = getSingleLocalElementByName(input.getName()); if (lookUp != null) { if (lookUp == input) return true; if (lookUp.getEObjectOrProxy() == object) return true; if (uri.equals(lookUp.getEObjectURI())) return true; } return false; } }); return result; } protected Iterable getParentElements(Provider> provider) { if (getParent() == IScope.NULLSCOPE) return Collections.emptyList(); return new ParentIterable(this, provider); } /** * Returns true if the given description {@code input} from the parent scope is * shadowed by local elements. * @return true if the given description {@code input} from the parent scope is * shadowed by local elements. */ protected boolean isShadowed(IEObjectDescription input) { final Iterable localElements = getLocalElementsByName(input.getName()); final boolean isEmpty = isEmpty(localElements); return !isEmpty; } @Override public String toString() { String parentString = null; try { final IScope parent = getParent(); parentString = parent.toString(); } catch (Throwable t) { parentString = t.getClass().getSimpleName() + " : " + t.getMessage(); } return getClass().getSimpleName() + (ignoreCase? "[ignore case]":"") + getAllLocalElements() + " -> " + parentString; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy