Search in sources :

Example 1 with Type

use of org.lflang.lf.Type in project lingua-franca by lf-lang.

the class FedASTUtils method addNetworkSenderReaction.

/**
 * Add a network sender reaction for a given input port 'source' to
 * source's parent reactor. This reaction will react to the 'source'
 * and then send a message on the network destined for the destinationFederate.
 *
 * @note Used in federated execution
 *
 * @param source The source port instance.
 * @param destination The destination port instance.
 * @param connection The network connection.
 * @param sourceFederate The source federate.
 * @param leftBankIndex The left bank index or -1 if the left reactor is not in a bank.
 * @param leftChannelIndex The left channel index or -1 if the left port is not a multiport.
 * @param destinationFederate The destination federate.
 * @param generator The GeneratorBase instance used to perform some target-specific actions
 * @param coordination One of CoordinationType.DECENTRALIZED or CoordinationType.CENTRALIZED.
 * @param serializer The serializer used on the connection
 */
private static void addNetworkSenderReaction(PortInstance source, PortInstance destination, Connection connection, FederateInstance sourceFederate, int leftBankIndex, int leftChannelIndex, FederateInstance destinationFederate, GeneratorBase generator, CoordinationType coordination, SupportedSerializers serializer) {
    LfFactory factory = LfFactory.eINSTANCE;
    // Assume all the types are the same, so just use the first on the right.
    Type type = EcoreUtil.copy(source.getDefinition().getType());
    VarRef sourceRef = factory.createVarRef();
    VarRef destRef = factory.createVarRef();
    Reactor parent = (Reactor) connection.eContainer();
    Reaction networkSenderReaction = factory.createReaction();
    // These reactions do not require any dependency relationship
    // to other reactions in the container.
    generator.makeUnordered(networkSenderReaction);
    // If the sender or receiver is in a bank of reactors, then we want
    // these reactions to appear only in the federate whose bank ID matches.
    generator.setReactionBankIndex(networkSenderReaction, leftBankIndex);
    // The connection is 'physical' if it uses the ~> notation.
    if (connection.isPhysical()) {
        sourceFederate.outboundP2PConnections.add(destinationFederate);
    } else {
        // to make P2P connections
        if (coordination == CoordinationType.DECENTRALIZED) {
            sourceFederate.outboundP2PConnections.add(destinationFederate);
        }
    }
    // Record this action in the right federate.
    // The ID of the receiving port (rightPort) is the position
    // of the action in this list.
    int receivingPortID = destinationFederate.networkMessageActions.size();
    // Establish references to the involved ports.
    sourceRef.setContainer(source.getParent().getDefinition());
    sourceRef.setVariable(source.getDefinition());
    destRef.setContainer(destination.getParent().getDefinition());
    destRef.setVariable(destination.getDefinition());
    // Configure the sending reaction.
    networkSenderReaction.getTriggers().add(sourceRef);
    networkSenderReaction.setCode(factory.createCode());
    networkSenderReaction.getCode().setBody(generator.generateNetworkSenderBody(sourceRef, destRef, receivingPortID, sourceFederate, leftBankIndex, leftChannelIndex, destinationFederate, InferredType.fromAST(type), connection.isPhysical(), connection.getDelay(), serializer));
    // Add the sending reaction to the parent.
    parent.getReactions().add(networkSenderReaction);
    // Add the network sender reaction to the federate instance's list
    // of network reactions
    sourceFederate.networkReactions.add(networkSenderReaction);
}
Also used : VarRef(org.lflang.lf.VarRef) InferredType(org.lflang.InferredType) Type(org.lflang.lf.Type) CoordinationType(org.lflang.TargetProperty.CoordinationType) LfFactory(org.lflang.lf.LfFactory) Reactor(org.lflang.lf.Reactor) Reaction(org.lflang.lf.Reaction)

Example 2 with Type

use of org.lflang.lf.Type in project lingua-franca by lf-lang.

the class FedASTUtils method createNetworkAction.

/**
 * Create a "network action" in the reactor that contains the given
 * connection and return it.
 *
 * The purpose of this action is to serve as a trigger for a "network
 * input reaction" that is responsible for relaying messages to the
 * port that is on the receiving side of the given connection. The
 * connection is assumed to be between two reactors that reside in
 * distinct federates. Hence, the container of the connection is
 * assumed to be top-level.
 *
 * @param connection A connection between to federates.
 * @param serializer The serializer used on the connection.
 * @param type The type of the source port (indicating the type of
 *  data to be received).
 * @param networkBufferType The type of the buffer used for network
 *  communication in the target (e.g., uint8_t* in C).
 * @return The newly created action.
 */
private static Action createNetworkAction(Connection connection, SupportedSerializers serializer, Type type, String networkBufferType) {
    Reactor top = (Reactor) connection.eContainer();
    LfFactory factory = LfFactory.eINSTANCE;
    Action action = factory.createAction();
    // Name the newly created action; set its delay and type.
    action.setName(ASTUtils.getUniqueIdentifier(top, "networkMessage"));
    if (serializer == SupportedSerializers.NATIVE) {
        action.setType(type);
    } else {
        Type action_type = factory.createType();
        action_type.setId(networkBufferType);
        action.setType(action_type);
    }
    // The connection is 'physical' if it uses the ~> notation.
    if (connection.isPhysical()) {
        action.setOrigin(ActionOrigin.PHYSICAL);
        // the minDelay.
        if (connection.getDelay() != null) {
            action.setMinDelay(factory.createValue());
            action.getMinDelay().setTime(connection.getDelay().getTime());
        }
    } else {
        action.setOrigin(ActionOrigin.LOGICAL);
    }
    return action;
}
Also used : Action(org.lflang.lf.Action) InferredType(org.lflang.InferredType) Type(org.lflang.lf.Type) CoordinationType(org.lflang.TargetProperty.CoordinationType) Reactor(org.lflang.lf.Reactor) LfFactory(org.lflang.lf.LfFactory)

Example 3 with Type

use of org.lflang.lf.Type in project lingua-franca by lf-lang.

the class ASTUtils method insertGeneratedDelays.

/**
 * Find connections in the given resource that have a delay associated with them,
 * and reroute them via a generated delay reactor.
 * @param resource The AST.
 * @param generator A code generator.
 */
public static void insertGeneratedDelays(Resource resource, GeneratorBase generator) {
    // The resulting changes to the AST are performed _after_ iterating
    // in order to avoid concurrent modification problems.
    List<Connection> oldConnections = new ArrayList<>();
    Map<EObject, List<Connection>> newConnections = new LinkedHashMap<>();
    Map<EObject, List<Instantiation>> delayInstances = new LinkedHashMap<>();
    Iterable<Reactor> containers = Iterables.filter(IteratorExtensions.toIterable(resource.getAllContents()), Reactor.class);
    // Iterate over the connections in the tree.
    for (Reactor container : containers) {
        for (Connection connection : allConnections(container)) {
            if (connection.getDelay() != null) {
                EObject parent = connection.eContainer();
                // Assume all the types are the same, so just use the first on the right.
                Type type = ((Port) connection.getRightPorts().get(0).getVariable()).getType();
                Reactor delayClass = getDelayClass(type, generator);
                String generic = generator.getTargetTypes().supportsGenerics() ? generator.getTargetTypes().getTargetType(InferredType.fromAST(type)) : "";
                Instantiation delayInstance = getDelayInstance(delayClass, connection, generic, !generator.generateAfterDelaysWithVariableWidth());
                // Stage the new connections for insertion into the tree.
                List<Connection> connections = convertToEmptyListIfNull(newConnections.get(parent));
                connections.addAll(rerouteViaDelay(connection, delayInstance));
                newConnections.put(parent, connections);
                // Stage the original connection for deletion from the tree.
                oldConnections.add(connection);
                // Stage the newly created delay reactor instance for insertion
                List<Instantiation> instances = convertToEmptyListIfNull(delayInstances.get(parent));
                instances.add(delayInstance);
                delayInstances.put(parent, instances);
            }
        }
    }
    // Remove old connections; insert new ones.
    oldConnections.forEach(connection -> {
        var container = connection.eContainer();
        if (container instanceof Reactor) {
            ((Reactor) container).getConnections().remove(connection);
        } else if (container instanceof Mode) {
            ((Mode) container).getConnections().remove(connection);
        }
    });
    newConnections.forEach((container, connections) -> {
        if (container instanceof Reactor) {
            ((Reactor) container).getConnections().addAll(connections);
        } else if (container instanceof Mode) {
            ((Mode) container).getConnections().addAll(connections);
        }
    });
    // Finally, insert the instances and, before doing so, assign them a unique name.
    delayInstances.forEach((container, instantiations) -> instantiations.forEach(instantiation -> {
        if (container instanceof Reactor) {
            instantiation.setName(getUniqueIdentifier((Reactor) container, "delay"));
            ((Reactor) container).getInstantiations().add(instantiation);
        } else if (container instanceof Mode) {
            instantiation.setName(getUniqueIdentifier((Reactor) container.eContainer(), "delay"));
            ((Mode) container).getInstantiations().add(instantiation);
        }
    }));
}
Also used : Code(org.lflang.lf.Code) LfPackage(org.lflang.lf.LfPackage) Delay(org.lflang.lf.Delay) WidthSpec(org.lflang.lf.WidthSpec) EStructuralFeature(org.eclipse.emf.ecore.EStructuralFeature) Action(org.lflang.lf.Action) Input(org.lflang.lf.Input) ILeafNode(org.eclipse.xtext.nodemodel.ILeafNode) StateVar(org.lflang.lf.StateVar) Matcher(java.util.regex.Matcher) HashMultimap(com.google.common.collect.HashMultimap) Port(org.lflang.lf.Port) Map(java.util.Map) Instantiation(org.lflang.lf.Instantiation) INode(org.eclipse.xtext.nodemodel.INode) Connection(org.lflang.lf.Connection) GeneratorBase(org.lflang.generator.GeneratorBase) Element(org.lflang.lf.Element) TypeParm(org.lflang.lf.TypeParm) Collection(java.util.Collection) CompositeNode(org.eclipse.xtext.nodemodel.impl.CompositeNode) Set(java.util.Set) InvalidSourceException(org.lflang.generator.InvalidSourceException) EObject(org.eclipse.emf.ecore.EObject) ICompositeNode(org.eclipse.xtext.nodemodel.ICompositeNode) ArraySpec(org.lflang.lf.ArraySpec) Mode(org.lflang.lf.Mode) Parameter(org.lflang.lf.Parameter) List(java.util.List) Value(org.lflang.lf.Value) CodeMap(org.lflang.generator.CodeMap) WidthTerm(org.lflang.lf.WidthTerm) Assignment(org.lflang.lf.Assignment) Resource(org.eclipse.emf.ecore.resource.Resource) ActionOrigin(org.lflang.lf.ActionOrigin) Pattern(java.util.regex.Pattern) StringExtensions(org.eclipse.xtext.xbase.lib.StringExtensions) Output(org.lflang.lf.Output) Variable(org.lflang.lf.Variable) Iterables(com.google.common.collect.Iterables) LfFactory(org.lflang.lf.LfFactory) NodeModelUtils(org.eclipse.xtext.nodemodel.util.NodeModelUtils) ImportedReactor(org.lflang.lf.ImportedReactor) Iterators(com.google.common.collect.Iterators) ArrayList(java.util.ArrayList) HashSet(java.util.HashSet) LinkedHashMap(java.util.LinkedHashMap) Pair(org.eclipse.xtext.util.Pair) TargetDecl(org.lflang.lf.TargetDecl) StringUtil(org.lflang.util.StringUtil) Reaction(org.lflang.lf.Reaction) KeyValuePair(org.lflang.lf.KeyValuePair) Type(org.lflang.lf.Type) LinkedHashSet(java.util.LinkedHashSet) Tuples(org.eclipse.xtext.util.Tuples) XtextResource(org.eclipse.xtext.resource.XtextResource) HiddenLeafNode(org.eclipse.xtext.nodemodel.impl.HiddenLeafNode) Model(org.lflang.lf.Model) ReactorDecl(org.lflang.lf.ReactorDecl) EcoreUtil(org.eclipse.emf.ecore.util.EcoreUtil) Time(org.lflang.lf.Time) EList(org.eclipse.emf.common.util.EList) IteratorExtensions(org.eclipse.xtext.xbase.lib.IteratorExtensions) IterableExtensions(org.eclipse.xtext.xbase.lib.IterableExtensions) TerminalRule(org.eclipse.xtext.TerminalRule) Reactor(org.lflang.lf.Reactor) VarRef(org.lflang.lf.VarRef) Timer(org.lflang.lf.Timer) Port(org.lflang.lf.Port) Mode(org.lflang.lf.Mode) Connection(org.lflang.lf.Connection) ArrayList(java.util.ArrayList) LinkedHashMap(java.util.LinkedHashMap) Type(org.lflang.lf.Type) EObject(org.eclipse.emf.ecore.EObject) List(java.util.List) ArrayList(java.util.ArrayList) EList(org.eclipse.emf.common.util.EList) ImportedReactor(org.lflang.lf.ImportedReactor) Reactor(org.lflang.lf.Reactor) Instantiation(org.lflang.lf.Instantiation)

Example 4 with Type

use of org.lflang.lf.Type in project lingua-franca by lf-lang.

the class LFValidator method checkConnection.

@Check(CheckType.FAST)
public void checkConnection(Connection connection) {
    // Report if connection is part of a cycle.
    Set<NamedInstance<?>> cycles = this.info.topologyCycles();
    for (VarRef lp : connection.getLeftPorts()) {
        for (VarRef rp : connection.getRightPorts()) {
            boolean leftInCycle = false;
            for (NamedInstance<?> it : cycles) {
                if ((lp.getContainer() == null && it.getDefinition().equals(lp.getVariable())) || (it.getDefinition().equals(lp.getVariable()) && it.getParent().equals(lp.getContainer()))) {
                    leftInCycle = true;
                    break;
                }
            }
            for (NamedInstance<?> it : cycles) {
                if ((rp.getContainer() == null && it.getDefinition().equals(rp.getVariable())) || (it.getDefinition().equals(rp.getVariable()) && it.getParent().equals(rp.getContainer()))) {
                    if (leftInCycle) {
                        Reactor reactor = ASTUtils.getEnclosingReactor(connection);
                        String reactorName = reactor.getName();
                        error(String.format("Connection in reactor %s creates", reactorName) + String.format("a cyclic dependency between %s and %s.", toText(lp), toText(rp)), Literals.CONNECTION__DELAY);
                    }
                }
            }
        }
    }
    // we leave type compatibility that language's compiler or interpreter.
    if (isCBasedTarget()) {
        Type type = (Type) null;
        for (VarRef port : connection.getLeftPorts()) {
            // error. Avoid a class cast exception.
            if (port.getVariable() instanceof Port) {
                if (type == null) {
                    type = ((Port) port.getVariable()).getType();
                } else {
                    // method for AST types, so we have to manually check the types.
                    if (!sameType(type, ((Port) port.getVariable()).getType())) {
                        error("Types do not match.", Literals.CONNECTION__LEFT_PORTS);
                    }
                }
            }
        }
        for (VarRef port : connection.getRightPorts()) {
            // error. Avoid a class cast exception.
            if (port.getVariable() instanceof Port) {
                if (type == null) {
                    type = ((Port) port.getVariable()).getType();
                } else {
                    if (!sameType(type, type = ((Port) port.getVariable()).getType())) {
                        error("Types do not match.", Literals.CONNECTION__RIGHT_PORTS);
                    }
                }
            }
        }
    }
    // Check whether the total width of the left side of the connection
    // matches the total width of the right side. This cannot be determined
    // here if the width is not given as a constant. In that case, it is up
    // to the code generator to check it.
    int leftWidth = 0;
    for (VarRef port : connection.getLeftPorts()) {
        // null args imply incomplete check.
        int width = inferPortWidth(port, null, null);
        if (width < 0 || leftWidth < 0) {
            // Cannot determine the width of the left ports.
            leftWidth = -1;
        } else {
            leftWidth += width;
        }
    }
    int rightWidth = 0;
    for (VarRef port : connection.getRightPorts()) {
        // null args imply incomplete check.
        int width = inferPortWidth(port, null, null);
        if (width < 0 || rightWidth < 0) {
            // Cannot determine the width of the left ports.
            rightWidth = -1;
        } else {
            rightWidth += width;
        }
    }
    if (leftWidth != -1 && rightWidth != -1 && leftWidth != rightWidth) {
        if (connection.isIterated()) {
            if (leftWidth == 0 || rightWidth % leftWidth != 0) {
                // FIXME: The second argument should be Literals.CONNECTION, but
                // stupidly, xtext will not accept that. There seems to be no way to
                // report an error for the whole connection statement.
                warning(String.format("Left width %s does not divide right width %s", leftWidth, rightWidth), Literals.CONNECTION__LEFT_PORTS);
            }
        } else {
            // FIXME: The second argument should be Literals.CONNECTION, but
            // stupidly, xtext will not accept that. There seems to be no way to
            // report an error for the whole connection statement.
            warning(String.format("Left width %s does not match right width %s", leftWidth, rightWidth), Literals.CONNECTION__LEFT_PORTS);
        }
    }
    Reactor reactor = ASTUtils.getEnclosingReactor(connection);
    // Make sure the right port is not already an effect of a reaction.
    for (Reaction reaction : ASTUtils.allReactions(reactor)) {
        for (VarRef effect : reaction.getEffects()) {
            for (VarRef rightPort : connection.getRightPorts()) {
                if (// Refers to the same variable
                rightPort.getVariable().equals(effect.getVariable()) && // Refers to the same instance
                rightPort.getContainer() == effect.getContainer() && (// Either is not part of a mode
                reaction.eContainer() instanceof Reactor || connection.eContainer() instanceof Reactor || // Or they are in the same mode
                connection.eContainer() == reaction.eContainer())) {
                    error("Cannot connect: Port named '" + effect.getVariable().getName() + "' is already effect of a reaction.", Literals.CONNECTION__RIGHT_PORTS);
                }
            }
        }
    }
    // upstream connection.
    for (Connection c : reactor.getConnections()) {
        if (c != connection) {
            for (VarRef thisRightPort : connection.getRightPorts()) {
                for (VarRef thatRightPort : c.getRightPorts()) {
                    if (// Refers to the same variable
                    thisRightPort.getVariable().equals(thatRightPort.getVariable()) && // Refers to the same instance
                    thisRightPort.getContainer() == thatRightPort.getContainer() && (// Or either of the connections in not part of a mode
                    connection.eContainer() instanceof Reactor || c.eContainer() instanceof Reactor || // Or they are in the same mode
                    connection.eContainer() == c.eContainer())) {
                        error("Cannot connect: Port named '" + thisRightPort.getVariable().getName() + "' may only appear once on the right side of a connection.", Literals.CONNECTION__RIGHT_PORTS);
                    }
                }
            }
        }
    }
}
Also used : VarRef(org.lflang.lf.VarRef) ASTUtils.isOfTimeType(org.lflang.ASTUtils.isOfTimeType) CheckType(org.eclipse.xtext.validation.CheckType) ModeTransitionType(org.lflang.generator.ModeInstance.ModeTransitionType) Type(org.lflang.lf.Type) Port(org.lflang.lf.Port) Connection(org.lflang.lf.Connection) ImportedReactor(org.lflang.lf.ImportedReactor) Reactor(org.lflang.lf.Reactor) Reaction(org.lflang.lf.Reaction) NamedInstance(org.lflang.generator.NamedInstance) Check(org.eclipse.xtext.validation.Check)

Aggregations

Reactor (org.lflang.lf.Reactor)4 Type (org.lflang.lf.Type)4 Reaction (org.lflang.lf.Reaction)3 VarRef (org.lflang.lf.VarRef)3 InferredType (org.lflang.InferredType)2 CoordinationType (org.lflang.TargetProperty.CoordinationType)2 Connection (org.lflang.lf.Connection)2 ImportedReactor (org.lflang.lf.ImportedReactor)2 LfFactory (org.lflang.lf.LfFactory)2 Port (org.lflang.lf.Port)2 HashMultimap (com.google.common.collect.HashMultimap)1 Iterables (com.google.common.collect.Iterables)1 Iterators (com.google.common.collect.Iterators)1 ArrayList (java.util.ArrayList)1 Collection (java.util.Collection)1 HashSet (java.util.HashSet)1 LinkedHashMap (java.util.LinkedHashMap)1 LinkedHashSet (java.util.LinkedHashSet)1 List (java.util.List)1 Map (java.util.Map)1