use of org.lflang.generator.ReactorInstance in project lingua-franca by lf-lang.
the class ModelInfo method update.
/**
* Redo all analysis based on the given model.
*
* @param model the model to analyze.
*/
public void update(Model model, ErrorReporter reporter) {
this.updated = true;
this.model = model;
this.instantiationGraph = new InstantiationGraph(model, true);
if (this.instantiationGraph.getCycles().size() == 0) {
List<ReactorInstance> topLevelReactorInstances = new LinkedList<>();
var main = model.getReactors().stream().filter(it -> it.isMain() || it.isFederated()).findFirst();
if (main.isPresent()) {
var inst = new ReactorInstance(main.get(), reporter);
topLevelReactorInstances.add(inst);
} else {
model.getReactors().forEach(it -> topLevelReactorInstances.add(new ReactorInstance(it, reporter)));
}
// don't store the graph into a field, only the cycles.
for (ReactorInstance top : topLevelReactorInstances) {
this.topologyCycles.addAll(top.getCycles());
}
}
// may be null if the target is invalid
var target = Target.forName(model.getTarget().getName()).orElse(null);
// Perform C-specific traversals.
if (target == Target.C) {
this.collectOverflowingNodes();
}
}
use of org.lflang.generator.ReactorInstance 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());
}
use of org.lflang.generator.ReactorInstance in project lingua-franca by lf-lang.
the class PythonReactorGenerator method generatePythonClass.
/**
* Generate a Python class corresponding to decl
* @param instance The reactor instance to be generated
* @param pythonClasses The class definition is appended to this code builder
* @param federate The federate instance for the reactor instance
* @param instantiatedClasses A list of visited instances to avoid generating duplicates
*/
public static String generatePythonClass(ReactorInstance instance, FederateInstance federate, List<String> instantiatedClasses, ReactorInstance main, PythonTypes types) {
CodeBuilder pythonClasses = new CodeBuilder();
ReactorDecl decl = instance.getDefinition().getReactorClass();
Reactor reactor = ASTUtils.toDefinition(decl);
String className = instance.getDefinition().getReactorClass().getName();
if (instance != main && !federate.contains(instance) || instantiatedClasses == null || // Do not generate code for delay reactors in Python
className.contains(GeneratorBase.GEN_DELAY_CLASS_NAME)) {
return "";
}
if (federate.contains(instance) && !instantiatedClasses.contains(className)) {
pythonClasses.pr(generatePythonClassHeader(className));
// Generate preamble code
pythonClasses.indent();
pythonClasses.pr(PythonPreambleGenerator.generatePythonPreambles(reactor.getPreambles()));
// Handle runtime initializations
pythonClasses.pr(generatePythonConstructor(decl, types));
pythonClasses.pr(PythonParameterGenerator.generatePythonGetters(decl));
List<Reaction> reactionToGenerate = ASTUtils.allReactions(reactor);
if (reactor.isFederated()) {
// Filter out reactions that are automatically generated in C in the top level federated reactor
reactionToGenerate.removeIf(it -> !federate.contains(it) || federate.networkReactions.contains(it));
}
pythonClasses.pr(PythonReactionGenerator.generatePythonReactions(reactor, reactionToGenerate));
pythonClasses.unindent();
instantiatedClasses.add(className);
}
for (ReactorInstance child : instance.children) {
pythonClasses.pr(generatePythonClass(child, federate, instantiatedClasses, main, types));
}
return pythonClasses.getCode();
}
use of org.lflang.generator.ReactorInstance in project lingua-franca by lf-lang.
the class PythonReactorGenerator method generateListsToHoldClassInstances.
/**
* Generate code to instantiate a Python list that will hold the Python
* class instance of reactor <code>instance<code>. Will recursively do
* the same for the children of <code>instance<code> as well.
*
* @param instance The reactor instance for which the Python list will be created.
* @param federate Will check if <code>instance<code> (or any of its children) belong to
* <code>federate<code> before generating code for them.
*/
public static String generateListsToHoldClassInstances(ReactorInstance instance, FederateInstance federate) {
CodeBuilder code = new CodeBuilder();
if (federate != null && !federate.contains(instance)) {
return "";
}
code.pr(PyUtil.reactorRefName(instance) + " = [None] * " + instance.getTotalWidth());
for (ReactorInstance child : instance.children) {
code.pr(generateListsToHoldClassInstances(child, federate));
}
return code.toString();
}
use of org.lflang.generator.ReactorInstance in project lingua-franca by lf-lang.
the class LinguaFrancaShapeExtensions method addReactorFigure.
/**
* Creates the visual representation of a reactor node
*/
public ReactorFigureComponents addReactorFigure(KNode node, ReactorInstance reactorInstance, String text) {
int padding = getBooleanValue(LinguaFrancaSynthesis.SHOW_HYPERLINKS) ? 8 : 6;
Function1<KRoundedRectangle, KRendering> style = r -> {
_kRenderingExtensions.setLineWidth(r, 1);
_kRenderingExtensions.setForeground(r, Colors.GRAY);
_kRenderingExtensions.setBackground(r, Colors.GRAY_95);
return _linguaFrancaStyleExtensions.boldLineSelectionStyle(r);
};
KRoundedRectangle figure = _kRenderingExtensions.addRoundedRectangle(node, 8, 8, 1);
_kContainerRenderingExtensions.setGridPlacement(figure, 1);
style.apply(figure);
figure.setProperty(REACTOR_CONTENT_CONTAINER, true);
// minimal node size is necessary if no text will be added
List<Float> minSize = List.of(2 * figure.getCornerWidth(), 2 * figure.getCornerHeight());
_kNodeExtensions.setMinimalNodeSize(node, minSize.get(0), minSize.get(1));
// Add parent container
KRectangle parentContainer = _kContainerRenderingExtensions.addRectangle(figure);
_kRenderingExtensions.setInvisible(parentContainer, true);
setGridPlacementDataFromPointToPoint(parentContainer, LEFT, padding, 0, TOP, padding, 0, RIGHT, padding, 0, BOTTOM, _utilityExtensions.hasContent(reactorInstance) ? 4 : padding, 0);
// Add centered child container
KRectangle childContainer = _kContainerRenderingExtensions.addRectangle(parentContainer);
_kRenderingExtensions.setInvisible(childContainer, true);
_kRenderingExtensions.setPointPlacementData(childContainer, _kRenderingExtensions.LEFT, 0, 0.5f, _kRenderingExtensions.TOP, 0, 0.5f, _kRenderingExtensions.H_CENTRAL, _kRenderingExtensions.V_CENTRAL, 0, 0, 0, 0);
KGridPlacement placement = _kContainerRenderingExtensions.setGridPlacement(childContainer, 1);
KText childText = _kContainerRenderingExtensions.addText(childContainer, text);
DiagramSyntheses.suppressSelectability(childText);
_linguaFrancaStyleExtensions.underlineSelectionStyle(childText);
if (!_utilityExtensions.isRoot(reactorInstance) && reactorInstance.getDefinition().getHost() != null) {
KRendering cloudUploadIcon = _linguaFrancaStyleExtensions.addCloudUploadIcon(childContainer);
setGridPlacementDataFromPointToPoint(cloudUploadIcon, LEFT, 3, 0, TOP, 0, 0, RIGHT, 0, 0, BOTTOM, 0, 0);
placement.setNumColumns(2);
if (getBooleanValue(LinguaFrancaSynthesis.SHOW_REACTOR_HOST)) {
KText reactorHostText = _kContainerRenderingExtensions.addText(childContainer, _utilityExtensions.toText(reactorInstance.getDefinition().getHost()));
DiagramSyntheses.suppressSelectability(reactorHostText);
_linguaFrancaStyleExtensions.underlineSelectionStyle(reactorHostText);
setGridPlacementDataFromPointToPoint(reactorHostText, LEFT, 3, 0, TOP, 0, 0, RIGHT, 0, 0, BOTTOM, 0, 0);
placement.setNumColumns(3);
}
}
if (reactorInstance.isBank()) {
List<KRendering> bank = new ArrayList<>();
KContainerRendering container = _kRenderingExtensions.addInvisibleContainerRendering(node);
// TODO handle unresolved width
KRoundedRectangle banks;
banks = _kContainerRenderingExtensions.addRoundedRectangle(container, 8, 8, 1);
style.apply(banks);
setGridPlacementDataFromPointToPoint(banks, LEFT, BANK_FIGURE_X_OFFSET_SUM, 0, TOP, BANK_FIGURE_Y_OFFSET_SUM, 0, RIGHT, 0, 0, BOTTOM, 0, 0);
if (reactorInstance.getWidth() == 3) {
banks = _kContainerRenderingExtensions.addRoundedRectangle(container, 8, 8, 1);
style.apply(banks);
setGridPlacementDataFromPointToPoint(banks, LEFT, BANK_FIGURE_X_OFFSET_SUM / 2, 0, TOP, BANK_FIGURE_Y_OFFSET_SUM / 2, 0, RIGHT, BANK_FIGURE_X_OFFSET_SUM / 2, 0, BOTTOM, BANK_FIGURE_Y_OFFSET_SUM / 2, 0);
} else if (reactorInstance.getWidth() != 2 && reactorInstance.getWidth() != 3) {
banks = _kContainerRenderingExtensions.addRoundedRectangle(container, 8, 8, 1);
style.apply(banks);
setGridPlacementDataFromPointToPoint(banks, LEFT, 2 * BANK_FIGURE_X_OFFSET_SUM / 3, 0, TOP, 2 * BANK_FIGURE_Y_OFFSET_SUM / 3, 0, RIGHT, BANK_FIGURE_X_OFFSET_SUM / 3, 0, BOTTOM, BANK_FIGURE_Y_OFFSET_SUM / 3, 0);
banks = _kContainerRenderingExtensions.addRoundedRectangle(container, 8, 8, 1);
style.apply(banks);
setGridPlacementDataFromPointToPoint(banks, LEFT, BANK_FIGURE_X_OFFSET_SUM / 3, 0, TOP, BANK_FIGURE_Y_OFFSET_SUM / 3, 0, RIGHT, 2 * BANK_FIGURE_X_OFFSET_SUM / 3, 0, BOTTOM, 2 * BANK_FIGURE_Y_OFFSET_SUM / 3, 0);
}
container.getChildren().add(figure);
setGridPlacementDataFromPointToPoint(figure, LEFT, 0, 0, TOP, 0, 0, RIGHT, BANK_FIGURE_X_OFFSET_SUM, 0, BOTTOM, BANK_FIGURE_Y_OFFSET_SUM, 0);
bank.addAll(container.getChildren());
KRectangle widthLabelContainer = _kContainerRenderingExtensions.addRectangle(container);
_kRenderingExtensions.setInvisible(widthLabelContainer, true);
setGridPlacementDataFromPointToPoint(widthLabelContainer, LEFT, 12, 0, BOTTOM, 9, 0, RIGHT, 6, 0, BOTTOM, 0.5f, 0);
// Handle unresolved width.
String widthLabel = reactorInstance.getWidth() >= 0 ? Integer.toString(reactorInstance.getWidth()) : "?";
KText widthLabelText = _kContainerRenderingExtensions.addText(widthLabelContainer, widthLabel);
_kRenderingExtensions.setHorizontalAlignment(widthLabelText, HorizontalAlignment.LEFT);
_kRenderingExtensions.setVerticalAlignment(widthLabelText, VerticalAlignment.BOTTOM);
_kRenderingExtensions.setFontSize(widthLabelText, 6);
_linguaFrancaStyleExtensions.noSelectionStyle(widthLabelText);
associateWith(widthLabelText, reactorInstance.getDefinition().getWidthSpec());
return new ReactorFigureComponents(container, figure, bank);
} else {
return new ReactorFigureComponents(figure, figure, List.of(figure));
}
}
Aggregations