Package org.csu.idl.xtext.scoping

Source Code of org.csu.idl.xtext.scoping.IDLScopingHelper

/*
* IDLScopingHelper.java
* Copyright (C) Cátedra SAES-UMU 2010 <catedra-saes-umu@listas.um.es>
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

package org.csu.idl.xtext.scoping;

import java.io.IOException;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Map;

import org.apache.log4j.Logger;
import org.csu.idl.idlmm.AliasDef;
import org.csu.idl.idlmm.ArrayDef;
import org.csu.idl.idlmm.Contained;
import org.csu.idl.idlmm.Container;
import org.csu.idl.idlmm.EnumDef;
import org.csu.idl.idlmm.Field;
import org.csu.idl.idlmm.IdlmmPackage;
import org.csu.idl.idlmm.Include;
import org.csu.idl.idlmm.InterfaceDef;
import org.csu.idl.idlmm.ModuleDef;
import org.csu.idl.idlmm.TranslationUnit;
import org.csu.idl.xtext.loader.IDLLoader;
import org.csu.idl.xtext.util.IDLUtil;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.TreeIterator;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.internal.xtend.util.Pair;
import org.eclipse.xtext.resource.IEObjectDescription;
import org.eclipse.xtext.scoping.IScope;
import org.eclipse.xtext.scoping.Scopes;
import org.eclipse.xtext.scoping.impl.SimpleScope;

public class IDLScopingHelper {
  // implementar relativeName, OK
  // Obsoleto: public static final SimpleAttributeResolver<EObject, String> resolver = SimpleAttributeResolver.newResolver(String.class, "identifier");

  private static Logger logger = Logger.getLogger(IDLScopingHelper.class);

  private static Map<Pair<EObject, EClass>, IScope> scopecache = new HashMap<Pair<EObject, EClass>, IScope>();

  public static IScope getScope(Container context, EClass type) throws Exception {
    // try to resolve from cache
    Pair<EObject, EClass> clave = new Pair<EObject, EClass>(context, type);
    if (scopecache.containsKey(clave))
      return scopecache.get(clave);

    // Compute the outer scope
    IScope outer = IScope.NULLSCOPE;

    EObject ct = context.eContainer();
    if (ct instanceof Container)
      outer = getScope((Container) ct, type);
    else if (ct instanceof TranslationUnit)
      outer = getFullScope((TranslationUnit) ct, type);

    IScope result = new SimpleScope(outer, getScopedElements(context, type));
    scopecache.put(clave, result);
    return result;
  }

  /**
   * Incluye también lo ya cargado. Resuelve el problema de los includes
   * circulares. Evita bucles infinitos.
   *
   * @param trunit
   * @param type
   * @return
   * @throws IOException
   */
  public static IScope getFullScope(TranslationUnit trunit, EClass type) throws Exception {

    IScope outer = IScope.NULLSCOPE;

    Collection<TranslationUnit> loaded = new LinkedList<TranslationUnit>();

    // Tambien es visible lo ya cargado
    Resource resource = trunit.eResource();
    ResourceSet resourceSet = resource.getResourceSet();
    EList<Resource> resources = resourceSet.getResources();
    int index = resources.indexOf(resource);

    for (int i = 0; i < index; i++) {
      loaded.add((TranslationUnit) resources.get(i).getContents().get(0));
    }

    if (!loaded.isEmpty())
      outer = depthTraverse(type, loaded.iterator());

    IScope scope = getScope(trunit, type);

    outer = concatenate(outer, scope.getOuterScope());

    return new SimpleScope(outer, scope.getContents());
  }

  /**
   * Ambito puro de un TranslationUnit
   *
   * @param trunit
   * @param type
   * @return
   * @throws IOException
   */
  public static IScope getScope(TranslationUnit trunit, EClass type) throws Exception {
    // try to resolve from cache
    Pair<EObject, EClass> clave = new Pair<EObject, EClass>(trunit, type);
    if (scopecache.containsKey(clave))
      return scopecache.get(clave);

    IScope outer = IScope.NULLSCOPE;

    Collection<TranslationUnit> includes = new LinkedList<TranslationUnit>();

    // y los includes del TranslationUnit actual
    includes.addAll(getIncludes(trunit, false));

    if (!includes.isEmpty())
      outer = depthTraverse(type, includes.iterator());

    IScope result = new SimpleScope(outer, getScopedElements(trunit, type));
    scopecache.put(clave, result);
    return result;
  }

  /**
   * Method designed to explore in reverse order the list of ExecutionTest, in
   * order to compute the scopes so that the last import is also the outmost
   * scope TODO: should check for loops?
   *
   * @param etest
   * @param type
   * @param iterator
   * @return
   * @throws IOException
   */
  private static IScope depthTraverse(EClass type, Iterator<TranslationUnit> iterator) throws Exception {
    IScope outer = IScope.NULLSCOPE;

    if (iterator.hasNext()) {
      TranslationUnit trunit = iterator.next();
      // inner scope calculation
      IScope scope = getScope(trunit, type);
      // outer scope calculation
      outer = depthTraverse(type, iterator);
      // concatenation
      outer = concatenate(outer, scope);
    }
    return outer;
  }

  /**
   *
   * @param elem
   * @param cont
   * @return true if elem is directly visible from cont
   */
  private static boolean isVisible(Contained elem, Container cont) {
    EObject container = elem.eContainer();

    if (container instanceof TranslationUnit)
      return true;

    if (container == cont)
      return true;

    if (container instanceof ModuleDef && cont instanceof ModuleDef
        && IDLUtil.getFQN((ModuleDef) container).equals(IDLUtil.getFQN((ModuleDef) cont)))
      return true;

    return false;
  }

  protected static String relativeName(Contained elem, Container cont) {
    String identifier = elem.getIdentifier();

    if (identifier == null && elem instanceof AliasDef && ((AliasDef) elem).getContainedType() instanceof ArrayDef) {
      identifier = ((ArrayDef) ((AliasDef) elem).getContainedType()).getName();
    }

    if (isVisible(elem, cont))
      return identifier;
   
    EObject econtainer = elem.eContainer();
   
    if (econtainer instanceof Field)
      return   relativeName((Contained) econtainer.eContainer(), cont) + "::" + identifier;
   
    // Saltamos el EnumDef
    /**
     * module m { enum e {OP1, OP2}; };
     *
     * es
     *   m::OP1 y m::OP2
     * y no
     *   m::e::OP1 y m::e::OP2
     */
    if (econtainer instanceof EnumDef)
    {
      EObject econtainercontainer = econtainer.eContainer();
      if (econtainercontainer instanceof Contained && !equivalentContexts(econtainercontainer).contains(cont))
        return relativeName((Contained) econtainercontainer, cont) + "::" + identifier;
      else
        return identifier;
    }

    return relativeName((Contained) econtainer, cont) + "::" + identifier;
  }

  /**
   * Unused
   *
   * @param include
   * @return
   */
  public static int include2stream(Include include) {
    TranslationUnit tu = (TranslationUnit) include.eContainer();
    Resource resource = tu.eResource();
    ResourceSet resourceSet = resource.getResourceSet();
    EList<Resource> resources = resourceSet.getResources();

    int result = tu.getIncludes().indexOf(include);
    int res = resources.indexOf(resource);

    for (int i = 0; i < res; i++) {
      result += ((TranslationUnit) resources.get(i)).getIncludes().size();
    }

    return result;
  }

  /**
   * Retrieves the list of includes used in a TranslationUnit
   *
   * @param tu
   *            TranslationUnit to explore for includes
   * @param recursive
   *            search includes
   * @return list of TranslationUnits referred by this one, ordered for
   *         "outer scope" concept
   * @throws IOException
   */
  private static Collection<TranslationUnit> getIncludes(TranslationUnit tu, boolean recursive) throws Exception {
    Collection<Include> includes = tu.getIncludes();
    LinkedList<TranslationUnit> result = new LinkedList<TranslationUnit>();

    for (Include incl : includes) {
      Resource resource = currentLoader.loadInclude(incl);

      TranslationUnit obj = (TranslationUnit) resource.getContents().get(0);

      // extract the list of includes ordered by "outer" for
      // using with depthTraverse
      result.add(obj);

      // recursively add includes
      if (recursive)
        result.addAll(getIncludes(obj, true));
    }

    return result;
  }

  /**
   * Helper function to concatenate two scopes in the same exact order
   *
   * @param outer
   * @param inner
   * @return
   */
  private static IScope concatenate(IScope outer, IScope inner) {
    IScope result = outer;

    if (inner != IScope.NULLSCOPE)
      result = new SimpleScope(concatenate(outer, inner.getOuterScope()), inner.getContents());

    return result;
  }

  /**
   * Retrieves the list of IScopedElement contained in a given context
   * EObject, filtered by their EClass, that has to be a subclass of Contained
   * (in order to have an identifier attribute to identify them).
   *
   * @param context
   *            EObject for which all the contents will be searched
   * @param type
   *            EClass of the elements to select and represent with
   *            IScopedElement
   * @return List of the resulting IScopedElement
   */
  private static Iterable<IEObjectDescription> getScopedElements(EObject context, EClass type) {
   
    // if the elements we want to retrieve aren't subclases of Contained,
    // return null
    if (!IdlmmPackage.eINSTANCE.getContained().isSuperTypeOf(type))
      return null;

    Collection<EObject> scopeList = getFilteredContents(context, type);

    // create the scopedElements from the EObjets in the scopeList
    LinkedList<IEObjectDescription> scopedElements = new LinkedList<IEObjectDescription>();

    Container base = (context instanceof Container ? (Container) context : null);

    final IDLAttributeResolver resolver = IDLAttributeResolver.newResolver(base);
    for (IEObjectDescription elm : Scopes.scopeFor(scopeList, resolver, IScope.NULLSCOPE).getContents()) {
      scopedElements.add(elm);
    }

    // in case the context is an InterfaceDef, we also add
    // recursively the elements defined in it's inheritance father
    if (context instanceof InterfaceDef) {
      EList<InterfaceDef> fathers = ((InterfaceDef) context).getDerivesFrom();
      for (InterfaceDef id : fathers)
        scopedElements.addAll((LinkedList<IEObjectDescription>) getScopedElements(id, type));
    }

    return scopedElements;
  }

  // TODO: Redefinition of elements in the hierarchy
  /**
   * Retrieves the list of EObjects of a given type, in a given context
   *
   * @param context
   * @param type
   * @return
   */
  private static Collection<EObject> getFilteredContents(EObject context, EClass type) {

    Collection<EObject> scopeList = new LinkedList<EObject>();

    // Are there other contexts with same FQN that the current
    // context?
    Collection<EObject> contexts = equivalentContexts(context);

    for (EObject con : contexts) {
      // we recover all the contents, adding to the scope list
      // only those of the specified type
      TreeIterator<EObject> allctts = con.eAllContents();

      while (allctts.hasNext()) {
        EObject eact = allctts.next();
        if (type.isSuperTypeOf(eact.eClass()))
          scopeList.add(eact);
      }
    }

    return scopeList;
  }

  private static Collection<EObject> equivalentContexts(EObject context) {
    Collection<EObject> contexts = new LinkedList<EObject>();

    contexts.add(context);

    // Find other ModuleDefs with the same FQN
    if (context instanceof ModuleDef) {
      ResourceSet set = context.eResource().getResourceSet();
      String myFQN = IDLUtil.getFQN((ModuleDef) context);

      for (Resource resource : set.getResources()) {
        TreeIterator<EObject> it = resource.getAllContents();
        while (it.hasNext()) {
          EObject eobj = it.next();

          if (eobj != context && eobj instanceof ModuleDef && IDLUtil.getFQN((ModuleDef) eobj).equals(myFQN))
            contexts.add(eobj);
        }
      }
    }
    return contexts;
  }

  // Static data

  private static IDLLoader currentLoader = null;

  public static void setCurrentLoader(IDLLoader loader) {
    currentLoader = loader;
  }
 
  public static IDLLoader getCurrentLoader() {
    return currentLoader;
  }
}
TOP

Related Classes of org.csu.idl.xtext.scoping.IDLScopingHelper

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.