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;
}
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;
}
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);
}
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);
}
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);
}
}
}
Aggregations