use of org.lflang.lf.Reactor 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();
}
use of org.lflang.lf.Reactor in project lingua-franca by lf-lang.
the class CUtil method deleteBinFiles.
/**
* Remove files in the bin directory that may have been created.
* Call this if a compilation occurs so that files from a previous
* version do not accidentally get executed.
* @param fileConfig
*/
public static void deleteBinFiles(FileConfig fileConfig) {
String name = FileUtil.nameWithoutExtension(fileConfig.srcFile);
String[] files = fileConfig.binPath.toFile().list();
// FIXME: put this in ASTUtils?
List<String> federateNames = new LinkedList<>();
fileConfig.resource.getAllContents().forEachRemaining(node -> {
if (node instanceof Reactor) {
Reactor r = (Reactor) node;
if (r.isFederated()) {
r.getInstantiations().forEach(inst -> federateNames.add(inst.getName()));
}
}
});
for (String f : files) {
// Delete RTI file, if any.
if (f.equals(name) || f.equals(name + RTI_BIN_SUFFIX) || f.equals(name + RTI_DISTRIBUTION_SCRIPT_SUFFIX)) {
// noinspection ResultOfMethodCallIgnored
fileConfig.binPath.resolve(f).toFile().delete();
}
// Delete federate executable files, if any.
for (String federateName : federateNames) {
if (f.equals(name + "_" + federateName)) {
// noinspection ResultOfMethodCallIgnored
fileConfig.binPath.resolve(f).toFile().delete();
}
}
}
}
use of org.lflang.lf.Reactor in project lingua-franca by lf-lang.
the class InstantiationGraph method buildGraph.
/**
* Traverse the AST and build this precedence graph relating the
* encountered instantiations. Also map each reactor to all
* declarations associated with it and each reactor to the sites of
* its instantiations.
*/
private void buildGraph(final Instantiation instantiation, final Set<Instantiation> visited) {
final ReactorDecl decl = instantiation.getReactorClass();
final Reactor reactor = ASTUtils.toDefinition(decl);
if (reactor != null) {
Reactor container = ASTUtils.getEnclosingReactor(instantiation);
if (visited.add(instantiation)) {
this.reactorToInstantiation.put(reactor, instantiation);
this.reactorToDecl.put(reactor, decl);
if (container != null) {
this.addEdge(container, reactor);
} else {
this.addNode(reactor);
}
for (final Instantiation inst : reactor.getInstantiations()) {
this.buildGraph(inst, visited);
}
}
}
}
use of org.lflang.lf.Reactor in project lingua-franca by lf-lang.
the class LFScopeProviderImpl method getScopeForVarRef.
protected IScope getScopeForVarRef(VarRef variable, EReference reference) {
if (reference == LfPackage.Literals.VAR_REF__VARIABLE) {
// Resolve hierarchical reference
Reactor reactor;
Mode mode = null;
if (variable.eContainer().eContainer() instanceof Reactor) {
reactor = (Reactor) variable.eContainer().eContainer();
} else if (variable.eContainer().eContainer() instanceof Mode) {
mode = (Mode) variable.eContainer().eContainer();
reactor = (Reactor) variable.eContainer().eContainer().eContainer();
} else {
return Scopes.scopeFor(emptyList());
}
RefType type = getRefType(variable);
if (variable.getContainer() != null) {
// Resolve hierarchical port reference
var instanceName = nameProvider.getFullyQualifiedName(variable.getContainer());
var instances = new ArrayList<Instantiation>(reactor.getInstantiations());
if (mode != null) {
instances.addAll(mode.getInstantiations());
}
if (instanceName != null) {
for (var instance : instances) {
var defn = toDefinition(instance.getReactorClass());
if (defn != null && instance.getName().equals(instanceName.toString())) {
switch(type) {
case TRIGGER:
case SOURCE:
case CLEFT:
return Scopes.scopeFor(allOutputs(defn));
case EFFECT:
case DEADLINE:
case CRIGHT:
return Scopes.scopeFor(allInputs(defn));
}
}
}
}
return Scopes.scopeFor(emptyList());
} else {
// Resolve local reference
switch(type) {
case TRIGGER:
{
var candidates = new ArrayList<EObject>();
if (mode != null) {
candidates.addAll(mode.getActions());
candidates.addAll(mode.getTimers());
}
candidates.addAll(allInputs(reactor));
candidates.addAll(allActions(reactor));
candidates.addAll(allTimers(reactor));
return Scopes.scopeFor(candidates);
}
case SOURCE:
return super.getScope(variable, reference);
case EFFECT:
{
var candidates = new ArrayList<EObject>();
if (mode != null) {
candidates.addAll(mode.getActions());
candidates.addAll(reactor.getModes());
}
candidates.addAll(allOutputs(reactor));
candidates.addAll(allActions(reactor));
return Scopes.scopeFor(candidates);
}
case DEADLINE:
case CLEFT:
return Scopes.scopeFor(allInputs(reactor));
case CRIGHT:
return Scopes.scopeFor(allOutputs(reactor));
default:
return Scopes.scopeFor(emptyList());
}
}
} else {
// Resolve instance
return super.getScope(variable, reference);
}
}
Aggregations