use of org.lflang.graph.InstantiationGraph in project lingua-franca by lf-lang.
the class GeneratorBase method setReactorsAndInstantiationGraph.
/**
* Create a new instantiation graph. This is a graph where each node is a Reactor (not a ReactorInstance)
* and an arc from Reactor A to Reactor B means that B contains an instance of A, constructed with a statement
* like `a = new A();` After creating the graph,
* sort the reactors in topological order and assign them to the reactors class variable.
* Hence, after this method returns, `this.reactors` will be a list of Reactors such that any
* reactor is preceded in the list by reactors that it instantiates.
*/
protected void setReactorsAndInstantiationGraph(LFGeneratorContext.Mode mode) {
// Build the instantiation graph .
instantiationGraph = new InstantiationGraph(fileConfig.resource, false);
// Topologically sort the reactors such that all of a reactor's instantiation dependencies occur earlier in
// the sorted list of reactors. This helps the code generator output code in the correct order.
// For example if `reactor Foo {bar = new Bar()}` then the definition of `Bar` has to be generated before
// the definition of `Foo`.
reactors = instantiationGraph.nodesInTopologicalOrder();
// list includes even reactors that are not instantiated anywhere.
if (mainDef == null || Objects.equal(mode, LFGeneratorContext.Mode.LSP_MEDIUM)) {
Iterable<EObject> nodes = IteratorExtensions.toIterable(fileConfig.resource.getAllContents());
for (Reactor r : IterableExtensions.filter(nodes, Reactor.class)) {
if (!reactors.contains(r)) {
reactors.add(r);
}
}
}
}
use of org.lflang.graph.InstantiationGraph in project lingua-franca by lf-lang.
the class GeneratorBase method doGenerate.
/**
* Generate code from the Lingua Franca model contained by the specified resource.
*
* This is the main entry point for code generation. This base class finds all
* reactor class definitions, including any reactors defined in imported .lf files
* (except any main reactors in those imported files), and adds them to the
* {@link #GeneratorBase.reactors reactors} list. If errors occur during
* generation, then a subsequent call to errorsOccurred() will return true.
* @param resource The resource containing the source code.
* @param context Context relating to invocation of the code generator.
* In stand alone mode, this object is also used to relay CLI arguments.
*/
public void doGenerate(Resource resource, LFGeneratorContext context) {
GeneratorUtils.setTargetConfig(context, GeneratorUtils.findTarget(fileConfig.resource), targetConfig, errorReporter);
cleanIfNeeded(context);
printInfo(context.getMode());
// Markers mark problems in the Eclipse IDE when running in integrated mode.
if (errorReporter instanceof EclipseErrorReporter) {
((EclipseErrorReporter) errorReporter).clearMarkers();
}
ASTUtils.setMainName(fileConfig.resource, fileConfig.name);
createMainInstantiation();
// Check if there are any conflicting main reactors elsewhere in the package.
if (Objects.equal(context.getMode(), LFGeneratorContext.Mode.STANDALONE) && mainDef != null) {
for (String conflict : new MainConflictChecker(fileConfig).conflicts) {
errorReporter.reportError(this.mainDef.getReactorClass(), "Conflicting main reactor in " + conflict);
}
}
// Configure the command factory
commandFactory.setVerbose();
if (Objects.equal(context.getMode(), LFGeneratorContext.Mode.STANDALONE) && context.getArgs().containsKey("quiet")) {
commandFactory.setQuiet();
}
// This must be done before desugaring delays below.
analyzeFederates(context);
// Process target files. Copy each of them into the src-gen dir.
// FIXME: Should we do this here? This doesn't make sense for federates the way it is
// done here.
copyUserFiles(this.targetConfig, this.fileConfig);
// Collect reactors and create an instantiation graph.
// These are needed to figure out which resources we need
// to validate, which happens in setResources().
setReactorsAndInstantiationGraph(context.getMode());
GeneratorUtils.validate(context, fileConfig, instantiationGraph, errorReporter);
List<Resource> allResources = GeneratorUtils.getResources(reactors);
resources.addAll(// FIXME: This filter reproduces the behavior of the method it replaces. But why must it be so complicated? Why are we worried about weird corner cases like this?
allResources.stream().filter(it -> !Objects.equal(it, fileConfig.resource) || mainDef != null && it == mainDef.getReactorClass().eResource()).map(it -> GeneratorUtils.getLFResource(it, fileConfig.getSrcGenBasePath(), context, errorReporter)).collect(Collectors.toList()));
GeneratorUtils.accommodatePhysicalActionsIfPresent(allResources, getTarget().setsKeepAliveOptionAutomatically(), targetConfig, errorReporter);
// FIXME: Should the GeneratorBase pull in `files` from imported
// resources?
// Reroute connections that have delays associated with them via
// generated delay reactors.
transformDelays();
// Transform connections that reside in mutually exclusive modes and are otherwise conflicting
// This should be done before creating the instantiation graph
transformConflictingConnectionsInModalReactors();
// Invoke these functions a second time because transformations
// may have introduced new reactors!
setReactorsAndInstantiationGraph(context.getMode());
// Check for existence and support of modes
hasModalReactors = IterableExtensions.exists(reactors, it -> !it.getModes().isEmpty());
checkModalReactorSupport(false);
enableSupportForSerializationIfApplicable(context.getCancelIndicator());
}
use of org.lflang.graph.InstantiationGraph in project lingua-franca by lf-lang.
the class ModelInfo method update.
/**
* Redo all analysis based on the given model.
*
* @param model the model to analyze.
*/
public void update(Model model, ErrorReporter reporter) {
this.updated = true;
this.model = model;
this.instantiationGraph = new InstantiationGraph(model, true);
if (this.instantiationGraph.getCycles().size() == 0) {
List<ReactorInstance> topLevelReactorInstances = new LinkedList<>();
var main = model.getReactors().stream().filter(it -> it.isMain() || it.isFederated()).findFirst();
if (main.isPresent()) {
var inst = new ReactorInstance(main.get(), reporter);
topLevelReactorInstances.add(inst);
} else {
model.getReactors().forEach(it -> topLevelReactorInstances.add(new ReactorInstance(it, reporter)));
}
// don't store the graph into a field, only the cycles.
for (ReactorInstance top : topLevelReactorInstances) {
this.topologyCycles.addAll(top.getCycles());
}
}
// may be null if the target is invalid
var target = Target.forName(model.getTarget().getName()).orElse(null);
// Perform C-specific traversals.
if (target == Target.C) {
this.collectOverflowingNodes();
}
}
Aggregations