use of org.lflang.generator.GeneratorBase in project lingua-franca by lf-lang.
the class FedASTUtils method addNetworkOutputControlReaction.
/**
* Add a network control reaction for a given output port 'source' to
* source's parent reactor. This reaction will send a port absent
* message if the status of the output port is absent.
*
* @note Used in federated execution
*
* @param source The output port of the source federate
* @param instance The federate instance is used to keep track of all
* network reactions and some relevant triggers
* @param receivingPortID The ID of the receiving port
* @param channelIndex The channel index of the sending port, if it is a multiport.
* @param bankIndex The bank index of the sending federate, if it is a bank.
* @param receivingFedID The ID of destination federate.
* @param generator The GeneratorBase instance used to perform some target-specific actions
* @param delay The delay value imposed on the connection using after
*/
private static void addNetworkOutputControlReaction(PortInstance source, FederateInstance instance, int receivingPortID, int bankIndex, int channelIndex, int receivingFedID, GeneratorBase generator, Delay delay) {
LfFactory factory = LfFactory.eINSTANCE;
Reaction reaction = factory.createReaction();
// Top-level reactor.
Reactor top = source.getParent().getParent().reactorDefinition;
// 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);
// Add the output from the contained reactor as a source to
// the reaction to preserve precedence order.
VarRef newPortRef = factory.createVarRef();
newPortRef.setContainer(source.getParent().getDefinition());
newPortRef.setVariable(source.getDefinition());
reaction.getSources().add(newPortRef);
// Check whether the action already has been created.
if (instance.networkOutputControlReactionsTrigger == null) {
// The port has not been created.
String triggerName = "outputControlReactionTrigger";
// Find the trigger definition in the reactor definition, which could have been
// generated for another federate instance if there are multiple instances
// of the same reactor that are each distinct federates.
Optional<Action> optTriggerInput = top.getActions().stream().filter(I -> I.getName().equals(triggerName)).findFirst();
if (optTriggerInput.isEmpty()) {
// If no trigger with the name "outputControlReactionTrigger" is
// already added to the reactor definition, we need to create it
// for the first time. The trigger is a logical action.
Action newTriggerForControlReactionVariable = factory.createAction();
newTriggerForControlReactionVariable.setName(triggerName);
newTriggerForControlReactionVariable.setOrigin(ActionOrigin.LOGICAL);
top.getActions().add(newTriggerForControlReactionVariable);
// Now that the variable is created, store it in the federate instance
instance.networkOutputControlReactionsTrigger = newTriggerForControlReactionVariable;
} else {
// If the "outputControlReactionTrigger" trigger is already
// there, we can re-use it for this new reaction since a single trigger
// will trigger
// all network output control reactions.
instance.networkOutputControlReactionsTrigger = optTriggerInput.get();
}
}
// Add the trigger for all output control reactions to the list of triggers
VarRef triggerRef = factory.createVarRef();
triggerRef.setVariable(instance.networkOutputControlReactionsTrigger);
reaction.getTriggers().add(triggerRef);
// Generate the code
reaction.setCode(factory.createCode());
reaction.getCode().setBody(generator.generateNetworkOutputControlReactionBody(newPortRef, receivingPortID, receivingFedID, bankIndex, channelIndex, delay));
// Make the reaction unordered w.r.t. other reactions in the top level.
generator.makeUnordered(reaction);
// Insert the newly generated reaction after the generated sender and
// receiver top-level reactions.
top.getReactions().add(reaction);
// Add the network output control reaction to the federate instance's list
// of network reactions
instance.networkReactions.add(reaction);
}
use of org.lflang.generator.GeneratorBase in project lingua-franca by lf-lang.
the class FedASTUtils method findMaxSTP.
/**
* Find the maximum STP offset for the given 'port'.
*
* An STP offset predicate can be nested in contained reactors in
* the federate.
* @param port The port to generate the STP list for.
* @param generator The GeneratorBase instance used to perform some target-specific actions
* @param reactor The top-level reactor (not the federate reactor)
* @return The maximum STP as a TimeValue
*/
private static TimeValue findMaxSTP(Variable port, FederateInstance instance, GeneratorBase generator, Reactor reactor) {
// Find a list of STP offsets (if any exists)
List<Value> STPList = new LinkedList<>();
// First, check if there are any connections to contained reactors that
// need to be handled
List<Connection> connectionsWithPort = ASTUtils.allConnections(reactor).stream().filter(c -> c.getLeftPorts().stream().anyMatch((VarRef v) -> v.getVariable().equals(port))).collect(Collectors.toList());
// Find the list of reactions that have the port as trigger or source
// (could be a variable name)
List<Reaction> reactionsWithPort = ASTUtils.allReactions(reactor).stream().filter(r -> {
// Check the triggers of reaction r first
return r.getTriggers().stream().anyMatch(t -> {
if (t instanceof VarRef) {
// Check if the variables match
return ((VarRef) t).getVariable() == port;
} else {
// Not a network port (startup or shutdown)
return false;
}
}) || // Then check the sources of reaction r
r.getSources().stream().anyMatch(s -> s.getVariable() == port);
}).collect(Collectors.toList());
// Find a list of STP offsets (if any exists)
if (generator.isFederatedAndDecentralized()) {
for (Reaction r : safe(reactionsWithPort)) {
if (!instance.contains(r)) {
continue;
}
// If not, assume it is zero
if (r.getStp() != null) {
if (r.getStp().getValue().getParameter() != null) {
List<Instantiation> instantList = new ArrayList<>();
instantList.add(instance.instantiation);
STPList.addAll(ASTUtils.initialValue(r.getStp().getValue().getParameter(), instantList));
} else {
STPList.add(r.getStp().getValue());
}
}
}
// Check the children for STPs as well
for (Connection c : safe(connectionsWithPort)) {
VarRef childPort = c.getRightPorts().get(0);
Reactor childReactor = (Reactor) childPort.getVariable().eContainer();
// Find the list of reactions that have the port as trigger or
// source (could be a variable name)
List<Reaction> childReactionsWithPort = ASTUtils.allReactions(childReactor).stream().filter(r -> r.getTriggers().stream().anyMatch(t -> {
if (t instanceof VarRef) {
// Check if the variables match
return ((VarRef) t).getVariable() == childPort.getVariable();
} else {
// Not a network port (startup or shutdown)
return false;
}
}) || r.getSources().stream().anyMatch(s -> s.getVariable() == childPort.getVariable())).collect(Collectors.toList());
for (Reaction r : safe(childReactionsWithPort)) {
if (!instance.contains(r)) {
continue;
}
// If not, assume it is zero
if (r.getStp() != null) {
if (r.getStp().getValue() instanceof Parameter) {
List<Instantiation> instantList = new ArrayList<>();
instantList.add(childPort.getContainer());
STPList.addAll(ASTUtils.initialValue(r.getStp().getValue().getParameter(), instantList));
} else {
STPList.add(r.getStp().getValue());
}
}
}
}
}
return STPList.stream().map(ASTUtils::getLiteralTimeValue).filter(Objects::nonNull).reduce(TimeValue.ZERO, TimeValue::max);
}
use of org.lflang.generator.GeneratorBase 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);
}
}));
}
Aggregations