use of org.lflang.generator.CodeBuilder in project lingua-franca by lf-lang.
the class PythonPortGenerator method generateVariablesForSendingToContainedReactors.
/**
* Generate into the specified string builder the code to
* pass local variables for sending data to an input
* of a contained reaction (e.g. for a deadline violation).
* @param builder The string builder.
* @param definition AST node defining the reactor within which this occurs
* @param input Input of the contained reactor.
*/
public static String generateVariablesForSendingToContainedReactors(List<String> pyObjects, Instantiation definition, Port port) {
CodeBuilder code = new CodeBuilder();
if (definition.getWidthSpec() != null) {
String widthSpec = NONMULTIPORT_WIDTHSPEC;
if (ASTUtils.isMultiport(port)) {
widthSpec = "self->_lf_" + definition.getName() + "[i]." + generateWidthVariable(port.getName());
}
// Contained reactor is a bank.
// Create a Python list
code.pr(generatePythonListForContainedBank(definition.getName(), port, widthSpec));
pyObjects.add(definition.getName() + "_py_list");
} else {
if (ASTUtils.isMultiport(port)) {
pyObjects.add(generateConvertCPortToPy(definition.getName() + "." + port.getName()));
} else {
pyObjects.add(generateConvertCPortToPy(definition.getName() + "." + port.getName(), NONMULTIPORT_WIDTHSPEC));
}
}
return code.toString();
}
use of org.lflang.generator.CodeBuilder 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.generator.CodeBuilder in project lingua-franca by lf-lang.
the class PythonReactionGenerator method generateCReaction.
/**
* Generate the reaction in the .c file, which calls the Python reaction through the CPython interface.
*
* @param reaction The reaction to generate Python-specific initialization for.
* @param decl The reactor to which <code>reaction<code> belongs to.
* @param reactionIndex The index number of the reaction in decl.
* @param mainDef The main reactor.
* @param errorReporter An error reporter.
* @param types A helper class for type-related stuff.
* @param isFederatedAndDecentralized True if program is federated and coordination type is decentralized.
*/
public static String generateCReaction(Reaction reaction, ReactorDecl decl, int reactionIndex, Instantiation mainDef, ErrorReporter errorReporter, CTypes types, boolean isFederatedAndDecentralized) {
// Contains the actual comma separated list of inputs to the reaction of type generic_port_instance_struct or generic_port_instance_with_token_struct.
// Each input must be cast to (PyObject *) (aka their descriptors for Py_BuildValue are "O")
List<String> pyObjects = new ArrayList<>();
CodeBuilder code = new CodeBuilder();
code.pr(generateCReactionFunctionHeader(decl, reactionIndex) + " {");
code.indent();
code.pr(CReactionGenerator.generateInitializationForReaction("", reaction, decl, reactionIndex, types, errorReporter, mainDef, isFederatedAndDecentralized, Target.Python.requiresTypes));
code.prSourceLineNumber(reaction.getCode());
code.pr(generateCPythonReactionCaller(decl, reactionIndex, pyObjects, generateCPythonInitializers(reaction, decl, pyObjects, errorReporter)));
code.unindent();
code.pr("}");
// Now generate code for the deadline violation function, if there is one.
if (reaction.getDeadline() != null) {
code.pr(generateCDeadlineFunctionHeader(decl, reactionIndex) + " {");
code.indent();
code.pr(CReactionGenerator.generateInitializationForReaction("", reaction, decl, reactionIndex, types, errorReporter, mainDef, isFederatedAndDecentralized, Target.Python.requiresTypes));
code.pr(generateCPythonDeadlineCaller(decl, reactionIndex, pyObjects));
code.unindent();
code.pr("}");
}
return code.toString();
}
use of org.lflang.generator.CodeBuilder in project lingua-franca by lf-lang.
the class PythonReactionGenerator method generateCPythonReactionLinkers.
/**
* Generate Python code to link cpython functions to python functions for each reaction.
* @param instance The reactor instance.
* @param reactions The reactions of this instance.
* @param mainDef The definition of the main reactor
* @param topLevelName The name of the module
*/
public static String generateCPythonReactionLinkers(ReactorInstance instance, Instantiation mainDef, String topLevelName) {
String nameOfSelfStruct = CUtil.reactorRef(instance);
Reactor reactor = ASTUtils.toDefinition(instance.getDefinition().getReactorClass());
CodeBuilder code = new CodeBuilder();
// Delay reactors and top-level reactions used in the top-level reactor(s) in federated execution are generated in C
if (reactor.getName().contains(GeneratorBase.GEN_DELAY_CLASS_NAME) || instance.getDefinition().getReactorClass() == (mainDef != null ? mainDef.getReactorClass() : null) && reactor.isFederated()) {
return "";
}
// Initialize the name field to the unique name of the instance
code.pr(nameOfSelfStruct + "->_lf_name = \"" + instance.uniqueID() + "_lf\";");
for (ReactionInstance reaction : instance.reactions) {
// Create a PyObject for each reaction
code.pr(generateCPythonReactionLinker(instance, reaction, topLevelName, nameOfSelfStruct));
}
return code.toString();
}
use of org.lflang.generator.CodeBuilder in project lingua-franca by lf-lang.
the class PythonReactionGenerator method generatePythonFunction.
/**
* Generate the function that is executed whenever the deadline of the reaction
* with the given reaction index is missed
* @param reaction The reaction to generate deadline miss code for
* @param reactionIndex The agreed-upon index of the reaction in the reactor (should match the C generated code)
* @param reactionParameters The parameters to the deadline violation function, which are the same as the reaction function
*/
public static String generatePythonFunction(String pythonFunctionName, String inits, String reactionBody, List<String> reactionParameters) {
String params = reactionParameters.size() > 0 ? ", " + String.join(", ", reactionParameters) : "";
CodeBuilder code = new CodeBuilder();
code.pr("def " + pythonFunctionName + "(self" + params + "):");
code.indent();
code.pr(inits);
code.pr(reactionBody);
code.pr("return 0");
return code.toString();
}
Aggregations