Search in sources :

Example 1 with Instantiation

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

the class GeneratorBase method analyzeFederates.

/**
 * Analyze the AST to determine whether code is being mapped to
 * single or to multiple target machines. If it is being mapped
 * to multiple machines, then set the {@link #isFederated} field to true,
 * create a FederateInstance for each federate, and record various
 * properties of the federation
 *
 * In addition, for each top-level connection, add top-level reactions to the AST
 * that send and receive messages over the network.
 *
 * This class is target independent, so the target code
 * generator still has quite a bit of work to do.
 * It needs to provide the body of the sending and
 * receiving reactions. It also needs to provide the
 * runtime infrastructure that uses the dependency
 * information between federates. See the C target
 * for a reference implementation.
 */
private void analyzeFederates(LFGeneratorContext context) {
    // Next, if there actually are federates, analyze the topology
    // interconnecting them and replace the connections between them
    // with an action and two reactions.
    Reactor mainReactor = mainDef != null ? ASTUtils.toDefinition(mainDef.getReactorClass()) : null;
    if (mainDef == null || !mainReactor.isFederated()) {
        // The program is not federated.
        // Ensure federates is never empty.
        FederateInstance federateInstance = new FederateInstance(null, 0, 0, this, errorReporter);
        federates.add(federateInstance);
        federateByID.put(0, federateInstance);
    } else {
        // The Lingua Franca program is federated
        isFederated = true;
        // If the "--rti" flag is given to the compiler, use the argument from the flag.
        if (context.getArgs().containsKey("rti")) {
            setFederationRTIProperties(context);
        } else if (mainReactor.getHost() != null) {
            // If not specified, this defaults to 'localhost'
            if (mainReactor.getHost().getAddr() != null) {
                federationRTIProperties.put("host", mainReactor.getHost().getAddr());
            }
            // If not specified, this defaults to 14045
            if (mainReactor.getHost().getPort() != 0) {
                federationRTIProperties.put("port", mainReactor.getHost().getPort());
            }
            // Get the user information, if specified.
            if (mainReactor.getHost().getUser() != null) {
                federationRTIProperties.put("user", mainReactor.getHost().getUser());
            }
        }
        // Since federates are always within the main (federated) reactor,
        // create a list containing just that one containing instantiation.
        // This will be used to look up parameter values.
        List<Instantiation> mainReactorContext = new ArrayList<>();
        mainReactorContext.add(mainDef);
        // Create a FederateInstance for each top-level reactor.
        for (Instantiation instantiation : ASTUtils.allInstantiations(mainReactor)) {
            int bankWidth = ASTUtils.width(instantiation.getWidthSpec(), mainReactorContext);
            if (bankWidth < 0) {
                errorReporter.reportError(instantiation, "Cannot determine bank width! Assuming width of 1.");
                // Continue with a bank width of 1.
                bankWidth = 1;
            }
            // Create one federate instance for each instance in a bank of reactors.
            List<FederateInstance> federateInstances = new ArrayList<>(bankWidth);
            for (int i = 0; i < bankWidth; i++) {
                // Assign an integer ID to the federate.
                int federateID = federates.size();
                FederateInstance federateInstance = new FederateInstance(instantiation, federateID, i, this, errorReporter);
                federateInstance.bankIndex = i;
                federates.add(federateInstance);
                federateInstances.add(federateInstance);
                federateByID.put(federateID, federateInstance);
                if (instantiation.getHost() != null) {
                    federateInstance.host = instantiation.getHost().getAddr();
                    // The following could be 0.
                    federateInstance.port = instantiation.getHost().getPort();
                    // The following could be null.
                    federateInstance.user = instantiation.getHost().getUser();
                    /* FIXME: The at keyword should support a directory component.
                         * federateInstance.dir = instantiation.getHost().dir
                         */
                    if (federateInstance.host != null && federateInstance.host != "localhost" && federateInstance.host != "0.0.0.0") {
                        federateInstance.isRemote = true;
                    }
                }
            }
            if (federatesByInstantiation == null) {
                federatesByInstantiation = new LinkedHashMap<Instantiation, List<FederateInstance>>();
            }
            federatesByInstantiation.put(instantiation, federateInstances);
        }
        // In a federated execution, we need keepalive to be true,
        // otherwise a federate could exit simply because it hasn't received
        // any messages.
        targetConfig.keepalive = true;
        // Analyze the connection topology of federates.
        // First, find all the connections between federates.
        // For each connection between federates, replace it in the
        // AST with an action (which inherits the delay) and two reactions.
        // The action will be physical for physical connections and logical
        // for logical connections.
        replaceFederateConnectionsWithActions();
        // Remove the connections at the top level
        mainReactor.getConnections().clear();
    }
}
Also used : FederateInstance(org.lflang.federated.FederateInstance) ArrayList(java.util.ArrayList) List(java.util.List) ArrayList(java.util.ArrayList) Reactor(org.lflang.lf.Reactor) Instantiation(org.lflang.lf.Instantiation)

Example 2 with Instantiation

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

the class GeneratorBase method doGenerate.

/**
 * Generate code from the Lingua Franca model contained by the specified resource.
 *
 * This is the main entry point for code generation. This base class finds all
 * reactor class definitions, including any reactors defined in imported .lf files
 * (except any main reactors in those imported files), and adds them to the
 * {@link #GeneratorBase.reactors reactors} list. If errors occur during
 * generation, then a subsequent call to errorsOccurred() will return true.
 * @param resource The resource containing the source code.
 * @param context Context relating to invocation of the code generator.
 * In stand alone mode, this object is also used to relay CLI arguments.
 */
public void doGenerate(Resource resource, LFGeneratorContext context) {
    GeneratorUtils.setTargetConfig(context, GeneratorUtils.findTarget(fileConfig.resource), targetConfig, errorReporter);
    cleanIfNeeded(context);
    printInfo(context.getMode());
    // Markers mark problems in the Eclipse IDE when running in integrated mode.
    if (errorReporter instanceof EclipseErrorReporter) {
        ((EclipseErrorReporter) errorReporter).clearMarkers();
    }
    ASTUtils.setMainName(fileConfig.resource, fileConfig.name);
    createMainInstantiation();
    // Check if there are any conflicting main reactors elsewhere in the package.
    if (Objects.equal(context.getMode(), LFGeneratorContext.Mode.STANDALONE) && mainDef != null) {
        for (String conflict : new MainConflictChecker(fileConfig).conflicts) {
            errorReporter.reportError(this.mainDef.getReactorClass(), "Conflicting main reactor in " + conflict);
        }
    }
    // Configure the command factory
    commandFactory.setVerbose();
    if (Objects.equal(context.getMode(), LFGeneratorContext.Mode.STANDALONE) && context.getArgs().containsKey("quiet")) {
        commandFactory.setQuiet();
    }
    // This must be done before desugaring delays below.
    analyzeFederates(context);
    // Process target files. Copy each of them into the src-gen dir.
    // FIXME: Should we do this here? This doesn't make sense for federates the way it is
    // done here.
    copyUserFiles(this.targetConfig, this.fileConfig);
    // Collect reactors and create an instantiation graph.
    // These are needed to figure out which resources we need
    // to validate, which happens in setResources().
    setReactorsAndInstantiationGraph(context.getMode());
    GeneratorUtils.validate(context, fileConfig, instantiationGraph, errorReporter);
    List<Resource> allResources = GeneratorUtils.getResources(reactors);
    resources.addAll(// FIXME: This filter reproduces the behavior of the method it replaces. But why must it be so complicated? Why are we worried about weird corner cases like this?
    allResources.stream().filter(it -> !Objects.equal(it, fileConfig.resource) || mainDef != null && it == mainDef.getReactorClass().eResource()).map(it -> GeneratorUtils.getLFResource(it, fileConfig.getSrcGenBasePath(), context, errorReporter)).collect(Collectors.toList()));
    GeneratorUtils.accommodatePhysicalActionsIfPresent(allResources, getTarget().setsKeepAliveOptionAutomatically(), targetConfig, errorReporter);
    // FIXME: Should the GeneratorBase pull in `files` from imported
    // resources?
    // Reroute connections that have delays associated with them via
    // generated delay reactors.
    transformDelays();
    // Transform connections that reside in mutually exclusive modes and are otherwise conflicting
    // This should be done before creating the instantiation graph
    transformConflictingConnectionsInModalReactors();
    // Invoke these functions a second time because transformations
    // may have introduced new reactors!
    setReactorsAndInstantiationGraph(context.getMode());
    // Check for existence and support of modes
    hasModalReactors = IterableExtensions.exists(reactors, it -> !it.getModes().isEmpty());
    checkModalReactorSupport(false);
    enableSupportForSerializationIfApplicable(context.getCancelIndicator());
}
Also used : SupportedSerializers(org.lflang.federated.serialization.SupportedSerializers) Delay(org.lflang.lf.Delay) FedASTUtils(org.lflang.federated.FedASTUtils) Action(org.lflang.lf.Action) InferredType(org.lflang.InferredType) Matcher(java.util.regex.Matcher) Map(java.util.Map) Instantiation(org.lflang.lf.Instantiation) Objects(com.google.common.base.Objects) Path(java.nio.file.Path) Connection(org.lflang.lf.Connection) MainConflictChecker(org.lflang.MainConflictChecker) TargetConfig(org.lflang.TargetConfig) Collection(java.util.Collection) Set(java.util.Set) EObject(org.eclipse.emf.ecore.EObject) Collectors(java.util.stream.Collectors) Parameter(org.lflang.lf.Parameter) List(java.util.List) Value(org.lflang.lf.Value) CollectionLiterals(org.eclipse.xtext.xbase.lib.CollectionLiterals) Target(org.lflang.Target) Resource(org.eclipse.emf.ecore.resource.Resource) Pattern(java.util.regex.Pattern) Pair(org.eclipse.xtext.xbase.lib.Pair) FileConfig(org.lflang.FileConfig) ASTUtils(org.lflang.ASTUtils) FederateInstance(org.lflang.federated.FederateInstance) Iterables(com.google.common.collect.Iterables) LfFactory(org.lflang.lf.LfFactory) ErrorReporter(org.lflang.ErrorReporter) AbstractLFValidator(org.lflang.validation.AbstractLFValidator) ArrayList(java.util.ArrayList) HashSet(java.util.HashSet) LinkedHashMap(java.util.LinkedHashMap) CancelIndicator(org.eclipse.xtext.util.CancelIndicator) Reaction(org.lflang.lf.Reaction) TimeUnit(org.lflang.TimeUnit) TimeValue(org.lflang.TimeValue) LinkedHashSet(java.util.LinkedHashSet) IMarker(org.eclipse.core.resources.IMarker) InstantiationGraph(org.lflang.graph.InstantiationGraph) CoordinationType(org.lflang.TargetProperty.CoordinationType) Model(org.lflang.lf.Model) IOException(java.io.IOException) Time(org.lflang.lf.Time) File(java.io.File) IteratorExtensions(org.eclipse.xtext.xbase.lib.IteratorExtensions) IterableExtensions(org.eclipse.xtext.xbase.lib.IterableExtensions) Paths(java.nio.file.Paths) Reactor(org.lflang.lf.Reactor) VarRef(org.lflang.lf.VarRef) MainConflictChecker(org.lflang.MainConflictChecker) Resource(org.eclipse.emf.ecore.resource.Resource)

Example 3 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<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);
}
Also used : Variable(org.lflang.lf.Variable) SupportedSerializers(org.lflang.federated.serialization.SupportedSerializers) Delay(org.lflang.lf.Delay) LfFactory(org.lflang.lf.LfFactory) Action(org.lflang.lf.Action) ArrayList(java.util.ArrayList) InferredType(org.lflang.InferredType) 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) Collectors(java.util.stream.Collectors) Objects(java.util.Objects) Parameter(org.lflang.lf.Parameter) List(java.util.List) Value(org.lflang.lf.Value) 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) Connection(org.lflang.lf.Connection) ArrayList(java.util.ArrayList) Reaction(org.lflang.lf.Reaction) LinkedList(java.util.LinkedList) TimeValue(org.lflang.TimeValue) Value(org.lflang.lf.Value) Parameter(org.lflang.lf.Parameter) Instantiation(org.lflang.lf.Instantiation) Reactor(org.lflang.lf.Reactor) TimeValue(org.lflang.TimeValue)

Example 4 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)) {
                    Parameter parameter = assignment.getRhs().get(0).getParameter();
                    if (parameter != null) {
                        // Check for overflow in the referenced parameter.
                        overflow = detectOverflow(visited, parameter) || 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 : Parameter(org.lflang.lf.Parameter) Instantiation(org.lflang.lf.Instantiation)

Example 5 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<Instantiation>}.
 * 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)

Aggregations

Instantiation (org.lflang.lf.Instantiation)19 Reactor (org.lflang.lf.Reactor)12 VarRef (org.lflang.lf.VarRef)10 ArrayList (java.util.ArrayList)7 Value (org.lflang.lf.Value)7 List (java.util.List)6 Action (org.lflang.lf.Action)6 Delay (org.lflang.lf.Delay)6 Parameter (org.lflang.lf.Parameter)6 Port (org.lflang.lf.Port)6 EObject (org.eclipse.emf.ecore.EObject)5 Connection (org.lflang.lf.Connection)5 LinkedHashMap (java.util.LinkedHashMap)4 LinkedHashSet (java.util.LinkedHashSet)4 InvalidSourceException (org.lflang.generator.InvalidSourceException)4 Assignment (org.lflang.lf.Assignment)4 Model (org.lflang.lf.Model)4 Time (org.lflang.lf.Time)4 Iterables (com.google.common.collect.Iterables)3 Collection (java.util.Collection)3