From 5f451e7a8930a7bead9968d2ef4f5df053e80503 Mon Sep 17 00:00:00 2001 From: Byeonggil Jun Date: Tue, 5 Mar 2024 10:42:31 -0700 Subject: [PATCH 01/16] Let `targetProperty` classes specifies their behavior on updating from imported file --- .../generator/FederateTargetConfig.java | 2 +- .../org/lflang/generator/c/CGenerator.java | 25 +++++++++++++++---- .../target/property/CmakeIncludeProperty.java | 10 ++++++++ .../target/property/TargetProperty.java | 15 +++++++++++ 4 files changed, 46 insertions(+), 6 deletions(-) diff --git a/core/src/main/java/org/lflang/federated/generator/FederateTargetConfig.java b/core/src/main/java/org/lflang/federated/generator/FederateTargetConfig.java index de58c2e543..f6b04494a7 100644 --- a/core/src/main/java/org/lflang/federated/generator/FederateTargetConfig.java +++ b/core/src/main/java/org/lflang/federated/generator/FederateTargetConfig.java @@ -108,7 +108,7 @@ public void update( .map(Objects::toString) .toList(); fileListProperty.update(config, files); - } else { + } else if (property.loadFromFederate()) { p.get().update(this, pair, err); } } diff --git a/core/src/main/java/org/lflang/generator/c/CGenerator.java b/core/src/main/java/org/lflang/generator/c/CGenerator.java index 58624b353d..dadd8f023f 100644 --- a/core/src/main/java/org/lflang/generator/c/CGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CGenerator.java @@ -28,6 +28,7 @@ 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; @@ -718,11 +719,25 @@ private void inspectReactorEResource(ReactorDecl reactor) { if (lfResource != null) { // Copy the user files and cmake-includes to the src-gen path of the main .lf file copyUserFiles(lfResource.getTargetConfig(), lfResource.getFileConfig()); - // Merge the CMake includes from the imported file into the target config - if (lfResource.getTargetConfig().isSet(CmakeIncludeProperty.INSTANCE)) { - CmakeIncludeProperty.INSTANCE.update( - this.targetConfig, lfResource.getTargetConfig().get(CmakeIncludeProperty.INSTANCE)); - } + + var config = lfResource.getTargetConfig(); + 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); + } + } + } + ); + // // Merge the CMake includes from the imported file into the target config + // if (lfResource.getTargetConfig().isSet(CmakeIncludeProperty.INSTANCE)) { + // CmakeIncludeProperty.INSTANCE.update( + // this.targetConfig, lfResource.getTargetConfig().get(CmakeIncludeProperty.INSTANCE)); + // } } } } diff --git a/core/src/main/java/org/lflang/target/property/CmakeIncludeProperty.java b/core/src/main/java/org/lflang/target/property/CmakeIncludeProperty.java index a47379fef1..b9a90a6ba9 100644 --- a/core/src/main/java/org/lflang/target/property/CmakeIncludeProperty.java +++ b/core/src/main/java/org/lflang/target/property/CmakeIncludeProperty.java @@ -39,4 +39,14 @@ public Element toAstElement(List value) { public String name() { return "cmake-include"; } + + @Override + public Boolean loadFromImport() { + return true; + } + + @Override + public Boolean loadFromFederate() { + return true; + } } diff --git a/core/src/main/java/org/lflang/target/property/TargetProperty.java b/core/src/main/java/org/lflang/target/property/TargetProperty.java index e1e1c444df..13182cb036 100644 --- a/core/src/main/java/org/lflang/target/property/TargetProperty.java +++ b/core/src/main/java/org/lflang/target/property/TargetProperty.java @@ -104,6 +104,21 @@ public Optional astElementFromConfig(TargetConfig config) { /** Return the name of this target property (in kebab case). */ public abstract String name(); + /** Return the policy of loading from imported file */ + public Boolean loadFromImport() { + return false; + } + + /** Return the policy of loading from imported file */ + public Boolean loadFromFederation() { + return true; + } + + /** Return the policy of loading from imported file */ + public Boolean loadFromFederate() { + return false; + } + /** * Replace the value assigned to this target property in the given config with the given value. * From bc8564f44c817c0cbc0cc80db53423f9d18e5384 Mon Sep 17 00:00:00 2001 From: Byeonggil Jun Date: Tue, 5 Mar 2024 11:22:39 -0700 Subject: [PATCH 02/16] Apply Spotless --- .../org/lflang/generator/c/CGenerator.java | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/core/src/main/java/org/lflang/generator/c/CGenerator.java b/core/src/main/java/org/lflang/generator/c/CGenerator.java index dadd8f023f..63e7cf466b 100644 --- a/core/src/main/java/org/lflang/generator/c/CGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CGenerator.java @@ -723,20 +723,20 @@ private void inspectReactorEResource(ReactorDecl reactor) { var config = lfResource.getTargetConfig(); 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); + pair -> { + var p = config.forName((pair.getName())); + if (p.isPresent()) { + var property = p.get(); + if (property.loadFromImport()) { + property.update(this.targetConfig, pair, messageReporter); + } } - } - } - ); + }); // // Merge the CMake includes from the imported file into the target config // if (lfResource.getTargetConfig().isSet(CmakeIncludeProperty.INSTANCE)) { // CmakeIncludeProperty.INSTANCE.update( - // this.targetConfig, lfResource.getTargetConfig().get(CmakeIncludeProperty.INSTANCE)); + // this.targetConfig, + // lfResource.getTargetConfig().get(CmakeIncludeProperty.INSTANCE)); // } } } From f4f93521331e23274b05096ce069f390c8e15d80 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Wed, 6 Mar 2024 00:14:08 -0800 Subject: [PATCH 03/16] Some cleanups --- .../org/lflang/generator/GeneratorBase.java | 11 ++-- .../org/lflang/generator/GeneratorUtils.java | 14 ++---- .../org/lflang/generator/c/CGenerator.java | 50 ++++--------------- 3 files changed, 17 insertions(+), 58 deletions(-) diff --git a/core/src/main/java/org/lflang/generator/GeneratorBase.java b/core/src/main/java/org/lflang/generator/GeneratorBase.java index 6911f5a4ed..34dba6618c 100644 --- a/core/src/main/java/org/lflang/generator/GeneratorBase.java +++ b/core/src/main/java/org/lflang/generator/GeneratorBase.java @@ -230,19 +230,14 @@ public void doGenerate(Resource resource, LFGeneratorContext context) { List allResources = GeneratorUtils.getResources(reactors); resources.addAll( - allResources - .stream() // 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, context.getFileConfig().resource) || mainDef != null && it == mainDef.getReactorClass().eResource()) - .map( - it -> - GeneratorUtils.getLFResource( - it, context.getFileConfig().getSrcGenBasePath(), context, messageReporter)) + .map(it -> GeneratorUtils.getLFResource(it, context)) .toList()); + GeneratorUtils.accommodatePhysicalActionsIfPresent( allResources, getTarget().setsKeepAliveOptionAutomatically(), diff --git a/core/src/main/java/org/lflang/generator/GeneratorUtils.java b/core/src/main/java/org/lflang/generator/GeneratorUtils.java index 88dc9fa075..c3622c10e3 100644 --- a/core/src/main/java/org/lflang/generator/GeneratorUtils.java +++ b/core/src/main/java/org/lflang/generator/GeneratorUtils.java @@ -1,6 +1,5 @@ package org.lflang.generator; -import java.nio.file.Path; import java.util.ArrayList; import java.util.HashSet; import java.util.List; @@ -106,18 +105,13 @@ public static List getResources(Iterable reactors) { * Return the {@code LFResource} representation of the given resource. * * @param resource The {@code Resource} to be represented as an {@code LFResource} - * @param srcGenBasePath The root directory for any generated sources associated with the - * resource. * @param context The generator invocation context. - * @param messageReporter An error message acceptor. * @return the {@code LFResource} representation of the given resource. */ - public static LFResource getLFResource( - Resource resource, - Path srcGenBasePath, - LFGeneratorContext context, - MessageReporter messageReporter) { + 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) { @@ -126,7 +120,7 @@ public static LFResource getLFResource( } FileConfig fc = LFGenerator.createFileConfig( - resource, srcGenBasePath, context.getFileConfig().useHierarchicalBin); + resource, mainFileConfig.getSrcGenBasePath(), mainFileConfig.useHierarchicalBin); return new LFResource(resource, fc, targetConfig); } diff --git a/core/src/main/java/org/lflang/generator/c/CGenerator.java b/core/src/main/java/org/lflang/generator/c/CGenerator.java index 63e7cf466b..694d09a22c 100644 --- a/core/src/main/java/org/lflang/generator/c/CGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CGenerator.java @@ -692,18 +692,10 @@ private boolean hasDeadlines(List reactors) { } /** - * Look at the 'reactor' eResource. If it is an imported .lf file, incorporate it into the current - * program in the following manner: - * - *
    - *
  • Merge its target property with {@code targetConfig} - *
  • If there are any preambles, add them to the preambles of the reactor. - *
+ * 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) { - // If the reactor is imported, look at the - // target definition of the .lf file in which the reactor is imported from and - // append any cmake-include. // Check if the reactor definition is imported if (reactor.eResource() != mainDef.getReactorClass().eResource()) { // Find the LFResource corresponding to this eResource @@ -714,13 +706,12 @@ private void inspectReactorEResource(ReactorDecl reactor) { break; } } - // FIXME: we're doing ad-hoc merging, and no validation. This is **not** the way to do it. if (lfResource != null) { - // Copy the user files and cmake-includes to the src-gen path of the main .lf file - copyUserFiles(lfResource.getTargetConfig(), lfResource.getFileConfig()); - 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 -> { @@ -732,12 +723,6 @@ private void inspectReactorEResource(ReactorDecl reactor) { } } }); - // // Merge the CMake includes from the imported file into the target config - // if (lfResource.getTargetConfig().isSet(CmakeIncludeProperty.INSTANCE)) { - // CmakeIncludeProperty.INSTANCE.update( - // this.targetConfig, - // lfResource.getTargetConfig().get(CmakeIncludeProperty.INSTANCE)); - // } } } } @@ -777,20 +762,12 @@ protected void copyUserFiles(TargetConfig targetConfig, FileConfig fileConfig) { } /** - * Generate code for defining all instantiated reactors. - * - *

Imported reactors' original .lf file is incorporated in the following manner: - * - *

    - *
  • If there are any cmake-include files, add them to the current list of cmake-include - * files. - *
  • If there are any preambles, add them to the preambles of the reactor. - *
+ * Generate code for defining all instantiated reactors and collect preambles and relevant target + * properties associated with imported reactors. */ private void generateReactorDefinitions() throws IOException { - var generatedReactors = new LinkedHashSet(); if (this.main != null) { - generateReactorChildren(this.main, generatedReactors); + generateReactorChildren(this.main, new LinkedHashSet<>()); generateReactorClass(new TypeParameterizedReactor(this.mainDef, reactors)); } // do not generate code for reactors that are not instantiated @@ -854,15 +831,8 @@ private void generateHeaders() throws IOException { } /** - * Generate code for the children of 'reactor' that belong to 'federate'. Duplicates are avoided. - * - *

Imported reactors' original .lf file is incorporated in the following manner: - * - *

    - *
  • If there are any cmake-include files, add them to the current list of cmake-include - * files. - *
  • If there are any preambles, add them to the preambles of the reactor. - *
+ * Recursively generate code for the children of the given reactor and collect preambles and + * relevant target properties associated with imported reactors. * * @param reactor Used to extract children from */ From 449222fb61f3edfe916fe39f123adf7b94f4fff7 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Wed, 6 Mar 2024 00:22:30 -0800 Subject: [PATCH 04/16] Remove what looks like a useless filter --- .../src/main/java/org/lflang/generator/GeneratorBase.java | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/core/src/main/java/org/lflang/generator/GeneratorBase.java b/core/src/main/java/org/lflang/generator/GeneratorBase.java index 34dba6618c..759195474c 100644 --- a/core/src/main/java/org/lflang/generator/GeneratorBase.java +++ b/core/src/main/java/org/lflang/generator/GeneratorBase.java @@ -230,13 +230,7 @@ public void doGenerate(Resource resource, LFGeneratorContext context) { List allResources = GeneratorUtils.getResources(reactors); resources.addAll( - allResources.stream() - .filter( - it -> - !Objects.equal(it, context.getFileConfig().resource) - || mainDef != null && it == mainDef.getReactorClass().eResource()) - .map(it -> GeneratorUtils.getLFResource(it, context)) - .toList()); + allResources.stream().map(it -> GeneratorUtils.getLFResource(it, context)).toList()); GeneratorUtils.accommodatePhysicalActionsIfPresent( allResources, From 24a6632161eb369edd87975b91bc60d3702f9e0a Mon Sep 17 00:00:00 2001 From: Byeonggil Jun Date: Wed, 26 Jun 2024 17:17:42 +0900 Subject: [PATCH 05/16] Remove FIXME that is already resolved --- core/src/main/java/org/lflang/generator/GeneratorBase.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/core/src/main/java/org/lflang/generator/GeneratorBase.java b/core/src/main/java/org/lflang/generator/GeneratorBase.java index 759195474c..05daf4f8ab 100644 --- a/core/src/main/java/org/lflang/generator/GeneratorBase.java +++ b/core/src/main/java/org/lflang/generator/GeneratorBase.java @@ -219,8 +219,6 @@ 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. From 9c1099b17611e332fdac8483bacd800278c35601 Mon Sep 17 00:00:00 2001 From: Byeonggil Jun Date: Fri, 28 Jun 2024 16:39:22 +0900 Subject: [PATCH 06/16] Copy cmake files after collecting all target properties --- .../org/lflang/generator/c/CGenerator.java | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/org/lflang/generator/c/CGenerator.java b/core/src/main/java/org/lflang/generator/c/CGenerator.java index 694d09a22c..e29ac6a9ae 100644 --- a/core/src/main/java/org/lflang/generator/c/CGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CGenerator.java @@ -582,6 +582,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. @@ -710,7 +711,8 @@ private void inspectReactorEResource(ReactorDecl reactor) { if (lfResource != null) { var config = lfResource.getTargetConfig(); // FIXME: this should not happen here, but once, after collecting all the files. - copyUserFiles(config, lfResource.getFileConfig()); + // copyUserFiles(config, lfResource.getFileConfig()); + final String basePath = lfResource.getFileConfig().srcPath.toString(); var pairs = convertToEmptyListIfNull(config.extractTargetDecl().getConfig().getPairs()); pairs.forEach( @@ -719,7 +721,19 @@ private void inspectReactorEResource(ReactorDecl reactor) { if (p.isPresent()) { var property = p.get(); if (property.loadFromImport()) { - property.update(this.targetConfig, pair, messageReporter); + if (property instanceof CmakeIncludeProperty) { + var list = (List) config.get(p.get()); + List u = new ArrayList<>(); + for (var s: list) { + if (s instanceof String) { + u.add((String) s); + } + } + u.replaceAll(entry -> Paths.get(entry).isAbsolute() ? entry : Paths.get(basePath, entry).toString()); + ((CmakeIncludeProperty)property).update(this.targetConfig, u); + } else { + property.update(this.targetConfig, pair, messageReporter); + } } } }); From 3eb1cb5cb653f70339ab88ad195b1cae171a0cee Mon Sep 17 00:00:00 2001 From: Byeonggil Jun Date: Fri, 28 Jun 2024 17:04:52 +0900 Subject: [PATCH 07/16] Copy files specified in `FileListProperty` too --- .../org/lflang/generator/c/CGenerator.java | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/core/src/main/java/org/lflang/generator/c/CGenerator.java b/core/src/main/java/org/lflang/generator/c/CGenerator.java index e29ac6a9ae..2fa6f383bc 100644 --- a/core/src/main/java/org/lflang/generator/c/CGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CGenerator.java @@ -91,6 +91,7 @@ import org.lflang.target.property.CompileDefinitionsProperty; import org.lflang.target.property.DockerProperty; import org.lflang.target.property.FedSetupProperty; +import org.lflang.target.property.FileListProperty; import org.lflang.target.property.LoggingProperty; import org.lflang.target.property.NoCompileProperty; import org.lflang.target.property.NoSourceMappingProperty; @@ -712,7 +713,7 @@ private void inspectReactorEResource(ReactorDecl reactor) { var config = lfResource.getTargetConfig(); // FIXME: this should not happen here, but once, after collecting all the files. // copyUserFiles(config, lfResource.getFileConfig()); - final String basePath = lfResource.getFileConfig().srcPath.toString(); + String basePath = lfResource.getFileConfig().srcPath.toString(); var pairs = convertToEmptyListIfNull(config.extractTargetDecl().getConfig().getPairs()); pairs.forEach( @@ -721,16 +722,19 @@ private void inspectReactorEResource(ReactorDecl reactor) { if (p.isPresent()) { var property = p.get(); if (property.loadFromImport()) { - if (property instanceof CmakeIncludeProperty) { + if (property instanceof FileListProperty) { var list = (List) config.get(p.get()); - List u = new ArrayList<>(); - for (var s: list) { + List paths = new ArrayList<>(); + for (var s : list) { if (s instanceof String) { - u.add((String) s); + Path path = Paths.get((String) s); + if (!path.isAbsolute()) { + path = Paths.get(basePath, path.toString()); + } + paths.add(path.toString()); } } - u.replaceAll(entry -> Paths.get(entry).isAbsolute() ? entry : Paths.get(basePath, entry).toString()); - ((CmakeIncludeProperty)property).update(this.targetConfig, u); + ((FileListProperty) property).update(this.targetConfig, paths); } else { property.update(this.targetConfig, pair, messageReporter); } From 0d157340dc1c04f96d8404f87d9f9cf1541986a2 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Fri, 28 Jun 2024 20:22:02 -0700 Subject: [PATCH 08/16] Stop-gap fix for test failure --- .../org/lflang/generator/c/CGenerator.java | 14 ++++++------- .../target/property/CmakeIncludeProperty.java | 7 +------ .../target/property/FileListProperty.java | 5 +++++ .../target/property/TargetProperty.java | 21 +++++++++++++------ 4 files changed, 27 insertions(+), 20 deletions(-) diff --git a/core/src/main/java/org/lflang/generator/c/CGenerator.java b/core/src/main/java/org/lflang/generator/c/CGenerator.java index 2fa6f383bc..d87313fb70 100644 --- a/core/src/main/java/org/lflang/generator/c/CGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CGenerator.java @@ -711,10 +711,7 @@ private void inspectReactorEResource(ReactorDecl reactor) { if (lfResource != null) { var config = lfResource.getTargetConfig(); - // FIXME: this should not happen here, but once, after collecting all the files. - // copyUserFiles(config, lfResource.getFileConfig()); - String basePath = lfResource.getFileConfig().srcPath.toString(); - + var fc = lfResource.getFileConfig(); var pairs = convertToEmptyListIfNull(config.extractTargetDecl().getConfig().getPairs()); pairs.forEach( pair -> { @@ -727,11 +724,12 @@ private void inspectReactorEResource(ReactorDecl reactor) { List paths = new ArrayList<>(); for (var s : list) { if (s instanceof String) { - Path path = Paths.get((String) s); - if (!path.isAbsolute()) { - path = Paths.get(basePath, path.toString()); + var found = FileUtil.findInPackage(Path.of((String) s), fc); + if (found != null) { + paths.add(found.toString()); + } else { + context.getErrorReporter().nowhere().error("Unable to locate file: " + s); } - paths.add(path.toString()); } } ((FileListProperty) property).update(this.targetConfig, paths); diff --git a/core/src/main/java/org/lflang/target/property/CmakeIncludeProperty.java b/core/src/main/java/org/lflang/target/property/CmakeIncludeProperty.java index b9a90a6ba9..38dbcacf0b 100644 --- a/core/src/main/java/org/lflang/target/property/CmakeIncludeProperty.java +++ b/core/src/main/java/org/lflang/target/property/CmakeIncludeProperty.java @@ -41,12 +41,7 @@ public String name() { } @Override - public Boolean loadFromImport() { - return true; - } - - @Override - public Boolean loadFromFederate() { + public boolean loadFromFederate() { return true; } } diff --git a/core/src/main/java/org/lflang/target/property/FileListProperty.java b/core/src/main/java/org/lflang/target/property/FileListProperty.java index 3409fcde8f..82dfe4cfc5 100644 --- a/core/src/main/java/org/lflang/target/property/FileListProperty.java +++ b/core/src/main/java/org/lflang/target/property/FileListProperty.java @@ -48,4 +48,9 @@ protected List fromString(String string, MessageReporter reporter) { public Element toAstElement(List value) { return ASTUtils.toElement(value); } + + @Override + public boolean loadFromImport() { + return true; + } } diff --git a/core/src/main/java/org/lflang/target/property/TargetProperty.java b/core/src/main/java/org/lflang/target/property/TargetProperty.java index 13182cb036..131721fc8d 100644 --- a/core/src/main/java/org/lflang/target/property/TargetProperty.java +++ b/core/src/main/java/org/lflang/target/property/TargetProperty.java @@ -104,18 +104,27 @@ public Optional astElementFromConfig(TargetConfig config) { /** Return the name of this target property (in kebab case). */ public abstract String name(); - /** Return the policy of loading from imported file */ - public Boolean loadFromImport() { + /** + * Return {@code true} if this property is to be loaded from imported files, {@code false} + * otherwise. + */ + public boolean loadFromImport() { return false; } - /** Return the policy of loading from imported file */ - public Boolean loadFromFederation() { + /** + * Return {@code true} if this property is to be loaded by federates when specified at the level + * of the federation, {@code false} otherwise. + */ + public boolean loadFromFederation() { return true; } - /** Return the policy of loading from imported file */ - public Boolean loadFromFederate() { + /** + * Return {@code true} if this property is to be loaded from imported federates, {@code false} + * otherwise. + */ + public boolean loadFromFederate() { return false; } From ec8829944265ba1c1ca44e3f9f19ad8ad144aed9 Mon Sep 17 00:00:00 2001 From: Byeonggil Jun Date: Sat, 29 Jun 2024 16:59:28 +0900 Subject: [PATCH 09/16] Do not call the function `copyUserFiles` in `GeneratorBase` --- core/src/main/java/org/lflang/generator/GeneratorBase.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/core/src/main/java/org/lflang/generator/GeneratorBase.java b/core/src/main/java/org/lflang/generator/GeneratorBase.java index 05daf4f8ab..cf8bf9adb9 100644 --- a/core/src/main/java/org/lflang/generator/GeneratorBase.java +++ b/core/src/main/java/org/lflang/generator/GeneratorBase.java @@ -218,9 +218,6 @@ public void doGenerate(Resource resource, LFGeneratorContext context) { } } - // Process target files. Copy each of them into the src-gen dir. - 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(). From 27c772702683469674cf398ed03b07e2cdd01865 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Sun, 30 Jun 2024 06:19:43 -0700 Subject: [PATCH 10/16] Considerable cleanups --- .../generator/FederateTargetConfig.java | 74 +--------- .../org/lflang/generator/GeneratorBase.java | 15 +-- .../org/lflang/generator/GeneratorUtils.java | 27 ---- .../java/org/lflang/generator/LFResource.java | 47 ------- .../org/lflang/generator/c/CGenerator.java | 56 ++------ .../java/org/lflang/target/TargetConfig.java | 127 ++++++++++++++---- .../main/java/org/lflang/util/FileUtil.java | 6 + 7 files changed, 120 insertions(+), 232 deletions(-) delete mode 100644 core/src/main/java/org/lflang/generator/LFResource.java diff --git a/core/src/main/java/org/lflang/federated/generator/FederateTargetConfig.java b/core/src/main/java/org/lflang/federated/generator/FederateTargetConfig.java index f6b04494a7..016fe1f2b5 100644 --- a/core/src/main/java/org/lflang/federated/generator/FederateTargetConfig.java +++ b/core/src/main/java/org/lflang/federated/generator/FederateTargetConfig.java @@ -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 @@ -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); @@ -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 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); - } - } - }); - } } diff --git a/core/src/main/java/org/lflang/generator/GeneratorBase.java b/core/src/main/java/org/lflang/generator/GeneratorBase.java index cf8bf9adb9..74cb6f8233 100644 --- a/core/src/main/java/org/lflang/generator/GeneratorBase.java +++ b/core/src/main/java/org/lflang/generator/GeneratorBase.java @@ -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; @@ -125,9 +123,6 @@ public Instantiation getMainDef() { */ protected List reactors = new ArrayList<>(); - /** The set of resources referenced reactor classes reside in. */ - protected Set 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 @@ -224,8 +219,6 @@ public void doGenerate(Resource resource, LFGeneratorContext context) { setReactorsAndInstantiationGraph(context.getMode()); List allResources = GeneratorUtils.getResources(reactors); - resources.addAll( - allResources.stream().map(it -> GeneratorUtils.getLFResource(it, context)).toList()); GeneratorUtils.accommodatePhysicalActionsIfPresent( allResources, @@ -241,7 +234,7 @@ public void doGenerate(Resource resource, LFGeneratorContext context) { // 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! @@ -410,9 +403,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 resources) { + for (Resource r : resources) { + var transform = ASTUtils.findConflictingConnectionsInModalReactors(r); if (!transform.isEmpty()) { var factory = LfFactory.eINSTANCE; for (Connection connection : transform) { diff --git a/core/src/main/java/org/lflang/generator/GeneratorUtils.java b/core/src/main/java/org/lflang/generator/GeneratorUtils.java index c3622c10e3..77240613e6 100644 --- a/core/src/main/java/org/lflang/generator/GeneratorUtils.java +++ b/core/src/main/java/org/lflang/generator/GeneratorUtils.java @@ -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; @@ -101,29 +97,6 @@ public static List getResources(Iterable 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 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. diff --git a/core/src/main/java/org/lflang/generator/LFResource.java b/core/src/main/java/org/lflang/generator/LFResource.java deleted file mode 100644 index 02fe98d032..0000000000 --- a/core/src/main/java/org/lflang/generator/LFResource.java +++ /dev/null @@ -1,47 +0,0 @@ -package org.lflang.generator; - -import org.eclipse.emf.ecore.resource.Resource; -import org.lflang.FileConfig; -import org.lflang.target.TargetConfig; - -/** - * A class that keeps metadata for discovered resources during code generation and the supporting - * structures associated with that resource. - * - * @author Soroush Bateni - */ -public class LFResource { - LFResource(Resource resource, FileConfig fileConfig, TargetConfig targetConfig) { - this.eResource = - resource; // FIXME: this is redundant because fileConfig already has the resource. - this.fileConfig = fileConfig; - this.targetConfig = targetConfig; - } - - /** Resource associated with a file either from the main .lf file or one of the imported ones. */ - Resource eResource; - - public Resource getEResource() { - return this.eResource; - } - ; - - /** - * The file config associated with 'resource' that can be used to discover files relative to that - * resource. - */ - FileConfig fileConfig; - - public FileConfig getFileConfig() { - return this.fileConfig; - } - ; - - /** The target config read from the resource. */ - TargetConfig targetConfig; - - public TargetConfig getTargetConfig() { - return this.targetConfig; - } - ; -} diff --git a/core/src/main/java/org/lflang/generator/c/CGenerator.java b/core/src/main/java/org/lflang/generator/c/CGenerator.java index d87313fb70..d19d1d7b7f 100644 --- a/core/src/main/java/org/lflang/generator/c/CGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CGenerator.java @@ -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; @@ -60,8 +59,8 @@ import org.lflang.generator.GeneratorBase; import org.lflang.generator.GeneratorResult; import org.lflang.generator.GeneratorUtils; +import org.lflang.generator.LFGenerator; 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; @@ -91,7 +90,6 @@ import org.lflang.target.property.CompileDefinitionsProperty; import org.lflang.target.property.DockerProperty; import org.lflang.target.property.FedSetupProperty; -import org.lflang.target.property.FileListProperty; import org.lflang.target.property.LoggingProperty; import org.lflang.target.property.NoCompileProperty; import org.lflang.target.property.NoSourceMappingProperty; @@ -698,49 +696,15 @@ private boolean hasDeadlines(List reactors) { * 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(); - var fc = 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()) { - if (property instanceof FileListProperty) { - var list = (List) config.get(p.get()); - List paths = new ArrayList<>(); - for (var s : list) { - if (s instanceof String) { - var found = FileUtil.findInPackage(Path.of((String) s), fc); - if (found != null) { - paths.add(found.toString()); - } else { - context.getErrorReporter().nowhere().error("Unable to locate file: " + s); - } - } - } - ((FileListProperty) property).update(this.targetConfig, paths); - } else { - property.update(this.targetConfig, pair, messageReporter); - } - } - } - }); - } - } + FileConfig fc = + LFGenerator.createFileConfig( + reactor.eResource(), fileConfig.getSrcGenBasePath(), fileConfig.useHierarchicalBin); + + var targetDecl = GeneratorUtils.findTargetDecl(fc.resource); + this.context + .getTargetConfig() + .mergeImportedConfig( + fc.resource, this.fileConfig.resource, p -> p.loadFromImport(), this.messageReporter); } /** diff --git a/core/src/main/java/org/lflang/target/TargetConfig.java b/core/src/main/java/org/lflang/target/TargetConfig.java index a5ce42c6cc..1aafa64201 100644 --- a/core/src/main/java/org/lflang/target/TargetConfig.java +++ b/core/src/main/java/org/lflang/target/TargetConfig.java @@ -24,7 +24,10 @@ ***************/ package org.lflang.target; +import static org.lflang.ast.ASTUtils.convertToEmptyListIfNull; + import com.google.gson.JsonObject; +import java.nio.file.Path; import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; @@ -33,8 +36,10 @@ import java.util.LinkedList; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Optional; import java.util.Set; +import java.util.function.Predicate; import java.util.stream.Collectors; import org.eclipse.emf.ecore.resource.Resource; import org.lflang.MessageReporter; @@ -48,11 +53,13 @@ import org.lflang.lf.TargetDecl; import org.lflang.target.property.FastProperty; import org.lflang.target.property.FedSetupProperty; +import org.lflang.target.property.FileListProperty; import org.lflang.target.property.LoggingProperty; import org.lflang.target.property.NoCompileProperty; import org.lflang.target.property.TargetProperty; import org.lflang.target.property.TimeOutProperty; import org.lflang.target.property.type.TargetPropertyType; +import org.lflang.util.FileUtil; /** * A class for keeping the current target configuration. @@ -120,14 +127,32 @@ protected TargetConfig(Target target) { * * @param resource A resource to load from. * @param reporter A reporter for reporting issues. + * @param reporter A message reporter for reporting errors and warnings. */ protected void load(Resource resource, MessageReporter reporter) { var targetDecl = GeneratorUtils.findTargetDecl(resource); var properties = targetDecl.getConfig(); + // Load properties from file if (properties != null) { List pairs = properties.getPairs(); - this.load(pairs, reporter); + pairs.forEach( + pair -> { + var p = forName(pair.getName()); + if (p.isPresent()) { + var property = p.get(); + // Record the pair. + keyValuePairs.put(property, pair); + // Only update the config if the pair matches the type. + if (property.checkType(pair, reporter)) { + property.update(this, pair, reporter); + // Ignore properties if they are imported and must not load from imports. + } + } else { + reportUnsupportedTargetProperty( + pair.getName(), reporter.at(pair, Literals.KEY_VALUE_PAIR__NAME)); + } + }); } } @@ -148,6 +173,71 @@ public TargetConfig(Resource resource, GeneratorArguments args, MessageReporter 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 importedResource The resource in which the target configuration is to be loaded from. + * @param mainResource The resource in which the main reactor is specified. + * @param loadOrNot Predicate to determine for each target property whether it should be loaded. + * @param messageReporter An error reporter to use when problems are encountered. + */ + public void mergeImportedConfig( + Resource importedResource, + Resource mainResource, + Predicate loadOrNot, + MessageReporter messageReporter) { + // If the federate is imported, then update the configuration based on target properties + // in the imported file. + if (!importedResource.equals(mainResource)) { + var importedTargetDecl = GeneratorUtils.findTargetDecl(importedResource); + var targetProperties = importedTargetDecl.getConfig(); + if (targetProperties != null) { + // Merge properties + update( + this, + convertToEmptyListIfNull(targetProperties.getPairs()), + FileUtil.getRelativePath(mainResource, importedResource), + loadOrNot, + messageReporter); + } + } + } + + /** + * 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 pairs, + Path relativePath, + Predicate loadOrNot, + 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 (loadOrNot.test(property)) { + p.get().update(this, pair, err); + } + } + }); + } + /** * Update this configuration based on the given JSON object. * @@ -257,6 +347,14 @@ public String listOfRegisteredProperties() { .collect(Collectors.joining(", ")); } + /** Return the target properties that are have been assigned a value. */ + public List> getAssignedProperties() { + return this.properties.keySet().stream() + .filter(this::isSet) + .sorted(Comparator.comparing(p -> p.getClass().getName())) + .collect(Collectors.toList()); + } + /** Return the target properties that are currently registered. */ public List> getRegisteredProperties() { return this.properties.keySet().stream() @@ -286,33 +384,6 @@ public void load(GeneratorArguments args, MessageReporter err) { args.overrides().forEach(a -> a.update(this, err)); } - /** - * Update the configuration using the given pairs from the AST. - * - * @param pairs AST node that holds all the target properties. - * @param err A message reporter for reporting errors and warnings. - */ - public void load(List pairs, MessageReporter err) { - if (pairs != null) { - pairs.forEach( - pair -> { - var p = forName(pair.getName()); - if (p.isPresent()) { - var property = p.get(); - // Record the pair. - keyValuePairs.put(property, pair); - if (property.checkType(pair, err)) { - // Only update the config is the pair matches the type. - property.update(this, pair, err); - } - } else { - reportUnsupportedTargetProperty( - pair.getName(), err.at(pair, Literals.KEY_VALUE_PAIR__NAME)); - } - }); - } - } - /** * Assign the given value to the given target property. * diff --git a/core/src/main/java/org/lflang/util/FileUtil.java b/core/src/main/java/org/lflang/util/FileUtil.java index 3bc09469f4..cfd44c432c 100644 --- a/core/src/main/java/org/lflang/util/FileUtil.java +++ b/core/src/main/java/org/lflang/util/FileUtil.java @@ -842,6 +842,12 @@ public static Path findInPackage(Path fileOrDirectory, FileConfig fileConfig) { return null; } + public static Path getRelativePath(Resource source, Resource target) { + return FileUtil.toPath(source.getURI()) + .getParent() + .relativize(FileUtil.toPath(target.getURI()).getParent()); + } + /** Get the iResource corresponding to the provided resource if it can be found. */ public static IResource getIResource(Resource r) { return getIResource(FileUtil.toPath(r).toFile().toURI()); From a6e771870b751391d837166a5daa5a41914cdf06 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Sun, 30 Jun 2024 06:31:19 -0700 Subject: [PATCH 11/16] Minor cleanup --- .../org/lflang/generator/c/CGenerator.java | 28 ++++++++++--------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/core/src/main/java/org/lflang/generator/c/CGenerator.java b/core/src/main/java/org/lflang/generator/c/CGenerator.java index d19d1d7b7f..97091472a1 100644 --- a/core/src/main/java/org/lflang/generator/c/CGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CGenerator.java @@ -692,19 +692,21 @@ private boolean hasDeadlines(List reactors) { } /** - * Look at the 'reactor' eResource. If it is an imported .lf file, gather preambles and relevant - * target properties associated with imported reactors. + * If the given reactor is defined in another file, process its target properties so that they are + * reflected in the target configuration. */ - private void inspectReactorEResource(ReactorDecl reactor) { - FileConfig fc = - LFGenerator.createFileConfig( - reactor.eResource(), fileConfig.getSrcGenBasePath(), fileConfig.useHierarchicalBin); - - var targetDecl = GeneratorUtils.findTargetDecl(fc.resource); - this.context - .getTargetConfig() - .mergeImportedConfig( - fc.resource, this.fileConfig.resource, p -> p.loadFromImport(), this.messageReporter); + private void loadTargetProperties(Resource resource) { + if (resource != this.fileConfig.resource) { + this.context + .getTargetConfig() + .mergeImportedConfig( + LFGenerator.createFileConfig( + resource, fileConfig.getSrcGenBasePath(), fileConfig.useHierarchicalBin) + .resource, + this.fileConfig.resource, + p -> p.loadFromImport(), + this.messageReporter); + } } /** @@ -824,7 +826,7 @@ private void generateReactorChildren( if (r.reactorDeclaration != null && !generatedReactors.contains(newTpr)) { generatedReactors.add(newTpr); generateReactorChildren(r, generatedReactors); - inspectReactorEResource(r.reactorDeclaration); + loadTargetProperties(r.reactorDeclaration.eResource()); generateReactorClass(newTpr); } } From 5771fc0a4bb2960c883f26585d7a3a8aece0e955 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Sun, 30 Jun 2024 06:51:29 -0700 Subject: [PATCH 12/16] Address another fixme --- .../org/lflang/generator/GeneratorBase.java | 36 ++++++++++++------- .../org/lflang/generator/c/CGenerator.java | 20 ----------- 2 files changed, 23 insertions(+), 33 deletions(-) diff --git a/core/src/main/java/org/lflang/generator/GeneratorBase.java b/core/src/main/java/org/lflang/generator/GeneratorBase.java index 74cb6f8233..d8b3d2d7d4 100644 --- a/core/src/main/java/org/lflang/generator/GeneratorBase.java +++ b/core/src/main/java/org/lflang/generator/GeneratorBase.java @@ -78,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; @@ -142,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 astTransformations = new ArrayList<>(); @@ -165,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. @@ -225,8 +234,9 @@ public void doGenerate(Resource resource, LFGeneratorContext context) { 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); diff --git a/core/src/main/java/org/lflang/generator/c/CGenerator.java b/core/src/main/java/org/lflang/generator/c/CGenerator.java index 97091472a1..be0d544352 100644 --- a/core/src/main/java/org/lflang/generator/c/CGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CGenerator.java @@ -59,7 +59,6 @@ import org.lflang.generator.GeneratorBase; import org.lflang.generator.GeneratorResult; import org.lflang.generator.GeneratorUtils; -import org.lflang.generator.LFGenerator; import org.lflang.generator.LFGeneratorContext; import org.lflang.generator.ParameterInstance; import org.lflang.generator.PortInstance; @@ -691,24 +690,6 @@ private boolean hasDeadlines(List reactors) { return false; } - /** - * 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) { - if (resource != this.fileConfig.resource) { - this.context - .getTargetConfig() - .mergeImportedConfig( - LFGenerator.createFileConfig( - resource, fileConfig.getSrcGenBasePath(), fileConfig.useHierarchicalBin) - .resource, - this.fileConfig.resource, - p -> p.loadFromImport(), - this.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 @@ -826,7 +807,6 @@ private void generateReactorChildren( if (r.reactorDeclaration != null && !generatedReactors.contains(newTpr)) { generatedReactors.add(newTpr); generateReactorChildren(r, generatedReactors); - loadTargetProperties(r.reactorDeclaration.eResource()); generateReactorClass(newTpr); } } From b150bb3659fdec58b5d9afc811d4fe6bc20d40a1 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Sun, 30 Jun 2024 08:34:09 -0700 Subject: [PATCH 13/16] Fix #2286 --- .../org/lflang/generator/GeneratorBase.java | 5 +-- .../org/lflang/generator/GeneratorUtils.java | 32 +++++++++++++------ test/C/src/target/ImportedCMakeInclude.lf | 8 +++++ 3 files changed, 33 insertions(+), 12 deletions(-) create mode 100644 test/C/src/target/ImportedCMakeInclude.lf diff --git a/core/src/main/java/org/lflang/generator/GeneratorBase.java b/core/src/main/java/org/lflang/generator/GeneratorBase.java index d8b3d2d7d4..0713b863be 100644 --- a/core/src/main/java/org/lflang/generator/GeneratorBase.java +++ b/core/src/main/java/org/lflang/generator/GeneratorBase.java @@ -34,6 +34,7 @@ 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; @@ -227,7 +228,7 @@ public void doGenerate(Resource resource, LFGeneratorContext context) { // to validate, which happens in setResources(). setReactorsAndInstantiationGraph(context.getMode()); - List allResources = GeneratorUtils.getResources(reactors); + Set allResources = GeneratorUtils.getResources(reactors); GeneratorUtils.accommodatePhysicalActionsIfPresent( allResources, @@ -413,7 +414,7 @@ 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(List resources) { + private void transformConflictingConnectionsInModalReactors(Set resources) { for (Resource r : resources) { var transform = ASTUtils.findConflictingConnectionsInModalReactors(r); if (!transform.isEmpty()) { diff --git a/core/src/main/java/org/lflang/generator/GeneratorUtils.java b/core/src/main/java/org/lflang/generator/GeneratorUtils.java index 77240613e6..f7d6a07855 100644 --- a/core/src/main/java/org/lflang/generator/GeneratorUtils.java +++ b/core/src/main/java/org/lflang/generator/GeneratorUtils.java @@ -1,8 +1,8 @@ package org.lflang.generator; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; +import java.util.LinkedHashSet; +import java.util.Set; + import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; @@ -13,6 +13,7 @@ import org.lflang.generator.LFGeneratorContext.Mode; import org.lflang.lf.Action; import org.lflang.lf.ActionOrigin; +import org.lflang.lf.ImportedReactor; import org.lflang.lf.Instantiation; import org.lflang.lf.Reactor; import org.lflang.lf.TargetDecl; @@ -40,7 +41,7 @@ public static TargetDecl findTargetDecl(Resource resource) { * targetConfig}. This is a helper function for setTargetConfig. It should not be used elsewhere. */ public static void accommodatePhysicalActionsIfPresent( - List resources, + Set resources, boolean setsKeepAliveOptionAutomatically, TargetConfig targetConfig, MessageReporter messageReporter) { @@ -84,17 +85,28 @@ public static Iterable findAll(Resource resource, Class nodeType) { * @param reactors The reactors for which to find containing resources. * @return the resources that provide the given reactors. */ - public static List getResources(Iterable reactors) { - HashSet visited = new HashSet<>(); - List resources = new ArrayList<>(); + public static Set getResources(Iterable reactors) { + Set visited = new LinkedHashSet<>(); for (Reactor r : reactors) { Resource resource = r.eResource(); if (!visited.contains(resource)) { - visited.add(resource); - resources.add(resource); + addInheritedResources(r, visited); + } + } + return visited; + } + + public static void addInheritedResources(Reactor reactor, Set resources) { + resources.add(reactor.eResource()); + for (var s : reactor.getSuperClasses()) { + if (!resources.contains(s)) { + if (s instanceof ImportedReactor i) { + addInheritedResources(i.getReactorClass(), resources); + } else if (s instanceof Reactor r) { + addInheritedResources(r, resources); + } } } - return resources; } /** diff --git a/test/C/src/target/ImportedCMakeInclude.lf b/test/C/src/target/ImportedCMakeInclude.lf new file mode 100644 index 0000000000..b19fa87069 --- /dev/null +++ b/test/C/src/target/ImportedCMakeInclude.lf @@ -0,0 +1,8 @@ +target C { + timeout: 1ms +} +import Foo from "./CMakeInclude.lf" +reactor Bar extends Foo { } +main reactor { + r = new Foo() +} \ No newline at end of file From b4d248986b8024d1bb42f8fedfa7c3d64d793f34 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Sun, 30 Jun 2024 08:41:23 -0700 Subject: [PATCH 14/16] Added test and comments --- .../main/java/org/lflang/generator/GeneratorUtils.java | 6 +++--- test/C/src/target/ImportedCMakeInclude.lf | 10 +++++++--- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/core/src/main/java/org/lflang/generator/GeneratorUtils.java b/core/src/main/java/org/lflang/generator/GeneratorUtils.java index f7d6a07855..5db8c0c2f9 100644 --- a/core/src/main/java/org/lflang/generator/GeneratorUtils.java +++ b/core/src/main/java/org/lflang/generator/GeneratorUtils.java @@ -2,7 +2,6 @@ import java.util.LinkedHashSet; import java.util.Set; - import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; @@ -80,7 +79,7 @@ public static Iterable findAll(Resource resource, Class nodeType) { } /** - * Return the resources that provide the given reactors. + * Return the resources that provide the given reactors and their ancestors. * * @param reactors The reactors for which to find containing resources. * @return the resources that provide the given reactors. @@ -96,7 +95,8 @@ public static Set getResources(Iterable reactors) { return visited; } - public static void addInheritedResources(Reactor reactor, Set resources) { + /** Collect all resources associated with reactor through class inheritance. */ + private static void addInheritedResources(Reactor reactor, Set resources) { resources.add(reactor.eResource()); for (var s : reactor.getSuperClasses()) { if (!resources.contains(s)) { diff --git a/test/C/src/target/ImportedCMakeInclude.lf b/test/C/src/target/ImportedCMakeInclude.lf index b19fa87069..bc922d7429 100644 --- a/test/C/src/target/ImportedCMakeInclude.lf +++ b/test/C/src/target/ImportedCMakeInclude.lf @@ -1,8 +1,12 @@ target C { - timeout: 1ms + timeout: 1 ms } + import Foo from "./CMakeInclude.lf" -reactor Bar extends Foo { } + +reactor Bar extends Foo { +} + main reactor { r = new Foo() -} \ No newline at end of file +} From be6f7403cab6ff475ae647ab9fee651a70444176 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Sun, 30 Jun 2024 08:56:09 -0700 Subject: [PATCH 15/16] Shave off one more line --- core/src/main/java/org/lflang/generator/GeneratorUtils.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/core/src/main/java/org/lflang/generator/GeneratorUtils.java b/core/src/main/java/org/lflang/generator/GeneratorUtils.java index 5db8c0c2f9..bda5a5cf2e 100644 --- a/core/src/main/java/org/lflang/generator/GeneratorUtils.java +++ b/core/src/main/java/org/lflang/generator/GeneratorUtils.java @@ -87,8 +87,7 @@ public static Iterable findAll(Resource resource, Class nodeType) { public static Set getResources(Iterable reactors) { Set visited = new LinkedHashSet<>(); for (Reactor r : reactors) { - Resource resource = r.eResource(); - if (!visited.contains(resource)) { + if (!visited.contains(r.eResource())) { addInheritedResources(r, visited); } } From adfb734b630c3c2d72c10830f7c22765be16e40f Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Sun, 30 Jun 2024 12:53:54 -0700 Subject: [PATCH 16/16] Apply suggestions from code review Co-authored-by: Christian Menard --- core/src/main/java/org/lflang/target/TargetConfig.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/org/lflang/target/TargetConfig.java b/core/src/main/java/org/lflang/target/TargetConfig.java index 1aafa64201..c0f6821bbb 100644 --- a/core/src/main/java/org/lflang/target/TargetConfig.java +++ b/core/src/main/java/org/lflang/target/TargetConfig.java @@ -174,7 +174,7 @@ public TargetConfig(Resource resource, GeneratorArguments args, MessageReporter } /** - * If the federate that target configuration applies to is imported, merge target properties + * If the federate that the target configuration applies to is imported, merge target properties * declared in the file that it was imported from. * * @param importedResource The resource in which the target configuration is to be loaded from. @@ -347,7 +347,7 @@ public String listOfRegisteredProperties() { .collect(Collectors.joining(", ")); } - /** Return the target properties that are have been assigned a value. */ + /** Return the target properties that have been assigned a value. */ public List> getAssignedProperties() { return this.properties.keySet().stream() .filter(this::isSet)