use of org.lflang.lf.VarRef in project lingua-franca by lf-lang.
the class CReactionGenerator method generateInitializationForReaction.
/**
* Generate necessary initialization code inside the body of the reaction that belongs to reactor decl.
* @param body The body of the reaction. Used to check for the DISABLE_REACTION_INITIALIZATION_MARKER.
* @param reaction The initialization code will be generated for this specific reaction
* @param decl The reactor that has the reaction
* @param reactionIndex The index of the reaction relative to other reactions in the reactor, starting from 0
*/
public static String generateInitializationForReaction(String body, Reaction reaction, ReactorDecl decl, int reactionIndex, CTypes types, ErrorReporter errorReporter, Instantiation mainDef, boolean isFederatedAndDecentralized, boolean requiresTypes) {
Reactor reactor = ASTUtils.toDefinition(decl);
// Construct the reactionInitialization code to go into
// the body of the function before the verbatim code.
CodeBuilder reactionInitialization = new CodeBuilder();
CodeBuilder code = new CodeBuilder();
// Define the "self" struct.
String structType = CUtil.selfType(decl);
// or anything else. No need to declare it.
if (structType != null) {
code.pr(String.join("\n", "#pragma GCC diagnostic push", "#pragma GCC diagnostic ignored \"-Wunused-variable\"", structType + "* self = (" + structType + "*)instance_args;"));
}
// to not generate it.
if (body.startsWith(CGenerator.DISABLE_REACTION_INITIALIZATION_MARKER)) {
code.pr("#pragma GCC diagnostic pop");
return code.toString();
}
// A reaction may send to or receive from multiple ports of
// a contained reactor. The variables for these ports need to
// all be declared as fields of the same struct. Hence, we first
// collect the fields to be defined in the structs and then
// generate the structs.
Map<Instantiation, CodeBuilder> fieldsForStructsForContainedReactors = new LinkedHashMap<>();
// Actions may appear twice, first as a trigger, then with the outputs.
// But we need to declare it only once. Collect in this data structure
// the actions that are declared as triggered so that if they appear
// again with the outputs, they are not defined a second time.
// That second redefinition would trigger a compile error.
Set<Action> actionsAsTriggers = new LinkedHashSet<>();
// defined so that they can be used in the verbatim code.
for (TriggerRef trigger : ASTUtils.convertToEmptyListIfNull(reaction.getTriggers())) {
if (trigger instanceof VarRef) {
VarRef triggerAsVarRef = (VarRef) trigger;
if (triggerAsVarRef.getVariable() instanceof Port) {
generatePortVariablesInReaction(reactionInitialization, fieldsForStructsForContainedReactors, triggerAsVarRef, decl, types);
} else if (triggerAsVarRef.getVariable() instanceof Action) {
reactionInitialization.pr(generateActionVariablesInReaction((Action) triggerAsVarRef.getVariable(), decl, types));
actionsAsTriggers.add((Action) triggerAsVarRef.getVariable());
}
}
}
if (reaction.getTriggers() == null || reaction.getTriggers().size() == 0) {
// NOTE: this does not include contained outputs.
for (Input input : reactor.getInputs()) {
reactionInitialization.pr(generateInputVariablesInReaction(input, decl, types));
}
}
// Define argument for non-triggering inputs.
for (VarRef src : ASTUtils.convertToEmptyListIfNull(reaction.getSources())) {
if (src.getVariable() instanceof Port) {
generatePortVariablesInReaction(reactionInitialization, fieldsForStructsForContainedReactors, src, decl, types);
} else if (src.getVariable() instanceof Action) {
// It's a bit odd to read but not be triggered by an action, but
// OK, I guess we allow it.
reactionInitialization.pr(generateActionVariablesInReaction((Action) src.getVariable(), decl, types));
actionsAsTriggers.add((Action) src.getVariable());
}
}
// value that may have been written to that output in an earlier reaction.
if (reaction.getEffects() != null) {
for (VarRef effect : reaction.getEffects()) {
Variable variable = effect.getVariable();
if (variable instanceof Action) {
// If it has already appeared as trigger, do not redefine it.
if (!actionsAsTriggers.contains(effect.getVariable())) {
reactionInitialization.pr(CGenerator.variableStructType(variable, decl) + "* " + variable.getName() + " = &self->_lf_" + variable.getName() + ";");
}
} else if (effect.getVariable() instanceof Mode) {
// Mode change effect
int idx = ASTUtils.allModes(reactor).indexOf((Mode) effect.getVariable());
String name = effect.getVariable().getName();
if (idx >= 0) {
reactionInitialization.pr("reactor_mode_t* " + name + " = &self->_lf__modes[" + idx + "];\n" + "char _lf_" + name + "_change_type = " + (ModeTransitionType.getModeTransitionType(effect) == ModeTransitionType.HISTORY ? 2 : 1) + ";");
} else {
errorReporter.reportError(reaction, "In generateReaction(): " + name + " not a valid mode of this reactor.");
}
} else {
if (variable instanceof Output) {
reactionInitialization.pr(generateOutputVariablesInReaction(effect, decl, errorReporter, requiresTypes));
} else if (variable instanceof Input) {
// It is the input of a contained reactor.
generateVariablesForSendingToContainedReactors(reactionInitialization, fieldsForStructsForContainedReactors, effect.getContainer(), (Input) variable);
} else {
errorReporter.reportError(reaction, "In generateReaction(): effect is neither an input nor an output.");
}
}
}
}
// generate the structs used for communication to and from contained reactors.
for (Instantiation containedReactor : fieldsForStructsForContainedReactors.keySet()) {
String array = "";
if (containedReactor.getWidthSpec() != null) {
String containedReactorWidthVar = generateWidthVariable(containedReactor.getName());
code.pr("int " + containedReactorWidthVar + " = self->_lf_" + containedReactorWidthVar + ";");
// Windows does not support variables in arrays declared on the stack,
// so we use the maximum size over all bank members.
array = "[" + maxContainedReactorBankWidth(containedReactor, null, 0, mainDef) + "]";
}
code.pr(String.join("\n", "struct " + containedReactor.getName() + " {", " " + fieldsForStructsForContainedReactors.get(containedReactor) + "", "} " + containedReactor.getName() + array + ";"));
}
// Next generate all the collected setup code.
code.pr(reactionInitialization.toString());
code.pr("#pragma GCC diagnostic pop");
if (reaction.getStp() == null) {
// Pass down the intended_tag to all input and output effects
// downstream if the current reaction does not have a STP
// handler.
code.pr(generateIntendedTagInheritence(body, reaction, decl, reactionIndex, types, isFederatedAndDecentralized));
}
return code.toString();
}
Aggregations