use of org.lflang.lf.VarRef in project lingua-franca by lf-lang.
the class ASTUtils method hasMultipleConnections.
/**
* Return true if the connection involves multiple ports on the left or right side of the connection, or
* if the port on the left or right of the connection involves a bank of reactors or a multiport.
* @param connection The connection.
*/
public static boolean hasMultipleConnections(Connection connection) {
if (connection.getLeftPorts().size() > 1 || connection.getRightPorts().size() > 1) {
return true;
}
VarRef leftPort = connection.getLeftPorts().get(0);
VarRef rightPort = connection.getRightPorts().get(0);
Instantiation leftContainer = leftPort.getContainer();
Instantiation rightContainer = rightPort.getContainer();
Port leftPortAsPort = (Port) leftPort.getVariable();
Port rightPortAsPort = (Port) rightPort.getVariable();
if (leftPortAsPort.getWidthSpec() != null || (leftContainer != null && leftContainer.getWidthSpec() != null) || rightPortAsPort.getWidthSpec() != null || (rightContainer != null && rightContainer.getWidthSpec() != null)) {
return true;
}
return false;
}
use of org.lflang.lf.VarRef in project lingua-franca by lf-lang.
the class ASTUtils method rerouteViaDelay.
/**
* Take a connection and reroute it via an instance of a generated delay
* reactor. This method returns a list to new connections to substitute
* the original one.
* @param connection The connection to reroute.
* @param delayInstance The delay instance to route the connection through.
*/
private static List<Connection> rerouteViaDelay(Connection connection, Instantiation delayInstance) {
List<Connection> connections = new ArrayList<>();
Connection upstream = factory.createConnection();
Connection downstream = factory.createConnection();
VarRef input = factory.createVarRef();
VarRef output = factory.createVarRef();
Reactor delayClass = toDefinition(delayInstance.getReactorClass());
// Establish references to the involved ports.
input.setContainer(delayInstance);
input.setVariable(delayClass.getInputs().get(0));
output.setContainer(delayInstance);
output.setVariable(delayClass.getOutputs().get(0));
upstream.getLeftPorts().addAll(connection.getLeftPorts());
upstream.getRightPorts().add(input);
downstream.getLeftPorts().add(output);
downstream.getRightPorts().addAll(connection.getRightPorts());
downstream.setIterated(connection.isIterated());
connections.add(upstream);
connections.add(downstream);
return connections;
}
use of org.lflang.lf.VarRef in project lingua-franca by lf-lang.
the class PythonReactionGenerator method generateCPythonInitializers.
/**
* Generate necessary Python-specific initialization code for <code>reaction<code> that belongs to reactor
* <code>decl<code>.
*
* @param reaction The reaction to generate Python-specific initialization for.
* @param decl The reactor to which <code>reaction<code> belongs to.
* @param pyObjectDescriptor For each port object created, a Python-specific descriptor will be added to this that
* then can be used as an argument to <code>Py_BuildValue<code>
* (@see <a href="https://docs.python.org/3/c-api/arg.html#c.Py_BuildValue">docs.python.org/3/c-api</a>).
* @param pyObjects A "," delimited list of expressions that would be (or result in a creation of) a PyObject.
*/
private static String generateCPythonInitializers(Reaction reaction, ReactorDecl decl, List<String> pyObjects, ErrorReporter errorReporter) {
Set<Action> actionsAsTriggers = new LinkedHashSet<>();
Reactor reactor = ASTUtils.toDefinition(decl);
CodeBuilder code = new CodeBuilder();
// TODO: handle triggers
for (TriggerRef trigger : ASTUtils.convertToEmptyListIfNull(reaction.getTriggers())) {
if (trigger instanceof VarRef) {
VarRef triggerAsVarRef = (VarRef) trigger;
code.pr(generateVariableToSendPythonReaction(triggerAsVarRef, actionsAsTriggers, decl, pyObjects));
}
}
if (reaction.getTriggers() == null || reaction.getTriggers().size() == 0) {
// NOTE: this does not include contained outputs.
for (Input input : reactor.getInputs()) {
PythonPortGenerator.generateInputVariablesToSendToPythonReaction(pyObjects, input, decl);
}
}
// Next add non-triggering inputs.
for (VarRef src : ASTUtils.convertToEmptyListIfNull(reaction.getSources())) {
code.pr(generateVariableToSendPythonReaction(src, actionsAsTriggers, decl, pyObjects));
}
// Next, handle effects
if (reaction.getEffects() != null) {
for (VarRef effect : reaction.getEffects()) {
if (effect.getVariable() instanceof Action) {
// If it has already appeared as trigger, do not redefine it.
if (!actionsAsTriggers.contains(effect.getVariable())) {
PythonPortGenerator.generateActionVariableToSendToPythonReaction(pyObjects, (Action) effect.getVariable(), decl);
}
} else {
if (effect.getVariable() instanceof Output) {
PythonPortGenerator.generateOutputVariablesToSendToPythonReaction(pyObjects, (Output) effect.getVariable());
} else if (effect.getVariable() instanceof Input) {
// It is the input of a contained reactor.
code.pr(PythonPortGenerator.generateVariablesForSendingToContainedReactors(pyObjects, effect.getContainer(), (Input) effect.getVariable()));
} else {
errorReporter.reportError(reaction, "In generateReaction(): " + effect.getVariable().getName() + " is neither an input nor an output.");
}
}
}
}
return code.toString();
}
use of org.lflang.lf.VarRef in project lingua-franca by lf-lang.
the class PythonReactionGenerator method generatePythonReactionParametersAndInitializations.
/**
* Generate parameters and their respective initialization code for a reaction function
* The initialization code is put at the beginning of the reaction before user code
* @param parameters The parameters used for function definition
* @param inits The initialization code for those paramters
* @param decl Reactor declaration
* @param reaction The reaction to be used to generate parameters for
*/
public static void generatePythonReactionParametersAndInitializations(List<String> parameters, CodeBuilder inits, ReactorDecl decl, Reaction reaction) {
Reactor reactor = ASTUtils.toDefinition(decl);
LinkedHashSet<String> generatedParams = new LinkedHashSet<>();
// Handle triggers
for (TriggerRef trigger : ASTUtils.convertToEmptyListIfNull(reaction.getTriggers())) {
if (!(trigger instanceof VarRef)) {
continue;
}
VarRef triggerAsVarRef = (VarRef) trigger;
if (triggerAsVarRef.getVariable() instanceof Port) {
if (triggerAsVarRef.getVariable() instanceof Input) {
if (((Input) triggerAsVarRef.getVariable()).isMutable()) {
generatedParams.add("mutable_" + triggerAsVarRef.getVariable().getName() + "");
// Create a deep copy
if (ASTUtils.isMultiport((Input) triggerAsVarRef.getVariable())) {
inits.pr(triggerAsVarRef.getVariable().getName() + " = [Make() for i in range(len(mutable_" + triggerAsVarRef.getVariable().getName() + "))]");
inits.pr("for i in range(len(mutable_" + triggerAsVarRef.getVariable().getName() + ")):");
inits.pr(" " + triggerAsVarRef.getVariable().getName() + "[i].value = copy.deepcopy(mutable_" + triggerAsVarRef.getVariable().getName() + "[i].value)");
} else {
inits.pr(triggerAsVarRef.getVariable().getName() + " = Make()");
inits.pr(triggerAsVarRef.getVariable().getName() + ".value = copy.deepcopy(mutable_" + triggerAsVarRef.getVariable().getName() + ".value)");
}
} else {
generatedParams.add(triggerAsVarRef.getVariable().getName());
}
} else {
// Handle contained reactors' ports
generatedParams.add(triggerAsVarRef.getContainer().getName() + "_" + triggerAsVarRef.getVariable().getName());
inits.pr(PythonPortGenerator.generatePythonPortVariableInReaction(triggerAsVarRef));
}
} else if (triggerAsVarRef.getVariable() instanceof Action) {
generatedParams.add(triggerAsVarRef.getVariable().getName());
}
}
// Handle non-triggering inputs
if (reaction.getTriggers() == null || reaction.getTriggers().size() == 0) {
for (Input input : ASTUtils.convertToEmptyListIfNull(reactor.getInputs())) {
generatedParams.add(input.getName());
if (input.isMutable()) {
// Create a deep copy
inits.pr(input.getName() + " = copy.deepcopy(" + input.getName() + ")");
}
}
}
for (VarRef src : ASTUtils.convertToEmptyListIfNull(reaction.getSources())) {
if (src.getVariable() instanceof Output) {
// Output of a contained reactor
generatedParams.add(src.getContainer().getName() + "_" + src.getVariable().getName());
inits.pr(PythonPortGenerator.generatePythonPortVariableInReaction(src));
} else {
generatedParams.add(src.getVariable().getName());
if (src.getVariable() instanceof Input) {
if (((Input) src.getVariable()).isMutable()) {
// Create a deep copy
inits.pr(src.getVariable().getName() + " = copy.deepcopy(" + src.getVariable().getName() + ")");
}
}
}
}
// Handle effects
for (VarRef effect : ASTUtils.convertToEmptyListIfNull(reaction.getEffects())) {
if (effect.getVariable() instanceof Input) {
generatedParams.add(effect.getContainer().getName() + "_" + effect.getVariable().getName());
inits.pr(PythonPortGenerator.generatePythonPortVariableInReaction(effect));
} else {
generatedParams.add(effect.getVariable().getName());
if (effect.getVariable() instanceof Port) {
if (ASTUtils.isMultiport((Port) effect.getVariable())) {
// Handle multiports
}
}
}
}
for (String s : generatedParams) {
parameters.add(s);
}
}
use of org.lflang.lf.VarRef in project lingua-franca by lf-lang.
the class ReactorInstance method listPortInstances.
/**
* Given a list of port references, as found on either side of a connection,
* return a list of the port instance ranges referenced. These may be multiports,
* and may be ports of a contained bank (a port representing ports of the bank
* members) so the returned list includes ranges of banks and channels.
*
* If a given port reference has the form `interleaved(b.m)`, where `b` is
* a bank and `m` is a multiport, then the corresponding range in the returned
* list is marked interleaved.
*
* For example, if `b` and `m` have width 2, without the interleaved keyword,
* the returned range represents the sequence `[b0.m0, b0.m1, b1.m0, b1.m1]`.
* With the interleaved marking, the returned range represents the sequence
* `[b0.m0, b1.m0, b0.m1, b1.m1]`. Both ranges will have width 4.
*
* @param references The variable references on one side of the connection.
* @param connection The connection.
*/
private List<RuntimeRange<PortInstance>> listPortInstances(List<VarRef> references, Connection connection) {
List<RuntimeRange<PortInstance>> result = new ArrayList<RuntimeRange<PortInstance>>();
List<RuntimeRange<PortInstance>> tails = new LinkedList<RuntimeRange<PortInstance>>();
int count = 0;
for (VarRef portRef : references) {
// Simple error checking first.
if (!(portRef.getVariable() instanceof Port)) {
reporter.reportError(portRef, "Not a port.");
return result;
}
// First, figure out which reactor we are dealing with.
// The reactor we want is the container of the port.
// If the port reference has no container, then the reactor is this one.
var reactor = this;
if (portRef.getContainer() != null) {
reactor = getChildReactorInstance(portRef.getContainer());
}
// Skip this portRef so that diagram synthesis can complete.
if (reactor != null) {
PortInstance portInstance = reactor.lookupPortInstance((Port) portRef.getVariable());
Set<ReactorInstance> interleaved = new LinkedHashSet<ReactorInstance>();
if (portRef.isInterleaved()) {
// NOTE: Here, we are assuming that the interleaved()
// keyword is only allowed on the multiports contained by
// contained reactors.
interleaved.add(portInstance.parent);
}
RuntimeRange<PortInstance> range = new RuntimeRange.Port(portInstance, interleaved);
// in the hierarchy.
if (count < references.size() - 1) {
int portWidth = portInstance.width;
int portParentWidth = portInstance.parent.width;
int widthBound = portWidth * portParentWidth;
// If either of these widths cannot be determined, assume infinite.
if (portWidth < 0)
widthBound = Integer.MAX_VALUE;
if (portParentWidth < 0)
widthBound = Integer.MAX_VALUE;
if (widthBound < range.width) {
// Need to split the range.
tails.add(range.tail(widthBound));
range = range.head(widthBound);
}
}
result.add(range);
}
}
// Iterate over the tails.
while (tails.size() > 0) {
List<RuntimeRange<PortInstance>> moreTails = new LinkedList<RuntimeRange<PortInstance>>();
count = 0;
for (RuntimeRange<PortInstance> tail : tails) {
if (count < tails.size() - 1) {
int widthBound = tail.instance.width;
if (tail._interleaved.contains(tail.instance.parent)) {
widthBound = tail.instance.parent.width;
}
// If the width cannot be determined, assume infinite.
if (widthBound < 0)
widthBound = Integer.MAX_VALUE;
if (widthBound < tail.width) {
// Need to split the range again
moreTails.add(tail.tail(widthBound));
tail = tail.head(widthBound);
}
}
result.add(tail);
}
tails = moreTails;
}
return result;
}
Aggregations