Search in sources :

Example 1 with Port

use of org.lflang.lf.Port 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)

Example 2 with Port

use of org.lflang.lf.Port 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();
    if (leftPortAsPort.getWidthSpec() != null || (leftContainer != null && leftContainer.getWidthSpec() != null) || rightPortAsPort.getWidthSpec() != null || (rightContainer != null && rightContainer.getWidthSpec() != null)) {
        return true;
    }
    return false;
}
Also used : VarRef(org.lflang.lf.VarRef) Port(org.lflang.lf.Port) Instantiation(org.lflang.lf.Instantiation)

Example 3 with Port

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

the class ASTUtils method findConflictingConnectionsInModalReactors.

/**
 * Find connections in the given resource that would be conflicting writes if they were not located in mutually
 * exclusive modes.
 *
 * @param resource The AST.
 * @return a list of connections being able to be transformed
 */
public static Collection<Connection> findConflictingConnectionsInModalReactors(Resource resource) {
    var transform = new HashSet<Connection>();
    var reactors = Iterables.filter(IteratorExtensions.toIterable(resource.getAllContents()), Reactor.class);
    for (Reactor reactor : reactors) {
        if (!reactor.getModes().isEmpty()) {
            // Only for modal reactors
            var allWriters = HashMultimap.<Pair<Instantiation, Variable>, EObject>create();
            // Collect destinations
            for (var rea : allReactions(reactor)) {
                for (var eff : rea.getEffects()) {
                    if (eff.getVariable() instanceof Port) {
                        allWriters.put(Tuples.pair(eff.getContainer(), eff.getVariable()), rea);
                    }
                }
            }
            for (var con : ASTUtils.<Connection>collectElements(reactor, featurePackage.getReactor_Connections(), false, true)) {
                for (var port : con.getRightPorts()) {
                    allWriters.put(Tuples.pair(port.getContainer(), port.getVariable()), con);
                }
            }
            // Handle conflicting writers
            for (var key : allWriters.keySet()) {
                var writers = allWriters.get(key);
                if (writers.size() > 1) {
                    // has multiple sources
                    var writerModes = HashMultimap.<Mode, EObject>create();
                    // find modes
                    for (var writer : writers) {
                        if (writer.eContainer() instanceof Mode) {
                            writerModes.put((Mode) writer.eContainer(), writer);
                        } else {
                            writerModes.put(null, writer);
                        }
                    }
                    // Conflicting connection can only be handled if..
                    if (// no writer is on root level (outside of modes) and...
                    !writerModes.containsKey(null) && writerModes.keySet().stream().map(m -> writerModes.get(m)).allMatch(// all writers in a mode are either...
                    writersInMode -> // the only writer or...
                    writersInMode.size() == 1 || // all are reactions and hence ordered
                    writersInMode.stream().allMatch(w -> w instanceof Reaction))) {
                        // Add connections to transform list
                        writers.stream().filter(w -> w instanceof Connection).forEach(c -> transform.add((Connection) c));
                    }
                }
            }
        }
    }
    return transform;
}
Also used : Code(org.lflang.lf.Code) LfPackage(org.lflang.lf.LfPackage) Delay(org.lflang.lf.Delay) WidthSpec(org.lflang.lf.WidthSpec) EStructuralFeature(org.eclipse.emf.ecore.EStructuralFeature) Action(org.lflang.lf.Action) Input(org.lflang.lf.Input) ILeafNode(org.eclipse.xtext.nodemodel.ILeafNode) StateVar(org.lflang.lf.StateVar) Matcher(java.util.regex.Matcher) HashMultimap(com.google.common.collect.HashMultimap) Port(org.lflang.lf.Port) Map(java.util.Map) Instantiation(org.lflang.lf.Instantiation) INode(org.eclipse.xtext.nodemodel.INode) Connection(org.lflang.lf.Connection) GeneratorBase(org.lflang.generator.GeneratorBase) Element(org.lflang.lf.Element) TypeParm(org.lflang.lf.TypeParm) Collection(java.util.Collection) CompositeNode(org.eclipse.xtext.nodemodel.impl.CompositeNode) Set(java.util.Set) InvalidSourceException(org.lflang.generator.InvalidSourceException) EObject(org.eclipse.emf.ecore.EObject) ICompositeNode(org.eclipse.xtext.nodemodel.ICompositeNode) ArraySpec(org.lflang.lf.ArraySpec) Mode(org.lflang.lf.Mode) Parameter(org.lflang.lf.Parameter) List(java.util.List) Value(org.lflang.lf.Value) CodeMap(org.lflang.generator.CodeMap) WidthTerm(org.lflang.lf.WidthTerm) Assignment(org.lflang.lf.Assignment) Resource(org.eclipse.emf.ecore.resource.Resource) ActionOrigin(org.lflang.lf.ActionOrigin) Pattern(java.util.regex.Pattern) StringExtensions(org.eclipse.xtext.xbase.lib.StringExtensions) Output(org.lflang.lf.Output) Variable(org.lflang.lf.Variable) Iterables(com.google.common.collect.Iterables) LfFactory(org.lflang.lf.LfFactory) NodeModelUtils(org.eclipse.xtext.nodemodel.util.NodeModelUtils) ImportedReactor(org.lflang.lf.ImportedReactor) Iterators(com.google.common.collect.Iterators) ArrayList(java.util.ArrayList) HashSet(java.util.HashSet) LinkedHashMap(java.util.LinkedHashMap) Pair(org.eclipse.xtext.util.Pair) TargetDecl(org.lflang.lf.TargetDecl) StringUtil(org.lflang.util.StringUtil) Reaction(org.lflang.lf.Reaction) KeyValuePair(org.lflang.lf.KeyValuePair) Type(org.lflang.lf.Type) LinkedHashSet(java.util.LinkedHashSet) Tuples(org.eclipse.xtext.util.Tuples) XtextResource(org.eclipse.xtext.resource.XtextResource) HiddenLeafNode(org.eclipse.xtext.nodemodel.impl.HiddenLeafNode) Model(org.lflang.lf.Model) ReactorDecl(org.lflang.lf.ReactorDecl) EcoreUtil(org.eclipse.emf.ecore.util.EcoreUtil) Time(org.lflang.lf.Time) EList(org.eclipse.emf.common.util.EList) IteratorExtensions(org.eclipse.xtext.xbase.lib.IteratorExtensions) IterableExtensions(org.eclipse.xtext.xbase.lib.IterableExtensions) TerminalRule(org.eclipse.xtext.TerminalRule) Reactor(org.lflang.lf.Reactor) VarRef(org.lflang.lf.VarRef) Timer(org.lflang.lf.Timer) EObject(org.eclipse.emf.ecore.EObject) Port(org.lflang.lf.Port) Mode(org.lflang.lf.Mode) Connection(org.lflang.lf.Connection) ImportedReactor(org.lflang.lf.ImportedReactor) Reactor(org.lflang.lf.Reactor) Reaction(org.lflang.lf.Reaction) HashSet(java.util.HashSet) LinkedHashSet(java.util.LinkedHashSet) Pair(org.eclipse.xtext.util.Pair) KeyValuePair(org.lflang.lf.KeyValuePair)

Example 4 with Port

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

the class PythonReactionGenerator method generatePythonReactionParametersAndInitializations.

/**
 * Generate parameters and their respective initialization code for a reaction function
 * The initialization code is put at the beginning of the reaction before user code
 * @param parameters The parameters used for function definition
 * @param inits The initialization code for those paramters
 * @param decl Reactor declaration
 * @param reaction The reaction to be used to generate parameters for
 */
public static void generatePythonReactionParametersAndInitializations(List<String> parameters, CodeBuilder inits, ReactorDecl decl, Reaction reaction) {
    Reactor reactor = ASTUtils.toDefinition(decl);
    LinkedHashSet<String> generatedParams = new LinkedHashSet<>();
    // Handle triggers
    for (TriggerRef trigger : ASTUtils.convertToEmptyListIfNull(reaction.getTriggers())) {
        if (!(trigger instanceof VarRef)) {
            continue;
        }
        VarRef triggerAsVarRef = (VarRef) trigger;
        if (triggerAsVarRef.getVariable() instanceof Port) {
            if (triggerAsVarRef.getVariable() instanceof Input) {
                if (((Input) triggerAsVarRef.getVariable()).isMutable()) {
                    generatedParams.add("mutable_" + triggerAsVarRef.getVariable().getName() + "");
                    // Create a deep copy
                    if (ASTUtils.isMultiport((Input) triggerAsVarRef.getVariable())) {
                        inits.pr(triggerAsVarRef.getVariable().getName() + " = [Make() for i in range(len(mutable_" + triggerAsVarRef.getVariable().getName() + "))]");
                        inits.pr("for i in range(len(mutable_" + triggerAsVarRef.getVariable().getName() + ")):");
                        inits.pr("    " + triggerAsVarRef.getVariable().getName() + "[i].value = copy.deepcopy(mutable_" + triggerAsVarRef.getVariable().getName() + "[i].value)");
                    } else {
                        inits.pr(triggerAsVarRef.getVariable().getName() + " = Make()");
                        inits.pr(triggerAsVarRef.getVariable().getName() + ".value = copy.deepcopy(mutable_" + triggerAsVarRef.getVariable().getName() + ".value)");
                    }
                } else {
                    generatedParams.add(triggerAsVarRef.getVariable().getName());
                }
            } else {
                // Handle contained reactors' ports
                generatedParams.add(triggerAsVarRef.getContainer().getName() + "_" + triggerAsVarRef.getVariable().getName());
                inits.pr(PythonPortGenerator.generatePythonPortVariableInReaction(triggerAsVarRef));
            }
        } else if (triggerAsVarRef.getVariable() instanceof Action) {
            generatedParams.add(triggerAsVarRef.getVariable().getName());
        }
    }
    // Handle non-triggering inputs
    if (reaction.getTriggers() == null || reaction.getTriggers().size() == 0) {
        for (Input input : ASTUtils.convertToEmptyListIfNull(reactor.getInputs())) {
            generatedParams.add(input.getName());
            if (input.isMutable()) {
                // Create a deep copy
                inits.pr(input.getName() + " = copy.deepcopy(" + input.getName() + ")");
            }
        }
    }
    for (VarRef src : ASTUtils.convertToEmptyListIfNull(reaction.getSources())) {
        if (src.getVariable() instanceof Output) {
            // Output of a contained reactor
            generatedParams.add(src.getContainer().getName() + "_" + src.getVariable().getName());
            inits.pr(PythonPortGenerator.generatePythonPortVariableInReaction(src));
        } else {
            generatedParams.add(src.getVariable().getName());
            if (src.getVariable() instanceof Input) {
                if (((Input) src.getVariable()).isMutable()) {
                    // Create a deep copy
                    inits.pr(src.getVariable().getName() + " = copy.deepcopy(" + src.getVariable().getName() + ")");
                }
            }
        }
    }
    // Handle effects
    for (VarRef effect : ASTUtils.convertToEmptyListIfNull(reaction.getEffects())) {
        if (effect.getVariable() instanceof Input) {
            generatedParams.add(effect.getContainer().getName() + "_" + effect.getVariable().getName());
            inits.pr(PythonPortGenerator.generatePythonPortVariableInReaction(effect));
        } else {
            generatedParams.add(effect.getVariable().getName());
            if (effect.getVariable() instanceof Port) {
                if (ASTUtils.isMultiport((Port) effect.getVariable())) {
                // Handle multiports
                }
            }
        }
    }
    for (String s : generatedParams) {
        parameters.add(s);
    }
}
Also used : LinkedHashSet(java.util.LinkedHashSet) VarRef(org.lflang.lf.VarRef) Input(org.lflang.lf.Input) Action(org.lflang.lf.Action) Port(org.lflang.lf.Port) Output(org.lflang.lf.Output) Reactor(org.lflang.lf.Reactor) TriggerRef(org.lflang.lf.TriggerRef)

Example 5 with Port

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

the class ReactorInstance method listPortInstances.

/**
 * Given a list of port references, as found on either side of a connection,
 * return a list of the port instance ranges referenced. These may be multiports,
 * and may be ports of a contained bank (a port representing ports of the bank
 * members) so the returned list includes ranges of banks and channels.
 *
 * If a given port reference has the form `interleaved(b.m)`, where `b` is
 * a bank and `m` is a multiport, then the corresponding range in the returned
 * list is marked interleaved.
 *
 * For example, if `b` and `m` have width 2, without the interleaved keyword,
 * the returned range represents the sequence `[b0.m0, b0.m1, b1.m0, b1.m1]`.
 * With the interleaved marking, the returned range represents the sequence
 * `[b0.m0, b1.m0, b0.m1, b1.m1]`. Both ranges will have width 4.
 *
 * @param references The variable references on one side of the connection.
 * @param connection The connection.
 */
private List<RuntimeRange<PortInstance>> listPortInstances(List<VarRef> references, Connection connection) {
    List<RuntimeRange<PortInstance>> result = new ArrayList<RuntimeRange<PortInstance>>();
    List<RuntimeRange<PortInstance>> tails = new LinkedList<RuntimeRange<PortInstance>>();
    int count = 0;
    for (VarRef portRef : references) {
        // Simple error checking first.
        if (!(portRef.getVariable() instanceof Port)) {
            reporter.reportError(portRef, "Not a port.");
            return result;
        }
        // First, figure out which reactor we are dealing with.
        // The reactor we want is the container of the port.
        // If the port reference has no container, then the reactor is this one.
        var reactor = this;
        if (portRef.getContainer() != null) {
            reactor = getChildReactorInstance(portRef.getContainer());
        }
        // Skip this portRef so that diagram synthesis can complete.
        if (reactor != null) {
            PortInstance portInstance = reactor.lookupPortInstance((Port) portRef.getVariable());
            Set<ReactorInstance> interleaved = new LinkedHashSet<ReactorInstance>();
            if (portRef.isInterleaved()) {
                // NOTE: Here, we are assuming that the interleaved()
                // keyword is only allowed on the multiports contained by
                // contained reactors.
                interleaved.add(portInstance.parent);
            }
            RuntimeRange<PortInstance> range = new RuntimeRange.Port(portInstance, interleaved);
            // in the hierarchy.
            if (count < references.size() - 1) {
                int portWidth = portInstance.width;
                int portParentWidth = portInstance.parent.width;
                int widthBound = portWidth * portParentWidth;
                // If either of these widths cannot be determined, assume infinite.
                if (portWidth < 0)
                    widthBound = Integer.MAX_VALUE;
                if (portParentWidth < 0)
                    widthBound = Integer.MAX_VALUE;
                if (widthBound < range.width) {
                    // Need to split the range.
                    tails.add(range.tail(widthBound));
                    range = range.head(widthBound);
                }
            }
            result.add(range);
        }
    }
    // Iterate over the tails.
    while (tails.size() > 0) {
        List<RuntimeRange<PortInstance>> moreTails = new LinkedList<RuntimeRange<PortInstance>>();
        count = 0;
        for (RuntimeRange<PortInstance> tail : tails) {
            if (count < tails.size() - 1) {
                int widthBound = tail.instance.width;
                if (tail._interleaved.contains(tail.instance.parent)) {
                    widthBound = tail.instance.parent.width;
                }
                // If the width cannot be determined, assume infinite.
                if (widthBound < 0)
                    widthBound = Integer.MAX_VALUE;
                if (widthBound < tail.width) {
                    // Need to split the range again
                    moreTails.add(tail.tail(widthBound));
                    tail = tail.head(widthBound);
                }
            }
            result.add(tail);
        }
        tails = moreTails;
    }
    return result;
}
Also used : VarRef(org.lflang.lf.VarRef) LinkedHashSet(java.util.LinkedHashSet) Port(org.lflang.lf.Port) ArrayList(java.util.ArrayList) LinkedList(java.util.LinkedList)

Aggregations

Port (org.lflang.lf.Port)11 VarRef (org.lflang.lf.VarRef)9 Reactor (org.lflang.lf.Reactor)7 Instantiation (org.lflang.lf.Instantiation)6 LinkedHashSet (java.util.LinkedHashSet)5 Action (org.lflang.lf.Action)5 Input (org.lflang.lf.Input)5 Output (org.lflang.lf.Output)5 ArrayList (java.util.ArrayList)3 LinkedHashMap (java.util.LinkedHashMap)3 Variable (org.lflang.lf.Variable)3 HashMultimap (com.google.common.collect.HashMultimap)2 Iterables (com.google.common.collect.Iterables)2 Iterators (com.google.common.collect.Iterators)2 Collection (java.util.Collection)2 HashSet (java.util.HashSet)2 List (java.util.List)2 Map (java.util.Map)2 Set (java.util.Set)2 Matcher (java.util.regex.Matcher)2