com.synflow.cx.scoping.CxScopeProvider.java Source code

Java tutorial

Introduction

Here is the source code for com.synflow.cx.scoping.CxScopeProvider.java

Source

/*******************************************************************************
 * Copyright (c) 2012-2015 Synflow SAS.
 * 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:
 *    Matthieu Wipliez - initial API and implementation and/or initial documentation
 *******************************************************************************/
package com.synflow.cx.scoping;

import static com.synflow.cx.CxConstants.DIR_IN;
import static com.synflow.cx.CxConstants.DIR_OUT;
import static com.synflow.cx.CxConstants.PROP_AVAILABLE;
import static com.synflow.cx.CxConstants.PROP_READ;
import static com.synflow.cx.CxConstants.TYPE_READS;
import static org.eclipse.xtext.EcoreUtil2.getContainerOfType;

import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;

import org.eclipse.emf.common.util.ECollections;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.xtext.naming.QualifiedName;
import org.eclipse.xtext.resource.EObjectDescription;
import org.eclipse.xtext.resource.IEObjectDescription;
import org.eclipse.xtext.scoping.IScope;
import org.eclipse.xtext.scoping.Scopes;
import org.eclipse.xtext.scoping.impl.AbstractDeclarativeScopeProvider;
import org.eclipse.xtext.scoping.impl.SimpleScope;

import com.google.common.base.Function;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.synflow.cx.CxUtil;
import com.synflow.cx.cx.Block;
import com.synflow.cx.cx.Bundle;
import com.synflow.cx.cx.Connect;
import com.synflow.cx.cx.CxPackage.Literals;
import com.synflow.cx.cx.ExpressionVariable;
import com.synflow.cx.cx.Inst;
import com.synflow.cx.cx.Instantiable;
import com.synflow.cx.cx.Module;
import com.synflow.cx.cx.Network;
import com.synflow.cx.cx.PortDecl;
import com.synflow.cx.cx.Statement;
import com.synflow.cx.cx.StatementLoop;
import com.synflow.cx.cx.StatementVariable;
import com.synflow.cx.cx.Task;
import com.synflow.cx.cx.VarRef;
import com.synflow.cx.cx.Variable;

/**
 * This class contains custom scoping description.
 * 
 */
public class CxScopeProvider extends AbstractDeclarativeScopeProvider {

    private Iterable<IEObjectDescription> getAllPortDescs(Network network, String direction) {
        Iterable<IEObjectDescription> descriptions = getPortDescs(network, direction);

        // invert direction when referencing ports in instances
        direction = direction == DIR_IN ? DIR_OUT : DIR_IN;
        for (final Inst inst : network.getInstances()) {
            descriptions = Iterables.concat(descriptions, getPortDescs(inst, direction));
        }
        return descriptions;
    }

    private Iterable<? extends IEObjectDescription> getPortDescs(final Inst inst, String direction) {
        Iterable<PortDecl> portDecls;
        Task task = inst.getTask();
        if (task == null) {
            Instantiable entity = inst.getEntity();
            if (entity == null) {
                return ImmutableSet.of();
            }
            portDecls = entity.getPortDecls();
        } else {
            portDecls = task.getPortDecls();
        }

        // names are computed as "instance.port"
        Iterable<Variable> ports = CxUtil.getPorts(portDecls, direction);
        return Iterables.transform(ports, new Function<Variable, IEObjectDescription>() {
            @Override
            public IEObjectDescription apply(Variable port) {
                QualifiedName name = QualifiedName.create(inst.getName(), port.getName());
                return new EObjectDescription(name, port, null);
            }
        });
    }

    private Iterable<IEObjectDescription> getPortDescs(Instantiable entity, String direction) {
        Iterable<Variable> ports = CxUtil.getPorts(entity.getPortDecls(), direction);
        return Iterables.transform(ports, new Function<Variable, IEObjectDescription>() {
            @Override
            public IEObjectDescription apply(Variable port) {
                QualifiedName name = QualifiedName.create(port.getName());
                return new EObjectDescription(name, port, null);
            }
        });
    }

    /**
     * Returns the scope for ports.
     * 
     * @param task
     *            task from which we are access a port
     * @param direction
     *            direction of ports in this task or in the parent design (if any)
     * @return a scope
     */
    private IScope getScopePorts(Task task, String direction) {
        Iterable<IEObjectDescription> descriptions = getPortDescs(task, direction);
        Network network = getContainerOfType(task, Network.class);
        if (network != null) {
            // network may be null if the task is not contained in an instance
            descriptions = Iterables.concat(descriptions, getAllPortDescs(network, direction));
        }
        return new SimpleScope(IScope.NULLSCOPE, descriptions);
    }

    /**
     * Returns the scope for a variable referenced inside a bundle. Returns the scope of global
     * variables.
     */
    public IScope scope_VarRef_variable(Bundle bundle, EReference reference) {
        Iterable<Variable> variables = CxUtil.getVariables(bundle);
        IScope outer = delegateGetScope(bundle, reference);
        return Scopes.scopeFor(variables, outer);
    }

    /**
     * Returns the scope for a variable referenced inside a task. Returns the scope of global
     * variables.
     */
    public IScope scope_VarRef_variable(Module module, EReference reference) {
        return delegateGetScope(module, reference);
    }

    /**
     * Returns the scope for a variable referenced inside a network.
     */
    public IScope scope_VarRef_variable(Network network, EReference reference) {
        return delegateGetScope(network, reference);
    }

    /**
     * Returns the scope for a variable referenced inside a statement.
     */
    public IScope scope_VarRef_variable(Statement statement, EReference reference) {
        List<Variable> variables = new ArrayList<Variable>();

        // go up until we find a function, collecting local variables along the way
        EObject cter = statement;
        while (cter != null) {
            EObject last = cter;
            cter = cter.eContainer();

            if (cter instanceof Block) {
                Block block = (Block) cter;
                List<Statement> stmts = block.getStmts();
                int index = ECollections.indexOf(stmts, last, 0);

                // includes the current statement in the scope
                ListIterator<Statement> it = stmts.listIterator(index + 1);
                while (it.hasPrevious()) {
                    Statement stmt = it.previous();
                    if (stmt instanceof StatementVariable) {
                        variables.addAll(((StatementVariable) stmt).getVariables());
                    }
                }
            } else if (cter instanceof Variable) {
                // got up to the containing function
                break;
            } else if (cter instanceof StatementLoop) {
                // specific case for a loop, if it declares a variable take it into account
                StatementLoop loop = (StatementLoop) cter;
                Statement init = loop.getInit();
                if (init instanceof StatementVariable) {
                    variables.addAll(((StatementVariable) init).getVariables());
                }
            }
        }

        // build scope (from outer to inner)
        IScope outer = getScope(cter, reference);
        if (variables.isEmpty()) {
            return outer;
        }
        return Scopes.scopeFor(variables, outer);
    }

    /**
     * Returns the scope for a variable referenced inside a statement.
     */
    public IScope scope_VarRef_variable(StatementLoop loop, EReference reference) {
        IScope outer = scope_VarRef_variable((Statement) loop, reference);

        Statement init = loop.getInit();
        if (init instanceof StatementVariable) {
            StatementVariable stmt = (StatementVariable) init;
            return Scopes.scopeFor(stmt.getVariables(), outer);
        }
        return outer;
    }

    /**
     * Returns the scope for a variable referenced inside a task. Returns the scope of global
     * variables.
     */
    public IScope scope_VarRef_variable(Task task, EReference reference) {
        Iterable<Variable> variables = CxUtil.getVariables(task);
        IScope outer = delegateGetScope(task, reference);
        return Scopes.scopeFor(variables, outer);
    }

    /**
     * Returns the scope for a variable referenced inside a function.
     */
    public IScope scope_VarRef_variable(Variable function, EReference reference) {
        IScope outer = getScope(function.eContainer(), reference);
        return Scopes.scopeFor(function.getParameters(), outer);
    }

    /**
     * Returns the scope for a variable referenced inside an expression. If used with the
     * 'available' or 'read' property, returns the scope of input ports. Otherwise, resolves the
     * scope with the expression's container.
     */
    public IScope scope_VarRef_variable(VarRef ref, EReference reference) {
        EObject cter = ref.eContainer();
        EStructuralFeature feature = ref.eContainingFeature();
        if (feature == Literals.EXPRESSION_VARIABLE__SOURCE) {
            ExpressionVariable expr = (ExpressionVariable) ref.eContainer();
            String prop = expr.getProperty();
            if (PROP_AVAILABLE.equals(prop) || PROP_READ.equals(prop)) {
                // variable referenced is an input port
                Task task = getContainerOfType(expr, Task.class);
                return getScopePorts(task, DIR_IN);
            }

            return super.getScope(expr, reference);
        } else if (feature == Literals.STATEMENT_WRITE__PORT) {
            Task task = getContainerOfType(cter, Task.class);
            return getScopePorts(task, DIR_OUT);
        } else if (feature == Literals.CONNECT__PORTS) {
            Connect connect = (Connect) cter;
            Network network = (Network) connect.eContainer();
            String direction = TYPE_READS.equals(connect.getType()) ? DIR_IN : DIR_OUT;
            Iterable<IEObjectDescription> descriptions = getAllPortDescs(network, direction);
            return new SimpleScope(IScope.NULLSCOPE, descriptions);
        }

        return super.getScope(cter, reference);
    }

}