Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improved handling of files target property #2333

Merged
merged 8 commits into from
Jun 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,20 +1,10 @@
package org.lflang.federated.generator;

import static org.lflang.ast.ASTUtils.convertToEmptyListIfNull;

import java.nio.file.Path;
import java.util.List;
import java.util.Objects;
import org.eclipse.emf.ecore.resource.Resource;
import org.lflang.MessageReporter;
import org.lflang.ast.ASTUtils;
import org.lflang.generator.GeneratorUtils;
import org.lflang.generator.LFGeneratorContext;
import org.lflang.lf.KeyValuePair;
import org.lflang.target.Target;
import org.lflang.target.TargetConfig;
import org.lflang.target.property.FileListProperty;
import org.lflang.util.FileUtil;

/**
* Subclass of TargetConfig with a specialized constructor for creating configurations for
Expand Down Expand Up @@ -43,7 +33,7 @@ public FederateTargetConfig(LFGeneratorContext context, Resource federateResourc
load(federationResource, reporter);

// Load properties from the federate file
mergeImportedConfig(federateResource, federationResource, reporter);
mergeImportedConfig(federateResource, federationResource, p -> p.loadFromFederate(), reporter);

// Load properties from the generator context
load(context.getArgs(), reporter);
Expand All @@ -52,66 +42,4 @@ public FederateTargetConfig(LFGeneratorContext context, Resource federateResourc

this.validate(reporter);
}

/**
* If the federate that target configuration applies to is imported, merge target properties
* declared in the file that it was imported from.
*
* @param federateResource The resource where the class of the federate is specified.
* @param mainResource The resource in which the federation (i.e., main reactor) is specified.
* @param messageReporter An error reporter to use when problems are encountered.
*/
private void mergeImportedConfig(
Resource federateResource, Resource mainResource, MessageReporter messageReporter) {
// If the federate is imported, then update the configuration based on target properties
// in the imported file.
if (!federateResource.equals(mainResource)) {
var importedTargetDecl = GeneratorUtils.findTargetDecl(federateResource);
var targetProperties = importedTargetDecl.getConfig();
if (targetProperties != null) {
// Merge properties
update(
this,
convertToEmptyListIfNull(targetProperties.getPairs()),
getRelativePath(mainResource, federateResource),
messageReporter);
}
}
}

private Path getRelativePath(Resource source, Resource target) {
return FileUtil.toPath(source.getURI())
.getParent()
.relativize(FileUtil.toPath(target.getURI()).getParent());
}

/**
* Update the given configuration using the given target properties.
*
* @param config The configuration object to update.
* @param pairs AST node that holds all the target properties.
* @param relativePath The path from the main resource to the resource from which the new
* properties originate.
*/
public void update(
TargetConfig config, List<KeyValuePair> pairs, Path relativePath, MessageReporter err) {
pairs.forEach(
pair -> {
var p = config.forName(pair.getName());
if (p.isPresent()) {
var value = pair.getValue();
var property = p.get();
if (property instanceof FileListProperty fileListProperty) {
var files =
ASTUtils.elementToListOfStrings(value).stream()
.map(relativePath::resolve) // assume all paths are relative
.map(Objects::toString)
.toList();
fileListProperty.update(config, files);
} else if (property.loadFromFederate()) {
p.get().update(this, pair, err);
}
}
});
}
}
56 changes: 27 additions & 29 deletions core/src/main/java/org/lflang/generator/GeneratorBase.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,9 @@
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import org.eclipse.core.resources.IMarker;
import org.eclipse.emf.ecore.EObject;
Expand Down Expand Up @@ -80,18 +78,12 @@
*/
public abstract class GeneratorBase extends AbstractLFValidator {

////////////////////////////////////////////
//// Public fields.

/** The main (top-level) reactor instance. */
public ReactorInstance main;

/** An error reporter for reporting any errors or warnings during the code generation */
public MessageReporter messageReporter;

////////////////////////////////////////////
//// Protected fields.

/** The current target configuration. */
protected final TargetConfig targetConfig;

Expand Down Expand Up @@ -125,9 +117,6 @@ public Instantiation getMainDef() {
*/
protected List<Reactor> reactors = new ArrayList<>();

/** The set of resources referenced reactor classes reside in. */
protected Set<LFResource> resources = new LinkedHashSet<>(); // FIXME: Why do we need this?

/**
* Graph that tracks dependencies between instantiations. 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
Expand All @@ -147,9 +136,6 @@ public Instantiation getMainDef() {
/** Indicates whether the program has any watchdogs. This is used to check for support. */
public boolean hasWatchdogs = false;

// //////////////////////////////////////////
// // Private fields.

/** A list ot AST transformations to apply before code generation */
private final List<AstTransformation> astTransformations = new ArrayList<>();

Expand All @@ -170,8 +156,26 @@ protected void registerTransformation(AstTransformation transformation) {
astTransformations.add(transformation);
}

// //////////////////////////////////////////
// // Code generation functions to override for a concrete code generator.
/**
* If the given reactor is defined in another file, process its target properties so that they are
* reflected in the target configuration.
*/
private void loadTargetProperties(Resource resource) {
var mainFileConfig = this.context.getFileConfig();
if (resource != mainFileConfig.resource) {
this.context
.getTargetConfig()
.mergeImportedConfig(
LFGenerator.createFileConfig(
resource,
mainFileConfig.getSrcGenBasePath(),
mainFileConfig.useHierarchicalBin)
.resource,
mainFileConfig.resource,
p -> p.loadFromImport(),
this.messageReporter);
}
}

/**
* Generate code from the Lingua Franca model contained by the specified resource.
Expand Down Expand Up @@ -218,35 +222,29 @@ public void doGenerate(Resource resource, LFGeneratorContext 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, context.getFileConfig());

// 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());

List<Resource> allResources = GeneratorUtils.getResources(reactors);
resources.addAll(
allResources.stream().map(it -> GeneratorUtils.getLFResource(it, context)).toList());

GeneratorUtils.accommodatePhysicalActionsIfPresent(
allResources,
getTarget().setsKeepAliveOptionAutomatically(),
targetConfig,
messageReporter);
// FIXME: Should the GeneratorBase pull in {@code files} from imported
// resources?

// Load target properties for all resources.
allResources.forEach(r -> loadTargetProperties(r));

for (AstTransformation transformation : astTransformations) {
transformation.applyTransformation(reactors);
}

// Transform connections that reside in mutually exclusive modes and are otherwise conflicting
// This should be done before creating the instantiation graph
transformConflictingConnectionsInModalReactors();
transformConflictingConnectionsInModalReactors(allResources);

// Invoke these functions a second time because transformations
// may have introduced new reactors!
Expand Down Expand Up @@ -415,9 +413,9 @@ protected void checkWatchdogSupport(boolean isSupported) {
* Finds and transforms connections into forwarding reactions iff the connections have the same
* destination as other connections or reaction in mutually exclusive modes.
*/
private void transformConflictingConnectionsInModalReactors() {
for (LFResource r : resources) {
var transform = ASTUtils.findConflictingConnectionsInModalReactors(r.eResource);
private void transformConflictingConnectionsInModalReactors(List<Resource> resources) {
for (Resource r : resources) {
var transform = ASTUtils.findConflictingConnectionsInModalReactors(r);
if (!transform.isEmpty()) {
var factory = LfFactory.eINSTANCE;
for (Connection connection : transform) {
Expand Down
27 changes: 0 additions & 27 deletions core/src/main/java/org/lflang/generator/GeneratorUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,11 @@
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.xtext.xbase.lib.IteratorExtensions;
import org.lflang.FileConfig;
import org.lflang.MessageReporter;
import org.lflang.ast.ASTUtils;
import org.lflang.generator.LFGeneratorContext.Mode;
import org.lflang.lf.Action;
import org.lflang.lf.ActionOrigin;
import org.lflang.lf.Instantiation;
import org.lflang.lf.KeyValuePair;
import org.lflang.lf.KeyValuePairs;
import org.lflang.lf.Reactor;
import org.lflang.lf.TargetDecl;
import org.lflang.target.TargetConfig;
Expand Down Expand Up @@ -101,29 +97,6 @@ public static List<Resource> getResources(Iterable<Reactor> reactors) {
return resources;
}

/**
* Return the {@code LFResource} representation of the given resource.
*
* @param resource The {@code Resource} to be represented as an {@code LFResource}
* @param context The generator invocation context.
* @return the {@code LFResource} representation of the given resource.
*/
public static LFResource getLFResource(Resource resource, LFGeneratorContext context) {
var target = ASTUtils.targetDecl(resource);
var mainFileConfig = context.getFileConfig();
var messageReporter = context.getErrorReporter();
KeyValuePairs config = target.getConfig();
var targetConfig = new TargetConfig(resource, context.getArgs(), messageReporter);
if (config != null) {
List<KeyValuePair> pairs = config.getPairs();
targetConfig.load(pairs != null ? pairs : List.of(), messageReporter);
}
FileConfig fc =
LFGenerator.createFileConfig(
resource, mainFileConfig.getSrcGenBasePath(), mainFileConfig.useHierarchicalBin);
return new LFResource(resource, fc, targetConfig);
}

/**
* If the mode is Mode.EPOCH (the code generator is running in an Eclipse IDE), then refresh the
* project. This will ensure that any generated files become visible in the project.
Expand Down
47 changes: 0 additions & 47 deletions core/src/main/java/org/lflang/generator/LFResource.java

This file was deleted.

40 changes: 1 addition & 39 deletions core/src/main/java/org/lflang/generator/c/CGenerator.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@
import static org.lflang.ast.ASTUtils.allPorts;
import static org.lflang.ast.ASTUtils.allReactions;
import static org.lflang.ast.ASTUtils.allStateVars;
import static org.lflang.ast.ASTUtils.convertToEmptyListIfNull;
import static org.lflang.ast.ASTUtils.getInferredType;
import static org.lflang.ast.ASTUtils.isInitialized;
import static org.lflang.ast.ASTUtils.toDefinition;
Expand Down Expand Up @@ -61,7 +60,6 @@
import org.lflang.generator.GeneratorResult;
import org.lflang.generator.GeneratorUtils;
import org.lflang.generator.LFGeneratorContext;
import org.lflang.generator.LFResource;
import org.lflang.generator.ParameterInstance;
import org.lflang.generator.PortInstance;
import org.lflang.generator.ReactionInstance;
Expand Down Expand Up @@ -582,6 +580,7 @@ private void generateCodeFor(String lfModuleName) throws IOException {
code.pr(new CMainFunctionGenerator(targetConfig).generateCode());
// Generate code for each reactor.
generateReactorDefinitions();
copyUserFiles(targetConfig, fileConfig);

// Generate main instance, if there is one.
// Note that any main reactors in imported files are ignored.
Expand Down Expand Up @@ -691,42 +690,6 @@ private boolean hasDeadlines(List<Reactor> reactors) {
return false;
}

/**
* Look at the 'reactor' eResource. If it is an imported .lf file, gather preambles and relevant
* target properties associated with imported reactors.
*/
private void inspectReactorEResource(ReactorDecl reactor) {
// Check if the reactor definition is imported
if (reactor.eResource() != mainDef.getReactorClass().eResource()) {
// Find the LFResource corresponding to this eResource
LFResource lfResource = null;
for (var resource : resources) {
if (resource.getEResource() == reactor.eResource()) {
lfResource = resource;
break;
}
}

if (lfResource != null) {
var config = lfResource.getTargetConfig();
// FIXME: this should not happen here, but once, after collecting all the files.
copyUserFiles(config, lfResource.getFileConfig());

var pairs = convertToEmptyListIfNull(config.extractTargetDecl().getConfig().getPairs());
pairs.forEach(
pair -> {
var p = config.forName((pair.getName()));
if (p.isPresent()) {
var property = p.get();
if (property.loadFromImport()) {
property.update(this.targetConfig, pair, messageReporter);
}
}
});
}
}
}

/**
* Copy all files or directories listed in the target property {@code files}, {@code
* cmake-include}, and {@code _fed_setup} into the src-gen folder of the main .lf file
Expand Down Expand Up @@ -844,7 +807,6 @@ private void generateReactorChildren(
if (r.reactorDeclaration != null && !generatedReactors.contains(newTpr)) {
generatedReactors.add(newTpr);
generateReactorChildren(r, generatedReactors);
inspectReactorEResource(r.reactorDeclaration);
generateReactorClass(newTpr);
}
}
Expand Down
Loading
Loading