Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New handling of startup/shutdown/reset reactions in modes #1169

Merged
merged 23 commits into from
Jun 10, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
be1de0f
modes: Implemented new handling of startup/shutdown/reset in modes
a-sr May 13, 2022
a78d6ae
Merge remote-tracking branch 'origin/master' into modal-models
a-sr May 13, 2022
1c7ebbc
modes: Adjusted Kotlin files to new trigger API
a-sr May 13, 2022
341a8c4
modes: Added support for enlisting state variables for automatic reset
a-sr May 16, 2022
85ee331
modes: Fixed state variable reset in python target
a-sr May 19, 2022
0a728a7
Merge remote-tracking branch 'origin/master' into modal-models
a-sr May 19, 2022
257dee3
Merge remote-tracking branch 'origin/master' into modal-models
a-sr May 25, 2022
0318863
Fixed merge error
a-sr May 25, 2022
bad2201
Fixed missing import
a-sr May 25, 2022
d3c57eb
Merge remote-tracking branch 'origin/master' into modal-models
a-sr May 25, 2022
335c752
Updated reactor-c
a-sr May 25, 2022
25539dd
Merge remote-tracking branch 'origin/master' into modal-models
a-sr May 28, 2022
c75271c
modes: Added validation rule to check for reset state variables without
a-sr May 28, 2022
1666681
modes: Moved reset modifier in front of state keyword in state variable
a-sr May 28, 2022
330528c
modes: Fixed state reset value validation rule
a-sr May 28, 2022
1bfeac5
modes: Added newline in test model
a-sr Jun 3, 2022
bb9bf33
modes: Added unit tests for mode related validation rules.
a-sr Jun 3, 2022
fb3c134
diagrams: Added graphical representation of reset triggers
a-sr Jun 8, 2022
065baa8
diagrams: Added graphical representation for reset state variables.
a-sr Jun 8, 2022
4aa9170
diagrams: Removed code correspondence tags from state variable types.
a-sr Jun 8, 2022
fc89ee7
Merge remote-tracking branch 'origin/master' into modal-models
a-sr Jun 8, 2022
5b2fd41
diagrams: Adjusted symbol spacing for state variables
a-sr Jun 8, 2022
51fc447
Merge branch 'master' into modal-models
lhstrh Jun 10, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,9 @@ public boolean getBooleanValue(SynthesisOption option) {
public <T extends EObject> T associateWith(T derived, Object source) {
return delegate.associateWith(derived, source);
}

@SuppressWarnings("unchecked")
public <T extends AbstractDiagramSynthesis<?>> T getRootSynthesis() {
return (T) delegate;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
import org.eclipse.elk.core.math.ElkPadding;
import org.eclipse.elk.core.math.KVector;
import org.eclipse.elk.core.options.BoxLayouterOptions;
import org.eclipse.elk.core.options.ContentAlignment;
import org.eclipse.elk.core.options.CoreOptions;
import org.eclipse.elk.core.options.Direction;
import org.eclipse.elk.core.options.PortConstraints;
Expand Down Expand Up @@ -91,6 +92,7 @@
import org.lflang.generator.TimerInstance;
import org.lflang.generator.TriggerInstance;
import org.lflang.lf.Connection;
import org.lflang.lf.LfPackage;
import org.lflang.lf.Model;
import org.lflang.lf.Reactor;
import org.lflang.lf.StateVar;
Expand Down Expand Up @@ -359,7 +361,7 @@ private Collection<KNode> createReactorNode(
}

if (getBooleanValue(SHOW_STATE_VARIABLES)) {
var variables = ASTUtils.allStateVars(reactor);
var variables = ASTUtils.<StateVar>collectElements(reactor, LfPackage.eINSTANCE.getReactor_StateVars(), true, false);
if (!variables.isEmpty()) {
KRectangle rectangle = _kContainerRenderingExtensions.addRectangle(figure);
_kRenderingExtensions.setInvisible(rectangle, true);
Expand Down Expand Up @@ -452,7 +454,7 @@ private Collection<KNode> createReactorNode(
}

if (getBooleanValue(SHOW_STATE_VARIABLES)) {
var variables = ASTUtils.allStateVars(reactor);
var variables = ASTUtils.<StateVar>collectElements(reactor, LfPackage.eINSTANCE.getReactor_StateVars(), true, false);
if (!variables.isEmpty()) {
KRectangle rectangle = _kContainerRenderingExtensions.addRectangle(comps.getReactor());
_kRenderingExtensions.setInvisible(rectangle, true);
Expand Down Expand Up @@ -584,6 +586,11 @@ private Collection<KNode> createReactorNode(
}

private KNode configureReactorNodeLayout(KNode node) {
// Direction
setLayoutOption(node, CoreOptions.DIRECTION, Direction.RIGHT);
// Center free floating children
setLayoutOption(node, CoreOptions.CONTENT_ALIGNMENT, ContentAlignment.centerCenter());
// Do not shrink nodes below content
setLayoutOption(node, CoreOptions.NODE_SIZE_CONSTRAINTS, SizeConstraint.minimumSizeWithPorts());
// Allows to freely shuffle ports on each side
setLayoutOption(node, CoreOptions.PORT_CONSTRAINTS, PortConstraints.FIXED_SIDE);
Expand Down Expand Up @@ -735,6 +742,8 @@ private Collection<KNode> transformReactorNetwork(
boolean startupUsed = false;
KNode shutdownNode = _kNodeExtensions.createNode();
boolean shutdownUsed = false;
KNode resetNode = _kNodeExtensions.createNode();
boolean resetUsed = false;

// Transform instances
int index = 0;
Expand Down Expand Up @@ -809,6 +818,11 @@ private Collection<KNode> transformReactorNetwork(
shutdownNode,
port);
shutdownUsed = true;
} else if (trigger.isReset()) {
connect(createDependencyEdge(((TriggerInstance.BuiltinTriggerVariable) trigger.getDefinition()).definition),
resetNode,
port);
resetUsed = true;
} else if (trigger instanceof ActionInstance) {
actionDestinations.put(((ActionInstance) trigger), port);
} else if (trigger instanceof PortInstance) {
Expand Down Expand Up @@ -1027,6 +1041,22 @@ private Collection<KNode> transformReactorNetwork(
});
}
}
if (resetUsed) {
_linguaFrancaShapeExtensions.addResetFigure(resetNode);
_utilityExtensions.setID(resetNode, reactorInstance.uniqueID() + "_reset");
resetNode.setProperty(REACTION_SPECIAL_TRIGGER, true);
nodes.add(startupUsed ? 1 : 0, resetNode); // after startup
// try to order with reactions vertically if in one layer
setLayoutOption(resetNode, LayeredOptions.POSITION, new KVector(0, 0.5));
setLayoutOption(resetNode, LayeredOptions.LAYERING_LAYER_CONSTRAINT, LayerConstraint.FIRST);

if (getBooleanValue(REACTIONS_USE_HYPEREDGES)) { // connect all edges to one port
KPort port = addInvisiblePort(resetNode);
resetNode.getOutgoingEdges().forEach(it -> {
it.setSourcePort(port);
});
}
}

// Postprocess timer nodes
if (getBooleanValue(REACTIONS_USE_HYPEREDGES)) { // connect all edges to one port
Expand Down Expand Up @@ -1118,7 +1148,7 @@ private void addParameterList(KContainerRendering container, List<ParameterInsta
private String createParameterLabel(ParameterInstance param, boolean bullet) {
StringBuilder b = new StringBuilder();
if (bullet) {
b.append("\u2219 ");
b.append("\u2009\u2219\u2009\u2009"); // aligned spacing with state variables
}
b.append(param.getName());
String t = param.type.toOriginalText();
Expand All @@ -1133,7 +1163,7 @@ private String createParameterLabel(ParameterInstance param, boolean bullet) {
return b.toString();
}

private void addStateVariableList(KContainerRendering container, List<StateVar> variables) {
public void addStateVariableList(KContainerRendering container, List<StateVar> variables) {
int cols = 1;
try {
cols = getIntValue(REACTOR_BODY_TABLE_COLS);
Expand All @@ -1154,7 +1184,13 @@ private void addStateVariableList(KContainerRendering container, List<StateVar>
private String createStateVariableLabel(StateVar variable, boolean bullet) {
StringBuilder b = new StringBuilder();
if (bullet) {
b.append("\u229a ");
b.append("\u229a");
// Reset marker
if (variable.isReset()) {
b.append("\u1d63\u200a");
} else {
b.append("\u2009\u2009");
}
}
b.append(variable.getName());
if (variable.getType() != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -584,6 +584,31 @@ public KPolygon addShutdownFigure(KNode node) {
return figure;
}

/**
* Creates the visual representation of a shutdown trigger.
*/
public KEllipse addResetFigure(KNode node) {
_kNodeExtensions.setMinimalNodeSize(node, 18, 18);
KEllipse figure = _kRenderingExtensions.addEllipse(node);
_kRenderingExtensions.setLineWidth(figure, 1);
_kRenderingExtensions.setBackground(figure, Colors.WHITE);
_linguaFrancaStyleExtensions.noSelectionStyle(figure);
_linguaFrancaStyleExtensions.boldLineSelectionStyle(figure);

KEllipse inner = _kContainerRenderingExtensions.addEllipse(figure);
_kRenderingExtensions.setSurroundingSpace(inner, 2.5f, 0);
_kRenderingExtensions.setLineWidth(inner, 1);
_kRenderingExtensions.setBackground(inner, Colors.WHITE);
_linguaFrancaStyleExtensions.noSelectionStyle(inner);

KText text = _kContainerRenderingExtensions.addText(inner, "R");
_kRenderingExtensions.setFontSize(text, 6);
_kRenderingExtensions.setFontBold(text, true);
_linguaFrancaStyleExtensions.boldTextSelectionStyle(text);

return figure;
}

/**
* Creates the visual representation of a reactor port.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,11 @@
import org.lflang.diagram.synthesis.styles.LinguaFrancaShapeExtensions;
import org.lflang.diagram.synthesis.styles.LinguaFrancaStyleExtensions;
import org.lflang.generator.ModeInstance;
import org.lflang.generator.ModeInstance.ModeTransitionType;
import org.lflang.generator.ModeInstance.Transition;
import org.lflang.generator.ReactorInstance;
import org.lflang.lf.Action;
import org.lflang.lf.Mode;
import org.lflang.lf.ModeTransition;
import org.lflang.lf.Timer;

import com.google.common.collect.LinkedHashMultimap;
Expand All @@ -70,6 +70,7 @@
import de.cau.cs.kieler.klighd.kgraph.KNode;
import de.cau.cs.kieler.klighd.kgraph.KPort;
import de.cau.cs.kieler.klighd.krendering.Colors;
import de.cau.cs.kieler.klighd.krendering.HorizontalAlignment;
import de.cau.cs.kieler.klighd.krendering.KContainerRendering;
import de.cau.cs.kieler.klighd.krendering.KDecoratorPlacementData;
import de.cau.cs.kieler.klighd.krendering.KEllipse;
Expand Down Expand Up @@ -144,6 +145,7 @@ public void handleModes(List<KNode> nodes, ReactorInstance reactor) {
DiagramSyntheses.setLayoutOption(node, LayeredOptions.LAYERING_LAYER_CONSTRAINT, LayerConstraint.FIRST);
}
DiagramSyntheses.setLayoutOption(node, LayeredOptions.CROSSING_MINIMIZATION_SEMI_INTERACTIVE, true);
DiagramSyntheses.setLayoutOption(node, CoreOptions.DIRECTION, Direction.RIGHT);

var expansionState = MemorizingExpandCollapseAction.getExpansionState(mode);
DiagramSyntheses.setLayoutOption(node, KlighdProperties.EXPAND,
Expand All @@ -165,6 +167,34 @@ public void handleModes(List<KNode> nodes, ReactorInstance reactor) {
_kRenderingExtensions.addDoubleClickAction(textButton, MemorizingExpandCollapseAction.ID);
}

if (getBooleanValue(LinguaFrancaSynthesis.SHOW_STATE_VARIABLES)) {
// Add mode-local state variables
var variables = mode.getDefinition().getStateVars();
if (!variables.isEmpty()) {
KRectangle rectangle = _kContainerRenderingExtensions.addRectangle(expandFigure);
_kRenderingExtensions.setInvisible(rectangle, true);
if (!getBooleanValue(LinguaFrancaSynthesis.SHOW_HYPERLINKS)) {
_kRenderingExtensions.to(
_kRenderingExtensions.from(
_kRenderingExtensions.setGridPlacementData(rectangle),
_kRenderingExtensions.LEFT, 6, 0,
_kRenderingExtensions.TOP, 0, 0),
_kRenderingExtensions.RIGHT, 6, 0,
_kRenderingExtensions.BOTTOM, 4, 0);
} else {
_kRenderingExtensions.to(
_kRenderingExtensions.from(
_kRenderingExtensions.setGridPlacementData(rectangle),
_kRenderingExtensions.LEFT, 6, 0,
_kRenderingExtensions.TOP, 4, 0),
_kRenderingExtensions.RIGHT, 6, 0,
_kRenderingExtensions.BOTTOM, 0, 0);
}
_kRenderingExtensions.setHorizontalAlignment(rectangle, HorizontalAlignment.LEFT);
this.<LinguaFrancaSynthesis>getRootSynthesis().addStateVariableList(rectangle, variables);
}
}

_kContainerRenderingExtensions.addChildArea(expandFigure);

// Collapse Rectangle
Expand Down Expand Up @@ -228,9 +258,9 @@ public void handleModes(List<KNode> nodes, ReactorInstance reactor) {
}

// add transitions
var representedTargets = new HashSet<Pair<ModeInstance, ModeInstance.ModeTransitionType>>();
var representedTargets = new HashSet<Pair<ModeInstance, ModeTransition>>();
for (var transition : ListExtensions.reverseView(mode.transitions)) {
if (!representedTargets.contains(new Pair<ModeInstance, ModeInstance.ModeTransitionType>(transition.target, transition.type))) {
if (!representedTargets.contains(new Pair<ModeInstance, ModeTransition>(transition.target, transition.type))) {
var edge = _kEdgeExtensions.createEdge();
edge.setSource(modeNode);
edge.setTarget(modeNodes.get(transition.target));
Expand All @@ -240,7 +270,7 @@ public void handleModes(List<KNode> nodes, ReactorInstance reactor) {
associateWith(edge, transition.getDefinition());
} else {
// Bundle similar transitions
representedTargets.add(new Pair<ModeInstance, ModeInstance.ModeTransitionType>(transition.target, transition.type));
representedTargets.add(new Pair<ModeInstance, ModeTransition>(transition.target, transition.type));
}
}
}
Expand Down Expand Up @@ -430,7 +460,7 @@ private void addTransitionFigure(KEdge edge, Transition transition) {
_kRenderingExtensions.setForeground(spline, MODE_FG);
_linguaFrancaStyleExtensions.boldLineSelectionStyle(spline);

if (transition.type == ModeTransitionType.HISTORY) {
if (transition.type == ModeTransition.HISTORY) {
addHistoryDecorator(spline);
} else {
KRendering arrowDecorator = _kPolylineExtensions.addHeadArrowDecorator(spline);
Expand Down
Loading