Search in sources :

Example 11 with PortInstance

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

the class CTriggerObjectsGenerator method deferredCreateDefaultTokens.

/**
 * For each output of the specified reactor that has a token type
 * (type* or type[]), create a default token and put it on the self struct.
 * @param parent The reactor.
 */
private static String deferredCreateDefaultTokens(ReactorInstance reactor, CTypes types) {
    var code = new CodeBuilder();
    // Look for outputs with token types.
    for (PortInstance output : reactor.outputs) {
        var type = ASTUtils.getInferredType(output.getDefinition());
        if (CUtil.isTokenType(type, types)) {
            // Create the template token that goes in the trigger struct.
            // Its reference count is zero, enabling it to be used immediately.
            var rootType = CUtil.rootType(types.getTargetType(type));
            // If the rootType is 'void', we need to avoid generating the code
            // 'sizeof(void)', which some compilers reject.
            var size = (rootType.equals("void")) ? "0" : "sizeof(" + rootType + ")";
            code.startChannelIteration(output);
            code.pr(CUtil.portRef(output) + ".token = _lf_create_token(" + size + ");");
            code.endChannelIteration(output);
        }
    }
    return code.toString();
}
Also used : PortInstance(org.lflang.generator.PortInstance) CodeBuilder(org.lflang.generator.CodeBuilder)

Example 12 with PortInstance

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

the class PortInstanceTests method createRange.

@Test
public void createRange() throws Exception {
    Reactor main = factory.createReactor();
    ReactorInstance maini = new ReactorInstance(main, reporter);
    ReactorInstance a = newReactor("A", maini);
    ReactorInstance b = newReactor("B", maini);
    ReactorInstance c = newReactor("C", maini);
    PortInstance p = newOutputPort("p", a);
    PortInstance q = newInputPort("q", b);
    PortInstance r = newInputPort("r", c);
    Assertions.assertEquals(".A.p", p.getFullName());
    connect(p, q);
    connect(p, r);
    List<SendRange> sr = p.eventualDestinations();
    // Destinations should be empty because there are no reactions.
    Assertions.assertEquals("[]", sr.toString());
    // Clear caches to make a mutation.
    maini.clearCaches();
    newReaction(q);
    // Re-retrieve destinations.
    sr = p.eventualDestinations();
    Assertions.assertEquals("[.A.p(0,1)->[.B.q(0,1)]]", sr.toString());
    maini.clearCaches();
    newReaction(r);
    // Re-retrieve destinations.
    sr = p.eventualDestinations();
    Assertions.assertEquals("[.A.p(0,1)->[.B.q(0,1), .C.r(0,1)]]", sr.toString());
    // Now test multiports.
    p.setWidth(3);
    r.setWidth(2);
    // Have to redo the connections.
    clearConnections(maini);
    maini.clearCaches();
    connect(p, 0, 1, q, 0, 1);
    connect(p, 1, 2, r, 0, 2);
    // Re-retrieve destinations.
    sr = p.eventualDestinations();
    Assertions.assertEquals("[.A.p(0,1)->[.B.q(0,1)], .A.p(1,2)->[.C.r(0,2)]]", sr.toString());
    // More complicated multiport connection.
    clearConnections(maini);
    maini.clearCaches();
    ReactorInstance d = newReactor("D", maini);
    PortInstance v = newOutputPort("v", d);
    v.setWidth(2);
    q.setWidth(3);
    connect(v, 0, 2, q, 0, 2);
    connect(p, 0, 1, q, 2, 1);
    connect(p, 1, 2, r, 0, 2);
    sr = p.eventualDestinations();
    Assertions.assertEquals("[.A.p(0,1)->[.B.q(2,1)], .A.p(1,2)->[.C.r(0,2)]]", sr.toString());
    // Additional multicast connection.
    maini.clearCaches();
    ReactorInstance e = newReactor("E", maini);
    PortInstance s = newPort("s", e);
    s.setWidth(3);
    newReaction(s);
    connect(p, s);
    sr = p.eventualDestinations();
    Assertions.assertEquals("[.A.p(0,1)->[.B.q(2,1), .E.s(0,1)], .A.p(1,2)->[.C.r(0,2), .E.s(1,2)]]", sr.toString());
    // Add hierarchical reactors that further split the ranges.
    maini.clearCaches();
    ReactorInstance f = newReactor("F", e);
    PortInstance t = newPort("t", f);
    newReaction(t);
    ReactorInstance g = newReactor("G", e);
    PortInstance u = newPort("u", g);
    u.setWidth(2);
    newReaction(u);
    connect(s, 0, 1, t, 0, 1);
    connect(s, 1, 2, u, 0, 2);
    sr = p.eventualDestinations();
    // FIXME: Multicast destinations should be able to be reported in arbitrary order.
    Assertions.assertEquals("[.A.p(0,1)->[.E.F.t(0,1), .E.s(0,1), .B.q(2,1)], .A.p(1,2)->[.E.G.u(0,2), .E.s(1,2), .C.r(0,2)]]", sr.toString());
}
Also used : PortInstance(org.lflang.generator.PortInstance) ReactorInstance(org.lflang.generator.ReactorInstance) Reactor(org.lflang.lf.Reactor) SendRange(org.lflang.generator.SendRange) Test(org.junit.jupiter.api.Test)

Example 13 with PortInstance

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

the class RangeTests method createRange.

@Test
public void createRange() throws Exception {
    Reactor main = factory.createReactor();
    ReactorInstance maini = new ReactorInstance(main, reporter);
    Reactor a = factory.createReactor();
    a.setName("A");
    ReactorInstance ai = new ReactorInstance(a, maini, reporter);
    ai.setWidth(2);
    Reactor b = factory.createReactor();
    b.setName("B");
    ReactorInstance bi = new ReactorInstance(b, ai, reporter);
    bi.setWidth(2);
    Port p = factory.createPort();
    p.setName("P");
    PortInstance pi = new PortInstance(p, bi, reporter);
    pi.setWidth(2);
    Assertions.assertEquals(".A.B.P", pi.getFullName());
    RuntimeRange<PortInstance> range = new RuntimeRange.Port(pi, 3, 4, null);
    Assertions.assertEquals(8, range.maxWidth);
    Assertions.assertEquals(".A.B.P(3,4)", range.toString());
    // The results expected below are derived from the class comment for RuntimeRange,
    // which includes this example.
    List<Integer> instances = range.instances();
    Assertions.assertEquals(List.of(3, 4, 5, 6), instances);
    Set<Integer> parents = range.parentInstances(1);
    Assertions.assertEquals(Set.of(1, 2, 3), parents);
    parents = range.parentInstances(2);
    Assertions.assertEquals(Set.of(0, 1), parents);
    // Test startMR().getDigits.
    Assertions.assertEquals(List.of(1, 1, 0), range.startMR().getDigits());
    // Create a SendRange sending from and to this range.
    SendRange sendRange = new SendRange(pi, 3, 4, null, null);
    sendRange.destinations.add(range);
    // Test getNumberOfDestinationReactors.
    Assertions.assertEquals(3, sendRange.getNumberOfDestinationReactors());
    // Make first interleaved version.
    range = range.toggleInterleaved(bi);
    instances = range.instances();
    Assertions.assertEquals(List.of(3, 4, 6, 5), instances);
    // Test startMR().getDigits.
    Assertions.assertEquals(List.of(1, 1, 0), range.startMR().getDigits());
    // Make second interleaved version.
    range = range.toggleInterleaved(ai);
    instances = range.instances();
    Assertions.assertEquals(List.of(6, 1, 5, 3), instances);
    // Test startMR().getDigits.
    Assertions.assertEquals(List.of(0, 1, 1), range.startMR().getDigits());
    // Test instances of the parent.
    Assertions.assertEquals(Set.of(3, 0, 2, 1), range.parentInstances(1));
    // Add this range to the sendRange destinations and verify
    // that the number of destination reactors becomes 4.
    sendRange.addDestination(range);
    Assertions.assertEquals(4, sendRange.getNumberOfDestinationReactors());
    // Make third interleaved version.
    range = range.toggleInterleaved(bi);
    instances = range.instances();
    Assertions.assertEquals(List.of(5, 2, 6, 3), instances);
    // Test startMR().getDigits.
    Assertions.assertEquals(List.of(1, 0, 1), range.startMR().getDigits());
}
Also used : PortInstance(org.lflang.generator.PortInstance) ReactorInstance(org.lflang.generator.ReactorInstance) Port(org.lflang.lf.Port) Reactor(org.lflang.lf.Reactor) SendRange(org.lflang.generator.SendRange) Test(org.junit.jupiter.api.Test)

Example 14 with PortInstance

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

the class LinguaFrancaSynthesis method transformReactorNetwork.

private Collection<KNode> transformReactorNetwork(ReactorInstance reactorInstance, Map<PortInstance, KPort> parentInputPorts, Map<PortInstance, KPort> parentOutputPorts, Map<ReactorInstance, KNode> allReactorNodes) {
    List<KNode> nodes = new ArrayList<>();
    Table<ReactorInstance, PortInstance, KPort> inputPorts = HashBasedTable.create();
    Table<ReactorInstance, PortInstance, KPort> outputPorts = HashBasedTable.create();
    Map<ReactionInstance, KNode> reactionNodes = new HashMap<>();
    Map<KPort, KNode> directConnectionDummyNodes = new HashMap<>();
    Multimap<ActionInstance, KPort> actionDestinations = HashMultimap.create();
    Multimap<ActionInstance, KPort> actionSources = HashMultimap.create();
    Map<TimerInstance, KNode> timerNodes = new HashMap<>();
    KNode startupNode = _kNodeExtensions.createNode();
    boolean startupUsed = false;
    KNode shutdownNode = _kNodeExtensions.createNode();
    boolean shutdownUsed = false;
    // Transform instances
    int index = 0;
    for (ReactorInstance child : reactorInstance.children) {
        Boolean expansionState = MemorizingExpandCollapseAction.getExpansionState(child);
        Collection<KNode> rNodes = createReactorNode(child, expansionState != null ? expansionState : false, inputPorts, outputPorts, allReactorNodes);
        nodes.addAll(rNodes);
        index++;
    }
    // Create timers
    for (TimerInstance timer : reactorInstance.timers) {
        KNode node = associateWith(_kNodeExtensions.createNode(), timer.getDefinition());
        NamedInstanceUtil.linkInstance(node, timer);
        _utilityExtensions.setID(node, timer.uniqueID());
        nodes.add(node);
        Iterables.addAll(nodes, createUserComments(timer.getDefinition(), node));
        timerNodes.put(timer, node);
        _linguaFrancaShapeExtensions.addTimerFigure(node, timer);
    }
    // Create reactions
    for (ReactionInstance reaction : reactorInstance.reactions) {
        int idx = reactorInstance.reactions.indexOf(reaction);
        KNode node = associateWith(_kNodeExtensions.createNode(), reaction.getDefinition());
        NamedInstanceUtil.linkInstance(node, reaction);
        _utilityExtensions.setID(node, reaction.uniqueID());
        nodes.add(node);
        Iterables.addAll(nodes, createUserComments(reaction.getDefinition(), node));
        reactionNodes.put(reaction, node);
        setLayoutOption(node, CoreOptions.PORT_CONSTRAINTS, PortConstraints.FIXED_SIDE);
        // try order reactions vertically if in one layer (+1 to account for startup)
        setLayoutOption(node, LayeredOptions.POSITION, new KVector(0, idx + 1));
        var figure = _linguaFrancaShapeExtensions.addReactionFigure(node, reaction);
        int inputSize = Stream.concat(reaction.triggers.stream(), reaction.sources.stream()).collect(Collectors.toSet()).size();
        int outputSize = reaction.effects.size();
        if (!getBooleanValue(REACTIONS_USE_HYPEREDGES) && (inputSize > 1 || outputSize > 1)) {
            // If this node will have more than one input/output port, the port positions must be adjusted to the
            // pointy shape. However, this is only possible after the layout.
            ReactionPortAdjustment.apply(node, figure);
        }
        // connect input
        KPort port = null;
        for (TriggerInstance<?> trigger : reaction.triggers) {
            // Create new port if there is no previous one or each dependency should have its own one
            if (port == null || !getBooleanValue(REACTIONS_USE_HYPEREDGES)) {
                port = addInvisiblePort(node);
                setLayoutOption(port, CoreOptions.PORT_SIDE, PortSide.WEST);
                if (getBooleanValue(REACTIONS_USE_HYPEREDGES) || inputSize == 1) {
                    // manual adjustment disabling automatic one
                    setLayoutOption(port, CoreOptions.PORT_BORDER_OFFSET, (double) -LinguaFrancaShapeExtensions.REACTION_POINTINESS);
                }
            }
            if (trigger.isStartup()) {
                connect(createDependencyEdge(((TriggerInstance.BuiltinTriggerVariable) trigger.getDefinition()).definition), startupNode, port);
                startupUsed = true;
            } else if (trigger.isShutdown()) {
                connect(createDelayEdge(((TriggerInstance.BuiltinTriggerVariable) trigger.getDefinition()).definition), shutdownNode, port);
                shutdownUsed = true;
            } else if (trigger instanceof ActionInstance) {
                actionDestinations.put(((ActionInstance) trigger), port);
            } else if (trigger instanceof PortInstance) {
                KPort src = null;
                PortInstance triggerAsPort = (PortInstance) trigger;
                if (triggerAsPort.getParent() == reactorInstance) {
                    src = parentInputPorts.get(trigger);
                } else {
                    src = outputPorts.get(triggerAsPort.getParent(), trigger);
                }
                if (src != null) {
                    connect(createDependencyEdge(triggerAsPort.getDefinition()), src, port);
                }
            } else if (trigger instanceof TimerInstance) {
                KNode src = timerNodes.get(trigger);
                if (src != null) {
                    connect(createDependencyEdge(trigger.getDefinition()), src, port);
                }
            }
        }
        // connect dependencies
        for (TriggerInstance<?> dep : reaction.sources) {
            // skip
            if (reaction.triggers.contains(dep))
                continue;
            // Create new port if there is no previous one or each dependency should have its own one
            if (port == null || !getBooleanValue(REACTIONS_USE_HYPEREDGES)) {
                port = addInvisiblePort(node);
                setLayoutOption(port, CoreOptions.PORT_SIDE, PortSide.WEST);
                if (getBooleanValue(REACTIONS_USE_HYPEREDGES) || inputSize == 1) {
                    // manual adjustment disabling automatic one
                    setLayoutOption(port, CoreOptions.PORT_BORDER_OFFSET, (double) -LinguaFrancaShapeExtensions.REACTION_POINTINESS);
                }
            }
            if (dep instanceof PortInstance) {
                KPort src = null;
                PortInstance depAsPort = (PortInstance) dep;
                if (dep.getParent() == reactorInstance) {
                    src = parentInputPorts.get(dep);
                } else {
                    src = outputPorts.get(depAsPort.getParent(), dep);
                }
                if (src != null) {
                    connect(createDependencyEdge(dep.getDefinition()), src, port);
                }
            }
        }
        // connect outputs
        // enforce new ports for outputs
        port = null;
        Set<TriggerInstance<?>> iterSet = reaction.effects != null ? reaction.effects : new HashSet<>();
        for (TriggerInstance<?> effect : iterSet) {
            // Create new port if there is no previous one or each dependency should have its own one
            if (port == null || !getBooleanValue(REACTIONS_USE_HYPEREDGES)) {
                port = addInvisiblePort(node);
                setLayoutOption(port, CoreOptions.PORT_SIDE, PortSide.EAST);
            }
            if (effect instanceof ActionInstance) {
                actionSources.put((ActionInstance) effect, port);
            } else if (effect instanceof PortInstance) {
                KPort dst = null;
                PortInstance effectAsPort = (PortInstance) effect;
                if (effectAsPort.isOutput()) {
                    dst = parentOutputPorts.get(effect);
                } else {
                    dst = inputPorts.get(effectAsPort.getParent(), effect);
                }
                if (dst != null) {
                    connect(createDependencyEdge(effect), port, dst);
                }
            }
        }
    }
    // Connect actions
    Set<ActionInstance> actions = new HashSet<>();
    actions.addAll(actionSources.keySet());
    actions.addAll(actionDestinations.keySet());
    for (ActionInstance action : actions) {
        KNode node = associateWith(_kNodeExtensions.createNode(), action.getDefinition());
        NamedInstanceUtil.linkInstance(node, action);
        _utilityExtensions.setID(node, action.uniqueID());
        nodes.add(node);
        Iterables.addAll(nodes, createUserComments(action.getDefinition(), node));
        setLayoutOption(node, CoreOptions.PORT_CONSTRAINTS, PortConstraints.FIXED_SIDE);
        Pair<KPort, KPort> ports = _linguaFrancaShapeExtensions.addActionFigureAndPorts(node, action.isPhysical() ? "P" : "L");
        // TODO handle variables?
        if (action.getMinDelay() != null && action.getMinDelay() != ActionInstance.DEFAULT_MIN_DELAY) {
            _kLabelExtensions.addOutsideBottomCenteredNodeLabel(node, String.format("min delay: %s", action.getMinDelay().toString()), 7);
        }
        // TODO default value?
        if (action.getDefinition().getMinSpacing() != null) {
            _kLabelExtensions.addOutsideBottomCenteredNodeLabel(node, String.format("min spacing: %s", action.getMinSpacing().toString()), 7);
        }
        if (!StringExtensions.isNullOrEmpty(action.getDefinition().getPolicy())) {
            _kLabelExtensions.addOutsideBottomCenteredNodeLabel(node, String.format("policy: %s", action.getPolicy().toString()), 7);
        }
        // connect source
        for (KPort source : actionSources.get(action)) {
            connect(createDelayEdge(action), source, ports.getKey());
        }
        // connect targets
        for (KPort target : actionDestinations.get(action)) {
            connect(createDelayEdge(action), ports.getValue(), target);
        }
    }
    // Transform connections.
    // First, collect all the source ports.
    List<PortInstance> sourcePorts = new LinkedList<>(reactorInstance.inputs);
    for (ReactorInstance child : reactorInstance.children) {
        sourcePorts.addAll(child.outputs);
    }
    for (PortInstance leftPort : sourcePorts) {
        KPort source = leftPort.getParent() == reactorInstance ? parentInputPorts.get(leftPort) : outputPorts.get(leftPort.getParent(), leftPort);
        for (SendRange sendRange : leftPort.getDependentPorts()) {
            for (RuntimeRange<PortInstance> rightRange : sendRange.destinations) {
                PortInstance rightPort = rightRange.instance;
                KPort target = rightPort.getParent() == reactorInstance ? parentOutputPorts.get(rightPort) : inputPorts.get(rightPort.getParent(), rightPort);
                // There should be a connection, but skip if not.
                Connection connection = sendRange.connection;
                if (connection != null) {
                    KEdge edge = createIODependencyEdge(connection, (leftPort.isMultiport() || rightPort.isMultiport()));
                    if (connection.getDelay() != null) {
                        KLabel delayLabel = _kLabelExtensions.addCenterEdgeLabel(edge, ASTUtils.toOriginalText(connection.getDelay()));
                        associateWith(delayLabel, connection.getDelay());
                        if (connection.isPhysical()) {
                            _linguaFrancaStyleExtensions.applyOnEdgePysicalDelayStyle(delayLabel, reactorInstance.isMainOrFederated() ? Colors.WHITE : Colors.GRAY_95);
                        } else {
                            _linguaFrancaStyleExtensions.applyOnEdgeDelayStyle(delayLabel);
                        }
                    } else if (connection.isPhysical()) {
                        KLabel physicalConnectionLabel = _kLabelExtensions.addCenterEdgeLabel(edge, "---");
                        _linguaFrancaStyleExtensions.applyOnEdgePysicalStyle(physicalConnectionLabel, reactorInstance.isMainOrFederated() ? Colors.WHITE : Colors.GRAY_95);
                    }
                    if (source != null && target != null) {
                        // check for inside loop (direct in -> out connection with delay)
                        if (parentInputPorts.values().contains(source) && parentOutputPorts.values().contains(target)) {
                            // edge.setLayoutOption(CoreOptions.INSIDE_SELF_LOOPS_YO, true) // Does not work as expected
                            // Introduce dummy node to enable direct connection (that is also hidden when collapsed)
                            KNode dummy = _kNodeExtensions.createNode();
                            if (directConnectionDummyNodes.containsKey(target)) {
                                dummy = directConnectionDummyNodes.get(target);
                            } else {
                                nodes.add(dummy);
                                directConnectionDummyNodes.put(target, dummy);
                                _kRenderingExtensions.addInvisibleContainerRendering(dummy);
                                _kNodeExtensions.setNodeSize(dummy, 0, 0);
                                KEdge extraEdge = createIODependencyEdge(null, (leftPort.isMultiport() || rightPort.isMultiport()));
                                connect(extraEdge, dummy, target);
                            }
                            connect(edge, source, dummy);
                        } else {
                            connect(edge, source, target);
                        }
                    }
                }
            }
        }
    }
    // Add startup/shutdown
    if (startupUsed) {
        _linguaFrancaShapeExtensions.addStartupFigure(startupNode);
        _utilityExtensions.setID(startupNode, reactorInstance.uniqueID() + "_startup");
        startupNode.setProperty(REACTION_SPECIAL_TRIGGER, true);
        // add at the start (ordered first)
        nodes.add(0, startupNode);
        // try to order with reactions vertically if in one layer
        setLayoutOption(startupNode, LayeredOptions.POSITION, new KVector(0, 0));
        setLayoutOption(startupNode, LayeredOptions.LAYERING_LAYER_CONSTRAINT, LayerConstraint.FIRST);
        if (getBooleanValue(REACTIONS_USE_HYPEREDGES)) {
            KPort port = addInvisiblePort(startupNode);
            startupNode.getOutgoingEdges().forEach(it -> {
                it.setSourcePort(port);
            });
        }
    }
    if (shutdownUsed) {
        _linguaFrancaShapeExtensions.addShutdownFigure(shutdownNode);
        _utilityExtensions.setID(shutdownNode, reactorInstance.uniqueID() + "_shutdown");
        shutdownNode.setProperty(REACTION_SPECIAL_TRIGGER, true);
        // add at the end (ordered last)
        nodes.add(shutdownNode);
        // try to order with reactions vertically if in one layer
        setLayoutOption(shutdownNode, LayeredOptions.POSITION, new KVector(0, reactorInstance.reactions.size() + 1));
        if (getBooleanValue(REACTIONS_USE_HYPEREDGES)) {
            // connect all edges to one port
            KPort port = addInvisiblePort(shutdownNode);
            shutdownNode.getOutgoingEdges().forEach(it -> {
                it.setSourcePort(port);
            });
        }
    }
    // Postprocess timer nodes
    if (getBooleanValue(REACTIONS_USE_HYPEREDGES)) {
        // connect all edges to one port
        for (KNode timerNode : timerNodes.values()) {
            KPort port = addInvisiblePort(timerNode);
            timerNode.getOutgoingEdges().forEach(it -> {
                it.setSourcePort(port);
            });
        }
    }
    // Add reaction order edges (add last to have them on top of other edges)
    if (reactorInstance.reactions.size() > 1) {
        KNode prevNode = reactionNodes.get(IterableExtensions.head(reactorInstance.reactions));
        Iterable<KNode> iterList = IterableExtensions.map(IterableExtensions.drop(reactorInstance.reactions, 1), reactionNodes::get);
        for (KNode node : iterList) {
            KEdge edge = createOrderEdge();
            edge.setSource(prevNode);
            edge.setTarget(node);
            edge.setProperty(CoreOptions.NO_LAYOUT, true);
            // Do not remove them, as they are needed for cycle detection
            KRendering edgeRendering = _kRenderingExtensions.getKRendering(edge);
            _kRenderingExtensions.setInvisible(edgeRendering, !getBooleanValue(SHOW_REACTION_ORDER_EDGES));
            _kRenderingExtensions.getInvisible(edgeRendering).setPropagateToChildren(true);
            // TODO this does not work work with incremental update (https://github.com/kieler/KLighD/issues/37)
            // if (!getBooleanValue(SHOW_REACTION_ORDER_EDGES)) edge.initiallyHide()
            prevNode = node;
        }
    }
    _modeDiagrams.handleModes(nodes, reactorInstance);
    return nodes;
}
Also used : PortInstance(org.lflang.generator.PortInstance) ReactionInstance(org.lflang.generator.ReactionInstance) HashMap(java.util.HashMap) TimerInstance(org.lflang.generator.TimerInstance) ArrayList(java.util.ArrayList) KVector(org.eclipse.elk.core.math.KVector) KRendering(de.cau.cs.kieler.klighd.krendering.KRendering) HashSet(java.util.HashSet) Connection(org.lflang.lf.Connection) KEdge(de.cau.cs.kieler.klighd.kgraph.KEdge) KPort(de.cau.cs.kieler.klighd.kgraph.KPort) KNode(de.cau.cs.kieler.klighd.kgraph.KNode) TriggerInstance(org.lflang.generator.TriggerInstance) LayerConstraint(org.eclipse.elk.alg.layered.options.LayerConstraint) SizeConstraint(org.eclipse.elk.core.options.SizeConstraint) LinkedList(java.util.LinkedList) KLabel(de.cau.cs.kieler.klighd.kgraph.KLabel) ReactorInstance(org.lflang.generator.ReactorInstance) ActionInstance(org.lflang.generator.ActionInstance) SendRange(org.lflang.generator.SendRange)

Example 15 with PortInstance

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

the class LinguaFrancaSynthesis method transform.

// -------------------------------------------------------------------------
@Override
public KNode transform(final Model model) {
    KNode rootNode = _kNodeExtensions.createNode();
    try {
        // Find main
        Reactor main = IterableExtensions.findFirst(model.getReactors(), _utilityExtensions::isMainOrFederated);
        if (main != null) {
            ReactorInstance reactorInstance = new ReactorInstance(main, new SynthesisErrorReporter());
            rootNode.getChildren().addAll(createReactorNode(reactorInstance, true, null, null, new HashMap<>()));
        } else if (!getBooleanValue(SHOW_ALL_REACTORS)) {
            KNode messageNode = _kNodeExtensions.createNode();
            _linguaFrancaShapeExtensions.addErrorMessage(messageNode, TEXT_NO_MAIN_REACTOR, null);
            rootNode.getChildren().add(messageNode);
        }
        // Show all reactors
        if (main == null || getBooleanValue(SHOW_ALL_REACTORS)) {
            List<KNode> reactorNodes = new ArrayList<>();
            for (Reactor reactor : model.getReactors()) {
                if (reactor == main)
                    continue;
                ReactorInstance reactorInstance = new ReactorInstance(reactor, new SynthesisErrorReporter(), new HashSet<>());
                reactorNodes.addAll(createReactorNode(reactorInstance, main == null, HashBasedTable.<ReactorInstance, PortInstance, KPort>create(), HashBasedTable.<ReactorInstance, PortInstance, KPort>create(), new HashMap<>()));
            }
            if (!reactorNodes.isEmpty()) {
                // To allow ordering, we need box layout but we also need layered layout for ports thus wrap all node
                reactorNodes.add(0, IterableExtensions.head(rootNode.getChildren()));
                int index = 0;
                for (KNode node : reactorNodes) {
                    // Element could be null if there is no main reactor and Show All Reactors is checked.
                    if (node == null)
                        continue;
                    if (node.getProperty(CoreOptions.COMMENT_BOX))
                        continue;
                    KNode child = _kNodeExtensions.createNode();
                    child.getChildren().add(node);
                    // Add comment nodes
                    for (KEdge edge : node.getIncomingEdges()) {
                        if (!edge.getSource().getProperty(CoreOptions.COMMENT_BOX))
                            continue;
                        child.getChildren().add(edge.getSource());
                    }
                    _kRenderingExtensions.addInvisibleContainerRendering(child);
                    setLayoutOption(child, CoreOptions.ALGORITHM, LayeredOptions.ALGORITHM_ID);
                    setLayoutOption(child, CoreOptions.PADDING, new ElkPadding(0));
                    // Order!
                    setLayoutOption(child, CoreOptions.PRIORITY, reactorNodes.size() - index);
                    rootNode.getChildren().add(child);
                    index++;
                }
                setLayoutOption(rootNode, CoreOptions.ALGORITHM, BoxLayouterOptions.ALGORITHM_ID);
                setLayoutOption(rootNode, CoreOptions.SPACING_NODE_NODE, 25.0);
            }
        }
    } catch (Exception e) {
        e.printStackTrace();
        KNode messageNode = _kNodeExtensions.createNode();
        _linguaFrancaShapeExtensions.addErrorMessage(messageNode, "Error in Diagram Synthesis", e.getClass().getSimpleName() + " occurred. Could not create diagram.");
        rootNode.getChildren().add(messageNode);
    }
    return rootNode;
}
Also used : PortInstance(org.lflang.generator.PortInstance) SynthesisErrorReporter(org.lflang.diagram.synthesis.util.SynthesisErrorReporter) HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) KEdge(de.cau.cs.kieler.klighd.kgraph.KEdge) KPort(de.cau.cs.kieler.klighd.kgraph.KPort) KNode(de.cau.cs.kieler.klighd.kgraph.KNode) LayerConstraint(org.eclipse.elk.alg.layered.options.LayerConstraint) SizeConstraint(org.eclipse.elk.core.options.SizeConstraint) ReactorInstance(org.lflang.generator.ReactorInstance) Reactor(org.lflang.lf.Reactor) ElkPadding(org.eclipse.elk.core.math.ElkPadding)

Aggregations

PortInstance (org.lflang.generator.PortInstance)24 SendRange (org.lflang.generator.SendRange)10 CodeBuilder (org.lflang.generator.CodeBuilder)9 ReactionInstance (org.lflang.generator.ReactionInstance)8 ReactorInstance (org.lflang.generator.ReactorInstance)8 Reactor (org.lflang.lf.Reactor)7 ArrayList (java.util.ArrayList)5 LinkedList (java.util.LinkedList)4 ActionInstance (org.lflang.generator.ActionInstance)4 Connection (org.lflang.lf.Connection)4 KEdge (de.cau.cs.kieler.klighd.kgraph.KEdge)3 KNode (de.cau.cs.kieler.klighd.kgraph.KNode)3 KPort (de.cau.cs.kieler.klighd.kgraph.KPort)3 HashSet (java.util.HashSet)3 List (java.util.List)3 Collectors (java.util.stream.Collectors)3 EcoreUtil (org.eclipse.emf.ecore.util.EcoreUtil)3 ASTUtils (org.lflang.ASTUtils)3 InferredType (org.lflang.InferredType)3 TimeValue (org.lflang.TimeValue)3