Skip to content

Commit

Permalink
Merge pull request #2333 from lf-lang/target-property-handling2
Browse files Browse the repository at this point in the history
Improved handling of `files` target property
  • Loading branch information
lhstrh authored Jun 30, 2024
2 parents 1278647 + d1501dc commit 3811a1d
Show file tree
Hide file tree
Showing 10 changed files with 155 additions and 255 deletions.
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

0 comments on commit 3811a1d

Please sign in to comment.