use of org.lflang.lf.Instantiation 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<Expression> 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() instanceof ParameterReference) {
List<Instantiation> instantList = new ArrayList<>();
instantList.add(instance.instantiation);
final var param = ((ParameterReference) r.getStp().getValue()).getParameter();
STPList.addAll(ASTUtils.initialValue(param, 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 ParameterReference) {
List<Instantiation> instantList = new ArrayList<>();
instantList.add(childPort.getContainer());
final var param = ((ParameterReference) r.getStp().getValue()).getParameter();
STPList.addAll(ASTUtils.initialValue(param, 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.lf.Instantiation in project lingua-franca by lf-lang.
the class ASTUtils method inferPortWidth.
/**
* Infer the width of a port reference in a connection.
* The port reference one or two parts, a port and an (optional) container
* which is an Instantiation that may refer to a bank of reactors.
* The width will be the product of the bank width and the port width.
* The returned value will be 1 if the port is not in a bank and is not a multiport.
*
* If the width cannot be determined, this will return -1.
* The width cannot be determined if the list of instantiations is
* missing or incomplete.
*
* The instantiations list is as in
* {@link #initialValue(Parameter, List)}.
* The first element on this list should be the instantiation
* that contains the specified connection.
*
* @param reference A port reference.
* @param connection A connection, or null if not in the context of a connection.
* @param instantiations The (optional) list of instantiations.
*
* @return The width or -1 if it 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 inferPortWidth(VarRef reference, Connection connection, List<Instantiation> instantiations) {
if (reference.getVariable() instanceof Port) {
// If the port is given as a.b, then we want to prepend a to
// the list of instantiations to determine the width of this port.
List<Instantiation> extended = instantiations;
if (reference.getContainer() != null) {
extended = new ArrayList<>();
extended.add(reference.getContainer());
if (instantiations != null) {
extended.addAll(instantiations);
}
}
int portWidth = width(((Port) reference.getVariable()).getWidthSpec(), extended);
if (portWidth < 0) {
// Could not determine port width.
return -1;
}
// Next determine the bank width. This may be unspecified, in which
// case it has to be inferred using the connection.
int bankWidth = 1;
if (reference.getContainer() != null) {
bankWidth = width(reference.getContainer().getWidthSpec(), instantiations);
if (bankWidth < 0 && connection != null) {
// Try to infer the bank width from the connection.
if (reference.getContainer().getWidthSpec().isOfVariableLength()) {
// This occurs for a bank of delays.
int leftWidth = 0;
int rightWidth = 0;
int leftOrRight = 0;
for (VarRef leftPort : connection.getLeftPorts()) {
if (leftPort == reference) {
if (leftOrRight != 0) {
throw new InvalidSourceException("Multiple ports with variable width on a connection.");
}
// Indicate that this port is on the left.
leftOrRight = -1;
} else {
// The left port is not the same as this reference.
int otherWidth = inferPortWidth(leftPort, connection, instantiations);
if (otherWidth < 0) {
// Cannot determine width.
return -1;
}
leftWidth += otherWidth;
}
}
for (VarRef rightPort : connection.getRightPorts()) {
if (rightPort == reference) {
if (leftOrRight != 0) {
throw new InvalidSourceException("Multiple ports with variable width on a connection.");
}
// Indicate that this port is on the right.
leftOrRight = 1;
} else {
int otherWidth = inferPortWidth(rightPort, connection, instantiations);
if (otherWidth < 0) {
// Cannot determine width.
return -1;
}
rightWidth += otherWidth;
}
}
int discrepancy = 0;
if (leftOrRight < 0) {
// This port is on the left.
discrepancy = rightWidth - leftWidth;
} else if (leftOrRight > 0) {
// This port is on the right.
discrepancy = leftWidth - rightWidth;
}
// Check that portWidth divides the discrepancy.
if (discrepancy % portWidth != 0) {
// This is an error.
return -1;
}
bankWidth = discrepancy / portWidth;
} else {
// Could not determine the bank width.
return -1;
}
}
}
return portWidth * bankWidth;
}
// Argument is not a port.
return -1;
}
use of org.lflang.lf.Instantiation in project lingua-franca by lf-lang.
the class ModelInfo method detectOverflow.
/**
* Given a parameter that is used in a deadline specification, recursively
* track down its definition and check whether it is overflowing. Also
* detect and report overrides that are overflowing.
*/
private boolean detectOverflow(Set<Instantiation> visited, Parameter current) {
var overflow = false;
// Determine whether the parameter's default value overflows or not.
if (isTooLarge(ASTUtils.getDefaultAsTimeValue(current))) {
this.overflowingParameters.add(current);
overflow = true;
}
// Iterate over the instantiations of the reactor in which the
// current parameter was found.
Set<Instantiation> instantiations = this.instantiationGraph.getInstantiations((Reactor) current.eContainer());
for (var instantiation : instantiations) {
// Only visit each instantiation once per deadline to avoid cycles.
if (!visited.contains(instantiation)) {
visited.add(instantiation);
// Find assignments that override the current parameter.
for (var assignment : instantiation.getParameters()) {
if (assignment.getLhs().equals(current)) {
Expression expr = assignment.getRhs().get(0);
if (expr instanceof ParameterReference) {
// Check for overflow in the referenced parameter.
overflow = detectOverflow(visited, ((ParameterReference) expr).getParameter()) || overflow;
} else {
// constant; check whether it is too large.
if (isTooLarge(ASTUtils.getLiteralTimeValue(assignment.getRhs().get(0)))) {
this.overflowingAssignments.add(assignment);
overflow = true;
}
}
}
}
}
}
return overflow;
}
use of org.lflang.lf.Instantiation in project lingua-franca by lf-lang.
the class ASTUtils method hasMultipleConnections.
/**
* Return true if the connection involves multiple ports on the left or right side of the connection, or
* if the port on the left or right of the connection involves a bank of reactors or a multiport.
* @param connection The connection.
*/
public static boolean hasMultipleConnections(Connection connection) {
if (connection.getLeftPorts().size() > 1 || connection.getRightPorts().size() > 1) {
return true;
}
VarRef leftPort = connection.getLeftPorts().get(0);
VarRef rightPort = connection.getRightPorts().get(0);
Instantiation leftContainer = leftPort.getContainer();
Instantiation rightContainer = rightPort.getContainer();
Port leftPortAsPort = (Port) leftPort.getVariable();
Port rightPortAsPort = (Port) rightPort.getVariable();
return leftPortAsPort.getWidthSpec() != null || leftContainer != null && leftContainer.getWidthSpec() != null || rightPortAsPort.getWidthSpec() != null || rightContainer != null && rightContainer.getWidthSpec() != null;
}
use of org.lflang.lf.Instantiation in project lingua-franca by lf-lang.
the class LFValidator method isUnused.
/**
* Report whether a given imported reactor is used in this resource or not.
* @param reactor The imported reactor to check whether it is used.
*/
private boolean isUnused(ImportedReactor reactor) {
TreeIterator<EObject> instantiations = reactor.eResource().getAllContents();
TreeIterator<EObject> subclasses = reactor.eResource().getAllContents();
boolean instantiationsCheck = true;
while (instantiations.hasNext() && instantiationsCheck) {
EObject obj = instantiations.next();
if (!(obj instanceof Instantiation)) {
continue;
}
Instantiation inst = (Instantiation) obj;
instantiationsCheck &= (inst.getReactorClass() != reactor && inst.getReactorClass() != reactor.getReactorClass());
}
boolean subclassesCheck = true;
while (subclasses.hasNext() && subclassesCheck) {
EObject obj = subclasses.next();
if (!(obj instanceof Reactor)) {
continue;
}
Reactor subclass = (Reactor) obj;
for (ReactorDecl decl : subclass.getSuperClasses()) {
subclassesCheck &= (decl != reactor && decl != reactor.getReactorClass());
}
}
return instantiationsCheck && subclassesCheck;
}
Aggregations