Search in sources :

Example 1 with Timer

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

the class ModeDiagrams method handleModes.

public void handleModes(List<KNode> nodes, ReactorInstance reactor) {
    if (!reactor.modes.isEmpty()) {
        var modeNodes = new LinkedHashMap<ModeInstance, KNode>();
        var modeDefinitionMap = new LinkedHashMap<Mode, ModeInstance>();
        for (ModeInstance mode : reactor.modes) {
            var node = _kNodeExtensions.createNode();
            associateWith(node, mode.getDefinition());
            NamedInstanceUtil.linkInstance(node, mode);
            _utilityExtensions.setID(node, mode.uniqueID());
            modeNodes.put(mode, node);
            modeDefinitionMap.put(mode.getDefinition(), mode);
            if (mode.isInitial()) {
                DiagramSyntheses.setLayoutOption(node, LayeredOptions.LAYERING_LAYER_CONSTRAINT, LayerConstraint.FIRST);
            }
            DiagramSyntheses.setLayoutOption(node, LayeredOptions.CROSSING_MINIMIZATION_SEMI_INTERACTIVE, true);
            var expansionState = MemorizingExpandCollapseAction.getExpansionState(mode);
            DiagramSyntheses.setLayoutOption(node, KlighdProperties.EXPAND, expansionState != null ? expansionState : !this.getBooleanValue(INITIALLY_COLLAPSE_MODES));
            // Expanded Rectangle
            var expandFigure = addModeFigure(node, mode, true);
            expandFigure.setProperty(KlighdProperties.EXPANDED_RENDERING, true);
            _kRenderingExtensions.addDoubleClickAction(expandFigure, MemorizingExpandCollapseAction.ID);
            if (getBooleanValue(LinguaFrancaSynthesis.SHOW_HYPERLINKS)) {
                // Collapse button
                KText textButton = _linguaFrancaShapeExtensions.addTextButton(expandFigure, LinguaFrancaSynthesis.TEXT_HIDE_ACTION);
                _kRenderingExtensions.to(_kRenderingExtensions.from(_kRenderingExtensions.setGridPlacementData(textButton), _kRenderingExtensions.LEFT, 8, 0, _kRenderingExtensions.TOP, 0, 0), _kRenderingExtensions.RIGHT, 8, 0, _kRenderingExtensions.BOTTOM, 0, 0);
                _kRenderingExtensions.addSingleClickAction(textButton, MemorizingExpandCollapseAction.ID);
                _kRenderingExtensions.addDoubleClickAction(textButton, MemorizingExpandCollapseAction.ID);
            }
            _kContainerRenderingExtensions.addChildArea(expandFigure);
            // Collapse Rectangle
            var collapseFigure = addModeFigure(node, mode, false);
            collapseFigure.setProperty(KlighdProperties.COLLAPSED_RENDERING, true);
            if (this.hasContent(mode)) {
                _kRenderingExtensions.addDoubleClickAction(collapseFigure, MemorizingExpandCollapseAction.ID);
                if (getBooleanValue(LinguaFrancaSynthesis.SHOW_HYPERLINKS)) {
                    // Expand button
                    KText textButton = _linguaFrancaShapeExtensions.addTextButton(collapseFigure, LinguaFrancaSynthesis.TEXT_SHOW_ACTION);
                    _kRenderingExtensions.to(_kRenderingExtensions.from(_kRenderingExtensions.setGridPlacementData(textButton), _kRenderingExtensions.LEFT, 8, 0, _kRenderingExtensions.TOP, 0, 0), _kRenderingExtensions.RIGHT, 8, 0, _kRenderingExtensions.BOTTOM, 8, 0);
                    _kRenderingExtensions.addSingleClickAction(textButton, MemorizingExpandCollapseAction.ID);
                    _kRenderingExtensions.addDoubleClickAction(textButton, MemorizingExpandCollapseAction.ID);
                }
            }
        }
        var modeChildren = HashMultimap.<ModeInstance, KNode>create();
        var nodeModes = new HashMap<KNode, ModeInstance>();
        for (var node : nodes) {
            var instance = NamedInstanceUtil.getLinkedInstance(node);
            if (instance == null && node.getProperty(CoreOptions.COMMENT_BOX)) {
                var firstEdge = IterableExtensions.<KEdge>head(node.getOutgoingEdges());
                if (firstEdge != null && firstEdge.getTarget() != null) {
                    instance = NamedInstanceUtil.getLinkedInstance(firstEdge.getTarget());
                }
            }
            if (instance != null) {
                var mode = instance.getMode(true);
                modeChildren.put(mode, node);
                nodeModes.put(node, mode);
            } else {
                modeChildren.put(null, node);
            }
        }
        var modeContainer = _kNodeExtensions.createNode();
        modeContainer.getChildren().addAll(modeNodes.values());
        var fig = addModeContainerFigure(modeContainer);
        _kRenderingExtensions.addDoubleClickAction(fig, MemorizingExpandCollapseAction.ID);
        if (modeChildren.get(null).isEmpty()) {
            _kRenderingExtensions.setInvisible(fig, true);
            DiagramSyntheses.setLayoutOption(modeContainer, CoreOptions.PADDING, new ElkPadding());
        }
        DiagramSyntheses.setLayoutOption(modeContainer, CoreOptions.NODE_SIZE_CONSTRAINTS, SizeConstraint.minimumSizeWithPorts());
        DiagramSyntheses.setLayoutOption(modeContainer, CoreOptions.EDGE_ROUTING, EdgeRouting.SPLINES);
        DiagramSyntheses.setLayoutOption(modeContainer, CoreOptions.DIRECTION, Direction.DOWN);
        DiagramSyntheses.setLayoutOption(modeContainer, CoreOptions.PORT_CONSTRAINTS, PortConstraints.FIXED_ORDER);
        var modeContainerPorts = new HashMap<KPort, KPort>();
        for (var mode : ListExtensions.reverseView(reactor.modes)) {
            var modeNode = modeNodes.get(mode);
            var edges = new HashSet<KEdge>();
            // add children
            for (var child : modeChildren.get(mode)) {
                nodes.remove(child);
                modeNode.getChildren().add(child);
                edges.addAll(child.getIncomingEdges());
                edges.addAll(child.getOutgoingEdges());
            }
            // add transitions
            var representedTargets = new HashSet<Pair<ModeInstance, ModeInstance.ModeTransitionType>>();
            for (var transition : ListExtensions.reverseView(mode.transitions)) {
                if (!representedTargets.contains(new Pair<ModeInstance, ModeInstance.ModeTransitionType>(transition.target, transition.type))) {
                    var edge = _kEdgeExtensions.createEdge();
                    edge.setSource(modeNode);
                    edge.setTarget(modeNodes.get(transition.target));
                    addTransitionFigure(edge, transition);
                    if (getBooleanValue(SHOW_TRANSITION_LABELS)) {
                        associateWith(edge, transition.getDefinition());
                    } else {
                        // Bundle similar transitions
                        representedTargets.add(new Pair<ModeInstance, ModeInstance.ModeTransitionType>(transition.target, transition.type));
                    }
                }
            }
            // handle cross hierarchy edges
            var portCopies = new HashMap<KPort, KPort>();
            for (var edge : edges) {
                if (!edge.getProperty(CoreOptions.NO_LAYOUT)) {
                    var sourceNodeMode = nodeModes.get(edge.getSource());
                    if (sourceNodeMode == null) {
                        sourceNodeMode = nodeModes.get(edge.getSource().getParent());
                    }
                    var sourceIsInMode = sourceNodeMode != null;
                    var targetNodeMode = nodeModes.get(edge.getTarget());
                    if (targetNodeMode == null) {
                        targetNodeMode = nodeModes.get(edge.getTarget().getParent());
                    }
                    var targetIsInMode = targetNodeMode != null;
                    if (!sourceIsInMode || !targetIsInMode) {
                        var node = sourceIsInMode ? edge.getTarget() : edge.getSource();
                        var port = sourceIsInMode ? edge.getTargetPort() : edge.getSourcePort();
                        var isLocal = modeChildren.get(null).contains(node);
                        if (isLocal) {
                            // Add port to mode container
                            if (modeContainerPorts.containsKey(port)) {
                                node = modeContainer;
                                port = modeContainerPorts.get(port);
                            } else {
                                var containerPort = _kPortExtensions.createPort();
                                modeContainerPorts.put(port, containerPort);
                                modeContainer.getPorts().add(containerPort);
                                _kPortExtensions.setPortSize(containerPort, 8, 4);
                                KRectangle rect = _kRenderingExtensions.addRectangle(containerPort);
                                _kRenderingExtensions.setBackground(rect, Colors.BLACK);
                                DiagramSyntheses.setLayoutOption(containerPort, CoreOptions.PORT_BORDER_OFFSET, -4.0);
                                DiagramSyntheses.setLayoutOption(containerPort, CoreOptions.PORT_SIDE, sourceIsInMode ? PortSide.EAST : PortSide.WEST);
                                var source = _utilityExtensions.sourceElement(node);
                                var label = "";
                                if (source instanceof Action) {
                                    label = ((Action) source).getName();
                                } else if (source instanceof Timer) {
                                    label = ((Timer) source).getName();
                                }
                                _kLabelExtensions.addOutsidePortLabel(containerPort, label, 8);
                                // new connection
                                var copy = EcoreUtil.copy(edge);
                                if (sourceIsInMode) {
                                    copy.setSource(modeContainer);
                                    copy.setSourcePort(containerPort);
                                    copy.setTarget(edge.getTarget());
                                } else {
                                    copy.setTarget(modeContainer);
                                    copy.setTargetPort(containerPort);
                                    copy.setSource(edge.getSource());
                                }
                                node = modeContainer;
                                port = containerPort;
                            }
                        }
                        // Duplicate port
                        if (!portCopies.containsKey(port)) {
                            var copy = EcoreUtil.copy(port);
                            portCopies.put(port, copy);
                            var dummyNode = _kNodeExtensions.createNode();
                            var newID = mode.uniqueID() + "_";
                            if (!port.getLabels().isEmpty()) {
                                newID += IterableExtensions.head(port.getLabels()).getText();
                            }
                            _utilityExtensions.setID(dummyNode, newID);
                            _kRenderingExtensions.addInvisibleContainerRendering(dummyNode);
                            dummyNode.getPorts().add(copy);
                            DiagramSyntheses.setLayoutOption(dummyNode, LayeredOptions.LAYERING_LAYER_CONSTRAINT, port.getProperty(CoreOptions.PORT_SIDE) == PortSide.WEST ? LayerConstraint.FIRST : LayerConstraint.LAST);
                            modeNode.getChildren().add(dummyNode);
                        }
                        var newPort = portCopies.get(port);
                        if (sourceIsInMode) {
                            edge.setTarget(newPort.getNode());
                            edge.setTargetPort(newPort);
                        } else {
                            edge.setSource(newPort.getNode());
                            edge.setSourcePort(newPort);
                        }
                    }
                }
            }
        }
        nodes.add(modeContainer);
    }
}
Also used : ModeInstance(org.lflang.generator.ModeInstance) MemorizingExpandCollapseAction(org.lflang.diagram.synthesis.action.MemorizingExpandCollapseAction) Action(org.lflang.lf.Action) HashMap(java.util.HashMap) LinkedHashMap(java.util.LinkedHashMap) KEdge(de.cau.cs.kieler.klighd.kgraph.KEdge) KNode(de.cau.cs.kieler.klighd.kgraph.KNode) LinkedHashMap(java.util.LinkedHashMap) KRectangle(de.cau.cs.kieler.klighd.krendering.KRectangle) KText(de.cau.cs.kieler.klighd.krendering.KText) Timer(org.lflang.lf.Timer) ElkPadding(org.eclipse.elk.core.math.ElkPadding) HashSet(java.util.HashSet) ModeTransitionType(org.lflang.generator.ModeInstance.ModeTransitionType) Pair(org.eclipse.xtext.xbase.lib.Pair)

Example 2 with Timer

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

the class LFValidator method checkReactor.

@Check(CheckType.FAST)
public void checkReactor(Reactor reactor) throws IOException {
    Set<Reactor> superClasses = ASTUtils.superClasses(reactor);
    if (superClasses == null) {
        error("Problem with superclasses: Either they form a cycle or are not defined", Literals.REACTOR_DECL__NAME);
        // Continue checks, but without any superclasses.
        superClasses = new LinkedHashSet<>();
    }
    String name = FileUtil.nameWithoutExtension(reactor.eResource());
    if (reactor.getName() == null) {
        if (!reactor.isFederated() && !reactor.isMain()) {
            error("Reactor must be named.", Literals.REACTOR_DECL__NAME);
            // Prevent NPE in tests below.
            return;
        }
    }
    TreeIterator<EObject> iter = reactor.eResource().getAllContents();
    if (reactor.isFederated() || reactor.isMain()) {
        if (reactor.getName() != null && !reactor.getName().equals(name)) {
            // Make sure that if the name is given, it matches the expected name.
            error("Name of main reactor must match the file name (or be omitted).", Literals.REACTOR_DECL__NAME);
        }
        // Do not allow multiple main/federated reactors.
        int nMain = countMainOrFederated(iter);
        if (nMain > 1) {
            EAttribute attribute = Literals.REACTOR__MAIN;
            if (reactor.isFederated()) {
                attribute = Literals.REACTOR__FEDERATED;
            }
            error("Multiple definitions of main or federated reactor.", attribute);
        }
    } else {
        // Not federated or main.
        int nMain = countMainOrFederated(iter);
        if (nMain > 0 && reactor.getName().equals(name)) {
            error("Name conflict with main reactor.", Literals.REACTOR_DECL__NAME);
        }
    }
    // Check for illegal names.
    checkName(reactor.getName(), Literals.REACTOR_DECL__NAME);
    // C++ reactors may not be called 'preamble'
    if (this.target == Target.CPP && reactor.getName().equalsIgnoreCase("preamble")) {
        error("Reactor cannot be named '" + reactor.getName() + "'", Literals.REACTOR_DECL__NAME);
    }
    if (reactor.getHost() != null) {
        if (!reactor.isFederated()) {
            error("Cannot assign a host to reactor '" + reactor.getName() + "' because it is not federated.", Literals.REACTOR__HOST);
        }
    }
    List<Variable> variables = new ArrayList<>();
    variables.addAll(reactor.getInputs());
    variables.addAll(reactor.getOutputs());
    variables.addAll(reactor.getActions());
    variables.addAll(reactor.getTimers());
    // Perform checks on super classes.
    for (Reactor superClass : superClasses) {
        HashSet<Variable> conflicts = new HashSet<>();
        // Detect input conflicts
        checkConflict(superClass.getInputs(), reactor.getInputs(), variables, conflicts);
        // Detect output conflicts
        checkConflict(superClass.getOutputs(), reactor.getOutputs(), variables, conflicts);
        // Detect output conflicts
        checkConflict(superClass.getActions(), reactor.getActions(), variables, conflicts);
        // Detect conflicts
        for (Timer timer : superClass.getTimers()) {
            List<Variable> filteredVariables = new ArrayList<>(variables);
            filteredVariables.removeIf(it -> reactor.getTimers().contains(it));
            if (hasNameConflict(timer, filteredVariables)) {
                conflicts.add(timer);
            } else {
                variables.add(timer);
            }
        }
        // Report conflicts.
        if (conflicts.size() > 0) {
            List<String> names = new ArrayList<>();
            for (Variable it : conflicts) {
                names.add(it.getName());
            }
            error(String.format("Cannot extend %s due to the following conflicts: %s.", superClass.getName(), String.join(",", names)), Literals.REACTOR__SUPER_CLASSES);
        }
    }
}
Also used : TypedVariable(org.lflang.lf.TypedVariable) Variable(org.lflang.lf.Variable) ArrayList(java.util.ArrayList) EAttribute(org.eclipse.emf.ecore.EAttribute) Timer(org.lflang.lf.Timer) EObject(org.eclipse.emf.ecore.EObject) ImportedReactor(org.lflang.lf.ImportedReactor) Reactor(org.lflang.lf.Reactor) HashSet(java.util.HashSet) LinkedHashSet(java.util.LinkedHashSet) Check(org.eclipse.xtext.validation.Check)

Aggregations

HashSet (java.util.HashSet)2 Timer (org.lflang.lf.Timer)2 KEdge (de.cau.cs.kieler.klighd.kgraph.KEdge)1 KNode (de.cau.cs.kieler.klighd.kgraph.KNode)1 KRectangle (de.cau.cs.kieler.klighd.krendering.KRectangle)1 KText (de.cau.cs.kieler.klighd.krendering.KText)1 ArrayList (java.util.ArrayList)1 HashMap (java.util.HashMap)1 LinkedHashMap (java.util.LinkedHashMap)1 LinkedHashSet (java.util.LinkedHashSet)1 ElkPadding (org.eclipse.elk.core.math.ElkPadding)1 EAttribute (org.eclipse.emf.ecore.EAttribute)1 EObject (org.eclipse.emf.ecore.EObject)1 Check (org.eclipse.xtext.validation.Check)1 Pair (org.eclipse.xtext.xbase.lib.Pair)1 MemorizingExpandCollapseAction (org.lflang.diagram.synthesis.action.MemorizingExpandCollapseAction)1 ModeInstance (org.lflang.generator.ModeInstance)1 ModeTransitionType (org.lflang.generator.ModeInstance.ModeTransitionType)1 Action (org.lflang.lf.Action)1 ImportedReactor (org.lflang.lf.ImportedReactor)1