Search in sources :

Example 6 with Instantiation

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);
}
Also used : Variable(org.lflang.lf.Variable) SupportedSerializers(org.lflang.federated.serialization.SupportedSerializers) LfFactory(org.lflang.lf.LfFactory) Action(org.lflang.lf.Action) ArrayList(java.util.ArrayList) InferredType(org.lflang.InferredType) Expression(org.lflang.lf.Expression) Instantiation(org.lflang.lf.Instantiation) Reaction(org.lflang.lf.Reaction) LinkedList(java.util.LinkedList) TimeValue(org.lflang.TimeValue) Connection(org.lflang.lf.Connection) Type(org.lflang.lf.Type) GeneratorBase(org.lflang.generator.GeneratorBase) CoordinationType(org.lflang.TargetProperty.CoordinationType) EcoreUtil(org.eclipse.emf.ecore.util.EcoreUtil) PortInstance(org.lflang.generator.PortInstance) ParameterReference(org.lflang.lf.ParameterReference) Collectors(java.util.stream.Collectors) Objects(java.util.Objects) List(java.util.List) Reactor(org.lflang.lf.Reactor) ActionOrigin(org.lflang.lf.ActionOrigin) Optional(java.util.Optional) VarRef(org.lflang.lf.VarRef) Collections(java.util.Collections) ASTUtils(org.lflang.ASTUtils) VarRef(org.lflang.lf.VarRef) ASTUtils(org.lflang.ASTUtils) ParameterReference(org.lflang.lf.ParameterReference) Connection(org.lflang.lf.Connection) ArrayList(java.util.ArrayList) Reaction(org.lflang.lf.Reaction) LinkedList(java.util.LinkedList) Expression(org.lflang.lf.Expression) Instantiation(org.lflang.lf.Instantiation) Reactor(org.lflang.lf.Reactor) TimeValue(org.lflang.TimeValue)

Example 7 with Instantiation

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;
}
Also used : VarRef(org.lflang.lf.VarRef) InvalidSourceException(org.lflang.generator.InvalidSourceException) Port(org.lflang.lf.Port) Instantiation(org.lflang.lf.Instantiation)

Example 8 with Instantiation

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;
}
Also used : Expression(org.lflang.lf.Expression) ParameterReference(org.lflang.lf.ParameterReference) Instantiation(org.lflang.lf.Instantiation)

Example 9 with Instantiation

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;
}
Also used : VarRef(org.lflang.lf.VarRef) Port(org.lflang.lf.Port) Instantiation(org.lflang.lf.Instantiation)

Example 10 with Instantiation

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;
}
Also used : EObject(org.eclipse.emf.ecore.EObject) Instantiation(org.lflang.lf.Instantiation) ImportedReactor(org.lflang.lf.ImportedReactor) Reactor(org.lflang.lf.Reactor) ReactorDecl(org.lflang.lf.ReactorDecl)

Aggregations

Instantiation (org.lflang.lf.Instantiation)21 Reactor (org.lflang.lf.Reactor)12 VarRef (org.lflang.lf.VarRef)10 ArrayList (java.util.ArrayList)8 List (java.util.List)7 Expression (org.lflang.lf.Expression)7 Port (org.lflang.lf.Port)7 Action (org.lflang.lf.Action)6 Collectors (java.util.stream.Collectors)5 EObject (org.eclipse.emf.ecore.EObject)5 Assignment (org.lflang.lf.Assignment)5 Connection (org.lflang.lf.Connection)5 Input (org.lflang.lf.Input)5 Parameter (org.lflang.lf.Parameter)5 ParameterReference (org.lflang.lf.ParameterReference)5 Time (org.lflang.lf.Time)5 LinkedHashMap (java.util.LinkedHashMap)4 LinkedHashSet (java.util.LinkedHashSet)4 ASTUtils (org.lflang.ASTUtils)4 TimeValue (org.lflang.TimeValue)4