From 80c56373236d72254984937bb8e9f9e673d6a48b Mon Sep 17 00:00:00 2001 From: Atharva Patil Date: Mon, 5 Jun 2023 05:14:04 +0900 Subject: [PATCH 01/24] Changed the 'threading' CLI option, build param and target property to 'single threaded'. --- cli/lfc/src/main/java/org/lflang/cli/Lfc.java | 19 +++++-------------- .../test/java/org/lflang/cli/LfcCliTest.java | 4 ++-- .../federated/extensions/CExtension.java | 2 +- .../org/lflang/generator/GeneratorBase.java | 4 +++- .../lflang/generator/c/CCmakeGenerator.java | 4 ++-- .../org/lflang/generator/c/CGenerator.java | 5 +++-- .../generator/c/CPreambleGenerator.java | 3 +-- .../java/org/lflang/tests/Configurators.java | 1 - 8 files changed, 17 insertions(+), 25 deletions(-) diff --git a/cli/lfc/src/main/java/org/lflang/cli/Lfc.java b/cli/lfc/src/main/java/org/lflang/cli/Lfc.java index 163c1f4099..90af5a3673 100644 --- a/cli/lfc/src/main/java/org/lflang/cli/Lfc.java +++ b/cli/lfc/src/main/java/org/lflang/cli/Lfc.java @@ -140,10 +140,10 @@ public class Lfc extends CliBase { private String scheduler; @Option( - names = {"-t", "--threading"}, - paramLabel = "", - description = "Specify whether the runtime should use multi-threading" + " (true/false).") - private String threading; + names = "--single-threaded", + arity = "0", + description = "Specify whether the runtime should be single-threaded.") + private Boolean singleThreaded; @Option( names = {"--tracing"}, @@ -331,15 +331,6 @@ private TracingOptions getTracingOptions() { } } - /** Return whether threading has been enabled via the CLI arguments, or {@code null} otherwise. */ - private Boolean getThreading() { - if (threading != null) { - return Boolean.parseBoolean(threading); - } else { - return null; - } - } - /** Check the values of the commandline arguments and return them. */ public GeneratorArguments getArgs() { @@ -360,7 +351,7 @@ public GeneratorArguments getArgs() { new Argument<>(VerifyProperty.INSTANCE, verify), new Argument<>(RuntimeVersionProperty.INSTANCE, runtimeVersion), new Argument<>(SchedulerProperty.INSTANCE, getScheduler()), - new Argument<>(ThreadingProperty.INSTANCE, getThreading()), + new Argument<>(ThreadingProperty.INSTANCE, singleThreaded), new Argument<>(TracingProperty.INSTANCE, getTracingOptions()), new Argument<>(WorkersProperty.INSTANCE, workers))); } diff --git a/cli/lfc/src/test/java/org/lflang/cli/LfcCliTest.java b/cli/lfc/src/test/java/org/lflang/cli/LfcCliTest.java index ef7a7676c8..0a7a7039c9 100644 --- a/cli/lfc/src/test/java/org/lflang/cli/LfcCliTest.java +++ b/cli/lfc/src/test/java/org/lflang/cli/LfcCliTest.java @@ -92,7 +92,7 @@ public class LfcCliTest { "rti": "path/to/rti", "runtime-version": "rs", "scheduler": "GEDF_NP", - "threading": false, + "single-threaded": true, "workers": "1" } } @@ -333,7 +333,7 @@ public void testGeneratorArgs(@TempDir Path tempDir) throws IOException { "rs", "--scheduler", "GEDF_NP", - "--threading", + "--single-threaded", "false", "--workers", "1", diff --git a/core/src/main/java/org/lflang/federated/extensions/CExtension.java b/core/src/main/java/org/lflang/federated/extensions/CExtension.java index 7b6f1054f1..fcd8889ff9 100644 --- a/core/src/main/java/org/lflang/federated/extensions/CExtension.java +++ b/core/src/main/java/org/lflang/federated/extensions/CExtension.java @@ -93,7 +93,7 @@ public void initializeTargetConfig( // Also, create the RTI C file and the launcher script. // Handle target parameters. // If the program is federated, then ensure that threading is enabled. - ThreadingProperty.INSTANCE.override(federate.targetConfig, true); + ThreadingProperty.INSTANCE.override(federate.targetConfig, true); // FIXME: invert // Include the fed setup file for this federate in the target property FedSetupProperty.INSTANCE.override(federate.targetConfig, getPreamblePath(federate)); diff --git a/core/src/main/java/org/lflang/generator/GeneratorBase.java b/core/src/main/java/org/lflang/generator/GeneratorBase.java index c1851ec361..19e49e3ff4 100644 --- a/core/src/main/java/org/lflang/generator/GeneratorBase.java +++ b/core/src/main/java/org/lflang/generator/GeneratorBase.java @@ -267,7 +267,9 @@ public void doGenerate(Resource resource, LFGeneratorContext context) { // Check for the existence and support of watchdogs hasWatchdogs = IterableExtensions.exists(reactors, it -> !it.getWatchdogs().isEmpty()); - checkWatchdogSupport(getTarget() == Target.C && targetConfig.get(ThreadingProperty.INSTANCE)); + + checkWatchdogSupport( + getTarget() == Target.C && targetConfig.get(ThreadingProperty.INSTANCE)); // FIXME: invert additionalPostProcessingForModes(); } diff --git a/core/src/main/java/org/lflang/generator/c/CCmakeGenerator.java b/core/src/main/java/org/lflang/generator/c/CCmakeGenerator.java index f3e4afeee8..a896d1181f 100644 --- a/core/src/main/java/org/lflang/generator/c/CCmakeGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CCmakeGenerator.java @@ -355,7 +355,7 @@ CodeBuilder generateCMakeCode( } if (targetConfig.get(ThreadingProperty.INSTANCE) - && platformOptions.platform() != Platform.ZEPHYR) { + && platformOptions.platform() != Platform.ZEPHYR) { // FIXME: invert // If threaded computation is requested, add the threads option. cMakeCode.pr("# Find threads and link to it"); cMakeCode.pr("find_package(Threads REQUIRED)"); @@ -365,7 +365,7 @@ CodeBuilder generateCMakeCode( // Add additional flags so runtime can distinguish between multi-threaded and single-threaded // mode - if (targetConfig.get(ThreadingProperty.INSTANCE)) { + if (targetConfig.get(ThreadingProperty.INSTANCE)) { // FIXME: invert cMakeCode.pr("# Set the number of workers to enable threading/tracing"); cMakeCode.pr( "target_compile_definitions(${LF_MAIN_TARGET} PUBLIC NUMBER_OF_WORKERS=" 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 1c277f5d29..4491f62dc6 100644 --- a/core/src/main/java/org/lflang/generator/c/CGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CGenerator.java @@ -362,7 +362,7 @@ public void accommodatePhysicalActionsIfPresent() { // instead // because it is the only one currently capable of handling asynchronous events. var threading = ThreadingProperty.INSTANCE; - if (!targetConfig.get(threading) && !targetConfig.isSet(threading)) { + if (!targetConfig.get(threading) && !targetConfig.isSet(threading)) { // FIXME: invert threading.override(targetConfig, true); String message = "Using the threaded C runtime to allow for asynchronous handling of physical action" @@ -470,7 +470,8 @@ public void doGenerate(Resource resource, LFGeneratorContext context) { try { Path include = fileConfig.getSrcGenPath().resolve("include/"); Path src = fileConfig.getSrcGenPath().resolve("src/"); - FileUtil.arduinoDeleteHelper(src, targetConfig.get(ThreadingProperty.INSTANCE)); + FileUtil.arduinoDeleteHelper( + src, targetConfig.get(ThreadingProperty.INSTANCE)); // FIXME: invert FileUtil.relativeIncludeHelper(src, include, messageReporter); FileUtil.relativeIncludeHelper(include, include, messageReporter); } catch (IOException e) { diff --git a/core/src/main/java/org/lflang/generator/c/CPreambleGenerator.java b/core/src/main/java/org/lflang/generator/c/CPreambleGenerator.java index d76e86fc86..dd4ebaf45e 100644 --- a/core/src/main/java/org/lflang/generator/c/CPreambleGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CPreambleGenerator.java @@ -48,7 +48,7 @@ public static String generateIncludeStatements(TargetConfig targetConfig, boolea .forEach(it -> code.pr("#include " + StringUtil.addDoubleQuotes(it))); code.pr("#include \"include/core/reactor.h\""); code.pr("#include \"include/core/reactor_common.h\""); - if (targetConfig.get(ThreadingProperty.INSTANCE)) { + if (targetConfig.get(ThreadingProperty.INSTANCE)) { // FIXME: invert code.pr("#include \"include/core/threaded/scheduler.h\""); } @@ -87,7 +87,6 @@ public static String generateDefineDirectives(TargetConfig targetConfig, Path sr // targetConfig.clockSyncOptions // )); // } - if (targetConfig.get(ThreadingProperty.INSTANCE)) { definitions.put("LF_THREADED", "1"); } else { diff --git a/core/src/testFixtures/java/org/lflang/tests/Configurators.java b/core/src/testFixtures/java/org/lflang/tests/Configurators.java index 5576f33dba..95a85069fa 100644 --- a/core/src/testFixtures/java/org/lflang/tests/Configurators.java +++ b/core/src/testFixtures/java/org/lflang/tests/Configurators.java @@ -84,7 +84,6 @@ public static boolean makeZephyrCompatibleUnthreaded(TargetConfig config) { platform.baudRate(), false, platform.userThreads())); - return true; } From 937ea824aef03846fd8b3ebe3254893997af288d Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Fri, 3 Nov 2023 15:20:05 -0700 Subject: [PATCH 02/24] Rename ThreadingProperty to SingleThreadedProperty and invert uses --- cli/lfc/src/main/java/org/lflang/cli/Lfc.java | 4 ++-- .../test/java/org/lflang/cli/LfcCliTest.java | 4 ++-- .../federated/extensions/CExtension.java | 4 ++-- .../org/lflang/generator/GeneratorBase.java | 4 ++-- .../lflang/generator/c/CCmakeGenerator.java | 8 +++---- .../org/lflang/generator/c/CGenerator.java | 22 +++++++++---------- .../generator/c/CPreambleGenerator.java | 8 +++---- .../generator/c/CTriggerObjectsGenerator.java | 4 ++-- .../main/java/org/lflang/target/Target.java | 8 +++---- .../target/property/PlatformProperty.java | 5 +++-- ...perty.java => SingleThreadedProperty.java} | 8 +++---- .../target/property/TracingProperty.java | 10 ++++----- .../org/lflang/generator/rust/RustModel.kt | 8 +++---- .../java/org/lflang/tests/Configurators.java | 4 ++-- 14 files changed, 51 insertions(+), 50 deletions(-) rename core/src/main/java/org/lflang/target/property/{ThreadingProperty.java => SingleThreadedProperty.java} (57%) diff --git a/cli/lfc/src/main/java/org/lflang/cli/Lfc.java b/cli/lfc/src/main/java/org/lflang/cli/Lfc.java index 90af5a3673..55299e8c3c 100644 --- a/cli/lfc/src/main/java/org/lflang/cli/Lfc.java +++ b/cli/lfc/src/main/java/org/lflang/cli/Lfc.java @@ -22,7 +22,7 @@ import org.lflang.target.property.PrintStatisticsProperty; import org.lflang.target.property.RuntimeVersionProperty; import org.lflang.target.property.SchedulerProperty; -import org.lflang.target.property.ThreadingProperty; +import org.lflang.target.property.SingleThreadedProperty; import org.lflang.target.property.TracingProperty; import org.lflang.target.property.TracingProperty.TracingOptions; import org.lflang.target.property.VerifyProperty; @@ -351,7 +351,7 @@ public GeneratorArguments getArgs() { new Argument<>(VerifyProperty.INSTANCE, verify), new Argument<>(RuntimeVersionProperty.INSTANCE, runtimeVersion), new Argument<>(SchedulerProperty.INSTANCE, getScheduler()), - new Argument<>(ThreadingProperty.INSTANCE, singleThreaded), + new Argument<>(SingleThreadedProperty.INSTANCE, singleThreaded), new Argument<>(TracingProperty.INSTANCE, getTracingOptions()), new Argument<>(WorkersProperty.INSTANCE, workers))); } diff --git a/cli/lfc/src/test/java/org/lflang/cli/LfcCliTest.java b/cli/lfc/src/test/java/org/lflang/cli/LfcCliTest.java index 0a7a7039c9..8f28194650 100644 --- a/cli/lfc/src/test/java/org/lflang/cli/LfcCliTest.java +++ b/cli/lfc/src/test/java/org/lflang/cli/LfcCliTest.java @@ -51,7 +51,7 @@ import org.lflang.target.property.RuntimeVersionProperty; import org.lflang.target.property.SchedulerProperty; import org.lflang.target.property.TargetProperty; -import org.lflang.target.property.ThreadingProperty; +import org.lflang.target.property.SingleThreadedProperty; import org.lflang.target.property.WorkersProperty; import org.lflang.target.property.type.BuildTypeType.BuildType; import org.lflang.target.property.type.LoggingType.LogLevel; @@ -265,7 +265,7 @@ public void verifyGeneratorArgs(Path tempDir, String[] args) { checkOverrideValue(genArgs, PrintStatisticsProperty.INSTANCE, true); checkOverrideValue(genArgs, RuntimeVersionProperty.INSTANCE, "rs"); checkOverrideValue(genArgs, SchedulerProperty.INSTANCE, Scheduler.GEDF_NP); - checkOverrideValue(genArgs, ThreadingProperty.INSTANCE, false); + checkOverrideValue(genArgs, SingleThreadedProperty.INSTANCE, true); checkOverrideValue(genArgs, WorkersProperty.INSTANCE, 1); assertEquals(true, genArgs.clean()); diff --git a/core/src/main/java/org/lflang/federated/extensions/CExtension.java b/core/src/main/java/org/lflang/federated/extensions/CExtension.java index fcd8889ff9..ad0f6ce743 100644 --- a/core/src/main/java/org/lflang/federated/extensions/CExtension.java +++ b/core/src/main/java/org/lflang/federated/extensions/CExtension.java @@ -61,7 +61,7 @@ import org.lflang.target.property.CoordinationProperty; import org.lflang.target.property.FedSetupProperty; import org.lflang.target.property.KeepaliveProperty; -import org.lflang.target.property.ThreadingProperty; +import org.lflang.target.property.SingleThreadedProperty; import org.lflang.target.property.type.CoordinationModeType.CoordinationMode; /** @@ -93,7 +93,7 @@ public void initializeTargetConfig( // Also, create the RTI C file and the launcher script. // Handle target parameters. // If the program is federated, then ensure that threading is enabled. - ThreadingProperty.INSTANCE.override(federate.targetConfig, true); // FIXME: invert + SingleThreadedProperty.INSTANCE.override(federate.targetConfig, false); // Include the fed setup file for this federate in the target property FedSetupProperty.INSTANCE.override(federate.targetConfig, getPreamblePath(federate)); diff --git a/core/src/main/java/org/lflang/generator/GeneratorBase.java b/core/src/main/java/org/lflang/generator/GeneratorBase.java index 19e49e3ff4..dade9fed71 100644 --- a/core/src/main/java/org/lflang/generator/GeneratorBase.java +++ b/core/src/main/java/org/lflang/generator/GeneratorBase.java @@ -62,7 +62,7 @@ import org.lflang.target.Target; import org.lflang.target.TargetConfig; import org.lflang.target.property.FilesProperty; -import org.lflang.target.property.ThreadingProperty; +import org.lflang.target.property.SingleThreadedProperty; import org.lflang.target.property.VerifyProperty; import org.lflang.util.FileUtil; import org.lflang.validation.AbstractLFValidator; @@ -269,7 +269,7 @@ public void doGenerate(Resource resource, LFGeneratorContext context) { hasWatchdogs = IterableExtensions.exists(reactors, it -> !it.getWatchdogs().isEmpty()); checkWatchdogSupport( - getTarget() == Target.C && targetConfig.get(ThreadingProperty.INSTANCE)); // FIXME: invert + getTarget() == Target.C && !targetConfig.get(SingleThreadedProperty.INSTANCE)); additionalPostProcessingForModes(); } diff --git a/core/src/main/java/org/lflang/generator/c/CCmakeGenerator.java b/core/src/main/java/org/lflang/generator/c/CCmakeGenerator.java index a896d1181f..0723ba8d79 100644 --- a/core/src/main/java/org/lflang/generator/c/CCmakeGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CCmakeGenerator.java @@ -42,7 +42,7 @@ import org.lflang.target.property.CompilerProperty; import org.lflang.target.property.PlatformProperty; import org.lflang.target.property.ProtobufsProperty; -import org.lflang.target.property.ThreadingProperty; +import org.lflang.target.property.SingleThreadedProperty; import org.lflang.target.property.WorkersProperty; import org.lflang.target.property.type.PlatformType.Platform; import org.lflang.util.FileUtil; @@ -354,8 +354,8 @@ CodeBuilder generateCMakeCode( cMakeCode.newLine(); } - if (targetConfig.get(ThreadingProperty.INSTANCE) - && platformOptions.platform() != Platform.ZEPHYR) { // FIXME: invert + if (!targetConfig.get(SingleThreadedProperty.INSTANCE) + && platformOptions.platform() != Platform.ZEPHYR) { // If threaded computation is requested, add the threads option. cMakeCode.pr("# Find threads and link to it"); cMakeCode.pr("find_package(Threads REQUIRED)"); @@ -365,7 +365,7 @@ CodeBuilder generateCMakeCode( // Add additional flags so runtime can distinguish between multi-threaded and single-threaded // mode - if (targetConfig.get(ThreadingProperty.INSTANCE)) { // FIXME: invert + if (!targetConfig.get(SingleThreadedProperty.INSTANCE)) { cMakeCode.pr("# Set the number of workers to enable threading/tracing"); cMakeCode.pr( "target_compile_definitions(${LF_MAIN_TARGET} PUBLIC NUMBER_OF_WORKERS=" 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 4491f62dc6..2300a15e42 100644 --- a/core/src/main/java/org/lflang/generator/c/CGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CGenerator.java @@ -99,7 +99,7 @@ import org.lflang.target.property.PlatformProperty.PlatformOption; import org.lflang.target.property.ProtobufsProperty; import org.lflang.target.property.SchedulerProperty; -import org.lflang.target.property.ThreadingProperty; +import org.lflang.target.property.SingleThreadedProperty; import org.lflang.target.property.TracingProperty; import org.lflang.target.property.WorkersProperty; import org.lflang.target.property.type.PlatformType.Platform; @@ -361,9 +361,9 @@ public void accommodatePhysicalActionsIfPresent() { // If the unthreaded runtime is not requested by the user, use the threaded runtime // instead // because it is the only one currently capable of handling asynchronous events. - var threading = ThreadingProperty.INSTANCE; - if (!targetConfig.get(threading) && !targetConfig.isSet(threading)) { // FIXME: invert - threading.override(targetConfig, true); + var singleThreaded = SingleThreadedProperty.INSTANCE; + if (!targetConfig.isSet(singleThreaded) && targetConfig.get(singleThreaded)) { + singleThreaded.override(targetConfig, true); String message = "Using the threaded C runtime to allow for asynchronous handling of physical action" + " " @@ -471,7 +471,7 @@ public void doGenerate(Resource resource, LFGeneratorContext context) { Path include = fileConfig.getSrcGenPath().resolve("include/"); Path src = fileConfig.getSrcGenPath().resolve("src/"); FileUtil.arduinoDeleteHelper( - src, targetConfig.get(ThreadingProperty.INSTANCE)); // FIXME: invert + src, !targetConfig.get(SingleThreadedProperty.INSTANCE)); FileUtil.relativeIncludeHelper(src, include, messageReporter); FileUtil.relativeIncludeHelper(include, include, messageReporter); } catch (IOException e) { @@ -1951,7 +1951,7 @@ protected void setUpGeneralParameters() { if (targetConfig.isSet(PlatformProperty.INSTANCE)) { final var platformOptions = targetConfig.get(PlatformProperty.INSTANCE); - if (targetConfig.get(ThreadingProperty.INSTANCE) + if (targetConfig.get(SingleThreadedProperty.INSTANCE) && platformOptions.platform() == Platform.ARDUINO && (platformOptions.board() == null || !platformOptions.board().contains("mbed"))) { // non-MBED boards should not use threading @@ -1960,7 +1960,7 @@ protected void setUpGeneralParameters() { .info( "Threading is incompatible on your current Arduino flavor. Setting threading to" + " false."); - ThreadingProperty.INSTANCE.override(targetConfig, false); + SingleThreadedProperty.INSTANCE.override(targetConfig, false); } if (platformOptions.platform() == Platform.ARDUINO @@ -1977,7 +1977,7 @@ protected void setUpGeneralParameters() { } if (platformOptions.platform() == Platform.ZEPHYR - && targetConfig.get(ThreadingProperty.INSTANCE) + && !targetConfig.get(SingleThreadedProperty.INSTANCE) && platformOptions.userThreads() >= 0) { targetConfig .get(CompileDefinitionsProperty.INSTANCE) @@ -1987,11 +1987,11 @@ protected void setUpGeneralParameters() { .nowhere() .warning( "Specifying user threads is only for threaded Lingua Franca on the Zephyr platform." - + " This option will be ignored."); + + " This option will be ignored."); // FIXME: do this during validation instead } - if (targetConfig.get( - ThreadingProperty.INSTANCE)) { // FIXME: This logic is duplicated in CMake + if (!targetConfig.get( + SingleThreadedProperty.INSTANCE)) { // FIXME: This logic is duplicated in CMake pickScheduler(); // FIXME: this and pickScheduler should be combined. var map = new HashMap(); diff --git a/core/src/main/java/org/lflang/generator/c/CPreambleGenerator.java b/core/src/main/java/org/lflang/generator/c/CPreambleGenerator.java index dd4ebaf45e..c990db9eb7 100644 --- a/core/src/main/java/org/lflang/generator/c/CPreambleGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CPreambleGenerator.java @@ -10,7 +10,7 @@ import org.lflang.target.property.FedSetupProperty; import org.lflang.target.property.LoggingProperty; import org.lflang.target.property.PlatformProperty; -import org.lflang.target.property.ThreadingProperty; +import org.lflang.target.property.SingleThreadedProperty; import org.lflang.target.property.TracingProperty; import org.lflang.target.property.type.PlatformType.Platform; import org.lflang.util.StringUtil; @@ -48,7 +48,7 @@ public static String generateIncludeStatements(TargetConfig targetConfig, boolea .forEach(it -> code.pr("#include " + StringUtil.addDoubleQuotes(it))); code.pr("#include \"include/core/reactor.h\""); code.pr("#include \"include/core/reactor_common.h\""); - if (targetConfig.get(ThreadingProperty.INSTANCE)) { // FIXME: invert + if (!targetConfig.get(SingleThreadedProperty.INSTANCE)) { code.pr("#include \"include/core/threaded/scheduler.h\""); } @@ -87,12 +87,12 @@ public static String generateDefineDirectives(TargetConfig targetConfig, Path sr // targetConfig.clockSyncOptions // )); // } - if (targetConfig.get(ThreadingProperty.INSTANCE)) { + if (!targetConfig.get(SingleThreadedProperty.INSTANCE)) { definitions.put("LF_THREADED", "1"); } else { definitions.put("LF_UNTHREADED", "1"); } - if (targetConfig.get(ThreadingProperty.INSTANCE)) { + if (!targetConfig.get(SingleThreadedProperty.INSTANCE)) { definitions.put("LF_THREADED", "1"); } else { definitions.put("LF_UNTHREADED", "1"); diff --git a/core/src/main/java/org/lflang/generator/c/CTriggerObjectsGenerator.java b/core/src/main/java/org/lflang/generator/c/CTriggerObjectsGenerator.java index 8dcbda1e3a..e183615ce9 100644 --- a/core/src/main/java/org/lflang/generator/c/CTriggerObjectsGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CTriggerObjectsGenerator.java @@ -24,7 +24,7 @@ import org.lflang.generator.SendRange; import org.lflang.target.TargetConfig; import org.lflang.target.property.LoggingProperty; -import org.lflang.target.property.ThreadingProperty; +import org.lflang.target.property.SingleThreadedProperty; import org.lflang.target.property.type.LoggingType.LogLevel; /** @@ -102,7 +102,7 @@ public static String generateInitializeTriggerObjects( /** Generate code to initialize the scheduler for the threaded C runtime. */ public static String generateSchedulerInitializerMain( ReactorInstance main, TargetConfig targetConfig) { - if (!targetConfig.get(ThreadingProperty.INSTANCE)) { + if (targetConfig.get(SingleThreadedProperty.INSTANCE)) { return ""; } var code = new CodeBuilder(); diff --git a/core/src/main/java/org/lflang/target/Target.java b/core/src/main/java/org/lflang/target/Target.java index eb2cedd588..4c165b663e 100644 --- a/core/src/main/java/org/lflang/target/Target.java +++ b/core/src/main/java/org/lflang/target/Target.java @@ -55,7 +55,7 @@ import org.lflang.target.property.RustIncludeProperty; import org.lflang.target.property.SchedulerProperty; import org.lflang.target.property.SingleFileProjectProperty; -import org.lflang.target.property.ThreadingProperty; +import org.lflang.target.property.SingleThreadedProperty; import org.lflang.target.property.TracingProperty; import org.lflang.target.property.VerifyProperty; import org.lflang.target.property.WorkersProperty; @@ -600,7 +600,7 @@ public void initialize(TargetConfig config) { PlatformProperty.INSTANCE, ProtobufsProperty.INSTANCE, SchedulerProperty.INSTANCE, - ThreadingProperty.INSTANCE, + SingleThreadedProperty.INSTANCE, TracingProperty.INSTANCE, VerifyProperty.INSTANCE, WorkersProperty.INSTANCE); @@ -632,7 +632,7 @@ public void initialize(TargetConfig config) { KeepaliveProperty.INSTANCE, ProtobufsProperty.INSTANCE, SchedulerProperty.INSTANCE, - ThreadingProperty.INSTANCE, + SingleThreadedProperty.INSTANCE, TracingProperty.INSTANCE, WorkersProperty.INSTANCE); case Rust -> config.register( @@ -648,7 +648,7 @@ public void initialize(TargetConfig config) { KeepaliveProperty.INSTANCE, RuntimeVersionProperty.INSTANCE, SingleFileProjectProperty.INSTANCE, - ThreadingProperty.INSTANCE, + SingleThreadedProperty.INSTANCE, WorkersProperty.INSTANCE); case TS -> config.register( CoordinationOptionsProperty.INSTANCE, diff --git a/core/src/main/java/org/lflang/target/property/PlatformProperty.java b/core/src/main/java/org/lflang/target/property/PlatformProperty.java index 98867d23e2..3381aa1083 100644 --- a/core/src/main/java/org/lflang/target/property/PlatformProperty.java +++ b/core/src/main/java/org/lflang/target/property/PlatformProperty.java @@ -75,8 +75,9 @@ protected PlatformOptions fromString(String string, MessageReporter reporter) { @Override public void validate(KeyValuePair pair, Model ast, MessageReporter reporter) { var config = fromAst(pair.getValue(), reporter); - var threading = TargetProperty.getKeyValuePair(ast, ThreadingProperty.INSTANCE); - if (threading != null && config.platform == Platform.RP2040) { + var singleThreaded = SingleThreadedProperty.INSTANCE.fromAst( + TargetProperty.getKeyValuePair(ast, SingleThreadedProperty.INSTANCE).getValue(), reporter); + if (!singleThreaded && config.platform == Platform.RP2040) { reporter .at(pair, Literals.KEY_VALUE_PAIR__VALUE) .error("Platform " + Platform.RP2040 + " does not support threading"); diff --git a/core/src/main/java/org/lflang/target/property/ThreadingProperty.java b/core/src/main/java/org/lflang/target/property/SingleThreadedProperty.java similarity index 57% rename from core/src/main/java/org/lflang/target/property/ThreadingProperty.java rename to core/src/main/java/org/lflang/target/property/SingleThreadedProperty.java index f953dc8f1d..f96a755cc3 100644 --- a/core/src/main/java/org/lflang/target/property/ThreadingProperty.java +++ b/core/src/main/java/org/lflang/target/property/SingleThreadedProperty.java @@ -1,18 +1,18 @@ package org.lflang.target.property; /** Directive to indicate whether the runtime should use multi-threading. */ -public class ThreadingProperty extends BooleanProperty { +public class SingleThreadedProperty extends BooleanProperty { /** Singleton target property instance. */ - public static final ThreadingProperty INSTANCE = new ThreadingProperty(); + public static final SingleThreadedProperty INSTANCE = new SingleThreadedProperty(); - private ThreadingProperty() { + private SingleThreadedProperty() { super(); } @Override public String name() { - return "threading"; + return "single-threaded"; } @Override diff --git a/core/src/main/java/org/lflang/target/property/TracingProperty.java b/core/src/main/java/org/lflang/target/property/TracingProperty.java index a403c906a9..d78e596e0e 100644 --- a/core/src/main/java/org/lflang/target/property/TracingProperty.java +++ b/core/src/main/java/org/lflang/target/property/TracingProperty.java @@ -60,17 +60,17 @@ protected TracingOptions fromString(String string, MessageReporter reporter) { public void validate(KeyValuePair pair, Model ast, MessageReporter reporter) { if (pair != null && this.fromAst(pair.getValue(), reporter) != null) { // If tracing is anything but "false" and threading is off, error. - var threading = TargetProperty.getKeyValuePair(ast, ThreadingProperty.INSTANCE); - if (threading != null) { - if (!ASTUtils.toBoolean(threading.getValue())) { + var kvPair = TargetProperty.getKeyValuePair(ast, SingleThreadedProperty.INSTANCE); + var singleThreaded = SingleThreadedProperty.INSTANCE.fromAst( + kvPair.getValue(), reporter); + if (singleThreaded) { reporter .at(pair, Literals.KEY_VALUE_PAIR__NAME) .error("Cannot enable tracing because threading support is disabled"); reporter - .at(threading, Literals.KEY_VALUE_PAIR__NAME) + .at(kvPair, Literals.KEY_VALUE_PAIR__NAME) .error("Cannot disable treading support because tracing is enabled"); } - } } if (ASTUtils.getTarget(ast).equals(Target.CPP) && pair.getValue().getKeyvalue() != null) { reporter diff --git a/core/src/main/kotlin/org/lflang/generator/rust/RustModel.kt b/core/src/main/kotlin/org/lflang/generator/rust/RustModel.kt index 060a3b1772..232618a225 100644 --- a/core/src/main/kotlin/org/lflang/generator/rust/RustModel.kt +++ b/core/src/main/kotlin/org/lflang/generator/rust/RustModel.kt @@ -40,7 +40,7 @@ import org.lflang.target.property.KeepaliveProperty import org.lflang.target.property.RuntimeVersionProperty import org.lflang.target.property.RustIncludeProperty import org.lflang.target.property.SingleFileProjectProperty -import org.lflang.target.property.ThreadingProperty +import org.lflang.target.property.SingleThreadedProperty import org.lflang.target.property.TimeOutProperty import org.lflang.target.property.WorkersProperty import java.nio.file.Path @@ -490,7 +490,7 @@ object RustModelBuilder { // default configuration for the runtime crate // enable parallel feature if asked - val parallelFeature = listOf(PARALLEL_RT_FEATURE).takeIf { targetConfig.get(ThreadingProperty.INSTANCE) } + val parallelFeature = listOf(PARALLEL_RT_FEATURE).takeIf { !targetConfig.get(SingleThreadedProperty.INSTANCE) } val spec = newCargoSpec( features = parallelFeature, @@ -516,11 +516,11 @@ object RustModelBuilder { } // enable parallel feature if asked - if (targetConfig.get(ThreadingProperty.INSTANCE)) { + if (!targetConfig.get(SingleThreadedProperty.INSTANCE)) { userSpec.features += PARALLEL_RT_FEATURE } - if (!targetConfig.get(ThreadingProperty.INSTANCE) && PARALLEL_RT_FEATURE in userSpec.features) { + if (targetConfig.get(SingleThreadedProperty.INSTANCE) && PARALLEL_RT_FEATURE in userSpec.features) { messageReporter.nowhere().warning("Threading cannot be disabled as it was enabled manually as a runtime feature.") } diff --git a/core/src/testFixtures/java/org/lflang/tests/Configurators.java b/core/src/testFixtures/java/org/lflang/tests/Configurators.java index 95a85069fa..aed02e9d31 100644 --- a/core/src/testFixtures/java/org/lflang/tests/Configurators.java +++ b/core/src/testFixtures/java/org/lflang/tests/Configurators.java @@ -28,7 +28,7 @@ import org.lflang.target.property.LoggingProperty; import org.lflang.target.property.PlatformProperty; import org.lflang.target.property.PlatformProperty.PlatformOptions; -import org.lflang.target.property.ThreadingProperty; +import org.lflang.target.property.SingleThreadedProperty; import org.lflang.target.property.WorkersProperty; import org.lflang.target.property.type.LoggingType.LogLevel; import org.lflang.target.property.type.PlatformType.Platform; @@ -63,7 +63,7 @@ public interface Configurator { * @return True if successful, false otherwise. */ public static boolean disableThreading(TargetConfig config) { - ThreadingProperty.INSTANCE.override(config, false); + SingleThreadedProperty.INSTANCE.override(config, true); WorkersProperty.INSTANCE.override(config, 1); return true; } From 9d4b8de810aca1ad5b06426a3388cabd06a47ec3 Mon Sep 17 00:00:00 2001 From: Atharva Patil Date: Wed, 7 Jun 2023 16:50:16 +0900 Subject: [PATCH 03/24] Changed property in LF tests. --- test/C/src/DeadlineInherited.lf | 2 +- test/C/src/DeadlinePriority.lf | 2 +- test/C/src/DeadlineWithAfterDelay.lf | 2 +- test/C/src/DeadlineWithBanks.lf | 2 +- test/C/src/arduino/BlinkAttemptThreading.lf | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/test/C/src/DeadlineInherited.lf b/test/C/src/DeadlineInherited.lf index 785087b18b..28d4205b3c 100644 --- a/test/C/src/DeadlineInherited.lf +++ b/test/C/src/DeadlineInherited.lf @@ -1,7 +1,7 @@ // Test to verify that deadline priority are inherited target C { timeout: 1 sec, - threading: false + single-threaded: true } preamble {= diff --git a/test/C/src/DeadlinePriority.lf b/test/C/src/DeadlinePriority.lf index 95db38a259..46ed5e1281 100644 --- a/test/C/src/DeadlinePriority.lf +++ b/test/C/src/DeadlinePriority.lf @@ -1,7 +1,7 @@ // Test to verify that deadline gives priority target C { timeout: 1 sec, - threading: false + single-threaded: true } preamble {= diff --git a/test/C/src/DeadlineWithAfterDelay.lf b/test/C/src/DeadlineWithAfterDelay.lf index 12bd80425b..b62407ba74 100644 --- a/test/C/src/DeadlineWithAfterDelay.lf +++ b/test/C/src/DeadlineWithAfterDelay.lf @@ -1,7 +1,7 @@ // Test to verify that deadline priority are inherited when using after delays target C { timeout: 1 sec, - threading: false + single-threaded: true } preamble {= diff --git a/test/C/src/DeadlineWithBanks.lf b/test/C/src/DeadlineWithBanks.lf index 7d8c06b8fd..01a764f317 100644 --- a/test/C/src/DeadlineWithBanks.lf +++ b/test/C/src/DeadlineWithBanks.lf @@ -3,7 +3,7 @@ * downstream reactions. A global variable is used to check execution order. Threading is disabled */ target C { - threading: false, + single-threaded: true, timeout: 300 msec, build-type: Debug } diff --git a/test/C/src/arduino/BlinkAttemptThreading.lf b/test/C/src/arduino/BlinkAttemptThreading.lf index fb08214d26..99003e0506 100644 --- a/test/C/src/arduino/BlinkAttemptThreading.lf +++ b/test/C/src/arduino/BlinkAttemptThreading.lf @@ -8,7 +8,7 @@ target C { name: "arduino", board: "arduino:avr:mega" }, - threading: true + single-threaded: false } main reactor BlinkAttemptThreading { From 3d3f06446037cc1d5b2690af3738c26c09c4939b Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Fri, 3 Nov 2023 15:27:14 -0700 Subject: [PATCH 04/24] Adjust description --- core/src/testFixtures/java/org/lflang/tests/TestBase.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/testFixtures/java/org/lflang/tests/TestBase.java b/core/src/testFixtures/java/org/lflang/tests/TestBase.java index b2d5475efa..8f8d8f0021 100644 --- a/core/src/testFixtures/java/org/lflang/tests/TestBase.java +++ b/core/src/testFixtures/java/org/lflang/tests/TestBase.java @@ -148,7 +148,7 @@ public static class Message { public static final String DESC_ZEPHYR = "Running Zephyr tests."; public static final String DESC_AS_CCPP = "Running C tests as CCpp."; public static final String DESC_SINGLE_THREADED = - "Run non-concurrent and non-federated tests with threading = off."; + "Run non-concurrent and non-federated tests with in single-threaded mode."; public static final String DESC_SCHED_SWAPPING = "Running with non-default runtime scheduler "; public static final String DESC_ROS2 = "Running tests using ROS2."; public static final String DESC_MODAL = "Run modal reactor tests."; From 1bec63731f8eb7508fb00c48eb5478ef9b9d8ab8 Mon Sep 17 00:00:00 2001 From: Atharva Patil Date: Mon, 3 Jul 2023 18:34:21 +0900 Subject: [PATCH 05/24] Made CLI options --single-threaded and --workers mutually exclusive. --- cli/lfc/src/main/java/org/lflang/cli/Lfc.java | 50 ++++++++++++++----- .../test/java/org/lflang/cli/LfcCliTest.java | 15 ++++-- 2 files changed, 49 insertions(+), 16 deletions(-) diff --git a/cli/lfc/src/main/java/org/lflang/cli/Lfc.java b/cli/lfc/src/main/java/org/lflang/cli/Lfc.java index 55299e8c3c..c4cab73fde 100644 --- a/cli/lfc/src/main/java/org/lflang/cli/Lfc.java +++ b/cli/lfc/src/main/java/org/lflang/cli/Lfc.java @@ -33,6 +33,7 @@ import org.lflang.target.property.type.LoggingType.LogLevel; import org.lflang.target.property.type.SchedulerType; import org.lflang.target.property.type.SchedulerType.Scheduler; +import picocli.CommandLine.ArgGroup; import picocli.CommandLine.Command; import picocli.CommandLine.Option; @@ -139,22 +140,28 @@ public class Lfc extends CliBase { description = "Specify the runtime scheduler (if supported).") private String scheduler; - @Option( - names = "--single-threaded", - arity = "0", - description = "Specify whether the runtime should be single-threaded.") - private Boolean singleThreaded; - @Option( names = {"--tracing"}, arity = "0", description = "Specify whether to enable run-time tracing (if supported).") private Boolean tracing; - @Option( - names = {"-w", "--workers"}, - description = "Specify the default number of worker threads.") - private Integer workers; + /** Mutually exclusive options related to threading. */ + static class ThreadingMutuallyExclusive { + @Option( + names = "--single-threaded", + arity = "0", + description = "Specify whether the runtime should be single-threaded.") + private boolean singleThreaded; + + @Option( + names = {"-w", "--workers"}, + description = "Specify the default number of worker threads.") + private Integer workers; + } + + @ArgGroup(exclusive = true, multiplicity = "0..1") + Lfc.ThreadingMutuallyExclusive threading; /** * Main function of the stand-alone compiler. Caution: this will invoke System.exit. @@ -331,6 +338,25 @@ private TracingOptions getTracingOptions() { } } + /** Return the single threaded mode has been specified, or {@code null} if none was specified. */ + private Boolean getSingleThreaded() { + Boolean singleThreaded = null; + // Set one of the mutually-exclusive threading options. + if (threading != null) { + singleThreaded = threading.singleThreaded; + } + return singleThreaded; + } + + /** Return the number of workers specified, or {@code null} if none was specified. */ + private Integer getWorkers() { + Integer workers = null; + // Set one of the mutually-exclusive threading options. + if (threading != null) { + workers = threading.workers; + } + return workers; + } /** Check the values of the commandline arguments and return them. */ public GeneratorArguments getArgs() { @@ -351,8 +377,8 @@ public GeneratorArguments getArgs() { new Argument<>(VerifyProperty.INSTANCE, verify), new Argument<>(RuntimeVersionProperty.INSTANCE, runtimeVersion), new Argument<>(SchedulerProperty.INSTANCE, getScheduler()), - new Argument<>(SingleThreadedProperty.INSTANCE, singleThreaded), + new Argument<>(SingleThreadedProperty.INSTANCE, getSingleThreaded()), new Argument<>(TracingProperty.INSTANCE, getTracingOptions()), - new Argument<>(WorkersProperty.INSTANCE, workers))); + new Argument<>(WorkersProperty.INSTANCE, getWorkers()))); } } diff --git a/cli/lfc/src/test/java/org/lflang/cli/LfcCliTest.java b/cli/lfc/src/test/java/org/lflang/cli/LfcCliTest.java index 8f28194650..acc48b091b 100644 --- a/cli/lfc/src/test/java/org/lflang/cli/LfcCliTest.java +++ b/cli/lfc/src/test/java/org/lflang/cli/LfcCliTest.java @@ -50,8 +50,8 @@ import org.lflang.target.property.PrintStatisticsProperty; import org.lflang.target.property.RuntimeVersionProperty; import org.lflang.target.property.SchedulerProperty; -import org.lflang.target.property.TargetProperty; import org.lflang.target.property.SingleThreadedProperty; +import org.lflang.target.property.TargetProperty; import org.lflang.target.property.WorkersProperty; import org.lflang.target.property.type.BuildTypeType.BuildType; import org.lflang.target.property.type.LoggingType.LogLevel; @@ -92,8 +92,7 @@ public class LfcCliTest { "rti": "path/to/rti", "runtime-version": "rs", "scheduler": "GEDF_NP", - "single-threaded": true, - "workers": "1" + "single-threaded": true } } """; @@ -136,6 +135,14 @@ public void testMutuallyExclusiveCliArgs() { result.checkStdErr(containsString("are mutually exclusive (specify only one)")); result.checkFailed(); }); + + lfcTester + .run("File.lf", "--single-threaded", "--workers", "1") + .verify( + result -> { + result.checkStdErr(containsString("are mutually exclusive (specify only one)")); + result.checkFailed(); + }); } @Test @@ -336,7 +343,7 @@ public void testGeneratorArgs(@TempDir Path tempDir) throws IOException { "--single-threaded", "false", "--workers", - "1", + "1" }; verifyGeneratorArgs(tempDir, args); } From 4486ab0a9a786796fba7b6b979451c7090355404 Mon Sep 17 00:00:00 2001 From: Atharva Patil Date: Tue, 4 Jul 2023 00:07:34 +0900 Subject: [PATCH 06/24] Added LF validation test for mutually exclusive threading properties. --- .../tests/compiler/LinguaFrancaValidationTest.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/core/src/test/java/org/lflang/tests/compiler/LinguaFrancaValidationTest.java b/core/src/test/java/org/lflang/tests/compiler/LinguaFrancaValidationTest.java index a29655e4de..b27185390f 100644 --- a/core/src/test/java/org/lflang/tests/compiler/LinguaFrancaValidationTest.java +++ b/core/src/test/java/org/lflang/tests/compiler/LinguaFrancaValidationTest.java @@ -2301,4 +2301,18 @@ public void testUnspecifiedTransitionType() throws Exception { + "Reset and history transitions have different effects on this target mode. " + "Currently, a reset type is implicitly assumed."); } + + @Test + public void testMutuallyExclusiveThreadingParams() throws Exception { + String testCase = + """ + target C { single-threaded: true, workers: 1 } + main reactor {} + """; + List issues = validator.validate(parseWithoutError(testCase)); + Assertions.assertTrue( + issues.size() == 1 + && issues.get(0).getMessage().contains( + "Workers cannot be set when the single-threaded property is enabled.")); + } } From 6380e24d2dc4e44f8ae307bb345cc5571f3406f9 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Fri, 3 Nov 2023 15:44:31 -0700 Subject: [PATCH 07/24] Minor changes --- cli/lfc/src/main/java/org/lflang/cli/Lfc.java | 2 +- .../java/org/lflang/generator/c/CGenerator.java | 3 +-- .../target/property/PlatformProperty.java | 6 ++++-- .../lflang/target/property/TracingProperty.java | 17 ++++++++--------- test/C/src/arduino/BlinkAttemptThreading.lf | 3 +-- test/C/src/zephyr/threaded/UserThreads.lf | 1 - 6 files changed, 15 insertions(+), 17 deletions(-) diff --git a/cli/lfc/src/main/java/org/lflang/cli/Lfc.java b/cli/lfc/src/main/java/org/lflang/cli/Lfc.java index c4cab73fde..57dd65ba40 100644 --- a/cli/lfc/src/main/java/org/lflang/cli/Lfc.java +++ b/cli/lfc/src/main/java/org/lflang/cli/Lfc.java @@ -156,7 +156,7 @@ static class ThreadingMutuallyExclusive { @Option( names = {"-w", "--workers"}, - description = "Specify the default number of worker threads.") + description = "Specify the number of worker threads.") private Integer workers; } 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 2300a15e42..8e6e130d79 100644 --- a/core/src/main/java/org/lflang/generator/c/CGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CGenerator.java @@ -470,8 +470,7 @@ public void doGenerate(Resource resource, LFGeneratorContext context) { try { Path include = fileConfig.getSrcGenPath().resolve("include/"); Path src = fileConfig.getSrcGenPath().resolve("src/"); - FileUtil.arduinoDeleteHelper( - src, !targetConfig.get(SingleThreadedProperty.INSTANCE)); + FileUtil.arduinoDeleteHelper(src, !targetConfig.get(SingleThreadedProperty.INSTANCE)); FileUtil.relativeIncludeHelper(src, include, messageReporter); FileUtil.relativeIncludeHelper(include, include, messageReporter); } catch (IOException e) { diff --git a/core/src/main/java/org/lflang/target/property/PlatformProperty.java b/core/src/main/java/org/lflang/target/property/PlatformProperty.java index 3381aa1083..0194e6491b 100644 --- a/core/src/main/java/org/lflang/target/property/PlatformProperty.java +++ b/core/src/main/java/org/lflang/target/property/PlatformProperty.java @@ -75,8 +75,10 @@ protected PlatformOptions fromString(String string, MessageReporter reporter) { @Override public void validate(KeyValuePair pair, Model ast, MessageReporter reporter) { var config = fromAst(pair.getValue(), reporter); - var singleThreaded = SingleThreadedProperty.INSTANCE.fromAst( - TargetProperty.getKeyValuePair(ast, SingleThreadedProperty.INSTANCE).getValue(), reporter); + var singleThreaded = + SingleThreadedProperty.INSTANCE.fromAst( + TargetProperty.getKeyValuePair(ast, SingleThreadedProperty.INSTANCE).getValue(), + reporter); if (!singleThreaded && config.platform == Platform.RP2040) { reporter .at(pair, Literals.KEY_VALUE_PAIR__VALUE) diff --git a/core/src/main/java/org/lflang/target/property/TracingProperty.java b/core/src/main/java/org/lflang/target/property/TracingProperty.java index d78e596e0e..6489aca4df 100644 --- a/core/src/main/java/org/lflang/target/property/TracingProperty.java +++ b/core/src/main/java/org/lflang/target/property/TracingProperty.java @@ -61,16 +61,15 @@ public void validate(KeyValuePair pair, Model ast, MessageReporter reporter) { if (pair != null && this.fromAst(pair.getValue(), reporter) != null) { // If tracing is anything but "false" and threading is off, error. var kvPair = TargetProperty.getKeyValuePair(ast, SingleThreadedProperty.INSTANCE); - var singleThreaded = SingleThreadedProperty.INSTANCE.fromAst( - kvPair.getValue(), reporter); + var singleThreaded = SingleThreadedProperty.INSTANCE.fromAst(kvPair.getValue(), reporter); if (singleThreaded) { - reporter - .at(pair, Literals.KEY_VALUE_PAIR__NAME) - .error("Cannot enable tracing because threading support is disabled"); - reporter - .at(kvPair, Literals.KEY_VALUE_PAIR__NAME) - .error("Cannot disable treading support because tracing is enabled"); - } + reporter + .at(pair, Literals.KEY_VALUE_PAIR__NAME) + .error("Cannot enable tracing because threading support is disabled"); + reporter + .at(kvPair, Literals.KEY_VALUE_PAIR__NAME) + .error("Cannot disable treading support because tracing is enabled"); + } } if (ASTUtils.getTarget(ast).equals(Target.CPP) && pair.getValue().getKeyvalue() != null) { reporter diff --git a/test/C/src/arduino/BlinkAttemptThreading.lf b/test/C/src/arduino/BlinkAttemptThreading.lf index 99003e0506..3cb37ec280 100644 --- a/test/C/src/arduino/BlinkAttemptThreading.lf +++ b/test/C/src/arduino/BlinkAttemptThreading.lf @@ -7,8 +7,7 @@ target C { platform: { name: "arduino", board: "arduino:avr:mega" - }, - single-threaded: false + } } main reactor BlinkAttemptThreading { diff --git a/test/C/src/zephyr/threaded/UserThreads.lf b/test/C/src/zephyr/threaded/UserThreads.lf index 36f6e5b27a..ca515b5d6f 100644 --- a/test/C/src/zephyr/threaded/UserThreads.lf +++ b/test/C/src/zephyr/threaded/UserThreads.lf @@ -5,7 +5,6 @@ target C { name: Zephyr, user-threads: 3 }, - threading: true, workers: 2 } From 7c1e56bea2ca4413b71023e13fc67666b85b3057 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Sun, 5 Nov 2023 10:41:42 -0800 Subject: [PATCH 08/24] Fix unit tests and improve validation mechanism --- cli/lfc/src/main/java/org/lflang/cli/Lfc.java | 2 +- .../test/java/org/lflang/cli/LfcCliTest.java | 7 +- .../main/java/org/lflang/ast/ASTUtils.java | 19 +++- .../federated/generator/FedGenerator.java | 4 +- .../generator/FederateTargetConfig.java | 9 +- .../org/lflang/generator/GeneratorUtils.java | 3 +- .../org/lflang/generator/MainContext.java | 3 +- .../org/lflang/generator/c/CGenerator.java | 2 + .../main/java/org/lflang/target/Target.java | 3 +- .../java/org/lflang/target/TargetConfig.java | 95 +++++++++---------- .../property/CargoDependenciesProperty.java | 9 +- .../property/ClockSyncModeProperty.java | 23 ++--- .../property/ClockSyncOptionsProperty.java | 19 ++-- .../property/CoordinationOptionsProperty.java | 3 +- .../target/property/DockerProperty.java | 8 +- .../lflang/target/property/FastProperty.java | 52 +++++----- .../target/property/PlatformProperty.java | 40 ++++---- .../property/Ros2DependenciesProperty.java | 12 +-- .../target/property/SchedulerProperty.java | 52 +++++----- .../property/SingleThreadedProperty.java | 12 ++- .../target/property/TargetProperty.java | 54 +++-------- .../target/property/TracingProperty.java | 38 ++++---- .../target/property/WorkersProperty.java | 13 +++ .../org/lflang/validation/LFValidator.java | 3 +- .../compiler/LinguaFrancaValidationTest.java | 12 ++- 25 files changed, 235 insertions(+), 262 deletions(-) diff --git a/cli/lfc/src/main/java/org/lflang/cli/Lfc.java b/cli/lfc/src/main/java/org/lflang/cli/Lfc.java index 57dd65ba40..92751487b6 100644 --- a/cli/lfc/src/main/java/org/lflang/cli/Lfc.java +++ b/cli/lfc/src/main/java/org/lflang/cli/Lfc.java @@ -161,7 +161,7 @@ static class ThreadingMutuallyExclusive { } @ArgGroup(exclusive = true, multiplicity = "0..1") - Lfc.ThreadingMutuallyExclusive threading; + ThreadingMutuallyExclusive threading; /** * Main function of the stand-alone compiler. Caution: this will invoke System.exit. diff --git a/cli/lfc/src/test/java/org/lflang/cli/LfcCliTest.java b/cli/lfc/src/test/java/org/lflang/cli/LfcCliTest.java index acc48b091b..aa9090c480 100644 --- a/cli/lfc/src/test/java/org/lflang/cli/LfcCliTest.java +++ b/cli/lfc/src/test/java/org/lflang/cli/LfcCliTest.java @@ -52,7 +52,6 @@ import org.lflang.target.property.SchedulerProperty; import org.lflang.target.property.SingleThreadedProperty; import org.lflang.target.property.TargetProperty; -import org.lflang.target.property.WorkersProperty; import org.lflang.target.property.type.BuildTypeType.BuildType; import org.lflang.target.property.type.LoggingType.LogLevel; import org.lflang.target.property.type.SchedulerType.Scheduler; @@ -273,7 +272,6 @@ public void verifyGeneratorArgs(Path tempDir, String[] args) { checkOverrideValue(genArgs, RuntimeVersionProperty.INSTANCE, "rs"); checkOverrideValue(genArgs, SchedulerProperty.INSTANCE, Scheduler.GEDF_NP); checkOverrideValue(genArgs, SingleThreadedProperty.INSTANCE, true); - checkOverrideValue(genArgs, WorkersProperty.INSTANCE, 1); assertEquals(true, genArgs.clean()); assertEquals("src", Path.of(genArgs.externalRuntimeUri()).getFileName().toString()); @@ -340,10 +338,7 @@ public void testGeneratorArgs(@TempDir Path tempDir) throws IOException { "rs", "--scheduler", "GEDF_NP", - "--single-threaded", - "false", - "--workers", - "1" + "--single-threaded" }; verifyGeneratorArgs(tempDir, args); } diff --git a/core/src/main/java/org/lflang/ast/ASTUtils.java b/core/src/main/java/org/lflang/ast/ASTUtils.java index 1017d36dd3..b7709bec78 100644 --- a/core/src/main/java/org/lflang/ast/ASTUtils.java +++ b/core/src/main/java/org/lflang/ast/ASTUtils.java @@ -151,10 +151,10 @@ public static List getAllReactors(Resource resource) { } /** - * Get the main reactor defined in the given resource. + * Get the main reactor defined in the given resource, if there is one. * * @param resource the resource to extract reactors from - * @return An iterable over all reactors found in the resource + * @return An {@code Optional} reactor that may be present or absent. */ public static Optional getMainReactor(Resource resource) { return StreamSupport.stream( @@ -165,6 +165,21 @@ public static Optional getMainReactor(Resource resource) { .findFirst(); } + /** + * Get the federated reactor defined in the given resource, if there is one. + * + * @param resource the resource to extract reactors from + * @return An {@code Optional} reactor that may be present or absent. + */ + public static Optional getFederatedReactor(Resource resource) { + return StreamSupport.stream( + IteratorExtensions.toIterable(resource.getAllContents()).spliterator(), false) + .filter(Reactor.class::isInstance) + .map(Reactor.class::cast) + .filter(it -> it.isFederated()) + .findFirst(); + } + /** * Find connections in the given resource that would be conflicting writes if they were not * located in mutually exclusive modes. diff --git a/core/src/main/java/org/lflang/federated/generator/FedGenerator.java b/core/src/main/java/org/lflang/federated/generator/FedGenerator.java index f6bbac3b3f..c1cdc22f45 100644 --- a/core/src/main/java/org/lflang/federated/generator/FedGenerator.java +++ b/core/src/main/java/org/lflang/federated/generator/FedGenerator.java @@ -291,9 +291,7 @@ private Map compileFederates( TargetConfig subConfig = new TargetConfig( - GeneratorUtils.findTargetDecl(subFileConfig.resource), - GeneratorArguments.none(), - subContextMessageReporter); + subFileConfig.resource, GeneratorArguments.none(), subContextMessageReporter); if (targetConfig.get(DockerProperty.INSTANCE).enabled && targetConfig.target.buildsUsingDocker()) { NoCompileProperty.INSTANCE.override(subConfig, true); 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 6fc29f7164..aa7e1e148b 100644 --- a/core/src/main/java/org/lflang/federated/generator/FederateTargetConfig.java +++ b/core/src/main/java/org/lflang/federated/generator/FederateTargetConfig.java @@ -12,7 +12,6 @@ import org.lflang.generator.LFGeneratorContext; import org.lflang.lf.KeyValuePair; import org.lflang.lf.LfFactory; -import org.lflang.target.Target; import org.lflang.target.TargetConfig; import org.lflang.target.property.ClockSyncModeProperty; import org.lflang.target.property.ClockSyncOptionsProperty; @@ -36,11 +35,7 @@ public class FederateTargetConfig extends TargetConfig { public FederateTargetConfig(LFGeneratorContext context, Resource federateResource) { // Create target config based on the main .lf file (but with the target of the federate, // which could be different). - super( - Target.fromDecl(GeneratorUtils.findTargetDecl(federateResource)), - GeneratorUtils.findTargetDecl(context.getFileConfig().resource).getConfig(), - context.getArgs(), - context.getErrorReporter()); + super(federateResource, context.getArgs(), context.getErrorReporter()); mergeImportedConfig( federateResource, context.getFileConfig().resource, context.getErrorReporter()); @@ -119,7 +114,7 @@ public void update( value = LfFactory.eINSTANCE.createElement(); value.setArray(array); } - p.get().update(this, value, err); + p.get().update(this, pair, err); } }); } diff --git a/core/src/main/java/org/lflang/generator/GeneratorUtils.java b/core/src/main/java/org/lflang/generator/GeneratorUtils.java index 43854e9217..88dc9fa075 100644 --- a/core/src/main/java/org/lflang/generator/GeneratorUtils.java +++ b/core/src/main/java/org/lflang/generator/GeneratorUtils.java @@ -21,7 +21,6 @@ import org.lflang.lf.KeyValuePairs; import org.lflang.lf.Reactor; import org.lflang.lf.TargetDecl; -import org.lflang.target.Target; import org.lflang.target.TargetConfig; import org.lflang.target.property.KeepaliveProperty; @@ -120,7 +119,7 @@ public static LFResource getLFResource( MessageReporter messageReporter) { var target = ASTUtils.targetDecl(resource); KeyValuePairs config = target.getConfig(); - var targetConfig = new TargetConfig(Target.fromDecl(target)); + var targetConfig = new TargetConfig(resource, context.getArgs(), messageReporter); if (config != null) { List pairs = config.getPairs(); targetConfig.load(pairs != null ? pairs : List.of(), messageReporter); diff --git a/core/src/main/java/org/lflang/generator/MainContext.java b/core/src/main/java/org/lflang/generator/MainContext.java index e670c5696d..294b9a61b0 100644 --- a/core/src/main/java/org/lflang/generator/MainContext.java +++ b/core/src/main/java/org/lflang/generator/MainContext.java @@ -160,7 +160,6 @@ public void reportProgress(String message, int percentage) { * in the target configuration. */ public void loadTargetConfig() { - this.targetConfig = - new TargetConfig(GeneratorUtils.findTargetDecl(fileConfig.resource), args, messageReporter); + this.targetConfig = new TargetConfig(fileConfig.resource, args, messageReporter); } } 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 8e6e130d79..c56f9a6fcc 100644 --- a/core/src/main/java/org/lflang/generator/c/CGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CGenerator.java @@ -714,6 +714,8 @@ 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()); diff --git a/core/src/main/java/org/lflang/target/Target.java b/core/src/main/java/org/lflang/target/Target.java index 4c165b663e..cb5505dc6c 100644 --- a/core/src/main/java/org/lflang/target/Target.java +++ b/core/src/main/java/org/lflang/target/Target.java @@ -545,7 +545,8 @@ public boolean setsKeepAliveOptionAutomatically() { * @param string The string to match against candidates. * @param candidates The candidates to match the string against. */ - public static T match(final String string, final Iterable candidates) { + public static T match( + final String string, final Iterable candidates) { // FIXME: use Optional // kotlin: candidates.firstOrNull { it.toString().equalsIgnoreCase(string) } for (T candidate : candidates) { if (candidate.toString().equalsIgnoreCase(string)) { diff --git a/core/src/main/java/org/lflang/target/TargetConfig.java b/core/src/main/java/org/lflang/target/TargetConfig.java index 584b4e4694..49b438bfa2 100644 --- a/core/src/main/java/org/lflang/target/TargetConfig.java +++ b/core/src/main/java/org/lflang/target/TargetConfig.java @@ -36,13 +36,15 @@ import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; +import org.eclipse.emf.ecore.resource.Resource; import org.lflang.MessageReporter; +import org.lflang.ast.ASTUtils; import org.lflang.generator.GeneratorArguments; +import org.lflang.generator.GeneratorUtils; import org.lflang.lf.KeyValuePair; import org.lflang.lf.KeyValuePairs; import org.lflang.lf.LfFactory; import org.lflang.lf.LfPackage.Literals; -import org.lflang.lf.Model; import org.lflang.lf.TargetDecl; import org.lflang.target.property.FastProperty; import org.lflang.target.property.FedSetupProperty; @@ -51,7 +53,6 @@ import org.lflang.target.property.TargetProperty; import org.lflang.target.property.TimeOutProperty; import org.lflang.target.property.type.TargetPropertyType; -import org.lflang.validation.ValidatorMessageReporter; /** * A class for keeping the current target configuration. @@ -65,6 +66,12 @@ public class TargetConfig { /** The target of this configuration (e.g., C, TypeScript, Python). */ public final Target target; + private Resource mainResource; + + public Resource getMainResource() { + return mainResource; + } + /** * Create a new target configuration based on the given target declaration AST node only. * @@ -91,30 +98,15 @@ public TargetConfig(Target target) { * Create a new target configuration based on the given target declaration AST node and the * arguments passed to the code generator. * - * @param target AST node of a target declaration. + * @param resource The main resource. * @param args The arguments passed to the code generator. * @param messageReporter An error reporter. */ - public TargetConfig(TargetDecl target, GeneratorArguments args, MessageReporter messageReporter) { - this(Target.fromDecl(target), target.getConfig(), args, messageReporter); - } - - /** - * Create a new target configuration based on the given commandline arguments and target - * declaration AST node. - * - * @param target The target of this configuration. - * @param properties The key-value pairs that represent the target properties. - * @param args Arguments passed on the commandline. - * @param messageReporter An error reporter to report problems. - */ - public TargetConfig( - Target target, - KeyValuePairs properties, - GeneratorArguments args, - MessageReporter messageReporter) { - this(target); - + public TargetConfig(Resource resource, GeneratorArguments args, MessageReporter messageReporter) { + this(Target.fromDecl(GeneratorUtils.findTargetDecl(resource))); + this.mainResource = resource; + var targetDecl = GeneratorUtils.findTargetDecl(resource); + var properties = targetDecl.getConfig(); // Load properties from file if (properties != null) { List pairs = properties.getPairs(); @@ -126,6 +118,9 @@ public TargetConfig( // Load properties from CLI args load(args, messageReporter); + + // Validate to ensure consistency + validate(messageReporter); } private void load(JsonObject jsonObject, MessageReporter messageReporter) { @@ -155,6 +150,7 @@ public void reportUnsupportedTargetProperty(String name, MessageReporter.Stage2 String.format( "The target property '%s' is not supported by the %s target and is thus ignored.", name, this.target)); + stage2.info("Recognized properties are: " + this.listOfRegisteredProperties()); } /** Additional sources to add to the compile command if appropriate. */ @@ -163,6 +159,9 @@ public void reportUnsupportedTargetProperty(String name, MessageReporter.Stage2 /** Map of target properties */ protected final Map, Object> properties = new HashMap<>(); + /** Map from */ + protected final Map, KeyValuePair> keyValuePairs = new HashMap<>(); + /** Set of target properties that have been assigned a value */ private final Set> setProperties = new HashSet<>(); @@ -266,15 +265,20 @@ public void load(GeneratorArguments args, MessageReporter err) { */ 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(); - property.update(this, pair.getValue(), err); + // 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.nowhere()); + reportUnsupportedTargetProperty( + pair.getName(), err.at(pair, Literals.KEY_VALUE_PAIR__NAME)); } }); } @@ -306,6 +310,15 @@ public String settings() { return sb.toString(); } + public KeyValuePair lookup( + TargetProperty targetProperty) { + return this.keyValuePairs.get(targetProperty); + } + + public boolean isFederated() { + return ASTUtils.getFederatedReactor(this.getMainResource()).isPresent(); + } + /** * Extract all properties as a list of key-value pairs from a TargetConfig. The returned list only * includes properties that were explicitly set. @@ -349,32 +362,14 @@ public TargetDecl extractTargetDecl() { } /** - * Validate the given key-value pairs and report issues via the given reporter. + * Validate all set properties and report issues via the given reporter. * - * @param pairs The key-value pairs to validate. - * @param ast The root node of the AST from which the key-value pairs were taken. * @param reporter A reporter to report errors and warnings through. */ - public void validate(KeyValuePairs pairs, Model ast, ValidatorMessageReporter reporter) { - pairs - .getPairs() - .forEach( - pair -> { - var match = - this.getRegisteredProperties().stream() - .filter(prop -> prop.name().equalsIgnoreCase(pair.getName())) - .findAny(); - if (match.isPresent()) { - var p = match.get(); - p.checkType(pair, reporter); - p.validate(pair, ast, reporter); - } else { - reportUnsupportedTargetProperty( - pair.getName(), reporter.at(pair, Literals.KEY_VALUE_PAIR__NAME)); - reporter - .at(pair, Literals.KEY_VALUE_PAIR__NAME) - .info("Recognized properties are: " + this.listOfRegisteredProperties()); - } - }); + public void validate(MessageReporter reporter) { + this.setProperties.forEach( + p -> { + p.validate(this, reporter); + }); } } diff --git a/core/src/main/java/org/lflang/target/property/CargoDependenciesProperty.java b/core/src/main/java/org/lflang/target/property/CargoDependenciesProperty.java index 764ab70c11..abb10975cd 100644 --- a/core/src/main/java/org/lflang/target/property/CargoDependenciesProperty.java +++ b/core/src/main/java/org/lflang/target/property/CargoDependenciesProperty.java @@ -3,6 +3,7 @@ import java.util.HashMap; import java.util.Map; import org.lflang.MessageReporter; +import org.lflang.generator.InvalidLfSourceException; import org.lflang.generator.rust.CargoDependencySpec; import org.lflang.generator.rust.CargoDependencySpec.CargoDependenciesPropertyType; import org.lflang.lf.Element; @@ -52,7 +53,13 @@ public Map initialValue() { @Override protected Map fromAst(Element node, MessageReporter reporter) { - return CargoDependencySpec.parseAll(node); + Map map = null; + try { + map = CargoDependencySpec.parseAll(node); + } catch (InvalidLfSourceException e) { + reporter.at(e.getNode()).error(e.getMessage()); + } + return map; } @Override diff --git a/core/src/main/java/org/lflang/target/property/ClockSyncModeProperty.java b/core/src/main/java/org/lflang/target/property/ClockSyncModeProperty.java index 115b781366..796f862c18 100644 --- a/core/src/main/java/org/lflang/target/property/ClockSyncModeProperty.java +++ b/core/src/main/java/org/lflang/target/property/ClockSyncModeProperty.java @@ -4,10 +4,8 @@ import org.lflang.MessageReporter; import org.lflang.ast.ASTUtils; import org.lflang.lf.Element; -import org.lflang.lf.KeyValuePair; import org.lflang.lf.LfPackage.Literals; -import org.lflang.lf.Model; -import org.lflang.lf.Reactor; +import org.lflang.target.TargetConfig; import org.lflang.target.property.type.ClockSyncModeType; import org.lflang.target.property.type.ClockSyncModeType.ClockSyncMode; @@ -38,20 +36,11 @@ protected ClockSyncMode fromString(String string, MessageReporter reporter) { } @Override - public void validate(KeyValuePair pair, Model ast, MessageReporter reporter) { - super.validate(pair, ast, reporter); - if (pair != null) { - boolean federatedExists = false; - for (Reactor reactor : ast.getReactors()) { - if (reactor.isFederated()) { - federatedExists = true; - } - } - if (!federatedExists) { - reporter - .at(pair, Literals.KEY_VALUE_PAIR__NAME) - .warning("The clock-sync target property is incompatible with non-federated programs."); - } + public void validate(TargetConfig config, MessageReporter reporter) { + if (!config.isFederated()) { + reporter + .at(config.lookup(this), Literals.KEY_VALUE_PAIR__NAME) + .warning("The 'clock-sync' target property is incompatible with non-federated programs."); } } diff --git a/core/src/main/java/org/lflang/target/property/ClockSyncOptionsProperty.java b/core/src/main/java/org/lflang/target/property/ClockSyncOptionsProperty.java index b5d08eaedd..fc24495ad2 100644 --- a/core/src/main/java/org/lflang/target/property/ClockSyncOptionsProperty.java +++ b/core/src/main/java/org/lflang/target/property/ClockSyncOptionsProperty.java @@ -36,14 +36,17 @@ public ClockSyncOptions fromAst(Element node, MessageReporter reporter) { for (KeyValuePair entry : node.getKeyvalue().getPairs()) { ClockSyncOption option = (ClockSyncOption) DictionaryType.CLOCK_SYNC_OPTION_DICT.forName(entry.getName()); - switch (option) { - case ATTENUATION -> options.attenuation = ASTUtils.toInteger(entry.getValue()); - case COLLECT_STATS -> options.collectStats = ASTUtils.toBoolean(entry.getValue()); - case LOCAL_FEDERATES_ON -> options.localFederatesOn = ASTUtils.toBoolean(entry.getValue()); - case PERIOD -> options.period = ASTUtils.toTimeValue(entry.getValue()); - case TEST_OFFSET -> options.testOffset = ASTUtils.toTimeValue(entry.getValue()); - case TRIALS -> options.trials = ASTUtils.toInteger(entry.getValue()); - default -> {} + if (option != null) { + switch (option) { + case ATTENUATION -> options.attenuation = ASTUtils.toInteger(entry.getValue()); + case COLLECT_STATS -> options.collectStats = ASTUtils.toBoolean(entry.getValue()); + case LOCAL_FEDERATES_ON -> options.localFederatesOn = + ASTUtils.toBoolean(entry.getValue()); + case PERIOD -> options.period = ASTUtils.toTimeValue(entry.getValue()); + case TEST_OFFSET -> options.testOffset = ASTUtils.toTimeValue(entry.getValue()); + case TRIALS -> options.trials = ASTUtils.toInteger(entry.getValue()); + default -> {} + } } } return options; diff --git a/core/src/main/java/org/lflang/target/property/CoordinationOptionsProperty.java b/core/src/main/java/org/lflang/target/property/CoordinationOptionsProperty.java index 9d0767ee31..913e46d1cc 100644 --- a/core/src/main/java/org/lflang/target/property/CoordinationOptionsProperty.java +++ b/core/src/main/java/org/lflang/target/property/CoordinationOptionsProperty.java @@ -1,6 +1,5 @@ package org.lflang.target.property; -import java.util.Objects; import org.lflang.MessageReporter; import org.lflang.TimeValue; import org.lflang.ast.ASTUtils; @@ -36,7 +35,7 @@ public CoordinationOptions fromAst(Element node, MessageReporter reporter) { for (KeyValuePair entry : node.getKeyvalue().getPairs()) { CoordinationOption option = (CoordinationOption) DictionaryType.COORDINATION_OPTION_DICT.forName(entry.getName()); - if (Objects.requireNonNull(option) == CoordinationOption.ADVANCE_MESSAGE_INTERVAL) { + if (option != null && option.equals(CoordinationOption.ADVANCE_MESSAGE_INTERVAL)) { options.advanceMessageInterval = ASTUtils.toTimeValue(entry.getValue()); } } diff --git a/core/src/main/java/org/lflang/target/property/DockerProperty.java b/core/src/main/java/org/lflang/target/property/DockerProperty.java index fc72cf245c..369fcac9a9 100644 --- a/core/src/main/java/org/lflang/target/property/DockerProperty.java +++ b/core/src/main/java/org/lflang/target/property/DockerProperty.java @@ -1,6 +1,5 @@ package org.lflang.target.property; -import java.util.Objects; import org.lflang.MessageReporter; import org.lflang.ast.ASTUtils; import org.lflang.lf.Element; @@ -39,11 +38,12 @@ public DockerOptions fromAst(Element node, MessageReporter reporter) { if (ASTUtils.toBoolean(node)) { options.enabled = true; } - } else { + } else if (node.getKeyvalue() != null) { + + options.enabled = true; for (KeyValuePair entry : node.getKeyvalue().getPairs()) { - options.enabled = true; DockerOption option = (DockerOption) DictionaryType.DOCKER_DICT.forName(entry.getName()); - if (Objects.requireNonNull(option) == DockerOption.FROM) { + if (option != null && option.equals(DockerOption.FROM)) { options.from = ASTUtils.elementToSingleString(entry.getValue()); } } diff --git a/core/src/main/java/org/lflang/target/property/FastProperty.java b/core/src/main/java/org/lflang/target/property/FastProperty.java index d2509b81c3..e978bf0aa8 100644 --- a/core/src/main/java/org/lflang/target/property/FastProperty.java +++ b/core/src/main/java/org/lflang/target/property/FastProperty.java @@ -4,11 +4,10 @@ import org.lflang.ast.ASTUtils; import org.lflang.lf.Action; import org.lflang.lf.ActionOrigin; -import org.lflang.lf.KeyValuePair; import org.lflang.lf.LfPackage.Literals; -import org.lflang.lf.Model; import org.lflang.lf.Reactor; import org.lflang.target.Target; +import org.lflang.target.TargetConfig; /** * If true, configure the execution environment such that it does not wait for physical time to @@ -29,35 +28,28 @@ public String name() { } @Override - public void validate(KeyValuePair pair, Model ast, MessageReporter reporter) { - if (pair != null) { - // Check for federated - for (Reactor reactor : ast.getReactors()) { - // Check to see if the program has a federated reactor - if (reactor.isFederated()) { - reporter - .at(pair, Literals.KEY_VALUE_PAIR__NAME) - .error("The fast target property is incompatible with federated programs."); - break; - } - } + public void validate(TargetConfig config, MessageReporter reporter) { + var pair = config.lookup(this); + if (config.isSet(this) && config.isFederated()) { + reporter + .at(pair, Literals.KEY_VALUE_PAIR__NAME) + .error("The fast target property is incompatible with federated programs."); + } - final var target = ASTUtils.getTarget(ast); - if (target != Target.CPP) { - // Check for physical actions - for (Reactor reactor : ast.getReactors()) { - // Check to see if the program has a physical action in a reactor - for (Action action : reactor.getActions()) { - if (action.getOrigin().equals(ActionOrigin.PHYSICAL)) { - reporter - .at(pair, Literals.KEY_VALUE_PAIR__NAME) - .error( - String.format( - "In the %s target, the fast target property is incompatible with physical" - + " actions.", - target.toString())); - break; - } + if (config.target != Target.CPP) { + // Check for physical actions + for (Reactor reactor : ASTUtils.getAllReactors(config.getMainResource())) { + // Check to see if the program has a physical action in a reactor + for (Action action : reactor.getActions()) { + if (action.getOrigin().equals(ActionOrigin.PHYSICAL)) { + reporter + .at(pair, Literals.KEY_VALUE_PAIR__NAME) + .error( + String.format( + "In the %s target, the fast target property is incompatible with physical" + + " actions.", + config.target.toString())); + break; } } } diff --git a/core/src/main/java/org/lflang/target/property/PlatformProperty.java b/core/src/main/java/org/lflang/target/property/PlatformProperty.java index 0194e6491b..4e5ea72503 100644 --- a/core/src/main/java/org/lflang/target/property/PlatformProperty.java +++ b/core/src/main/java/org/lflang/target/property/PlatformProperty.java @@ -7,7 +7,7 @@ import org.lflang.lf.KeyValuePairs; import org.lflang.lf.LfFactory; import org.lflang.lf.LfPackage.Literals; -import org.lflang.lf.Model; +import org.lflang.target.TargetConfig; import org.lflang.target.property.PlatformProperty.PlatformOptions; import org.lflang.target.property.type.DictionaryType; import org.lflang.target.property.type.DictionaryType.DictionaryElement; @@ -45,22 +45,22 @@ public PlatformOptions fromAst(Element node, MessageReporter reporter) { var userThreads = 0; if (node.getLiteral() != null || node.getId() != null) { platform = new PlatformType().forName(ASTUtils.elementToSingleString(node)); - } else { + } else if (node.getKeyvalue() != null) { for (KeyValuePair entry : node.getKeyvalue().getPairs()) { PlatformOption option = (PlatformOption) DictionaryType.PLATFORM_DICT.forName(entry.getName()); - if (option == null) { - continue; // FIXME: should not be necessary - } - switch (option) { - case NAME -> { - platform = new PlatformType().forName(ASTUtils.elementToSingleString(entry.getValue())); + if (option != null) { + switch (option) { + case NAME -> { + platform = + new PlatformType().forName(ASTUtils.elementToSingleString(entry.getValue())); + } + case BAUDRATE -> baudRate = ASTUtils.toInteger(entry.getValue()); + case BOARD -> board = ASTUtils.elementToSingleString(entry.getValue()); + case FLASH -> flash = ASTUtils.toBoolean(entry.getValue()); + case PORT -> port = ASTUtils.elementToSingleString(entry.getValue()); + case USER_THREADS -> userThreads = ASTUtils.toInteger(entry.getValue()); } - case BAUDRATE -> baudRate = ASTUtils.toInteger(entry.getValue()); - case BOARD -> board = ASTUtils.elementToSingleString(entry.getValue()); - case FLASH -> flash = ASTUtils.toBoolean(entry.getValue()); - case PORT -> port = ASTUtils.elementToSingleString(entry.getValue()); - case USER_THREADS -> userThreads = ASTUtils.toInteger(entry.getValue()); } } } @@ -73,16 +73,12 @@ protected PlatformOptions fromString(String string, MessageReporter reporter) { } @Override - public void validate(KeyValuePair pair, Model ast, MessageReporter reporter) { - var config = fromAst(pair.getValue(), reporter); - var singleThreaded = - SingleThreadedProperty.INSTANCE.fromAst( - TargetProperty.getKeyValuePair(ast, SingleThreadedProperty.INSTANCE).getValue(), - reporter); - if (!singleThreaded && config.platform == Platform.RP2040) { + public void validate(TargetConfig config, MessageReporter reporter) { + var singleThreaded = config.get(SingleThreadedProperty.INSTANCE); + if (!singleThreaded && config.get(PlatformProperty.INSTANCE).platform == Platform.RP2040) { reporter - .at(pair, Literals.KEY_VALUE_PAIR__VALUE) - .error("Platform " + Platform.RP2040 + " does not support threading"); + .at(config.lookup(this), Literals.KEY_VALUE_PAIR__VALUE) + .error("Platform " + Platform.RP2040 + " does not support threading."); } } diff --git a/core/src/main/java/org/lflang/target/property/Ros2DependenciesProperty.java b/core/src/main/java/org/lflang/target/property/Ros2DependenciesProperty.java index ec21d58027..6c3f08758a 100644 --- a/core/src/main/java/org/lflang/target/property/Ros2DependenciesProperty.java +++ b/core/src/main/java/org/lflang/target/property/Ros2DependenciesProperty.java @@ -5,9 +5,8 @@ import org.lflang.MessageReporter; import org.lflang.ast.ASTUtils; import org.lflang.lf.Element; -import org.lflang.lf.KeyValuePair; import org.lflang.lf.LfPackage.Literals; -import org.lflang.lf.Model; +import org.lflang.target.TargetConfig; import org.lflang.target.property.type.ArrayType; /** Directive to specify additional ROS2 packages that this LF program depends on. */ @@ -36,12 +35,11 @@ protected List fromString(String string, MessageReporter reporter) { } @Override - public void validate(KeyValuePair pair, Model ast, MessageReporter reporter) { - var ros2enabled = TargetProperty.getKeyValuePair(ast, Ros2Property.INSTANCE); - if (pair != null && (ros2enabled == null || !ASTUtils.toBoolean(ros2enabled.getValue()))) { + public void validate(TargetConfig config, MessageReporter reporter) { + if (config.isSet(this) && !config.get(Ros2Property.INSTANCE)) { reporter - .at(pair, Literals.KEY_VALUE_PAIR__NAME) - .warning("Ignoring ros2-dependencies as ros2 compilation is disabled"); + .at(config.lookup(this), Literals.KEY_VALUE_PAIR__NAME) + .warning("Ignoring ros2-dependencies as ros2 compilation is disabled."); } } diff --git a/core/src/main/java/org/lflang/target/property/SchedulerProperty.java b/core/src/main/java/org/lflang/target/property/SchedulerProperty.java index 52bc48cc0b..2abadd7f75 100644 --- a/core/src/main/java/org/lflang/target/property/SchedulerProperty.java +++ b/core/src/main/java/org/lflang/target/property/SchedulerProperty.java @@ -3,9 +3,8 @@ import org.lflang.MessageReporter; import org.lflang.ast.ASTUtils; import org.lflang.lf.Element; -import org.lflang.lf.KeyValuePair; import org.lflang.lf.LfPackage.Literals; -import org.lflang.lf.Model; +import org.lflang.target.TargetConfig; import org.lflang.target.property.type.SchedulerType; import org.lflang.target.property.type.SchedulerType.Scheduler; @@ -50,34 +49,27 @@ public String name() { } @Override - public void validate(KeyValuePair pair, Model ast, MessageReporter reporter) { - if (pair != null) { - String schedulerName = ASTUtils.elementToSingleString(pair.getValue()); - try { - if (!Scheduler.valueOf(schedulerName).prioritizesDeadline()) { - // Check if a deadline is assigned to any reaction - // Filter reactors that contain at least one reaction that - // has a deadline handler. - if (ast.getReactors().stream() - .anyMatch( - // Filter reactors that contain at least one reaction that - // has a deadline handler. - reactor -> - ASTUtils.allReactions(reactor).stream() - .anyMatch(reaction -> reaction.getDeadline() != null))) { - reporter - .at(pair, Literals.KEY_VALUE_PAIR__VALUE) - .warning( - "This program contains deadlines, but the chosen " - + schedulerName - + " scheduler does not prioritize reaction execution " - + "based on deadlines. This might result in a sub-optimal " - + "scheduling."); - } - } - } catch (IllegalArgumentException e) { - // the given scheduler is invalid, but this is already checked by - // checkTargetProperties + public void validate(TargetConfig config, MessageReporter reporter) { + var scheduler = config.get(this); + if (!scheduler.prioritizesDeadline()) { + // Check if a deadline is assigned to any reaction + // Filter reactors that contain at least one reaction that + // has a deadline handler. + if (ASTUtils.getAllReactors(config.getMainResource()).stream() + .anyMatch( + // Filter reactors that contain at least one reaction that + // has a deadline handler. + reactor -> + ASTUtils.allReactions(reactor).stream() + .anyMatch(reaction -> reaction.getDeadline() != null))) { + reporter + .at(config.lookup(this), Literals.KEY_VALUE_PAIR__VALUE) + .warning( + "This program contains deadlines, but the chosen " + + scheduler + + " scheduler does not prioritize reaction execution " + + "based on deadlines. This might result in a sub-optimal " + + "scheduling."); } } } diff --git a/core/src/main/java/org/lflang/target/property/SingleThreadedProperty.java b/core/src/main/java/org/lflang/target/property/SingleThreadedProperty.java index f96a755cc3..6fd051261c 100644 --- a/core/src/main/java/org/lflang/target/property/SingleThreadedProperty.java +++ b/core/src/main/java/org/lflang/target/property/SingleThreadedProperty.java @@ -1,5 +1,9 @@ package org.lflang.target.property; +import org.lflang.MessageReporter; +import org.lflang.lf.LfPackage.Literals; +import org.lflang.target.TargetConfig; + /** Directive to indicate whether the runtime should use multi-threading. */ public class SingleThreadedProperty extends BooleanProperty { @@ -16,7 +20,11 @@ public String name() { } @Override - public Boolean initialValue() { - return true; + public void validate(TargetConfig config, MessageReporter reporter) { + if (config.isFederated() && config.get(this).equals(true)) { + reporter + .at(config.lookup(this), Literals.KEY_VALUE_PAIR__VALUE) + .error("Cannot enable single-threaded mode for federated program."); + } } } 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 1f3dc5182e..dfae6cba04 100644 --- a/core/src/main/java/org/lflang/target/property/TargetProperty.java +++ b/core/src/main/java/org/lflang/target/property/TargetProperty.java @@ -1,7 +1,6 @@ package org.lflang.target.property; import com.google.gson.JsonElement; -import java.util.List; import java.util.Optional; import org.lflang.MessageReporter; import org.lflang.lf.Element; @@ -40,12 +39,14 @@ protected TargetProperty(S type) { * @param reporter The reporter to issue an error through if the given key-value pair does not * match the type required by this property. */ - public void checkType(KeyValuePair pair, MessageReporter reporter) { - if (!this.type.check(pair.getValue(), pair.getName(), reporter)) { + public boolean checkType(KeyValuePair pair, MessageReporter reporter) { + boolean isOk = this.type.check(pair.getValue(), pair.getName(), reporter); + if (!isOk) { reporter .at(pair, Literals.KEY_VALUE_PAIR__VALUE) .error("Target property '" + pair.getName() + "' is required to be " + type + "."); } + return isOk; } @Override @@ -53,20 +54,21 @@ public String toString() { return this.name(); } + public void validate(KeyValuePair pair, Model ast, MessageReporter reporter) {} + + /** Return the initial value to assign to this target property. */ + public abstract T initialValue(); + /** * Override this method to implement additional checks. The base implementation does nothing. * *

This method is meant to perform additional validation above and beyond checking target * support and type checking which are done automatically. * - * @param pair The key-value pair to type check. - * @param ast The root of the abstract syntax tree. + * @param config The target configuration to check against. * @param reporter A reporter for reporting errors. */ - public void validate(KeyValuePair pair, Model ast, MessageReporter reporter) {} - - /** Return the initial value to assign to this target property. */ - public abstract T initialValue(); + public void validate(TargetConfig config, MessageReporter reporter) {} /** * Given an AST node, produce a corresponding value that is assignable to this target property, or @@ -130,28 +132,17 @@ public void update(TargetConfig config, T value) { * Update the given configuration based on the given corresponding AST node. * * @param config The configuration to update. - * @param node The node to perform the update with. + * @param pair The pair that holds the value to perform the update with. * @param reporter A reporter to report issues. */ - public final void update(TargetConfig config, Element node, MessageReporter reporter) { - this.update(config, fromAst(node, reporter)); + public final void update(TargetConfig config, KeyValuePair pair, MessageReporter reporter) { + this.update(config, fromAst(pair.getValue(), reporter)); } public final void update(TargetConfig config, JsonElement element, MessageReporter reporter) { this.update(config, fromJSON(element, reporter)); } - /** - * Update the given configuration based on the given corresponding AST node. - * - * @param config The configuration to update. - * @param value The node to perform the update with. - * @param reporter A reporter to report issues. - */ - public final void update(TargetConfig config, String value, MessageReporter reporter) { - this.update(config, fromString(value, reporter)); - } - /** * Return true if the given object is an instance of a class with the same name. * @@ -176,21 +167,4 @@ protected T fromJSON(JsonElement element, MessageReporter reporter) { } return value; } - - /** - * Retrieve a key-value pair from the given AST that matches the given target property. - * - * @param ast The AST retrieve the key-value pair from. - * @param property The target property of interest. - * @return The found key-value pair, or {@code null} if no matching pair could be found. - */ - public static KeyValuePair getKeyValuePair(Model ast, TargetProperty property) { - var targetProperties = ast.getTarget().getConfig(); - List properties = - targetProperties.getPairs().stream() - .filter(pair -> pair.getName().equals(property.name())) - .toList(); - assert properties.size() <= 1; - return properties.size() > 0 ? properties.get(0) : null; - } } diff --git a/core/src/main/java/org/lflang/target/property/TracingProperty.java b/core/src/main/java/org/lflang/target/property/TracingProperty.java index 6489aca4df..b47793c717 100644 --- a/core/src/main/java/org/lflang/target/property/TracingProperty.java +++ b/core/src/main/java/org/lflang/target/property/TracingProperty.java @@ -8,7 +8,6 @@ import org.lflang.lf.KeyValuePairs; import org.lflang.lf.LfFactory; import org.lflang.lf.LfPackage.Literals; -import org.lflang.lf.Model; import org.lflang.target.Target; import org.lflang.target.TargetConfig; import org.lflang.target.property.TracingProperty.TracingOptions; @@ -57,27 +56,28 @@ protected TracingOptions fromString(String string, MessageReporter reporter) { } @Override - public void validate(KeyValuePair pair, Model ast, MessageReporter reporter) { - if (pair != null && this.fromAst(pair.getValue(), reporter) != null) { - // If tracing is anything but "false" and threading is off, error. - var kvPair = TargetProperty.getKeyValuePair(ast, SingleThreadedProperty.INSTANCE); - var singleThreaded = SingleThreadedProperty.INSTANCE.fromAst(kvPair.getValue(), reporter); - if (singleThreaded) { - reporter - .at(pair, Literals.KEY_VALUE_PAIR__NAME) - .error("Cannot enable tracing because threading support is disabled"); + public void validate(TargetConfig config, MessageReporter reporter) { + var noThreads = + config.isSet(SingleThreadedProperty.INSTANCE) + && config.get(SingleThreadedProperty.INSTANCE).equals(true); + var pair = config.lookup(this); + if (config.get(this).isEnabled() && noThreads) { + reporter + .at(pair, Literals.KEY_VALUE_PAIR__NAME) + .error("Cannot enable tracing because threading support is disabled"); + reporter + .at(config.lookup(SingleThreadedProperty.INSTANCE), Literals.KEY_VALUE_PAIR__NAME) + .error("Cannot disable treading support because tracing is enabled"); + } + if (pair != null) { + if (config.target.equals(Target.CPP) && pair.getValue().getKeyvalue() != null) { reporter - .at(kvPair, Literals.KEY_VALUE_PAIR__NAME) - .error("Cannot disable treading support because tracing is enabled"); + .at(pair, Literals.KEY_VALUE_PAIR__VALUE) + .warning( + "The C++ target only supports 'true' or 'false' and ignores additional" + + " configuration"); } } - if (ASTUtils.getTarget(ast).equals(Target.CPP) && pair.getValue().getKeyvalue() != null) { - reporter - .at(pair, Literals.KEY_VALUE_PAIR__VALUE) - .warning( - "The C++ target only supports 'true' or 'false' and ignores additional" - + " configuration"); - } } @Override diff --git a/core/src/main/java/org/lflang/target/property/WorkersProperty.java b/core/src/main/java/org/lflang/target/property/WorkersProperty.java index defbf97740..ce0cae056c 100644 --- a/core/src/main/java/org/lflang/target/property/WorkersProperty.java +++ b/core/src/main/java/org/lflang/target/property/WorkersProperty.java @@ -3,6 +3,8 @@ import org.lflang.MessageReporter; import org.lflang.ast.ASTUtils; import org.lflang.lf.Element; +import org.lflang.lf.LfPackage.Literals; +import org.lflang.target.TargetConfig; import org.lflang.target.property.type.PrimitiveType; /** @@ -28,6 +30,17 @@ protected Integer fromString(String string, MessageReporter reporter) { return Integer.parseInt(string); // FIXME: check for exception } + @Override + public void validate(TargetConfig config, MessageReporter reporter) { + if (config.isSet(this) + && config.isSet(SingleThreadedProperty.INSTANCE) + && config.get(SingleThreadedProperty.INSTANCE).equals(true)) { + reporter + .at(config.lookup(this), Literals.KEY_VALUE_PAIR__NAME) + .error("Cannot specify workers in single-threaded mode."); + } + } + @Override protected Integer fromAst(Element node, MessageReporter reporter) { return ASTUtils.toInteger(node); diff --git a/core/src/main/java/org/lflang/validation/LFValidator.java b/core/src/main/java/org/lflang/validation/LFValidator.java index def6bcc8de..7dfa0e557d 100644 --- a/core/src/main/java/org/lflang/validation/LFValidator.java +++ b/core/src/main/java/org/lflang/validation/LFValidator.java @@ -62,6 +62,7 @@ import org.lflang.ast.ASTUtils; import org.lflang.federated.serialization.SupportedSerializers; import org.lflang.federated.validation.FedValidator; +import org.lflang.generator.GeneratorArguments; import org.lflang.generator.NamedInstance; import org.lflang.generator.c.TypeParameterizedReactor; import org.lflang.lf.Action; @@ -1076,7 +1077,7 @@ public void checkTargetProperties(KeyValuePairs targetProperties) { if (targetProperties.eContainer() instanceof TargetDecl) { // Skip dictionaries that may be part of a target property value because type checking is done // recursively. - new TargetConfig(this.target).validate(targetProperties, this.info.model, getErrorReporter()); + new TargetConfig(targetProperties.eResource(), GeneratorArguments.none(), getErrorReporter()); } } diff --git a/core/src/test/java/org/lflang/tests/compiler/LinguaFrancaValidationTest.java b/core/src/test/java/org/lflang/tests/compiler/LinguaFrancaValidationTest.java index b27185390f..e13e5fd05f 100644 --- a/core/src/test/java/org/lflang/tests/compiler/LinguaFrancaValidationTest.java +++ b/core/src/test/java/org/lflang/tests/compiler/LinguaFrancaValidationTest.java @@ -1547,6 +1547,7 @@ public Collection checkTargetProperties() throws Exception { "Property %s (%s) - known bad assignment: %s" .formatted(property.name(), type, it), () -> { + var issues = validator.validate(createModel(Target.C, property, it)); validator.assertError( createModel(Target.C, property, it), LfPackage.eINSTANCE.getKeyValuePair(), @@ -2309,10 +2310,11 @@ public void testMutuallyExclusiveThreadingParams() throws Exception { target C { single-threaded: true, workers: 1 } main reactor {} """; - List issues = validator.validate(parseWithoutError(testCase)); - Assertions.assertTrue( - issues.size() == 1 - && issues.get(0).getMessage().contains( - "Workers cannot be set when the single-threaded property is enabled.")); + + validator.assertError( + parseWithoutError(testCase), + LfPackage.eINSTANCE.getKeyValuePair(), + null, + "Cannot specify workers in single-threaded mode."); } } From a299194a0da1385953f57726d43763bf2f1196dd Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Sun, 5 Nov 2023 11:51:05 -0800 Subject: [PATCH 09/24] Fix bug --- core/src/main/java/org/lflang/generator/c/CGenerator.java | 4 ++-- 1 file changed, 2 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 c56f9a6fcc..b4025732a6 100644 --- a/core/src/main/java/org/lflang/generator/c/CGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CGenerator.java @@ -1959,9 +1959,9 @@ protected void setUpGeneralParameters() { messageReporter .nowhere() .info( - "Threading is incompatible on your current Arduino flavor. Setting threading to" + "Threading is incompatible plain (non-MBED) Arduino. Setting threading to" + " false."); - SingleThreadedProperty.INSTANCE.override(targetConfig, false); + SingleThreadedProperty.INSTANCE.override(targetConfig, true); } if (platformOptions.platform() == Platform.ARDUINO From 9e7eecc0cfdb6b72461815c457524464be6c90b5 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Sun, 5 Nov 2023 12:01:29 -0800 Subject: [PATCH 10/24] Fix another logic problem --- core/src/main/java/org/lflang/generator/c/CGenerator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 b4025732a6..cdecb2f45f 100644 --- a/core/src/main/java/org/lflang/generator/c/CGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CGenerator.java @@ -1952,7 +1952,7 @@ protected void setUpGeneralParameters() { if (targetConfig.isSet(PlatformProperty.INSTANCE)) { final var platformOptions = targetConfig.get(PlatformProperty.INSTANCE); - if (targetConfig.get(SingleThreadedProperty.INSTANCE) + if (!targetConfig.get(SingleThreadedProperty.INSTANCE) && platformOptions.platform() == Platform.ARDUINO && (platformOptions.board() == null || !platformOptions.board().contains("mbed"))) { // non-MBED boards should not use threading From 7b9c33bcf7c1e3b948ed68f153b37dde337e9bba Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Sun, 5 Nov 2023 13:04:54 -0800 Subject: [PATCH 11/24] Comments --- .../java/org/lflang/target/TargetConfig.java | 46 +++++++++++++------ .../target/property/TargetProperty.java | 16 +++++-- 2 files changed, 44 insertions(+), 18 deletions(-) diff --git a/core/src/main/java/org/lflang/target/TargetConfig.java b/core/src/main/java/org/lflang/target/TargetConfig.java index 49b438bfa2..6b23a71449 100644 --- a/core/src/main/java/org/lflang/target/TargetConfig.java +++ b/core/src/main/java/org/lflang/target/TargetConfig.java @@ -66,11 +66,20 @@ public class TargetConfig { /** The target of this configuration (e.g., C, TypeScript, Python). */ public final Target target; - private Resource mainResource; + /** Additional sources to add to the compile command if appropriate. */ + public final List compileAdditionalSources = new ArrayList<>(); - public Resource getMainResource() { - return mainResource; - } + /** Map of target properties */ + protected final Map, Object> properties = new HashMap<>(); + + /** Map from */ + protected final Map, KeyValuePair> keyValuePairs = new HashMap<>(); + + /** Set of target properties that have been assigned a value */ + private final Set> setProperties = new HashSet<>(); + + /** The main resource that is under compilation. */ + private Resource mainResource; /** * Create a new target configuration based on the given target declaration AST node only. @@ -123,6 +132,12 @@ public TargetConfig(Resource resource, GeneratorArguments args, MessageReporter validate(messageReporter); } + /** + * Update this configuration based on the given JSON object. + * + * @param jsonObject The JSON object to read updates from. + * @param messageReporter A message reporter to report issues. + */ private void load(JsonObject jsonObject, MessageReporter messageReporter) { if (jsonObject != null && jsonObject.has("properties")) { var map = jsonObject.getAsJsonObject("properties").asMap(); @@ -153,17 +168,10 @@ public void reportUnsupportedTargetProperty(String name, MessageReporter.Stage2 stage2.info("Recognized properties are: " + this.listOfRegisteredProperties()); } - /** Additional sources to add to the compile command if appropriate. */ - public final List compileAdditionalSources = new ArrayList<>(); - - /** Map of target properties */ - protected final Map, Object> properties = new HashMap<>(); - - /** Map from */ - protected final Map, KeyValuePair> keyValuePairs = new HashMap<>(); - - /** Set of target properties that have been assigned a value */ - private final Set> setProperties = new HashSet<>(); + /** Get the main resource that is under compilation. */ + public Resource getMainResource() { + return mainResource; + } /** * Register target properties and assign them their initial value. @@ -310,11 +318,19 @@ public String settings() { return sb.toString(); } + /** + * Return the AST node that was used to assign a value for the given target property. + * + * @param targetProperty The target property to find a matching AST node for. + * @param The Java type of values assigned to the given target property. + * @param The LF type of values assigned to the given target property. + */ public KeyValuePair lookup( TargetProperty targetProperty) { return this.keyValuePairs.get(targetProperty); } + /** Return whether this configuration is used in the context of a federated program. */ public boolean isFederated() { return ASTUtils.getFederatedReactor(this.getMainResource()).isPresent(); } 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 dfae6cba04..d2d630d6b3 100644 --- a/core/src/main/java/org/lflang/target/property/TargetProperty.java +++ b/core/src/main/java/org/lflang/target/property/TargetProperty.java @@ -6,7 +6,6 @@ import org.lflang.lf.Element; import org.lflang.lf.KeyValuePair; import org.lflang.lf.LfPackage.Literals; -import org.lflang.lf.Model; import org.lflang.target.TargetConfig; import org.lflang.target.property.type.TargetPropertyType; @@ -54,8 +53,6 @@ public String toString() { return this.name(); } - public void validate(KeyValuePair pair, Model ast, MessageReporter reporter) {} - /** Return the initial value to assign to this target property. */ public abstract T initialValue(); @@ -139,6 +136,13 @@ public final void update(TargetConfig config, KeyValuePair pair, MessageReporter this.update(config, fromAst(pair.getValue(), reporter)); } + /** + * Update the given configuration based on the given JSON element. + * + * @param config The configuration to update. + * @param element The JSON element that holds the value to perform the update with. + * @param reporter A reporter to report issues. + */ public final void update(TargetConfig config, JsonElement element, MessageReporter reporter) { this.update(config, fromJSON(element, reporter)); } @@ -158,6 +162,12 @@ public int hashCode() { return this.getClass().getName().hashCode(); } + /** + * Return a value based on the given JSON element. + * + * @param element The JSON element to produce a value from/ + * @param reporter A message reporter for reporting issues. + */ protected T fromJSON(JsonElement element, MessageReporter reporter) { T value = null; if (element.isJsonPrimitive()) { From 9564ada274631129066936b9c08ee4aa20fc24ff Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Sun, 5 Nov 2023 14:29:00 -0800 Subject: [PATCH 12/24] Fix bug in FederateTargetConfig --- .../org/lflang/federated/generator/FederateTargetConfig.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 aa7e1e148b..032dfeedf6 100644 --- a/core/src/main/java/org/lflang/federated/generator/FederateTargetConfig.java +++ b/core/src/main/java/org/lflang/federated/generator/FederateTargetConfig.java @@ -35,7 +35,7 @@ public class FederateTargetConfig extends TargetConfig { public FederateTargetConfig(LFGeneratorContext context, Resource federateResource) { // Create target config based on the main .lf file (but with the target of the federate, // which could be different). - super(federateResource, context.getArgs(), context.getErrorReporter()); + super(context.getFileConfig().resource, context.getArgs(), context.getErrorReporter()); mergeImportedConfig( federateResource, context.getFileConfig().resource, context.getErrorReporter()); From 98a06ba54e66087d9bb74bfd5c0f4bcd118dc5d5 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Sun, 5 Nov 2023 20:00:10 -0800 Subject: [PATCH 13/24] Modulo some code duplication, this should take care of the path problem --- .../generator/FederateTargetConfig.java | 61 ++++++++++++------- .../java/org/lflang/target/TargetConfig.java | 4 +- 2 files changed, 40 insertions(+), 25 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 032dfeedf6..8ff9c92aa1 100644 --- a/core/src/main/java/org/lflang/federated/generator/FederateTargetConfig.java +++ b/core/src/main/java/org/lflang/federated/generator/FederateTargetConfig.java @@ -11,10 +11,11 @@ import org.lflang.generator.GeneratorUtils; import org.lflang.generator.LFGeneratorContext; import org.lflang.lf.KeyValuePair; -import org.lflang.lf.LfFactory; +import org.lflang.target.Target; import org.lflang.target.TargetConfig; import org.lflang.target.property.ClockSyncModeProperty; import org.lflang.target.property.ClockSyncOptionsProperty; +import org.lflang.target.property.FileListProperty; import org.lflang.util.FileUtil; /** @@ -33,16 +34,36 @@ public class FederateTargetConfig extends TargetConfig { * @param federateResource The resource in which to find the reactor class of the federate. */ public FederateTargetConfig(LFGeneratorContext context, Resource federateResource) { - // Create target config based on the main .lf file (but with the target of the federate, - // which could be different). - super(context.getFileConfig().resource, context.getArgs(), context.getErrorReporter()); + // Create target config with the target based on the federate. + super(Target.fromDecl(GeneratorUtils.findTargetDecl(federateResource))); + this.mainResource = federateResource; + FederationFileConfig federationFileConfig = (FederationFileConfig) context.getFileConfig(); + var federationResource = context.getFileConfig().resource; + var reporter = context.getErrorReporter(); - mergeImportedConfig( - federateResource, context.getFileConfig().resource, context.getErrorReporter()); + var targetDecl = GeneratorUtils.findTargetDecl(federationResource); + var properties = targetDecl.getConfig(); + + // Load properties from the federation file + if (properties != null) { + List pairs = properties.getPairs(); + this.load(pairs, reporter); + } + + // Load properties from Json + load(context.getArgs().jsonObject(), reporter); + + // Load properties from CLI args + load(context.getArgs(), reporter); + + // Load properties from the federate file + mergeImportedConfig(federateResource, federationResource, reporter); clearPropertiesToIgnore(); - ((FederationFileConfig) context.getFileConfig()).relativizePaths(this); + federationFileConfig.relativizePaths(this); + + this.validate(reporter); } /** @@ -93,28 +114,22 @@ private void clearPropertiesToIgnore() { */ public void update( TargetConfig config, List pairs, Path relativePath, MessageReporter err) { - // FIXME: https://issue.lf-lang.org/2080 pairs.forEach( pair -> { var p = config.forName(pair.getName()); if (p.isPresent()) { var value = pair.getValue(); - if (pair.getName().equals("files")) { - var array = LfFactory.eINSTANCE.createArray(); - ASTUtils.elementToListOfStrings(pair.getValue()).stream() - .map(relativePath::resolve) // assume all paths are relative - .map(Objects::toString) - .map( - s -> { - var element = LfFactory.eINSTANCE.createElement(); - element.setLiteral(s); - return element; - }) - .forEach(array.getElements()::add); - value = LfFactory.eINSTANCE.createElement(); - value.setArray(array); + 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 { + p.get().update(this, pair, err); } - p.get().update(this, pair, err); } }); } diff --git a/core/src/main/java/org/lflang/target/TargetConfig.java b/core/src/main/java/org/lflang/target/TargetConfig.java index 6b23a71449..d1eb55e449 100644 --- a/core/src/main/java/org/lflang/target/TargetConfig.java +++ b/core/src/main/java/org/lflang/target/TargetConfig.java @@ -79,7 +79,7 @@ public class TargetConfig { private final Set> setProperties = new HashSet<>(); /** The main resource that is under compilation. */ - private Resource mainResource; + protected Resource mainResource; /** * Create a new target configuration based on the given target declaration AST node only. @@ -138,7 +138,7 @@ public TargetConfig(Resource resource, GeneratorArguments args, MessageReporter * @param jsonObject The JSON object to read updates from. * @param messageReporter A message reporter to report issues. */ - private void load(JsonObject jsonObject, MessageReporter messageReporter) { + protected void load(JsonObject jsonObject, MessageReporter messageReporter) { if (jsonObject != null && jsonObject.has("properties")) { var map = jsonObject.getAsJsonObject("properties").asMap(); map.keySet() From bb72e52c64287f3ab28ca8eed394085318e25773 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Sun, 5 Nov 2023 22:40:53 -0800 Subject: [PATCH 14/24] Cleanup --- .../generator/FederateTargetConfig.java | 22 +++------- .../java/org/lflang/target/TargetConfig.java | 43 ++++++++++++------- .../compiler/LinguaFrancaValidationTest.java | 3 +- 3 files changed, 34 insertions(+), 34 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 8ff9c92aa1..58d1e2d980 100644 --- a/core/src/main/java/org/lflang/federated/generator/FederateTargetConfig.java +++ b/core/src/main/java/org/lflang/federated/generator/FederateTargetConfig.java @@ -34,34 +34,22 @@ public class FederateTargetConfig extends TargetConfig { * @param federateResource The resource in which to find the reactor class of the federate. */ public FederateTargetConfig(LFGeneratorContext context, Resource federateResource) { - // Create target config with the target based on the federate. + // Create target config with the target based on the federate (not the main resource). super(Target.fromDecl(GeneratorUtils.findTargetDecl(federateResource))); - this.mainResource = federateResource; - FederationFileConfig federationFileConfig = (FederationFileConfig) context.getFileConfig(); var federationResource = context.getFileConfig().resource; var reporter = context.getErrorReporter(); - var targetDecl = GeneratorUtils.findTargetDecl(federationResource); - var properties = targetDecl.getConfig(); + this.mainResource = federationResource; - // Load properties from the federation file - if (properties != null) { - List pairs = properties.getPairs(); - this.load(pairs, reporter); - } - - // Load properties from Json - load(context.getArgs().jsonObject(), reporter); - - // Load properties from CLI args - load(context.getArgs(), reporter); + // Load properties and args from the main file + load(federationResource, context.getArgs(), reporter); // Load properties from the federate file mergeImportedConfig(federateResource, federationResource, reporter); clearPropertiesToIgnore(); - federationFileConfig.relativizePaths(this); + ((FederationFileConfig) context.getFileConfig()).relativizePaths(this); this.validate(reporter); } diff --git a/core/src/main/java/org/lflang/target/TargetConfig.java b/core/src/main/java/org/lflang/target/TargetConfig.java index d1eb55e449..014249e0b4 100644 --- a/core/src/main/java/org/lflang/target/TargetConfig.java +++ b/core/src/main/java/org/lflang/target/TargetConfig.java @@ -81,12 +81,20 @@ public class TargetConfig { /** The main resource that is under compilation. */ protected Resource mainResource; + /** + * Return mock instance to use for testing, which is not tied to a generator context or a + * resource. + */ + public static TargetConfig getMockInstance(Target target) { + return new TargetConfig(target); + } + /** * Create a new target configuration based on the given target declaration AST node only. * * @param target AST node of a target declaration. */ - public TargetConfig(Target target) { + protected TargetConfig(Target target) { this.target = target; // Register target-specific properties @@ -103,33 +111,36 @@ public TargetConfig(Target target) { TimeOutProperty.INSTANCE); } - /** - * Create a new target configuration based on the given target declaration AST node and the - * arguments passed to the code generator. - * - * @param resource The main resource. - * @param args The arguments passed to the code generator. - * @param messageReporter An error reporter. - */ - public TargetConfig(Resource resource, GeneratorArguments args, MessageReporter messageReporter) { - this(Target.fromDecl(GeneratorUtils.findTargetDecl(resource))); - this.mainResource = resource; + protected void load(Resource resource, GeneratorArguments args, 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, messageReporter); + this.load(pairs, reporter); } // Load properties from Json - load(args.jsonObject(), messageReporter); + load(args.jsonObject(), reporter); // Load properties from CLI args - load(args, messageReporter); + load(args, reporter); + } + /** + * Create a new target configuration based on the given target declaration AST node and the + * arguments passed to the code generator. + * + * @param resource The main resource. + * @param args The arguments passed to the code generator. + * @param reporter An error reporter. + */ + public TargetConfig(Resource resource, GeneratorArguments args, MessageReporter reporter) { + this(Target.fromDecl(GeneratorUtils.findTargetDecl(resource))); + this.mainResource = resource; + load(resource, args, reporter); // Validate to ensure consistency - validate(messageReporter); + validate(reporter); } /** diff --git a/core/src/test/java/org/lflang/tests/compiler/LinguaFrancaValidationTest.java b/core/src/test/java/org/lflang/tests/compiler/LinguaFrancaValidationTest.java index e13e5fd05f..0897551b5f 100644 --- a/core/src/test/java/org/lflang/tests/compiler/LinguaFrancaValidationTest.java +++ b/core/src/test/java/org/lflang/tests/compiler/LinguaFrancaValidationTest.java @@ -1510,7 +1510,8 @@ private Model createModel(Target target, TargetProperty property, String value) public Collection checkTargetProperties() throws Exception { List result = new ArrayList<>(); - for (TargetProperty property : (new TargetConfig(Target.C)).getRegisteredProperties()) { + for (TargetProperty property : + TargetConfig.getMockInstance(Target.C).getRegisteredProperties()) { if (property instanceof CargoDependenciesProperty) { // we test that separately as it has better error messages continue; From 0ece33802ff22504af187ab837647c3024f68e8b Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Sun, 5 Nov 2023 22:45:08 -0800 Subject: [PATCH 15/24] Comment --- core/src/main/java/org/lflang/target/TargetConfig.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/core/src/main/java/org/lflang/target/TargetConfig.java b/core/src/main/java/org/lflang/target/TargetConfig.java index 014249e0b4..71cf9a7bf8 100644 --- a/core/src/main/java/org/lflang/target/TargetConfig.java +++ b/core/src/main/java/org/lflang/target/TargetConfig.java @@ -111,6 +111,13 @@ protected TargetConfig(Target target) { TimeOutProperty.INSTANCE); } + /** + * Load configuration from the given resource and generator arguments. + * + * @param resource A resource to load from. + * @param args Generator arguments to load from. + * @param reporter A reporter for reporting issues. + */ protected void load(Resource resource, GeneratorArguments args, MessageReporter reporter) { var targetDecl = GeneratorUtils.findTargetDecl(resource); var properties = targetDecl.getConfig(); From 00f71f18695f36f648621e374b1a02f6047236e6 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Mon, 6 Nov 2023 00:19:57 -0800 Subject: [PATCH 16/24] Address comment from @cmnrd --- .../federated/generator/FederateTargetConfig.java | 7 +++++-- .../main/java/org/lflang/target/TargetConfig.java | 15 +++++---------- 2 files changed, 10 insertions(+), 12 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 58d1e2d980..178120a95e 100644 --- a/core/src/main/java/org/lflang/federated/generator/FederateTargetConfig.java +++ b/core/src/main/java/org/lflang/federated/generator/FederateTargetConfig.java @@ -41,12 +41,15 @@ public FederateTargetConfig(LFGeneratorContext context, Resource federateResourc this.mainResource = federationResource; - // Load properties and args from the main file - load(federationResource, context.getArgs(), reporter); + // Load properties from the main file + load(federationResource, reporter); // Load properties from the federate file mergeImportedConfig(federateResource, federationResource, reporter); + // Load properties from the generator context + load(context.getArgs(), reporter); + clearPropertiesToIgnore(); ((FederationFileConfig) context.getFileConfig()).relativizePaths(this); diff --git a/core/src/main/java/org/lflang/target/TargetConfig.java b/core/src/main/java/org/lflang/target/TargetConfig.java index 71cf9a7bf8..6170947db0 100644 --- a/core/src/main/java/org/lflang/target/TargetConfig.java +++ b/core/src/main/java/org/lflang/target/TargetConfig.java @@ -112,13 +112,12 @@ protected TargetConfig(Target target) { } /** - * Load configuration from the given resource and generator arguments. + * Load configuration from the given resource. * * @param resource A resource to load from. - * @param args Generator arguments to load from. * @param reporter A reporter for reporting issues. */ - protected void load(Resource resource, GeneratorArguments args, MessageReporter reporter) { + protected void load(Resource resource, MessageReporter reporter) { var targetDecl = GeneratorUtils.findTargetDecl(resource); var properties = targetDecl.getConfig(); // Load properties from file @@ -126,12 +125,6 @@ protected void load(Resource resource, GeneratorArguments args, MessageReporter List pairs = properties.getPairs(); this.load(pairs, reporter); } - - // Load properties from Json - load(args.jsonObject(), reporter); - - // Load properties from CLI args - load(args, reporter); } /** @@ -145,7 +138,8 @@ protected void load(Resource resource, GeneratorArguments args, MessageReporter public TargetConfig(Resource resource, GeneratorArguments args, MessageReporter reporter) { this(Target.fromDecl(GeneratorUtils.findTargetDecl(resource))); this.mainResource = resource; - load(resource, args, reporter); + load(resource, reporter); + load(args, reporter); // Validate to ensure consistency validate(reporter); } @@ -280,6 +274,7 @@ public String listOfRegisteredProperties() { * @param err Message reporter to report attempts to set unsupported target properties. */ public void load(GeneratorArguments args, MessageReporter err) { + load(args.jsonObject(), err); args.overrides().forEach(a -> a.update(this, err)); } From c26d630a138123057161eb22d1adc2eb1e12a68b Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Mon, 6 Nov 2023 07:44:48 -0800 Subject: [PATCH 17/24] Update core/src/main/java/org/lflang/generator/c/CGenerator.java Co-authored-by: erling --- core/src/main/java/org/lflang/generator/c/CGenerator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 6943508a91..1093a399ed 100644 --- a/core/src/main/java/org/lflang/generator/c/CGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CGenerator.java @@ -1967,7 +1967,7 @@ protected void setUpGeneralParameters() { messageReporter .nowhere() .info( - "Threading is incompatible plain (non-MBED) Arduino. Setting threading to" + "Threading is incompatible with plain (non-MBED) Arduino. Setting threading to" + " false."); SingleThreadedProperty.INSTANCE.override(targetConfig, true); } From 34498d51c68baf251ccd3ca2b33cbe863ace666d Mon Sep 17 00:00:00 2001 From: Erling Rennemo Jellum Date: Mon, 6 Nov 2023 19:20:50 +0100 Subject: [PATCH 18/24] Fix Arduino building --- .../org/lflang/generator/c/CGenerator.java | 4 +- .../java/org/lflang/util/ArduinoUtil.java | 60 +++++++------------ 2 files changed, 24 insertions(+), 40 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 1093a399ed..c78959b928 100644 --- a/core/src/main/java/org/lflang/generator/c/CGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CGenerator.java @@ -492,9 +492,9 @@ public void doGenerate(Resource resource, LFGeneratorContext context) { + "Grab the FQBN and PORT from the command and run the following command in the" + " generated sources directory:\n\n" + "\tarduino-cli compile -b --build-property" - + " compiler.c.extra_flags='-DLF_UNTHREADED -DPLATFORM_ARDUINO" + + " compiler.c.extra_flags='-DLF_SINGLE_THREADED -DPLATFORM_ARDUINO" + " -DINITIAL_EVENT_QUEUE_SIZE=10 -DINITIAL_REACT_QUEUE_SIZE=10'" - + " --build-property compiler.cpp.extra_flags='-DLF_UNTHREADED" + + " --build-property compiler.cpp.extra_flags='-DLF_SINGLE_THREADED" + " -DPLATFORM_ARDUINO -DINITIAL_EVENT_QUEUE_SIZE=10" + " -DINITIAL_REACT_QUEUE_SIZE=10' .\n\n" + "To flash/upload your generated sketch to the board, run the following" diff --git a/core/src/main/java/org/lflang/util/ArduinoUtil.java b/core/src/main/java/org/lflang/util/ArduinoUtil.java index 75da247a12..3f3a14cd6a 100644 --- a/core/src/main/java/org/lflang/util/ArduinoUtil.java +++ b/core/src/main/java/org/lflang/util/ArduinoUtil.java @@ -56,45 +56,29 @@ private LFCommand arduinoCompileCommand(FileConfig fileConfig, TargetConfig targ throws IOException { if (!checkArduinoCLIExists()) { throw new IOException("Must have arduino-cli installed to auto-compile."); - } else { - var srcGenPath = fileConfig.getSrcGenPath(); - try { - // Write to a temporary file to execute since ProcessBuilder does not like spaces and double - // quotes in its arguments. - File testScript = File.createTempFile("arduino", null); - testScript.deleteOnExit(); - if (!testScript.setExecutable(true)) { - throw new IOException("Failed to make compile script executable"); - } - var fileWriter = new FileWriter(testScript.getAbsoluteFile(), true); - BufferedWriter bufferedWriter = new BufferedWriter(fileWriter); - String board = - targetConfig.get(PlatformProperty.INSTANCE).board() != null - ? targetConfig.get(PlatformProperty.INSTANCE).board() - : "arduino:avr:leonardo"; - String isThreaded = - targetConfig.get(PlatformProperty.INSTANCE).board().contains("mbed") - ? "-DLF_THREADED" - : "-DLF_UNTHREADED"; - bufferedWriter.write( - "arduino-cli compile -b " - + board - + " --build-property " - + "compiler.c.extra_flags=\"" - + isThreaded - + " -DPLATFORM_ARDUINO -DINITIAL_EVENT_QUEUE_SIZE=10" - + " -DINITIAL_REACT_QUEUE_SIZE=10\" --build-property compiler.cpp.extra_flags=\"" - + isThreaded - + " -DPLATFORM_ARDUINO -DINITIAL_EVENT_QUEUE_SIZE=10" - + " -DINITIAL_REACT_QUEUE_SIZE=10\" " - + srcGenPath.toString()); - bufferedWriter.close(); - return commandFactory.createCommand(testScript.getAbsolutePath(), List.of(), null); - } catch (IOException e) { - e.printStackTrace(); - throw new IOException(e); - } } + + var srcGenPath = fileConfig.getSrcGenPath(); + String board = + targetConfig.get(PlatformProperty.INSTANCE).board() != null + ? targetConfig.get(PlatformProperty.INSTANCE).board() + : "arduino:avr:leonardo"; + String compileDefs = targetConfig.get(PlatformProperty.INSTANCE).board().contains("mbed") ? + "" : "-DLF_SINGLE_THREADED" + + " -DPLATFORM_ARDUINO" + + " -DINITIAL_EVENT_QUEUE_SIZE=10" + + " -DINITIAL_REACT_QUEUE_SIZE=10"; + + return commandFactory.createCommand("arduino-cli", List.of( + "compile", + "-b", + board, + "--build-property", + "compiler.c.extra_flags="+compileDefs, + "--build-property", + "compiler.cpp.extra_flags=" + compileDefs, + srcGenPath.toString()), + null); } /** From 91c36ddbe64d1c1ed0e8e33d1ac27caaed3b6334 Mon Sep 17 00:00:00 2001 From: Erling Rennemo Jellum Date: Mon, 6 Nov 2023 19:40:42 +0100 Subject: [PATCH 19/24] Code-generate LF_SINGLE_THREADED also --- .../java/org/lflang/generator/c/CCmakeGenerator.java | 10 ++-------- .../org/lflang/generator/c/CPreambleGenerator.java | 11 ++--------- .../generator/python/PythonDelayBodyGenerator.java | 4 ++-- 3 files changed, 6 insertions(+), 19 deletions(-) diff --git a/core/src/main/java/org/lflang/generator/c/CCmakeGenerator.java b/core/src/main/java/org/lflang/generator/c/CCmakeGenerator.java index 0723ba8d79..e928cfbd3e 100644 --- a/core/src/main/java/org/lflang/generator/c/CCmakeGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CCmakeGenerator.java @@ -268,11 +268,7 @@ CodeBuilder generateCMakeCode( .get(CompileDefinitionsProperty.INSTANCE) .forEach( (key, value) -> { - if (key.equals("LF_THREADED") || key.equals("LF_UNTHREADED")) { - cMakeCode.pr("if (NOT DEFINED LF_THREADED AND NOT DEFINED LF_UNTHREADED)\n"); - } else { - cMakeCode.pr("if (NOT DEFINED " + key + ")\n"); - } + cMakeCode.pr("if (NOT DEFINED " + key + ")\n"); cMakeCode.indent(); var v = "TRUE"; if (value != null && !value.isEmpty()) { @@ -372,11 +368,9 @@ CodeBuilder generateCMakeCode( + targetConfig.get(WorkersProperty.INSTANCE) + ")"); cMakeCode.newLine(); - cMakeCode.pr("# Set flag to indicate a multi-threaded runtime"); - cMakeCode.pr("target_compile_definitions( ${LF_MAIN_TARGET} PUBLIC LF_THREADED=1)"); } else { cMakeCode.pr("# Set flag to indicate a single-threaded runtime"); - cMakeCode.pr("target_compile_definitions( ${LF_MAIN_TARGET} PUBLIC LF_UNTHREADED=1)"); + cMakeCode.pr("target_compile_definitions( ${LF_MAIN_TARGET} PUBLIC LF_SINGLE_THREADED=1)"); } cMakeCode.newLine(); diff --git a/core/src/main/java/org/lflang/generator/c/CPreambleGenerator.java b/core/src/main/java/org/lflang/generator/c/CPreambleGenerator.java index c990db9eb7..4eaf989981 100644 --- a/core/src/main/java/org/lflang/generator/c/CPreambleGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CPreambleGenerator.java @@ -87,15 +87,8 @@ public static String generateDefineDirectives(TargetConfig targetConfig, Path sr // targetConfig.clockSyncOptions // )); // } - if (!targetConfig.get(SingleThreadedProperty.INSTANCE)) { - definitions.put("LF_THREADED", "1"); - } else { - definitions.put("LF_UNTHREADED", "1"); - } - if (!targetConfig.get(SingleThreadedProperty.INSTANCE)) { - definitions.put("LF_THREADED", "1"); - } else { - definitions.put("LF_UNTHREADED", "1"); + if (targetConfig.get(SingleThreadedProperty.INSTANCE)) { + definitions.put("LF_SINGLE_THREADED", "1"); } CompileDefinitionsProperty.INSTANCE.update(targetConfig, definitions); code.newLine(); diff --git a/core/src/main/java/org/lflang/generator/python/PythonDelayBodyGenerator.java b/core/src/main/java/org/lflang/generator/python/PythonDelayBodyGenerator.java index 2feb887bf7..3ccb54f490 100644 --- a/core/src/main/java/org/lflang/generator/python/PythonDelayBodyGenerator.java +++ b/core/src/main/java/org/lflang/generator/python/PythonDelayBodyGenerator.java @@ -39,7 +39,7 @@ public String generateDelayBody(Action action, VarRef port) { return String.join( "\n", "// Create a token.", - "#if defined(LF_THREADED)", + "#if !defined(LF_SINGLE_THREADED)", "// Need to lock the mutex first.", "lf_mutex_lock(&self->base.environment->mutex);", "#endif", @@ -49,7 +49,7 @@ public String generateDelayBody(Action action, VarRef port) { + value + ", 1);", "Py_INCREF(" + value + ");", - "#if defined(LF_THREADED)", + "#if !defined(LF_SINGLE_THREADED)", "lf_mutex_unlock(&self->base.environment->mutex);", "#endif", "", From 00dc9a2bd3a7288f7a327da048ee59e3207e0b4b Mon Sep 17 00:00:00 2001 From: Erling Rennemo Jellum Date: Mon, 6 Nov 2023 19:40:55 +0100 Subject: [PATCH 20/24] Bump reactor-c --- core/src/main/resources/lib/c/reactor-c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/resources/lib/c/reactor-c b/core/src/main/resources/lib/c/reactor-c index 5bbdefd558..f6829c478f 160000 --- a/core/src/main/resources/lib/c/reactor-c +++ b/core/src/main/resources/lib/c/reactor-c @@ -1 +1 @@ -Subproject commit 5bbdefd558b2504cd6fd8e881132b11efdce498b +Subproject commit f6829c478f6764e99e85496af404ab5749172080 From f3aaf0bfb58f5f4c73a9d69d64d26b1b967e8da1 Mon Sep 17 00:00:00 2001 From: erlingrj Date: Mon, 6 Nov 2023 21:11:58 +0100 Subject: [PATCH 21/24] Fix Arduino compilation --- core/src/main/java/org/lflang/util/ArduinoUtil.java | 5 +++-- core/src/main/resources/lib/c/reactor-c | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/core/src/main/java/org/lflang/util/ArduinoUtil.java b/core/src/main/java/org/lflang/util/ArduinoUtil.java index 3f3a14cd6a..8264355f41 100644 --- a/core/src/main/java/org/lflang/util/ArduinoUtil.java +++ b/core/src/main/java/org/lflang/util/ArduinoUtil.java @@ -63,8 +63,9 @@ private LFCommand arduinoCompileCommand(FileConfig fileConfig, TargetConfig targ targetConfig.get(PlatformProperty.INSTANCE).board() != null ? targetConfig.get(PlatformProperty.INSTANCE).board() : "arduino:avr:leonardo"; - String compileDefs = targetConfig.get(PlatformProperty.INSTANCE).board().contains("mbed") ? - "" : "-DLF_SINGLE_THREADED" + + + String compileDefs = (targetConfig.get(PlatformProperty.INSTANCE).board().contains("mbed") ? + "" : "-DLF_SINGLE_THREADED") + " -DPLATFORM_ARDUINO" + " -DINITIAL_EVENT_QUEUE_SIZE=10" + " -DINITIAL_REACT_QUEUE_SIZE=10"; diff --git a/core/src/main/resources/lib/c/reactor-c b/core/src/main/resources/lib/c/reactor-c index f6829c478f..07c3c40b31 160000 --- a/core/src/main/resources/lib/c/reactor-c +++ b/core/src/main/resources/lib/c/reactor-c @@ -1 +1 @@ -Subproject commit f6829c478f6764e99e85496af404ab5749172080 +Subproject commit 07c3c40b3134480fff8b01da8927e4e0cc79d1d1 From f0d761ecc2a16655454868a18a8fab3e74e6b496 Mon Sep 17 00:00:00 2001 From: erlingrj Date: Mon, 6 Nov 2023 22:01:43 +0100 Subject: [PATCH 22/24] Spotless --- .../java/org/lflang/util/ArduinoUtil.java | 35 ++++++++++--------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/core/src/main/java/org/lflang/util/ArduinoUtil.java b/core/src/main/java/org/lflang/util/ArduinoUtil.java index 8264355f41..00d11431be 100644 --- a/core/src/main/java/org/lflang/util/ArduinoUtil.java +++ b/core/src/main/java/org/lflang/util/ArduinoUtil.java @@ -1,8 +1,5 @@ package org.lflang.util; -import java.io.BufferedWriter; -import java.io.File; -import java.io.FileWriter; import java.io.IOException; import java.util.List; import org.eclipse.xtext.xbase.lib.Exceptions; @@ -64,21 +61,25 @@ private LFCommand arduinoCompileCommand(FileConfig fileConfig, TargetConfig targ ? targetConfig.get(PlatformProperty.INSTANCE).board() : "arduino:avr:leonardo"; - String compileDefs = (targetConfig.get(PlatformProperty.INSTANCE).board().contains("mbed") ? - "" : "-DLF_SINGLE_THREADED") + - " -DPLATFORM_ARDUINO" + - " -DINITIAL_EVENT_QUEUE_SIZE=10" + - " -DINITIAL_REACT_QUEUE_SIZE=10"; + String compileDefs = + (targetConfig.get(PlatformProperty.INSTANCE).board().contains("mbed") + ? "" + : "-DLF_SINGLE_THREADED") + + " -DPLATFORM_ARDUINO" + + " -DINITIAL_EVENT_QUEUE_SIZE=10" + + " -DINITIAL_REACT_QUEUE_SIZE=10"; - return commandFactory.createCommand("arduino-cli", List.of( - "compile", - "-b", - board, - "--build-property", - "compiler.c.extra_flags="+compileDefs, - "--build-property", - "compiler.cpp.extra_flags=" + compileDefs, - srcGenPath.toString()), + return commandFactory.createCommand( + "arduino-cli", + List.of( + "compile", + "-b", + board, + "--build-property", + "compiler.c.extra_flags=" + compileDefs, + "--build-property", + "compiler.cpp.extra_flags=" + compileDefs, + srcGenPath.toString()), null); } From 3132c4e21216dd1fedbf669b5764dd02c55b2c3c Mon Sep 17 00:00:00 2001 From: Erling Rennemo Jellum Date: Tue, 7 Nov 2023 15:21:53 +0100 Subject: [PATCH 23/24] Bump reactor-c --- core/src/main/resources/lib/c/reactor-c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/resources/lib/c/reactor-c b/core/src/main/resources/lib/c/reactor-c index 07c3c40b31..02a13f0d43 160000 --- a/core/src/main/resources/lib/c/reactor-c +++ b/core/src/main/resources/lib/c/reactor-c @@ -1 +1 @@ -Subproject commit 07c3c40b3134480fff8b01da8927e4e0cc79d1d1 +Subproject commit 02a13f0d436b1618c2f923597319113fb1a28732 From e58de5b5f451c0ae741c85277623d0176e24c36f Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Tue, 7 Nov 2023 19:03:10 -0800 Subject: [PATCH 24/24] Update submodule --- core/src/main/resources/lib/c/reactor-c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/resources/lib/c/reactor-c b/core/src/main/resources/lib/c/reactor-c index 02a13f0d43..b19fff3339 160000 --- a/core/src/main/resources/lib/c/reactor-c +++ b/core/src/main/resources/lib/c/reactor-c @@ -1 +1 @@ -Subproject commit 02a13f0d436b1618c2f923597319113fb1a28732 +Subproject commit b19fff33391b19a01fa45c37d425d76f9f6ea21b