Search in sources :

Example 11 with VarRef

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

the class ASTUtils method getDelayInstance.

/**
 * Create a new instance delay instances using the given reactor class.
 * The supplied time value is used to override the default interval (which
 * is zero).
 * If the target supports parametric polymorphism, then a single class may
 * be used for each instantiation, in which case a non-empty string must
 * be supplied to parameterize the instance.
 * A default name ("delay") is assigned to the instantiation, but this
 * name must be overridden at the call site, where checks can be done to
 * avoid name collisions in the container in which the instantiation is
 * to be placed. Such checks (or modifications of the AST) are not
 * performed in this method in order to avoid causing concurrent
 * modification exceptions.
 * @param delayClass The class to create an instantiation for
 * @param connection The connection to create a delay instantiation foe
 * @param generic A string that denotes the appropriate type parameter,
 *  which should be null or empty if the target does not support generics.
 * @param defineWidthFromConnection If this is true and if the connection
 *  is a wide connection, then instantiate a bank of delays where the width
 *  is given by ports involved in the connection. Otherwise, the width will
 *  be  unspecified indicating a variable length.
 */
private static Instantiation getDelayInstance(Reactor delayClass, Connection connection, String generic, Boolean defineWidthFromConnection) {
    Delay delay = connection.getDelay();
    Instantiation delayInstance = factory.createInstantiation();
    delayInstance.setReactorClass(delayClass);
    if (!StringExtensions.isNullOrEmpty(generic)) {
        TypeParm typeParm = factory.createTypeParm();
        typeParm.setLiteral(generic);
        delayInstance.getTypeParms().add(typeParm);
    }
    if (hasMultipleConnections(connection)) {
        WidthSpec widthSpec = factory.createWidthSpec();
        if (defineWidthFromConnection) {
            // to delay the ports first, and then broadcast the output of the delays.
            for (VarRef port : connection.getLeftPorts()) {
                WidthTerm term = factory.createWidthTerm();
                term.setPort(EcoreUtil.copy(port));
                widthSpec.getTerms().add(term);
            }
        } else {
            widthSpec.setOfVariableLength(true);
        }
        delayInstance.setWidthSpec(widthSpec);
    }
    Assignment assignment = factory.createAssignment();
    assignment.setLhs(delayClass.getParameters().get(0));
    Value value = factory.createValue();
    if (delay.getParameter() != null) {
        value.setParameter(delay.getParameter());
    } else {
        value.setTime(delay.getTime());
    }
    assignment.getRhs().add(value);
    delayInstance.getParameters().add(assignment);
    // This has to be overridden.
    delayInstance.setName("delay");
    return delayInstance;
}
Also used : VarRef(org.lflang.lf.VarRef) Assignment(org.lflang.lf.Assignment) Value(org.lflang.lf.Value) Instantiation(org.lflang.lf.Instantiation) WidthTerm(org.lflang.lf.WidthTerm) Delay(org.lflang.lf.Delay) TypeParm(org.lflang.lf.TypeParm) WidthSpec(org.lflang.lf.WidthSpec)

Example 12 with VarRef

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

the class ASTUtils method width.

/**
 * Given the width specification of port or instantiation
 * and an (optional) list of nested instantiations, return
 * the width if it can be determined and -1 if not.
 * It will not be able to be determined if either the
 * width is variable (in which case you should use
 * {@link inferPortWidth(VarRef, Connection, List<Instantiation>})
 * or the list of instantiations is incomplete or missing.
 * If there are parameter references in the width, they are
 * evaluated to the extent possible given the instantiations list.
 *
 * The instantiations list is as in
 * {@link initialValue(Parameter, List<Instantiation>)}.
 * If the spec belongs to an instantiation (for a bank of reactors),
 * then the first element on this list should be the instantiation
 * that contains this instantiation. If the spec belongs to a port,
 * then the first element on the list should be the instantiation
 * of the reactor that contains the port.
 *
 * @param spec The width specification or null (to return 1).
 * @param instantiations The (optional) list of instantiations.
 *
 * @return The width, or -1 if the width could not be determined.
 *
 * @throws IllegalArgumentException If an instantiation provided is not as
 *  given above or if the chain of instantiations is not nested.
 */
public static int width(WidthSpec spec, List<Instantiation> instantiations) {
    if (spec == null) {
        return 1;
    }
    if (spec.isOfVariableLength() && spec.eContainer() instanceof Instantiation) {
        // Attempt to infer the width.
        for (Connection c : ((Reactor) spec.eContainer().eContainer()).getConnections()) {
            int leftWidth = 0;
            int rightWidth = 0;
            int leftOrRight = 0;
            for (VarRef leftPort : c.getLeftPorts()) {
                if (leftPort.getContainer() == spec.eContainer()) {
                    if (leftOrRight != 0) {
                        throw new InvalidSourceException("Multiple ports with variable width on a connection.");
                    }
                    // Indicate that the port is on the left.
                    leftOrRight = -1;
                } else {
                    leftWidth += inferPortWidth(leftPort, c, instantiations);
                }
            }
            for (VarRef rightPort : c.getRightPorts()) {
                if (rightPort.getContainer() == spec.eContainer()) {
                    if (leftOrRight != 0) {
                        throw new InvalidSourceException("Multiple ports with variable width on a connection.");
                    }
                    // Indicate that the port is on the right.
                    leftOrRight = 1;
                } else {
                    rightWidth += inferPortWidth(rightPort, c, instantiations);
                }
            }
            if (leftOrRight < 0) {
                return rightWidth - leftWidth;
            } else if (leftOrRight > 0) {
                return leftWidth - rightWidth;
            }
        }
        // A connection was not found with the instantiation.
        return -1;
    }
    var result = 0;
    for (WidthTerm term : spec.getTerms()) {
        if (term.getParameter() != null) {
            Integer termWidth = initialValueInt(term.getParameter(), instantiations);
            if (termWidth != null) {
                result += termWidth;
            } else {
                return -1;
            }
        } else if (term.getWidth() > 0) {
            result += term.getWidth();
        } else {
            return -1;
        }
    }
    return result;
}
Also used : VarRef(org.lflang.lf.VarRef) InvalidSourceException(org.lflang.generator.InvalidSourceException) Connection(org.lflang.lf.Connection) Instantiation(org.lflang.lf.Instantiation) ImportedReactor(org.lflang.lf.ImportedReactor) Reactor(org.lflang.lf.Reactor) WidthTerm(org.lflang.lf.WidthTerm)

Example 13 with VarRef

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

the class FedASTUtils method addNetworkInputControlReaction.

/**
 * Add a network control reaction for a given input port 'destination' to
 * destination's parent reactor. This reaction will block for
 * any valid logical time until it is known whether the trigger for the
 * action corresponding to the given port is present or absent.
 *
 * @note Used in federated execution
 *
 * @param source The output port of the source federate reactor.
 *  Added as a trigger to the network control reaction to preserve the
 *  overall dependency structure of the program across federates.
 * @param destination The input port of the destination federate reactor.
 * @param recevingPortID The ID of the receiving port
 * @param bankIndex The bank index of the receiving federate, or -1 if not in a bank.
 * @param instance The federate instance is used to keep track of all
 *  network input ports globally
 * @param generator The GeneratorBase instance used to perform some target-specific actions
 */
private static void addNetworkInputControlReaction(PortInstance source, PortInstance destination, int recevingPortID, int bankIndex, FederateInstance instance, GeneratorBase generator) {
    LfFactory factory = LfFactory.eINSTANCE;
    Reaction reaction = factory.createReaction();
    VarRef sourceRef = factory.createVarRef();
    VarRef destRef = factory.createVarRef();
    // 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(reaction, bankIndex);
    // Create a new action that will be used to trigger the
    // input control reactions.
    Action newTriggerForControlReactionInput = factory.createAction();
    newTriggerForControlReactionInput.setOrigin(ActionOrigin.LOGICAL);
    // Set the container and variable according to the network port
    destRef.setContainer(destination.getParent().getDefinition());
    destRef.setVariable(destination.getDefinition());
    sourceRef.setContainer(source.getParent().getDefinition());
    sourceRef.setVariable(source.getDefinition());
    Reactor top = destination.getParent().getParent().reactorDefinition;
    newTriggerForControlReactionInput.setName(ASTUtils.getUniqueIdentifier(top, "inputControlReactionTrigger"));
    // Add the newly created Action to the action list of the federated reactor.
    top.getActions().add(newTriggerForControlReactionInput);
    // Create the trigger for the reaction
    VarRef newTriggerForControlReaction = factory.createVarRef();
    newTriggerForControlReaction.setVariable(newTriggerForControlReactionInput);
    // Add the appropriate triggers to the list of triggers of the reaction
    reaction.getTriggers().add(newTriggerForControlReaction);
    // Add the original output port of the source federate
    // as a trigger to keep the overall dependency structure.
    // This is useful when assigning levels.
    reaction.getTriggers().add(sourceRef);
    // Add this trigger to the list of disconnected network reaction triggers
    instance.remoteNetworkReactionTriggers.add(sourceRef);
    // Add the destination port as an effect of the reaction
    reaction.getEffects().add(destRef);
    // Generate code for the network input control reaction
    reaction.setCode(factory.createCode());
    TimeValue maxSTP = findMaxSTP(destination.getDefinition(), instance, generator, destination.getParent().reactorDefinition);
    reaction.getCode().setBody(generator.generateNetworkInputControlReactionBody(recevingPortID, maxSTP));
    generator.makeUnordered(reaction);
    // Insert the reaction
    top.getReactions().add(reaction);
    // Add the trigger for this reaction to the list of triggers, used to actually
    // trigger the reaction at the beginning of each logical time.
    instance.networkInputControlReactionsTriggers.add(newTriggerForControlReactionInput);
    // Add the network input control reaction to the federate instance's list
    // of network reactions
    instance.networkReactions.add(reaction);
}
Also used : VarRef(org.lflang.lf.VarRef) Action(org.lflang.lf.Action) LfFactory(org.lflang.lf.LfFactory) Reaction(org.lflang.lf.Reaction) Reactor(org.lflang.lf.Reactor) TimeValue(org.lflang.TimeValue)

Example 14 with VarRef

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

the class FedASTUtils method addNetworkReceiverReaction.

/**
 * Add a network receiver reaction for a given input port 'destination' to
 * destination's parent reactor. This reaction will react to a generated
 * 'networkAction' (triggered asynchronously, e.g., by federate.c). This
 * 'networkAction' will contain the actual message that is sent by the sender
 * in 'action->value'. This value is forwarded to 'destination' in the network
 * receiver reaction.
 *
 * @note: Used in federated execution
 *
 * @param networkAction The network action (also, @see createNetworkAction)
 * @param source The source port instance.
 * @param destination The destination port instance.
 * @param connection The network connection.
 * @param sourceFederate The source federate.
 * @param destinationFederate The destination federate.
 * @param rightBankIndex The right bank index or -1 if the right reactor is not in a bank.
 * @param rightChannelIndex The right channel index or -1 if the right port is not a multiport.
 * @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 addNetworkReceiverReaction(Action networkAction, PortInstance source, PortInstance destination, Connection connection, FederateInstance sourceFederate, FederateInstance destinationFederate, int rightBankIndex, int rightChannelIndex, GeneratorBase generator, CoordinationType coordination, SupportedSerializers serializer) {
    LfFactory factory = LfFactory.eINSTANCE;
    VarRef sourceRef = factory.createVarRef();
    VarRef destRef = factory.createVarRef();
    Reactor parent = (Reactor) connection.eContainer();
    Reaction networkReceiverReaction = factory.createReaction();
    // These reactions do not require any dependency relationship
    // to other reactions in the container.
    generator.makeUnordered(networkReceiverReaction);
    // 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(networkReceiverReaction, rightBankIndex);
    // The connection is 'physical' if it uses the ~> notation.
    if (connection.isPhysical()) {
        destinationFederate.inboundP2PConnections.add(sourceFederate);
    } else {
        // to make P2P connections
        if (coordination == CoordinationType.DECENTRALIZED) {
            destinationFederate.inboundP2PConnections.add(sourceFederate);
        }
    }
    // 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());
    if (!connection.isPhysical()) {
        // If the connection is not physical,
        // add the original output port of the source federate
        // as a trigger to keep the overall dependency structure.
        // This is useful when assigning levels.
        VarRef senderOutputPort = factory.createVarRef();
        senderOutputPort.setContainer(source.getParent().getDefinition());
        senderOutputPort.setVariable(source.getDefinition());
        networkReceiverReaction.getTriggers().add(senderOutputPort);
        // Add this trigger to the list of disconnected network reaction triggers
        destinationFederate.remoteNetworkReactionTriggers.add(senderOutputPort);
    }
    // Add the input port at the receiver federate reactor as an effect
    networkReceiverReaction.getEffects().add(destRef);
    VarRef triggerRef = factory.createVarRef();
    // Establish references to the action.
    triggerRef.setVariable(networkAction);
    // Add the action as a trigger to the receiver reaction
    networkReceiverReaction.getTriggers().add(triggerRef);
    // Generate code for the network receiver reaction
    networkReceiverReaction.setCode(factory.createCode());
    networkReceiverReaction.getCode().setBody(generator.generateNetworkReceiverBody(networkAction, sourceRef, destRef, receivingPortID, sourceFederate, destinationFederate, rightBankIndex, rightChannelIndex, ASTUtils.getInferredType(networkAction), connection.isPhysical(), serializer));
    // Add the receiver reaction to the parent
    parent.getReactions().add(networkReceiverReaction);
    // Add the network receiver reaction to the federate instance's list
    // of network reactions
    destinationFederate.networkReactions.add(networkReceiverReaction);
}
Also used : VarRef(org.lflang.lf.VarRef) LfFactory(org.lflang.lf.LfFactory) Reactor(org.lflang.lf.Reactor) Reaction(org.lflang.lf.Reaction)

Example 15 with VarRef

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

the class FederateInstance method indexExcludedTopLevelReactions.

/**
 * Build an index of reactions at the top-level (in the
 * federatedReactor) that don't belong to this federate
 * instance. This index is put in the excludeReactions
 * class variable.
 *
 * @param federatedReactor The top-level federated reactor
 */
private void indexExcludedTopLevelReactions(Reactor federatedReactor) {
    boolean inFederate = false;
    if (excludeReactions != null) {
        throw new IllegalStateException("The index for excluded reactions at the top level is already built.");
    }
    excludeReactions = new LinkedHashSet<Reaction>();
    // Construct the set of excluded reactions for this federate.
    // If a reaction is a network reaction that belongs to this federate, we
    // don't need to perform this analysis.
    Iterable<Reaction> reactions = IterableExtensions.filter(ASTUtils.allReactions(federatedReactor), it -> {
        return !networkReactions.contains(it);
    });
    for (Reaction react : reactions) {
        // Create a collection of all the VarRefs (i.e., triggers, sources, and effects) in the react
        // signature that are ports that reference federates.
        // We then later check that all these VarRefs reference this federate. If not, we will add this
        // react to the list of reactions that have to be excluded (note that mixing VarRefs from
        // different federates is not allowed).
        List<VarRef> allVarRefsReferencingFederates = new ArrayList<VarRef>();
        // Add all the triggers that are outputs
        Stream<VarRef> triggersAsVarRef = react.getTriggers().stream().filter(it -> it instanceof VarRef).map(it -> (VarRef) it);
        allVarRefsReferencingFederates.addAll(triggersAsVarRef.filter(it -> it.getVariable() instanceof Output).collect(Collectors.toList()));
        // Add all the sources that are outputs
        allVarRefsReferencingFederates.addAll(react.getSources().stream().filter(it -> it.getVariable() instanceof Output).collect(Collectors.toList()));
        // Add all the effects that are inputs
        allVarRefsReferencingFederates.addAll(react.getEffects().stream().filter(it -> it.getVariable() instanceof Input).collect(Collectors.toList()));
        inFederate = containsAllVarRefs(allVarRefsReferencingFederates);
        if (!inFederate) {
            excludeReactions.add(react);
        }
    }
}
Also used : VarRef(org.lflang.lf.VarRef) Variable(org.lflang.lf.Variable) Delay(org.lflang.lf.Delay) ErrorReporter(org.lflang.ErrorReporter) Action(org.lflang.lf.Action) Input(org.lflang.lf.Input) ArrayList(java.util.ArrayList) LinkedHashMap(java.util.LinkedHashMap) Map(java.util.Map) Instantiation(org.lflang.lf.Instantiation) TriggerInstance(org.lflang.generator.TriggerInstance) Reaction(org.lflang.lf.Reaction) Objects(com.google.common.base.Objects) TimeValue(org.lflang.TimeValue) LinkedHashSet(java.util.LinkedHashSet) GeneratorBase(org.lflang.generator.GeneratorBase) Set(java.util.Set) PortInstance(org.lflang.generator.PortInstance) ReactionInstance(org.lflang.generator.ReactionInstance) Collectors(java.util.stream.Collectors) ActionInstance(org.lflang.generator.ActionInstance) ReactorInstance(org.lflang.generator.ReactorInstance) List(java.util.List) Stream(java.util.stream.Stream) IterableExtensions(org.eclipse.xtext.xbase.lib.IterableExtensions) Reactor(org.lflang.lf.Reactor) ActionOrigin(org.lflang.lf.ActionOrigin) VarRef(org.lflang.lf.VarRef) ASTUtils(org.lflang.ASTUtils) Output(org.lflang.lf.Output) Timer(org.lflang.lf.Timer) TriggerRef(org.lflang.lf.TriggerRef) Input(org.lflang.lf.Input) Output(org.lflang.lf.Output) ArrayList(java.util.ArrayList) Reaction(org.lflang.lf.Reaction)

Aggregations

VarRef (org.lflang.lf.VarRef)21 Reactor (org.lflang.lf.Reactor)16 Action (org.lflang.lf.Action)10 Instantiation (org.lflang.lf.Instantiation)9 Reaction (org.lflang.lf.Reaction)8 Input (org.lflang.lf.Input)7 Output (org.lflang.lf.Output)7 Port (org.lflang.lf.Port)7 ArrayList (java.util.ArrayList)6 LinkedHashSet (java.util.LinkedHashSet)6 TriggerRef (org.lflang.lf.TriggerRef)6 Variable (org.lflang.lf.Variable)6 Connection (org.lflang.lf.Connection)5 ImportedReactor (org.lflang.lf.ImportedReactor)5 LfFactory (org.lflang.lf.LfFactory)5 TimeValue (org.lflang.TimeValue)4 Delay (org.lflang.lf.Delay)4 LinkedList (java.util.LinkedList)3 List (java.util.List)3 Collectors (java.util.stream.Collectors)3