use of org.lflang.lf.Reaction in project lingua-franca by lf-lang.
the class LFValidator method checkConnection.
@Check(CheckType.FAST)
public void checkConnection(Connection connection) {
// Report if connection is part of a cycle.
Set<NamedInstance<?>> cycles = this.info.topologyCycles();
for (VarRef lp : connection.getLeftPorts()) {
for (VarRef rp : connection.getRightPorts()) {
boolean leftInCycle = false;
for (NamedInstance<?> it : cycles) {
if ((lp.getContainer() == null && it.getDefinition().equals(lp.getVariable())) || (it.getDefinition().equals(lp.getVariable()) && it.getParent().equals(lp.getContainer()))) {
leftInCycle = true;
break;
}
}
for (NamedInstance<?> it : cycles) {
if ((rp.getContainer() == null && it.getDefinition().equals(rp.getVariable())) || (it.getDefinition().equals(rp.getVariable()) && it.getParent().equals(rp.getContainer()))) {
if (leftInCycle) {
Reactor reactor = ASTUtils.getEnclosingReactor(connection);
String reactorName = reactor.getName();
error(String.format("Connection in reactor %s creates", reactorName) + String.format("a cyclic dependency between %s and %s.", toText(lp), toText(rp)), Literals.CONNECTION__DELAY);
}
}
}
}
}
// we leave type compatibility that language's compiler or interpreter.
if (isCBasedTarget()) {
Type type = (Type) null;
for (VarRef port : connection.getLeftPorts()) {
// error. Avoid a class cast exception.
if (port.getVariable() instanceof Port) {
if (type == null) {
type = ((Port) port.getVariable()).getType();
} else {
// method for AST types, so we have to manually check the types.
if (!sameType(type, ((Port) port.getVariable()).getType())) {
error("Types do not match.", Literals.CONNECTION__LEFT_PORTS);
}
}
}
}
for (VarRef port : connection.getRightPorts()) {
// error. Avoid a class cast exception.
if (port.getVariable() instanceof Port) {
if (type == null) {
type = ((Port) port.getVariable()).getType();
} else {
if (!sameType(type, type = ((Port) port.getVariable()).getType())) {
error("Types do not match.", Literals.CONNECTION__RIGHT_PORTS);
}
}
}
}
}
// Check whether the total width of the left side of the connection
// matches the total width of the right side. This cannot be determined
// here if the width is not given as a constant. In that case, it is up
// to the code generator to check it.
int leftWidth = 0;
for (VarRef port : connection.getLeftPorts()) {
// null args imply incomplete check.
int width = inferPortWidth(port, null, null);
if (width < 0 || leftWidth < 0) {
// Cannot determine the width of the left ports.
leftWidth = -1;
} else {
leftWidth += width;
}
}
int rightWidth = 0;
for (VarRef port : connection.getRightPorts()) {
// null args imply incomplete check.
int width = inferPortWidth(port, null, null);
if (width < 0 || rightWidth < 0) {
// Cannot determine the width of the left ports.
rightWidth = -1;
} else {
rightWidth += width;
}
}
if (leftWidth != -1 && rightWidth != -1 && leftWidth != rightWidth) {
if (connection.isIterated()) {
if (leftWidth == 0 || rightWidth % leftWidth != 0) {
// FIXME: The second argument should be Literals.CONNECTION, but
// stupidly, xtext will not accept that. There seems to be no way to
// report an error for the whole connection statement.
warning(String.format("Left width %s does not divide right width %s", leftWidth, rightWidth), Literals.CONNECTION__LEFT_PORTS);
}
} else {
// FIXME: The second argument should be Literals.CONNECTION, but
// stupidly, xtext will not accept that. There seems to be no way to
// report an error for the whole connection statement.
warning(String.format("Left width %s does not match right width %s", leftWidth, rightWidth), Literals.CONNECTION__LEFT_PORTS);
}
}
Reactor reactor = ASTUtils.getEnclosingReactor(connection);
// Make sure the right port is not already an effect of a reaction.
for (Reaction reaction : ASTUtils.allReactions(reactor)) {
for (VarRef effect : reaction.getEffects()) {
for (VarRef rightPort : connection.getRightPorts()) {
if (// Refers to the same variable
rightPort.getVariable().equals(effect.getVariable()) && // Refers to the same instance
rightPort.getContainer() == effect.getContainer() && (// Either is not part of a mode
reaction.eContainer() instanceof Reactor || connection.eContainer() instanceof Reactor || // Or they are in the same mode
connection.eContainer() == reaction.eContainer())) {
error("Cannot connect: Port named '" + effect.getVariable().getName() + "' is already effect of a reaction.", Literals.CONNECTION__RIGHT_PORTS);
}
}
}
}
// upstream connection.
for (Connection c : reactor.getConnections()) {
if (c != connection) {
for (VarRef thisRightPort : connection.getRightPorts()) {
for (VarRef thatRightPort : c.getRightPorts()) {
if (// Refers to the same variable
thisRightPort.getVariable().equals(thatRightPort.getVariable()) && // Refers to the same instance
thisRightPort.getContainer() == thatRightPort.getContainer() && (// Or either of the connections in not part of a mode
connection.eContainer() instanceof Reactor || c.eContainer() instanceof Reactor || // Or they are in the same mode
connection.eContainer() == c.eContainer())) {
error("Cannot connect: Port named '" + thisRightPort.getVariable().getName() + "' may only appear once on the right side of a connection.", Literals.CONNECTION__RIGHT_PORTS);
}
}
}
}
}
}
use of org.lflang.lf.Reaction in project lingua-franca by lf-lang.
the class PythonGenerator method generateSelfStructExtension.
/**
* This function is provided to allow extensions of the CGenerator to append the structure of the self struct
* @param selfStructBody The body of the self struct
* @param decl The reactor declaration for the self struct
* @param instance The current federate instance
* @param constructorCode Code that is executed when the reactor is instantiated
*/
@Override
public void generateSelfStructExtension(CodeBuilder selfStructBody, ReactorDecl decl, CodeBuilder constructorCode) {
Reactor reactor = ASTUtils.toDefinition(decl);
// Add the name field
selfStructBody.pr("char *_lf_name;");
int reactionIndex = 0;
for (Reaction reaction : ASTUtils.allReactions(reactor)) {
// Create a PyObject for each reaction
selfStructBody.pr("PyObject* " + PythonReactionGenerator.generateCPythonReactionFunctionName(reactionIndex) + ";");
if (reaction.getDeadline() != null) {
selfStructBody.pr("PyObject* " + PythonReactionGenerator.generateCPythonDeadlineFunctionName(reactionIndex) + ";");
}
reactionIndex++;
}
}
use of org.lflang.lf.Reaction in project lingua-franca by lf-lang.
the class PythonReactionGenerator method generatePythonReactions.
/**
* Generate the Python code for reactions in reactor
* @param reactor The reactor
* @param reactions The reactions of reactor
*/
public static String generatePythonReactions(Reactor reactor, List<Reaction> reactions) {
CodeBuilder code = new CodeBuilder();
int reactionIndex = 0;
for (Reaction reaction : reactions) {
code.pr(generatePythonReaction(reactor, reaction, reactionIndex));
reactionIndex++;
}
return code.toString();
}
use of org.lflang.lf.Reaction in project lingua-franca by lf-lang.
the class ReactorInstance method createReactionInstances.
// ////////////////////////////////////////////////////
// // Protected methods.
/**
* Create all the reaction instances of this reactor instance
* and record the dependencies and antidependencies
* between ports, actions, and timers and reactions.
* This also records the dependencies between reactions
* that follows from the order in which they are defined.
*/
protected void createReactionInstances() {
List<Reaction> reactions = ASTUtils.allReactions(reactorDefinition);
if (reactions != null) {
int count = 0;
// Check for startup and shutdown triggers.
for (Reaction reaction : reactions) {
// Create the reaction instance.
var reactionInstance = new ReactionInstance(reaction, this, unorderedReactions.contains(reaction), count++);
// Add the reaction instance to the map of reactions for this
// reactor.
this.reactions.add(reactionInstance);
}
}
}
Aggregations