From d56eceaa81527f1080d76b7631ad785a55ad9e7b Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Thu, 31 Aug 2023 22:26:04 -0700 Subject: [PATCH 001/145] WIP towards refactoring target properties --- cli/lfc/src/main/java/org/lflang/cli/Lfc.java | 2 +- .../lflang/tests/runtime/CSchedulerTest.java | 2 +- .../main/java/org/lflang/TargetConfig.java | 14 +- .../main/java/org/lflang/TargetProperty.java | 2322 ++++++----------- .../java/org/lflang/TargetPropertyConfig.java | 26 + .../federated/extensions/CExtension.java | 2 +- .../extensions/FedTargetExtension.java | 2 +- .../federated/extensions/PythonExtension.java | 2 +- .../federated/extensions/TSExtension.java | 2 +- .../federated/generator/FedASTUtils.java | 2 +- .../federated/generator/FedGenerator.java | 2 +- .../launcher/FedLauncherGenerator.java | 4 +- .../lflang/generator/c/CCmakeGenerator.java | 2 +- .../org/lflang/generator/c/CCompiler.java | 6 +- .../org/lflang/generator/c/CGenerator.java | 5 +- .../generator/c/CMainFunctionGenerator.java | 2 +- .../generator/c/CPreambleGenerator.java | 2 +- .../generator/c/CTriggerObjectsGenerator.java | 2 +- .../generator/rust/CargoDependencySpec.java | 2 +- .../generator/rust/RustTargetConfig.java | 2 +- .../org/lflang/target/AuthConfigurator.java | 33 + .../lflang/target/ClockSyncConfigurator.java | 115 + .../org/lflang/target/CoordinationConfig.java | 83 + .../java/org/lflang/target/DockerConfig.java | 66 + .../org/lflang/target/FastConfigurator.java | 64 + .../lflang/target/KeepaliveConfigurator.java | 42 + .../lflang/target/LoggingConfigurator.java | 23 + .../lflang/target/PlatformConfigurator.java | 142 + .../target/Ros2DependenciesConfigurator.java | 41 + .../lflang/target/SchedulerConfigurator.java | 121 + .../lflang/target/TracingConfigurator.java | 131 + .../lflang/target/property/BuildConfig.java | 32 + .../target/property/type/ArrayType.java | 61 + .../target/property/type/DictionaryType.java | 95 + .../target/property/type/PrimitiveType.java | 114 + .../property/type/StringDictionaryType.java | 35 + .../property/type/TargetPropertyType.java | 48 + .../target/property/type/UnionType.java | 137 + .../org/lflang/validation/LFValidator.java | 184 +- .../lflang/validation/ValidationReporter.java | 10 + .../compiler/LinguaFrancaValidationTest.java | 12 +- .../java/org/lflang/tests/Configurators.java | 4 +- 42 files changed, 2262 insertions(+), 1736 deletions(-) create mode 100644 core/src/main/java/org/lflang/TargetPropertyConfig.java create mode 100644 core/src/main/java/org/lflang/target/AuthConfigurator.java create mode 100644 core/src/main/java/org/lflang/target/ClockSyncConfigurator.java create mode 100644 core/src/main/java/org/lflang/target/CoordinationConfig.java create mode 100644 core/src/main/java/org/lflang/target/DockerConfig.java create mode 100644 core/src/main/java/org/lflang/target/FastConfigurator.java create mode 100644 core/src/main/java/org/lflang/target/KeepaliveConfigurator.java create mode 100644 core/src/main/java/org/lflang/target/LoggingConfigurator.java create mode 100644 core/src/main/java/org/lflang/target/PlatformConfigurator.java create mode 100644 core/src/main/java/org/lflang/target/Ros2DependenciesConfigurator.java create mode 100644 core/src/main/java/org/lflang/target/SchedulerConfigurator.java create mode 100644 core/src/main/java/org/lflang/target/TracingConfigurator.java create mode 100644 core/src/main/java/org/lflang/target/property/BuildConfig.java create mode 100644 core/src/main/java/org/lflang/target/property/type/ArrayType.java create mode 100644 core/src/main/java/org/lflang/target/property/type/DictionaryType.java create mode 100644 core/src/main/java/org/lflang/target/property/type/PrimitiveType.java create mode 100644 core/src/main/java/org/lflang/target/property/type/StringDictionaryType.java create mode 100644 core/src/main/java/org/lflang/target/property/type/TargetPropertyType.java create mode 100644 core/src/main/java/org/lflang/target/property/type/UnionType.java create mode 100644 core/src/main/java/org/lflang/validation/ValidationReporter.java 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 f8a51d367f..eb30503aca 100644 --- a/cli/lfc/src/main/java/org/lflang/cli/Lfc.java +++ b/cli/lfc/src/main/java/org/lflang/cli/Lfc.java @@ -10,7 +10,7 @@ import org.eclipse.xtext.generator.JavaIoFileSystemAccess; import org.eclipse.xtext.util.CancelIndicator; import org.lflang.FileConfig; -import org.lflang.TargetProperty.UnionType; +import org.lflang.target.property.type.UnionType; import org.lflang.ast.ASTUtils; import org.lflang.generator.LFGeneratorContext; import org.lflang.generator.LFGeneratorContext.BuildParm; diff --git a/core/src/integrationTest/java/org/lflang/tests/runtime/CSchedulerTest.java b/core/src/integrationTest/java/org/lflang/tests/runtime/CSchedulerTest.java index fd2345723f..c064560ead 100644 --- a/core/src/integrationTest/java/org/lflang/tests/runtime/CSchedulerTest.java +++ b/core/src/integrationTest/java/org/lflang/tests/runtime/CSchedulerTest.java @@ -3,7 +3,7 @@ import java.util.EnumSet; import org.junit.jupiter.api.Test; import org.lflang.Target; -import org.lflang.TargetProperty.SchedulerOption; +import org.lflang.target.SchedulerConfigurator.SchedulerOption; import org.lflang.tests.Configurators; import org.lflang.tests.TestBase; import org.lflang.tests.TestRegistry.TestCategory; diff --git a/core/src/main/java/org/lflang/TargetConfig.java b/core/src/main/java/org/lflang/TargetConfig.java index 12096f9d6c..2e7ee40005 100644 --- a/core/src/main/java/org/lflang/TargetConfig.java +++ b/core/src/main/java/org/lflang/TargetConfig.java @@ -32,17 +32,17 @@ import java.util.Objects; import java.util.Properties; import java.util.Set; -import org.lflang.TargetProperty.BuildType; -import org.lflang.TargetProperty.ClockSyncMode; -import org.lflang.TargetProperty.CoordinationType; -import org.lflang.TargetProperty.LogLevel; -import org.lflang.TargetProperty.Platform; -import org.lflang.TargetProperty.SchedulerOption; -import org.lflang.TargetProperty.UnionType; import org.lflang.generator.LFGeneratorContext.BuildParm; import org.lflang.generator.rust.RustTargetConfig; import org.lflang.lf.KeyValuePair; import org.lflang.lf.TargetDecl; +import org.lflang.target.property.BuildConfig.BuildType; +import org.lflang.target.ClockSyncConfigurator.ClockSyncMode; +import org.lflang.target.CoordinationConfig.CoordinationType; +import org.lflang.target.LoggingConfigurator.LogLevel; +import org.lflang.target.PlatformConfigurator.Platform; +import org.lflang.target.SchedulerConfigurator.SchedulerOption; +import org.lflang.target.property.type.UnionType; /** * A class for keeping the current target configuration. diff --git a/core/src/main/java/org/lflang/TargetProperty.java b/core/src/main/java/org/lflang/TargetProperty.java index d494e1d760..5246f72e51 100644 --- a/core/src/main/java/org/lflang/TargetProperty.java +++ b/core/src/main/java/org/lflang/TargetProperty.java @@ -25,18 +25,14 @@ package org.lflang; -import com.google.common.collect.ImmutableList; import java.nio.file.Path; import java.util.Arrays; import java.util.LinkedList; import java.util.List; import java.util.Objects; -import java.util.Optional; -import java.util.function.Predicate; -import java.util.stream.Collectors; + import org.lflang.TargetConfig.DockerOptions; import org.lflang.TargetConfig.PlatformOptions; -import org.lflang.TargetConfig.TracingOptions; import org.lflang.ast.ASTUtils; import org.lflang.generator.InvalidLfSourceException; import org.lflang.generator.rust.CargoDependencySpec; @@ -46,10 +42,30 @@ import org.lflang.lf.KeyValuePair; import org.lflang.lf.KeyValuePairs; import org.lflang.lf.LfFactory; +import org.lflang.lf.Model; import org.lflang.lf.TargetDecl; +import org.lflang.target.property.BuildConfig.BuildType; +import org.lflang.target.ClockSyncConfigurator; +import org.lflang.target.ClockSyncConfigurator.ClockSyncOption; +import org.lflang.target.CoordinationConfig.CoordinationOption; +import org.lflang.target.CoordinationConfig.CoordinationType; +import org.lflang.target.DockerConfig.DockerOption; +import org.lflang.target.FastConfigurator; +import org.lflang.target.KeepaliveConfigurator; +import org.lflang.target.LoggingConfigurator.LogLevel; +import org.lflang.target.PlatformConfigurator.Platform; +import org.lflang.target.PlatformConfigurator.PlatformOption; +import org.lflang.target.SchedulerConfigurator; +import org.lflang.target.property.type.ArrayType; +import org.lflang.target.property.type.DictionaryType; +import org.lflang.target.property.type.StringDictionaryType; +import org.lflang.target.property.type.TargetPropertyType; +import org.lflang.target.property.type.PrimitiveType; +import org.lflang.target.TracingConfigurator; +import org.lflang.target.property.type.UnionType; import org.lflang.util.FileUtil; import org.lflang.util.StringUtil; -import org.lflang.validation.LFValidator; +import org.lflang.validation.ValidationReporter; /** * A target properties along with a type and a list of supporting targets that supports it, as well @@ -59,776 +75,730 @@ */ public enum TargetProperty { /** Directive to allow including OpenSSL libraries and process HMAC authentication. */ - AUTH( - "auth", - PrimitiveType.BOOLEAN, - Arrays.asList(Target.C, Target.CCPP), - (config) -> ASTUtils.toElement(config.auth), - (config, value, err) -> { - config.auth = ASTUtils.toBoolean(value); - }), - /** Directive to let the generator use the custom build command. */ - BUILD( - "build", - UnionType.STRING_OR_STRING_ARRAY, - Arrays.asList(Target.C, Target.CCPP), - (config) -> ASTUtils.toElement(config.buildCommands), - (config, value, err) -> { - config.buildCommands = ASTUtils.elementToListOfStrings(value); - }), - - /** - * Directive to specify the target build type such as 'Release' or 'Debug'. This is also used in - * the Rust target to select a Cargo profile. - */ - BUILD_TYPE( - "build-type", - UnionType.BUILD_TYPE_UNION, - Arrays.asList(Target.C, Target.CCPP, Target.CPP, Target.Rust), - (config) -> ASTUtils.toElement(config.cmakeBuildType.toString()), - (config, value, err) -> { - config.cmakeBuildType = - (BuildType) UnionType.BUILD_TYPE_UNION.forName(ASTUtils.elementToSingleString(value)); - // set it there too, because the default is different. - config.rust.setBuildType(config.cmakeBuildType); - }), - - /** Directive to let the federate execution handle clock synchronization in software. */ - CLOCK_SYNC( - "clock-sync", - UnionType.CLOCK_SYNC_UNION, - Arrays.asList(Target.C, Target.CCPP, Target.Python), - (config) -> ASTUtils.toElement(config.clockSync.toString()), - (config, value, err) -> { - config.clockSync = - (ClockSyncMode) - UnionType.CLOCK_SYNC_UNION.forName(ASTUtils.elementToSingleString(value)); - }), - /** Key-value pairs giving options for clock synchronization. */ - CLOCK_SYNC_OPTIONS( - "clock-sync-options", - DictionaryType.CLOCK_SYNC_OPTION_DICT, - Arrays.asList(Target.C, Target.CCPP, Target.Python), - (config) -> { - Element e = LfFactory.eINSTANCE.createElement(); - KeyValuePairs kvp = LfFactory.eINSTANCE.createKeyValuePairs(); - for (ClockSyncOption opt : ClockSyncOption.values()) { - KeyValuePair pair = LfFactory.eINSTANCE.createKeyValuePair(); - pair.setName(opt.toString()); - switch (opt) { - case ATTENUATION: - pair.setValue(ASTUtils.toElement(config.clockSyncOptions.attenuation)); - break; - case COLLECT_STATS: - pair.setValue(ASTUtils.toElement(config.clockSyncOptions.collectStats)); - break; - case LOCAL_FEDERATES_ON: - pair.setValue(ASTUtils.toElement(config.clockSyncOptions.localFederatesOn)); - break; - case PERIOD: - if (config.clockSyncOptions.period == null) continue; // don't set if null - pair.setValue(ASTUtils.toElement(config.clockSyncOptions.period)); - break; - case TEST_OFFSET: - if (config.clockSyncOptions.testOffset == null) continue; // don't set if null - pair.setValue(ASTUtils.toElement(config.clockSyncOptions.testOffset)); - break; - case TRIALS: - pair.setValue(ASTUtils.toElement(config.clockSyncOptions.trials)); - break; - } - kvp.getPairs().add(pair); - } - e.setKeyvalue(kvp); - // kvp will never be empty - return e; - }, - (config, value, err) -> { - for (KeyValuePair entry : value.getKeyvalue().getPairs()) { - ClockSyncOption option = - (ClockSyncOption) DictionaryType.CLOCK_SYNC_OPTION_DICT.forName(entry.getName()); - switch (option) { - case ATTENUATION: - config.clockSyncOptions.attenuation = ASTUtils.toInteger(entry.getValue()); - break; - case COLLECT_STATS: - config.clockSyncOptions.collectStats = ASTUtils.toBoolean(entry.getValue()); - break; - case LOCAL_FEDERATES_ON: - config.clockSyncOptions.localFederatesOn = ASTUtils.toBoolean(entry.getValue()); - break; - case PERIOD: - config.clockSyncOptions.period = ASTUtils.toTimeValue(entry.getValue()); - break; - case TEST_OFFSET: - config.clockSyncOptions.testOffset = ASTUtils.toTimeValue(entry.getValue()); - break; - case TRIALS: - config.clockSyncOptions.trials = ASTUtils.toInteger(entry.getValue()); - break; - default: - break; - } - } - }), - - /** - * Directive to specify a cmake to be included by the generated build systems. - * - *

This gives full control over the C/C++ build as any cmake parameters can be adjusted in the - * included file. - */ - CMAKE_INCLUDE( - "cmake-include", - UnionType.FILE_OR_FILE_ARRAY, - Arrays.asList(Target.CPP, Target.C, Target.CCPP), - (config) -> ASTUtils.toElement(config.cmakeIncludes), - (config, value, err) -> { - config.cmakeIncludes = ASTUtils.elementToListOfStrings(value); - }, - // FIXME: This merging of lists is potentially dangerous since - // the incoming list of cmake-includes can belong to a .lf file that is - // located in a different location, and keeping just filename - // strings like this without absolute paths is incorrect. - (config, value, err) -> { - config.cmakeIncludes.addAll(ASTUtils.elementToListOfStrings(value)); - }), - /** Directive to specify the target compiler. */ - COMPILER( - "compiler", - PrimitiveType.STRING, - Target.ALL, - (config) -> ASTUtils.toElement(config.compiler), - (config, value, err) -> { - config.compiler = ASTUtils.elementToSingleString(value); - }), - - /** Directive to specify compile-time definitions. */ - COMPILE_DEFINITIONS( - "compile-definitions", - StringDictionaryType.COMPILE_DEFINITION, - Arrays.asList(Target.C, Target.CCPP, Target.Python), - (config) -> ASTUtils.toElement(config.compileDefinitions), - (config, value, err) -> { - config.compileDefinitions = ASTUtils.elementToStringMaps(value); - }), - - /** - * Directive to generate a Dockerfile. This is either a boolean, true or false, or a dictionary of - * options. - */ - DOCKER( - "docker", - UnionType.DOCKER_UNION, - Arrays.asList(Target.C, Target.CCPP, Target.Python, Target.TS), - (config) -> { - if (config.dockerOptions == null) { - return null; - } else if (config.dockerOptions.equals(new DockerOptions())) { - // default configuration - return ASTUtils.toElement(true); - } else { - Element e = LfFactory.eINSTANCE.createElement(); - KeyValuePairs kvp = LfFactory.eINSTANCE.createKeyValuePairs(); - for (DockerOption opt : DockerOption.values()) { - KeyValuePair pair = LfFactory.eINSTANCE.createKeyValuePair(); - pair.setName(opt.toString()); - switch (opt) { - case FROM: - if (config.dockerOptions.from == null) continue; - pair.setValue(ASTUtils.toElement(config.dockerOptions.from)); - break; - } - kvp.getPairs().add(pair); - } - e.setKeyvalue(kvp); - if (kvp.getPairs().isEmpty()) return null; - return e; - } - }, - (config, value, err) -> setDockerProperty(config, value), - (config, value, err) -> setDockerProperty(config, value)), - - /** Directive for specifying a path to an external runtime to be used for the compiled binary. */ - EXTERNAL_RUNTIME_PATH( - "external-runtime-path", - PrimitiveType.STRING, - List.of(Target.CPP), - (config) -> ASTUtils.toElement(config.externalRuntimePath), - (config, value, err) -> { - config.externalRuntimePath = ASTUtils.elementToSingleString(value); - }), - - /** - * Directive to let the execution engine allow logical time to elapse faster than physical time. - */ - FAST( - "fast", - PrimitiveType.BOOLEAN, - Target.ALL, - (config) -> ASTUtils.toElement(config.fastMode), - (config, value, err) -> { - config.fastMode = ASTUtils.toBoolean(value); - }), - - /** - * Directive to stage particular files on the class path to be processed by the code generator. - */ - FILES( - "files", - UnionType.FILE_OR_FILE_ARRAY, - List.of(Target.C, Target.CCPP, Target.Python), - (config) -> ASTUtils.toElement(config.files), - (config, value, err) -> { - config.files = ASTUtils.elementToListOfStrings(value); - }, - (config, value, err) -> { - config.files.addAll(ASTUtils.elementToListOfStrings(value)); - }), - - /** Flags to be passed on to the target compiler. */ - FLAGS( - "flags", - UnionType.STRING_OR_STRING_ARRAY, - Arrays.asList(Target.C, Target.CCPP), - (config) -> ASTUtils.toElement(config.compilerFlags), - (config, value, err) -> { - config.compilerFlags = ASTUtils.elementToListOfStrings(value); - }), - - /** Directive to specify the coordination mode */ - COORDINATION( - "coordination", - UnionType.COORDINATION_UNION, - Arrays.asList(Target.C, Target.CCPP, Target.Python), - (config) -> ASTUtils.toElement(config.coordination.toString()), - (config, value, err) -> { - config.coordination = - (CoordinationType) - UnionType.COORDINATION_UNION.forName(ASTUtils.elementToSingleString(value)); - }, - (config, value, err) -> { - config.coordination = - (CoordinationType) - UnionType.COORDINATION_UNION.forName(ASTUtils.elementToSingleString(value)); - }), - - /** Key-value pairs giving options for clock synchronization. */ - COORDINATION_OPTIONS( - "coordination-options", - DictionaryType.COORDINATION_OPTION_DICT, - Arrays.asList(Target.C, Target.CCPP, Target.Python, Target.TS), - (config) -> { - Element e = LfFactory.eINSTANCE.createElement(); - KeyValuePairs kvp = LfFactory.eINSTANCE.createKeyValuePairs(); - for (CoordinationOption opt : CoordinationOption.values()) { - KeyValuePair pair = LfFactory.eINSTANCE.createKeyValuePair(); - pair.setName(opt.toString()); - switch (opt) { - case ADVANCE_MESSAGE_INTERVAL: - if (config.coordinationOptions.advance_message_interval == null) continue; - pair.setValue( - ASTUtils.toElement(config.coordinationOptions.advance_message_interval)); - break; - } - kvp.getPairs().add(pair); - } - e.setKeyvalue(kvp); - if (kvp.getPairs().isEmpty()) return null; - return e; - }, - (config, value, err) -> { - for (KeyValuePair entry : value.getKeyvalue().getPairs()) { - CoordinationOption option = - (CoordinationOption) DictionaryType.COORDINATION_OPTION_DICT.forName(entry.getName()); - switch (option) { - case ADVANCE_MESSAGE_INTERVAL: - config.coordinationOptions.advance_message_interval = - ASTUtils.toTimeValue(entry.getValue()); - break; - default: - break; - } - } - }, - (config, value, err) -> { - for (KeyValuePair entry : value.getKeyvalue().getPairs()) { - CoordinationOption option = - (CoordinationOption) DictionaryType.COORDINATION_OPTION_DICT.forName(entry.getName()); - switch (option) { - case ADVANCE_MESSAGE_INTERVAL: - config.coordinationOptions.advance_message_interval = - ASTUtils.toTimeValue(entry.getValue()); - break; - default: - break; - } - } - }), - - /** - * Directive to let the execution engine remain active also if there are no more events in the - * event queue. - */ - KEEPALIVE( - "keepalive", - PrimitiveType.BOOLEAN, - Target.ALL, - (config) -> ASTUtils.toElement(config.keepalive), - (config, value, err) -> { - config.keepalive = ASTUtils.toBoolean(value); - }), - - /** Directive to specify the grain at which to report log messages during execution. */ - LOGGING( - "logging", - UnionType.LOGGING_UNION, - Target.ALL, - (config) -> ASTUtils.toElement(config.logLevel.toString()), - (config, value, err) -> { - config.logLevel = - (LogLevel) UnionType.LOGGING_UNION.forName(ASTUtils.elementToSingleString(value)); - }), - - /** Directive to not invoke the target compiler. */ - NO_COMPILE( - "no-compile", - PrimitiveType.BOOLEAN, - Arrays.asList(Target.C, Target.CPP, Target.CCPP, Target.Python), - (config) -> ASTUtils.toElement(config.noCompile), - (config, value, err) -> { - config.noCompile = ASTUtils.toBoolean(value); - }), - - /** Directive to disable validation of reactor rules at runtime. */ - NO_RUNTIME_VALIDATION( - "no-runtime-validation", - PrimitiveType.BOOLEAN, - Arrays.asList(Target.CPP), - (config) -> ASTUtils.toElement(config.noRuntimeValidation), - (config, value, err) -> { - config.noRuntimeValidation = ASTUtils.toBoolean(value); - }), - - /** Directive to check the generated verification model. */ - VERIFY( - "verify", - PrimitiveType.BOOLEAN, - Arrays.asList(Target.C), - (config) -> ASTUtils.toElement(config.verify), - (config, value, err) -> { - config.verify = ASTUtils.toBoolean(value); - }), - - /** - * Directive to specify the platform for cross code generation. This is either a string of the - * platform or a dictionary of options that includes the string name. - */ - PLATFORM( - "platform", - UnionType.PLATFORM_STRING_OR_DICTIONARY, - Target.ALL, - (config) -> { - Element e = LfFactory.eINSTANCE.createElement(); - KeyValuePairs kvp = LfFactory.eINSTANCE.createKeyValuePairs(); - for (PlatformOption opt : PlatformOption.values()) { - KeyValuePair pair = LfFactory.eINSTANCE.createKeyValuePair(); - pair.setName(opt.toString()); - switch (opt) { - case NAME: - pair.setValue(ASTUtils.toElement(config.platformOptions.platform.toString())); - break; - case BAUDRATE: - pair.setValue(ASTUtils.toElement(config.platformOptions.baudRate)); - break; - case BOARD: - pair.setValue(ASTUtils.toElement(config.platformOptions.board)); - break; - case FLASH: - pair.setValue(ASTUtils.toElement(config.platformOptions.flash)); - break; - case PORT: - pair.setValue(ASTUtils.toElement(config.platformOptions.port)); - break; - case USER_THREADS: - pair.setValue(ASTUtils.toElement(config.platformOptions.userThreads)); - break; - } - kvp.getPairs().add(pair); - } - e.setKeyvalue(kvp); - if (kvp.getPairs().isEmpty()) return null; - return e; - }, - (config, value, err) -> { - if (value.getLiteral() != null) { - config.platformOptions = new PlatformOptions(); - config.platformOptions.platform = - (Platform) UnionType.PLATFORM_UNION.forName(ASTUtils.elementToSingleString(value)); - if (config.platformOptions.platform == null) { - String s = - "Unidentified Platform Type, LF supports the following platform types: " - + Arrays.asList(Platform.values()).toString(); - err.at(value).error(s); - throw new AssertionError(s); - } - } else { - config.platformOptions = new PlatformOptions(); - for (KeyValuePair entry : value.getKeyvalue().getPairs()) { - PlatformOption option = - (PlatformOption) DictionaryType.PLATFORM_DICT.forName(entry.getName()); - switch (option) { - case NAME: - Platform p = - (Platform) - UnionType.PLATFORM_UNION.forName( - ASTUtils.elementToSingleString(entry.getValue())); - if (p == null) { - String s = - "Unidentified Platform Type, LF supports the following platform types: " - + Arrays.asList(Platform.values()).toString(); - err.at(entry).error(s); - throw new AssertionError(s); - } - config.platformOptions.platform = p; - break; - case BAUDRATE: - config.platformOptions.baudRate = ASTUtils.toInteger(entry.getValue()); - break; - case BOARD: - config.platformOptions.board = ASTUtils.elementToSingleString(entry.getValue()); - break; - case FLASH: - config.platformOptions.flash = ASTUtils.toBoolean(entry.getValue()); - break; - case PORT: - config.platformOptions.port = ASTUtils.elementToSingleString(entry.getValue()); - break; - case USER_THREADS: - config.platformOptions.userThreads = ASTUtils.toInteger(entry.getValue()); - break; - default: - break; - } - } - } - // If the platform does not support threading, disable it. - if (!config.platformOptions.platform.isMultiThreaded()) { - config.threading = false; - } - }), - - /** Directive to instruct the runtime to collect and print execution statistics. */ - PRINT_STATISTICS( - "print-statistics", - PrimitiveType.BOOLEAN, - Arrays.asList(Target.CPP), - (config) -> ASTUtils.toElement(config.printStatistics), - (config, value, err) -> { - config.printStatistics = ASTUtils.toBoolean(value); - }), - - /** - * Directive for specifying .proto files that need to be compiled and their code included in the - * sources. - */ - PROTOBUFS( - "protobufs", - UnionType.FILE_OR_FILE_ARRAY, - Arrays.asList(Target.C, Target.CCPP, Target.TS, Target.Python), - (config) -> ASTUtils.toElement(config.protoFiles), - (config, value, err) -> { - config.protoFiles = ASTUtils.elementToListOfStrings(value); - }), - - /** Directive to specify that ROS2 specific code is generated, */ - ROS2( - "ros2", - PrimitiveType.BOOLEAN, - List.of(Target.CPP), - (config) -> ASTUtils.toElement(config.ros2), - (config, value, err) -> { - config.ros2 = ASTUtils.toBoolean(value); - }), - - /** Directive to specify additional ROS2 packages that this LF program depends on. */ - ROS2_DEPENDENCIES( - "ros2-dependencies", - ArrayType.STRING_ARRAY, - List.of(Target.CPP), - (config) -> ASTUtils.toElement(config.ros2Dependencies), - (config, value, err) -> { - config.ros2Dependencies = ASTUtils.elementToListOfStrings(value); - }), - - /** Directive for specifying a specific version of the reactor runtime library. */ - RUNTIME_VERSION( - "runtime-version", - PrimitiveType.STRING, - Arrays.asList(Target.CPP), - (config) -> ASTUtils.toElement(config.runtimeVersion), - (config, value, err) -> { - config.runtimeVersion = ASTUtils.elementToSingleString(value); - }), - - /** Directive for specifying a specific runtime scheduler, if supported. */ - SCHEDULER( - "scheduler", - UnionType.SCHEDULER_UNION, - Arrays.asList(Target.C, Target.CCPP, Target.Python), - (config) -> ASTUtils.toElement(config.schedulerType.toString()), - (config, value, err) -> { - config.schedulerType = - (SchedulerOption) - UnionType.SCHEDULER_UNION.forName(ASTUtils.elementToSingleString(value)); - }), - - /** Directive to specify that all code is generated in a single file. */ - SINGLE_FILE_PROJECT( - "single-file-project", - PrimitiveType.BOOLEAN, - List.of(Target.Rust), - (config) -> ASTUtils.toElement(config.singleFileProject), - (config, value, err) -> { - config.singleFileProject = ASTUtils.toBoolean(value); - }), - - /** Directive to indicate whether the runtime should use multi-threading. */ - THREADING( - "threading", - PrimitiveType.BOOLEAN, - List.of(Target.C, Target.CCPP, Target.Python), - (config) -> ASTUtils.toElement(config.threading), - (config, value, err) -> { - config.threading = ASTUtils.toBoolean(value); - }), - - /** Directive to specify the number of worker threads used by the runtime. */ - WORKERS( - "workers", - PrimitiveType.NON_NEGATIVE_INTEGER, - List.of(Target.C, Target.CCPP, Target.Python, Target.CPP, Target.Rust), - (config) -> ASTUtils.toElement(config.workers), - (config, value, err) -> { - config.workers = ASTUtils.toInteger(value); - }), - - /** Directive to specify the execution timeout. */ - TIMEOUT( - "timeout", - PrimitiveType.TIME_VALUE, - Target.ALL, - (config) -> ASTUtils.toElement(config.timeout), - (config, value, err) -> { - config.timeout = ASTUtils.toTimeValue(value); - }, - (config, value, err) -> { - config.timeout = ASTUtils.toTimeValue(value); - }), - - /** Directive to enable tracing. */ - TRACING( - "tracing", - UnionType.TRACING_UNION, - Arrays.asList(Target.C, Target.CCPP, Target.CPP, Target.Python), - (config) -> { - if (config.tracing == null) { - return null; - } else if (config.tracing.equals(new TracingOptions())) { - // default values - return ASTUtils.toElement(true); - } else { - Element e = LfFactory.eINSTANCE.createElement(); - KeyValuePairs kvp = LfFactory.eINSTANCE.createKeyValuePairs(); - for (TracingOption opt : TracingOption.values()) { - KeyValuePair pair = LfFactory.eINSTANCE.createKeyValuePair(); - pair.setName(opt.toString()); - switch (opt) { - case TRACE_FILE_NAME: - if (config.tracing.traceFileName == null) continue; - pair.setValue(ASTUtils.toElement(config.tracing.traceFileName)); - } - kvp.getPairs().add(pair); - } - e.setKeyvalue(kvp); - if (kvp.getPairs().isEmpty()) return null; - return e; - } - }, - (config, value, err) -> { - if (value.getLiteral() != null) { - if (ASTUtils.toBoolean(value)) { - config.tracing = new TracingOptions(); - } else { - config.tracing = null; - } - } else { - config.tracing = new TracingOptions(); - for (KeyValuePair entry : value.getKeyvalue().getPairs()) { - TracingOption option = - (TracingOption) DictionaryType.TRACING_DICT.forName(entry.getName()); - switch (option) { - case TRACE_FILE_NAME: - config.tracing.traceFileName = ASTUtils.elementToSingleString(entry.getValue()); - break; - default: - break; - } - } - } - }), - - /** - * Directive to let the runtime export its internal dependency graph. - * - *

This is a debugging feature and currently only used for C++ and Rust programs. - */ - EXPORT_DEPENDENCY_GRAPH( - "export-dependency-graph", - PrimitiveType.BOOLEAN, - List.of(Target.CPP, Target.Rust), - (config) -> ASTUtils.toElement(config.exportDependencyGraph), - (config, value, err) -> { - config.exportDependencyGraph = ASTUtils.toBoolean(value); - }), - - /** - * Directive to let the runtime export the program structure to a yaml file. - * - *

This is a debugging feature and currently only used for C++ programs. - */ - EXPORT_TO_YAML( - "export-to-yaml", - PrimitiveType.BOOLEAN, - List.of(Target.CPP), - (config) -> ASTUtils.toElement(config.exportToYaml), - (config, value, err) -> { - config.exportToYaml = ASTUtils.toBoolean(value); - }), - - /** - * List of module files to link into the crate as top-level. For instance, a {@code target Rust { - * rust-modules: [ "foo.rs" ] }} will cause the file to be copied into the generated project, and - * the generated {@code main.rs} will include it with a {@code mod foo;}. If one of the paths is a - * directory, it must contain a {@code mod.rs} file, and all its contents are copied. - */ - RUST_INCLUDE( - "rust-include", - UnionType.FILE_OR_FILE_ARRAY, - List.of(Target.Rust), - (config) -> { - // do not check paths here, and simply copy the absolute path over - List paths = config.rust.getRustTopLevelModules(); - if (paths.isEmpty()) return null; - else if (paths.size() == 1) { - return ASTUtils.toElement(paths.get(0).toString()); - } else { - Element e = LfFactory.eINSTANCE.createElement(); - Array arr = LfFactory.eINSTANCE.createArray(); - for (Path p : paths) { - arr.getElements().add(ASTUtils.toElement(p.toString())); - } - e.setArray(arr); - return e; - } - }, - (config, value, err) -> { - Path referencePath; - try { - referencePath = FileUtil.toPath(value.eResource().getURI()).toAbsolutePath(); - } catch (IllegalArgumentException e) { - err.at(value).error("Invalid path? " + e.getMessage()); - throw e; - } - - // we'll resolve relative paths to check that the files - // are as expected. - - if (value.getLiteral() != null) { - Path resolved = referencePath.resolveSibling(StringUtil.removeQuotes(value.getLiteral())); - - config.rust.addAndCheckTopLevelModule(resolved, value, err); - } else if (value.getArray() != null) { - for (Element element : value.getArray().getElements()) { - String literal = StringUtil.removeQuotes(element.getLiteral()); - Path resolved = referencePath.resolveSibling(literal); - config.rust.addAndCheckTopLevelModule(resolved, element, err); - } - } - }), - - /** Directive for specifying Cargo features of the generated program to enable. */ - CARGO_FEATURES( - "cargo-features", - ArrayType.STRING_ARRAY, - List.of(Target.Rust), - (config) -> ASTUtils.toElement(config.rust.getCargoFeatures()), - (config, value, err) -> { - config.rust.setCargoFeatures(ASTUtils.elementToListOfStrings(value)); - }), - - /** - * Dependency specifications for Cargo. This property looks like this: - * - *

{@code
-   * cargo-dependencies: {
-   *    // Name-of-the-crate: "version"
-   *    rand: "0.8",
-   *    // Equivalent to using an explicit map:
-   *    rand: {
-   *      version: "0.8"
-   *    },
-   *    // The map allows specifying more details
-   *    rand: {
-   *      // A path to a local unpublished crate.
-   *      // Note 'path' is mutually exclusive with 'version'.
-   *      path: "/home/me/Git/local-rand-clone"
-   *    },
-   *    rand: {
-   *      version: "0.8",
-   *      // you can specify cargo features
-   *      features: ["some-cargo-feature",]
-   *    }
-   * }
-   * }
- */ - CARGO_DEPENDENCIES( - "cargo-dependencies", - CargoDependenciesPropertyType.INSTANCE, - List.of(Target.Rust), - (config) -> { - var deps = config.rust.getCargoDependencies(); - if (deps.size() == 0) return null; - else { - Element e = LfFactory.eINSTANCE.createElement(); - KeyValuePairs kvp = LfFactory.eINSTANCE.createKeyValuePairs(); - for (var ent : deps.entrySet()) { - KeyValuePair pair = LfFactory.eINSTANCE.createKeyValuePair(); - pair.setName(ent.getKey()); - pair.setValue(CargoDependencySpec.extractSpec(ent.getValue())); - kvp.getPairs().add(pair); - } - e.setKeyvalue(kvp); - return e; - } - }, - (config, value, err) -> { - config.rust.setCargoDependencies(CargoDependencySpec.parseAll(value)); - }), - - /** - * Directs the C or Python target to include the associated C file used for setting up federated - * execution before processing the first tag. - */ - FED_SETUP( - "_fed_setup", - PrimitiveType.FILE, - Arrays.asList(Target.C, Target.CCPP, Target.Python), - (config) -> ASTUtils.toElement(config.fedSetupPreamble), - (config, value, err) -> - config.fedSetupPreamble = StringUtil.removeQuotes(ASTUtils.elementToSingleString(value))); - - /** Update {@code config}.dockerOptions based on value. */ + AUTH( + "auth", + PrimitiveType.BOOLEAN, + Arrays.asList(Target.C, Target.CCPP), + (config) -> ASTUtils.toElement(config.auth), + (config, value, err) -> { + config.auth = ASTUtils.toBoolean(value); + }), + /** Directive to let the generator use the custom build command. */ + BUILD( + "build", + UnionType.STRING_OR_STRING_ARRAY, + Arrays.asList(Target.C, Target.CCPP), + (config) -> ASTUtils.toElement(config.buildCommands), + (config, value, err) -> { + config.buildCommands = ASTUtils.elementToListOfStrings(value); + }), + + /** + * Directive to specify the target build type such as 'Release' or 'Debug'. This is also used in + * the Rust target to select a Cargo profile. + */ + BUILD_TYPE( + "build-type", + UnionType.BUILD_TYPE_UNION, + Arrays.asList(Target.C, Target.CCPP, Target.CPP, Target.Rust), + (config) -> ASTUtils.toElement(config.cmakeBuildType.toString()), + (config, value, err) -> { + config.cmakeBuildType = + (BuildType) UnionType.BUILD_TYPE_UNION.forName(ASTUtils.elementToSingleString(value)); + // set it there too, because the default is different. + config.rust.setBuildType(config.cmakeBuildType); + }), + + /** Directive to let the federate execution handle clock synchronization in software. */ + CLOCK_SYNC( + "clock-sync", + UnionType.CLOCK_SYNC_UNION, + Arrays.asList(Target.C, Target.CCPP, Target.Python), + new ClockSyncConfigurator()), + /** Key-value pairs giving options for clock synchronization. */ + CLOCK_SYNC_OPTIONS( + "clock-sync-options", + DictionaryType.CLOCK_SYNC_OPTION_DICT, + Arrays.asList(Target.C, Target.CCPP, Target.Python), + (config) -> { + Element e = LfFactory.eINSTANCE.createElement(); + KeyValuePairs kvp = LfFactory.eINSTANCE.createKeyValuePairs(); + for (ClockSyncOption opt : ClockSyncOption.values()) { + KeyValuePair pair = LfFactory.eINSTANCE.createKeyValuePair(); + pair.setName(opt.toString()); + switch (opt) { + case ATTENUATION: + pair.setValue(ASTUtils.toElement(config.clockSyncOptions.attenuation)); + break; + case COLLECT_STATS: + pair.setValue(ASTUtils.toElement(config.clockSyncOptions.collectStats)); + break; + case LOCAL_FEDERATES_ON: + pair.setValue(ASTUtils.toElement(config.clockSyncOptions.localFederatesOn)); + break; + case PERIOD: + if (config.clockSyncOptions.period == null) { + continue; // don't set if null + } + pair.setValue(ASTUtils.toElement(config.clockSyncOptions.period)); + break; + case TEST_OFFSET: + if (config.clockSyncOptions.testOffset == null) { + continue; // don't set if null + } + pair.setValue(ASTUtils.toElement(config.clockSyncOptions.testOffset)); + break; + case TRIALS: + pair.setValue(ASTUtils.toElement(config.clockSyncOptions.trials)); + break; + } + kvp.getPairs().add(pair); + } + e.setKeyvalue(kvp); + // kvp will never be empty + return e; + }, + (config, value, err) -> { + for (KeyValuePair entry : value.getKeyvalue().getPairs()) { + ClockSyncOption option = + (ClockSyncOption) DictionaryType.CLOCK_SYNC_OPTION_DICT.forName(entry.getName()); + switch (option) { + case ATTENUATION: + config.clockSyncOptions.attenuation = ASTUtils.toInteger(entry.getValue()); + break; + case COLLECT_STATS: + config.clockSyncOptions.collectStats = ASTUtils.toBoolean(entry.getValue()); + break; + case LOCAL_FEDERATES_ON: + config.clockSyncOptions.localFederatesOn = ASTUtils.toBoolean(entry.getValue()); + break; + case PERIOD: + config.clockSyncOptions.period = ASTUtils.toTimeValue(entry.getValue()); + break; + case TEST_OFFSET: + config.clockSyncOptions.testOffset = ASTUtils.toTimeValue(entry.getValue()); + break; + case TRIALS: + config.clockSyncOptions.trials = ASTUtils.toInteger(entry.getValue()); + break; + default: + break; + } + } + }), + + /** + * Directive to specify a cmake to be included by the generated build systems. + * + *

This gives full control over the C/C++ build as any cmake parameters can be adjusted in the + * included file. + */ + CMAKE_INCLUDE( + "cmake-include", + UnionType.FILE_OR_FILE_ARRAY, + Arrays.asList(Target.CPP, Target.C, Target.CCPP), + (config) -> ASTUtils.toElement(config.cmakeIncludes), + (config, value, err) -> { + config.cmakeIncludes = ASTUtils.elementToListOfStrings(value); + }, + // FIXME: This merging of lists is potentially dangerous since + // the incoming list of cmake-includes can belong to a .lf file that is + // located in a different location, and keeping just filename + // strings like this without absolute paths is incorrect. + (config, value, err) -> { + config.cmakeIncludes.addAll(ASTUtils.elementToListOfStrings(value)); + }), + /** Directive to specify the target compiler. */ + COMPILER( + "compiler", + PrimitiveType.STRING, + Target.ALL, + (config) -> ASTUtils.toElement(config.compiler), + (config, value, err) -> { + config.compiler = ASTUtils.elementToSingleString(value); + }), + + /** Directive to specify compile-time definitions. */ + COMPILE_DEFINITIONS( + "compile-definitions", + StringDictionaryType.COMPILE_DEFINITION, + Arrays.asList(Target.C, Target.CCPP, Target.Python), + (config) -> ASTUtils.toElement(config.compileDefinitions), + (config, value, err) -> { + config.compileDefinitions = ASTUtils.elementToStringMaps(value); + }), + + /** + * Directive to generate a Dockerfile. This is either a boolean, true or false, or a dictionary of + * options. + */ + DOCKER( + "docker", + UnionType.DOCKER_UNION, + Arrays.asList(Target.C, Target.CCPP, Target.Python, Target.TS), + (config) -> { + if (config.dockerOptions == null) { + return null; + } else if (config.dockerOptions.equals(new DockerOptions())) { + // default configuration + return ASTUtils.toElement(true); + } else { + Element e = LfFactory.eINSTANCE.createElement(); + KeyValuePairs kvp = LfFactory.eINSTANCE.createKeyValuePairs(); + for (DockerOption opt : DockerOption.values()) { + KeyValuePair pair = LfFactory.eINSTANCE.createKeyValuePair(); + pair.setName(opt.toString()); + switch (opt) { + case FROM: + if (config.dockerOptions.from == null) { + continue; + } + pair.setValue(ASTUtils.toElement(config.dockerOptions.from)); + break; + } + kvp.getPairs().add(pair); + } + e.setKeyvalue(kvp); + if (kvp.getPairs().isEmpty()) { + return null; + } + return e; + } + }, + (config, value, err) -> setDockerProperty(config, value), + (config, value, err) -> setDockerProperty(config, value)), + + /** Directive for specifying a path to an external runtime to be used for the compiled binary. */ + EXTERNAL_RUNTIME_PATH( + "external-runtime-path", + PrimitiveType.STRING, + List.of(Target.CPP), + (config) -> ASTUtils.toElement(config.externalRuntimePath), + (config, value, err) -> { + config.externalRuntimePath = ASTUtils.elementToSingleString(value); + }), + + /** + * Directive to let the execution engine allow logical time to elapse faster than physical time. + */ + FAST( + "fast", + PrimitiveType.BOOLEAN, + Target.ALL, + new FastConfigurator()), + /** + * Directive to stage particular files on the class path to be processed by the code generator. + */ + FILES( + "files", + UnionType.FILE_OR_FILE_ARRAY, + List.of(Target.C, Target.CCPP, Target.Python), + (config) -> ASTUtils.toElement(config.files), + (config, value, err) -> { + config.files = ASTUtils.elementToListOfStrings(value); + }, + (config, value, err) -> { + config.files.addAll(ASTUtils.elementToListOfStrings(value)); + }), + + /** Flags to be passed on to the target compiler. */ + FLAGS( + "flags", + UnionType.STRING_OR_STRING_ARRAY, + Arrays.asList(Target.C, Target.CCPP), + (config) -> ASTUtils.toElement(config.compilerFlags), + (config, value, err) -> { + config.compilerFlags = ASTUtils.elementToListOfStrings(value); + }), + + /** Directive to specify the coordination mode */ + COORDINATION( + "coordination", + UnionType.COORDINATION_UNION, + Arrays.asList(Target.C, Target.CCPP, Target.Python), + (config) -> ASTUtils.toElement(config.coordination.toString()), + (config, value, err) -> { + config.coordination = + (CoordinationType) + UnionType.COORDINATION_UNION.forName(ASTUtils.elementToSingleString(value)); + }, + (config, value, err) -> { + config.coordination = + (CoordinationType) + UnionType.COORDINATION_UNION.forName(ASTUtils.elementToSingleString(value)); + }), + + /** Key-value pairs giving options for clock synchronization. */ + COORDINATION_OPTIONS( + "coordination-options", + DictionaryType.COORDINATION_OPTION_DICT, + Arrays.asList(Target.C, Target.CCPP, Target.Python, Target.TS), + (config) -> { + Element e = LfFactory.eINSTANCE.createElement(); + KeyValuePairs kvp = LfFactory.eINSTANCE.createKeyValuePairs(); + for (CoordinationOption opt : CoordinationOption.values()) { + KeyValuePair pair = LfFactory.eINSTANCE.createKeyValuePair(); + pair.setName(opt.toString()); + switch (opt) { + case ADVANCE_MESSAGE_INTERVAL: + if (config.coordinationOptions.advance_message_interval == null) { + continue; + } + pair.setValue( + ASTUtils.toElement(config.coordinationOptions.advance_message_interval)); + break; + } + kvp.getPairs().add(pair); + } + e.setKeyvalue(kvp); + if (kvp.getPairs().isEmpty()) { + return null; + } + return e; + }, + (config, value, err) -> { + for (KeyValuePair entry : value.getKeyvalue().getPairs()) { + CoordinationOption option = + (CoordinationOption) DictionaryType.COORDINATION_OPTION_DICT.forName(entry.getName()); + switch (option) { + case ADVANCE_MESSAGE_INTERVAL: + config.coordinationOptions.advance_message_interval = + ASTUtils.toTimeValue(entry.getValue()); + break; + default: + break; + } + } + }, + (config, value, err) -> { + for (KeyValuePair entry : value.getKeyvalue().getPairs()) { + CoordinationOption option = + (CoordinationOption) DictionaryType.COORDINATION_OPTION_DICT.forName(entry.getName()); + switch (option) { + case ADVANCE_MESSAGE_INTERVAL: + config.coordinationOptions.advance_message_interval = + ASTUtils.toTimeValue(entry.getValue()); + break; + default: + break; + } + } + }), + + /** + * Directive to let the execution engine remain active also if there are no more events in the + * event queue. + */ + KEEPALIVE( + "keepalive", + PrimitiveType.BOOLEAN, + Target.ALL, + new KeepaliveConfigurator()), + + /** Directive to specify the grain at which to report log messages during execution. */ + LOGGING( + "logging", + UnionType.LOGGING_UNION, + Target.ALL, + (config) -> ASTUtils.toElement(config.logLevel.toString()), + (config, value, err) -> { + config.logLevel = + (LogLevel) UnionType.LOGGING_UNION.forName(ASTUtils.elementToSingleString(value)); + }), + + /** Directive to not invoke the target compiler. */ + NO_COMPILE( + "no-compile", + PrimitiveType.BOOLEAN, + Arrays.asList(Target.C, Target.CPP, Target.CCPP, Target.Python), + (config) -> ASTUtils.toElement(config.noCompile), + (config, value, err) -> { + config.noCompile = ASTUtils.toBoolean(value); + }), + + /** Directive to disable validation of reactor rules at runtime. */ + NO_RUNTIME_VALIDATION( + "no-runtime-validation", + PrimitiveType.BOOLEAN, + Arrays.asList(Target.CPP), + (config) -> ASTUtils.toElement(config.noRuntimeValidation), + (config, value, err) -> { + config.noRuntimeValidation = ASTUtils.toBoolean(value); + }), + + /** Directive to check the generated verification model. */ + VERIFY( + "verify", + PrimitiveType.BOOLEAN, + Arrays.asList(Target.C), + (config) -> ASTUtils.toElement(config.verify), + (config, value, err) -> { + config.verify = ASTUtils.toBoolean(value); + }), + + /** + * Directive to specify the platform for cross code generation. This is either a string of the + * platform or a dictionary of options that includes the string name. + */ + PLATFORM( + "platform", + UnionType.PLATFORM_STRING_OR_DICTIONARY, + Target.ALL, + (config) -> { + Element e = LfFactory.eINSTANCE.createElement(); + KeyValuePairs kvp = LfFactory.eINSTANCE.createKeyValuePairs(); + for (PlatformOption opt : PlatformOption.values()) { + KeyValuePair pair = LfFactory.eINSTANCE.createKeyValuePair(); + pair.setName(opt.toString()); + switch (opt) { + case NAME: + pair.setValue(ASTUtils.toElement(config.platformOptions.platform.toString())); + break; + case BAUDRATE: + pair.setValue(ASTUtils.toElement(config.platformOptions.baudRate)); + break; + case BOARD: + pair.setValue(ASTUtils.toElement(config.platformOptions.board)); + break; + case FLASH: + pair.setValue(ASTUtils.toElement(config.platformOptions.flash)); + break; + case PORT: + pair.setValue(ASTUtils.toElement(config.platformOptions.port)); + break; + case USER_THREADS: + pair.setValue(ASTUtils.toElement(config.platformOptions.userThreads)); + break; + } + kvp.getPairs().add(pair); + } + e.setKeyvalue(kvp); + if (kvp.getPairs().isEmpty()) { + return null; + } + return e; + }, + (config, value, err) -> { + if (value.getLiteral() != null) { + config.platformOptions = new PlatformOptions(); + config.platformOptions.platform = + (Platform) UnionType.PLATFORM_UNION.forName(ASTUtils.elementToSingleString(value)); + if (config.platformOptions.platform == null) { + String s = + "Unidentified Platform Type, LF supports the following platform types: " + + Arrays.asList(Platform.values()).toString(); + err.at(value).error(s); + throw new AssertionError(s); + } + } else { + config.platformOptions = new PlatformOptions(); + for (KeyValuePair entry : value.getKeyvalue().getPairs()) { + PlatformOption option = + (PlatformOption) DictionaryType.PLATFORM_DICT.forName(entry.getName()); + switch (option) { + case NAME: + Platform p = + (Platform) + UnionType.PLATFORM_UNION.forName( + ASTUtils.elementToSingleString(entry.getValue())); + if (p == null) { + String s = + "Unidentified Platform Type, LF supports the following platform types: " + + Arrays.asList(Platform.values()).toString(); + err.at(entry).error(s); + throw new AssertionError(s); + } + config.platformOptions.platform = p; + break; + case BAUDRATE: + config.platformOptions.baudRate = ASTUtils.toInteger(entry.getValue()); + break; + case BOARD: + config.platformOptions.board = ASTUtils.elementToSingleString(entry.getValue()); + break; + case FLASH: + config.platformOptions.flash = ASTUtils.toBoolean(entry.getValue()); + break; + case PORT: + config.platformOptions.port = ASTUtils.elementToSingleString(entry.getValue()); + break; + case USER_THREADS: + config.platformOptions.userThreads = ASTUtils.toInteger(entry.getValue()); + break; + default: + break; + } + } + } + // If the platform does not support threading, disable it. + if (!config.platformOptions.platform.isMultiThreaded()) { + config.threading = false; + } + }), + + /** Directive to instruct the runtime to collect and print execution statistics. */ + PRINT_STATISTICS( + "print-statistics", + PrimitiveType.BOOLEAN, + Arrays.asList(Target.CPP), + (config) -> ASTUtils.toElement(config.printStatistics), + (config, value, err) -> { + config.printStatistics = ASTUtils.toBoolean(value); + }), + + /** + * Directive for specifying .proto files that need to be compiled and their code included in the + * sources. + */ + PROTOBUFS( + "protobufs", + UnionType.FILE_OR_FILE_ARRAY, + Arrays.asList(Target.C, Target.CCPP, Target.TS, Target.Python), + (config) -> ASTUtils.toElement(config.protoFiles), + (config, value, err) -> { + config.protoFiles = ASTUtils.elementToListOfStrings(value); + }), + + /** Directive to specify that ROS2 specific code is generated, */ + ROS2( + "ros2", + PrimitiveType.BOOLEAN, + List.of(Target.CPP), + (config) -> ASTUtils.toElement(config.ros2), + (config, value, err) -> { + config.ros2 = ASTUtils.toBoolean(value); + }), + + /** Directive to specify additional ROS2 packages that this LF program depends on. */ + ROS2_DEPENDENCIES( + "ros2-dependencies", + ArrayType.STRING_ARRAY, + List.of(Target.CPP), + (config) -> ASTUtils.toElement(config.ros2Dependencies), + (config, value, err) -> { + config.ros2Dependencies = ASTUtils.elementToListOfStrings(value); + }), + + /** Directive for specifying a specific version of the reactor runtime library. */ + RUNTIME_VERSION( + "runtime-version", + PrimitiveType.STRING, + Arrays.asList(Target.CPP), + (config) -> ASTUtils.toElement(config.runtimeVersion), + (config, value, err) -> { + config.runtimeVersion = ASTUtils.elementToSingleString(value); + }), + + /** Directive for specifying a specific runtime scheduler, if supported. */ + SCHEDULER( + "scheduler", + UnionType.SCHEDULER_UNION, + Arrays.asList(Target.C, Target.CCPP, Target.Python), + new SchedulerConfigurator() + ), + /** Directive to specify that all code is generated in a single file. */ + SINGLE_FILE_PROJECT( + "single-file-project", + PrimitiveType.BOOLEAN, + List.of(Target.Rust), + (config) -> ASTUtils.toElement(config.singleFileProject), + (config, value, err) -> { + config.singleFileProject = ASTUtils.toBoolean(value); + }), + + /** Directive to indicate whether the runtime should use multi-threading. */ + THREADING( + "threading", + PrimitiveType.BOOLEAN, + List.of(Target.C, Target.CCPP, Target.Python), + (config) -> ASTUtils.toElement(config.threading), + (config, value, err) -> { + config.threading = ASTUtils.toBoolean(value); + }), + + /** Directive to specify the number of worker threads used by the runtime. */ + WORKERS( + "workers", + PrimitiveType.NON_NEGATIVE_INTEGER, + List.of(Target.C, Target.CCPP, Target.Python, Target.CPP, Target.Rust), + (config) -> ASTUtils.toElement(config.workers), + (config, value, err) -> { + config.workers = ASTUtils.toInteger(value); + }), + + /** Directive to specify the execution timeout. */ + TIMEOUT( + "timeout", + PrimitiveType.TIME_VALUE, + Target.ALL, + (config) -> ASTUtils.toElement(config.timeout), + (config, value, err) -> { + config.timeout = ASTUtils.toTimeValue(value); + }, + (config, value, err) -> { + config.timeout = ASTUtils.toTimeValue(value); + }), + + /** Directive to enable tracing. */ + TRACING( + "tracing", + UnionType.TRACING_UNION, + Arrays.asList(Target.C, Target.CCPP, Target.CPP, Target.Python), + new TracingConfigurator()), + + /** + * Directive to let the runtime export its internal dependency graph. + * + *

This is a debugging feature and currently only used for C++ and Rust programs. + */ + EXPORT_DEPENDENCY_GRAPH( + "export-dependency-graph", + PrimitiveType.BOOLEAN, + List.of(Target.CPP, Target.Rust), + (config) -> ASTUtils.toElement(config.exportDependencyGraph), + (config, value, err) -> { + config.exportDependencyGraph = ASTUtils.toBoolean(value); + }), + + /** + * Directive to let the runtime export the program structure to a yaml file. + * + *

This is a debugging feature and currently only used for C++ programs. + */ + EXPORT_TO_YAML( + "export-to-yaml", + PrimitiveType.BOOLEAN, + List.of(Target.CPP), + (config) -> ASTUtils.toElement(config.exportToYaml), + (config, value, err) -> { + config.exportToYaml = ASTUtils.toBoolean(value); + }), + + /** + * List of module files to link into the crate as top-level. For instance, a {@code target Rust { + * rust-modules: [ "foo.rs" ] }} will cause the file to be copied into the generated project, and + * the generated {@code main.rs} will include it with a {@code mod foo;}. If one of the paths is a + * directory, it must contain a {@code mod.rs} file, and all its contents are copied. + */ + RUST_INCLUDE( + "rust-include", + UnionType.FILE_OR_FILE_ARRAY, + List.of(Target.Rust), + (config) -> { + // do not check paths here, and simply copy the absolute path over + List paths = config.rust.getRustTopLevelModules(); + if (paths.isEmpty()) { + return null; + } else if (paths.size() == 1) { + return ASTUtils.toElement(paths.get(0).toString()); + } else { + Element e = LfFactory.eINSTANCE.createElement(); + Array arr = LfFactory.eINSTANCE.createArray(); + for (Path p : paths) { + arr.getElements().add(ASTUtils.toElement(p.toString())); + } + e.setArray(arr); + return e; + } + }, + (config, value, err) -> { + Path referencePath; + try { + referencePath = FileUtil.toPath(value.eResource().getURI()).toAbsolutePath(); + } catch (IllegalArgumentException e) { + err.at(value).error("Invalid path? " + e.getMessage()); + throw e; + } + + // we'll resolve relative paths to check that the files + // are as expected. + + if (value.getLiteral() != null) { + Path resolved = referencePath.resolveSibling(StringUtil.removeQuotes(value.getLiteral())); + + config.rust.addAndCheckTopLevelModule(resolved, value, err); + } else if (value.getArray() != null) { + for (Element element : value.getArray().getElements()) { + String literal = StringUtil.removeQuotes(element.getLiteral()); + Path resolved = referencePath.resolveSibling(literal); + config.rust.addAndCheckTopLevelModule(resolved, element, err); + } + } + }), + + /** Directive for specifying Cargo features of the generated program to enable. */ + CARGO_FEATURES( + "cargo-features", + ArrayType.STRING_ARRAY, + List.of(Target.Rust), + (config) -> ASTUtils.toElement(config.rust.getCargoFeatures()), + (config, value, err) -> { + config.rust.setCargoFeatures(ASTUtils.elementToListOfStrings(value)); + }), + + /** + * Dependency specifications for Cargo. This property looks like this: + * + *

{@code
+       * cargo-dependencies: {
+       *    // Name-of-the-crate: "version"
+       *    rand: "0.8",
+       *    // Equivalent to using an explicit map:
+       *    rand: {
+       *      version: "0.8"
+       *    },
+       *    // The map allows specifying more details
+       *    rand: {
+       *      // A path to a local unpublished crate.
+       *      // Note 'path' is mutually exclusive with 'version'.
+       *      path: "/home/me/Git/local-rand-clone"
+       *    },
+       *    rand: {
+       *      version: "0.8",
+       *      // you can specify cargo features
+       *      features: ["some-cargo-feature",]
+       *    }
+       * }
+       * }
+ */ + CARGO_DEPENDENCIES( + "cargo-dependencies", + CargoDependenciesPropertyType.INSTANCE, + List.of(Target.Rust), + (config) -> { + var deps = config.rust.getCargoDependencies(); + if (deps.size() == 0) { + return null; + } else { + Element e = LfFactory.eINSTANCE.createElement(); + KeyValuePairs kvp = LfFactory.eINSTANCE.createKeyValuePairs(); + for (var ent : deps.entrySet()) { + KeyValuePair pair = LfFactory.eINSTANCE.createKeyValuePair(); + pair.setName(ent.getKey()); + pair.setValue(CargoDependencySpec.extractSpec(ent.getValue())); + kvp.getPairs().add(pair); + } + e.setKeyvalue(kvp); + return e; + } + }, + (config, value, err) -> { + config.rust.setCargoDependencies(CargoDependencySpec.parseAll(value)); + }), + + /** + * Directs the C or Python target to include the associated C file used for setting up federated + * execution before processing the first tag. + */ + FED_SETUP( + "_fed_setup", + PrimitiveType.FILE, + Arrays.asList(Target.C, Target.CCPP, Target.Python), + (config) -> ASTUtils.toElement(config.fedSetupPreamble), + (config, value, err) -> + config.fedSetupPreamble = StringUtil.removeQuotes(ASTUtils.elementToSingleString(value))); + + /** Update {@code config}.dockerOptions based on value. */ private static void setDockerProperty(TargetConfig config, Element value) { if (value.getLiteral() != null) { if (ASTUtils.toBoolean(value)) { @@ -869,12 +839,21 @@ private static void setDockerProperty(TargetConfig config, Element value) { */ public final PropertyParser setter; - /** + private final PropertyValidator validator; + + + /** * Function that given a configuration object and an Element AST node sets the configuration. It * is assumed that validation already occurred, so this code should be straightforward. */ public final PropertyParser updater; + + @FunctionalInterface + private interface PropertyValidator { + void validate(KeyValuePair pair, Model ast, TargetConfig config, ValidationReporter reporter); + } + @FunctionalInterface private interface PropertyParser { @@ -917,6 +896,18 @@ private interface PropertyGetter { this.getter = getter; this.setter = setter; this.updater = setter; // (Re)set by default + this.validator = (pair, ast, config, validator) -> {}; + } + + TargetProperty(String description, TargetPropertyType type, List supportedBy, + TargetPropertyConfig configurator) { + this.description = description; + this.type = type; + this.supportedBy = supportedBy; + this.setter = configurator::parseIntoTargetConfig; + this.getter = configurator::getPropertyElement; + this.updater = configurator::parseIntoTargetConfig; + this.validator = configurator::validate; } /** @@ -942,6 +933,7 @@ private interface PropertyGetter { this.getter = getter; this.setter = setter; this.updater = updater; + this.validator = (pair, ast, config, validator) -> {}; } /** @@ -1012,6 +1004,23 @@ public static TargetDecl extractTargetDecl(Target target, TargetConfig config) { return decl; } + public static KeyValuePair getKeyValuePair(KeyValuePairs targetProperties, TargetProperty property) { + List properties = + targetProperties.getPairs().stream() + .filter(pair -> pair.getName().equals(property.description)) + .toList(); + assert (properties.size() <= 1); + return properties.size() > 0 ? properties.get(0) : null; + } + + public static KeyValuePair getKeyValuePair(Model ast, TargetProperty property) { + return getKeyValuePair(ast.getTarget().getConfig(), property); + } + + public void validate(KeyValuePairs pairs, Model ast, TargetConfig config, ValidationReporter reporter) { + this.validator.validate(getKeyValuePair(pairs, this), ast, config, reporter); + } + /** * Update the given configuration using the given target properties. * @@ -1096,768 +1105,9 @@ public String toString() { return this.description; } - // Inner classes for the various supported types. - - /** Dictionary type that allows for keys that will be interpreted as strings and string values. */ - public enum StringDictionaryType implements TargetPropertyType { - COMPILE_DEFINITION(); - - @Override - public boolean validate(Element e) { - if (e.getKeyvalue() != null) { - return true; - } - return false; - } - - @Override - public void check(Element e, String name, LFValidator v) { - KeyValuePairs kv = e.getKeyvalue(); - if (kv == null) { - TargetPropertyType.produceError(name, this.toString(), v); - } else { - for (KeyValuePair pair : kv.getPairs()) { - String key = pair.getName(); - Element val = pair.getValue(); - - // Make sure the type is string - PrimitiveType.STRING.check(val, name + "." + key, v); - } - } - } - } - /** Interface for dictionary elements. It associates an entry with a type. */ public interface DictionaryElement { TargetPropertyType getType(); } - - /** - * A dictionary type with a predefined set of possible keys and assignable types. - * - * @author Marten Lohstroh - */ - public enum DictionaryType implements TargetPropertyType { - CLOCK_SYNC_OPTION_DICT(Arrays.asList(ClockSyncOption.values())), - DOCKER_DICT(Arrays.asList(DockerOption.values())), - PLATFORM_DICT(Arrays.asList(PlatformOption.values())), - COORDINATION_OPTION_DICT(Arrays.asList(CoordinationOption.values())), - TRACING_DICT(Arrays.asList(TracingOption.values())); - - /** The keys and assignable types that are allowed in this dictionary. */ - public List options; - - /** - * A dictionary type restricted to sets of predefined keys and types of values. - * - * @param options The dictionary elements allowed by this type. - */ - private DictionaryType(List options) { - this.options = options; - } - - /** - * Return the dictionary element of which the key matches the given string. - * - * @param name The string to match against. - * @return The matching dictionary element (or null if there is none). - */ - public DictionaryElement forName(String name) { - return Target.match(name, options); - } - - /** Recursively check that the passed in element conforms to the rules of this dictionary. */ - @Override - public void check(Element e, String name, LFValidator v) { - KeyValuePairs kv = e.getKeyvalue(); - if (kv == null) { - TargetPropertyType.produceError(name, this.toString(), v); - } else { - for (KeyValuePair pair : kv.getPairs()) { - String key = pair.getName(); - Element val = pair.getValue(); - Optional match = - this.options.stream() - .filter(element -> key.equalsIgnoreCase(element.toString())) - .findAny(); - if (match.isPresent()) { - // Make sure the type is correct, too. - TargetPropertyType type = match.get().getType(); - type.check(val, name + "." + key, v); - } else { - // No match found; report error. - TargetPropertyType.produceError(name, this.toString(), v); - } - } - } - } - - /** Return true if the given element represents a dictionary, false otherwise. */ - @Override - public boolean validate(Element e) { - if (e.getKeyvalue() != null) { - return true; - } - return false; - } - - /** Return a human-readable description of this type. */ - @Override - public String toString() { - return "a dictionary with one or more of the following keys: " - + options.stream().map(option -> option.toString()).collect(Collectors.joining(", ")); - } - } - /** - * A type that can assume one of several types. - * - * @author Marten Lohstroh - */ - public enum UnionType implements TargetPropertyType { - STRING_OR_STRING_ARRAY(Arrays.asList(PrimitiveType.STRING, ArrayType.STRING_ARRAY), null), - PLATFORM_STRING_OR_DICTIONARY( - Arrays.asList(PrimitiveType.STRING, DictionaryType.PLATFORM_DICT), null), - FILE_OR_FILE_ARRAY(Arrays.asList(PrimitiveType.FILE, ArrayType.FILE_ARRAY), null), - BUILD_TYPE_UNION(Arrays.asList(BuildType.values()), null), - COORDINATION_UNION(Arrays.asList(CoordinationType.values()), CoordinationType.CENTRALIZED), - SCHEDULER_UNION(Arrays.asList(SchedulerOption.values()), SchedulerOption.getDefault()), - LOGGING_UNION(Arrays.asList(LogLevel.values()), LogLevel.INFO), - PLATFORM_UNION(Arrays.asList(Platform.values()), Platform.AUTO), - CLOCK_SYNC_UNION(Arrays.asList(ClockSyncMode.values()), ClockSyncMode.INIT), - DOCKER_UNION(Arrays.asList(PrimitiveType.BOOLEAN, DictionaryType.DOCKER_DICT), null), - TRACING_UNION(Arrays.asList(PrimitiveType.BOOLEAN, DictionaryType.TRACING_DICT), null); - - /** The constituents of this type union. */ - public final List> options; - - /** The default type, if there is one. */ - private final Enum defaultOption; - - /** - * Private constructor for creating unions types. - * - * @param options The types that that are part of the union. - * @param defaultOption The default type. - */ - private UnionType(List> options, Enum defaultOption) { - this.options = options; - this.defaultOption = defaultOption; - } - - /** - * Return the type among those in this type union that matches the given name. - * - * @param name The string to match against. - * @return The matching dictionary element (or null if there is none). - */ - public Enum forName(String name) { - return Target.match(name, options); - } - - /** Recursively check that the passed in element conforms to the rules of this union. */ - @Override - public void check(Element e, String name, LFValidator v) { - Optional> match = this.match(e); - if (match.isPresent()) { - // Go deeper if the element is an array or dictionary. - Enum type = match.get(); - if (type instanceof DictionaryType) { - ((DictionaryType) type).check(e, name, v); - } else if (type instanceof ArrayType) { - ((ArrayType) type).check(e, name, v); - } else if (type instanceof PrimitiveType) { - ((PrimitiveType) type).check(e, name, v); - } else if (!(type instanceof Enum)) { - throw new RuntimeException("Encountered an unknown type."); - } - } else { - // No match found; report error. - TargetPropertyType.produceError(name, this.toString(), v); - } - } - - /** - * Internal method for matching a given element against the allowable types. - * - * @param e AST node that represents the value of a target property. - * @return The matching type wrapped in an Optional object. - */ - private Optional> match(Element e) { - return this.options.stream() - .filter( - option -> { - if (option instanceof TargetPropertyType) { - return ((TargetPropertyType) option).validate(e); - } else { - return ASTUtils.elementToSingleString(e).equalsIgnoreCase(option.toString()); - } - }) - .findAny(); - } - - /** - * Return true if this union has an option that matches the given element. - * - * @param e The element to match against this type. - */ - @Override - public boolean validate(Element e) { - if (this.match(e).isPresent()) { - return true; - } - return false; - } - - /** - * Return a human-readable description of this type. If three is a default option, then indicate - * it. - */ - @Override - public String toString() { - return "one of the following: " - + options.stream() - .map( - option -> { - if (option == this.defaultOption) { - return option.toString() + " (default)"; - } else { - return option.toString(); - } - }) - .collect(Collectors.joining(", ")); - } - } - - /** - * An array type of which the elements confirm to a given type. - * - * @author Marten Lohstroh - */ - public enum ArrayType implements TargetPropertyType { - STRING_ARRAY(PrimitiveType.STRING), - FILE_ARRAY(PrimitiveType.FILE); - - /** Type parameter of this array type. */ - public TargetPropertyType type; - - /** - * Private constructor to create a new array type. - * - * @param type The type of elements in the array. - */ - private ArrayType(TargetPropertyType type) { - this.type = type; - } - - /** - * Check that the passed in element represents an array and ensure that its elements are all of - * the correct type. - */ - @Override - public void check(Element e, String name, LFValidator v) { - Array array = e.getArray(); - if (array == null) { - TargetPropertyType.produceError(name, this.toString(), v); - } else { - List elements = array.getElements(); - for (int i = 0; i < elements.size(); i++) { - this.type.check(elements.get(i), name + "[" + i + "]", v); - } - } - } - - /** Return true of the given element is an array. */ - @Override - public boolean validate(Element e) { - if (e.getArray() != null) { - return true; - } - return false; - } - - /** Return a human-readable description of this type. */ - @Override - public String toString() { - return "an array of which each element is " + this.type.toString(); - } - } - - /** - * Enumeration of Cmake build types. These are also mapped to Cargo profiles for the Rust target - * (see {@link org.lflang.generator.rust.RustTargetConfig}) - * - * @author Christian Menard - */ - public enum BuildType { - RELEASE("Release"), - DEBUG("Debug"), - TEST("Test"), - REL_WITH_DEB_INFO("RelWithDebInfo"), - MIN_SIZE_REL("MinSizeRel"); - - /** Alias used in toString method. */ - private final String alias; - - /** Private constructor for Cmake build types. */ - BuildType(String alias) { - this.alias = alias; - } - - /** Return the alias. */ - @Override - public String toString() { - return this.alias; - } - } - - /** - * Enumeration of coordination types. - * - * @author Marten Lohstroh - */ - public enum CoordinationType { - CENTRALIZED, - DECENTRALIZED; - - /** Return the name in lower case. */ - @Override - public String toString() { - return this.name().toLowerCase(); - } - } - - /** - * Enumeration of clock synchronization modes. - * - *
    - *
  • OFF: The clock synchronization is universally off. - *
  • STARTUP: Clock synchronization occurs at startup only. - *
  • ON: Clock synchronization occurs at startup and at runtime. - *
- * - * @author Edward A. Lee - */ - public enum ClockSyncMode { - OFF, - INIT, - ON; // TODO Discuss initial in now a mode keyword (same as startup) and cannot be used as target - // property value, thus changed it to init - // FIXME I could not test if this change breaks anything - - /** Return the name in lower case. */ - @Override - public String toString() { - return this.name().toLowerCase(); - } - } - - /** - * An interface for types associated with target properties. - * - * @author Marten Lohstroh - */ - public interface TargetPropertyType { - - /** - * Return true if the the given Element is a valid instance of this type. - * - * @param e The Element to validate. - * @return True if the element conforms to this type, false otherwise. - */ - public boolean validate(Element e); - - /** - * Check (recursively) the given Element against its associated type(s) and add found problems - * to the given list of errors. - * - * @param e The Element to type check. - * @param name The name of the target property. - * @param v A reference to the validator to report errors to. - */ - public void check(Element e, String name, LFValidator v); - - /** - * Helper function to produce an error during type checking. - * - * @param name The description of the target property. - * @param description The description of the type. - * @param v A reference to the validator to report errors to. - */ - public static void produceError(String name, String description, LFValidator v) { - - v.reportTargetPropertyError( - "Target property '" + name + "' is required to be " + description + "."); - } - } - - /** - * Primitive types for target properties, each with a description used in error messages and - * predicate used for validating values. - * - * @author Marten Lohstroh - */ - public enum PrimitiveType implements TargetPropertyType { - BOOLEAN( - "'true' or 'false'", - v -> - ASTUtils.elementToSingleString(v).equalsIgnoreCase("true") - || ASTUtils.elementToSingleString(v).equalsIgnoreCase("false")), - INTEGER( - "an integer", - v -> { - try { - Integer.parseInt(ASTUtils.elementToSingleString(v)); - } catch (NumberFormatException e) { - return false; - } - return true; - }), - NON_NEGATIVE_INTEGER( - "a non-negative integer", - v -> { - try { - int result = Integer.parseInt(ASTUtils.elementToSingleString(v)); - if (result < 0) return false; - } catch (NumberFormatException e) { - return false; - } - return true; - }), - TIME_VALUE( - "a time value with units", - v -> - v.getKeyvalue() == null - && v.getArray() == null - && v.getLiteral() == null - && v.getId() == null - && (v.getTime() == 0 || v.getUnit() != null)), - STRING( - "a string", - v -> v.getLiteral() != null && !isCharLiteral(v.getLiteral()) || v.getId() != null), - FILE("a path to a file", STRING.validator); - - /** A description of this type, featured in error messages. */ - private final String description; - - /** A predicate for determining whether a given Element conforms to this type. */ - public final Predicate validator; - - /** - * Private constructor to create a new primitive type. - * - * @param description A textual description of the type that should start with "a/an". - * @param validator A predicate that returns true if a given Element conforms to this type. - */ - private PrimitiveType(String description, Predicate validator) { - this.description = description; - this.validator = validator; - } - - /** Return true if the the given Element is a valid instance of this type. */ - public boolean validate(Element e) { - return this.validator.test(e); - } - - /** - * Check (recursively) the given Element against its associated type(s) and add found problems - * to the given list of errors. - * - * @param e The element to type check. - * @param name The name of the target property. - * @param v The LFValidator to append errors to. - */ - public void check(Element e, String name, LFValidator v) { - if (!this.validate(e)) { - TargetPropertyType.produceError(name, this.description, v); - } - // If this is a file, perform an additional check to make sure - // the file actually exists. - // FIXME: premature because we first need a mechanism for looking up files! - // Looking in the same directory is too restrictive. Disabling this check for now. - /* - if (this == FILE) { - String file = ASTUtils.toSingleString(e); - - if (!FileConfig.fileExists(file, FileConfig.toPath(e.eResource().getURI()).toFile().getParent())) { - v.targetPropertyWarnings - .add("Could not find file: '" + file + "'."); - } - } - */ - } - - /** Return a textual description of this type. */ - @Override - public String toString() { - return this.description; - } - - private static boolean isCharLiteral(String s) { - return s.length() > 2 && '\'' == s.charAt(0) && '\'' == s.charAt(s.length() - 1); - } - } - - /** - * Clock synchronization options. - * - * @author Marten Lohstroh - */ - public enum ClockSyncOption implements DictionaryElement { - ATTENUATION("attenuation", PrimitiveType.NON_NEGATIVE_INTEGER), - LOCAL_FEDERATES_ON("local-federates-on", PrimitiveType.BOOLEAN), - PERIOD("period", PrimitiveType.TIME_VALUE), - TEST_OFFSET("test-offset", PrimitiveType.TIME_VALUE), - TRIALS("trials", PrimitiveType.NON_NEGATIVE_INTEGER), - COLLECT_STATS("collect-stats", PrimitiveType.BOOLEAN); - - public final PrimitiveType type; - - private final String description; - - private ClockSyncOption(String alias, PrimitiveType type) { - this.description = alias; - this.type = type; - } - - /** Return the description of this dictionary element. */ - @Override - public String toString() { - return this.description; - } - - /** Return the type associated with this dictionary element. */ - public TargetPropertyType getType() { - return this.type; - } - } - - /** - * Docker options. - * - * @author Edward A. Lee - */ - public enum DockerOption implements DictionaryElement { - FROM("FROM", PrimitiveType.STRING); - - public final PrimitiveType type; - - private final String description; - - private DockerOption(String alias, PrimitiveType type) { - this.description = alias; - this.type = type; - } - - /** Return the description of this dictionary element. */ - @Override - public String toString() { - return this.description; - } - - /** Return the type associated with this dictionary element. */ - public TargetPropertyType getType() { - return this.type; - } - } - - /** - * Platform options. - * - * @author Anirudh Rengarajan - */ - public enum PlatformOption implements DictionaryElement { - NAME("name", PrimitiveType.STRING), - BAUDRATE("baud-rate", PrimitiveType.NON_NEGATIVE_INTEGER), - BOARD("board", PrimitiveType.STRING), - FLASH("flash", PrimitiveType.BOOLEAN), - PORT("port", PrimitiveType.STRING), - USER_THREADS("user-threads", PrimitiveType.NON_NEGATIVE_INTEGER); - - public final PrimitiveType type; - - private final String description; - - private PlatformOption(String alias, PrimitiveType type) { - this.description = alias; - this.type = type; - } - - /** Return the description of this dictionary element. */ - @Override - public String toString() { - return this.description; - } - - /** Return the type associated with this dictionary element. */ - public TargetPropertyType getType() { - return this.type; - } - } - - /** - * Coordination options. - * - * @author Edward A. Lee - */ - public enum CoordinationOption implements DictionaryElement { - ADVANCE_MESSAGE_INTERVAL("advance-message-interval", PrimitiveType.TIME_VALUE); - - public final PrimitiveType type; - - private final String description; - - private CoordinationOption(String alias, PrimitiveType type) { - this.description = alias; - this.type = type; - } - - /** Return the description of this dictionary element. */ - @Override - public String toString() { - return this.description; - } - - /** Return the type associated with this dictionary element. */ - public TargetPropertyType getType() { - return this.type; - } - } - - /** - * Log levels in descending order of severity. - * - * @author Marten Lohstroh - */ - public enum LogLevel { - ERROR, - WARN, - INFO, - LOG, - DEBUG; - - /** Return the name in lower case. */ - @Override - public String toString() { - return this.name().toLowerCase(); - } - } - - /** Enumeration of supported platforms */ - public enum Platform { - AUTO, - ARDUINO, - NRF52("Nrf52", true), - RP2040("Rp2040", false), - LINUX("Linux", true), - MAC("Darwin", true), - ZEPHYR("Zephyr", true), - WINDOWS("Windows", true); - - String cMakeName; - - private boolean multiThreaded = true; - - Platform() { - this.cMakeName = this.toString(); - } - - Platform(String cMakeName, boolean isMultiThreaded) { - this.cMakeName = cMakeName; - this.multiThreaded = isMultiThreaded; - } - - /** Return the name in lower case. */ - @Override - public String toString() { - return this.name().toLowerCase(); - } - - /** Get the CMake name for the platform. */ - public String getcMakeName() { - return this.cMakeName; - } - - public boolean isMultiThreaded() { - return this.multiThreaded; - } - } - - /** - * Supported schedulers. - * - * @author Soroush Bateni - */ - public enum SchedulerOption { - NP(false), // Non-preemptive - ADAPTIVE( - false, - List.of( - Path.of("scheduler_adaptive.c"), - Path.of("worker_assignments.h"), - Path.of("worker_states.h"), - Path.of("data_collection.h"))), - GEDF_NP(true), // Global EDF non-preemptive - GEDF_NP_CI(true); // Global EDF non-preemptive with chain ID - // PEDF_NP(true); // Partitioned EDF non-preemptive (FIXME: To be re-added in a future PR) - - /** Indicate whether or not the scheduler prioritizes reactions by deadline. */ - private final boolean prioritizesDeadline; - - /** Relative paths to files required by this scheduler. */ - private final List relativePaths; - - SchedulerOption(boolean prioritizesDeadline) { - this(prioritizesDeadline, null); - } - - SchedulerOption(boolean prioritizesDeadline, List relativePaths) { - this.prioritizesDeadline = prioritizesDeadline; - this.relativePaths = relativePaths; - } - - /** Return true if the scheduler prioritizes reactions by deadline. */ - public boolean prioritizesDeadline() { - return this.prioritizesDeadline; - } - - public List getRelativePaths() { - return relativePaths != null - ? ImmutableList.copyOf(relativePaths) - : List.of(Path.of("scheduler_" + this + ".c")); - } - - public static SchedulerOption getDefault() { - return NP; - } - } - - /** - * Tracing options. - * - * @author Edward A. Lee - */ - public enum TracingOption implements DictionaryElement { - TRACE_FILE_NAME("trace-file-name", PrimitiveType.STRING); - - public final PrimitiveType type; - - private final String description; - - private TracingOption(String alias, PrimitiveType type) { - this.description = alias; - this.type = type; - } - - /** Return the description of this dictionary element. */ - @Override - public String toString() { - return this.description; - } - - /** Return the type associated with this dictionary element. */ - public TargetPropertyType getType() { - return this.type; - } - } } diff --git a/core/src/main/java/org/lflang/TargetPropertyConfig.java b/core/src/main/java/org/lflang/TargetPropertyConfig.java new file mode 100644 index 0000000000..1e784da0a5 --- /dev/null +++ b/core/src/main/java/org/lflang/TargetPropertyConfig.java @@ -0,0 +1,26 @@ +package org.lflang; + +import org.lflang.lf.Element; +import org.lflang.lf.KeyValuePair; +import org.lflang.lf.Model; +import org.lflang.validation.ValidationReporter; + +public interface TargetPropertyConfig { + + /** + * Parse the given element into the given target config. May use the error reporter to report + * format errors. + */ + void parseIntoTargetConfig(TargetConfig config, Element value, MessageReporter err); + + T parse(Element value); + + // FIXME: config may not be needed. + void validate(KeyValuePair pair, Model ast, TargetConfig config, ValidationReporter reporter); + + /** + * Read this property from the target config and build an element which represents it for the AST. + * May return null if the given value of this property is the same as the default. + */ + Element getPropertyElement(TargetConfig config); +} 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 d6493f96c0..206798a14c 100644 --- a/core/src/main/java/org/lflang/federated/extensions/CExtension.java +++ b/core/src/main/java/org/lflang/federated/extensions/CExtension.java @@ -37,7 +37,6 @@ import org.lflang.MessageReporter; import org.lflang.Target; import org.lflang.TargetProperty; -import org.lflang.TargetProperty.CoordinationType; import org.lflang.TimeValue; import org.lflang.ast.ASTUtils; import org.lflang.federated.generator.FedASTUtils; @@ -58,6 +57,7 @@ import org.lflang.lf.Port; import org.lflang.lf.Reactor; import org.lflang.lf.VarRef; +import org.lflang.target.CoordinationConfig.CoordinationType; /** * An extension class to the CGenerator that enables certain federated functionalities. diff --git a/core/src/main/java/org/lflang/federated/extensions/FedTargetExtension.java b/core/src/main/java/org/lflang/federated/extensions/FedTargetExtension.java index f3a9c48d51..61a6583026 100644 --- a/core/src/main/java/org/lflang/federated/extensions/FedTargetExtension.java +++ b/core/src/main/java/org/lflang/federated/extensions/FedTargetExtension.java @@ -3,7 +3,6 @@ import java.io.IOException; import org.lflang.InferredType; import org.lflang.MessageReporter; -import org.lflang.TargetProperty.CoordinationType; import org.lflang.federated.generator.FedConnectionInstance; import org.lflang.federated.generator.FedFileConfig; import org.lflang.federated.generator.FederateInstance; @@ -14,6 +13,7 @@ import org.lflang.lf.Reaction; import org.lflang.lf.Reactor; import org.lflang.lf.VarRef; +import org.lflang.target.CoordinationConfig.CoordinationType; public interface FedTargetExtension { diff --git a/core/src/main/java/org/lflang/federated/extensions/PythonExtension.java b/core/src/main/java/org/lflang/federated/extensions/PythonExtension.java index 3d84d78562..0b5007f5bc 100644 --- a/core/src/main/java/org/lflang/federated/extensions/PythonExtension.java +++ b/core/src/main/java/org/lflang/federated/extensions/PythonExtension.java @@ -29,7 +29,6 @@ import java.io.IOException; import org.lflang.InferredType; import org.lflang.MessageReporter; -import org.lflang.TargetProperty.CoordinationType; import org.lflang.ast.ASTUtils; import org.lflang.federated.generator.FedConnectionInstance; import org.lflang.federated.generator.FedFileConfig; @@ -43,6 +42,7 @@ import org.lflang.lf.Action; import org.lflang.lf.Reaction; import org.lflang.lf.VarRef; +import org.lflang.target.CoordinationConfig.CoordinationType; /** * An extension class to the PythonGenerator that enables certain federated functionalities. diff --git a/core/src/main/java/org/lflang/federated/extensions/TSExtension.java b/core/src/main/java/org/lflang/federated/extensions/TSExtension.java index 9ef81c6a23..a3ac049a37 100644 --- a/core/src/main/java/org/lflang/federated/extensions/TSExtension.java +++ b/core/src/main/java/org/lflang/federated/extensions/TSExtension.java @@ -7,7 +7,6 @@ import java.util.stream.Collectors; import org.lflang.InferredType; import org.lflang.MessageReporter; -import org.lflang.TargetProperty.CoordinationType; import org.lflang.TimeValue; import org.lflang.ast.ASTUtils; import org.lflang.federated.generator.FedASTUtils; @@ -26,6 +25,7 @@ import org.lflang.lf.Reactor; import org.lflang.lf.VarRef; import org.lflang.lf.Variable; +import org.lflang.target.CoordinationConfig.CoordinationType; public class TSExtension implements FedTargetExtension { @Override diff --git a/core/src/main/java/org/lflang/federated/generator/FedASTUtils.java b/core/src/main/java/org/lflang/federated/generator/FedASTUtils.java index e145248cb5..6414db1e9c 100644 --- a/core/src/main/java/org/lflang/federated/generator/FedASTUtils.java +++ b/core/src/main/java/org/lflang/federated/generator/FedASTUtils.java @@ -45,7 +45,6 @@ import org.eclipse.xtext.xbase.lib.IteratorExtensions; import org.lflang.InferredType; import org.lflang.MessageReporter; -import org.lflang.TargetProperty.CoordinationType; import org.lflang.TimeValue; import org.lflang.ast.ASTUtils; import org.lflang.federated.extensions.FedTargetExtension; @@ -71,6 +70,7 @@ import org.lflang.lf.Type; import org.lflang.lf.VarRef; import org.lflang.lf.Variable; +import org.lflang.target.CoordinationConfig.CoordinationType; /** * A helper class for AST transformations needed for federated execution. 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 f885daabdf..05a500710c 100644 --- a/core/src/main/java/org/lflang/federated/generator/FedGenerator.java +++ b/core/src/main/java/org/lflang/federated/generator/FedGenerator.java @@ -32,7 +32,6 @@ import org.lflang.MessageReporter; import org.lflang.Target; import org.lflang.TargetConfig; -import org.lflang.TargetProperty.CoordinationType; import org.lflang.ast.ASTUtils; import org.lflang.federated.launcher.FedLauncherGenerator; import org.lflang.federated.launcher.RtiConfig; @@ -59,6 +58,7 @@ import org.lflang.lf.Reactor; import org.lflang.lf.TargetDecl; import org.lflang.lf.VarRef; +import org.lflang.target.CoordinationConfig.CoordinationType; import org.lflang.util.Averager; public class FedGenerator { diff --git a/core/src/main/java/org/lflang/federated/launcher/FedLauncherGenerator.java b/core/src/main/java/org/lflang/federated/launcher/FedLauncherGenerator.java index 6f2347d85c..bff26e5c2f 100644 --- a/core/src/main/java/org/lflang/federated/launcher/FedLauncherGenerator.java +++ b/core/src/main/java/org/lflang/federated/launcher/FedLauncherGenerator.java @@ -7,7 +7,7 @@ * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * - * 2. Redistributions in binary form must reproduce the above copyright notice, + * 2. Redistributions in binary formimport org.lflang.TargetProperty.ClockSyncMode; must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * @@ -35,9 +35,9 @@ import java.util.List; import org.lflang.MessageReporter; import org.lflang.TargetConfig; -import org.lflang.TargetProperty.ClockSyncMode; import org.lflang.federated.generator.FedFileConfig; import org.lflang.federated.generator.FederateInstance; +import org.lflang.target.ClockSyncConfigurator.ClockSyncMode; /** * Utility class that can be used to create a launcher for federated LF programs. 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 0ee24fc39a..e7b7ecb5a5 100644 --- a/core/src/main/java/org/lflang/generator/c/CCmakeGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CCmakeGenerator.java @@ -34,8 +34,8 @@ import org.lflang.FileConfig; import org.lflang.MessageReporter; import org.lflang.TargetConfig; -import org.lflang.TargetProperty.Platform; import org.lflang.generator.CodeBuilder; +import org.lflang.target.PlatformConfigurator.Platform; import org.lflang.util.FileUtil; /** diff --git a/core/src/main/java/org/lflang/generator/c/CCompiler.java b/core/src/main/java/org/lflang/generator/c/CCompiler.java index 0933d95594..0df21fc413 100644 --- a/core/src/main/java/org/lflang/generator/c/CCompiler.java +++ b/core/src/main/java/org/lflang/generator/c/CCompiler.java @@ -36,12 +36,12 @@ import org.lflang.FileConfig; import org.lflang.MessageReporter; import org.lflang.TargetConfig; -import org.lflang.TargetProperty; -import org.lflang.TargetProperty.Platform; import org.lflang.generator.GeneratorBase; import org.lflang.generator.GeneratorCommandFactory; import org.lflang.generator.GeneratorUtils; import org.lflang.generator.LFGeneratorContext; +import org.lflang.target.property.BuildConfig; +import org.lflang.target.PlatformConfigurator.Platform; import org.lflang.util.FileUtil; import org.lflang.util.LFCommand; @@ -261,7 +261,7 @@ private static List cmakeOptions(TargetConfig targetConfig, FileConfig f } /** Return the cmake config name correspnding to a given build type. */ - private String buildTypeToCmakeConfig(TargetProperty.BuildType type) { + private String buildTypeToCmakeConfig(BuildConfig.BuildType type) { if (type == null) { return "Release"; } 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 f6faa499a2..335a971247 100644 --- a/core/src/main/java/org/lflang/generator/c/CGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CGenerator.java @@ -54,7 +54,6 @@ import org.lflang.Target; import org.lflang.TargetConfig; import org.lflang.TargetProperty; -import org.lflang.TargetProperty.Platform; import org.lflang.TargetProperty.PlatformOption; import org.lflang.ast.ASTUtils; import org.lflang.ast.DelayedConnectionTransformation; @@ -89,6 +88,8 @@ import org.lflang.lf.ReactorDecl; import org.lflang.lf.StateVar; import org.lflang.lf.Variable; +import org.lflang.target.PlatformConfigurator.Platform; +import org.lflang.target.SchedulerConfigurator.SchedulerOption; import org.lflang.util.ArduinoUtil; import org.lflang.util.FileUtil; @@ -698,7 +699,7 @@ private void pickScheduler() { // Check if a deadline is assigned to any reaction if (hasDeadlines(reactors)) { if (!targetConfig.setByUser.contains(TargetProperty.SCHEDULER)) { - targetConfig.schedulerType = TargetProperty.SchedulerOption.GEDF_NP; + targetConfig.schedulerType = SchedulerOption.GEDF_NP; } } } diff --git a/core/src/main/java/org/lflang/generator/c/CMainFunctionGenerator.java b/core/src/main/java/org/lflang/generator/c/CMainFunctionGenerator.java index 5f0657c322..99f3df0f0b 100644 --- a/core/src/main/java/org/lflang/generator/c/CMainFunctionGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CMainFunctionGenerator.java @@ -3,8 +3,8 @@ import java.util.ArrayList; import java.util.List; import org.lflang.TargetConfig; -import org.lflang.TargetProperty.Platform; import org.lflang.generator.CodeBuilder; +import org.lflang.target.PlatformConfigurator.Platform; import org.lflang.util.StringUtil; public class CMainFunctionGenerator { 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 30095ec598..dc48f5d40b 100644 --- a/core/src/main/java/org/lflang/generator/c/CPreambleGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CPreambleGenerator.java @@ -4,8 +4,8 @@ import java.nio.file.Path; import org.lflang.TargetConfig; -import org.lflang.TargetProperty.Platform; import org.lflang.generator.CodeBuilder; +import org.lflang.target.PlatformConfigurator.Platform; import org.lflang.util.StringUtil; /** 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 77e7eee22e..25ab8b59b9 100644 --- a/core/src/main/java/org/lflang/generator/c/CTriggerObjectsGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CTriggerObjectsGenerator.java @@ -15,7 +15,6 @@ import java.util.stream.Collectors; import org.lflang.AttributeUtils; import org.lflang.TargetConfig; -import org.lflang.TargetProperty.LogLevel; import org.lflang.ast.ASTUtils; import org.lflang.federated.extensions.CExtensionUtils; import org.lflang.generator.CodeBuilder; @@ -24,6 +23,7 @@ import org.lflang.generator.ReactorInstance; import org.lflang.generator.RuntimeRange; import org.lflang.generator.SendRange; +import org.lflang.target.LoggingConfigurator.LogLevel; /** * Generate code for the "_lf_initialize_trigger_objects" function diff --git a/core/src/main/java/org/lflang/generator/rust/CargoDependencySpec.java b/core/src/main/java/org/lflang/generator/rust/CargoDependencySpec.java index cd160f53c1..c1e6fad3f3 100644 --- a/core/src/main/java/org/lflang/generator/rust/CargoDependencySpec.java +++ b/core/src/main/java/org/lflang/generator/rust/CargoDependencySpec.java @@ -34,7 +34,6 @@ import org.eclipse.emf.ecore.EObject; import org.lflang.MessageReporter; import org.lflang.TargetProperty; -import org.lflang.TargetProperty.TargetPropertyType; import org.lflang.ast.ASTUtils; import org.lflang.generator.InvalidLfSourceException; import org.lflang.lf.Array; @@ -42,6 +41,7 @@ import org.lflang.lf.KeyValuePair; import org.lflang.lf.KeyValuePairs; import org.lflang.lf.LfFactory; +import org.lflang.target.property.type.TargetPropertyType; import org.lflang.util.StringUtil; import org.lflang.validation.LFValidator; diff --git a/core/src/main/java/org/lflang/generator/rust/RustTargetConfig.java b/core/src/main/java/org/lflang/generator/rust/RustTargetConfig.java index 7c164c1957..83ef50589b 100644 --- a/core/src/main/java/org/lflang/generator/rust/RustTargetConfig.java +++ b/core/src/main/java/org/lflang/generator/rust/RustTargetConfig.java @@ -32,7 +32,7 @@ import java.util.Map; import org.eclipse.emf.ecore.EObject; import org.lflang.MessageReporter; -import org.lflang.TargetProperty.BuildType; +import org.lflang.target.property.BuildConfig.BuildType; /** * Rust-specific part of a {@link org.lflang.TargetConfig}. diff --git a/core/src/main/java/org/lflang/target/AuthConfigurator.java b/core/src/main/java/org/lflang/target/AuthConfigurator.java new file mode 100644 index 0000000000..7a1aec6372 --- /dev/null +++ b/core/src/main/java/org/lflang/target/AuthConfigurator.java @@ -0,0 +1,33 @@ +package org.lflang.target; + +import org.lflang.MessageReporter; +import org.lflang.TargetConfig; +import org.lflang.TargetPropertyConfig; +import org.lflang.ast.ASTUtils; +import org.lflang.lf.Element; +import org.lflang.lf.KeyValuePair; +import org.lflang.lf.Model; +import org.lflang.validation.LFValidator.ValidationReporter; + +public class AuthConfigurator implements TargetPropertyConfig { + + @Override + public void parseIntoTargetConfig(TargetConfig config, Element value, MessageReporter err) { + config.auth = this.parse(value); + } + + @Override + public Boolean parse(Element value) { + return ASTUtils.toBoolean(value); + } + + @Override + public void validate(KeyValuePair pair, Model ast, TargetConfig config, ValidationReporter reporter) { + + } + + @Override + public Element getPropertyElement(TargetConfig config) { + return ASTUtils.toElement(config.auth); + } +} diff --git a/core/src/main/java/org/lflang/target/ClockSyncConfigurator.java b/core/src/main/java/org/lflang/target/ClockSyncConfigurator.java new file mode 100644 index 0000000000..4508aa809b --- /dev/null +++ b/core/src/main/java/org/lflang/target/ClockSyncConfigurator.java @@ -0,0 +1,115 @@ +package org.lflang.target; + +import org.lflang.MessageReporter; +import org.lflang.TargetConfig; +import org.lflang.TargetProperty.DictionaryElement; +import org.lflang.TargetPropertyConfig; +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.ClockSyncConfigurator.ClockSyncMode; +import org.lflang.target.property.type.TargetPropertyType; +import org.lflang.target.property.type.PrimitiveType; +import org.lflang.target.property.type.UnionType; +import org.lflang.validation.LFValidator.ValidationReporter; + +public class ClockSyncConfigurator implements TargetPropertyConfig { + + @Override + public void parseIntoTargetConfig(TargetConfig config, Element value, MessageReporter err) { + config.clockSync = this.parse(value); + + } + + @Override + public ClockSyncMode parse(Element value) { + return (ClockSyncMode) + UnionType.CLOCK_SYNC_UNION.forName(ASTUtils.elementToSingleString(value)); + } + + + @Override + public void validate(KeyValuePair pair, Model ast, TargetConfig config, ValidationReporter reporter) { + if (pair != null) { + boolean federatedExists = false; + for (Reactor reactor : ast.getReactors()) { + if (reactor.isFederated()) { + federatedExists = true; + } + } + if (!federatedExists) { + reporter.warning( + "The clock-sync target property is incompatible with non-federated programs.", + pair, + Literals.KEY_VALUE_PAIR__NAME); + } + } + } + + @Override + public Element getPropertyElement(TargetConfig config) { + return ASTUtils.toElement(config.clockSync.toString()); + } + + /** + * Clock synchronization options. + * + * @author Marten Lohstroh + */ + public enum ClockSyncOption implements DictionaryElement { + ATTENUATION("attenuation", PrimitiveType.NON_NEGATIVE_INTEGER), + LOCAL_FEDERATES_ON("local-federates-on", PrimitiveType.BOOLEAN), + PERIOD("period", PrimitiveType.TIME_VALUE), + TEST_OFFSET("test-offset", PrimitiveType.TIME_VALUE), + TRIALS("trials", PrimitiveType.NON_NEGATIVE_INTEGER), + COLLECT_STATS("collect-stats", PrimitiveType.BOOLEAN); + + public final PrimitiveType type; + + private final String description; + + private ClockSyncOption(String alias, PrimitiveType type) { + this.description = alias; + this.type = type; + } + + /** Return the description of this dictionary element. */ + @Override + public String toString() { + return this.description; + } + + /** Return the type associated with this dictionary element. */ + public TargetPropertyType getType() { + return this.type; + } + } + + /** + * Enumeration of clock synchronization modes. + * + *
    + *
  • OFF: The clock synchronization is universally off. + *
  • STARTUP: Clock synchronization occurs at startup only. + *
  • ON: Clock synchronization occurs at startup and at runtime. + *
+ * + * @author Edward A. Lee + */ + public enum ClockSyncMode { + OFF, + INIT, + ON; // TODO Discuss initial in now a mode keyword (same as startup) and cannot be used as target + // property value, thus changed it to init + // FIXME I could not test if this change breaks anything + + /** Return the name in lower case. */ + @Override + public String toString() { + return this.name().toLowerCase(); + } + } +} diff --git a/core/src/main/java/org/lflang/target/CoordinationConfig.java b/core/src/main/java/org/lflang/target/CoordinationConfig.java new file mode 100644 index 0000000000..08ed4204a7 --- /dev/null +++ b/core/src/main/java/org/lflang/target/CoordinationConfig.java @@ -0,0 +1,83 @@ +package org.lflang.target; + +import org.lflang.MessageReporter; +import org.lflang.TargetConfig; +import org.lflang.TargetProperty.DictionaryElement; +import org.lflang.TargetPropertyConfig; +import org.lflang.lf.Element; +import org.lflang.lf.KeyValuePair; +import org.lflang.lf.Model; +import org.lflang.target.CoordinationConfig.CoordinationOption; +import org.lflang.target.property.type.TargetPropertyType; +import org.lflang.target.property.type.PrimitiveType; +import org.lflang.validation.LFValidator.ValidationReporter; + +public class CoordinationConfig implements TargetPropertyConfig { + + @Override + public void parseIntoTargetConfig(TargetConfig config, Element value, MessageReporter err) { + + } + + @Override + public CoordinationOption parse(Element value) { + return null; + } + + @Override + public void validate(KeyValuePair pair, Model ast, TargetConfig config, ValidationReporter reporter) { + + } + + @Override + public Element getPropertyElement(TargetConfig config) { + return null; + } + + /** + * Coordination options. + * + * @author Edward A. Lee + */ + public enum CoordinationOption implements DictionaryElement { + ADVANCE_MESSAGE_INTERVAL("advance-message-interval", PrimitiveType.TIME_VALUE); + + public final PrimitiveType type; + + private final String description; + + private CoordinationOption(String alias, PrimitiveType type) { + this.description = alias; + this.type = type; + } + + /** Return the description of this dictionary element. */ + @Override + public String toString() { + return this.description; + } + + /** Return the type associated with this dictionary element. */ + public TargetPropertyType getType() { + return this.type; + } + } + + /** + * Enumeration of coordination types. + * + * @author Marten Lohstroh + */ + public enum CoordinationType { + CENTRALIZED, + DECENTRALIZED; + + /** Return the name in lower case. */ + @Override + public String toString() { + return this.name().toLowerCase(); + } + } + + +} diff --git a/core/src/main/java/org/lflang/target/DockerConfig.java b/core/src/main/java/org/lflang/target/DockerConfig.java new file mode 100644 index 0000000000..3853ceb1c7 --- /dev/null +++ b/core/src/main/java/org/lflang/target/DockerConfig.java @@ -0,0 +1,66 @@ +package org.lflang.target; + +import org.lflang.MessageReporter; +import org.lflang.TargetConfig; +import org.lflang.TargetProperty.DictionaryElement; +import org.lflang.target.property.type.PrimitiveType; +import org.lflang.target.property.type.TargetPropertyType; +import org.lflang.TargetPropertyConfig; +import org.lflang.lf.Element; +import org.lflang.lf.KeyValuePair; +import org.lflang.lf.Model; +import org.lflang.target.DockerConfig.DockerOption; +import org.lflang.target.property.type.TargetPropertyType; +import org.lflang.validation.LFValidator.ValidationReporter; + +public class DockerConfig implements TargetPropertyConfig { + + @Override + public void parseIntoTargetConfig(TargetConfig config, Element value, MessageReporter err) { + + } + + @Override + public DockerOption parse(Element value) { + return null; + } + + @Override + public void validate(KeyValuePair pair, Model ast, TargetConfig config, ValidationReporter reporter) { + + } + + @Override + public Element getPropertyElement(TargetConfig config) { + return null; + } + + /** + * Docker options. + * + * @author Edward A. Lee + */ + public enum DockerOption implements DictionaryElement { + FROM("FROM", PrimitiveType.STRING); + + public final PrimitiveType type; + + private final String description; + + private DockerOption(String alias, PrimitiveType type) { + this.description = alias; + this.type = type; + } + + /** Return the description of this dictionary element. */ + @Override + public String toString() { + return this.description; + } + + /** Return the type associated with this dictionary element. */ + public TargetPropertyType getType() { + return this.type; + } + } +} diff --git a/core/src/main/java/org/lflang/target/FastConfigurator.java b/core/src/main/java/org/lflang/target/FastConfigurator.java new file mode 100644 index 0000000000..d9e4696167 --- /dev/null +++ b/core/src/main/java/org/lflang/target/FastConfigurator.java @@ -0,0 +1,64 @@ +package org.lflang.target; + +import org.lflang.MessageReporter; +import org.lflang.TargetConfig; +import org.lflang.TargetPropertyConfig; +import org.lflang.ast.ASTUtils; +import org.lflang.lf.Action; +import org.lflang.lf.ActionOrigin; +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.validation.LFValidator.ValidationReporter; + +public class FastConfigurator implements TargetPropertyConfig { + + @Override + public void parseIntoTargetConfig(TargetConfig config, Element value, MessageReporter err) { + config.fastMode = this.parse(value); + } + + @Override + public Boolean parse(Element value) { + return ASTUtils.toBoolean(value); + } + + @Override + public void validate(KeyValuePair pair, Model ast, TargetConfig config, ValidationReporter 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.error( + "The fast target property is incompatible with federated programs.", + pair, + Literals.KEY_VALUE_PAIR__NAME); + break; + } + } + + // 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.error( + "The fast target property is incompatible with physical actions.", + pair, + Literals.KEY_VALUE_PAIR__NAME); + break; + } + } + } + } + + } + + @Override + public Element getPropertyElement(TargetConfig config) { + return ASTUtils.toElement(config.fastMode); + } +} diff --git a/core/src/main/java/org/lflang/target/KeepaliveConfigurator.java b/core/src/main/java/org/lflang/target/KeepaliveConfigurator.java new file mode 100644 index 0000000000..9753084e16 --- /dev/null +++ b/core/src/main/java/org/lflang/target/KeepaliveConfigurator.java @@ -0,0 +1,42 @@ +package org.lflang.target; + +import org.lflang.MessageReporter; +import org.lflang.Target; +import org.lflang.TargetConfig; +import org.lflang.TargetPropertyConfig; +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.validation.LFValidator.ValidationReporter; + +public class KeepaliveConfigurator implements TargetPropertyConfig { + + @Override + public void parseIntoTargetConfig(TargetConfig config, Element value, MessageReporter err) { + config.keepalive = this.parse(value); + } + + @Override + public Boolean parse(Element value) { + return ASTUtils.toBoolean(value); + } + + + @Override + public void validate(KeyValuePair pair, Model ast, TargetConfig config, ValidationReporter reporter) { + if (pair != null && config.target == Target.CPP) { + reporter.warning( + "The keepalive property is inferred automatically by the C++ " + + "runtime and the value given here is ignored", + pair, + Literals.KEY_VALUE_PAIR__NAME); + } + } + + @Override + public Element getPropertyElement(TargetConfig config) { + return ASTUtils.toElement(config.keepalive); + } +} diff --git a/core/src/main/java/org/lflang/target/LoggingConfigurator.java b/core/src/main/java/org/lflang/target/LoggingConfigurator.java new file mode 100644 index 0000000000..5f0b537fd8 --- /dev/null +++ b/core/src/main/java/org/lflang/target/LoggingConfigurator.java @@ -0,0 +1,23 @@ +package org.lflang.target; + +public class LoggingConfigurator { + + /** + * Log levels in descending order of severity. + * + * @author Marten Lohstroh + */ + public enum LogLevel { + ERROR, + WARN, + INFO, + LOG, + DEBUG; + + /** Return the name in lower case. */ + @Override + public String toString() { + return this.name().toLowerCase(); + } + } +} diff --git a/core/src/main/java/org/lflang/target/PlatformConfigurator.java b/core/src/main/java/org/lflang/target/PlatformConfigurator.java new file mode 100644 index 0000000000..542323efe1 --- /dev/null +++ b/core/src/main/java/org/lflang/target/PlatformConfigurator.java @@ -0,0 +1,142 @@ +package org.lflang.target; + +import org.lflang.MessageReporter; +import org.lflang.TargetConfig; +import org.lflang.TargetProperty; +import org.lflang.TargetProperty.DictionaryElement; +import org.lflang.ast.ASTUtils; +import org.lflang.lf.LfPackage.Literals; +import org.lflang.target.property.type.PrimitiveType; +import org.lflang.target.property.type.TargetPropertyType; +import org.lflang.TargetPropertyConfig; +import org.lflang.lf.Element; +import org.lflang.lf.KeyValuePair; +import org.lflang.lf.Model; +import org.lflang.target.PlatformConfigurator.PlatformOption; +import org.lflang.validation.LFValidator.ValidationReporter; + +public class PlatformConfigurator implements TargetPropertyConfig { + + @Override + public void parseIntoTargetConfig(TargetConfig config, Element value, MessageReporter err) { + + } + + @Override + public PlatformOption parse(Element value) { + return null; + } + + @Override + public void validate(KeyValuePair pair, Model ast, TargetConfig config, ValidationReporter reporter) { + var threading = TargetProperty.getKeyValuePair(ast, TargetProperty.THREADING); + if (threading != null) { + if (pair != null && ASTUtils.toBoolean(threading.getValue())) { + var lit = ASTUtils.elementToSingleString(pair.getValue()); + var dic = pair.getValue().getKeyvalue(); + if (lit != null && lit.equalsIgnoreCase(Platform.RP2040.toString())) { + reporter.error( + "Platform " + Platform.RP2040 + " does not support threading", + pair, + Literals.KEY_VALUE_PAIR__VALUE); + } + if (dic != null) { + var rp = + dic.getPairs().stream() + .filter( + kv -> + kv.getName().equalsIgnoreCase("name") + && ASTUtils.elementToSingleString(kv.getValue()) + .equalsIgnoreCase(Platform.RP2040.toString())) + .findFirst(); + if (rp.isPresent()) { + reporter.error( + "Platform " + Platform.RP2040 + " does not support threading", + rp.get(), + Literals.KEY_VALUE_PAIR__VALUE); + } + } + } + } + } + + @Override + public Element getPropertyElement(TargetConfig config) { + return null; + } + + /** Enumeration of supported platforms */ + public enum Platform { + AUTO, + ARDUINO, + NRF52("Nrf52", true), + RP2040("Rp2040", false), + LINUX("Linux", true), + MAC("Darwin", true), + ZEPHYR("Zephyr", true), + WINDOWS("Windows", true); + + String cMakeName; + + private boolean multiThreaded = true; + + Platform() { + this.cMakeName = this.toString(); + } + + Platform(String cMakeName, boolean isMultiThreaded) { + this.cMakeName = cMakeName; + this.multiThreaded = isMultiThreaded; + } + + /** Return the name in lower case. */ + @Override + public String toString() { + return this.name().toLowerCase(); + } + + /** Get the CMake name for the platform. */ + public String getcMakeName() { + return this.cMakeName; + } + + public boolean isMultiThreaded() { + return this.multiThreaded; + } + } + + /** + * Platform options. + * + * @author Anirudh Rengarajan + */ + public enum PlatformOption implements DictionaryElement { + NAME("name", PrimitiveType.STRING), + BAUDRATE("baud-rate", PrimitiveType.NON_NEGATIVE_INTEGER), + BOARD("board", PrimitiveType.STRING), + FLASH("flash", PrimitiveType.BOOLEAN), + PORT("port", PrimitiveType.STRING), + USER_THREADS("user-threads", PrimitiveType.NON_NEGATIVE_INTEGER); + + public final PrimitiveType type; + + private final String description; + + private PlatformOption(String alias, PrimitiveType type) { + this.description = alias; + this.type = type; + } + + /** Return the description of this dictionary element. */ + @Override + public String toString() { + return this.description; + } + + /** Return the type associated with this dictionary element. */ + public TargetPropertyType getType() { + return this.type; + } + } + +} diff --git a/core/src/main/java/org/lflang/target/Ros2DependenciesConfigurator.java b/core/src/main/java/org/lflang/target/Ros2DependenciesConfigurator.java new file mode 100644 index 0000000000..f1c6ac9eae --- /dev/null +++ b/core/src/main/java/org/lflang/target/Ros2DependenciesConfigurator.java @@ -0,0 +1,41 @@ +package org.lflang.target; + +import org.lflang.MessageReporter; +import org.lflang.TargetConfig; +import org.lflang.TargetProperty; +import org.lflang.TargetPropertyConfig; +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.validation.LFValidator.ValidationReporter; + +public class Ros2DependenciesConfigurator implements TargetPropertyConfig { + + @Override + public void parseIntoTargetConfig(TargetConfig config, Element value, MessageReporter err) { + + } + + @Override + public Boolean parse(Element value) { + return null; + } + + @Override + public void validate(KeyValuePair pair, Model ast, TargetConfig config, ValidationReporter reporter) { + var ros2enabled = TargetProperty.getKeyValuePair(ast, TargetProperty.ROS2); + if (pair != null && (ros2enabled == null || !ASTUtils.toBoolean(ros2enabled.getValue()))) { + reporter.warning( + "Ignoring ros2-dependencies as ros2 compilation is disabled", + pair, + Literals.KEY_VALUE_PAIR__NAME); + } + } + + @Override + public Element getPropertyElement(TargetConfig config) { + return null; + } +} diff --git a/core/src/main/java/org/lflang/target/SchedulerConfigurator.java b/core/src/main/java/org/lflang/target/SchedulerConfigurator.java new file mode 100644 index 0000000000..5bedf0494a --- /dev/null +++ b/core/src/main/java/org/lflang/target/SchedulerConfigurator.java @@ -0,0 +1,121 @@ +package org.lflang.target; + +import java.nio.file.Path; +import java.util.List; + +import org.lflang.MessageReporter; +import org.lflang.TargetConfig; +import org.lflang.TargetPropertyConfig; +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.SchedulerConfigurator.SchedulerOption; +import org.lflang.target.property.type.UnionType; +import org.lflang.validation.LFValidator.ValidationReporter; + +import com.google.common.collect.ImmutableList; + +public class SchedulerConfigurator implements TargetPropertyConfig { + + @Override + public void parseIntoTargetConfig(TargetConfig config, Element value, MessageReporter err) { + config.schedulerType = this.parse(value); + + } + + @Override + public SchedulerOption parse(Element value) { + return (SchedulerOption) + UnionType.SCHEDULER_UNION.forName(ASTUtils.elementToSingleString(value)); + } + + @Override + public void validate(KeyValuePair pair, Model ast, TargetConfig config, ValidationReporter reporter) { + if (pair != null) { + String schedulerName = ASTUtils.elementToSingleString(pair.getValue()); + try { + if (!SchedulerOption.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.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.", + pair, + Literals.KEY_VALUE_PAIR__VALUE); + } + } + } catch (IllegalArgumentException e) { + // the given scheduler is invalid, but this is already checked by + // checkTargetProperties + } + } + + } + + @Override + public Element getPropertyElement(TargetConfig config) { + return ASTUtils.toElement(config.schedulerType.toString()); + } + + /** + * Supported schedulers. + * + * @author Soroush Bateni + */ + public enum SchedulerOption { + NP(false), // Non-preemptive + ADAPTIVE( + false, + List.of( + Path.of("scheduler_adaptive.c"), + Path.of("worker_assignments.h"), + Path.of("worker_states.h"), + Path.of("data_collection.h"))), + GEDF_NP(true), // Global EDF non-preemptive + GEDF_NP_CI(true); // Global EDF non-preemptive with chain ID + // PEDF_NP(true); // Partitioned EDF non-preemptive (FIXME: To be re-added in a future PR) + + /** Indicate whether or not the scheduler prioritizes reactions by deadline. */ + private final boolean prioritizesDeadline; + + /** Relative paths to files required by this scheduler. */ + private final List relativePaths; + + SchedulerOption(boolean prioritizesDeadline) { + this(prioritizesDeadline, null); + } + + SchedulerOption(boolean prioritizesDeadline, List relativePaths) { + this.prioritizesDeadline = prioritizesDeadline; + this.relativePaths = relativePaths; + } + + /** Return true if the scheduler prioritizes reactions by deadline. */ + public boolean prioritizesDeadline() { + return this.prioritizesDeadline; + } + + public List getRelativePaths() { + return relativePaths != null + ? ImmutableList.copyOf(relativePaths) + : List.of(Path.of("scheduler_" + this + ".c")); + } + + public static SchedulerOption getDefault() { + return NP; + } + } +} diff --git a/core/src/main/java/org/lflang/target/TracingConfigurator.java b/core/src/main/java/org/lflang/target/TracingConfigurator.java new file mode 100644 index 0000000000..ef47b9ad5d --- /dev/null +++ b/core/src/main/java/org/lflang/target/TracingConfigurator.java @@ -0,0 +1,131 @@ +package org.lflang.target; + +import org.lflang.MessageReporter; +import org.lflang.TargetConfig; +import org.lflang.TargetConfig.TracingOptions; +import org.lflang.TargetProperty; +import org.lflang.TargetProperty.DictionaryElement; +import org.lflang.target.property.type.DictionaryType; +import org.lflang.target.property.type.PrimitiveType; +import org.lflang.target.property.type.TargetPropertyType; +import org.lflang.TargetPropertyConfig; +import org.lflang.ast.ASTUtils; +import org.lflang.lf.Element; +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.validation.LFValidator.ValidationReporter; + +public class TracingConfigurator implements TargetPropertyConfig { + + @Override + public void parseIntoTargetConfig(TargetConfig config, Element value, MessageReporter err) { + config.tracing = parse(value); + } + + @Override + public TracingOptions parse(Element value) { + var options = new TracingOptions(); + if (value.getLiteral() != null) { + if (ASTUtils.toBoolean(value)) { + return options; + } else { + return null; + } + } else { + for (KeyValuePair entry : value.getKeyvalue().getPairs()) { + TracingOption option = + (TracingOption) DictionaryType.TRACING_DICT.forName(entry.getName()); + switch (option) { + case TRACE_FILE_NAME: + options.traceFileName = ASTUtils.elementToSingleString(entry.getValue()); + break; + default: + break; + } + } + return options; + } + } + + @Override + public void validate(KeyValuePair pair, Model ast, TargetConfig config, ValidationReporter reporter) { + if (pair != null && this.parse(pair.getValue()) != null) { + // If tracing is anything but "false" and threading is off, error. + var threading = TargetProperty.getKeyValuePair(ast, TargetProperty.THREADING); + if (threading != null) { + if (!ASTUtils.toBoolean(threading.getValue())) { + reporter.error( + "Cannot enable tracing because threading support is disabled", + pair, + Literals.KEY_VALUE_PAIR__NAME); + reporter.error( + "Cannot disable treading support because tracing is enabled", + threading, + Literals.KEY_VALUE_PAIR__NAME); + } + } + } + } + + @Override + public Element getPropertyElement(TargetConfig config) { + if (config.tracing == null) { + return null; + } else if (config.tracing.equals(new TracingOptions())) { + // default values + return ASTUtils.toElement(true); + } else { + Element e = LfFactory.eINSTANCE.createElement(); + KeyValuePairs kvp = LfFactory.eINSTANCE.createKeyValuePairs(); + for (TracingOption opt : TracingOption.values()) { + KeyValuePair pair = LfFactory.eINSTANCE.createKeyValuePair(); + pair.setName(opt.toString()); + switch (opt) { + case TRACE_FILE_NAME: + if (config.tracing.traceFileName == null) { + continue; + } + pair.setValue(ASTUtils.toElement(config.tracing.traceFileName)); + } + kvp.getPairs().add(pair); + } + e.setKeyvalue(kvp); + if (kvp.getPairs().isEmpty()) { + return null; + } + return e; + } + } + + /** + * Tracing options. + * + * @author Edward A. Lee + */ + public enum TracingOption implements DictionaryElement { + TRACE_FILE_NAME("trace-file-name", PrimitiveType.STRING); + + public final PrimitiveType type; + + private final String description; + + private TracingOption(String alias, PrimitiveType type) { + this.description = alias; + this.type = type; + } + + /** Return the description of this dictionary element. */ + @Override + public String toString() { + return this.description; + } + + /** Return the type associated with this dictionary element. */ + public TargetPropertyType getType() { + return this.type; + } + } +} diff --git a/core/src/main/java/org/lflang/target/property/BuildConfig.java b/core/src/main/java/org/lflang/target/property/BuildConfig.java new file mode 100644 index 0000000000..e9af8402c9 --- /dev/null +++ b/core/src/main/java/org/lflang/target/property/BuildConfig.java @@ -0,0 +1,32 @@ +package org.lflang.target.property; + +public class BuildConfig { + + /** + * Enumeration of Cmake build types. These are also mapped to Cargo profiles for the Rust target + * (see {@link org.lflang.generator.rust.RustTargetConfig}) + * + * @author Christian Menard + */ + public enum BuildType { + RELEASE("Release"), + DEBUG("Debug"), + TEST("Test"), + REL_WITH_DEB_INFO("RelWithDebInfo"), + MIN_SIZE_REL("MinSizeRel"); + + /** Alias used in toString method. */ + private final String alias; + + /** Private constructor for Cmake build types. */ + BuildType(String alias) { + this.alias = alias; + } + + /** Return the alias. */ + @Override + public String toString() { + return this.alias; + } + } +} diff --git a/core/src/main/java/org/lflang/target/property/type/ArrayType.java b/core/src/main/java/org/lflang/target/property/type/ArrayType.java new file mode 100644 index 0000000000..8b6621535a --- /dev/null +++ b/core/src/main/java/org/lflang/target/property/type/ArrayType.java @@ -0,0 +1,61 @@ +package org.lflang.target.property.type; + +import java.util.List; + +import org.lflang.lf.Array; +import org.lflang.lf.Element; +import org.lflang.validation.LFValidator; + +/** + * An array type of which the elements confirm to a given type. + * + * @author Marten Lohstroh + */ +public enum ArrayType implements TargetPropertyType { + STRING_ARRAY(PrimitiveType.STRING), + FILE_ARRAY(PrimitiveType.FILE); + + /** Type parameter of this array type. */ + public TargetPropertyType type; + + /** + * Private constructor to create a new array type. + * + * @param type The type of elements in the array. + */ + private ArrayType(TargetPropertyType type) { + this.type = type; + } + + /** + * Check that the passed in element represents an array and ensure that its elements are all of + * the correct type. + */ + @Override + public void check(Element e, String name, LFValidator v) { + Array array = e.getArray(); + if (array == null) { + TargetPropertyType.produceError(name, this.toString(), v); + } else { + List elements = array.getElements(); + for (int i = 0; i < elements.size(); i++) { + this.type.check(elements.get(i), name + "[" + i + "]", v); + } + } + } + + /** Return true of the given element is an array. */ + @Override + public boolean validate(Element e) { + if (e.getArray() != null) { + return true; + } + return false; + } + + /** Return a human-readable description of this type. */ + @Override + public String toString() { + return "an array of which each element is " + this.type.toString(); + } +} \ No newline at end of file diff --git a/core/src/main/java/org/lflang/target/property/type/DictionaryType.java b/core/src/main/java/org/lflang/target/property/type/DictionaryType.java new file mode 100644 index 0000000000..e26d2ba122 --- /dev/null +++ b/core/src/main/java/org/lflang/target/property/type/DictionaryType.java @@ -0,0 +1,95 @@ +package org.lflang.target.property.type; + +import java.util.Arrays; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +import org.lflang.Target; +import org.lflang.TargetProperty.DictionaryElement; +import org.lflang.lf.Element; +import org.lflang.lf.KeyValuePair; +import org.lflang.lf.KeyValuePairs; +import org.lflang.target.ClockSyncConfigurator.ClockSyncOption; +import org.lflang.target.CoordinationConfig.CoordinationOption; +import org.lflang.target.DockerConfig.DockerOption; +import org.lflang.target.PlatformConfigurator.PlatformOption; +import org.lflang.target.TracingConfigurator.TracingOption; +import org.lflang.validation.LFValidator; + +/** + * A dictionary type with a predefined set of possible keys and assignable types. + * + * @author Marten Lohstroh + */ +public enum DictionaryType implements TargetPropertyType { + CLOCK_SYNC_OPTION_DICT(Arrays.asList(ClockSyncOption.values())), + DOCKER_DICT(Arrays.asList(DockerOption.values())), + PLATFORM_DICT(Arrays.asList(PlatformOption.values())), + COORDINATION_OPTION_DICT(Arrays.asList(CoordinationOption.values())), + TRACING_DICT(Arrays.asList(TracingOption.values())); + + /** The keys and assignable types that are allowed in this dictionary. */ + public List options; + + /** + * A dictionary type restricted to sets of predefined keys and types of values. + * + * @param options The dictionary elements allowed by this type. + */ + private DictionaryType(List options) { + this.options = options; + } + + /** + * Return the dictionary element of which the key matches the given string. + * + * @param name The string to match against. + * @return The matching dictionary element (or null if there is none). + */ + public DictionaryElement forName(String name) { + return Target.match(name, options); + } + + /** Recursively check that the passed in element conforms to the rules of this dictionary. */ + @Override + public void check(Element e, String name, LFValidator v) { + KeyValuePairs kv = e.getKeyvalue(); + if (kv == null) { + TargetPropertyType.produceError(name, this.toString(), v); + } else { + for (KeyValuePair pair : kv.getPairs()) { + String key = pair.getName(); + Element val = pair.getValue(); + Optional match = + this.options.stream() + .filter(element -> key.equalsIgnoreCase(element.toString())) + .findAny(); + if (match.isPresent()) { + // Make sure the type is correct, too. + TargetPropertyType type = match.get().getType(); + type.check(val, name + "." + key, v); + } else { + // No match found; report error. + TargetPropertyType.produceError(name, this.toString(), v); + } + } + } + } + + /** Return true if the given element represents a dictionary, false otherwise. */ + @Override + public boolean validate(Element e) { + if (e.getKeyvalue() != null) { + return true; + } + return false; + } + + /** Return a human-readable description of this type. */ + @Override + public String toString() { + return "a dictionary with one or more of the following keys: " + + options.stream().map(option -> option.toString()).collect(Collectors.joining(", ")); + } +} \ No newline at end of file diff --git a/core/src/main/java/org/lflang/target/property/type/PrimitiveType.java b/core/src/main/java/org/lflang/target/property/type/PrimitiveType.java new file mode 100644 index 0000000000..0e3a6a5be3 --- /dev/null +++ b/core/src/main/java/org/lflang/target/property/type/PrimitiveType.java @@ -0,0 +1,114 @@ +package org.lflang.target.property.type; + +import java.util.function.Predicate; + +import org.lflang.ast.ASTUtils; +import org.lflang.lf.Element; +import org.lflang.validation.LFValidator; + +/** + * Primitive types for target properties, each with a description used in error messages and + * predicate used for validating values. + * + * @author Marten Lohstroh + */ +public enum PrimitiveType implements TargetPropertyType { + BOOLEAN( + "'true' or 'false'", + v -> + ASTUtils.elementToSingleString(v).equalsIgnoreCase("true") + || ASTUtils.elementToSingleString(v).equalsIgnoreCase("false")), + INTEGER( + "an integer", + v -> { + try { + Integer.parseInt(ASTUtils.elementToSingleString(v)); + } catch (NumberFormatException e) { + return false; + } + return true; + }), + NON_NEGATIVE_INTEGER( + "a non-negative integer", + v -> { + try { + int result = Integer.parseInt(ASTUtils.elementToSingleString(v)); + if (result < 0) return false; + } catch (NumberFormatException e) { + return false; + } + return true; + }), + TIME_VALUE( + "a time value with units", + v -> + v.getKeyvalue() == null + && v.getArray() == null + && v.getLiteral() == null + && v.getId() == null + && (v.getTime() == 0 || v.getUnit() != null)), + STRING( + "a string", + v -> v.getLiteral() != null && !isCharLiteral(v.getLiteral()) || v.getId() != null), + FILE("a path to a file", STRING.validator); + + /** A description of this type, featured in error messages. */ + private final String description; + + /** A predicate for determining whether a given Element conforms to this type. */ + public final Predicate validator; + + /** + * Private constructor to create a new primitive type. + * + * @param description A textual description of the type that should start with "a/an". + * @param validator A predicate that returns true if a given Element conforms to this type. + */ + private PrimitiveType(String description, Predicate validator) { + this.description = description; + this.validator = validator; + } + + /** Return true if the the given Element is a valid instance of this type. */ + public boolean validate(Element e) { + return this.validator.test(e); + } + + /** + * Check (recursively) the given Element against its associated type(s) and add found problems + * to the given list of errors. + * + * @param e The element to type check. + * @param name The name of the target property. + * @param v The LFValidator to append errors to. + */ + public void check(Element e, String name, LFValidator v) { + if (!this.validate(e)) { + TargetPropertyType.produceError(name, this.description, v); + } + // If this is a file, perform an additional check to make sure + // the file actually exists. + // FIXME: premature because we first need a mechanism for looking up files! + // Looking in the same directory is too restrictive. Disabling this check for now. + /* + if (this == FILE) { + String file = ASTUtils.toSingleString(e); + + if (!FileConfig.fileExists(file, FileConfig.toPath(e.eResource().getURI()).toFile().getParent())) { + v.targetPropertyWarnings + .add("Could not find file: '" + file + "'."); + } + } + */ + } + + /** Return a textual description of this type. */ + @Override + public String toString() { + return this.description; + } + + private static boolean isCharLiteral(String s) { + return s.length() > 2 && '\'' == s.charAt(0) && '\'' == s.charAt(s.length() - 1); + } +} diff --git a/core/src/main/java/org/lflang/target/property/type/StringDictionaryType.java b/core/src/main/java/org/lflang/target/property/type/StringDictionaryType.java new file mode 100644 index 0000000000..cec3a7f9df --- /dev/null +++ b/core/src/main/java/org/lflang/target/property/type/StringDictionaryType.java @@ -0,0 +1,35 @@ +package org.lflang.target.property.type; + +import org.lflang.lf.Element; +import org.lflang.lf.KeyValuePair; +import org.lflang.lf.KeyValuePairs; +import org.lflang.validation.LFValidator; + +/** Dictionary type that allows for keys that will be interpreted as strings and string values. */ +public enum StringDictionaryType implements TargetPropertyType { + COMPILE_DEFINITION(); + + @Override + public boolean validate(Element e) { + if (e.getKeyvalue() != null) { + return true; + } + return false; + } + + @Override + public void check(Element e, String name, LFValidator v) { + KeyValuePairs kv = e.getKeyvalue(); + if (kv == null) { + TargetPropertyType.produceError(name, this.toString(), v); + } else { + for (KeyValuePair pair : kv.getPairs()) { + String key = pair.getName(); + Element val = pair.getValue(); + + // Make sure the type is string + PrimitiveType.STRING.check(val, name + "." + key, v); + } + } + } +} \ No newline at end of file diff --git a/core/src/main/java/org/lflang/target/property/type/TargetPropertyType.java b/core/src/main/java/org/lflang/target/property/type/TargetPropertyType.java new file mode 100644 index 0000000000..390d4aa1e7 --- /dev/null +++ b/core/src/main/java/org/lflang/target/property/type/TargetPropertyType.java @@ -0,0 +1,48 @@ +package org.lflang.target.property.type; + +import java.util.function.Predicate; + +import org.lflang.ast.ASTUtils; +import org.lflang.lf.Element; +import org.lflang.validation.LFValidator; + +/** + * An interface for types associated with target properties. + * + * @author Marten Lohstroh + */ +public interface TargetPropertyType { + + /** + * Return true if the the given Element is a valid instance of this type. + * + * @param e The Element to validate. + * @return True if the element conforms to this type, false otherwise. + */ + public boolean validate(Element e); + + /** + * Check (recursively) the given Element against its associated type(s) and add found problems + * to the given list of errors. + * + * @param e The Element to type check. + * @param name The name of the target property. + * @param v A reference to the validator to report errors to. + */ + public void check(Element e, String name, LFValidator v); + + /** + * Helper function to produce an error during type checking. + * + * @param name The description of the target property. + * @param description The description of the type. + * @param v A reference to the validator to report errors to. + */ + public static void produceError(String name, String description, LFValidator v) { + + v.reportTargetPropertyError( + "Target property '" + name + "' is required to be " + description + "."); + } +} + + diff --git a/core/src/main/java/org/lflang/target/property/type/UnionType.java b/core/src/main/java/org/lflang/target/property/type/UnionType.java new file mode 100644 index 0000000000..51ef4debb4 --- /dev/null +++ b/core/src/main/java/org/lflang/target/property/type/UnionType.java @@ -0,0 +1,137 @@ +package org.lflang.target.property.type; + +import java.util.Arrays; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +import org.lflang.Target; +import org.lflang.ast.ASTUtils; +import org.lflang.lf.Element; +import org.lflang.target.ClockSyncConfigurator.ClockSyncMode; +import org.lflang.target.CoordinationConfig.CoordinationType; +import org.lflang.target.LoggingConfigurator.LogLevel; +import org.lflang.target.PlatformConfigurator.Platform; +import org.lflang.target.SchedulerConfigurator.SchedulerOption; +import org.lflang.target.property.BuildConfig.BuildType; +import org.lflang.validation.LFValidator; + +/** + * A type that can assume one of several types. + * + * @author Marten Lohstroh + */ +public enum UnionType implements TargetPropertyType { + STRING_OR_STRING_ARRAY(Arrays.asList(PrimitiveType.STRING, ArrayType.STRING_ARRAY), null), + PLATFORM_STRING_OR_DICTIONARY( + Arrays.asList(PrimitiveType.STRING, DictionaryType.PLATFORM_DICT), null), + FILE_OR_FILE_ARRAY(Arrays.asList(PrimitiveType.FILE, ArrayType.FILE_ARRAY), null), + BUILD_TYPE_UNION(Arrays.asList(BuildType.values()), null), + COORDINATION_UNION(Arrays.asList(CoordinationType.values()), CoordinationType.CENTRALIZED), + SCHEDULER_UNION(Arrays.asList(SchedulerOption.values()), SchedulerOption.getDefault()), + LOGGING_UNION(Arrays.asList(LogLevel.values()), LogLevel.INFO), + PLATFORM_UNION(Arrays.asList(Platform.values()), Platform.AUTO), + CLOCK_SYNC_UNION(Arrays.asList(ClockSyncMode.values()), ClockSyncMode.INIT), + DOCKER_UNION(Arrays.asList(PrimitiveType.BOOLEAN, DictionaryType.DOCKER_DICT), null), + TRACING_UNION(Arrays.asList(PrimitiveType.BOOLEAN, DictionaryType.TRACING_DICT), null); + + /** The constituents of this type union. */ + public final List> options; + + /** The default type, if there is one. */ + private final Enum defaultOption; + + /** + * Private constructor for creating unions types. + * + * @param options The types that that are part of the union. + * @param defaultOption The default type. + */ + private UnionType(List> options, Enum defaultOption) { + this.options = options; + this.defaultOption = defaultOption; + } + + /** + * Return the type among those in this type union that matches the given name. + * + * @param name The string to match against. + * @return The matching dictionary element (or null if there is none). + */ + public Enum forName(String name) { + return Target.match(name, options); + } + + /** Recursively check that the passed in element conforms to the rules of this union. */ + @Override + public void check(Element e, String name, LFValidator v) { + Optional> match = this.match(e); + if (match.isPresent()) { + // Go deeper if the element is an array or dictionary. + Enum type = match.get(); + if (type instanceof DictionaryType) { + ((DictionaryType) type).check(e, name, v); + } else if (type instanceof ArrayType) { + ((ArrayType) type).check(e, name, v); + } else if (type instanceof PrimitiveType) { + ((PrimitiveType) type).check(e, name, v); + } else if (!(type instanceof Enum)) { + throw new RuntimeException("Encountered an unknown type."); + } + } else { + // No match found; report error. + TargetPropertyType.produceError(name, this.toString(), v); + } + } + + /** + * Internal method for matching a given element against the allowable types. + * + * @param e AST node that represents the value of a target property. + * @return The matching type wrapped in an Optional object. + */ + private Optional> match(Element e) { + return this.options.stream() + .filter( + option -> { + if (option instanceof TargetPropertyType) { + return ((TargetPropertyType) option).validate(e); + } else { + return ASTUtils.elementToSingleString(e).equalsIgnoreCase(option.toString()); + } + }) + .findAny(); + } + + /** + * Return true if this union has an option that matches the given element. + * + * @param e The element to match against this type. + */ + @Override + public boolean validate(Element e) { + if (this.match(e).isPresent()) { + return true; + } + return false; + } + + /** + * Return a human-readable description of this type. If three is a default option, then indicate + * it. + */ + @Override + public String toString() { + return "one of the following: " + + options.stream() + .map( + option -> { + if (option == this.defaultOption) { + return option.toString() + " (default)"; + } else { + return option.toString(); + } + }) + .collect(Collectors.joining(", ")); + } +} \ No newline at end of file diff --git a/core/src/main/java/org/lflang/validation/LFValidator.java b/core/src/main/java/org/lflang/validation/LFValidator.java index 7dcf00d107..dddb837917 100644 --- a/core/src/main/java/org/lflang/validation/LFValidator.java +++ b/core/src/main/java/org/lflang/validation/LFValidator.java @@ -59,8 +59,8 @@ import org.lflang.InferredType; import org.lflang.ModelInfo; import org.lflang.Target; +import org.lflang.TargetConfig; import org.lflang.TargetProperty; -import org.lflang.TargetProperty.Platform; import org.lflang.TimeValue; import org.lflang.ast.ASTUtils; import org.lflang.federated.serialization.SupportedSerializers; @@ -132,6 +132,8 @@ */ public class LFValidator extends BaseLFValidator { + private TargetConfig targetConfig; + // The methods annotated with @Check are automatically invoked on AST nodes matching the types of // their arguments. CheckType.FAST ensures that these checks run whenever a file is modified; // when CheckType.NORMAL is used, the check is run upon saving. @@ -1100,12 +1102,14 @@ public void checkTargetDecl(TargetDecl target) throws IOException { if (targetOpt.isEmpty()) { error("Unrecognized target: " + target.getName(), Literals.TARGET_DECL__NAME); } else { - this.target = targetOpt.get(); + this.target = targetOpt.get(); // FIXME: remove + this.targetConfig = new TargetConfig(target); } String lfFileName = FileUtil.nameWithoutExtension(target.eResource()); if (Character.isDigit(lfFileName.charAt(0))) { errorReporter.nowhere().error("LF file names must not start with a number"); } + } /** @@ -1115,12 +1119,20 @@ public void checkTargetDecl(TargetDecl target) throws IOException { */ @Check(CheckType.NORMAL) public void checkTargetProperties(KeyValuePairs targetProperties) { - validateFastTargetProperty(targetProperties); - validateClockSyncTargetProperties(targetProperties); - validateSchedulerTargetProperties(targetProperties); - validateRos2TargetProperties(targetProperties); - validateKeepalive(targetProperties); - validateThreading(targetProperties); + Arrays.stream(TargetProperty.values()).forEach(p -> { + p.validate(targetProperties, this.info.model, this.targetConfig, + new ValidationReporter() { + @Override + public void error(String message, EObject source, EStructuralFeature feature) { + error(message, source, feature); + } + + @Override + public void warning(String message, EObject source, EStructuralFeature feature) { + warning(message, source, feature); + } + }); + }); } private KeyValuePair getKeyValuePair(KeyValuePairs targetProperties, TargetProperty property) { @@ -1132,162 +1144,6 @@ private KeyValuePair getKeyValuePair(KeyValuePairs targetProperties, TargetPrope return properties.size() > 0 ? properties.get(0) : null; } - private void validateFastTargetProperty(KeyValuePairs targetProperties) { - KeyValuePair fastTargetProperty = getKeyValuePair(targetProperties, TargetProperty.FAST); - - if (fastTargetProperty != null) { - // Check for federated - for (Reactor reactor : info.model.getReactors()) { - // Check to see if the program has a federated reactor - if (reactor.isFederated()) { - error( - "The fast target property is incompatible with federated programs.", - fastTargetProperty, - Literals.KEY_VALUE_PAIR__NAME); - break; - } - } - - // Check for physical actions - for (Reactor reactor : info.model.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)) { - error( - "The fast target property is incompatible with physical actions.", - fastTargetProperty, - Literals.KEY_VALUE_PAIR__NAME); - break; - } - } - } - } - } - - private void validateClockSyncTargetProperties(KeyValuePairs targetProperties) { - KeyValuePair clockSyncTargetProperty = - getKeyValuePair(targetProperties, TargetProperty.CLOCK_SYNC); - - if (clockSyncTargetProperty != null) { - boolean federatedExists = false; - for (Reactor reactor : info.model.getReactors()) { - if (reactor.isFederated()) { - federatedExists = true; - } - } - if (!federatedExists) { - warning( - "The clock-sync target property is incompatible with non-federated programs.", - clockSyncTargetProperty, - Literals.KEY_VALUE_PAIR__NAME); - } - } - } - - private void validateSchedulerTargetProperties(KeyValuePairs targetProperties) { - KeyValuePair schedulerTargetProperty = - getKeyValuePair(targetProperties, TargetProperty.SCHEDULER); - if (schedulerTargetProperty != null) { - String schedulerName = ASTUtils.elementToSingleString(schedulerTargetProperty.getValue()); - try { - if (!TargetProperty.SchedulerOption.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 (info.model.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))) { - 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.", - schedulerTargetProperty, - Literals.KEY_VALUE_PAIR__VALUE); - } - } - } catch (IllegalArgumentException e) { - // the given scheduler is invalid, but this is already checked by - // checkTargetProperties - } - } - } - - private void validateKeepalive(KeyValuePairs targetProperties) { - KeyValuePair keepalive = getKeyValuePair(targetProperties, TargetProperty.KEEPALIVE); - if (keepalive != null && target == Target.CPP) { - warning( - "The keepalive property is inferred automatically by the C++ " - + "runtime and the value given here is ignored", - keepalive, - Literals.KEY_VALUE_PAIR__NAME); - } - } - - private void validateThreading(KeyValuePairs targetProperties) { - var threadingP = getKeyValuePair(targetProperties, TargetProperty.THREADING); - var tracingP = getKeyValuePair(targetProperties, TargetProperty.TRACING); - var platformP = getKeyValuePair(targetProperties, TargetProperty.PLATFORM); - if (threadingP != null) { - if (tracingP != null) { - if (!ASTUtils.toBoolean(threadingP.getValue()) - && !tracingP.getValue().toString().equalsIgnoreCase("false")) { - error( - "Cannot disable treading support because tracing is enabled", - threadingP, - Literals.KEY_VALUE_PAIR__NAME); - error( - "Cannot enable tracing because threading support is disabled", - tracingP, - Literals.KEY_VALUE_PAIR__NAME); - } - } - if (platformP != null && ASTUtils.toBoolean(threadingP.getValue())) { - var lit = ASTUtils.elementToSingleString(platformP.getValue()); - var dic = platformP.getValue().getKeyvalue(); - if (lit != null && lit.equalsIgnoreCase(Platform.RP2040.toString())) { - error( - "Platform " + Platform.RP2040 + " does not support threading", - platformP, - Literals.KEY_VALUE_PAIR__VALUE); - } - if (dic != null) { - var rp = - dic.getPairs().stream() - .filter( - kv -> - kv.getName().equalsIgnoreCase("name") - && ASTUtils.elementToSingleString(kv.getValue()) - .equalsIgnoreCase(Platform.RP2040.toString())) - .findFirst(); - if (rp.isPresent()) { - error( - "Platform " + Platform.RP2040 + " does not support threading", - rp.get(), - Literals.KEY_VALUE_PAIR__VALUE); - } - } - } - } - } - - private void validateRos2TargetProperties(KeyValuePairs targetProperties) { - KeyValuePair ros2 = getKeyValuePair(targetProperties, TargetProperty.ROS2); - KeyValuePair ros2Dependencies = - getKeyValuePair(targetProperties, TargetProperty.ROS2_DEPENDENCIES); - if (ros2Dependencies != null && (ros2 == null || !ASTUtils.toBoolean(ros2.getValue()))) { - warning( - "Ignoring ros2-dependencies as ros2 compilation is disabled", - ros2Dependencies, - Literals.KEY_VALUE_PAIR__NAME); - } - } - @Check(CheckType.FAST) public void checkTimer(Timer timer) { checkName(timer.getName(), Literals.VARIABLE__NAME); diff --git a/core/src/main/java/org/lflang/validation/ValidationReporter.java b/core/src/main/java/org/lflang/validation/ValidationReporter.java new file mode 100644 index 0000000000..ddd25754e3 --- /dev/null +++ b/core/src/main/java/org/lflang/validation/ValidationReporter.java @@ -0,0 +1,10 @@ +package org.lflang.validation; + +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.EStructuralFeature; + +public interface ValidationReporter { + void error(String message, EObject source, EStructuralFeature feature); + + void warning(String message, EObject source, EStructuralFeature feature); +} \ No newline at end of file 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 347bf8c78d..628d8cef4b 100644 --- a/core/src/test/java/org/lflang/tests/compiler/LinguaFrancaValidationTest.java +++ b/core/src/test/java/org/lflang/tests/compiler/LinguaFrancaValidationTest.java @@ -46,17 +46,17 @@ import org.junit.jupiter.api.extension.ExtendWith; import org.lflang.Target; import org.lflang.TargetProperty; -import org.lflang.TargetProperty.ArrayType; +import org.lflang.target.property.type.ArrayType; import org.lflang.TargetProperty.DictionaryElement; -import org.lflang.TargetProperty.DictionaryType; -import org.lflang.TargetProperty.PrimitiveType; -import org.lflang.TargetProperty.StringDictionaryType; -import org.lflang.TargetProperty.TargetPropertyType; -import org.lflang.TargetProperty.UnionType; import org.lflang.TimeValue; import org.lflang.lf.LfPackage; import org.lflang.lf.Model; import org.lflang.lf.Visibility; +import org.lflang.target.property.type.DictionaryType; +import org.lflang.target.property.type.StringDictionaryType; +import org.lflang.target.property.type.TargetPropertyType; +import org.lflang.target.property.type.PrimitiveType; +import org.lflang.target.property.type.UnionType; import org.lflang.tests.LFInjectorProvider; import org.lflang.util.StringUtil; diff --git a/core/src/testFixtures/java/org/lflang/tests/Configurators.java b/core/src/testFixtures/java/org/lflang/tests/Configurators.java index 4191687278..12e83dadac 100644 --- a/core/src/testFixtures/java/org/lflang/tests/Configurators.java +++ b/core/src/testFixtures/java/org/lflang/tests/Configurators.java @@ -25,8 +25,8 @@ package org.lflang.tests; import org.lflang.TargetProperty; -import org.lflang.TargetProperty.LogLevel; -import org.lflang.TargetProperty.Platform; +import org.lflang.target.LoggingConfigurator.LogLevel; +import org.lflang.target.PlatformConfigurator.Platform; import org.lflang.tests.TestRegistry.TestCategory; /** From 092d9ffc22bbcc7779bf28071801e6d71d324b4a Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Sat, 16 Sep 2023 01:14:39 -0700 Subject: [PATCH 002/145] More work in progress --- .../lflang/tests/runtime/CSchedulerTest.java | 2 +- .../main/java/org/lflang/TargetConfig.java | 211 ++-------- .../main/java/org/lflang/TargetProperty.java | 363 +++--------------- .../java/org/lflang/TargetPropertyConfig.java | 49 ++- .../federated/extensions/CExtension.java | 26 +- .../federated/extensions/CExtensionUtils.java | 20 +- .../extensions/FedTargetExtension.java | 10 +- .../federated/extensions/PythonExtension.java | 10 +- .../federated/extensions/TSExtension.java | 10 +- .../federated/generator/FedASTUtils.java | 20 +- .../federated/generator/FedGenerator.java | 8 +- .../launcher/FedLauncherGenerator.java | 16 +- .../org/lflang/generator/GeneratorUtils.java | 4 +- .../lflang/generator/c/CCmakeGenerator.java | 32 +- .../org/lflang/generator/c/CCompiler.java | 18 +- .../lflang/generator/c/CDockerGenerator.java | 8 +- .../c/CEnvironmentFunctionGenerator.java | 9 +- .../org/lflang/generator/c/CGenerator.java | 50 +-- .../generator/c/CMainFunctionGenerator.java | 14 +- .../generator/c/CPreambleGenerator.java | 8 +- .../java/org/lflang/generator/c/CUtil.java | 2 +- .../generator/rust/RustTargetConfig.java | 12 +- .../java/org/lflang/target/AuthConfig.java | 24 ++ .../org/lflang/target/AuthConfigurator.java | 33 -- .../lflang/target/ClockSyncConfigurator.java | 115 ------ .../lflang/target/ClockSyncModeConfig.java | 83 ++++ .../org/lflang/target/CoordinationConfig.java | 83 ---- .../lflang/target/CoordinationModeConfig.java | 49 +++ .../target/CoordinationOptionsConfig.java | 118 ++++++ .../java/org/lflang/target/DockerConfig.java | 114 +++++- ...tConfigurator.java => FastModeConfig.java} | 14 +- ...Configurator.java => KeepaliveConfig.java} | 26 +- .../org/lflang/target/PlatformConfig.java | 253 ++++++++++++ .../lflang/target/PlatformConfigurator.java | 142 ------- ...rator.java => Ros2DependenciesConfig.java} | 20 +- ...Configurator.java => SchedulerConfig.java} | 42 +- ...ngConfigurator.java => TracingConfig.java} | 63 ++- .../target/property/BuildCommandsConfig.java | 27 ++ .../target/property/BuildTypeConfig.java | 38 ++ .../property/ClockSyncOptionsConfig.java | 157 ++++++++ .../target/property/type/DictionaryType.java | 8 +- .../target/property/type/UnionType.java | 10 +- .../java/org/lflang/util/ArduinoUtil.java | 14 +- .../org/lflang/generator/cpp/CppExtensions.kt | 17 +- .../generator/cpp/CppPlatformGenerator.kt | 2 +- .../generator/cpp/CppRos2PackageGenerator.kt | 2 +- .../cpp/CppStandaloneCmakeGenerator.kt | 2 +- .../generator/cpp/CppStandaloneGenerator.kt | 10 +- .../generator/rust/RustCargoTomlEmitter.kt | 2 +- .../lflang/generator/rust/RustGenerator.kt | 6 +- .../org/lflang/generator/rust/RustModel.kt | 4 +- .../generator/ts/TSConstructorGenerator.kt | 3 +- .../java/org/lflang/tests/Configurators.java | 14 +- 53 files changed, 1285 insertions(+), 1112 deletions(-) create mode 100644 core/src/main/java/org/lflang/target/AuthConfig.java delete mode 100644 core/src/main/java/org/lflang/target/AuthConfigurator.java delete mode 100644 core/src/main/java/org/lflang/target/ClockSyncConfigurator.java create mode 100644 core/src/main/java/org/lflang/target/ClockSyncModeConfig.java delete mode 100644 core/src/main/java/org/lflang/target/CoordinationConfig.java create mode 100644 core/src/main/java/org/lflang/target/CoordinationModeConfig.java create mode 100644 core/src/main/java/org/lflang/target/CoordinationOptionsConfig.java rename core/src/main/java/org/lflang/target/{FastConfigurator.java => FastModeConfig.java} (80%) rename core/src/main/java/org/lflang/target/{KeepaliveConfigurator.java => KeepaliveConfig.java} (58%) create mode 100644 core/src/main/java/org/lflang/target/PlatformConfig.java delete mode 100644 core/src/main/java/org/lflang/target/PlatformConfigurator.java rename core/src/main/java/org/lflang/target/{Ros2DependenciesConfigurator.java => Ros2DependenciesConfig.java} (69%) rename core/src/main/java/org/lflang/target/{SchedulerConfigurator.java => SchedulerConfig.java} (79%) rename core/src/main/java/org/lflang/target/{TracingConfigurator.java => TracingConfig.java} (72%) create mode 100644 core/src/main/java/org/lflang/target/property/BuildCommandsConfig.java create mode 100644 core/src/main/java/org/lflang/target/property/BuildTypeConfig.java create mode 100644 core/src/main/java/org/lflang/target/property/ClockSyncOptionsConfig.java diff --git a/core/src/integrationTest/java/org/lflang/tests/runtime/CSchedulerTest.java b/core/src/integrationTest/java/org/lflang/tests/runtime/CSchedulerTest.java index c064560ead..f6032227f8 100644 --- a/core/src/integrationTest/java/org/lflang/tests/runtime/CSchedulerTest.java +++ b/core/src/integrationTest/java/org/lflang/tests/runtime/CSchedulerTest.java @@ -3,7 +3,7 @@ import java.util.EnumSet; import org.junit.jupiter.api.Test; import org.lflang.Target; -import org.lflang.target.SchedulerConfigurator.SchedulerOption; +import org.lflang.target.SchedulerConfig.SchedulerOption; import org.lflang.tests.Configurators; import org.lflang.tests.TestBase; import org.lflang.tests.TestRegistry.TestCategory; diff --git a/core/src/main/java/org/lflang/TargetConfig.java b/core/src/main/java/org/lflang/TargetConfig.java index 2e7ee40005..ffd2c426b3 100644 --- a/core/src/main/java/org/lflang/TargetConfig.java +++ b/core/src/main/java/org/lflang/TargetConfig.java @@ -29,20 +29,28 @@ import java.util.HashSet; import java.util.List; import java.util.Map; -import java.util.Objects; import java.util.Properties; import java.util.Set; import org.lflang.generator.LFGeneratorContext.BuildParm; import org.lflang.generator.rust.RustTargetConfig; import org.lflang.lf.KeyValuePair; import org.lflang.lf.TargetDecl; -import org.lflang.target.property.BuildConfig.BuildType; -import org.lflang.target.ClockSyncConfigurator.ClockSyncMode; -import org.lflang.target.CoordinationConfig.CoordinationType; +import org.lflang.target.AuthConfig; +import org.lflang.target.ClockSyncModeConfig; +import org.lflang.target.CoordinationModeConfig; +import org.lflang.target.CoordinationOptionsConfig; +import org.lflang.target.DockerConfig; +import org.lflang.target.FastModeConfig; +import org.lflang.target.KeepaliveConfig; +import org.lflang.target.PlatformConfig; +import org.lflang.target.SchedulerConfig; +import org.lflang.target.TracingConfig; +import org.lflang.target.TracingConfig.TracingOptions; +import org.lflang.target.property.BuildCommandsConfig; import org.lflang.target.LoggingConfigurator.LogLevel; -import org.lflang.target.PlatformConfigurator.Platform; -import org.lflang.target.SchedulerConfigurator.SchedulerOption; -import org.lflang.target.property.type.UnionType; +import org.lflang.target.SchedulerConfig.SchedulerOption; +import org.lflang.target.property.ClockSyncOptionsConfig; +import org.lflang.target.property.BuildTypeConfig; /** * A class for keeping the current target configuration. @@ -79,26 +87,18 @@ public TargetConfig(Properties cliArgs, TargetDecl target, MessageReporter messa List pairs = target.getConfig().getPairs(); TargetProperty.set(this, pairs != null ? pairs : List.of(), messageReporter); } + + if (cliArgs != null) { + TargetProperty.override(this, cliArgs, messageReporter); + } + if (cliArgs.containsKey("no-compile")) { this.noCompile = true; } if (cliArgs.containsKey("verify")) { this.verify = true; } - if (cliArgs.containsKey("docker")) { - var arg = cliArgs.getProperty("docker"); - if (Boolean.parseBoolean(arg)) { - this.dockerOptions = new DockerOptions(); - } else { - this.dockerOptions = null; - } - // FIXME: this is pretty ad-hoc and does not account for more complex overrides yet. - } - if (cliArgs.containsKey("build-type")) { - this.cmakeBuildType = - (BuildType) UnionType.BUILD_TYPE_UNION.forName(cliArgs.getProperty("build-type")); - this.setByUser.add(TargetProperty.BUILD_TYPE); - } + if (cliArgs.containsKey("logging")) { this.logLevel = LogLevel.valueOf(cliArgs.getProperty("logging").toUpperCase()); this.setByUser.add(TargetProperty.LOGGING); @@ -116,13 +116,10 @@ public TargetConfig(Properties cliArgs, TargetDecl target, MessageReporter messa this.setByUser.add(TargetProperty.COMPILER); } if (cliArgs.containsKey("tracing")) { - this.tracing = new TracingOptions(); + this.tracing.override(new TracingOptions()); this.setByUser.add(TargetProperty.TRACING); } - if (cliArgs.containsKey("scheduler")) { - this.schedulerType = SchedulerOption.valueOf(cliArgs.getProperty("scheduler")); - this.setByUser.add(TargetProperty.SCHEDULER); - } + if (cliArgs.containsKey("target-flags")) { this.compilerFlags.clear(); if (!cliArgs.getProperty("target-flags").isEmpty()) { @@ -138,11 +135,7 @@ public TargetConfig(Properties cliArgs, TargetDecl target, MessageReporter messa this.externalRuntimePath = cliArgs.getProperty("external-runtime-path"); this.setByUser.add(TargetProperty.EXTERNAL_RUNTIME_PATH); } - if (cliArgs.containsKey(TargetProperty.KEEPALIVE.description)) { - this.keepalive = - Boolean.parseBoolean(cliArgs.getProperty(TargetProperty.KEEPALIVE.description)); - this.setByUser.add(TargetProperty.KEEPALIVE); - } + if (cliArgs.containsKey(BuildParm.PRINT_STATISTICS.getKey())) { this.printStatistics = true; this.setByUser.add(TargetProperty.PRINT_STATISTICS); @@ -157,18 +150,18 @@ public TargetConfig(Properties cliArgs, TargetDecl target, MessageReporter messa * designated compiler. A common usage of this target property is to set the command to build on * the basis of a Makefile. */ - public List buildCommands = new ArrayList<>(); + public BuildCommandsConfig buildCommands = new BuildCommandsConfig(); /** * The mode of clock synchronization to be used in federated programs. The default is 'initial'. */ - public ClockSyncMode clockSync = ClockSyncMode.INIT; + public final ClockSyncModeConfig clockSync = new ClockSyncModeConfig(); /** Clock sync options. */ - public ClockSyncOptions clockSyncOptions = new ClockSyncOptions(); + public final ClockSyncOptionsConfig clockSyncOptions = new ClockSyncOptionsConfig(); /** Parameter passed to cmake. The default is 'Release'. */ - public BuildType cmakeBuildType = BuildType.RELEASE; + public BuildTypeConfig buildType = new BuildTypeConfig(); /** Optional additional extensions to include in the generated CMakeLists.txt. */ public List cmakeIncludes = new ArrayList<>(); @@ -194,13 +187,13 @@ public TargetConfig(Properties cliArgs, TargetDecl target, MessageReporter messa * The type of coordination used during the execution of a federated program. The default is * 'centralized'. */ - public CoordinationType coordination = CoordinationType.CENTRALIZED; + public CoordinationModeConfig coordination = new CoordinationModeConfig(); /** Docker options. */ - public DockerOptions dockerOptions = null; + public DockerConfig dockerOptions = new DockerConfig(); /** Coordination options. */ - public CoordinationOptions coordinationOptions = new CoordinationOptions(); + public CoordinationOptionsConfig coordinationOptions = new CoordinationOptionsConfig(); /** Link to an external runtime library instead of the default one. */ public String externalRuntimePath = null; @@ -209,7 +202,7 @@ public TargetConfig(Properties cliArgs, TargetDecl target, MessageReporter messa * If true, configure the execution environment such that it does not wait for physical time to * match logical time. The default is false. */ - public boolean fastMode = false; + public FastModeConfig fastMode = new FastModeConfig(); /** List of files to be copied to src-gen. */ public List files = new ArrayList<>(); @@ -218,7 +211,7 @@ public TargetConfig(Properties cliArgs, TargetDecl target, MessageReporter messa * If true, configure the execution environment to keep executing if there are no more events on * the event queue. The default is false. */ - public boolean keepalive = false; + public KeepaliveConfig keepalive = new KeepaliveConfig(); /** The level of logging during execution. The default is INFO. */ public LogLevel logLevel = LogLevel.INFO; @@ -242,7 +235,7 @@ public TargetConfig(Properties cliArgs, TargetDecl target, MessageReporter messa *

This is now a wrapped class to account for overloaded definitions of defining platform * (either a string or dictionary of values) */ - public PlatformOptions platformOptions = new PlatformOptions(); + public PlatformConfig platformOptions = new PlatformConfig(); /** If true, instruct the runtime to collect and print execution statistics. */ public boolean printStatistics = false; @@ -263,7 +256,7 @@ public TargetConfig(Properties cliArgs, TargetDecl target, MessageReporter messa public boolean singleFileProject = false; /** What runtime scheduler to use. */ - public SchedulerOption schedulerType = SchedulerOption.getDefault(); + public SchedulerConfig schedulerType = new SchedulerConfig(); /** * The number of worker threads to deploy. The default is zero, which indicates that the runtime @@ -272,7 +265,7 @@ public TargetConfig(Properties cliArgs, TargetDecl target, MessageReporter messa public int workers = 0; /** Indicate whether HMAC authentication is used. */ - public boolean auth = false; + public AuthConfig auth = new AuthConfig(); /** Indicate whether the runtime should use multithreaded execution. */ public boolean threading = true; @@ -281,7 +274,7 @@ public TargetConfig(Properties cliArgs, TargetDecl target, MessageReporter messa public TimeValue timeout; /** If non-null, configure the runtime environment to perform tracing. The default is null. */ - public TracingOptions tracing = null; + public TracingConfig tracing = new TracingConfig(); /** * If true, the resulting binary will output a graph visualizing all reaction dependencies. @@ -307,137 +300,9 @@ public TargetConfig(Properties cliArgs, TargetDecl target, MessageReporter messa /** Path to a C file used by the Python target to setup federated execution. */ public String fedSetupPreamble = null; // FIXME: https://issue.lf-lang.org/1558 - /** Settings related to clock synchronization. */ - public static class ClockSyncOptions { - - /** - * Dampen the adjustments to the clock synchronization offset by this rate. The default is 10. - */ - public int attenuation = 10; - - /** - * Whether to collect statistics while performing clock synchronization. This setting is only - * considered when clock synchronization has been activated. The default is true. - */ - public boolean collectStats = true; - - /** Enable clock synchronization for federates on the same machine. Default is false. */ - public boolean localFederatesOn = false; - - /** - * Interval at which clock synchronization is initiated by the RTI (will be passed to it as an - * argument on the command-line). The default is 5 milliseconds. - */ - public TimeValue period = new TimeValue(5, TimeUnit.MILLI); - - /** - * Indicate the number of exchanges to be had per each clock synchronization round. See - * /lib/core/federated/clock-sync.h for more details. The default is 10. - */ - public int trials = 10; - - /** - * Used to create an artificial clock synchronization error for the purpose of testing. The - * default is null. - */ - public TimeValue testOffset; - } - /** Settings related to coordination of federated execution. */ - public static class CoordinationOptions { - - /** - * For centralized coordination, if a federate has a physical action that can trigger an output, - * directly or indirectly, then it will send NET (next event tag) messages to the RTI - * periodically as its physical clock advances. This option sets the amount of time to wait - * between sending such messages. Increasing this value results in downstream federates that lag - * further behind physical time (if the "after" delays are insufficient). The default is null, - * which means it is up the implementation to choose an interval. - */ - public TimeValue advance_message_interval = null; - } - /** Settings related to Docker options. */ - public static class DockerOptions { - /** - * The base image and tag from which to build the Docker image. The default is "alpine:latest". - */ - public String from = "alpine:latest"; - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - DockerOptions that = (DockerOptions) o; - return from.equals(that.from); - } - } - /** Settings related to Platform Options. */ - public static class PlatformOptions { - - /** - * The base platform we build our LF Files on. Should be set to AUTO by default unless - * developing for specific OS/Embedded Platform - */ - public Platform platform = Platform.AUTO; - - /** - * The string value used to determine what type of embedded board we work with and can be used - * to simplify the build process. This string has the form "board_name[:option]*" (zero or more - * options separated by colons). For example, "pico:usb" specifies a Raspberry Pi Pico where - * stdin and stdout go through a USB serial port. - */ - public String board = null; - - /** - * The string value used to determine the port on which to flash the compiled program (i.e. - * /dev/cu.usbmodem21301) - */ - public String port = null; - - /** - * The baud rate used as a parameter to certain embedded platforms. 9600 is a standard rate - * amongst systems like Arduino, so it's the default value. - */ - public int baudRate = 9600; - - /** - * The boolean statement used to determine whether we should automatically attempt to flash once - * we compile. This may require the use of board and port values depending on the infrastructure - * you use to flash the boards. - */ - public boolean flash = false; - - /** - * The int value is used to determine the number of needed threads for the user application in - * Zephyr. - */ - public int userThreads = 0; - } - /** Settings related to tracing options. */ - public static class TracingOptions { - /** - * The name to use as the root of the trace file produced. This defaults to the name of the .lf - * file. - */ - public String traceFileName = null; - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - TracingOptions that = (TracingOptions) o; - return Objects.equals(traceFileName, that.traceFileName); // traceFileName may be null - } - } + } diff --git a/core/src/main/java/org/lflang/TargetProperty.java b/core/src/main/java/org/lflang/TargetProperty.java index 5246f72e51..ff459ce747 100644 --- a/core/src/main/java/org/lflang/TargetProperty.java +++ b/core/src/main/java/org/lflang/TargetProperty.java @@ -30,9 +30,8 @@ import java.util.LinkedList; import java.util.List; import java.util.Objects; +import java.util.Properties; -import org.lflang.TargetConfig.DockerOptions; -import org.lflang.TargetConfig.PlatformOptions; import org.lflang.ast.ASTUtils; import org.lflang.generator.InvalidLfSourceException; import org.lflang.generator.rust.CargoDependencySpec; @@ -44,24 +43,12 @@ import org.lflang.lf.LfFactory; import org.lflang.lf.Model; import org.lflang.lf.TargetDecl; -import org.lflang.target.property.BuildConfig.BuildType; -import org.lflang.target.ClockSyncConfigurator; -import org.lflang.target.ClockSyncConfigurator.ClockSyncOption; -import org.lflang.target.CoordinationConfig.CoordinationOption; -import org.lflang.target.CoordinationConfig.CoordinationType; -import org.lflang.target.DockerConfig.DockerOption; -import org.lflang.target.FastConfigurator; -import org.lflang.target.KeepaliveConfigurator; import org.lflang.target.LoggingConfigurator.LogLevel; -import org.lflang.target.PlatformConfigurator.Platform; -import org.lflang.target.PlatformConfigurator.PlatformOption; -import org.lflang.target.SchedulerConfigurator; import org.lflang.target.property.type.ArrayType; import org.lflang.target.property.type.DictionaryType; import org.lflang.target.property.type.StringDictionaryType; import org.lflang.target.property.type.TargetPropertyType; import org.lflang.target.property.type.PrimitiveType; -import org.lflang.target.TracingConfigurator; import org.lflang.target.property.type.UnionType; import org.lflang.util.FileUtil; import org.lflang.util.StringUtil; @@ -79,19 +66,14 @@ public enum TargetProperty { "auth", PrimitiveType.BOOLEAN, Arrays.asList(Target.C, Target.CCPP), - (config) -> ASTUtils.toElement(config.auth), - (config, value, err) -> { - config.auth = ASTUtils.toBoolean(value); - }), + (TargetConfig config) -> config.auth), + /** Directive to let the generator use the custom build command. */ BUILD( "build", UnionType.STRING_OR_STRING_ARRAY, Arrays.asList(Target.C, Target.CCPP), - (config) -> ASTUtils.toElement(config.buildCommands), - (config, value, err) -> { - config.buildCommands = ASTUtils.elementToListOfStrings(value); - }), + (TargetConfig config) -> config.buildCommands), /** * Directive to specify the target build type such as 'Release' or 'Debug'. This is also used in @@ -101,91 +83,20 @@ public enum TargetProperty { "build-type", UnionType.BUILD_TYPE_UNION, Arrays.asList(Target.C, Target.CCPP, Target.CPP, Target.Rust), - (config) -> ASTUtils.toElement(config.cmakeBuildType.toString()), - (config, value, err) -> { - config.cmakeBuildType = - (BuildType) UnionType.BUILD_TYPE_UNION.forName(ASTUtils.elementToSingleString(value)); - // set it there too, because the default is different. - config.rust.setBuildType(config.cmakeBuildType); - }), + (TargetConfig config) -> config.buildType), /** Directive to let the federate execution handle clock synchronization in software. */ CLOCK_SYNC( "clock-sync", UnionType.CLOCK_SYNC_UNION, Arrays.asList(Target.C, Target.CCPP, Target.Python), - new ClockSyncConfigurator()), + (TargetConfig config) -> config.clockSync), /** Key-value pairs giving options for clock synchronization. */ CLOCK_SYNC_OPTIONS( "clock-sync-options", DictionaryType.CLOCK_SYNC_OPTION_DICT, Arrays.asList(Target.C, Target.CCPP, Target.Python), - (config) -> { - Element e = LfFactory.eINSTANCE.createElement(); - KeyValuePairs kvp = LfFactory.eINSTANCE.createKeyValuePairs(); - for (ClockSyncOption opt : ClockSyncOption.values()) { - KeyValuePair pair = LfFactory.eINSTANCE.createKeyValuePair(); - pair.setName(opt.toString()); - switch (opt) { - case ATTENUATION: - pair.setValue(ASTUtils.toElement(config.clockSyncOptions.attenuation)); - break; - case COLLECT_STATS: - pair.setValue(ASTUtils.toElement(config.clockSyncOptions.collectStats)); - break; - case LOCAL_FEDERATES_ON: - pair.setValue(ASTUtils.toElement(config.clockSyncOptions.localFederatesOn)); - break; - case PERIOD: - if (config.clockSyncOptions.period == null) { - continue; // don't set if null - } - pair.setValue(ASTUtils.toElement(config.clockSyncOptions.period)); - break; - case TEST_OFFSET: - if (config.clockSyncOptions.testOffset == null) { - continue; // don't set if null - } - pair.setValue(ASTUtils.toElement(config.clockSyncOptions.testOffset)); - break; - case TRIALS: - pair.setValue(ASTUtils.toElement(config.clockSyncOptions.trials)); - break; - } - kvp.getPairs().add(pair); - } - e.setKeyvalue(kvp); - // kvp will never be empty - return e; - }, - (config, value, err) -> { - for (KeyValuePair entry : value.getKeyvalue().getPairs()) { - ClockSyncOption option = - (ClockSyncOption) DictionaryType.CLOCK_SYNC_OPTION_DICT.forName(entry.getName()); - switch (option) { - case ATTENUATION: - config.clockSyncOptions.attenuation = ASTUtils.toInteger(entry.getValue()); - break; - case COLLECT_STATS: - config.clockSyncOptions.collectStats = ASTUtils.toBoolean(entry.getValue()); - break; - case LOCAL_FEDERATES_ON: - config.clockSyncOptions.localFederatesOn = ASTUtils.toBoolean(entry.getValue()); - break; - case PERIOD: - config.clockSyncOptions.period = ASTUtils.toTimeValue(entry.getValue()); - break; - case TEST_OFFSET: - config.clockSyncOptions.testOffset = ASTUtils.toTimeValue(entry.getValue()); - break; - case TRIALS: - config.clockSyncOptions.trials = ASTUtils.toInteger(entry.getValue()); - break; - default: - break; - } - } - }), + (TargetConfig config) -> config.clockSyncOptions), /** * Directive to specify a cmake to be included by the generated build systems. @@ -236,37 +147,7 @@ public enum TargetProperty { "docker", UnionType.DOCKER_UNION, Arrays.asList(Target.C, Target.CCPP, Target.Python, Target.TS), - (config) -> { - if (config.dockerOptions == null) { - return null; - } else if (config.dockerOptions.equals(new DockerOptions())) { - // default configuration - return ASTUtils.toElement(true); - } else { - Element e = LfFactory.eINSTANCE.createElement(); - KeyValuePairs kvp = LfFactory.eINSTANCE.createKeyValuePairs(); - for (DockerOption opt : DockerOption.values()) { - KeyValuePair pair = LfFactory.eINSTANCE.createKeyValuePair(); - pair.setName(opt.toString()); - switch (opt) { - case FROM: - if (config.dockerOptions.from == null) { - continue; - } - pair.setValue(ASTUtils.toElement(config.dockerOptions.from)); - break; - } - kvp.getPairs().add(pair); - } - e.setKeyvalue(kvp); - if (kvp.getPairs().isEmpty()) { - return null; - } - return e; - } - }, - (config, value, err) -> setDockerProperty(config, value), - (config, value, err) -> setDockerProperty(config, value)), + (TargetConfig config) -> config.dockerOptions), /** Directive for specifying a path to an external runtime to be used for the compiled binary. */ EXTERNAL_RUNTIME_PATH( @@ -285,7 +166,7 @@ public enum TargetProperty { "fast", PrimitiveType.BOOLEAN, Target.ALL, - new FastConfigurator()), + (TargetConfig config) -> config.fastMode), /** * Directive to stage particular files on the class path to be processed by the code generator. */ @@ -316,74 +197,13 @@ public enum TargetProperty { "coordination", UnionType.COORDINATION_UNION, Arrays.asList(Target.C, Target.CCPP, Target.Python), - (config) -> ASTUtils.toElement(config.coordination.toString()), - (config, value, err) -> { - config.coordination = - (CoordinationType) - UnionType.COORDINATION_UNION.forName(ASTUtils.elementToSingleString(value)); - }, - (config, value, err) -> { - config.coordination = - (CoordinationType) - UnionType.COORDINATION_UNION.forName(ASTUtils.elementToSingleString(value)); - }), - + (TargetConfig config) -> config.coordination), /** Key-value pairs giving options for clock synchronization. */ COORDINATION_OPTIONS( "coordination-options", DictionaryType.COORDINATION_OPTION_DICT, Arrays.asList(Target.C, Target.CCPP, Target.Python, Target.TS), - (config) -> { - Element e = LfFactory.eINSTANCE.createElement(); - KeyValuePairs kvp = LfFactory.eINSTANCE.createKeyValuePairs(); - for (CoordinationOption opt : CoordinationOption.values()) { - KeyValuePair pair = LfFactory.eINSTANCE.createKeyValuePair(); - pair.setName(opt.toString()); - switch (opt) { - case ADVANCE_MESSAGE_INTERVAL: - if (config.coordinationOptions.advance_message_interval == null) { - continue; - } - pair.setValue( - ASTUtils.toElement(config.coordinationOptions.advance_message_interval)); - break; - } - kvp.getPairs().add(pair); - } - e.setKeyvalue(kvp); - if (kvp.getPairs().isEmpty()) { - return null; - } - return e; - }, - (config, value, err) -> { - for (KeyValuePair entry : value.getKeyvalue().getPairs()) { - CoordinationOption option = - (CoordinationOption) DictionaryType.COORDINATION_OPTION_DICT.forName(entry.getName()); - switch (option) { - case ADVANCE_MESSAGE_INTERVAL: - config.coordinationOptions.advance_message_interval = - ASTUtils.toTimeValue(entry.getValue()); - break; - default: - break; - } - } - }, - (config, value, err) -> { - for (KeyValuePair entry : value.getKeyvalue().getPairs()) { - CoordinationOption option = - (CoordinationOption) DictionaryType.COORDINATION_OPTION_DICT.forName(entry.getName()); - switch (option) { - case ADVANCE_MESSAGE_INTERVAL: - config.coordinationOptions.advance_message_interval = - ASTUtils.toTimeValue(entry.getValue()); - break; - default: - break; - } - } - }), + (TargetConfig config) -> config.coordinationOptions), /** * Directive to let the execution engine remain active also if there are no more events in the @@ -393,7 +213,7 @@ public enum TargetProperty { "keepalive", PrimitiveType.BOOLEAN, Target.ALL, - new KeepaliveConfigurator()), + (TargetConfig config) -> config.keepalive), /** Directive to specify the grain at which to report log messages during execution. */ LOGGING( @@ -444,97 +264,7 @@ public enum TargetProperty { "platform", UnionType.PLATFORM_STRING_OR_DICTIONARY, Target.ALL, - (config) -> { - Element e = LfFactory.eINSTANCE.createElement(); - KeyValuePairs kvp = LfFactory.eINSTANCE.createKeyValuePairs(); - for (PlatformOption opt : PlatformOption.values()) { - KeyValuePair pair = LfFactory.eINSTANCE.createKeyValuePair(); - pair.setName(opt.toString()); - switch (opt) { - case NAME: - pair.setValue(ASTUtils.toElement(config.platformOptions.platform.toString())); - break; - case BAUDRATE: - pair.setValue(ASTUtils.toElement(config.platformOptions.baudRate)); - break; - case BOARD: - pair.setValue(ASTUtils.toElement(config.platformOptions.board)); - break; - case FLASH: - pair.setValue(ASTUtils.toElement(config.platformOptions.flash)); - break; - case PORT: - pair.setValue(ASTUtils.toElement(config.platformOptions.port)); - break; - case USER_THREADS: - pair.setValue(ASTUtils.toElement(config.platformOptions.userThreads)); - break; - } - kvp.getPairs().add(pair); - } - e.setKeyvalue(kvp); - if (kvp.getPairs().isEmpty()) { - return null; - } - return e; - }, - (config, value, err) -> { - if (value.getLiteral() != null) { - config.platformOptions = new PlatformOptions(); - config.platformOptions.platform = - (Platform) UnionType.PLATFORM_UNION.forName(ASTUtils.elementToSingleString(value)); - if (config.platformOptions.platform == null) { - String s = - "Unidentified Platform Type, LF supports the following platform types: " - + Arrays.asList(Platform.values()).toString(); - err.at(value).error(s); - throw new AssertionError(s); - } - } else { - config.platformOptions = new PlatformOptions(); - for (KeyValuePair entry : value.getKeyvalue().getPairs()) { - PlatformOption option = - (PlatformOption) DictionaryType.PLATFORM_DICT.forName(entry.getName()); - switch (option) { - case NAME: - Platform p = - (Platform) - UnionType.PLATFORM_UNION.forName( - ASTUtils.elementToSingleString(entry.getValue())); - if (p == null) { - String s = - "Unidentified Platform Type, LF supports the following platform types: " - + Arrays.asList(Platform.values()).toString(); - err.at(entry).error(s); - throw new AssertionError(s); - } - config.platformOptions.platform = p; - break; - case BAUDRATE: - config.platformOptions.baudRate = ASTUtils.toInteger(entry.getValue()); - break; - case BOARD: - config.platformOptions.board = ASTUtils.elementToSingleString(entry.getValue()); - break; - case FLASH: - config.platformOptions.flash = ASTUtils.toBoolean(entry.getValue()); - break; - case PORT: - config.platformOptions.port = ASTUtils.elementToSingleString(entry.getValue()); - break; - case USER_THREADS: - config.platformOptions.userThreads = ASTUtils.toInteger(entry.getValue()); - break; - default: - break; - } - } - } - // If the platform does not support threading, disable it. - if (!config.platformOptions.platform.isMultiThreaded()) { - config.threading = false; - } - }), + (TargetConfig config) -> config.platformOptions), /** Directive to instruct the runtime to collect and print execution statistics. */ PRINT_STATISTICS( @@ -594,7 +324,7 @@ public enum TargetProperty { "scheduler", UnionType.SCHEDULER_UNION, Arrays.asList(Target.C, Target.CCPP, Target.Python), - new SchedulerConfigurator() + (TargetConfig config) -> config.schedulerType ), /** Directive to specify that all code is generated in a single file. */ SINGLE_FILE_PROJECT( @@ -644,7 +374,7 @@ public enum TargetProperty { "tracing", UnionType.TRACING_UNION, Arrays.asList(Target.C, Target.CCPP, Target.CPP, Target.Python), - new TracingConfigurator()), + (TargetConfig config) -> config.tracing), /** * Directive to let the runtime export its internal dependency graph. @@ -798,28 +528,6 @@ public enum TargetProperty { (config, value, err) -> config.fedSetupPreamble = StringUtil.removeQuotes(ASTUtils.elementToSingleString(value))); - /** Update {@code config}.dockerOptions based on value. */ - private static void setDockerProperty(TargetConfig config, Element value) { - if (value.getLiteral() != null) { - if (ASTUtils.toBoolean(value)) { - config.dockerOptions = new DockerOptions(); - } else { - config.dockerOptions = null; - } - } else { - config.dockerOptions = new DockerOptions(); - for (KeyValuePair entry : value.getKeyvalue().getPairs()) { - DockerOption option = (DockerOption) DictionaryType.DOCKER_DICT.forName(entry.getName()); - switch (option) { - case FROM: - config.dockerOptions.from = ASTUtils.elementToSingleString(entry.getValue()); - break; - default: - break; - } - } - } - } /** String representation of this target property. */ public final String description; @@ -849,6 +557,11 @@ private static void setDockerProperty(TargetConfig config, Element value) { public final PropertyParser updater; + @FunctionalInterface + private interface ConfigGetter { + TargetPropertyConfig get(TargetConfig config); + } + @FunctionalInterface private interface PropertyValidator { void validate(KeyValuePair pair, Model ast, TargetConfig config, ValidationReporter reporter); @@ -900,14 +613,24 @@ private interface PropertyGetter { } TargetProperty(String description, TargetPropertyType type, List supportedBy, - TargetPropertyConfig configurator) { + ConfigGetter g) { this.description = description; this.type = type; this.supportedBy = supportedBy; - this.setter = configurator::parseIntoTargetConfig; - this.getter = configurator::getPropertyElement; - this.updater = configurator::parseIntoTargetConfig; - this.validator = configurator::validate; + this.setter = (TargetConfig config, Element element, MessageReporter err) -> { + g.get(config).set(element, err); + }; + this.updater = (TargetConfig config, Element element, MessageReporter err) -> { + g.get(config).set(element, err); + }; + + this.getter = (TargetConfig config) -> { + return g.get(config).export(); + }; + + this.validator = (KeyValuePair pair, Model ast, TargetConfig config, ValidationReporter reporter) -> { + g.get(config).validate(pair, ast, config, reporter); + }; } /** @@ -945,6 +668,22 @@ public String getDisplayName() { return description; } + public static void override(TargetConfig config, Properties properties, MessageReporter err) { + properties.keySet().forEach( + key -> { + TargetProperty p = forName(key.toString()); + if (p != null) { + // Mark the specified target property as set by the user + config.setByUser.add(p); + try { + // FIXME: p.setter.parseIntoTargetConfig(config, properties.get(key), err); + } catch (InvalidLfSourceException e) { + err.at(e.getNode()).error(e.getProblem()); + } + } + }); + } + /** * Set the given configuration using the given target properties. * diff --git a/core/src/main/java/org/lflang/TargetPropertyConfig.java b/core/src/main/java/org/lflang/TargetPropertyConfig.java index 1e784da0a5..d6dcccd523 100644 --- a/core/src/main/java/org/lflang/TargetPropertyConfig.java +++ b/core/src/main/java/org/lflang/TargetPropertyConfig.java @@ -1,26 +1,65 @@ package org.lflang; +import java.util.Properties; + import org.lflang.lf.Element; import org.lflang.lf.KeyValuePair; import org.lflang.lf.Model; import org.lflang.validation.ValidationReporter; -public interface TargetPropertyConfig { +public abstract class TargetPropertyConfig { //implements TargetPropertyConfigurator { + + protected T value = initialize(); + + protected boolean setByUser; + + public void override(T value) { // FIXME: do all overrides imply setByUser? + this.value = value; + } + + public abstract T initialize(); /** * Parse the given element into the given target config. May use the error reporter to report * format errors. */ - void parseIntoTargetConfig(TargetConfig config, Element value, MessageReporter err); + public void set(Element value, MessageReporter err) { + var parsed = this.parse(value); // FIXME pass in error reporter. Maybe also rename to load? + if (parsed != null) { + this.setByUser = true; + this.value = parsed; + } + } + + public void update(Element value, MessageReporter err) { + this.set(value, err); + } + + public void update(Properties cliArgs) { + this.setByUser = true; + } + + /** + * Return the current configuration. + */ + public T get() { + return value; + } - T parse(Element value); + protected abstract T parse(Element value); // FIXME: config may not be needed. - void validate(KeyValuePair pair, Model ast, TargetConfig config, ValidationReporter reporter); + public void validate(KeyValuePair pair, Model ast, TargetConfig config, ValidationReporter reporter) { + + } /** * Read this property from the target config and build an element which represents it for the AST. * May return null if the given value of this property is the same as the default. */ - Element getPropertyElement(TargetConfig config); + public abstract Element export(); + + public boolean isSetByUser() { + return setByUser; + } } 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 206798a14c..3deefb3757 100644 --- a/core/src/main/java/org/lflang/federated/extensions/CExtension.java +++ b/core/src/main/java/org/lflang/federated/extensions/CExtension.java @@ -57,7 +57,7 @@ import org.lflang.lf.Port; import org.lflang.lf.Reactor; import org.lflang.lf.VarRef; -import org.lflang.target.CoordinationConfig.CoordinationType; +import org.lflang.target.CoordinationModeConfig.CoordinationMode; /** * An extension class to the CGenerator that enables certain federated functionalities. @@ -82,7 +82,7 @@ public void initializeTargetConfig( generateCMakeInclude(federate, fileConfig); - federate.targetConfig.keepalive = true; + federate.targetConfig.keepalive.override(true); federate.targetConfig.setByUser.add(TargetProperty.KEEPALIVE); // If there are federates, copy the required files for that. @@ -112,7 +112,7 @@ protected void generateCMakeInclude(FederateInstance federate, FedFileConfig fil * @param receivingPort The ID of the destination port. * @param connection The federated connection being lowered. * @param type The type of the data conveyed by the port. - * @param coordinationType The coordination type + * @param coordinationMode The coordination type */ public String generateNetworkReceiverBody( Action action, @@ -120,7 +120,7 @@ public String generateNetworkReceiverBody( VarRef receivingPort, FedConnectionInstance connection, InferredType type, - CoordinationType coordinationType, + CoordinationMode coordinationMode, MessageReporter messageReporter) { var receiveRef = CUtil.portRefInReaction(receivingPort, connection.getDstBank(), connection.getDstChannel()); @@ -131,7 +131,7 @@ public String generateNetworkReceiverBody( + "->physical_time_of_arrival = self->_lf__" + action.getName() + ".physical_time_of_arrival;"); - if (coordinationType == CoordinationType.DECENTRALIZED + if (coordinationMode == CoordinationMode.DECENTRALIZED && !connection.getDefinition().isPhysical()) { // Transfer the intended tag. result.pr( @@ -257,14 +257,14 @@ public void supplySenderIndexParameter(Instantiation inst, int idx) { * @param receivingPort The variable reference to the destination port. * @param connection The federated connection being lowered. * @param type The type of the data conveyed by the connection. - * @param coordinationType Centralized or decentralized. + * @param coordinationMode Centralized or decentralized. */ public String generateNetworkSenderBody( VarRef sendingPort, VarRef receivingPort, FedConnectionInstance connection, InferredType type, - CoordinationType coordinationType, + CoordinationMode coordinationMode, MessageReporter messageReporter) { var sendRef = CUtil.portRefInReaction(sendingPort, connection.getSrcBank(), connection.getSrcChannel()); @@ -311,7 +311,7 @@ public String generateNetworkSenderBody( if (connection.getDefinition().isPhysical()) { messageType = "MSG_TYPE_P2P_MESSAGE"; - } else if (coordinationType == CoordinationType.DECENTRALIZED) { + } else if (coordinationMode == CoordinationMode.DECENTRALIZED) { messageType = "MSG_TYPE_P2P_TAGGED_MESSAGE"; } else { // Logical connection @@ -680,7 +680,7 @@ private String generateCodeToInitializeFederate(FederateInstance federate, RtiCo "lf_cond_init(&logical_time_changed, &env->mutex);"))); // Find the STA (A.K.A. the global STP offset) for this federate. - if (federate.targetConfig.coordination == CoordinationType.DECENTRALIZED) { + if (federate.targetConfig.coordination.get() == CoordinationMode.DECENTRALIZED) { var reactor = ASTUtils.toDefinition(federate.instantiation.getReactorClass()); var stpParam = reactor.getParameters().stream() @@ -740,12 +740,12 @@ private String generateCodeToInitializeFederate(FederateInstance federate, RtiCo } // If a test clock offset has been specified, insert code to set it here. - if (federate.targetConfig.clockSyncOptions.testOffset != null) { + if (federate.targetConfig.clockSyncOptions.get().testOffset != null) { code.pr( "lf_set_physical_clock_offset((1 + " + federate.id + ") * " - + federate.targetConfig.clockSyncOptions.testOffset.toNanoSeconds() + + federate.targetConfig.clockSyncOptions.get().testOffset.toNanoSeconds() + "LL);"); } @@ -800,7 +800,7 @@ private String generateCodeToInitializeFederate(FederateInstance federate, RtiCo private String generateCodeForPhysicalActions( FederateInstance federate, MessageReporter messageReporter) { CodeBuilder code = new CodeBuilder(); - if (federate.targetConfig.coordination.equals(CoordinationType.CENTRALIZED)) { + if (federate.targetConfig.coordination.equals(CoordinationMode.CENTRALIZED)) { // If this program uses centralized coordination then check // for outputs that depend on physical actions so that null messages can be // sent to the RTI. @@ -823,7 +823,7 @@ private String generateCodeForPhysicalActions( } if (minDelay != TimeValue.MAX_VALUE) { // Unless silenced, issue a warning. - if (federate.targetConfig.coordinationOptions.advance_message_interval == null) { + if (federate.targetConfig.coordinationOptions.get().advanceMessageInterval == null) { String message = String.join( "\n", diff --git a/core/src/main/java/org/lflang/federated/extensions/CExtensionUtils.java b/core/src/main/java/org/lflang/federated/extensions/CExtensionUtils.java index 0903d2d90d..2b622d3b46 100644 --- a/core/src/main/java/org/lflang/federated/extensions/CExtensionUtils.java +++ b/core/src/main/java/org/lflang/federated/extensions/CExtensionUtils.java @@ -8,9 +8,7 @@ import java.util.regex.Pattern; import org.lflang.InferredType; import org.lflang.MessageReporter; -import org.lflang.TargetConfig.ClockSyncOptions; import org.lflang.TargetProperty; -import org.lflang.TargetProperty.ClockSyncMode; import org.lflang.ast.ASTUtils; import org.lflang.federated.generator.FedFileConfig; import org.lflang.federated.generator.FederateInstance; @@ -25,6 +23,8 @@ import org.lflang.lf.Expression; import org.lflang.lf.Input; import org.lflang.lf.ParameterReference; +import org.lflang.target.ClockSyncModeConfig.ClockSyncMode; +import org.lflang.target.property.ClockSyncOptionsConfig.ClockSyncOptions; public class CExtensionUtils { @@ -177,7 +177,7 @@ public static void handleCompileDefinitions( federate.targetConfig.compileDefinitions.put("FEDERATED", ""); federate.targetConfig.compileDefinitions.put( "FEDERATED_" + federate.targetConfig.coordination.toString().toUpperCase(), ""); - if (federate.targetConfig.auth) { + if (federate.targetConfig.auth.get()) { federate.targetConfig.compileDefinitions.put("FEDERATED_AUTHENTICATED", ""); } federate.targetConfig.compileDefinitions.put( @@ -190,7 +190,7 @@ public static void handleCompileDefinitions( } private static void handleAdvanceMessageInterval(FederateInstance federate) { - var advanceMessageInterval = federate.targetConfig.coordinationOptions.advance_message_interval; + var advanceMessageInterval = federate.targetConfig.coordinationOptions.get().advanceMessageInterval; federate.targetConfig.setByUser.remove(TargetProperty.COORDINATION_OPTIONS); if (advanceMessageInterval != null) { federate.targetConfig.compileDefinitions.put( @@ -199,9 +199,9 @@ private static void handleAdvanceMessageInterval(FederateInstance federate) { } static boolean clockSyncIsOn(FederateInstance federate, RtiConfig rtiConfig) { - return federate.targetConfig.clockSync != ClockSyncMode.OFF + return federate.targetConfig.clockSync.get() != ClockSyncMode.OFF && (!rtiConfig.getHost().equals(federate.host) - || federate.targetConfig.clockSyncOptions.localFederatesOn); + || federate.targetConfig.clockSyncOptions.get().localFederatesOn); } /** @@ -219,8 +219,8 @@ public static void initializeClockSynchronization( messageReporter .nowhere() .info("Initial clock synchronization is enabled for federate " + federate.id); - if (federate.targetConfig.clockSync == ClockSyncMode.ON) { - if (federate.targetConfig.clockSyncOptions.collectStats) { + if (federate.targetConfig.clockSync.get() == ClockSyncMode.ON) { + if (federate.targetConfig.clockSyncOptions.get().collectStats) { messageReporter .nowhere() .info("Will collect clock sync statistics for federate " + federate.id); @@ -251,8 +251,8 @@ public static void initializeClockSynchronization( */ public static void addClockSyncCompileDefinitions(FederateInstance federate) { - ClockSyncMode mode = federate.targetConfig.clockSync; - ClockSyncOptions options = federate.targetConfig.clockSyncOptions; + ClockSyncMode mode = federate.targetConfig.clockSync.get(); + ClockSyncOptions options = federate.targetConfig.clockSyncOptions.get(); federate.targetConfig.compileDefinitions.put("_LF_CLOCK_SYNC_INITIAL", ""); federate.targetConfig.compileDefinitions.put( diff --git a/core/src/main/java/org/lflang/federated/extensions/FedTargetExtension.java b/core/src/main/java/org/lflang/federated/extensions/FedTargetExtension.java index 61a6583026..9c2c4168f9 100644 --- a/core/src/main/java/org/lflang/federated/extensions/FedTargetExtension.java +++ b/core/src/main/java/org/lflang/federated/extensions/FedTargetExtension.java @@ -13,7 +13,7 @@ import org.lflang.lf.Reaction; import org.lflang.lf.Reactor; import org.lflang.lf.VarRef; -import org.lflang.target.CoordinationConfig.CoordinationType; +import org.lflang.target.CoordinationModeConfig.CoordinationMode; public interface FedTargetExtension { @@ -44,7 +44,7 @@ void initializeTargetConfig( * @param receivingPort The ID of the destination port. * @param connection The federated connection being lowered. * @param type The type of the data being sent over the connection. - * @param coordinationType The coordination type + * @param coordinationMode The coordination type */ String generateNetworkReceiverBody( Action action, @@ -52,7 +52,7 @@ String generateNetworkReceiverBody( VarRef receivingPort, FedConnectionInstance connection, InferredType type, - CoordinationType coordinationType, + CoordinationMode coordinationMode, MessageReporter messageReporter); /** Generate code for initializing a network output reactor from its startup reaction. */ @@ -75,14 +75,14 @@ String generateNetworkReceiverBody( * @param receivingPort The variable reference to the destination port. * @param connection The federated connection being lowered. * @param type The type of the data being sent over the connection. - * @param coordinationType Whether the federated program is centralized or decentralized. + * @param coordinationMode Whether the federated program is centralized or decentralized. */ String generateNetworkSenderBody( VarRef sendingPort, VarRef receivingPort, FedConnectionInstance connection, InferredType type, - CoordinationType coordinationType, + CoordinationMode coordinationMode, MessageReporter messageReporter); /** diff --git a/core/src/main/java/org/lflang/federated/extensions/PythonExtension.java b/core/src/main/java/org/lflang/federated/extensions/PythonExtension.java index 0b5007f5bc..abf51be552 100644 --- a/core/src/main/java/org/lflang/federated/extensions/PythonExtension.java +++ b/core/src/main/java/org/lflang/federated/extensions/PythonExtension.java @@ -42,7 +42,7 @@ import org.lflang.lf.Action; import org.lflang.lf.Reaction; import org.lflang.lf.VarRef; -import org.lflang.target.CoordinationConfig.CoordinationType; +import org.lflang.target.CoordinationModeConfig.CoordinationMode; /** * An extension class to the PythonGenerator that enables certain federated functionalities. @@ -84,13 +84,13 @@ public String generateNetworkSenderBody( VarRef receivingPort, FedConnectionInstance connection, InferredType type, - CoordinationType coordinationType, + CoordinationMode coordinationMode, MessageReporter messageReporter) { var result = new CodeBuilder(); result.pr(PyUtil.generateGILAcquireCode() + "\n"); result.pr( super.generateNetworkSenderBody( - sendingPort, receivingPort, connection, type, coordinationType, messageReporter)); + sendingPort, receivingPort, connection, type, coordinationMode, messageReporter)); result.pr(PyUtil.generateGILReleaseCode() + "\n"); return result.getCode(); } @@ -102,7 +102,7 @@ public String generateNetworkReceiverBody( VarRef receivingPort, FedConnectionInstance connection, InferredType type, - CoordinationType coordinationType, + CoordinationMode coordinationMode, MessageReporter messageReporter) { var result = new CodeBuilder(); result.pr(PyUtil.generateGILAcquireCode() + "\n"); @@ -113,7 +113,7 @@ public String generateNetworkReceiverBody( receivingPort, connection, type, - coordinationType, + coordinationMode, messageReporter)); result.pr(PyUtil.generateGILReleaseCode() + "\n"); return result.getCode(); diff --git a/core/src/main/java/org/lflang/federated/extensions/TSExtension.java b/core/src/main/java/org/lflang/federated/extensions/TSExtension.java index a3ac049a37..d10932265b 100644 --- a/core/src/main/java/org/lflang/federated/extensions/TSExtension.java +++ b/core/src/main/java/org/lflang/federated/extensions/TSExtension.java @@ -25,7 +25,7 @@ import org.lflang.lf.Reactor; import org.lflang.lf.VarRef; import org.lflang.lf.Variable; -import org.lflang.target.CoordinationConfig.CoordinationType; +import org.lflang.target.CoordinationModeConfig.CoordinationMode; public class TSExtension implements FedTargetExtension { @Override @@ -44,7 +44,7 @@ public String generateNetworkReceiverBody( VarRef receivingPort, FedConnectionInstance connection, InferredType type, - CoordinationType coordinationType, + CoordinationMode coordinationMode, MessageReporter messageReporter) { return """ // generateNetworkReceiverBody @@ -106,7 +106,7 @@ public String generateNetworkSenderBody( VarRef receivingPort, FedConnectionInstance connection, InferredType type, - CoordinationType coordinationType, + CoordinationMode coordinationMode, MessageReporter messageReporter) { return """ if (%1$s%2$s[0] !== undefined) { @@ -200,7 +200,7 @@ public String generatePreamble( private TimeValue getMinOutputDelay( FederateInstance federate, FedFileConfig fileConfig, MessageReporter messageReporter) { - if (federate.targetConfig.coordination.equals(CoordinationType.CENTRALIZED)) { + if (federate.targetConfig.coordination.equals(CoordinationMode.CENTRALIZED)) { // If this program uses centralized coordination then check // for outputs that depend on physical actions so that null messages can be // sent to the RTI. @@ -223,7 +223,7 @@ private TimeValue getMinOutputDelay( } if (minOutputDelay != TimeValue.MAX_VALUE) { // Unless silenced, issue a warning. - if (federate.targetConfig.coordinationOptions.advance_message_interval == null) { + if (federate.targetConfig.coordinationOptions.get().advanceMessageInterval == null) { String message = String.join( "\n", diff --git a/core/src/main/java/org/lflang/federated/generator/FedASTUtils.java b/core/src/main/java/org/lflang/federated/generator/FedASTUtils.java index 6414db1e9c..210365b261 100644 --- a/core/src/main/java/org/lflang/federated/generator/FedASTUtils.java +++ b/core/src/main/java/org/lflang/federated/generator/FedASTUtils.java @@ -70,7 +70,7 @@ import org.lflang.lf.Type; import org.lflang.lf.VarRef; import org.lflang.lf.Variable; -import org.lflang.target.CoordinationConfig.CoordinationType; +import org.lflang.target.CoordinationModeConfig.CoordinationMode; /** * A helper class for AST transformations needed for federated execution. @@ -136,7 +136,7 @@ public static Reactor findFederatedReactor(Resource resource) { public static void makeCommunication( FedConnectionInstance connection, Resource resource, - CoordinationType coordination, + CoordinationMode coordination, MessageReporter messageReporter) { addNetworkSenderReactor(connection, coordination, resource, messageReporter); @@ -213,7 +213,7 @@ public static Reactor addReactorDefinition(String name, Resource resource) { */ private static void addNetworkReceiverReactor( FedConnectionInstance connection, - CoordinationType coordination, + CoordinationMode coordination, Resource resource, MessageReporter messageReporter) { LfFactory factory = LfFactory.eINSTANCE; @@ -311,7 +311,7 @@ private static void addNetworkReceiverReactor( // If the connection is logical but coordination // is decentralized, we would need // to make P2P connections - if (coordination == CoordinationType.DECENTRALIZED) { + if (coordination == CoordinationMode.DECENTRALIZED) { connection.dstFederate.inboundP2PConnections.add(connection.srcFederate); } } @@ -500,7 +500,7 @@ private static void followReactionUpstream( * @return The maximum STP as a TimeValue */ private static TimeValue findMaxSTP( - FedConnectionInstance connection, CoordinationType coordination) { + FedConnectionInstance connection, CoordinationMode coordination) { Variable port = connection.getDestinationPortInstance().getDefinition(); FederateInstance instance = connection.dstFederate; Reactor reactor = connection.getDestinationPortInstance().getParent().reactorDefinition; @@ -540,7 +540,7 @@ private static TimeValue findMaxSTP( .collect(Collectors.toList()); // Find a list of STP offsets (if any exists) - if (coordination == CoordinationType.DECENTRALIZED) { + if (coordination == CoordinationMode.DECENTRALIZED) { for (Reaction r : safe(reactionsWithPort)) { // If STP offset is determined, add it // If not, assume it is zero @@ -632,7 +632,7 @@ public static List safe(List list) { */ private static Reactor getNetworkSenderReactor( FedConnectionInstance connection, - CoordinationType coordination, + CoordinationMode coordination, Resource resource, MessageReporter messageReporter) { var extension = @@ -708,7 +708,7 @@ private static Reaction getNetworkSenderReaction( VarRef inRef, VarRef destRef, FedConnectionInstance connection, - CoordinationType coordination, + CoordinationMode coordination, Type type, MessageReporter messageReporter) { var networkSenderReaction = LfFactory.eINSTANCE.createReaction(); @@ -754,7 +754,7 @@ private static Reaction getInitializationReaction(FedTargetExtension extension, */ private static void addNetworkSenderReactor( FedConnectionInstance connection, - CoordinationType coordination, + CoordinationMode coordination, Resource resource, MessageReporter messageReporter) { LfFactory factory = LfFactory.eINSTANCE; @@ -804,7 +804,7 @@ private static void addNetworkSenderReactor( // If the connection is logical but coordination // is decentralized, we would need // to make P2P connections - if (coordination == CoordinationType.DECENTRALIZED) { + if (coordination == CoordinationMode.DECENTRALIZED) { connection.srcFederate.outboundP2PConnections.add(connection.dstFederate); } } 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 05a500710c..0feee8144f 100644 --- a/core/src/main/java/org/lflang/federated/generator/FedGenerator.java +++ b/core/src/main/java/org/lflang/federated/generator/FedGenerator.java @@ -58,7 +58,7 @@ import org.lflang.lf.Reactor; import org.lflang.lf.TargetDecl; import org.lflang.lf.VarRef; -import org.lflang.target.CoordinationConfig.CoordinationType; +import org.lflang.target.CoordinationModeConfig.CoordinationMode; import org.lflang.util.Averager; public class FedGenerator { @@ -121,7 +121,7 @@ public boolean doGenerate(Resource resource, LFGeneratorContext context) throws // In a federated execution, we need keepalive to be true, // otherwise a federate could exit simply because it hasn't received // any messages. - targetConfig.keepalive = true; + targetConfig.keepalive.override(true); // Process command-line arguments processCLIArguments(context); @@ -669,7 +669,7 @@ private void replaceOneToManyConnection( */ private void replaceFedConnection(FedConnectionInstance connection, Resource resource) { if (!connection.getDefinition().isPhysical() - && targetConfig.coordination != CoordinationType.DECENTRALIZED) { + && targetConfig.coordination.get() != CoordinationMode.DECENTRALIZED) { // Map the delays on connections between federates. Set dependsOnDelays = connection.dstFederate.dependsOn.computeIfAbsent( @@ -693,6 +693,6 @@ private void replaceFedConnection(FedConnectionInstance connection, Resource res } } - FedASTUtils.makeCommunication(connection, resource, targetConfig.coordination, messageReporter); + FedASTUtils.makeCommunication(connection, resource, targetConfig.coordination.get(), messageReporter); } } diff --git a/core/src/main/java/org/lflang/federated/launcher/FedLauncherGenerator.java b/core/src/main/java/org/lflang/federated/launcher/FedLauncherGenerator.java index bff26e5c2f..7532ff1c66 100644 --- a/core/src/main/java/org/lflang/federated/launcher/FedLauncherGenerator.java +++ b/core/src/main/java/org/lflang/federated/launcher/FedLauncherGenerator.java @@ -37,7 +37,7 @@ import org.lflang.TargetConfig; import org.lflang.federated.generator.FedFileConfig; import org.lflang.federated.generator.FederateInstance; -import org.lflang.target.ClockSyncConfigurator.ClockSyncMode; +import org.lflang.target.ClockSyncModeConfig.ClockSyncMode; /** * Utility class that can be used to create a launcher for federated LF programs. @@ -334,7 +334,7 @@ private String getRtiCommand(List federates, boolean isRemote) } else { commands.add("RTI -i ${FEDERATION_ID} \\"); } - if (targetConfig.auth) { + if (targetConfig.auth.get()) { commands.add(" -a \\"); } if (targetConfig.tracing != null) { @@ -343,13 +343,13 @@ private String getRtiCommand(List federates, boolean isRemote) commands.addAll( List.of( " -n " + federates.size() + " \\", - " -c " + targetConfig.clockSync.toString() + " \\")); - if (targetConfig.clockSync.equals(ClockSyncMode.ON)) { - commands.add("period " + targetConfig.clockSyncOptions.period.toNanoSeconds() + " \\"); + " -c " + targetConfig.clockSync.get().toString() + " \\")); + if (targetConfig.clockSync.get().equals(ClockSyncMode.ON)) { + commands.add("period " + targetConfig.clockSyncOptions.get().period.toNanoSeconds() + " \\"); } - if (targetConfig.clockSync.equals(ClockSyncMode.ON) - || targetConfig.clockSync.equals(ClockSyncMode.INIT)) { - commands.add("exchanges-per-interval " + targetConfig.clockSyncOptions.trials + " \\"); + if (targetConfig.clockSync.get().equals(ClockSyncMode.ON) + || targetConfig.clockSync.get().equals(ClockSyncMode.INIT)) { + commands.add("exchanges-per-interval " + targetConfig.clockSyncOptions.get().trials + " \\"); } commands.add("&"); return String.join("\n", commands); diff --git a/core/src/main/java/org/lflang/generator/GeneratorUtils.java b/core/src/main/java/org/lflang/generator/GeneratorUtils.java index 09cf940fb3..469ba28b46 100644 --- a/core/src/main/java/org/lflang/generator/GeneratorUtils.java +++ b/core/src/main/java/org/lflang/generator/GeneratorUtils.java @@ -58,9 +58,9 @@ public static void accommodatePhysicalActionsIfPresent( && // Check if the user has explicitly set keepalive to false !targetConfig.setByUser.contains(TargetProperty.KEEPALIVE) - && !targetConfig.keepalive) { + && !targetConfig.keepalive.get()) { // If not, set it to true - targetConfig.keepalive = true; + targetConfig.keepalive.override(true); String message = String.format( "Setting %s to true because of the physical action %s.", 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 e7b7ecb5a5..6af1b1fc57 100644 --- a/core/src/main/java/org/lflang/generator/c/CCmakeGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CCmakeGenerator.java @@ -35,7 +35,7 @@ import org.lflang.MessageReporter; import org.lflang.TargetConfig; import org.lflang.generator.CodeBuilder; -import org.lflang.target.PlatformConfigurator.Platform; +import org.lflang.target.PlatformConfig.Platform; import org.lflang.util.FileUtil; /** @@ -118,8 +118,8 @@ CodeBuilder generateCMakeCode( // rp2040 : // arduino String[] boardProperties = {}; - if (targetConfig.platformOptions.board != null) { - boardProperties = targetConfig.platformOptions.board.trim().split(":"); + if (targetConfig.platformOptions.get().board != null) { + boardProperties = targetConfig.platformOptions.get().board.trim().split(":"); // Ignore whitespace for (int i = 0; i < boardProperties.length; i++) { boardProperties[i] = boardProperties[i].trim(); @@ -132,14 +132,14 @@ CodeBuilder generateCMakeCode( cMakeCode.pr("cmake_minimum_required(VERSION " + MIN_CMAKE_VERSION + ")"); // Setup the project header for different platforms - switch (targetConfig.platformOptions.platform) { + switch (targetConfig.platformOptions.get().platform) { case ZEPHYR: cMakeCode.pr("# Set default configuration file. To add custom configurations,"); cMakeCode.pr("# pass -- -DOVERLAY_CONFIG=my_config.prj to either cmake or west"); cMakeCode.pr("set(CONF_FILE prj_lf.conf)"); - if (targetConfig.platformOptions.board != null) { + if (targetConfig.platformOptions.get().board != null) { cMakeCode.pr("# Selecting board specified in target property"); - cMakeCode.pr("set(BOARD " + targetConfig.platformOptions.board + ")"); + cMakeCode.pr("set(BOARD " + targetConfig.platformOptions.get().board + ")"); } else { cMakeCode.pr("# Selecting default board"); cMakeCode.pr("set(BOARD qemu_cortex_m3)"); @@ -175,7 +175,7 @@ CodeBuilder generateCMakeCode( cMakeCode.pr("project(" + executableName + " LANGUAGES C CXX ASM)"); cMakeCode.newLine(); // board type for rp2040 based boards - if (targetConfig.platformOptions.board != null) { + if (targetConfig.platformOptions.get().board != null) { if (boardProperties.length < 1 || boardProperties[0].equals("")) { cMakeCode.pr("set(PICO_BOARD pico)"); } else { @@ -231,7 +231,7 @@ CodeBuilder generateCMakeCode( } // Set the build type - cMakeCode.pr("set(DEFAULT_BUILD_TYPE " + targetConfig.cmakeBuildType + ")\n"); + cMakeCode.pr("set(DEFAULT_BUILD_TYPE " + targetConfig.buildType + ")\n"); cMakeCode.pr("if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)\n"); cMakeCode.pr( " set(CMAKE_BUILD_TYPE ${DEFAULT_BUILD_TYPE} CACHE STRING \"Choose the type of build.\"" @@ -249,14 +249,14 @@ CodeBuilder generateCMakeCode( cMakeCode.newLine(); } - if (targetConfig.platformOptions.platform != Platform.AUTO) { + if (targetConfig.platformOptions.get().platform != Platform.AUTO) { cMakeCode.pr( - "set(CMAKE_SYSTEM_NAME " + targetConfig.platformOptions.platform.getcMakeName() + ")"); + "set(CMAKE_SYSTEM_NAME " + targetConfig.platformOptions.get().platform.getcMakeName() + ")"); } cMakeCode.newLine(); // Setup main target for different platforms - switch (targetConfig.platformOptions.platform) { + switch (targetConfig.platformOptions.get().platform) { case ZEPHYR: cMakeCode.pr( setUpMainTargetZephyr( @@ -296,12 +296,12 @@ CodeBuilder generateCMakeCode( cMakeCode.pr("target_include_directories(${LF_MAIN_TARGET} PUBLIC include/core/utils)"); // post target definition board configurations - switch (targetConfig.platformOptions.platform) { + switch (targetConfig.platformOptions.get().platform) { case RP2040: // set stdio output boolean usb = true; boolean uart = true; - if (targetConfig.platformOptions.board != null && boardProperties.length > 1) { + if (targetConfig.platformOptions.get().board != null && boardProperties.length > 1) { uart = !boardProperties[1].equals("usb"); usb = !boardProperties[1].equals("uart"); } @@ -310,12 +310,12 @@ CodeBuilder generateCMakeCode( break; } - if (targetConfig.auth) { + if (targetConfig.auth.get()) { // If security is requested, add the auth option. var osName = System.getProperty("os.name").toLowerCase(); // if platform target was set, use given platform instead - if (targetConfig.platformOptions.platform != Platform.AUTO) { - osName = targetConfig.platformOptions.platform.toString(); + if (targetConfig.platformOptions.get().platform != Platform.AUTO) { + osName = targetConfig.platformOptions.get().platform.toString(); } if (osName.contains("mac")) { cMakeCode.pr("set(OPENSSL_ROOT_DIR /usr/local/opt/openssl)"); diff --git a/core/src/main/java/org/lflang/generator/c/CCompiler.java b/core/src/main/java/org/lflang/generator/c/CCompiler.java index 0df21fc413..f35b698c51 100644 --- a/core/src/main/java/org/lflang/generator/c/CCompiler.java +++ b/core/src/main/java/org/lflang/generator/c/CCompiler.java @@ -41,7 +41,7 @@ import org.lflang.generator.GeneratorUtils; import org.lflang.generator.LFGeneratorContext; import org.lflang.target.property.BuildConfig; -import org.lflang.target.PlatformConfigurator.Platform; +import org.lflang.target.PlatformConfig.Platform; import org.lflang.util.FileUtil; import org.lflang.util.LFCommand; @@ -179,8 +179,8 @@ public boolean runCCompiler(GeneratorBase generator, LFGeneratorContext context) + " finished with no errors."); } - if (targetConfig.platformOptions.platform == Platform.ZEPHYR - && targetConfig.platformOptions.flash) { + if (targetConfig.platformOptions.get().platform == Platform.ZEPHYR + && targetConfig.platformOptions.get().flash) { messageReporter.nowhere().info("Invoking flash command for Zephyr"); LFCommand flash = buildWestFlashCommand(); int flashRet = flash.run(); @@ -237,8 +237,8 @@ private static List cmakeOptions(TargetConfig targetConfig, FileConfig f arguments.addAll( List.of( "-DCMAKE_BUILD_TYPE=" - + ((targetConfig.cmakeBuildType != null) - ? targetConfig.cmakeBuildType.toString() + + ((targetConfig.buildType != null) + ? targetConfig.buildType.toString() : "Release"), "-DCMAKE_INSTALL_PREFIX=" + FileUtil.toUnixString(fileConfig.getOutPath()), "-DCMAKE_INSTALL_BINDIR=" @@ -260,7 +260,7 @@ private static List cmakeOptions(TargetConfig targetConfig, FileConfig f return arguments; } - /** Return the cmake config name correspnding to a given build type. */ + /** Return the cmake config name corresponding to a given build type. */ private String buildTypeToCmakeConfig(BuildConfig.BuildType type) { if (type == null) { return "Release"; @@ -295,7 +295,7 @@ public LFCommand buildCmakeCommand() { "--parallel", cores, "--config", - buildTypeToCmakeConfig(targetConfig.cmakeBuildType)), + buildTypeToCmakeConfig(targetConfig.buildType.get())), buildPath); if (command == null) { messageReporter @@ -316,7 +316,7 @@ public LFCommand buildCmakeCommand() { public LFCommand buildWestFlashCommand() { // Set the build directory to be "build" Path buildPath = fileConfig.getSrcGenPath().resolve("build"); - String board = targetConfig.platformOptions.board; + String board = targetConfig.platformOptions.get().board; LFCommand cmd; if (board == null || board.startsWith("qemu") || board.equals("native_posix")) { cmd = commandFactory.createCommand("west", List.of("build", "-t", "run"), buildPath); @@ -445,7 +445,7 @@ public LFCommand compileCCommand(String fileToCompile, boolean noBinary) { * .cpp files instead of .c files and uses a C++ compiler to compiler the code. */ static String getTargetFileName(String fileName, boolean cppMode, TargetConfig targetConfig) { - if (targetConfig.platformOptions.platform == Platform.ARDUINO) { + if (targetConfig.platformOptions.get().platform == Platform.ARDUINO) { return fileName + ".ino"; } if (cppMode) { diff --git a/core/src/main/java/org/lflang/generator/c/CDockerGenerator.java b/core/src/main/java/org/lflang/generator/c/CDockerGenerator.java index f52e23a949..f6dc1bf200 100644 --- a/core/src/main/java/org/lflang/generator/c/CDockerGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CDockerGenerator.java @@ -30,13 +30,13 @@ protected String generateDockerFileContent() { var lfModuleName = context.getFileConfig().name; var config = context.getTargetConfig(); var compileCommand = - IterableExtensions.isNullOrEmpty(config.buildCommands) + IterableExtensions.isNullOrEmpty(config.buildCommands.get()) ? generateDefaultCompileCommand() - : StringUtil.joinObjects(config.buildCommands, " "); + : StringUtil.joinObjects(config.buildCommands.get(), " "); var compiler = config.target == Target.CCPP ? "g++" : "gcc"; var baseImage = DEFAULT_BASE_IMAGE; - if (config.dockerOptions != null && config.dockerOptions.from != null) { - baseImage = config.dockerOptions.from; + if (config.dockerOptions != null && config.dockerOptions.get().from != null) { + baseImage = config.dockerOptions.get().from; } return String.join( "\n", diff --git a/core/src/main/java/org/lflang/generator/c/CEnvironmentFunctionGenerator.java b/core/src/main/java/org/lflang/generator/c/CEnvironmentFunctionGenerator.java index 71134fb806..90a09b3dc1 100644 --- a/core/src/main/java/org/lflang/generator/c/CEnvironmentFunctionGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CEnvironmentFunctionGenerator.java @@ -89,13 +89,14 @@ private String generateCreateEnvironments() { // Figure out the name of the trace file String traceFileName = "NULL"; - if (targetConfig.tracing != null) { - if (targetConfig.tracing.traceFileName != null) { + var tracing = targetConfig.tracing.get(); + if (tracing.isEnabled()) { + if (tracing.traceFileName != null) { if (enclave.isMainOrFederated()) { - traceFileName = "\"" + targetConfig.tracing.traceFileName + ".lft\""; + traceFileName = "\"" + tracing.traceFileName + ".lft\""; } else { traceFileName = - "\"" + targetConfig.tracing.traceFileName + enclave.getName() + ".lft\""; + "\"" + tracing.traceFileName + enclave.getName() + ".lft\""; } } else { if (enclave.isMainOrFederated()) { 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 335a971247..f4b1b9043f 100644 --- a/core/src/main/java/org/lflang/generator/c/CGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CGenerator.java @@ -54,7 +54,7 @@ import org.lflang.Target; import org.lflang.TargetConfig; import org.lflang.TargetProperty; -import org.lflang.TargetProperty.PlatformOption; +import org.lflang.target.PlatformConfig.PlatformOption; import org.lflang.ast.ASTUtils; import org.lflang.ast.DelayedConnectionTransformation; import org.lflang.federated.extensions.CExtensionUtils; @@ -88,8 +88,8 @@ import org.lflang.lf.ReactorDecl; import org.lflang.lf.StateVar; import org.lflang.lf.Variable; -import org.lflang.target.PlatformConfigurator.Platform; -import org.lflang.target.SchedulerConfigurator.SchedulerOption; +import org.lflang.target.PlatformConfig.Platform; +import org.lflang.target.SchedulerConfig.SchedulerOption; import org.lflang.util.ArduinoUtil; import org.lflang.util.FileUtil; @@ -432,7 +432,7 @@ public void doGenerate(Resource resource, LFGeneratorContext context) { } // If cmake is requested, generate the CMakeLists.txt - if (targetConfig.platformOptions.platform != Platform.ARDUINO) { + if (targetConfig.platformOptions.get().platform != Platform.ARDUINO) { var cmakeFile = fileConfig.getSrcGenPath() + File.separator + "CMakeLists.txt"; var sources = allTypeParameterizedReactors() @@ -539,7 +539,7 @@ public void doGenerate(Resource resource, LFGeneratorContext context) { // clean it up after, removing the #line directives after errors have been reported. if (!targetConfig.noCompile && targetConfig.dockerOptions == null - && IterableExtensions.isNullOrEmpty(targetConfig.buildCommands) + && IterableExtensions.isNullOrEmpty(targetConfig.buildCommands.get()) // This code is unreachable in LSP_FAST mode, so that check is omitted. && context.getMode() != LFGeneratorContext.Mode.LSP_MEDIUM) { // FIXME: Currently, a lack of main is treated as a request to not produce @@ -582,7 +582,7 @@ public void doGenerate(Resource resource, LFGeneratorContext context) { // If a build directive has been given, invoke it now. // Note that the code does not get cleaned in this case. if (!targetConfig.noCompile) { - if (!IterableExtensions.isNullOrEmpty(targetConfig.buildCommands)) { + if (!IterableExtensions.isNullOrEmpty(targetConfig.buildCommands.get())) { CUtil.runBuildCommand( fileConfig, targetConfig, @@ -654,7 +654,7 @@ private void generateCodeFor(String lfModuleName) throws IOException { // is set to decentralized) or, if there are // downstream federates, will notify the RTI // that the specified logical time is complete. - if (CCppMode || targetConfig.platformOptions.platform == Platform.ARDUINO) + if (CCppMode || targetConfig.platformOptions.get().platform == Platform.ARDUINO) code.pr("extern \"C\""); code.pr( String.join( @@ -695,11 +695,11 @@ protected String getConflictingConnectionsInModalReactorsBody(String source, Str private void pickScheduler() { // Don't use a scheduler that does not prioritize reactions based on deadlines // if the program contains a deadline (handler). Use the GEDF_NP scheduler instead. - if (!targetConfig.schedulerType.prioritizesDeadline()) { + if (!targetConfig.schedulerType.get().prioritizesDeadline()) { // Check if a deadline is assigned to any reaction if (hasDeadlines(reactors)) { if (!targetConfig.setByUser.contains(TargetProperty.SCHEDULER)) { - targetConfig.schedulerType = SchedulerOption.GEDF_NP; + targetConfig.schedulerType.override(SchedulerOption.GEDF_NP); } } } @@ -899,8 +899,8 @@ private void generateReactorChildren( private void pickCompilePlatform() { var osName = System.getProperty("os.name").toLowerCase(); // if platform target was set, use given platform instead - if (targetConfig.platformOptions.platform != Platform.AUTO) { - osName = targetConfig.platformOptions.platform.toString(); + if (targetConfig.platformOptions.get().platform != Platform.AUTO) { + osName = targetConfig.platformOptions.get().platform.toString(); } else if (Stream.of("mac", "darwin", "win", "nux").noneMatch(osName::contains)) { messageReporter.nowhere().error("Platform " + osName + " is not supported"); } @@ -911,7 +911,7 @@ protected void copyTargetFiles() throws IOException { // Copy the core lib String coreLib = LFGeneratorContext.BuildParm.EXTERNAL_RUNTIME_PATH.getValue(context); Path dest = fileConfig.getSrcGenPath(); - if (targetConfig.platformOptions.platform == Platform.ARDUINO) { + if (targetConfig.platformOptions.get().platform == Platform.ARDUINO) { dest = dest.resolve("src"); } if (coreLib != null) { @@ -922,7 +922,7 @@ protected void copyTargetFiles() throws IOException { } // For the Zephyr target, copy default config and board files. - if (targetConfig.platformOptions.platform == Platform.ZEPHYR) { + if (targetConfig.platformOptions.get().platform == Platform.ZEPHYR) { FileUtil.copyFromClassPath( "/lib/platform/zephyr/boards", fileConfig.getSrcGenPath(), false, false); FileUtil.copyFileFromClassPath( @@ -933,7 +933,7 @@ protected void copyTargetFiles() throws IOException { } // For the pico src-gen, copy over vscode configurations for debugging - if (targetConfig.platformOptions.platform == Platform.RP2040) { + if (targetConfig.platformOptions.get().platform == Platform.RP2040) { Path vscodePath = fileConfig.getSrcGenPath().resolve(".vscode"); // If pico-sdk-path not defined, this can be used to pull the sdk into src-gen FileUtil.copyFileFromClassPath( @@ -980,7 +980,7 @@ private void generateReactorClass(TypeParameterizedReactor tpr) throws IOExcepti fileConfig.getSrcGenPath().resolve(headerName), true); var extension = - targetConfig.platformOptions.platform == Platform.ARDUINO + targetConfig.platformOptions.get().platform == Platform.ARDUINO ? ".ino" : CCppMode ? ".cpp" : ".c"; FileUtil.writeToFile( @@ -1970,9 +1970,9 @@ protected void setUpGeneralParameters() { targetConfig.compileDefinitions.put("MODAL_REACTORS", "TRUE"); } if (targetConfig.threading - && targetConfig.platformOptions.platform == Platform.ARDUINO - && (targetConfig.platformOptions.board == null - || !targetConfig.platformOptions.board.contains("mbed"))) { + && targetConfig.platformOptions.get().platform == Platform.ARDUINO + && (targetConfig.platformOptions.get().board == null + || !targetConfig.platformOptions.get().board.contains("mbed"))) { // non-MBED boards should not use threading messageReporter .nowhere() @@ -1982,9 +1982,9 @@ protected void setUpGeneralParameters() { targetConfig.threading = false; } - if (targetConfig.platformOptions.platform == Platform.ARDUINO + if (targetConfig.platformOptions.get().platform == Platform.ARDUINO && !targetConfig.noCompile - && targetConfig.platformOptions.board == null) { + && targetConfig.platformOptions.get().board == null) { messageReporter .nowhere() .info( @@ -1995,13 +1995,13 @@ protected void setUpGeneralParameters() { targetConfig.noCompile = true; } - if (targetConfig.platformOptions.platform == Platform.ZEPHYR + if (targetConfig.platformOptions.get().platform == Platform.ZEPHYR && targetConfig.threading - && targetConfig.platformOptions.userThreads >= 0) { + && targetConfig.platformOptions.get().userThreads >= 0) { targetConfig.compileDefinitions.put( PlatformOption.USER_THREADS.name(), - String.valueOf(targetConfig.platformOptions.userThreads)); - } else if (targetConfig.platformOptions.userThreads > 0) { + String.valueOf(targetConfig.platformOptions.get().userThreads)); + } else if (targetConfig.platformOptions.get().userThreads > 0) { messageReporter .nowhere() .warning( @@ -2012,7 +2012,7 @@ protected void setUpGeneralParameters() { if (targetConfig.threading) { // FIXME: This logic is duplicated in CMake pickScheduler(); // FIXME: this and pickScheduler should be combined. - targetConfig.compileDefinitions.put("SCHEDULER", targetConfig.schedulerType.name()); + targetConfig.compileDefinitions.put("SCHEDULER", targetConfig.schedulerType.get().name()); targetConfig.compileDefinitions.put( "NUMBER_OF_WORKERS", String.valueOf(targetConfig.workers)); } diff --git a/core/src/main/java/org/lflang/generator/c/CMainFunctionGenerator.java b/core/src/main/java/org/lflang/generator/c/CMainFunctionGenerator.java index 99f3df0f0b..9dd130471c 100644 --- a/core/src/main/java/org/lflang/generator/c/CMainFunctionGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CMainFunctionGenerator.java @@ -4,7 +4,7 @@ import java.util.List; import org.lflang.TargetConfig; import org.lflang.generator.CodeBuilder; -import org.lflang.target.PlatformConfigurator.Platform; +import org.lflang.target.PlatformConfig.Platform; import org.lflang.util.StringUtil; public class CMainFunctionGenerator { @@ -33,7 +33,7 @@ public String generateCode() { /** Generate the {@code main} function. */ private String generateMainFunction() { - if (targetConfig.platformOptions.platform == Platform.ARDUINO) { + if (targetConfig.platformOptions.get().platform == Platform.ARDUINO) { /** * By default, we must have a serial begin line prior to calling lf_reactor_c_main due to * internal debugging messages requiring a print buffer. For the future, we can check whether @@ -48,12 +48,12 @@ private String generateMainFunction() { "}\n", "// Arduino setup() and loop() functions", "void setup() {", - "\tSerial.begin(" + targetConfig.platformOptions.baudRate + ");", + "\tSerial.begin(" + targetConfig.platformOptions.get().baudRate + ");", "\tlf_register_print_function(&_lf_arduino_print_message_function, LOG_LEVEL);", "\tlf_reactor_c_main(0, NULL);", "}\n", "void loop() {}"); - } else if (targetConfig.platformOptions.platform == Platform.ZEPHYR) { + } else if (targetConfig.platformOptions.get().platform == Platform.ZEPHYR) { // The Zephyr "runtime" does not terminate when main returns. // Rather, {@code exit} should be called explicitly. return String.join( @@ -62,7 +62,7 @@ private String generateMainFunction() { " int res = lf_reactor_c_main(0, NULL);", " exit(res);", "}"); - } else if (targetConfig.platformOptions.platform == Platform.RP2040) { + } else if (targetConfig.platformOptions.get().platform == Platform.RP2040) { // Pico platform cannot use command line args. return String.join("\n", "int main(void) {", " return lf_reactor_c_main(0, NULL);", "}"); } else { @@ -97,11 +97,11 @@ private String generateSetDefaultCliOption() { /** Parse the target parameters and set flags to the runCommand accordingly. */ private void parseTargetParameters() { - if (targetConfig.fastMode) { + if (targetConfig.fastMode.get()) { runCommand.add("-f"); runCommand.add("true"); } - if (targetConfig.keepalive) { + if (targetConfig.keepalive.get()) { runCommand.add("-k"); runCommand.add("true"); } 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 dc48f5d40b..da3794d44e 100644 --- a/core/src/main/java/org/lflang/generator/c/CPreambleGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CPreambleGenerator.java @@ -5,7 +5,7 @@ import java.nio.file.Path; import org.lflang.TargetConfig; import org.lflang.generator.CodeBuilder; -import org.lflang.target.PlatformConfigurator.Platform; +import org.lflang.target.PlatformConfig.Platform; import org.lflang.util.StringUtil; /** @@ -28,7 +28,7 @@ public class CPreambleGenerator { public static String generateIncludeStatements(TargetConfig targetConfig, boolean cppMode) { var tracing = targetConfig.tracing; CodeBuilder code = new CodeBuilder(); - if (cppMode || targetConfig.platformOptions.platform == Platform.ARDUINO) { + if (cppMode || targetConfig.platformOptions.get().platform == Platform.ARDUINO) { code.pr("extern \"C\" {"); } code.pr("#include "); @@ -53,7 +53,7 @@ public static String generateIncludeStatements(TargetConfig targetConfig, boolea code.pr("#include \"include/core/federated/federate.h\""); code.pr("#include \"include/core/federated/net_common.h\""); } - if (cppMode || targetConfig.platformOptions.platform == Platform.ARDUINO) { + if (cppMode || targetConfig.platformOptions.get().platform == Platform.ARDUINO) { code.pr("}"); } return code.toString(); @@ -63,7 +63,7 @@ public static String generateDefineDirectives( TargetConfig targetConfig, Path srcGenPath, boolean hasModalReactors) { int logLevel = targetConfig.logLevel.ordinal(); var coordinationType = targetConfig.coordination; - var tracing = targetConfig.tracing; + var tracing = targetConfig.tracing.get(); CodeBuilder code = new CodeBuilder(); // TODO: Get rid of all of these code.pr("#define LOG_LEVEL " + logLevel); diff --git a/core/src/main/java/org/lflang/generator/c/CUtil.java b/core/src/main/java/org/lflang/generator/c/CUtil.java index aa53e9edc0..a92ef82c93 100644 --- a/core/src/main/java/org/lflang/generator/c/CUtil.java +++ b/core/src/main/java/org/lflang/generator/c/CUtil.java @@ -614,7 +614,7 @@ public static void runBuildCommand( ReportCommandErrors reportCommandErrors, LFGeneratorContext.Mode mode) { List commands = - getCommands(targetConfig.buildCommands, commandFactory, fileConfig.srcPath); + getCommands(targetConfig.buildCommands.get(), commandFactory, fileConfig.srcPath); // If the build command could not be found, abort. // An error has already been reported in createCommand. if (commands.stream().anyMatch(Objects::isNull)) return; diff --git a/core/src/main/java/org/lflang/generator/rust/RustTargetConfig.java b/core/src/main/java/org/lflang/generator/rust/RustTargetConfig.java index 83ef50589b..dc9a766ba8 100644 --- a/core/src/main/java/org/lflang/generator/rust/RustTargetConfig.java +++ b/core/src/main/java/org/lflang/generator/rust/RustTargetConfig.java @@ -33,6 +33,7 @@ import org.eclipse.emf.ecore.EObject; import org.lflang.MessageReporter; import org.lflang.target.property.BuildConfig.BuildType; +import org.lflang.target.property.BuildTypeConfig; /** * Rust-specific part of a {@link org.lflang.TargetConfig}. @@ -95,12 +96,13 @@ public List getRustTopLevelModules() { } /** The build type to use. Corresponds to a Cargo profile. */ - public BuildType getBuildType() { + public BuildType getBuildType(BuildTypeConfig cmakeBuildType) { + // FIXME: this is because Rust uses a different default. + // Can we just use the same? + if (cmakeBuildType.isSetByUser()) { + return cmakeBuildType.get(); + } return profile; } - /** Set a build profile chosen based on a cmake profile. */ - public void setBuildType(BuildType profile) { - this.profile = profile; - } } diff --git a/core/src/main/java/org/lflang/target/AuthConfig.java b/core/src/main/java/org/lflang/target/AuthConfig.java new file mode 100644 index 0000000000..2c97897f7b --- /dev/null +++ b/core/src/main/java/org/lflang/target/AuthConfig.java @@ -0,0 +1,24 @@ +package org.lflang.target; + +import org.lflang.TargetPropertyConfig; +import org.lflang.ast.ASTUtils; +import org.lflang.lf.Element; + +public class AuthConfig extends TargetPropertyConfig { + + @Override + public Boolean initialize() { + return false; + } + + @Override + public Boolean parse(Element value) { + return ASTUtils.toBoolean(value); + } + + @Override + public Element export() { + return ASTUtils.toElement(this.value.toString()); + } + +} diff --git a/core/src/main/java/org/lflang/target/AuthConfigurator.java b/core/src/main/java/org/lflang/target/AuthConfigurator.java deleted file mode 100644 index 7a1aec6372..0000000000 --- a/core/src/main/java/org/lflang/target/AuthConfigurator.java +++ /dev/null @@ -1,33 +0,0 @@ -package org.lflang.target; - -import org.lflang.MessageReporter; -import org.lflang.TargetConfig; -import org.lflang.TargetPropertyConfig; -import org.lflang.ast.ASTUtils; -import org.lflang.lf.Element; -import org.lflang.lf.KeyValuePair; -import org.lflang.lf.Model; -import org.lflang.validation.LFValidator.ValidationReporter; - -public class AuthConfigurator implements TargetPropertyConfig { - - @Override - public void parseIntoTargetConfig(TargetConfig config, Element value, MessageReporter err) { - config.auth = this.parse(value); - } - - @Override - public Boolean parse(Element value) { - return ASTUtils.toBoolean(value); - } - - @Override - public void validate(KeyValuePair pair, Model ast, TargetConfig config, ValidationReporter reporter) { - - } - - @Override - public Element getPropertyElement(TargetConfig config) { - return ASTUtils.toElement(config.auth); - } -} diff --git a/core/src/main/java/org/lflang/target/ClockSyncConfigurator.java b/core/src/main/java/org/lflang/target/ClockSyncConfigurator.java deleted file mode 100644 index 4508aa809b..0000000000 --- a/core/src/main/java/org/lflang/target/ClockSyncConfigurator.java +++ /dev/null @@ -1,115 +0,0 @@ -package org.lflang.target; - -import org.lflang.MessageReporter; -import org.lflang.TargetConfig; -import org.lflang.TargetProperty.DictionaryElement; -import org.lflang.TargetPropertyConfig; -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.ClockSyncConfigurator.ClockSyncMode; -import org.lflang.target.property.type.TargetPropertyType; -import org.lflang.target.property.type.PrimitiveType; -import org.lflang.target.property.type.UnionType; -import org.lflang.validation.LFValidator.ValidationReporter; - -public class ClockSyncConfigurator implements TargetPropertyConfig { - - @Override - public void parseIntoTargetConfig(TargetConfig config, Element value, MessageReporter err) { - config.clockSync = this.parse(value); - - } - - @Override - public ClockSyncMode parse(Element value) { - return (ClockSyncMode) - UnionType.CLOCK_SYNC_UNION.forName(ASTUtils.elementToSingleString(value)); - } - - - @Override - public void validate(KeyValuePair pair, Model ast, TargetConfig config, ValidationReporter reporter) { - if (pair != null) { - boolean federatedExists = false; - for (Reactor reactor : ast.getReactors()) { - if (reactor.isFederated()) { - federatedExists = true; - } - } - if (!federatedExists) { - reporter.warning( - "The clock-sync target property is incompatible with non-federated programs.", - pair, - Literals.KEY_VALUE_PAIR__NAME); - } - } - } - - @Override - public Element getPropertyElement(TargetConfig config) { - return ASTUtils.toElement(config.clockSync.toString()); - } - - /** - * Clock synchronization options. - * - * @author Marten Lohstroh - */ - public enum ClockSyncOption implements DictionaryElement { - ATTENUATION("attenuation", PrimitiveType.NON_NEGATIVE_INTEGER), - LOCAL_FEDERATES_ON("local-federates-on", PrimitiveType.BOOLEAN), - PERIOD("period", PrimitiveType.TIME_VALUE), - TEST_OFFSET("test-offset", PrimitiveType.TIME_VALUE), - TRIALS("trials", PrimitiveType.NON_NEGATIVE_INTEGER), - COLLECT_STATS("collect-stats", PrimitiveType.BOOLEAN); - - public final PrimitiveType type; - - private final String description; - - private ClockSyncOption(String alias, PrimitiveType type) { - this.description = alias; - this.type = type; - } - - /** Return the description of this dictionary element. */ - @Override - public String toString() { - return this.description; - } - - /** Return the type associated with this dictionary element. */ - public TargetPropertyType getType() { - return this.type; - } - } - - /** - * Enumeration of clock synchronization modes. - * - *

    - *
  • OFF: The clock synchronization is universally off. - *
  • STARTUP: Clock synchronization occurs at startup only. - *
  • ON: Clock synchronization occurs at startup and at runtime. - *
- * - * @author Edward A. Lee - */ - public enum ClockSyncMode { - OFF, - INIT, - ON; // TODO Discuss initial in now a mode keyword (same as startup) and cannot be used as target - // property value, thus changed it to init - // FIXME I could not test if this change breaks anything - - /** Return the name in lower case. */ - @Override - public String toString() { - return this.name().toLowerCase(); - } - } -} diff --git a/core/src/main/java/org/lflang/target/ClockSyncModeConfig.java b/core/src/main/java/org/lflang/target/ClockSyncModeConfig.java new file mode 100644 index 0000000000..f0372002db --- /dev/null +++ b/core/src/main/java/org/lflang/target/ClockSyncModeConfig.java @@ -0,0 +1,83 @@ +package org.lflang.target; + + +import org.lflang.TargetConfig; +import org.lflang.TargetPropertyConfig; +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.ClockSyncModeConfig.ClockSyncMode; +import org.lflang.target.property.type.UnionType; +import org.lflang.validation.ValidationReporter; + +public class ClockSyncModeConfig extends TargetPropertyConfig { + + + @Override + public ClockSyncMode initialize() { + return ClockSyncMode.INIT; + } + + @Override + public ClockSyncMode parse(Element value) { + + UnionType.CLOCK_SYNC_UNION.validate(value); + var mode = (ClockSyncMode) + UnionType.CLOCK_SYNC_UNION.forName(ASTUtils.elementToSingleString(value)); + if (mode != null) { + return mode; + } else { + return ClockSyncMode.INIT; + } + } + + @Override + public void validate(KeyValuePair pair, Model ast, TargetConfig config, ValidationReporter reporter) { + if (pair != null) { + boolean federatedExists = false; + for (Reactor reactor : ast.getReactors()) { + if (reactor.isFederated()) { + federatedExists = true; + } + } + if (!federatedExists) { + reporter.warning( + "The clock-sync target property is incompatible with non-federated programs.", + pair, + Literals.KEY_VALUE_PAIR__NAME); + } + } + } + + @Override + public Element export() { + return ASTUtils.toElement(this.value.toString()); + } + + + + /** + * Enumeration of clock synchronization modes. + * + *
    + *
  • OFF: The clock synchronization is universally off. + *
  • STARTUP: Clock synchronization occurs at startup only. + *
  • ON: Clock synchronization occurs at startup and at runtime. + *
+ * + * @author Edward A. Lee + */ + public enum ClockSyncMode { + OFF, + INIT, + ON; + /** Return the name in lower case. */ + @Override + public String toString() { + return this.name().toLowerCase(); + } + } +} diff --git a/core/src/main/java/org/lflang/target/CoordinationConfig.java b/core/src/main/java/org/lflang/target/CoordinationConfig.java deleted file mode 100644 index 08ed4204a7..0000000000 --- a/core/src/main/java/org/lflang/target/CoordinationConfig.java +++ /dev/null @@ -1,83 +0,0 @@ -package org.lflang.target; - -import org.lflang.MessageReporter; -import org.lflang.TargetConfig; -import org.lflang.TargetProperty.DictionaryElement; -import org.lflang.TargetPropertyConfig; -import org.lflang.lf.Element; -import org.lflang.lf.KeyValuePair; -import org.lflang.lf.Model; -import org.lflang.target.CoordinationConfig.CoordinationOption; -import org.lflang.target.property.type.TargetPropertyType; -import org.lflang.target.property.type.PrimitiveType; -import org.lflang.validation.LFValidator.ValidationReporter; - -public class CoordinationConfig implements TargetPropertyConfig { - - @Override - public void parseIntoTargetConfig(TargetConfig config, Element value, MessageReporter err) { - - } - - @Override - public CoordinationOption parse(Element value) { - return null; - } - - @Override - public void validate(KeyValuePair pair, Model ast, TargetConfig config, ValidationReporter reporter) { - - } - - @Override - public Element getPropertyElement(TargetConfig config) { - return null; - } - - /** - * Coordination options. - * - * @author Edward A. Lee - */ - public enum CoordinationOption implements DictionaryElement { - ADVANCE_MESSAGE_INTERVAL("advance-message-interval", PrimitiveType.TIME_VALUE); - - public final PrimitiveType type; - - private final String description; - - private CoordinationOption(String alias, PrimitiveType type) { - this.description = alias; - this.type = type; - } - - /** Return the description of this dictionary element. */ - @Override - public String toString() { - return this.description; - } - - /** Return the type associated with this dictionary element. */ - public TargetPropertyType getType() { - return this.type; - } - } - - /** - * Enumeration of coordination types. - * - * @author Marten Lohstroh - */ - public enum CoordinationType { - CENTRALIZED, - DECENTRALIZED; - - /** Return the name in lower case. */ - @Override - public String toString() { - return this.name().toLowerCase(); - } - } - - -} diff --git a/core/src/main/java/org/lflang/target/CoordinationModeConfig.java b/core/src/main/java/org/lflang/target/CoordinationModeConfig.java new file mode 100644 index 0000000000..b541b4a164 --- /dev/null +++ b/core/src/main/java/org/lflang/target/CoordinationModeConfig.java @@ -0,0 +1,49 @@ +package org.lflang.target; + +import org.lflang.TargetConfig; +import org.lflang.TargetPropertyConfig; +import org.lflang.ast.ASTUtils; +import org.lflang.lf.Element; +import org.lflang.lf.KeyValuePair; +import org.lflang.lf.Model; +import org.lflang.target.CoordinationModeConfig.CoordinationMode; +import org.lflang.target.property.type.UnionType; +import org.lflang.validation.ValidationReporter; + +public class CoordinationModeConfig extends TargetPropertyConfig { + + @Override + public CoordinationMode initialize() { + return CoordinationMode.CENTRALIZED; + } + + @Override + public CoordinationMode parse(Element value) { + return (CoordinationMode) UnionType.COORDINATION_UNION.forName(ASTUtils.elementToSingleString(value)); + } + + @Override + public void validate(KeyValuePair pair, Model ast, TargetConfig config, ValidationReporter reporter) {} + + @Override + public Element export() { + return ASTUtils.toElement(this.value.toString()); + } + + /** + * Enumeration of coordination types. + * + * @author Marten Lohstroh + */ + public enum CoordinationMode { + CENTRALIZED, + DECENTRALIZED; + + /** Return the name in lower case. */ + @Override + public String toString() { + return this.name().toLowerCase(); + } + } + +} diff --git a/core/src/main/java/org/lflang/target/CoordinationOptionsConfig.java b/core/src/main/java/org/lflang/target/CoordinationOptionsConfig.java new file mode 100644 index 0000000000..755ffc73ff --- /dev/null +++ b/core/src/main/java/org/lflang/target/CoordinationOptionsConfig.java @@ -0,0 +1,118 @@ +package org.lflang.target; + +import org.lflang.TargetConfig; + +import org.lflang.TargetProperty.DictionaryElement; +import org.lflang.TargetPropertyConfig; +import org.lflang.TimeValue; +import org.lflang.ast.ASTUtils; +import org.lflang.lf.Element; +import org.lflang.lf.KeyValuePair; +import org.lflang.lf.KeyValuePairs; +import org.lflang.lf.LfFactory; +import org.lflang.lf.Model; +import org.lflang.target.CoordinationOptionsConfig.CoordinationOptions; +import org.lflang.target.property.type.DictionaryType; +import org.lflang.target.property.type.PrimitiveType; +import org.lflang.target.property.type.TargetPropertyType; +import org.lflang.validation.ValidationReporter; + +public class CoordinationOptionsConfig extends TargetPropertyConfig { + + @Override + public CoordinationOptions initialize() { + return new CoordinationOptions(); + } + + @Override + public CoordinationOptions parse(Element value) { + var options = new CoordinationOptions(); + for (KeyValuePair entry : value.getKeyvalue().getPairs()) { + CoordinationOption option = + (CoordinationOption) DictionaryType.COORDINATION_OPTION_DICT.forName(entry.getName()); + switch (option) { + case ADVANCE_MESSAGE_INTERVAL: + options.advanceMessageInterval = + ASTUtils.toTimeValue(entry.getValue()); + break; + default: + break; + } + } + return options; + } + + @Override + public void validate(KeyValuePair pair, Model ast, TargetConfig config, ValidationReporter reporter) { + // FIXME + } + + @Override + public Element export() { + Element e = LfFactory.eINSTANCE.createElement(); + KeyValuePairs kvp = LfFactory.eINSTANCE.createKeyValuePairs(); + for (CoordinationOption opt : CoordinationOption.values()) { + KeyValuePair pair = LfFactory.eINSTANCE.createKeyValuePair(); + pair.setName(opt.toString()); + switch (opt) { + case ADVANCE_MESSAGE_INTERVAL: + if (this.value.advanceMessageInterval == null) { + continue; + } + pair.setValue( + ASTUtils.toElement(value.advanceMessageInterval)); + break; + } + kvp.getPairs().add(pair); + } + e.setKeyvalue(kvp); + if (kvp.getPairs().isEmpty()) { + return null; + } + return e; + } + + /** Settings related to coordination of federated execution. */ + public static class CoordinationOptions { + + /** + * For centralized coordination, if a federate has a physical action that can trigger an output, + * directly or indirectly, then it will send NET (next event tag) messages to the RTI + * periodically as its physical clock advances. This option sets the amount of time to wait + * between sending such messages. Increasing this value results in downstream federates that lag + * further behind physical time (if the "after" delays are insufficient). The default is null, + * which means it is up the implementation to choose an interval. + */ + public TimeValue advanceMessageInterval = null; + } + + /** + * Coordination options. + * + * @author Edward A. Lee + */ + public enum CoordinationOption implements DictionaryElement { + ADVANCE_MESSAGE_INTERVAL("advance-message-interval", PrimitiveType.TIME_VALUE); + + public final PrimitiveType type; + + private final String description; + + private CoordinationOption(String alias, PrimitiveType type) { + this.description = alias; + this.type = type; + } + + /** Return the description of this dictionary element. */ + @Override + public String toString() { + return this.description; + } + + /** Return the type associated with this dictionary element. */ + public TargetPropertyType getType() { + return this.type; + } + } + +} diff --git a/core/src/main/java/org/lflang/target/DockerConfig.java b/core/src/main/java/org/lflang/target/DockerConfig.java index 3853ceb1c7..ebc319b768 100644 --- a/core/src/main/java/org/lflang/target/DockerConfig.java +++ b/core/src/main/java/org/lflang/target/DockerConfig.java @@ -1,28 +1,65 @@ package org.lflang.target; -import org.lflang.MessageReporter; + +import java.util.Properties; + import org.lflang.TargetConfig; +import org.lflang.TargetProperty; +import org.lflang.TargetPropertyConfig; import org.lflang.TargetProperty.DictionaryElement; +import org.lflang.ast.ASTUtils; +import org.lflang.lf.KeyValuePairs; +import org.lflang.lf.LfFactory; +import org.lflang.target.DockerConfig.DockerOptions; +import org.lflang.target.property.type.DictionaryType; import org.lflang.target.property.type.PrimitiveType; import org.lflang.target.property.type.TargetPropertyType; -import org.lflang.TargetPropertyConfig; import org.lflang.lf.Element; import org.lflang.lf.KeyValuePair; import org.lflang.lf.Model; -import org.lflang.target.DockerConfig.DockerOption; -import org.lflang.target.property.type.TargetPropertyType; -import org.lflang.validation.LFValidator.ValidationReporter; +import org.lflang.validation.ValidationReporter; + -public class DockerConfig implements TargetPropertyConfig { +public class DockerConfig extends TargetPropertyConfig { @Override - public void parseIntoTargetConfig(TargetConfig config, Element value, MessageReporter err) { + public DockerOptions initialize() { + return new DockerOptions(false); + } + @Override + public void update(Properties cliArgs) { + var key = TargetProperty.DOCKER.toString(); + if (cliArgs.containsKey(key)) { + var arg = cliArgs.getProperty(key); + if (Boolean.parseBoolean(arg)) { + this.value.enabled = true; + } else { + this.value.enabled = false; + } + } } @Override - public DockerOption parse(Element value) { - return null; + public DockerOptions parse(Element value) { + var options = new DockerOptions(false); + if (value.getLiteral() != null) { + if (ASTUtils.toBoolean(value)) { + options.enabled = true; + } + } else { + for (KeyValuePair entry : value.getKeyvalue().getPairs()) { + DockerOption option = (DockerOption) DictionaryType.DOCKER_DICT.forName(entry.getName()); + switch (option) { + case FROM: + options.from = ASTUtils.elementToSingleString(entry.getValue()); + break; + default: + break; + } + } + } + return options; } @Override @@ -31,10 +68,65 @@ public void validate(KeyValuePair pair, Model ast, TargetConfig config, Validati } @Override - public Element getPropertyElement(TargetConfig config) { - return null; + public Element export() { + if (!this.value.enabled) { + return null; + } else if (this.value.equals(new DockerOptions(true))) { + // default configuration + return ASTUtils.toElement(true); + } else { + Element e = LfFactory.eINSTANCE.createElement(); + KeyValuePairs kvp = LfFactory.eINSTANCE.createKeyValuePairs(); + for (DockerOption opt : DockerOption.values()) { + KeyValuePair pair = LfFactory.eINSTANCE.createKeyValuePair(); + pair.setName(opt.toString()); + switch (opt) { + case FROM: + if (this.value.from == null) { + continue; + } + pair.setValue(ASTUtils.toElement(this.value.from)); + break; + } + kvp.getPairs().add(pair); + } + e.setKeyvalue(kvp); + if (kvp.getPairs().isEmpty()) { + return null; + } + return e; + } } + /** Settings related to Docker options. */ + public static class DockerOptions { + + public boolean enabled; + + public DockerOptions(boolean enabled) { + this.enabled = enabled; + } + + /** + * The base image and tag from which to build the Docker image. The default is "alpine:latest". + */ + public String from = "alpine:latest"; + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + DockerOptions that = (DockerOptions) o; + return from.equals(that.from); + } + } + + + /** * Docker options. * diff --git a/core/src/main/java/org/lflang/target/FastConfigurator.java b/core/src/main/java/org/lflang/target/FastModeConfig.java similarity index 80% rename from core/src/main/java/org/lflang/target/FastConfigurator.java rename to core/src/main/java/org/lflang/target/FastModeConfig.java index d9e4696167..72ded2c473 100644 --- a/core/src/main/java/org/lflang/target/FastConfigurator.java +++ b/core/src/main/java/org/lflang/target/FastModeConfig.java @@ -1,6 +1,5 @@ package org.lflang.target; -import org.lflang.MessageReporter; import org.lflang.TargetConfig; import org.lflang.TargetPropertyConfig; import org.lflang.ast.ASTUtils; @@ -11,13 +10,13 @@ import org.lflang.lf.LfPackage.Literals; import org.lflang.lf.Model; import org.lflang.lf.Reactor; -import org.lflang.validation.LFValidator.ValidationReporter; +import org.lflang.validation.ValidationReporter; -public class FastConfigurator implements TargetPropertyConfig { +public class FastModeConfig extends TargetPropertyConfig { @Override - public void parseIntoTargetConfig(TargetConfig config, Element value, MessageReporter err) { - config.fastMode = this.parse(value); + public Boolean initialize() { + return false; } @Override @@ -58,7 +57,8 @@ public void validate(KeyValuePair pair, Model ast, TargetConfig config, Validati } @Override - public Element getPropertyElement(TargetConfig config) { - return ASTUtils.toElement(config.fastMode); + public Element export() { + return ASTUtils.toElement(this.value); } + } diff --git a/core/src/main/java/org/lflang/target/KeepaliveConfigurator.java b/core/src/main/java/org/lflang/target/KeepaliveConfig.java similarity index 58% rename from core/src/main/java/org/lflang/target/KeepaliveConfigurator.java rename to core/src/main/java/org/lflang/target/KeepaliveConfig.java index 9753084e16..c7059b946d 100644 --- a/core/src/main/java/org/lflang/target/KeepaliveConfigurator.java +++ b/core/src/main/java/org/lflang/target/KeepaliveConfig.java @@ -1,21 +1,32 @@ package org.lflang.target; -import org.lflang.MessageReporter; +import java.util.Properties; + import org.lflang.Target; import org.lflang.TargetConfig; +import org.lflang.TargetProperty; import org.lflang.TargetPropertyConfig; 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.validation.LFValidator.ValidationReporter; +import org.lflang.validation.ValidationReporter; + +public class KeepaliveConfig extends TargetPropertyConfig { -public class KeepaliveConfigurator implements TargetPropertyConfig { + @Override + public Boolean initialize() { + return false; + } @Override - public void parseIntoTargetConfig(TargetConfig config, Element value, MessageReporter err) { - config.keepalive = this.parse(value); + public void update(Properties cliArgs) { + super.update(cliArgs); + var key = TargetProperty.KEEPALIVE.toString(); + if (cliArgs.containsKey(key)) { + this.override(Boolean.parseBoolean(cliArgs.getProperty(TargetProperty.KEEPALIVE.description))); + } } @Override @@ -23,7 +34,6 @@ public Boolean parse(Element value) { return ASTUtils.toBoolean(value); } - @Override public void validate(KeyValuePair pair, Model ast, TargetConfig config, ValidationReporter reporter) { if (pair != null && config.target == Target.CPP) { @@ -36,7 +46,7 @@ public void validate(KeyValuePair pair, Model ast, TargetConfig config, Validati } @Override - public Element getPropertyElement(TargetConfig config) { - return ASTUtils.toElement(config.keepalive); + public Element export() { + return ASTUtils.toElement(this.value); } } diff --git a/core/src/main/java/org/lflang/target/PlatformConfig.java b/core/src/main/java/org/lflang/target/PlatformConfig.java new file mode 100644 index 0000000000..28b8d82a33 --- /dev/null +++ b/core/src/main/java/org/lflang/target/PlatformConfig.java @@ -0,0 +1,253 @@ +package org.lflang.target; + +import java.util.Arrays; + +import org.lflang.TargetConfig; +import org.lflang.TargetProperty; +import org.lflang.TargetProperty.DictionaryElement; +import org.lflang.ast.ASTUtils; +import org.lflang.lf.KeyValuePairs; +import org.lflang.lf.LfFactory; +import org.lflang.lf.LfPackage.Literals; +import org.lflang.target.PlatformConfig.PlatformOptions; +import org.lflang.target.property.type.DictionaryType; +import org.lflang.target.property.type.PrimitiveType; +import org.lflang.target.property.type.TargetPropertyType; +import org.lflang.TargetPropertyConfig; +import org.lflang.lf.Element; +import org.lflang.lf.KeyValuePair; +import org.lflang.lf.Model; +import org.lflang.target.property.type.UnionType; +import org.lflang.validation.ValidationReporter; + +public class PlatformConfig extends TargetPropertyConfig { + + @Override + public PlatformOptions initialize() { + return new PlatformOptions(); + } + + @Override + public PlatformOptions parse(Element value) { // FIXME: pass in err + var config = new PlatformOptions(); + if (value.getLiteral() != null) { + config.platform = + (Platform) UnionType.PLATFORM_UNION.forName(ASTUtils.elementToSingleString(value)); + if (config.platform == null) { + String s = + "Unidentified Platform Type, LF supports the following platform types: " + + Arrays.asList(Platform.values()); + //err.at(value).error(s); + throw new AssertionError(s); + } + } else { + for (KeyValuePair entry : value.getKeyvalue().getPairs()) { + PlatformOption option = + (PlatformOption) DictionaryType.PLATFORM_DICT.forName(entry.getName()); + switch (option) { + case NAME -> { + Platform p = + (Platform) + UnionType.PLATFORM_UNION.forName( + ASTUtils.elementToSingleString(entry.getValue())); + if (p == null) { + String s = + "Unidentified Platform Type, LF supports the following platform types: " + + Arrays.asList(Platform.values()); + //err.at(entry).error(s); // FIXME + throw new AssertionError(s); + } + config.platform = p; + } + case BAUDRATE -> config.baudRate = ASTUtils.toInteger(entry.getValue()); + case BOARD -> config.board = ASTUtils.elementToSingleString(entry.getValue()); + case FLASH -> config.flash = ASTUtils.toBoolean(entry.getValue()); + case PORT -> config.port = ASTUtils.elementToSingleString(entry.getValue()); + case USER_THREADS -> config.userThreads = ASTUtils.toInteger(entry.getValue()); + default -> { + } + } + } + } + // If the platform does not support threading, disable it. +// if (!config.platform.isMultiThreaded()) { +// config.threading = false; // FIXME: this should instead be dealt with in the validator +// } + return config; + } + + @Override + public void validate(KeyValuePair pair, Model ast, TargetConfig config, ValidationReporter reporter) { + var threading = TargetProperty.getKeyValuePair(ast, TargetProperty.THREADING); + if (threading != null) { + if (pair != null && ASTUtils.toBoolean(threading.getValue())) { + var lit = ASTUtils.elementToSingleString(pair.getValue()); + var dic = pair.getValue().getKeyvalue(); + if (lit != null && lit.equalsIgnoreCase(Platform.RP2040.toString())) { + reporter.error( + "Platform " + Platform.RP2040 + " does not support threading", + pair, + Literals.KEY_VALUE_PAIR__VALUE); + } + if (dic != null) { + var rp = + dic.getPairs().stream() + .filter( + kv -> + kv.getName().equalsIgnoreCase("name") + && ASTUtils.elementToSingleString(kv.getValue()) + .equalsIgnoreCase(Platform.RP2040.toString())) + .findFirst(); + rp.ifPresent(keyValuePair -> reporter.error( + "Platform " + Platform.RP2040 + " does not support threading", + keyValuePair, + Literals.KEY_VALUE_PAIR__VALUE)); + } + } + } + } + + @Override + public Element export() { + Element e = LfFactory.eINSTANCE.createElement(); + KeyValuePairs kvp = LfFactory.eINSTANCE.createKeyValuePairs(); + for (PlatformOption opt : PlatformOption.values()) { + KeyValuePair pair = LfFactory.eINSTANCE.createKeyValuePair(); + pair.setName(opt.toString()); + switch (opt) { + case NAME -> pair.setValue(ASTUtils.toElement(value.platform.toString())); + case BAUDRATE -> pair.setValue(ASTUtils.toElement(value.baudRate)); + case BOARD -> pair.setValue(ASTUtils.toElement(value.board)); + case FLASH -> pair.setValue(ASTUtils.toElement(value.flash)); + case PORT -> pair.setValue(ASTUtils.toElement(value.port)); + case USER_THREADS -> pair.setValue(ASTUtils.toElement(value.userThreads)); + } + kvp.getPairs().add(pair); + } + e.setKeyvalue(kvp); + if (kvp.getPairs().isEmpty()) { + return null; + } + return e; + } + + + /** Settings related to Platform Options. */ + public static class PlatformOptions { + + /** + * The base platform we build our LF Files on. Should be set to AUTO by default unless + * developing for specific OS/Embedded Platform + */ + public Platform platform = Platform.AUTO; + + /** + * The string value used to determine what type of embedded board we work with and can be used + * to simplify the build process. This string has the form "board_name[:option]*" (zero or more + * options separated by colons). For example, "pico:usb" specifies a Raspberry Pi Pico where + * stdin and stdout go through a USB serial port. + */ + public String board = null; + + /** + * The string value used to determine the port on which to flash the compiled program (i.e. + * /dev/cu.usbmodem21301) + */ + public String port = null; + + /** + * The baud rate used as a parameter to certain embedded platforms. 9600 is a standard rate + * amongst systems like Arduino, so it's the default value. + */ + public int baudRate = 9600; + + /** + * The boolean statement used to determine whether we should automatically attempt to flash once + * we compile. This may require the use of board and port values depending on the infrastructure + * you use to flash the boards. + */ + public boolean flash = false; + + /** + * The int value is used to determine the number of needed threads for the user application in + * Zephyr. + */ + public int userThreads = 0; + } + + + /** Enumeration of supported platforms */ + public enum Platform { + AUTO, + ARDUINO, + NRF52("Nrf52", true), + RP2040("Rp2040", false), + LINUX("Linux", true), + MAC("Darwin", true), + ZEPHYR("Zephyr", true), + WINDOWS("Windows", true); + + final String cMakeName; + + private boolean multiThreaded = true; + + Platform() { + this.cMakeName = this.toString(); + } + + Platform(String cMakeName, boolean isMultiThreaded) { + this.cMakeName = cMakeName; + this.multiThreaded = isMultiThreaded; + } + + /** Return the name in lower case. */ + @Override + public String toString() { + return this.name().toLowerCase(); + } + + /** Get the CMake name for the platform. */ + public String getcMakeName() { + return this.cMakeName; + } + + public boolean isMultiThreaded() { + return this.multiThreaded; + } + } + + /** + * Platform options. + * + * @author Anirudh Rengarajan + */ + public enum PlatformOption implements DictionaryElement { + NAME("name", PrimitiveType.STRING), + BAUDRATE("baud-rate", PrimitiveType.NON_NEGATIVE_INTEGER), + BOARD("board", PrimitiveType.STRING), + FLASH("flash", PrimitiveType.BOOLEAN), + PORT("port", PrimitiveType.STRING), + USER_THREADS("user-threads", PrimitiveType.NON_NEGATIVE_INTEGER); + + public final PrimitiveType type; + + private final String description; + + PlatformOption(String alias, PrimitiveType type) { + this.description = alias; + this.type = type; + } + + /** Return the description of this dictionary element. */ + @Override + public String toString() { + return this.description; + } + + /** Return the type associated with this dictionary element. */ + public TargetPropertyType getType() { + return this.type; + } + } + +} diff --git a/core/src/main/java/org/lflang/target/PlatformConfigurator.java b/core/src/main/java/org/lflang/target/PlatformConfigurator.java deleted file mode 100644 index 542323efe1..0000000000 --- a/core/src/main/java/org/lflang/target/PlatformConfigurator.java +++ /dev/null @@ -1,142 +0,0 @@ -package org.lflang.target; - -import org.lflang.MessageReporter; -import org.lflang.TargetConfig; -import org.lflang.TargetProperty; -import org.lflang.TargetProperty.DictionaryElement; -import org.lflang.ast.ASTUtils; -import org.lflang.lf.LfPackage.Literals; -import org.lflang.target.property.type.PrimitiveType; -import org.lflang.target.property.type.TargetPropertyType; -import org.lflang.TargetPropertyConfig; -import org.lflang.lf.Element; -import org.lflang.lf.KeyValuePair; -import org.lflang.lf.Model; -import org.lflang.target.PlatformConfigurator.PlatformOption; -import org.lflang.validation.LFValidator.ValidationReporter; - -public class PlatformConfigurator implements TargetPropertyConfig { - - @Override - public void parseIntoTargetConfig(TargetConfig config, Element value, MessageReporter err) { - - } - - @Override - public PlatformOption parse(Element value) { - return null; - } - - @Override - public void validate(KeyValuePair pair, Model ast, TargetConfig config, ValidationReporter reporter) { - var threading = TargetProperty.getKeyValuePair(ast, TargetProperty.THREADING); - if (threading != null) { - if (pair != null && ASTUtils.toBoolean(threading.getValue())) { - var lit = ASTUtils.elementToSingleString(pair.getValue()); - var dic = pair.getValue().getKeyvalue(); - if (lit != null && lit.equalsIgnoreCase(Platform.RP2040.toString())) { - reporter.error( - "Platform " + Platform.RP2040 + " does not support threading", - pair, - Literals.KEY_VALUE_PAIR__VALUE); - } - if (dic != null) { - var rp = - dic.getPairs().stream() - .filter( - kv -> - kv.getName().equalsIgnoreCase("name") - && ASTUtils.elementToSingleString(kv.getValue()) - .equalsIgnoreCase(Platform.RP2040.toString())) - .findFirst(); - if (rp.isPresent()) { - reporter.error( - "Platform " + Platform.RP2040 + " does not support threading", - rp.get(), - Literals.KEY_VALUE_PAIR__VALUE); - } - } - } - } - } - - @Override - public Element getPropertyElement(TargetConfig config) { - return null; - } - - /** Enumeration of supported platforms */ - public enum Platform { - AUTO, - ARDUINO, - NRF52("Nrf52", true), - RP2040("Rp2040", false), - LINUX("Linux", true), - MAC("Darwin", true), - ZEPHYR("Zephyr", true), - WINDOWS("Windows", true); - - String cMakeName; - - private boolean multiThreaded = true; - - Platform() { - this.cMakeName = this.toString(); - } - - Platform(String cMakeName, boolean isMultiThreaded) { - this.cMakeName = cMakeName; - this.multiThreaded = isMultiThreaded; - } - - /** Return the name in lower case. */ - @Override - public String toString() { - return this.name().toLowerCase(); - } - - /** Get the CMake name for the platform. */ - public String getcMakeName() { - return this.cMakeName; - } - - public boolean isMultiThreaded() { - return this.multiThreaded; - } - } - - /** - * Platform options. - * - * @author Anirudh Rengarajan - */ - public enum PlatformOption implements DictionaryElement { - NAME("name", PrimitiveType.STRING), - BAUDRATE("baud-rate", PrimitiveType.NON_NEGATIVE_INTEGER), - BOARD("board", PrimitiveType.STRING), - FLASH("flash", PrimitiveType.BOOLEAN), - PORT("port", PrimitiveType.STRING), - USER_THREADS("user-threads", PrimitiveType.NON_NEGATIVE_INTEGER); - - public final PrimitiveType type; - - private final String description; - - private PlatformOption(String alias, PrimitiveType type) { - this.description = alias; - this.type = type; - } - - /** Return the description of this dictionary element. */ - @Override - public String toString() { - return this.description; - } - - /** Return the type associated with this dictionary element. */ - public TargetPropertyType getType() { - return this.type; - } - } - -} diff --git a/core/src/main/java/org/lflang/target/Ros2DependenciesConfigurator.java b/core/src/main/java/org/lflang/target/Ros2DependenciesConfig.java similarity index 69% rename from core/src/main/java/org/lflang/target/Ros2DependenciesConfigurator.java rename to core/src/main/java/org/lflang/target/Ros2DependenciesConfig.java index f1c6ac9eae..176cc3d6bc 100644 --- a/core/src/main/java/org/lflang/target/Ros2DependenciesConfigurator.java +++ b/core/src/main/java/org/lflang/target/Ros2DependenciesConfig.java @@ -1,5 +1,7 @@ package org.lflang.target; +import java.util.List; + import org.lflang.MessageReporter; import org.lflang.TargetConfig; import org.lflang.TargetProperty; @@ -9,18 +11,19 @@ import org.lflang.lf.KeyValuePair; import org.lflang.lf.LfPackage.Literals; import org.lflang.lf.Model; -import org.lflang.validation.LFValidator.ValidationReporter; +import org.lflang.validation.ValidationReporter; -public class Ros2DependenciesConfigurator implements TargetPropertyConfig { +public class Ros2DependenciesConfig extends TargetPropertyConfig> { - @Override - public void parseIntoTargetConfig(TargetConfig config, Element value, MessageReporter err) { + @Override + public List initialize() { + return null; // FIXME } @Override - public Boolean parse(Element value) { - return null; + public List parse(Element value) { + return ASTUtils.elementToListOfStrings(value); } @Override @@ -35,7 +38,8 @@ public void validate(KeyValuePair pair, Model ast, TargetConfig config, Validati } @Override - public Element getPropertyElement(TargetConfig config) { - return null; + public Element export() { + return ASTUtils.toElement(value); } + } diff --git a/core/src/main/java/org/lflang/target/SchedulerConfigurator.java b/core/src/main/java/org/lflang/target/SchedulerConfig.java similarity index 79% rename from core/src/main/java/org/lflang/target/SchedulerConfigurator.java rename to core/src/main/java/org/lflang/target/SchedulerConfig.java index 5bedf0494a..9f90ea6d6c 100644 --- a/core/src/main/java/org/lflang/target/SchedulerConfigurator.java +++ b/core/src/main/java/org/lflang/target/SchedulerConfig.java @@ -2,33 +2,55 @@ import java.nio.file.Path; import java.util.List; +import java.util.Properties; import org.lflang.MessageReporter; import org.lflang.TargetConfig; +import org.lflang.TargetProperty; import org.lflang.TargetPropertyConfig; 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.SchedulerConfigurator.SchedulerOption; + +import org.lflang.target.SchedulerConfig.SchedulerOption; import org.lflang.target.property.type.UnionType; -import org.lflang.validation.LFValidator.ValidationReporter; +import org.lflang.validation.ValidationReporter; + import com.google.common.collect.ImmutableList; -public class SchedulerConfigurator implements TargetPropertyConfig { +public class SchedulerConfig extends TargetPropertyConfig { @Override - public void parseIntoTargetConfig(TargetConfig config, Element value, MessageReporter err) { - config.schedulerType = this.parse(value); + public SchedulerOption initialize() { + return SchedulerOption.getDefault(); + } + @Override + public void update(Properties cliArgs) { + super.update(cliArgs); + var key = TargetProperty.SCHEDULER.toString(); + if (cliArgs.containsKey(key)) { + value = SchedulerOption.valueOf(cliArgs.getProperty("scheduler")); + } } @Override public SchedulerOption parse(Element value) { - return (SchedulerOption) + var scheduler = (SchedulerOption) UnionType.SCHEDULER_UNION.forName(ASTUtils.elementToSingleString(value)); + if (scheduler != null) { + return scheduler; + } else { + return SchedulerOption.getDefault(); + } + } + + @Override + public Element export() { + return ASTUtils.toElement(this.value.toString()); } @Override @@ -65,10 +87,6 @@ public void validate(KeyValuePair pair, Model ast, TargetConfig config, Validati } - @Override - public Element getPropertyElement(TargetConfig config) { - return ASTUtils.toElement(config.schedulerType.toString()); - } /** * Supported schedulers. @@ -86,9 +104,9 @@ public enum SchedulerOption { Path.of("data_collection.h"))), GEDF_NP(true), // Global EDF non-preemptive GEDF_NP_CI(true); // Global EDF non-preemptive with chain ID - // PEDF_NP(true); // Partitioned EDF non-preemptive (FIXME: To be re-added in a future PR) - /** Indicate whether or not the scheduler prioritizes reactions by deadline. */ + + /** Indicate whether the scheduler prioritizes reactions by deadline. */ private final boolean prioritizesDeadline; /** Relative paths to files required by this scheduler. */ diff --git a/core/src/main/java/org/lflang/target/TracingConfigurator.java b/core/src/main/java/org/lflang/target/TracingConfig.java similarity index 72% rename from core/src/main/java/org/lflang/target/TracingConfigurator.java rename to core/src/main/java/org/lflang/target/TracingConfig.java index ef47b9ad5d..926291e348 100644 --- a/core/src/main/java/org/lflang/target/TracingConfigurator.java +++ b/core/src/main/java/org/lflang/target/TracingConfig.java @@ -1,14 +1,15 @@ package org.lflang.target; -import org.lflang.MessageReporter; +import java.util.Objects; + import org.lflang.TargetConfig; -import org.lflang.TargetConfig.TracingOptions; import org.lflang.TargetProperty; import org.lflang.TargetProperty.DictionaryElement; +import org.lflang.TargetPropertyConfig; +import org.lflang.target.TracingConfig.TracingOptions; import org.lflang.target.property.type.DictionaryType; import org.lflang.target.property.type.PrimitiveType; import org.lflang.target.property.type.TargetPropertyType; -import org.lflang.TargetPropertyConfig; import org.lflang.ast.ASTUtils; import org.lflang.lf.Element; import org.lflang.lf.KeyValuePair; @@ -16,23 +17,22 @@ import org.lflang.lf.LfFactory; import org.lflang.lf.LfPackage.Literals; import org.lflang.lf.Model; -import org.lflang.validation.LFValidator.ValidationReporter; +import org.lflang.validation.ValidationReporter; + +public class TracingConfig extends TargetPropertyConfig { -public class TracingConfigurator implements TargetPropertyConfig { @Override - public void parseIntoTargetConfig(TargetConfig config, Element value, MessageReporter err) { - config.tracing = parse(value); + public TracingOptions initialize() { + return new TracingOptions(); } @Override public TracingOptions parse(Element value) { var options = new TracingOptions(); if (value.getLiteral() != null) { - if (ASTUtils.toBoolean(value)) { - return options; - } else { - return null; + if (!ASTUtils.toBoolean(value)) { + options.enabled = false; } } else { for (KeyValuePair entry : value.getKeyvalue().getPairs()) { @@ -46,8 +46,8 @@ public TracingOptions parse(Element value) { break; } } - return options; } + return options; } @Override @@ -71,10 +71,10 @@ public void validate(KeyValuePair pair, Model ast, TargetConfig config, Validati } @Override - public Element getPropertyElement(TargetConfig config) { - if (config.tracing == null) { + public Element export() { + if (this.value.isEnabled()) { return null; - } else if (config.tracing.equals(new TracingOptions())) { + } else if (this.value.equals(new TracingOptions())) { // default values return ASTUtils.toElement(true); } else { @@ -85,10 +85,10 @@ public Element getPropertyElement(TargetConfig config) { pair.setName(opt.toString()); switch (opt) { case TRACE_FILE_NAME: - if (config.tracing.traceFileName == null) { + if (this.value.traceFileName == null) { continue; } - pair.setValue(ASTUtils.toElement(config.tracing.traceFileName)); + pair.setValue(ASTUtils.toElement(this.value.traceFileName)); } kvp.getPairs().add(pair); } @@ -100,6 +100,35 @@ public Element getPropertyElement(TargetConfig config) { } } + /** Settings related to tracing options. */ + public static class TracingOptions { + + protected boolean enabled = true; + + /** + * The name to use as the root of the trace file produced. This defaults to the name of the .lf + * file. + */ + public String traceFileName = null; + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + TracingOptions that = (TracingOptions) o; + return Objects.equals(traceFileName, that.traceFileName); // traceFileName may be null + } + + public boolean isEnabled() { + return enabled; + } + } + + /** * Tracing options. * diff --git a/core/src/main/java/org/lflang/target/property/BuildCommandsConfig.java b/core/src/main/java/org/lflang/target/property/BuildCommandsConfig.java new file mode 100644 index 0000000000..22458f8a76 --- /dev/null +++ b/core/src/main/java/org/lflang/target/property/BuildCommandsConfig.java @@ -0,0 +1,27 @@ +package org.lflang.target.property; + +import java.util.ArrayList; +import java.util.List; + +import org.lflang.TargetPropertyConfig; +import org.lflang.ast.ASTUtils; +import org.lflang.lf.Element; + +public class BuildCommandsConfig extends TargetPropertyConfig> { + + @Override + public List initialize() { + return new ArrayList<>(); + } + + @Override + public List parse(Element value) { + return ASTUtils.elementToListOfStrings(value); + } + + @Override + public Element export() { + return ASTUtils.toElement(this.value.toString()); + } + +} diff --git a/core/src/main/java/org/lflang/target/property/BuildTypeConfig.java b/core/src/main/java/org/lflang/target/property/BuildTypeConfig.java new file mode 100644 index 0000000000..28e2e37cfe --- /dev/null +++ b/core/src/main/java/org/lflang/target/property/BuildTypeConfig.java @@ -0,0 +1,38 @@ +package org.lflang.target.property; + +import java.util.Properties; + +import org.lflang.TargetProperty; +import org.lflang.TargetPropertyConfig; +import org.lflang.ast.ASTUtils; +import org.lflang.lf.Element; +import org.lflang.target.property.BuildConfig.BuildType; +import org.lflang.target.property.type.UnionType; + +public class BuildTypeConfig extends TargetPropertyConfig { + + @Override + public Element export() { + return ASTUtils.toElement(this.value.toString()); + } + + @Override + public BuildType initialize() { + return BuildType.RELEASE; + } + + @Override + public BuildType parse(Element value) { + return (BuildType) UnionType.BUILD_TYPE_UNION.forName(ASTUtils.elementToSingleString(value)); + } + + @Override + public void update(Properties cliArgs) { + super.update(cliArgs); + var key = TargetProperty.BUILD_TYPE.toString(); + if (cliArgs.containsKey(key)) { + this.value = + (BuildType) UnionType.BUILD_TYPE_UNION.forName(cliArgs.getProperty(key)); + } + } +} diff --git a/core/src/main/java/org/lflang/target/property/ClockSyncOptionsConfig.java b/core/src/main/java/org/lflang/target/property/ClockSyncOptionsConfig.java new file mode 100644 index 0000000000..9e984318a4 --- /dev/null +++ b/core/src/main/java/org/lflang/target/property/ClockSyncOptionsConfig.java @@ -0,0 +1,157 @@ +package org.lflang.target.property; + +import org.lflang.TargetConfig; +import org.lflang.TargetProperty.DictionaryElement; +import org.lflang.TargetPropertyConfig; +import org.lflang.TimeUnit; +import org.lflang.TimeValue; +import org.lflang.ast.ASTUtils; +import org.lflang.lf.Element; +import org.lflang.lf.KeyValuePair; +import org.lflang.lf.KeyValuePairs; +import org.lflang.lf.LfFactory; +import org.lflang.lf.Model; +import org.lflang.target.property.ClockSyncOptionsConfig.ClockSyncOptions; +import org.lflang.target.property.type.DictionaryType; +import org.lflang.target.property.type.PrimitiveType; +import org.lflang.target.property.type.TargetPropertyType; +import org.lflang.validation.ValidationReporter; + +public class ClockSyncOptionsConfig extends TargetPropertyConfig { + + @Override + public ClockSyncOptions initialize() { + return new ClockSyncOptions(); + } + + @Override + public ClockSyncOptions parse(Element value) { + var options = new ClockSyncOptions(); + for (KeyValuePair entry : value.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 -> { + } + } + } + return options; + } + + @Override + public void validate(KeyValuePair pair, Model ast, TargetConfig config, ValidationReporter reporter) { + + } + + @Override + public Element export() { + Element e = LfFactory.eINSTANCE.createElement(); + KeyValuePairs kvp = LfFactory.eINSTANCE.createKeyValuePairs(); + for (ClockSyncOption opt : ClockSyncOption.values()) { + KeyValuePair pair = LfFactory.eINSTANCE.createKeyValuePair(); + pair.setName(opt.toString()); + switch (opt) { + case ATTENUATION -> pair.setValue(ASTUtils.toElement(value.attenuation)); + case COLLECT_STATS -> pair.setValue(ASTUtils.toElement(value.collectStats)); + case LOCAL_FEDERATES_ON -> pair.setValue(ASTUtils.toElement(value.localFederatesOn)); + case PERIOD -> { + if (value.period == null) { + continue; // don't set if null + } + pair.setValue(ASTUtils.toElement(value.period)); + } + case TEST_OFFSET -> { + if (value.testOffset == null) { + continue; // don't set if null + } + pair.setValue(ASTUtils.toElement(value.testOffset)); + } + case TRIALS -> pair.setValue(ASTUtils.toElement(value.trials)); + } + kvp.getPairs().add(pair); + } + e.setKeyvalue(kvp); + // kvp will never be empty + return e; + } + + /** Settings related to clock synchronization. */ + public static class ClockSyncOptions { + + /** + * Dampen the adjustments to the clock synchronization offset by this rate. The default is 10. + */ + public int attenuation = 10; + + /** + * Whether to collect statistics while performing clock synchronization. This setting is only + * considered when clock synchronization has been activated. The default is true. + */ + public boolean collectStats = true; + + /** Enable clock synchronization for federates on the same machine. Default is false. */ + public boolean localFederatesOn = false; + + /** + * Interval at which clock synchronization is initiated by the RTI (will be passed to it as an + * argument on the command-line). The default is 5 milliseconds. + */ + public TimeValue period = new TimeValue(5, TimeUnit.MILLI); + + /** + * Indicate the number of exchanges to be had per each clock synchronization round. See + * /lib/core/federated/clock-sync.h for more details. The default is 10. + */ + public int trials = 10; + + /** + * Used to create an artificial clock synchronization error for the purpose of testing. The + * default is null. + */ + public TimeValue testOffset; + } + + + + /** + * Clock synchronization options. + * + * @author Marten Lohstroh + */ + public enum ClockSyncOption implements DictionaryElement { + ATTENUATION("attenuation", PrimitiveType.NON_NEGATIVE_INTEGER), + LOCAL_FEDERATES_ON("local-federates-on", PrimitiveType.BOOLEAN), + PERIOD("period", PrimitiveType.TIME_VALUE), + TEST_OFFSET("test-offset", PrimitiveType.TIME_VALUE), + TRIALS("trials", PrimitiveType.NON_NEGATIVE_INTEGER), + COLLECT_STATS("collect-stats", PrimitiveType.BOOLEAN); + + public final PrimitiveType type; + + private final String description; + + ClockSyncOption(String alias, PrimitiveType type) { + this.description = alias; + this.type = type; + } + + /** Return the description of this dictionary element. */ + @Override + public String toString() { + return this.description; + } + + /** Return the type associated with this dictionary element. */ + public TargetPropertyType getType() { + return this.type; + } + } + +} diff --git a/core/src/main/java/org/lflang/target/property/type/DictionaryType.java b/core/src/main/java/org/lflang/target/property/type/DictionaryType.java index e26d2ba122..7f4ba7e44f 100644 --- a/core/src/main/java/org/lflang/target/property/type/DictionaryType.java +++ b/core/src/main/java/org/lflang/target/property/type/DictionaryType.java @@ -10,11 +10,11 @@ import org.lflang.lf.Element; import org.lflang.lf.KeyValuePair; import org.lflang.lf.KeyValuePairs; -import org.lflang.target.ClockSyncConfigurator.ClockSyncOption; -import org.lflang.target.CoordinationConfig.CoordinationOption; +import org.lflang.target.CoordinationOptionsConfig.CoordinationOption; import org.lflang.target.DockerConfig.DockerOption; -import org.lflang.target.PlatformConfigurator.PlatformOption; -import org.lflang.target.TracingConfigurator.TracingOption; +import org.lflang.target.PlatformConfig.PlatformOption; +import org.lflang.target.TracingConfig.TracingOption; +import org.lflang.target.property.ClockSyncOptionsConfig.ClockSyncOption; import org.lflang.validation.LFValidator; /** diff --git a/core/src/main/java/org/lflang/target/property/type/UnionType.java b/core/src/main/java/org/lflang/target/property/type/UnionType.java index 51ef4debb4..4703605b09 100644 --- a/core/src/main/java/org/lflang/target/property/type/UnionType.java +++ b/core/src/main/java/org/lflang/target/property/type/UnionType.java @@ -8,11 +8,11 @@ import org.lflang.Target; import org.lflang.ast.ASTUtils; import org.lflang.lf.Element; -import org.lflang.target.ClockSyncConfigurator.ClockSyncMode; -import org.lflang.target.CoordinationConfig.CoordinationType; +import org.lflang.target.ClockSyncModeConfig.ClockSyncMode; +import org.lflang.target.CoordinationModeConfig.CoordinationMode; import org.lflang.target.LoggingConfigurator.LogLevel; -import org.lflang.target.PlatformConfigurator.Platform; -import org.lflang.target.SchedulerConfigurator.SchedulerOption; +import org.lflang.target.PlatformConfig.Platform; +import org.lflang.target.SchedulerConfig.SchedulerOption; import org.lflang.target.property.BuildConfig.BuildType; import org.lflang.validation.LFValidator; @@ -27,7 +27,7 @@ public enum UnionType implements TargetPropertyType { Arrays.asList(PrimitiveType.STRING, DictionaryType.PLATFORM_DICT), null), FILE_OR_FILE_ARRAY(Arrays.asList(PrimitiveType.FILE, ArrayType.FILE_ARRAY), null), BUILD_TYPE_UNION(Arrays.asList(BuildType.values()), null), - COORDINATION_UNION(Arrays.asList(CoordinationType.values()), CoordinationType.CENTRALIZED), + COORDINATION_UNION(Arrays.asList(CoordinationMode.values()), CoordinationMode.CENTRALIZED), SCHEDULER_UNION(Arrays.asList(SchedulerOption.values()), SchedulerOption.getDefault()), LOGGING_UNION(Arrays.asList(LogLevel.values()), LogLevel.INFO), PLATFORM_UNION(Arrays.asList(Platform.values()), Platform.AUTO), diff --git a/core/src/main/java/org/lflang/util/ArduinoUtil.java b/core/src/main/java/org/lflang/util/ArduinoUtil.java index 13f854f9c7..4903f8c719 100644 --- a/core/src/main/java/org/lflang/util/ArduinoUtil.java +++ b/core/src/main/java/org/lflang/util/ArduinoUtil.java @@ -68,11 +68,11 @@ private LFCommand arduinoCompileCommand(FileConfig fileConfig, TargetConfig targ var fileWriter = new FileWriter(testScript.getAbsoluteFile(), true); BufferedWriter bufferedWriter = new BufferedWriter(fileWriter); String board = - targetConfig.platformOptions.board != null - ? targetConfig.platformOptions.board + targetConfig.platformOptions.get().board != null + ? targetConfig.platformOptions.get().board : "arduino:avr:leonardo"; String isThreaded = - targetConfig.platformOptions.board.contains("mbed") + targetConfig.platformOptions.get().board.contains("mbed") ? "-DLF_THREADED" : "-DLF_UNTHREADED"; bufferedWriter.write( @@ -122,8 +122,8 @@ public void buildArduino(FileConfig fileConfig, TargetConfig targetConfig) { "SUCCESS: Compiling generated code for " + fileConfig.name + " finished with no errors."); - if (targetConfig.platformOptions.flash) { - if (targetConfig.platformOptions.port != null) { + if (targetConfig.platformOptions.get().flash) { + if (targetConfig.platformOptions.get().port != null) { messageReporter.nowhere().info("Invoking flash command for Arduino"); LFCommand flash = commandFactory.createCommand( @@ -131,9 +131,9 @@ public void buildArduino(FileConfig fileConfig, TargetConfig targetConfig) { List.of( "upload", "-b", - targetConfig.platformOptions.board, + targetConfig.platformOptions.get().board, "-p", - targetConfig.platformOptions.port), + targetConfig.platformOptions.get().port), fileConfig.getSrcGenPath()); if (flash == null) { messageReporter.nowhere().error("Could not create arduino-cli flash command."); diff --git a/core/src/main/kotlin/org/lflang/generator/cpp/CppExtensions.kt b/core/src/main/kotlin/org/lflang/generator/cpp/CppExtensions.kt index 45a39eb68a..bd0d0a3a46 100644 --- a/core/src/main/kotlin/org/lflang/generator/cpp/CppExtensions.kt +++ b/core/src/main/kotlin/org/lflang/generator/cpp/CppExtensions.kt @@ -13,6 +13,7 @@ import org.lflang.lf.TriggerRef import org.lflang.lf.VarRef import org.lflang.lf.Visibility import org.lflang.lf.WidthSpec +import org.lflang.target.LoggingConfigurator.LogLevel /************* * Copyright (c) 2019-2021, TU Dresden. @@ -67,12 +68,10 @@ fun Expression.toCppCode(inferredType: InferredType? = null): String = /** - * Convert a value to a time representation in C++ code* + * Convert a value to a time representation in C++ code * * If the value evaluates to 0, it is interpreted as a time. * - * @param outerContext A flag indicating whether to generate code for the scope of the outer reactor class. - * This should be set to false if called from code generators for the inner class. */ fun Expression?.toCppTime(): String = this?.toCppCode(inferredType = InferredType.time()) ?: "reactor::Duration::zero()" @@ -140,13 +139,13 @@ val InferredType.cppType: String /** Convert a log level to a severity number understood by the reactor-cpp runtime. */ -val TargetProperty.LogLevel.severity +val LogLevel.severity get() = when (this) { - TargetProperty.LogLevel.ERROR -> 1 - TargetProperty.LogLevel.WARN -> 2 - TargetProperty.LogLevel.INFO -> 3 - TargetProperty.LogLevel.LOG -> 4 - TargetProperty.LogLevel.DEBUG -> 4 + LogLevel.ERROR -> 1 + LogLevel.WARN -> 2 + LogLevel.INFO -> 3 + LogLevel.LOG -> 4 + LogLevel.DEBUG -> 4 } fun Reactor.hasBankIndexParameter() = parameters.firstOrNull { it.name == "bank_index" } != null diff --git a/core/src/main/kotlin/org/lflang/generator/cpp/CppPlatformGenerator.kt b/core/src/main/kotlin/org/lflang/generator/cpp/CppPlatformGenerator.kt index e2106456b8..eefa2fa0cd 100644 --- a/core/src/main/kotlin/org/lflang/generator/cpp/CppPlatformGenerator.kt +++ b/core/src/main/kotlin/org/lflang/generator/cpp/CppPlatformGenerator.kt @@ -25,7 +25,7 @@ abstract class CppPlatformGenerator(protected val generator: CppGenerator) { protected val cmakeArgs: List get() = listOf( - "-DCMAKE_BUILD_TYPE=${targetConfig.cmakeBuildType}", + "-DCMAKE_BUILD_TYPE=${targetConfig.buildType}", "-DREACTOR_CPP_VALIDATE=${if (targetConfig.noRuntimeValidation) "OFF" else "ON"}", "-DREACTOR_CPP_PRINT_STATISTICS=${if (targetConfig.printStatistics) "ON" else "OFF"}", "-DREACTOR_CPP_TRACE=${if (targetConfig.tracing != null) "ON" else "OFF"}", diff --git a/core/src/main/kotlin/org/lflang/generator/cpp/CppRos2PackageGenerator.kt b/core/src/main/kotlin/org/lflang/generator/cpp/CppRos2PackageGenerator.kt index b4e00262aa..d49ed3d2b6 100644 --- a/core/src/main/kotlin/org/lflang/generator/cpp/CppRos2PackageGenerator.kt +++ b/core/src/main/kotlin/org/lflang/generator/cpp/CppRos2PackageGenerator.kt @@ -60,7 +60,7 @@ class CppRos2PackageGenerator(generator: CppGenerator, private val nodeName: Str |set(CMAKE_CXX_STANDARD_REQUIRED ON) |set(CMAKE_CXX_EXTENSIONS OFF) | - |set(DEFAULT_BUILD_TYPE "${targetConfig.cmakeBuildType}") + |set(DEFAULT_BUILD_TYPE "${targetConfig.buildType}") |if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) |set (CMAKE_BUILD_TYPE "$S{DEFAULT_BUILD_TYPE}" CACHE STRING "Choose the type of build." FORCE) |endif() diff --git a/core/src/main/kotlin/org/lflang/generator/cpp/CppStandaloneCmakeGenerator.kt b/core/src/main/kotlin/org/lflang/generator/cpp/CppStandaloneCmakeGenerator.kt index 1464d6514f..c64ef9b47f 100644 --- a/core/src/main/kotlin/org/lflang/generator/cpp/CppStandaloneCmakeGenerator.kt +++ b/core/src/main/kotlin/org/lflang/generator/cpp/CppStandaloneCmakeGenerator.kt @@ -79,7 +79,7 @@ class CppStandaloneCmakeGenerator(private val targetConfig: TargetConfig, privat |include($S{CMAKE_ROOT}/Modules/ExternalProject.cmake) |include(GNUInstallDirs) | - |set(DEFAULT_BUILD_TYPE "${targetConfig.cmakeBuildType}") + |set(DEFAULT_BUILD_TYPE "${targetConfig.buildType}") |if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) |set (CMAKE_BUILD_TYPE "$S{DEFAULT_BUILD_TYPE}" CACHE STRING "Choose the type of build." FORCE) |endif() diff --git a/core/src/main/kotlin/org/lflang/generator/cpp/CppStandaloneGenerator.kt b/core/src/main/kotlin/org/lflang/generator/cpp/CppStandaloneGenerator.kt index 45fa65f4f5..192a5c62a4 100644 --- a/core/src/main/kotlin/org/lflang/generator/cpp/CppStandaloneGenerator.kt +++ b/core/src/main/kotlin/org/lflang/generator/cpp/CppStandaloneGenerator.kt @@ -1,6 +1,6 @@ package org.lflang.generator.cpp -import org.lflang.TargetProperty +import org.lflang.target.property.BuildConfig.BuildType import org.lflang.generator.CodeMap import org.lflang.generator.LFGeneratorContext import org.lflang.toUnixString @@ -130,9 +130,9 @@ class CppStandaloneGenerator(generator: CppGenerator) : return 0 } - private fun buildTypeToCmakeConfig(type: TargetProperty.BuildType?) = when (type) { + private fun buildTypeToCmakeConfig(type: BuildType?) = when (type) { null -> "Release" - TargetProperty.BuildType.TEST -> "Debug" + BuildType.TEST -> "Debug" else -> type.toString() } @@ -141,7 +141,7 @@ class CppStandaloneGenerator(generator: CppGenerator) : if (version.compareVersion("3.12.0") < 0) { messageReporter.nowhere().warning("CMAKE is older than version 3.12. Parallel building is not supported.") makeArgs = - listOf("--build", ".", "--target", target, "--config", targetConfig.cmakeBuildType?.toString() ?: "Release") + listOf("--build", ".", "--target", target, "--config", targetConfig.buildType?.toString() ?: "Release") } else { val cores = Runtime.getRuntime().availableProcessors() makeArgs = listOf( @@ -152,7 +152,7 @@ class CppStandaloneGenerator(generator: CppGenerator) : "--parallel", cores.toString(), "--config", - buildTypeToCmakeConfig(targetConfig.cmakeBuildType) + buildTypeToCmakeConfig(targetConfig.buildType.get()) ) } diff --git a/core/src/main/kotlin/org/lflang/generator/rust/RustCargoTomlEmitter.kt b/core/src/main/kotlin/org/lflang/generator/rust/RustCargoTomlEmitter.kt index a4b9ba0548..2a733438ec 100644 --- a/core/src/main/kotlin/org/lflang/generator/rust/RustCargoTomlEmitter.kt +++ b/core/src/main/kotlin/org/lflang/generator/rust/RustCargoTomlEmitter.kt @@ -24,7 +24,7 @@ package org.lflang.generator.rust -import org.lflang.TargetProperty.BuildType.* +import org.lflang.target.property.BuildConfig.BuildType.* import org.lflang.escapeStringLiteral import org.lflang.generator.PrependOperator.rangeTo import org.lflang.joinWithCommas diff --git a/core/src/main/kotlin/org/lflang/generator/rust/RustGenerator.kt b/core/src/main/kotlin/org/lflang/generator/rust/RustGenerator.kt index 41128800e3..b733db66de 100644 --- a/core/src/main/kotlin/org/lflang/generator/rust/RustGenerator.kt +++ b/core/src/main/kotlin/org/lflang/generator/rust/RustGenerator.kt @@ -26,7 +26,7 @@ package org.lflang.generator.rust import org.eclipse.emf.ecore.resource.Resource import org.lflang.Target -import org.lflang.TargetProperty.BuildType +import org.lflang.target.property.BuildConfig.BuildType import org.lflang.generator.GeneratorUtils.canGenerate import org.lflang.generator.CodeMap import org.lflang.generator.GeneratorBase @@ -96,7 +96,7 @@ class RustGenerator( val args = mutableListOf().apply { this += "build" - val buildType = targetConfig.rust.buildType + val buildType = targetConfig.rust.getBuildType(context.targetConfig.buildType) if (buildType == BuildType.RELEASE) { this += "--release" } else if (buildType != BuildType.DEBUG) { @@ -125,7 +125,7 @@ class RustGenerator( if (cargoReturnCode == 0) { // We still have to copy the compiled binary to the destination folder. - val buildType = targetConfig.rust.buildType + val buildType = targetConfig.rust.getBuildType(context.targetConfig.buildType) val binaryPath = validator.metadata?.targetDirectory!! .resolve(buildType.cargoProfileName) .resolve(fileConfig.executable.fileName) 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 b2bacb0ce3..9b3d9208c8 100644 --- a/core/src/main/kotlin/org/lflang/generator/rust/RustModel.kt +++ b/core/src/main/kotlin/org/lflang/generator/rust/RustModel.kt @@ -26,7 +26,7 @@ package org.lflang.generator.rust import org.lflang.* -import org.lflang.TargetProperty.BuildType +import org.lflang.target.property.BuildConfig.BuildType import org.lflang.ast.ASTUtils import org.lflang.generator.* import org.lflang.lf.* @@ -519,7 +519,7 @@ object RustModelBuilder { private fun TargetConfig.toRustProperties(): RustTargetProperties = RustTargetProperties( - keepAlive = this.keepalive, + keepAlive = this.keepalive.get(), timeout = this.timeout?.toRustTimeExpr(), timeoutLf = this.timeout, singleFile = this.singleFileProject, diff --git a/core/src/main/kotlin/org/lflang/generator/ts/TSConstructorGenerator.kt b/core/src/main/kotlin/org/lflang/generator/ts/TSConstructorGenerator.kt index fc8b942a2f..2d1376fae9 100644 --- a/core/src/main/kotlin/org/lflang/generator/ts/TSConstructorGenerator.kt +++ b/core/src/main/kotlin/org/lflang/generator/ts/TSConstructorGenerator.kt @@ -4,7 +4,6 @@ import org.lflang.MessageReporter import org.lflang.TargetConfig import org.lflang.generator.PrependOperator import org.lflang.generator.getTargetInitializer -import org.lflang.joinWithLn import org.lflang.lf.Parameter import org.lflang.lf.Reactor import java.util.* @@ -78,7 +77,7 @@ class TSConstructorGenerator( // Generate code for setting target configurations. private fun generateTargetConfigurations(targetConfig: TargetConfig): String { - val interval = targetConfig.coordinationOptions.advance_message_interval + val interval = targetConfig.coordinationOptions.get().advanceMessageInterval return if ((reactor.isMain) && interval != null) { "this.setAdvanceMessageInterval(${interval.toTsTime()})" } else "" diff --git a/core/src/testFixtures/java/org/lflang/tests/Configurators.java b/core/src/testFixtures/java/org/lflang/tests/Configurators.java index 12e83dadac..784286e1f0 100644 --- a/core/src/testFixtures/java/org/lflang/tests/Configurators.java +++ b/core/src/testFixtures/java/org/lflang/tests/Configurators.java @@ -26,7 +26,7 @@ import org.lflang.TargetProperty; import org.lflang.target.LoggingConfigurator.LogLevel; -import org.lflang.target.PlatformConfigurator.Platform; +import org.lflang.target.PlatformConfig.Platform; import org.lflang.tests.TestRegistry.TestCategory; /** @@ -68,9 +68,9 @@ public static boolean makeZephyrCompatibleUnthreaded(LFTest test) { test.getContext().getArgs().setProperty("tracing", "false"); test.getContext().getTargetConfig().setByUser.add(TargetProperty.THREADING); test.getContext().getTargetConfig().threading = false; - test.getContext().getTargetConfig().platformOptions.platform = Platform.ZEPHYR; - test.getContext().getTargetConfig().platformOptions.flash = false; - test.getContext().getTargetConfig().platformOptions.board = "qemu_cortex_m3"; + test.getContext().getTargetConfig().platformOptions.get().platform = Platform.ZEPHYR; + test.getContext().getTargetConfig().platformOptions.get().flash = false; + test.getContext().getTargetConfig().platformOptions.get().board = "qemu_cortex_m3"; // FIXME: Zephyr emulations fails with debug log-levels. test.getContext().getTargetConfig().logLevel = LogLevel.WARN; @@ -80,9 +80,9 @@ public static boolean makeZephyrCompatibleUnthreaded(LFTest test) { public static boolean makeZephyrCompatible(LFTest test) { test.getContext().getArgs().setProperty("tracing", "false"); - test.getContext().getTargetConfig().platformOptions.platform = Platform.ZEPHYR; - test.getContext().getTargetConfig().platformOptions.flash = false; - test.getContext().getTargetConfig().platformOptions.board = "qemu_cortex_m3"; + test.getContext().getTargetConfig().platformOptions.get().platform = Platform.ZEPHYR; + test.getContext().getTargetConfig().platformOptions.get().flash = false; + test.getContext().getTargetConfig().platformOptions.get().board = "qemu_cortex_m3"; // FIXME: Zephyr emulations fails with debug log-levels. test.getContext().getTargetConfig().logLevel = LogLevel.WARN; From 15368c78cab1181c212e99bc6206b58c520e460a Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Mon, 25 Sep 2023 12:44:11 -0700 Subject: [PATCH 003/145] Incremental changes --- .../main/java/org/lflang/TargetConfig.java | 13 +++---- .../main/java/org/lflang/TargetProperty.java | 17 +-------- .../java/org/lflang/TargetPropertyConfig.java | 10 +++++ .../federated/extensions/CExtensionUtils.java | 2 +- .../federated/generator/FedFileConfig.java | 2 +- .../lflang/generator/c/CCmakeGenerator.java | 4 +- .../org/lflang/generator/c/CGenerator.java | 8 ++-- .../lflang/target/Ros2DependenciesConfig.java | 3 +- .../java/org/lflang/target/TracingConfig.java | 24 +++++++++--- .../property/type/CmakeIncludeConfig.java | 37 +++++++++++++++++++ .../generator/cpp/CppRos2PackageGenerator.kt | 2 +- .../cpp/CppStandaloneCmakeGenerator.kt | 2 +- 12 files changed, 85 insertions(+), 39 deletions(-) create mode 100644 core/src/main/java/org/lflang/target/property/type/CmakeIncludeConfig.java diff --git a/core/src/main/java/org/lflang/TargetConfig.java b/core/src/main/java/org/lflang/TargetConfig.java index ffd2c426b3..78b0d050aa 100644 --- a/core/src/main/java/org/lflang/TargetConfig.java +++ b/core/src/main/java/org/lflang/TargetConfig.java @@ -43,14 +43,14 @@ import org.lflang.target.FastModeConfig; import org.lflang.target.KeepaliveConfig; import org.lflang.target.PlatformConfig; +import org.lflang.target.Ros2DependenciesConfig; import org.lflang.target.SchedulerConfig; import org.lflang.target.TracingConfig; -import org.lflang.target.TracingConfig.TracingOptions; import org.lflang.target.property.BuildCommandsConfig; import org.lflang.target.LoggingConfigurator.LogLevel; -import org.lflang.target.SchedulerConfig.SchedulerOption; import org.lflang.target.property.ClockSyncOptionsConfig; import org.lflang.target.property.BuildTypeConfig; +import org.lflang.target.property.type.CmakeIncludeConfig; /** * A class for keeping the current target configuration. @@ -115,10 +115,7 @@ public TargetConfig(Properties cliArgs, TargetDecl target, MessageReporter messa this.compiler = cliArgs.getProperty("target-compiler"); this.setByUser.add(TargetProperty.COMPILER); } - if (cliArgs.containsKey("tracing")) { - this.tracing.override(new TracingOptions()); - this.setByUser.add(TargetProperty.TRACING); - } + if (cliArgs.containsKey("target-flags")) { this.compilerFlags.clear(); @@ -164,7 +161,7 @@ public TargetConfig(Properties cliArgs, TargetDecl target, MessageReporter messa public BuildTypeConfig buildType = new BuildTypeConfig(); /** Optional additional extensions to include in the generated CMakeLists.txt. */ - public List cmakeIncludes = new ArrayList<>(); + public CmakeIncludeConfig cmakeIncludes = new CmakeIncludeConfig(); /** The compiler to invoke, unless a build command has been specified. */ public String compiler = ""; @@ -247,7 +244,7 @@ public TargetConfig(Properties cliArgs, TargetDecl target, MessageReporter messa public boolean ros2 = false; /** Additional ROS2 packages that the LF program depends on. */ - public List ros2Dependencies = null; + public Ros2DependenciesConfig ros2Dependencies = new Ros2DependenciesConfig(); /** The version of the runtime library to be used in the generated target. */ public String runtimeVersion = null; diff --git a/core/src/main/java/org/lflang/TargetProperty.java b/core/src/main/java/org/lflang/TargetProperty.java index ff459ce747..c09a0979c9 100644 --- a/core/src/main/java/org/lflang/TargetProperty.java +++ b/core/src/main/java/org/lflang/TargetProperty.java @@ -108,17 +108,7 @@ public enum TargetProperty { "cmake-include", UnionType.FILE_OR_FILE_ARRAY, Arrays.asList(Target.CPP, Target.C, Target.CCPP), - (config) -> ASTUtils.toElement(config.cmakeIncludes), - (config, value, err) -> { - config.cmakeIncludes = ASTUtils.elementToListOfStrings(value); - }, - // FIXME: This merging of lists is potentially dangerous since - // the incoming list of cmake-includes can belong to a .lf file that is - // located in a different location, and keeping just filename - // strings like this without absolute paths is incorrect. - (config, value, err) -> { - config.cmakeIncludes.addAll(ASTUtils.elementToListOfStrings(value)); - }), + (TargetConfig config) -> config.cmakeIncludes), /** Directive to specify the target compiler. */ COMPILER( "compiler", @@ -304,10 +294,7 @@ public enum TargetProperty { "ros2-dependencies", ArrayType.STRING_ARRAY, List.of(Target.CPP), - (config) -> ASTUtils.toElement(config.ros2Dependencies), - (config, value, err) -> { - config.ros2Dependencies = ASTUtils.elementToListOfStrings(value); - }), + (TargetConfig config) -> config.platformOptions), /** Directive for specifying a specific version of the reactor runtime library. */ RUNTIME_VERSION( diff --git a/core/src/main/java/org/lflang/TargetPropertyConfig.java b/core/src/main/java/org/lflang/TargetPropertyConfig.java index d6dcccd523..3a637d8616 100644 --- a/core/src/main/java/org/lflang/TargetPropertyConfig.java +++ b/core/src/main/java/org/lflang/TargetPropertyConfig.java @@ -7,6 +7,15 @@ import org.lflang.lf.Model; import org.lflang.validation.ValidationReporter; +/** + * Extend this class to manage a non-trivial target property configuration, i.e.: + *
    + *
  • it requires additional validation (override {@code validate});
  • + *
  • it uses elaborate datastructures (define as inner classes); or
  • + *
  • it performs non-trivial updates (override {@code update}.
  • + *
+ * @param The type of the configuration value. + */ public abstract class TargetPropertyConfig { //implements TargetPropertyConfigurator { protected T value = initialize(); @@ -32,6 +41,7 @@ public void set(Element value, MessageReporter err) { } public void update(Element value, MessageReporter err) { + this.setByUser = true; this.set(value, err); } diff --git a/core/src/main/java/org/lflang/federated/extensions/CExtensionUtils.java b/core/src/main/java/org/lflang/federated/extensions/CExtensionUtils.java index 2b622d3b46..7ae00b3608 100644 --- a/core/src/main/java/org/lflang/federated/extensions/CExtensionUtils.java +++ b/core/src/main/java/org/lflang/federated/extensions/CExtensionUtils.java @@ -292,7 +292,7 @@ public static void generateCMakeInclude(FederateInstance federate, FedFileConfig srcWriter.write(cmakeIncludeCode.getCode()); } - federate.targetConfig.cmakeIncludes.add( + federate.targetConfig.cmakeIncludes.get().add( fileConfig.getSrcPath().relativize(cmakeIncludePath).toString()); federate.targetConfig.setByUser.add(TargetProperty.CMAKE_INCLUDE); } diff --git a/core/src/main/java/org/lflang/federated/generator/FedFileConfig.java b/core/src/main/java/org/lflang/federated/generator/FedFileConfig.java index cb12c90a7d..8ec7776cd4 100644 --- a/core/src/main/java/org/lflang/federated/generator/FedFileConfig.java +++ b/core/src/main/java/org/lflang/federated/generator/FedFileConfig.java @@ -102,7 +102,7 @@ public void doClean() throws IOException { public void relativizePaths(FedTargetConfig targetConfig) { relativizePathList(targetConfig.protoFiles); relativizePathList(targetConfig.files); - relativizePathList(targetConfig.cmakeIncludes); + relativizePathList(targetConfig.cmakeIncludes.get()); } /** 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 6af1b1fc57..3deb90c18f 100644 --- a/core/src/main/java/org/lflang/generator/c/CCmakeGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CCmakeGenerator.java @@ -218,7 +218,7 @@ CodeBuilder generateCMakeCode( cMakeCode.pr("set(CMAKE_CXX_STANDARD 17)"); cMakeCode.pr("set(CMAKE_CXX_STANDARD_REQUIRED ON)"); cMakeCode.newLine(); - if (!targetConfig.cmakeIncludes.isEmpty()) { + if (!targetConfig.cmakeIncludes.get().isEmpty()) { // The user might be using the non-keyword form of // target_link_libraries. Ideally we would detect whether they are // doing that, but it is easier to just always have a deprecation @@ -401,7 +401,7 @@ CodeBuilder generateCMakeCode( cMakeCode.newLine(); // Add the include file - for (String includeFile : targetConfig.cmakeIncludes) { + for (String includeFile : targetConfig.cmakeIncludes.get()) { cMakeCode.pr("include(\"" + Path.of(includeFile).getFileName() + "\")"); } cMakeCode.newLine(); 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 f4b1b9043f..70a2056f13 100644 --- a/core/src/main/java/org/lflang/generator/c/CGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CGenerator.java @@ -745,11 +745,11 @@ private void inspectReactorEResource(ReactorDecl reactor) { // Merge the CMake includes from the imported file into the target config lfResource .getTargetConfig() - .cmakeIncludes + .cmakeIncludes.get() .forEach( incl -> { - if (!this.targetConfig.cmakeIncludes.contains(incl)) { - this.targetConfig.cmakeIncludes.add(incl); + if (!this.targetConfig.cmakeIncludes.get().contains(incl)) { + this.targetConfig.cmakeIncludes.get().add(incl); } }); } @@ -770,7 +770,7 @@ protected void copyUserFiles(TargetConfig targetConfig, FileConfig fileConfig) { var destination = this.fileConfig.getSrcGenPath(); FileUtil.copyFilesOrDirectories( - targetConfig.cmakeIncludes, destination, fileConfig, messageReporter, true); + targetConfig.cmakeIncludes.get(), destination, fileConfig, messageReporter, true); // FIXME: Unclear what the following does, but it does not appear to belong here. if (!StringExtensions.isNullOrEmpty(targetConfig.fedSetupPreamble)) { diff --git a/core/src/main/java/org/lflang/target/Ros2DependenciesConfig.java b/core/src/main/java/org/lflang/target/Ros2DependenciesConfig.java index 176cc3d6bc..c8fb599a85 100644 --- a/core/src/main/java/org/lflang/target/Ros2DependenciesConfig.java +++ b/core/src/main/java/org/lflang/target/Ros2DependenciesConfig.java @@ -1,5 +1,6 @@ package org.lflang.target; +import java.util.ArrayList; import java.util.List; import org.lflang.MessageReporter; @@ -18,7 +19,7 @@ public class Ros2DependenciesConfig extends TargetPropertyConfig> { @Override public List initialize() { - return null; // FIXME + return new ArrayList<>(); } @Override diff --git a/core/src/main/java/org/lflang/target/TracingConfig.java b/core/src/main/java/org/lflang/target/TracingConfig.java index 926291e348..cee56c3ddd 100644 --- a/core/src/main/java/org/lflang/target/TracingConfig.java +++ b/core/src/main/java/org/lflang/target/TracingConfig.java @@ -1,6 +1,7 @@ package org.lflang.target; import java.util.Objects; +import java.util.Properties; import org.lflang.TargetConfig; import org.lflang.TargetProperty; @@ -24,12 +25,21 @@ public class TracingConfig extends TargetPropertyConfig { @Override public TracingOptions initialize() { - return new TracingOptions(); + return new TracingOptions(false); + } + + @Override + public void update(Properties cliArgs) { + super.update(cliArgs); + var key = TargetProperty.TRACING.toString(); + if (cliArgs.containsKey(key)) { + this.value.enabled = true; + } } @Override public TracingOptions parse(Element value) { - var options = new TracingOptions(); + var options = new TracingOptions(false); if (value.getLiteral() != null) { if (!ASTUtils.toBoolean(value)) { options.enabled = false; @@ -72,9 +82,9 @@ public void validate(KeyValuePair pair, Model ast, TargetConfig config, Validati @Override public Element export() { - if (this.value.isEnabled()) { + if (!this.value.isEnabled()) { return null; - } else if (this.value.equals(new TracingOptions())) { + } else if (this.value.equals(new TracingOptions(true))) { // default values return ASTUtils.toElement(true); } else { @@ -103,7 +113,11 @@ public Element export() { /** Settings related to tracing options. */ public static class TracingOptions { - protected boolean enabled = true; + protected boolean enabled = false; + + TracingOptions(boolean enabled) { + this.enabled = enabled; + } /** * The name to use as the root of the trace file produced. This defaults to the name of the .lf diff --git a/core/src/main/java/org/lflang/target/property/type/CmakeIncludeConfig.java b/core/src/main/java/org/lflang/target/property/type/CmakeIncludeConfig.java new file mode 100644 index 0000000000..ebfac71d55 --- /dev/null +++ b/core/src/main/java/org/lflang/target/property/type/CmakeIncludeConfig.java @@ -0,0 +1,37 @@ +package org.lflang.target.property.type; + +import java.util.ArrayList; +import java.util.List; + +import org.lflang.MessageReporter; +import org.lflang.TargetPropertyConfig; +import org.lflang.ast.ASTUtils; +import org.lflang.lf.Element; + +public class CmakeIncludeConfig extends TargetPropertyConfig> { + + @Override + public List initialize() { + return new ArrayList<>(); + } + + @Override + public void update(Element value, MessageReporter err) { + super.update(value, err); + // FIXME: This merging of lists is potentially dangerous since + // the incoming list of cmake-includes can belong to a .lf file that is + // located in a different location, and keeping just filename + // strings like this without absolute paths is incorrect. + this.value.addAll(ASTUtils.elementToListOfStrings(value)); + } + + @Override + protected List parse(Element value) { + return ASTUtils.elementToListOfStrings(value); + } + + @Override + public Element export() { + return ASTUtils.toElement(this.value); + } +} diff --git a/core/src/main/kotlin/org/lflang/generator/cpp/CppRos2PackageGenerator.kt b/core/src/main/kotlin/org/lflang/generator/cpp/CppRos2PackageGenerator.kt index d49ed3d2b6..aaca9b4378 100644 --- a/core/src/main/kotlin/org/lflang/generator/cpp/CppRos2PackageGenerator.kt +++ b/core/src/main/kotlin/org/lflang/generator/cpp/CppRos2PackageGenerator.kt @@ -47,7 +47,7 @@ class CppRos2PackageGenerator(generator: CppGenerator, private val nodeName: Str fun generatePackageCmake(sources: List): String { // Resolve path to the cmake include files if any was provided - val includeFiles = targetConfig.cmakeIncludes?.map { fileConfig.srcPath.resolve(it).toUnixString() } + val includeFiles = targetConfig.cmakeIncludes.get()?.map { fileConfig.srcPath.resolve(it).toUnixString() } return with(PrependOperator) { with(CppGenerator) { diff --git a/core/src/main/kotlin/org/lflang/generator/cpp/CppStandaloneCmakeGenerator.kt b/core/src/main/kotlin/org/lflang/generator/cpp/CppStandaloneCmakeGenerator.kt index c64ef9b47f..86f3486cb1 100644 --- a/core/src/main/kotlin/org/lflang/generator/cpp/CppStandaloneCmakeGenerator.kt +++ b/core/src/main/kotlin/org/lflang/generator/cpp/CppStandaloneCmakeGenerator.kt @@ -133,7 +133,7 @@ class CppStandaloneCmakeGenerator(private val targetConfig: TargetConfig, privat fun generateCmake(sources: List): String { // Resolve path to the cmake include files if any was provided - val includeFiles = targetConfig.cmakeIncludes?.map { fileConfig.srcPath.resolve(it).toUnixString() } + val includeFiles = targetConfig.cmakeIncludes.get()?.map { fileConfig.srcPath.resolve(it).toUnixString() } val reactorCppTarget = when { targetConfig.externalRuntimePath != null -> "reactor-cpp" From 62f6d29d97a70c5e8336b7d83ef345d8aa2b33c3 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Tue, 26 Sep 2023 21:39:41 -0700 Subject: [PATCH 004/145] More refactoring --- cli/lfc/src/main/java/org/lflang/cli/Lfc.java | 2 +- .../lflang/tests/runtime/CSchedulerTest.java | 2 +- .../lflang/tests/runtime/CVerifierTest.java | 2 +- .../main/java/org/lflang/TargetConfig.java | 134 +++-- .../main/java/org/lflang/TargetProperty.java | 544 +++--------------- .../java/org/lflang/TargetPropertyConfig.java | 48 +- .../main/java/org/lflang/ast/ASTUtils.java | 2 +- .../federated/extensions/CExtension.java | 2 +- .../federated/extensions/CExtensionUtils.java | 30 +- .../extensions/FedTargetExtension.java | 2 +- .../federated/extensions/PythonExtension.java | 2 +- .../federated/extensions/TSExtension.java | 2 +- .../federated/generator/FedASTUtils.java | 2 +- .../federated/generator/FedFileConfig.java | 4 +- .../federated/generator/FedGenerator.java | 4 +- .../launcher/FedLauncherGenerator.java | 2 +- .../org/lflang/generator/GeneratorUtils.java | 2 +- .../org/lflang/generator/LFGenerator.java | 2 +- .../lflang/generator/c/CCmakeGenerator.java | 6 +- .../org/lflang/generator/c/CCompiler.java | 14 +- .../org/lflang/generator/c/CGenerator.java | 40 +- .../generator/c/CMainFunctionGenerator.java | 8 +- .../generator/c/CPreambleGenerator.java | 14 +- .../generator/c/CTriggerObjectsGenerator.java | 4 +- .../generator/python/PythonGenerator.java | 8 +- .../generator/rust/CargoDependencySpec.java | 10 +- .../generator/rust/RustTargetConfig.java | 61 +- .../lflang/target/LoggingConfigurator.java | 23 - .../lflang/target/property/AuthProperty.java | 16 + .../property/BuildCommandsProperty.java | 40 ++ ...TypeConfig.java => BuildTypeProperty.java} | 14 +- .../property/CargoDependenciesProperty.java | 57 ++ .../property/CargoFeaturesProperty.java | 15 + .../ClockSyncModeProperty.java} | 27 +- ...fig.java => ClockSyncOptionsProperty.java} | 19 +- ...eConfig.java => CmakeIncludeProperty.java} | 16 +- .../property/CompileDefinitionsConfig.java | 38 ++ .../property/CompilerFlagsProperty.java | 15 + .../CoordinationModeProperty.java} | 19 +- .../CoordinationOptionsProperty.java} | 21 +- .../DefaultBooleanProperty.java} | 14 +- .../property/DefaultFileListProperty.java | 39 ++ .../target/property/DefaultStringConfig.java | 33 ++ ...ig.java => DefaultStringListProperty.java} | 11 +- .../DockerProperty.java} | 21 +- .../ExportDependencyGraphProperty.java | 14 + .../target/property/ExportToYamlProperty.java | 14 + .../property/ExternalRuntimePathConfig.java | 14 + .../FastProperty.java} | 28 +- .../lflang/target/property/FilesProperty.java | 14 + .../KeepaliveProperty.java} | 30 +- .../target/property/LoggingProperty.java | 58 ++ .../target/property/NoCompileProperty.java | 15 + .../property/NoRuntimeValidationProperty.java | 14 + .../PlatformProperty.java} | 18 +- .../property/PrintStatisticsProperty.java | 14 + .../target/property/ProtobufsProperty.java | 14 + .../Ros2DependenciesProperty.java} | 16 +- .../lflang/target/property/Ros2Property.java | 14 + .../property/RuntimeVersionProperty.java | 13 + .../target/property/RustIncludeProperty.java | 97 ++++ .../SchedulerProperty.java} | 20 +- .../property/SingleFileProjectProperty.java | 14 + .../target/property/ThreadingProperty.java | 19 + .../target/property/TimeOutProperty.java | 39 ++ .../TracingProperty.java} | 18 +- .../target/property/VerifyProperty.java | 15 + .../target/property/WorkersProperty.java | 37 ++ .../target/property/type/ArrayType.java | 12 +- .../target/property/type/CompilerConfig.java | 14 + .../target/property/type/DictionaryType.java | 26 +- .../target/property/type/PrimitiveType.java | 26 +- .../property/type/StringDictionaryType.java | 12 +- .../property/type/TargetPropertyType.java | 17 +- .../target/property/type/UnionType.java | 25 +- .../org/lflang/validation/LFValidator.java | 15 +- .../lflang/validation/ValidationReporter.java | 1 + .../validation/ValidatorMessageReporter.java | 3 + .../org/lflang/generator/cpp/CppExtensions.kt | 2 +- .../org/lflang/generator/cpp/CppGenerator.kt | 9 +- .../generator/cpp/CppPlatformGenerator.kt | 4 +- .../generator/cpp/CppRos2NodeGenerator.kt | 2 +- .../generator/cpp/CppRos2PackageGenerator.kt | 2 +- .../cpp/CppStandaloneCmakeGenerator.kt | 6 +- .../org/lflang/generator/rust/RustModel.kt | 2 +- .../java/org/lflang/tests/Configurators.java | 8 +- 86 files changed, 1225 insertions(+), 901 deletions(-) delete mode 100644 core/src/main/java/org/lflang/target/LoggingConfigurator.java create mode 100644 core/src/main/java/org/lflang/target/property/AuthProperty.java create mode 100644 core/src/main/java/org/lflang/target/property/BuildCommandsProperty.java rename core/src/main/java/org/lflang/target/property/{BuildTypeConfig.java => BuildTypeProperty.java} (72%) create mode 100644 core/src/main/java/org/lflang/target/property/CargoDependenciesProperty.java create mode 100644 core/src/main/java/org/lflang/target/property/CargoFeaturesProperty.java rename core/src/main/java/org/lflang/target/{ClockSyncModeConfig.java => property/ClockSyncModeProperty.java} (76%) rename core/src/main/java/org/lflang/target/property/{ClockSyncOptionsConfig.java => ClockSyncOptionsProperty.java} (92%) rename core/src/main/java/org/lflang/target/property/{type/CmakeIncludeConfig.java => CmakeIncludeProperty.java} (69%) create mode 100644 core/src/main/java/org/lflang/target/property/CompileDefinitionsConfig.java create mode 100644 core/src/main/java/org/lflang/target/property/CompilerFlagsProperty.java rename core/src/main/java/org/lflang/target/{CoordinationModeConfig.java => property/CoordinationModeProperty.java} (69%) rename core/src/main/java/org/lflang/target/{CoordinationOptionsConfig.java => property/CoordinationOptionsProperty.java} (87%) rename core/src/main/java/org/lflang/target/{AuthConfig.java => property/DefaultBooleanProperty.java} (53%) create mode 100644 core/src/main/java/org/lflang/target/property/DefaultFileListProperty.java create mode 100644 core/src/main/java/org/lflang/target/property/DefaultStringConfig.java rename core/src/main/java/org/lflang/target/property/{BuildCommandsConfig.java => DefaultStringListProperty.java} (61%) rename core/src/main/java/org/lflang/target/{DockerConfig.java => property/DockerProperty.java} (89%) create mode 100644 core/src/main/java/org/lflang/target/property/ExportDependencyGraphProperty.java create mode 100644 core/src/main/java/org/lflang/target/property/ExportToYamlProperty.java create mode 100644 core/src/main/java/org/lflang/target/property/ExternalRuntimePathConfig.java rename core/src/main/java/org/lflang/target/{FastModeConfig.java => property/FastProperty.java} (77%) create mode 100644 core/src/main/java/org/lflang/target/property/FilesProperty.java rename core/src/main/java/org/lflang/target/{KeepaliveConfig.java => property/KeepaliveProperty.java} (61%) create mode 100644 core/src/main/java/org/lflang/target/property/LoggingProperty.java create mode 100644 core/src/main/java/org/lflang/target/property/NoCompileProperty.java create mode 100644 core/src/main/java/org/lflang/target/property/NoRuntimeValidationProperty.java rename core/src/main/java/org/lflang/target/{PlatformConfig.java => property/PlatformProperty.java} (95%) create mode 100644 core/src/main/java/org/lflang/target/property/PrintStatisticsProperty.java create mode 100644 core/src/main/java/org/lflang/target/property/ProtobufsProperty.java rename core/src/main/java/org/lflang/target/{Ros2DependenciesConfig.java => property/Ros2DependenciesProperty.java} (73%) create mode 100644 core/src/main/java/org/lflang/target/property/Ros2Property.java create mode 100644 core/src/main/java/org/lflang/target/property/RuntimeVersionProperty.java create mode 100644 core/src/main/java/org/lflang/target/property/RustIncludeProperty.java rename core/src/main/java/org/lflang/target/{SchedulerConfig.java => property/SchedulerProperty.java} (90%) create mode 100644 core/src/main/java/org/lflang/target/property/SingleFileProjectProperty.java create mode 100644 core/src/main/java/org/lflang/target/property/ThreadingProperty.java create mode 100644 core/src/main/java/org/lflang/target/property/TimeOutProperty.java rename core/src/main/java/org/lflang/target/{TracingConfig.java => property/TracingProperty.java} (91%) create mode 100644 core/src/main/java/org/lflang/target/property/VerifyProperty.java create mode 100644 core/src/main/java/org/lflang/target/property/WorkersProperty.java create mode 100644 core/src/main/java/org/lflang/target/property/type/CompilerConfig.java 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 eb30503aca..82b1979c16 100644 --- a/cli/lfc/src/main/java/org/lflang/cli/Lfc.java +++ b/cli/lfc/src/main/java/org/lflang/cli/Lfc.java @@ -50,7 +50,7 @@ public class Lfc extends CliBase { description = "Clean before building.") private boolean clean; - @Option(names = "--target-compiler", description = "Target compiler to invoke.") + @Option(names = "--compiler", description = "Target compiler to invoke.") private String targetCompiler; @Option( diff --git a/core/src/integrationTest/java/org/lflang/tests/runtime/CSchedulerTest.java b/core/src/integrationTest/java/org/lflang/tests/runtime/CSchedulerTest.java index f6032227f8..09a11faa6f 100644 --- a/core/src/integrationTest/java/org/lflang/tests/runtime/CSchedulerTest.java +++ b/core/src/integrationTest/java/org/lflang/tests/runtime/CSchedulerTest.java @@ -3,7 +3,7 @@ import java.util.EnumSet; import org.junit.jupiter.api.Test; import org.lflang.Target; -import org.lflang.target.SchedulerConfig.SchedulerOption; +import org.lflang.target.property.SchedulerProperty.SchedulerOption; import org.lflang.tests.Configurators; import org.lflang.tests.TestBase; import org.lflang.tests.TestRegistry.TestCategory; diff --git a/core/src/integrationTest/java/org/lflang/tests/runtime/CVerifierTest.java b/core/src/integrationTest/java/org/lflang/tests/runtime/CVerifierTest.java index d9bde8b3ed..4ac734d314 100644 --- a/core/src/integrationTest/java/org/lflang/tests/runtime/CVerifierTest.java +++ b/core/src/integrationTest/java/org/lflang/tests/runtime/CVerifierTest.java @@ -21,7 +21,7 @@ public void runVerifierTests() { Message.DESC_VERIFIER, TestRegistry.TestCategory.VERIFIER::equals, test -> { - test.getContext().getTargetConfig().verify = true; + test.getContext().getTargetConfig().verify.override(true); return true; }, TestLevel.BUILD, diff --git a/core/src/main/java/org/lflang/TargetConfig.java b/core/src/main/java/org/lflang/TargetConfig.java index 78b0d050aa..cfa95768ec 100644 --- a/core/src/main/java/org/lflang/TargetConfig.java +++ b/core/src/main/java/org/lflang/TargetConfig.java @@ -25,32 +25,50 @@ package org.lflang; import java.util.ArrayList; -import java.util.HashMap; import java.util.HashSet; import java.util.List; -import java.util.Map; import java.util.Properties; import java.util.Set; + import org.lflang.generator.LFGeneratorContext.BuildParm; import org.lflang.generator.rust.RustTargetConfig; import org.lflang.lf.KeyValuePair; import org.lflang.lf.TargetDecl; -import org.lflang.target.AuthConfig; -import org.lflang.target.ClockSyncModeConfig; -import org.lflang.target.CoordinationModeConfig; -import org.lflang.target.CoordinationOptionsConfig; -import org.lflang.target.DockerConfig; -import org.lflang.target.FastModeConfig; -import org.lflang.target.KeepaliveConfig; -import org.lflang.target.PlatformConfig; -import org.lflang.target.Ros2DependenciesConfig; -import org.lflang.target.SchedulerConfig; -import org.lflang.target.TracingConfig; -import org.lflang.target.property.BuildCommandsConfig; -import org.lflang.target.LoggingConfigurator.LogLevel; -import org.lflang.target.property.ClockSyncOptionsConfig; -import org.lflang.target.property.BuildTypeConfig; -import org.lflang.target.property.type.CmakeIncludeConfig; +import org.lflang.target.property.AuthProperty; +import org.lflang.target.property.ClockSyncModeProperty; +import org.lflang.target.property.CoordinationModeProperty; +import org.lflang.target.property.CoordinationOptionsProperty; +import org.lflang.target.property.DockerProperty; +import org.lflang.target.property.FastProperty; +import org.lflang.target.property.KeepaliveProperty; +import org.lflang.target.property.PlatformProperty; +import org.lflang.target.property.Ros2DependenciesProperty; +import org.lflang.target.property.SchedulerProperty; +import org.lflang.target.property.LoggingProperty; +import org.lflang.target.property.LoggingProperty.LogLevel; +import org.lflang.target.property.TracingProperty; +import org.lflang.target.property.BuildCommandsProperty; +import org.lflang.target.property.ClockSyncOptionsProperty; +import org.lflang.target.property.BuildTypeProperty; +import org.lflang.target.property.CompilerFlagsProperty; +import org.lflang.target.property.ExportDependencyGraphProperty; +import org.lflang.target.property.ExportToYamlProperty; +import org.lflang.target.property.FilesProperty; +import org.lflang.target.property.NoCompileProperty; +import org.lflang.target.property.NoRuntimeValidationProperty; +import org.lflang.target.property.PrintStatisticsProperty; +import org.lflang.target.property.ProtobufsProperty; +import org.lflang.target.property.Ros2Property; +import org.lflang.target.property.RuntimeVersionProperty; +import org.lflang.target.property.SingleFileProjectProperty; +import org.lflang.target.property.ThreadingProperty; +import org.lflang.target.property.TimeOutProperty; +import org.lflang.target.property.WorkersProperty; +import org.lflang.target.property.CmakeIncludeProperty; +import org.lflang.target.property.type.CompileDefinitionsConfig; +import org.lflang.target.property.type.CompilerConfig; +import org.lflang.target.property.type.ExternalRuntimePathConfig; +import org.lflang.target.property.type.VerifyProperty; /** * A class for keeping the current target configuration. @@ -88,6 +106,8 @@ public TargetConfig(Properties cliArgs, TargetDecl target, MessageReporter messa TargetProperty.set(this, pairs != null ? pairs : List.of(), messageReporter); } + // FIXME: work these into the TargetProperty.set call above. + if (cliArgs != null) { TargetProperty.override(this, cliArgs, messageReporter); } @@ -111,11 +131,6 @@ public TargetConfig(Properties cliArgs, TargetDecl target, MessageReporter messa this.threading = Boolean.parseBoolean(cliArgs.getProperty("threading")); this.setByUser.add(TargetProperty.THREADING); } - if (cliArgs.containsKey("target-compiler")) { - this.compiler = cliArgs.getProperty("target-compiler"); - this.setByUser.add(TargetProperty.COMPILER); - } - if (cliArgs.containsKey("target-flags")) { this.compilerFlags.clear(); @@ -147,24 +162,24 @@ public TargetConfig(Properties cliArgs, TargetDecl target, MessageReporter messa * designated compiler. A common usage of this target property is to set the command to build on * the basis of a Makefile. */ - public BuildCommandsConfig buildCommands = new BuildCommandsConfig(); + public BuildCommandsProperty buildCommands = new BuildCommandsProperty(); /** * The mode of clock synchronization to be used in federated programs. The default is 'initial'. */ - public final ClockSyncModeConfig clockSync = new ClockSyncModeConfig(); + public final ClockSyncModeProperty clockSync = new ClockSyncModeProperty(); /** Clock sync options. */ - public final ClockSyncOptionsConfig clockSyncOptions = new ClockSyncOptionsConfig(); + public final ClockSyncOptionsProperty clockSyncOptions = new ClockSyncOptionsProperty(); /** Parameter passed to cmake. The default is 'Release'. */ - public BuildTypeConfig buildType = new BuildTypeConfig(); + public BuildTypeProperty buildType = new BuildTypeProperty(); /** Optional additional extensions to include in the generated CMakeLists.txt. */ - public CmakeIncludeConfig cmakeIncludes = new CmakeIncludeConfig(); + public CmakeIncludeProperty cmakeIncludes = new CmakeIncludeProperty(); /** The compiler to invoke, unless a build command has been specified. */ - public String compiler = ""; + public CompilerConfig compiler = new CompilerConfig(); /** Additional sources to add to the compile command if appropriate. */ public List compileAdditionalSources = new ArrayList<>(); @@ -175,55 +190,55 @@ public TargetConfig(Properties cliArgs, TargetDecl target, MessageReporter messa *

The first string is the definition itself, and the second string is the value to attribute * to that definition, if any. The second value could be left empty. */ - public Map compileDefinitions = new HashMap<>(); + public CompileDefinitionsConfig compileDefinitions = new CompileDefinitionsConfig(); /** Flags to pass to the compiler, unless a build command has been specified. */ - public List compilerFlags = new ArrayList<>(); + public CompilerFlagsProperty compilerFlags = new CompilerFlagsProperty(); /** * The type of coordination used during the execution of a federated program. The default is * 'centralized'. */ - public CoordinationModeConfig coordination = new CoordinationModeConfig(); + public CoordinationModeProperty coordination = new CoordinationModeProperty(); /** Docker options. */ - public DockerConfig dockerOptions = new DockerConfig(); + public DockerProperty dockerOptions = new DockerProperty(); /** Coordination options. */ - public CoordinationOptionsConfig coordinationOptions = new CoordinationOptionsConfig(); + public CoordinationOptionsProperty coordinationOptions = new CoordinationOptionsProperty(); /** Link to an external runtime library instead of the default one. */ - public String externalRuntimePath = null; + public ExternalRuntimePathConfig externalRuntimePath = new ExternalRuntimePathConfig(); /** * If true, configure the execution environment such that it does not wait for physical time to * match logical time. The default is false. */ - public FastModeConfig fastMode = new FastModeConfig(); + public FastProperty fastMode = new FastProperty(); /** List of files to be copied to src-gen. */ - public List files = new ArrayList<>(); + public FilesProperty files = new FilesProperty(); /** * If true, configure the execution environment to keep executing if there are no more events on * the event queue. The default is false. */ - public KeepaliveConfig keepalive = new KeepaliveConfig(); + public KeepaliveProperty keepalive = new KeepaliveProperty(); /** The level of logging during execution. The default is INFO. */ - public LogLevel logLevel = LogLevel.INFO; + public LoggingProperty logLevel = new LoggingProperty(); /** Flags to pass to the linker, unless a build command has been specified. */ public String linkerFlags = ""; /** If true, do not invoke the target compiler or build command. The default is false. */ - public boolean noCompile = false; + public NoCompileProperty noCompile = new NoCompileProperty(); /** If true, do not perform runtime validation. The default is false. */ - public boolean noRuntimeValidation = false; + public NoRuntimeValidationProperty noRuntimeValidation = new NoRuntimeValidationProperty(); /** If true, check the generated verification model. The default is false. */ - public boolean verify = false; + public VerifyProperty verify = new VerifyProperty(); /** * Set the target platform config. This tells the build system what platform-specific support @@ -232,46 +247,46 @@ public TargetConfig(Properties cliArgs, TargetDecl target, MessageReporter messa *

This is now a wrapped class to account for overloaded definitions of defining platform * (either a string or dictionary of values) */ - public PlatformConfig platformOptions = new PlatformConfig(); + public PlatformProperty platformOptions = new PlatformProperty(); /** If true, instruct the runtime to collect and print execution statistics. */ - public boolean printStatistics = false; + public PrintStatisticsProperty printStatistics = new PrintStatisticsProperty(); /** List of proto files to be processed by the code generator. */ - public List protoFiles = new ArrayList<>(); + public ProtobufsProperty protoFiles = new ProtobufsProperty(); /** If true, generate ROS2 specific code. */ - public boolean ros2 = false; + public Ros2Property ros2 = new Ros2Property(); /** Additional ROS2 packages that the LF program depends on. */ - public Ros2DependenciesConfig ros2Dependencies = new Ros2DependenciesConfig(); + public Ros2DependenciesProperty ros2Dependencies = new Ros2DependenciesProperty(); /** The version of the runtime library to be used in the generated target. */ - public String runtimeVersion = null; + public RuntimeVersionProperty runtimeVersion = new RuntimeVersionProperty(); /** Whether all reactors are to be generated into a single target language file. */ - public boolean singleFileProject = false; + public SingleFileProjectProperty singleFileProject = new SingleFileProjectProperty(); /** What runtime scheduler to use. */ - public SchedulerConfig schedulerType = new SchedulerConfig(); + public SchedulerProperty schedulerType = new SchedulerProperty(); /** * The number of worker threads to deploy. The default is zero, which indicates that the runtime * is allowed to freely choose the number of workers. */ - public int workers = 0; + public WorkersProperty workers = new WorkersProperty(); /** Indicate whether HMAC authentication is used. */ - public AuthConfig auth = new AuthConfig(); + public AuthProperty auth = new AuthProperty(); /** Indicate whether the runtime should use multithreaded execution. */ - public boolean threading = true; + public ThreadingProperty threading = new ThreadingProperty(); /** The timeout to be observed during execution of the program. */ - public TimeValue timeout; + public TimeOutProperty timeout = new TimeOutProperty(); /** If non-null, configure the runtime environment to perform tracing. The default is null. */ - public TracingConfig tracing = new TracingConfig(); + public TracingProperty tracing = new TracingProperty(); /** * If true, the resulting binary will output a graph visualizing all reaction dependencies. @@ -279,7 +294,7 @@ public TargetConfig(Properties cliArgs, TargetDecl target, MessageReporter messa *

This option is currently only used for C++ and Rust. This export function is a valuable tool * for debugging LF programs and helps to understand the dependencies inferred by the runtime. */ - public boolean exportDependencyGraph = false; + public ExportDependencyGraphProperty exportDependencyGraph = new ExportDependencyGraphProperty(); /** * If true, the resulting binary will output a yaml file describing the whole reactor structure of @@ -288,7 +303,7 @@ public TargetConfig(Properties cliArgs, TargetDecl target, MessageReporter messa *

This option is currently only used for C++. This export function is a valuable tool for * debugging LF programs and performing external analysis. */ - public boolean exportToYaml = false; + public ExportToYamlProperty exportToYaml = new ExportToYamlProperty(); /** Rust-specific configuration. */ public final RustTargetConfig rust = @@ -297,9 +312,4 @@ public TargetConfig(Properties cliArgs, TargetDecl target, MessageReporter messa /** Path to a C file used by the Python target to setup federated execution. */ public String fedSetupPreamble = null; // FIXME: https://issue.lf-lang.org/1558 - - - - - } diff --git a/core/src/main/java/org/lflang/TargetProperty.java b/core/src/main/java/org/lflang/TargetProperty.java index c09a0979c9..11a9f44253 100644 --- a/core/src/main/java/org/lflang/TargetProperty.java +++ b/core/src/main/java/org/lflang/TargetProperty.java @@ -36,21 +36,14 @@ import org.lflang.generator.InvalidLfSourceException; import org.lflang.generator.rust.CargoDependencySpec; import org.lflang.generator.rust.CargoDependencySpec.CargoDependenciesPropertyType; -import org.lflang.lf.Array; import org.lflang.lf.Element; import org.lflang.lf.KeyValuePair; import org.lflang.lf.KeyValuePairs; import org.lflang.lf.LfFactory; import org.lflang.lf.Model; import org.lflang.lf.TargetDecl; -import org.lflang.target.LoggingConfigurator.LogLevel; -import org.lflang.target.property.type.ArrayType; -import org.lflang.target.property.type.DictionaryType; -import org.lflang.target.property.type.StringDictionaryType; import org.lflang.target.property.type.TargetPropertyType; import org.lflang.target.property.type.PrimitiveType; -import org.lflang.target.property.type.UnionType; -import org.lflang.util.FileUtil; import org.lflang.util.StringUtil; import org.lflang.validation.ValidationReporter; @@ -61,42 +54,22 @@ * @author Marten Lohstroh */ public enum TargetProperty { - /** Directive to allow including OpenSSL libraries and process HMAC authentication. */ - AUTH( - "auth", - PrimitiveType.BOOLEAN, - Arrays.asList(Target.C, Target.CCPP), - (TargetConfig config) -> config.auth), - - /** Directive to let the generator use the custom build command. */ - BUILD( - "build", - UnionType.STRING_OR_STRING_ARRAY, - Arrays.asList(Target.C, Target.CCPP), - (TargetConfig config) -> config.buildCommands), + + /** Directive to allow including OpenSSL libraries and process HMAC authentication. */ + AUTH(config -> config.auth), + /** Directive to let the generator use the custom build command. */ + BUILD(config -> config.buildCommands), /** * Directive to specify the target build type such as 'Release' or 'Debug'. This is also used in * the Rust target to select a Cargo profile. */ - BUILD_TYPE( - "build-type", - UnionType.BUILD_TYPE_UNION, - Arrays.asList(Target.C, Target.CCPP, Target.CPP, Target.Rust), - (TargetConfig config) -> config.buildType), + BUILD_TYPE(config -> config.buildType), /** Directive to let the federate execution handle clock synchronization in software. */ - CLOCK_SYNC( - "clock-sync", - UnionType.CLOCK_SYNC_UNION, - Arrays.asList(Target.C, Target.CCPP, Target.Python), - (TargetConfig config) -> config.clockSync), + CLOCK_SYNC(config -> config.clockSync), /** Key-value pairs giving options for clock synchronization. */ - CLOCK_SYNC_OPTIONS( - "clock-sync-options", - DictionaryType.CLOCK_SYNC_OPTION_DICT, - Arrays.asList(Target.C, Target.CCPP, Target.Python), - (TargetConfig config) -> config.clockSyncOptions), + CLOCK_SYNC_OPTIONS(config -> config.clockSyncOptions), /** * Directive to specify a cmake to be included by the generated build systems. @@ -104,292 +77,106 @@ public enum TargetProperty { *

This gives full control over the C/C++ build as any cmake parameters can be adjusted in the * included file. */ - CMAKE_INCLUDE( - "cmake-include", - UnionType.FILE_OR_FILE_ARRAY, - Arrays.asList(Target.CPP, Target.C, Target.CCPP), - (TargetConfig config) -> config.cmakeIncludes), + CMAKE_INCLUDE(config -> config.cmakeIncludes), /** Directive to specify the target compiler. */ - COMPILER( - "compiler", - PrimitiveType.STRING, - Target.ALL, - (config) -> ASTUtils.toElement(config.compiler), - (config, value, err) -> { - config.compiler = ASTUtils.elementToSingleString(value); - }), - + COMPILER(config -> config.compiler), /** Directive to specify compile-time definitions. */ - COMPILE_DEFINITIONS( - "compile-definitions", - StringDictionaryType.COMPILE_DEFINITION, - Arrays.asList(Target.C, Target.CCPP, Target.Python), - (config) -> ASTUtils.toElement(config.compileDefinitions), - (config, value, err) -> { - config.compileDefinitions = ASTUtils.elementToStringMaps(value); - }), - + COMPILE_DEFINITIONS(config -> config.compileDefinitions), /** * Directive to generate a Dockerfile. This is either a boolean, true or false, or a dictionary of * options. */ - DOCKER( - "docker", - UnionType.DOCKER_UNION, - Arrays.asList(Target.C, Target.CCPP, Target.Python, Target.TS), - (TargetConfig config) -> config.dockerOptions), + /** Directive to specify the coordination mode */ + COORDINATION(config -> config.coordination), + /** Key-value pairs giving options for clock synchronization. */ + COORDINATION_OPTIONS(config -> config.coordinationOptions), + DOCKER(config -> config.dockerOptions), /** Directive for specifying a path to an external runtime to be used for the compiled binary. */ - EXTERNAL_RUNTIME_PATH( - "external-runtime-path", - PrimitiveType.STRING, - List.of(Target.CPP), - (config) -> ASTUtils.toElement(config.externalRuntimePath), - (config, value, err) -> { - config.externalRuntimePath = ASTUtils.elementToSingleString(value); - }), - + EXTERNAL_RUNTIME_PATH(config -> config.externalRuntimePath), /** * Directive to let the execution engine allow logical time to elapse faster than physical time. */ - FAST( - "fast", - PrimitiveType.BOOLEAN, - Target.ALL, - (TargetConfig config) -> config.fastMode), + FAST(config -> config.fastMode), /** * Directive to stage particular files on the class path to be processed by the code generator. */ - FILES( - "files", - UnionType.FILE_OR_FILE_ARRAY, - List.of(Target.C, Target.CCPP, Target.Python), - (config) -> ASTUtils.toElement(config.files), - (config, value, err) -> { - config.files = ASTUtils.elementToListOfStrings(value); - }, - (config, value, err) -> { - config.files.addAll(ASTUtils.elementToListOfStrings(value)); - }), + FILES(config -> config.files), /** Flags to be passed on to the target compiler. */ - FLAGS( - "flags", - UnionType.STRING_OR_STRING_ARRAY, - Arrays.asList(Target.C, Target.CCPP), - (config) -> ASTUtils.toElement(config.compilerFlags), - (config, value, err) -> { - config.compilerFlags = ASTUtils.elementToListOfStrings(value); - }), - - /** Directive to specify the coordination mode */ - COORDINATION( - "coordination", - UnionType.COORDINATION_UNION, - Arrays.asList(Target.C, Target.CCPP, Target.Python), - (TargetConfig config) -> config.coordination), - /** Key-value pairs giving options for clock synchronization. */ - COORDINATION_OPTIONS( - "coordination-options", - DictionaryType.COORDINATION_OPTION_DICT, - Arrays.asList(Target.C, Target.CCPP, Target.Python, Target.TS), - (TargetConfig config) -> config.coordinationOptions), + FLAGS(config -> config.compilerFlags), /** * Directive to let the execution engine remain active also if there are no more events in the * event queue. */ - KEEPALIVE( - "keepalive", - PrimitiveType.BOOLEAN, - Target.ALL, - (TargetConfig config) -> config.keepalive), + KEEPALIVE(config -> config.keepalive), /** Directive to specify the grain at which to report log messages during execution. */ - LOGGING( - "logging", - UnionType.LOGGING_UNION, - Target.ALL, - (config) -> ASTUtils.toElement(config.logLevel.toString()), - (config, value, err) -> { - config.logLevel = - (LogLevel) UnionType.LOGGING_UNION.forName(ASTUtils.elementToSingleString(value)); - }), + LOGGING(config -> config.logLevel), /** Directive to not invoke the target compiler. */ - NO_COMPILE( - "no-compile", - PrimitiveType.BOOLEAN, - Arrays.asList(Target.C, Target.CPP, Target.CCPP, Target.Python), - (config) -> ASTUtils.toElement(config.noCompile), - (config, value, err) -> { - config.noCompile = ASTUtils.toBoolean(value); - }), + NO_COMPILE(config -> config.noCompile), /** Directive to disable validation of reactor rules at runtime. */ - NO_RUNTIME_VALIDATION( - "no-runtime-validation", - PrimitiveType.BOOLEAN, - Arrays.asList(Target.CPP), - (config) -> ASTUtils.toElement(config.noRuntimeValidation), - (config, value, err) -> { - config.noRuntimeValidation = ASTUtils.toBoolean(value); - }), - - /** Directive to check the generated verification model. */ - VERIFY( - "verify", - PrimitiveType.BOOLEAN, - Arrays.asList(Target.C), - (config) -> ASTUtils.toElement(config.verify), - (config, value, err) -> { - config.verify = ASTUtils.toBoolean(value); - }), + NO_RUNTIME_VALIDATION(config -> config.noRuntimeValidation), /** * Directive to specify the platform for cross code generation. This is either a string of the * platform or a dictionary of options that includes the string name. */ - PLATFORM( - "platform", - UnionType.PLATFORM_STRING_OR_DICTIONARY, - Target.ALL, - (TargetConfig config) -> config.platformOptions), + PLATFORM((TargetConfig config) -> config.platformOptions), /** Directive to instruct the runtime to collect and print execution statistics. */ - PRINT_STATISTICS( - "print-statistics", - PrimitiveType.BOOLEAN, - Arrays.asList(Target.CPP), - (config) -> ASTUtils.toElement(config.printStatistics), - (config, value, err) -> { - config.printStatistics = ASTUtils.toBoolean(value); - }), + PRINT_STATISTICS(config -> config.printStatistics), /** * Directive for specifying .proto files that need to be compiled and their code included in the * sources. */ - PROTOBUFS( - "protobufs", - UnionType.FILE_OR_FILE_ARRAY, - Arrays.asList(Target.C, Target.CCPP, Target.TS, Target.Python), - (config) -> ASTUtils.toElement(config.protoFiles), - (config, value, err) -> { - config.protoFiles = ASTUtils.elementToListOfStrings(value); - }), + PROTOBUFS(config -> config.protoFiles), /** Directive to specify that ROS2 specific code is generated, */ - ROS2( - "ros2", - PrimitiveType.BOOLEAN, - List.of(Target.CPP), - (config) -> ASTUtils.toElement(config.ros2), - (config, value, err) -> { - config.ros2 = ASTUtils.toBoolean(value); - }), + ROS2(config -> config.ros2), /** Directive to specify additional ROS2 packages that this LF program depends on. */ - ROS2_DEPENDENCIES( - "ros2-dependencies", - ArrayType.STRING_ARRAY, - List.of(Target.CPP), - (TargetConfig config) -> config.platformOptions), + ROS2_DEPENDENCIES((TargetConfig config) -> config.ros2Dependencies), /** Directive for specifying a specific version of the reactor runtime library. */ - RUNTIME_VERSION( - "runtime-version", - PrimitiveType.STRING, - Arrays.asList(Target.CPP), - (config) -> ASTUtils.toElement(config.runtimeVersion), - (config, value, err) -> { - config.runtimeVersion = ASTUtils.elementToSingleString(value); - }), + RUNTIME_VERSION(config -> config.runtimeVersion), /** Directive for specifying a specific runtime scheduler, if supported. */ - SCHEDULER( - "scheduler", - UnionType.SCHEDULER_UNION, - Arrays.asList(Target.C, Target.CCPP, Target.Python), - (TargetConfig config) -> config.schedulerType - ), + SCHEDULER((TargetConfig config) -> config.schedulerType), /** Directive to specify that all code is generated in a single file. */ - SINGLE_FILE_PROJECT( - "single-file-project", - PrimitiveType.BOOLEAN, - List.of(Target.Rust), - (config) -> ASTUtils.toElement(config.singleFileProject), - (config, value, err) -> { - config.singleFileProject = ASTUtils.toBoolean(value); - }), + SINGLE_FILE_PROJECT(config -> config.singleFileProject), /** Directive to indicate whether the runtime should use multi-threading. */ - THREADING( - "threading", - PrimitiveType.BOOLEAN, - List.of(Target.C, Target.CCPP, Target.Python), - (config) -> ASTUtils.toElement(config.threading), - (config, value, err) -> { - config.threading = ASTUtils.toBoolean(value); - }), + THREADING(config -> config.threading), + /** Directive to check the generated verification model. */ + VERIFY(config -> config.verify), /** Directive to specify the number of worker threads used by the runtime. */ - WORKERS( - "workers", - PrimitiveType.NON_NEGATIVE_INTEGER, - List.of(Target.C, Target.CCPP, Target.Python, Target.CPP, Target.Rust), - (config) -> ASTUtils.toElement(config.workers), - (config, value, err) -> { - config.workers = ASTUtils.toInteger(value); - }), + WORKERS(config -> config.workers), /** Directive to specify the execution timeout. */ - TIMEOUT( - "timeout", - PrimitiveType.TIME_VALUE, - Target.ALL, - (config) -> ASTUtils.toElement(config.timeout), - (config, value, err) -> { - config.timeout = ASTUtils.toTimeValue(value); - }, - (config, value, err) -> { - config.timeout = ASTUtils.toTimeValue(value); - }), + TIMEOUT(config -> config.timeout), /** Directive to enable tracing. */ - TRACING( - "tracing", - UnionType.TRACING_UNION, - Arrays.asList(Target.C, Target.CCPP, Target.CPP, Target.Python), - (TargetConfig config) -> config.tracing), + TRACING(config -> config.tracing), /** * Directive to let the runtime export its internal dependency graph. * *

This is a debugging feature and currently only used for C++ and Rust programs. */ - EXPORT_DEPENDENCY_GRAPH( - "export-dependency-graph", - PrimitiveType.BOOLEAN, - List.of(Target.CPP, Target.Rust), - (config) -> ASTUtils.toElement(config.exportDependencyGraph), - (config, value, err) -> { - config.exportDependencyGraph = ASTUtils.toBoolean(value); - }), + EXPORT_DEPENDENCY_GRAPH(config -> config.exportDependencyGraph), /** * Directive to let the runtime export the program structure to a yaml file. * *

This is a debugging feature and currently only used for C++ programs. */ - EXPORT_TO_YAML( - "export-to-yaml", - PrimitiveType.BOOLEAN, - List.of(Target.CPP), - (config) -> ASTUtils.toElement(config.exportToYaml), - (config, value, err) -> { - config.exportToYaml = ASTUtils.toBoolean(value); - }), + EXPORT_TO_YAML(config -> config.exportToYaml), /** * List of module files to link into the crate as top-level. For instance, a {@code target Rust { @@ -397,61 +184,10 @@ public enum TargetProperty { * the generated {@code main.rs} will include it with a {@code mod foo;}. If one of the paths is a * directory, it must contain a {@code mod.rs} file, and all its contents are copied. */ - RUST_INCLUDE( - "rust-include", - UnionType.FILE_OR_FILE_ARRAY, - List.of(Target.Rust), - (config) -> { - // do not check paths here, and simply copy the absolute path over - List paths = config.rust.getRustTopLevelModules(); - if (paths.isEmpty()) { - return null; - } else if (paths.size() == 1) { - return ASTUtils.toElement(paths.get(0).toString()); - } else { - Element e = LfFactory.eINSTANCE.createElement(); - Array arr = LfFactory.eINSTANCE.createArray(); - for (Path p : paths) { - arr.getElements().add(ASTUtils.toElement(p.toString())); - } - e.setArray(arr); - return e; - } - }, - (config, value, err) -> { - Path referencePath; - try { - referencePath = FileUtil.toPath(value.eResource().getURI()).toAbsolutePath(); - } catch (IllegalArgumentException e) { - err.at(value).error("Invalid path? " + e.getMessage()); - throw e; - } - - // we'll resolve relative paths to check that the files - // are as expected. - - if (value.getLiteral() != null) { - Path resolved = referencePath.resolveSibling(StringUtil.removeQuotes(value.getLiteral())); - - config.rust.addAndCheckTopLevelModule(resolved, value, err); - } else if (value.getArray() != null) { - for (Element element : value.getArray().getElements()) { - String literal = StringUtil.removeQuotes(element.getLiteral()); - Path resolved = referencePath.resolveSibling(literal); - config.rust.addAndCheckTopLevelModule(resolved, element, err); - } - } - }), + RUST_INCLUDE(config -> config.rust.rustTopLevelModules), /** Directive for specifying Cargo features of the generated program to enable. */ - CARGO_FEATURES( - "cargo-features", - ArrayType.STRING_ARRAY, - List.of(Target.Rust), - (config) -> ASTUtils.toElement(config.rust.getCargoFeatures()), - (config, value, err) -> { - config.rust.setCargoFeatures(ASTUtils.elementToListOfStrings(value)); - }), + CARGO_FEATURES(config -> config.rust.cargoFeatures), /** * Dependency specifications for Cargo. This property looks like this: @@ -478,30 +214,7 @@ public enum TargetProperty { * } * } */ - CARGO_DEPENDENCIES( - "cargo-dependencies", - CargoDependenciesPropertyType.INSTANCE, - List.of(Target.Rust), - (config) -> { - var deps = config.rust.getCargoDependencies(); - if (deps.size() == 0) { - return null; - } else { - Element e = LfFactory.eINSTANCE.createElement(); - KeyValuePairs kvp = LfFactory.eINSTANCE.createKeyValuePairs(); - for (var ent : deps.entrySet()) { - KeyValuePair pair = LfFactory.eINSTANCE.createKeyValuePair(); - pair.setName(ent.getKey()); - pair.setValue(CargoDependencySpec.extractSpec(ent.getValue())); - kvp.getPairs().add(pair); - } - e.setKeyvalue(kvp); - return e; - } - }, - (config, value, err) -> { - config.rust.setCargoDependencies(CargoDependencySpec.parseAll(value)); - }), + CARGO_DEPENDENCIES(config -> config.rust.cargoDependencies), /** * Directs the C or Python target to include the associated C file used for setting up federated @@ -515,160 +228,28 @@ public enum TargetProperty { (config, value, err) -> config.fedSetupPreamble = StringUtil.removeQuotes(ASTUtils.elementToSingleString(value))); + public final PropertyGetter propertyGetter; - /** String representation of this target property. */ - public final String description; - - /** - * List of targets that support this property. If a property is used for a target that does not - * support it, a warning reported during validation. - */ - public final List supportedBy; - - /** The type of values that can be assigned to this property. */ - public final TargetPropertyType type; - - /** - * Function that given a configuration object and an Element AST node sets the configuration. It - * is assumed that validation already occurred, so this code should be straightforward. - */ - public final PropertyParser setter; - - private final PropertyValidator validator; - - - /** - * Function that given a configuration object and an Element AST node sets the configuration. It - * is assumed that validation already occurred, so this code should be straightforward. - */ - public final PropertyParser updater; - - - @FunctionalInterface - private interface ConfigGetter { + @FunctionalInterface + private interface PropertyGetter { TargetPropertyConfig get(TargetConfig config); } - @FunctionalInterface - private interface PropertyValidator { - void validate(KeyValuePair pair, Model ast, TargetConfig config, ValidationReporter reporter); - } - - @FunctionalInterface - private interface PropertyParser { - - /** - * Parse the given element into the given target config. May use the error reporter to report - * format errors. - */ - void parseIntoTargetConfig(TargetConfig config, Element element, MessageReporter err); - } - - public final PropertyGetter getter; - - @FunctionalInterface - private interface PropertyGetter { - - /** - * Read this property from the target config and build an element which represents it for the - * AST. May return null if the given value of this property is the same as the default. - */ - Element getPropertyElement(TargetConfig config); - } - - /** - * Private constructor for target properties. - * - * @param description String representation of this property. - * @param type The type that values assigned to this property should conform to. - * @param supportedBy List of targets that support this property. - * @param setter Function for configuration updates. - */ - TargetProperty( - String description, - TargetPropertyType type, - List supportedBy, - PropertyGetter getter, - PropertyParser setter) { - this.description = description; - this.type = type; - this.supportedBy = supportedBy; - this.getter = getter; - this.setter = setter; - this.updater = setter; // (Re)set by default - this.validator = (pair, ast, config, validator) -> {}; - } - - TargetProperty(String description, TargetPropertyType type, List supportedBy, - ConfigGetter g) { - this.description = description; - this.type = type; - this.supportedBy = supportedBy; - this.setter = (TargetConfig config, Element element, MessageReporter err) -> { - g.get(config).set(element, err); - }; - this.updater = (TargetConfig config, Element element, MessageReporter err) -> { - g.get(config).set(element, err); - }; - - this.getter = (TargetConfig config) -> { - return g.get(config).export(); - }; - - this.validator = (KeyValuePair pair, Model ast, TargetConfig config, ValidationReporter reporter) -> { - g.get(config).validate(pair, ast, config, reporter); - }; - } - - /** - * Private constructor for target properties. This will take an additional {@code updater}, which - * will be used to merge target properties from imported resources. - * - * @param description String representation of this property. - * @param type The type that values assigned to this property should conform to. - * @param supportedBy List of targets that support this property. - * @param setter Function for setting configuration values. - * @param updater Function for updating configuration values. - */ - TargetProperty( - String description, - TargetPropertyType type, - List supportedBy, - PropertyGetter getter, - PropertyParser setter, - PropertyParser updater) { - this.description = description; - this.type = type; - this.supportedBy = supportedBy; - this.getter = getter; - this.setter = setter; - this.updater = updater; - this.validator = (pair, ast, config, validator) -> {}; - } - - /** - * Return the name of the property in lingua franca. This is suitable for use as a key in a target - * properties block. It may be an invalid identifier in other languages (may contains dashes - * {@code -}). - */ - public String getDisplayName() { - return description; + TargetProperty(PropertyGetter propertyGetter) { + this.propertyGetter = propertyGetter; } public static void override(TargetConfig config, Properties properties, MessageReporter err) { - properties.keySet().forEach( - key -> { - TargetProperty p = forName(key.toString()); - if (p != null) { - // Mark the specified target property as set by the user - config.setByUser.add(p); - try { - // FIXME: p.setter.parseIntoTargetConfig(config, properties.get(key), err); - } catch (InvalidLfSourceException e) { - err.at(e.getNode()).error(e.getProblem()); - } + for (Object key : properties.keySet()) { + TargetProperty p = forName(key.toString()); + if (p != null) { + try { + p.propertyGetter.get(config).override(properties.get(key)); + } catch (InvalidLfSourceException e) { + err.at(e.getNode()).error(e.getProblem()); } - }); + } + } } /** @@ -744,7 +325,7 @@ public static KeyValuePair getKeyValuePair(Model ast, TargetProperty property) { } public void validate(KeyValuePairs pairs, Model ast, TargetConfig config, ValidationReporter reporter) { - this.validator.validate(getKeyValuePair(pairs, this), ast, config, reporter); + this.propertyGetter.get(config).validate(getKeyValuePair(pairs, this), ast, config, reporter); } /** @@ -801,7 +382,7 @@ public static void updateOne( List properties, MessageReporter err) { properties.stream() - .filter(p -> p.getName().equals(property.getDisplayName())) + .filter(p -> {return p.getName().equals(property.toString());}) .findFirst() .map(KeyValuePair::getValue) .ifPresent(value -> property.updater.parseIntoTargetConfig(config, value, err)); @@ -825,10 +406,13 @@ public static List getOptions() { return Arrays.asList(TargetProperty.values()); } - /** Return the description. */ + /** + * Return the name of the property in as it appears in the target declaration. + * It may be an invalid identifier in other languages (may contains dashes {@code -}). + */ @Override public String toString() { - return this.description; + return this.name().toLowerCase().replaceAll("_", "-"); } /** Interface for dictionary elements. It associates an entry with a type. */ diff --git a/core/src/main/java/org/lflang/TargetPropertyConfig.java b/core/src/main/java/org/lflang/TargetPropertyConfig.java index 3a637d8616..d32aab84ce 100644 --- a/core/src/main/java/org/lflang/TargetPropertyConfig.java +++ b/core/src/main/java/org/lflang/TargetPropertyConfig.java @@ -1,10 +1,13 @@ package org.lflang; +import java.util.List; import java.util.Properties; 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.property.type.TargetPropertyType; import org.lflang.validation.ValidationReporter; /** @@ -16,17 +19,25 @@ * * @param The type of the configuration value. */ -public abstract class TargetPropertyConfig { //implements TargetPropertyConfigurator { +public abstract class TargetPropertyConfig { protected T value = initialize(); protected boolean setByUser; - public void override(T value) { // FIXME: do all overrides imply setByUser? + /* The type of values that can be assigned to this property. */ + public final TargetPropertyType type; + + public TargetPropertyConfig(TargetPropertyType type) { + this.type = type; + } + + public void override(T value) { + this.setByUser = true; this.value = value; } - public abstract T initialize(); + public abstract T initialize(); // FIXME: rename to initialValue /** * Parse the given element into the given target config. May use the error reporter to report @@ -40,14 +51,14 @@ public void set(Element value, MessageReporter err) { } } - public void update(Element value, MessageReporter err) { + public void update(Element value, MessageReporter err) { // FIXME: diff with override?? this.setByUser = true; this.set(value, err); } public void update(Properties cliArgs) { this.setByUser = true; - } + } // FIXME: this is incomplete /** * Return the current configuration. @@ -58,8 +69,32 @@ public T get() { protected abstract T parse(Element value); + public abstract List supportedTargets(); + + public final boolean isSupported(Target target) { + if (supportedTargets().contains(target)) { + return true; + } + return false; + } + // FIXME: config may not be needed. public void validate(KeyValuePair pair, Model ast, TargetConfig config, ValidationReporter reporter) { + // Check whether the property is supported by the target. + if (!this.isSupported(config.target)) { + reporter.warning( + "The target parameter: " + + pair.getName() + + " is not supported by the " + + config.target + + " target and will thus be ignored.", + pair, + Literals.KEY_VALUE_PAIR__NAME); + } + + if (!this.type.check(pair.getValue(), pair.getName(), reporter)) { + reporter.error("Target property '" + pair.getName() + "' is required to be " + type + ".", pair, Literals.KEY_VALUE_PAIR__VALUE); + } } @@ -72,4 +107,7 @@ public void validate(KeyValuePair pair, Model ast, TargetConfig config, Validati public boolean isSetByUser() { return setByUser; } + + @Override + public String toString() { return value.toString(); } } diff --git a/core/src/main/java/org/lflang/ast/ASTUtils.java b/core/src/main/java/org/lflang/ast/ASTUtils.java index 057f0c9494..390f964369 100644 --- a/core/src/main/java/org/lflang/ast/ASTUtils.java +++ b/core/src/main/java/org/lflang/ast/ASTUtils.java @@ -614,7 +614,7 @@ public static ReactorInstance createMainReactorInstance( if (breadth == 0) { messageReporter.nowhere().warning("The program has no reactions"); } else { - targetConfig.compileDefinitions.put( + targetConfig.compileDefinitions.get().put( "LF_REACTION_GRAPH_BREADTH", String.valueOf(reactionInstanceGraph.getBreadth())); } return main; 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 3deefb3757..78a1abc910 100644 --- a/core/src/main/java/org/lflang/federated/extensions/CExtension.java +++ b/core/src/main/java/org/lflang/federated/extensions/CExtension.java @@ -57,7 +57,7 @@ import org.lflang.lf.Port; import org.lflang.lf.Reactor; import org.lflang.lf.VarRef; -import org.lflang.target.CoordinationModeConfig.CoordinationMode; +import org.lflang.target.property.CoordinationModeProperty.CoordinationMode; /** * An extension class to the CGenerator that enables certain federated functionalities. diff --git a/core/src/main/java/org/lflang/federated/extensions/CExtensionUtils.java b/core/src/main/java/org/lflang/federated/extensions/CExtensionUtils.java index 7ae00b3608..6bc46556c8 100644 --- a/core/src/main/java/org/lflang/federated/extensions/CExtensionUtils.java +++ b/core/src/main/java/org/lflang/federated/extensions/CExtensionUtils.java @@ -23,8 +23,8 @@ import org.lflang.lf.Expression; import org.lflang.lf.Input; import org.lflang.lf.ParameterReference; -import org.lflang.target.ClockSyncModeConfig.ClockSyncMode; -import org.lflang.target.property.ClockSyncOptionsConfig.ClockSyncOptions; +import org.lflang.target.property.ClockSyncModeProperty.ClockSyncMode; +import org.lflang.target.property.ClockSyncOptionsProperty.ClockSyncOptions; public class CExtensionUtils { @@ -174,15 +174,15 @@ public static void handleCompileDefinitions( RtiConfig rtiConfig, MessageReporter messageReporter) { federate.targetConfig.setByUser.add(TargetProperty.COMPILE_DEFINITIONS); - federate.targetConfig.compileDefinitions.put("FEDERATED", ""); - federate.targetConfig.compileDefinitions.put( + federate.targetConfig.compileDefinitions.get().put("FEDERATED", ""); + federate.targetConfig.compileDefinitions.get().put( "FEDERATED_" + federate.targetConfig.coordination.toString().toUpperCase(), ""); if (federate.targetConfig.auth.get()) { - federate.targetConfig.compileDefinitions.put("FEDERATED_AUTHENTICATED", ""); + federate.targetConfig.compileDefinitions.get().put("FEDERATED_AUTHENTICATED", ""); } - federate.targetConfig.compileDefinitions.put( + federate.targetConfig.compileDefinitions.get().put( "NUMBER_OF_FEDERATES", String.valueOf(numOfFederates)); - federate.targetConfig.compileDefinitions.put("EXECUTABLE_PREAMBLE", ""); + federate.targetConfig.compileDefinitions.get().put("EXECUTABLE_PREAMBLE", ""); handleAdvanceMessageInterval(federate); @@ -193,7 +193,7 @@ private static void handleAdvanceMessageInterval(FederateInstance federate) { var advanceMessageInterval = federate.targetConfig.coordinationOptions.get().advanceMessageInterval; federate.targetConfig.setByUser.remove(TargetProperty.COORDINATION_OPTIONS); if (advanceMessageInterval != null) { - federate.targetConfig.compileDefinitions.put( + federate.targetConfig.compileDefinitions.get().put( "ADVANCE_MESSAGE_INTERVAL", String.valueOf(advanceMessageInterval.toNanoSeconds())); } } @@ -229,7 +229,7 @@ public static void initializeClockSynchronization( // flags // FIXME: This is probably going to fail on MacOS (especially using clang) // because libm functions are builtin - federate.targetConfig.compilerFlags.add("-lm"); + federate.targetConfig.compilerFlags.get().add("-lm"); federate.targetConfig.setByUser.add(TargetProperty.FLAGS); } messageReporter @@ -254,18 +254,18 @@ public static void addClockSyncCompileDefinitions(FederateInstance federate) { ClockSyncMode mode = federate.targetConfig.clockSync.get(); ClockSyncOptions options = federate.targetConfig.clockSyncOptions.get(); - federate.targetConfig.compileDefinitions.put("_LF_CLOCK_SYNC_INITIAL", ""); - federate.targetConfig.compileDefinitions.put( + federate.targetConfig.compileDefinitions.get().put("_LF_CLOCK_SYNC_INITIAL", ""); + federate.targetConfig.compileDefinitions.get().put( "_LF_CLOCK_SYNC_PERIOD_NS", String.valueOf(options.period.toNanoSeconds())); - federate.targetConfig.compileDefinitions.put( + federate.targetConfig.compileDefinitions.get().put( "_LF_CLOCK_SYNC_EXCHANGES_PER_INTERVAL", String.valueOf(options.trials)); - federate.targetConfig.compileDefinitions.put( + federate.targetConfig.compileDefinitions.get().put( "_LF_CLOCK_SYNC_ATTENUATION", String.valueOf(options.attenuation)); if (mode == ClockSyncMode.ON) { - federate.targetConfig.compileDefinitions.put("_LF_CLOCK_SYNC_ON", ""); + federate.targetConfig.compileDefinitions.get().put("_LF_CLOCK_SYNC_ON", ""); if (options.collectStats) { - federate.targetConfig.compileDefinitions.put("_LF_CLOCK_SYNC_COLLECT_STATS", ""); + federate.targetConfig.compileDefinitions.get().put("_LF_CLOCK_SYNC_COLLECT_STATS", ""); } } } diff --git a/core/src/main/java/org/lflang/federated/extensions/FedTargetExtension.java b/core/src/main/java/org/lflang/federated/extensions/FedTargetExtension.java index 9c2c4168f9..4b20b09ba5 100644 --- a/core/src/main/java/org/lflang/federated/extensions/FedTargetExtension.java +++ b/core/src/main/java/org/lflang/federated/extensions/FedTargetExtension.java @@ -13,7 +13,7 @@ import org.lflang.lf.Reaction; import org.lflang.lf.Reactor; import org.lflang.lf.VarRef; -import org.lflang.target.CoordinationModeConfig.CoordinationMode; +import org.lflang.target.property.CoordinationModeProperty.CoordinationMode; public interface FedTargetExtension { diff --git a/core/src/main/java/org/lflang/federated/extensions/PythonExtension.java b/core/src/main/java/org/lflang/federated/extensions/PythonExtension.java index abf51be552..ab05d80f7e 100644 --- a/core/src/main/java/org/lflang/federated/extensions/PythonExtension.java +++ b/core/src/main/java/org/lflang/federated/extensions/PythonExtension.java @@ -42,7 +42,7 @@ import org.lflang.lf.Action; import org.lflang.lf.Reaction; import org.lflang.lf.VarRef; -import org.lflang.target.CoordinationModeConfig.CoordinationMode; +import org.lflang.target.property.CoordinationModeProperty.CoordinationMode; /** * An extension class to the PythonGenerator that enables certain federated functionalities. diff --git a/core/src/main/java/org/lflang/federated/extensions/TSExtension.java b/core/src/main/java/org/lflang/federated/extensions/TSExtension.java index d10932265b..2505686ec4 100644 --- a/core/src/main/java/org/lflang/federated/extensions/TSExtension.java +++ b/core/src/main/java/org/lflang/federated/extensions/TSExtension.java @@ -25,7 +25,7 @@ import org.lflang.lf.Reactor; import org.lflang.lf.VarRef; import org.lflang.lf.Variable; -import org.lflang.target.CoordinationModeConfig.CoordinationMode; +import org.lflang.target.property.CoordinationModeProperty.CoordinationMode; public class TSExtension implements FedTargetExtension { @Override diff --git a/core/src/main/java/org/lflang/federated/generator/FedASTUtils.java b/core/src/main/java/org/lflang/federated/generator/FedASTUtils.java index 210365b261..b970b15cd6 100644 --- a/core/src/main/java/org/lflang/federated/generator/FedASTUtils.java +++ b/core/src/main/java/org/lflang/federated/generator/FedASTUtils.java @@ -70,7 +70,7 @@ import org.lflang.lf.Type; import org.lflang.lf.VarRef; import org.lflang.lf.Variable; -import org.lflang.target.CoordinationModeConfig.CoordinationMode; +import org.lflang.target.property.CoordinationModeProperty.CoordinationMode; /** * A helper class for AST transformations needed for federated execution. diff --git a/core/src/main/java/org/lflang/federated/generator/FedFileConfig.java b/core/src/main/java/org/lflang/federated/generator/FedFileConfig.java index 8ec7776cd4..00e49baa7d 100644 --- a/core/src/main/java/org/lflang/federated/generator/FedFileConfig.java +++ b/core/src/main/java/org/lflang/federated/generator/FedFileConfig.java @@ -100,8 +100,8 @@ public void doClean() throws IOException { * the generated .lf file for the federate. */ public void relativizePaths(FedTargetConfig targetConfig) { - relativizePathList(targetConfig.protoFiles); - relativizePathList(targetConfig.files); + relativizePathList(targetConfig.protoFiles.get()); + relativizePathList(targetConfig.files.get()); relativizePathList(targetConfig.cmakeIncludes.get()); } 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 0feee8144f..f3b74c495d 100644 --- a/core/src/main/java/org/lflang/federated/generator/FedGenerator.java +++ b/core/src/main/java/org/lflang/federated/generator/FedGenerator.java @@ -58,7 +58,7 @@ import org.lflang.lf.Reactor; import org.lflang.lf.TargetDecl; import org.lflang.lf.VarRef; -import org.lflang.target.CoordinationModeConfig.CoordinationMode; +import org.lflang.target.property.CoordinationModeProperty.CoordinationMode; import org.lflang.util.Averager; public class FedGenerator { @@ -153,7 +153,7 @@ public boolean doGenerate(Resource resource, LFGeneratorContext context) throws } // Do not invoke target code generators if --no-compile flag is used. - if (context.getTargetConfig().noCompile) { + if (context.getTargetConfig().noCompile.get()) { context.finish(Status.GENERATED, lf2lfCodeMapMap); return false; } diff --git a/core/src/main/java/org/lflang/federated/launcher/FedLauncherGenerator.java b/core/src/main/java/org/lflang/federated/launcher/FedLauncherGenerator.java index 7532ff1c66..da4081b753 100644 --- a/core/src/main/java/org/lflang/federated/launcher/FedLauncherGenerator.java +++ b/core/src/main/java/org/lflang/federated/launcher/FedLauncherGenerator.java @@ -37,7 +37,7 @@ import org.lflang.TargetConfig; import org.lflang.federated.generator.FedFileConfig; import org.lflang.federated.generator.FederateInstance; -import org.lflang.target.ClockSyncModeConfig.ClockSyncMode; +import org.lflang.target.property.ClockSyncModeProperty.ClockSyncMode; /** * Utility class that can be used to create a launcher for federated LF programs. diff --git a/core/src/main/java/org/lflang/generator/GeneratorUtils.java b/core/src/main/java/org/lflang/generator/GeneratorUtils.java index 469ba28b46..bac3ff1e5c 100644 --- a/core/src/main/java/org/lflang/generator/GeneratorUtils.java +++ b/core/src/main/java/org/lflang/generator/GeneratorUtils.java @@ -64,7 +64,7 @@ public static void accommodatePhysicalActionsIfPresent( String message = String.format( "Setting %s to true because of the physical action %s.", - TargetProperty.KEEPALIVE.getDisplayName(), action.getName()); + TargetProperty.KEEPALIVE, action.getName()); messageReporter.at(action).warning(message); return; } diff --git a/core/src/main/java/org/lflang/generator/LFGenerator.java b/core/src/main/java/org/lflang/generator/LFGenerator.java index 84a13f6fc8..2af1a27f83 100644 --- a/core/src/main/java/org/lflang/generator/LFGenerator.java +++ b/core/src/main/java/org/lflang/generator/LFGenerator.java @@ -181,7 +181,7 @@ private void runVerifierIfPropertiesDetected(Resource resource, LFGeneratorConte uclidGenerator.doGenerate(resource, lfContext); // Check the generated uclid files. - if (uclidGenerator.targetConfig.verify) { + if (uclidGenerator.targetConfig.verify.get()) { // Check if Uclid5 and Z3 are installed. if (!execInstalled("uclid", "--help", "uclid 0.9.5") 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 3deb90c18f..471bd78dcf 100644 --- a/core/src/main/java/org/lflang/generator/c/CCmakeGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CCmakeGenerator.java @@ -35,7 +35,7 @@ import org.lflang.MessageReporter; import org.lflang.TargetConfig; import org.lflang.generator.CodeBuilder; -import org.lflang.target.PlatformConfig.Platform; +import org.lflang.target.property.PlatformProperty.Platform; import org.lflang.util.FileUtil; /** @@ -366,7 +366,7 @@ CodeBuilder generateCMakeCode( } // link protobuf - if (!targetConfig.protoFiles.isEmpty()) { + if (!targetConfig.protoFiles.get().isEmpty()) { cMakeCode.pr("include(FindPackageHandleStandardArgs)"); cMakeCode.pr("FIND_PATH( PROTOBUF_INCLUDE_DIR protobuf-c/protobuf-c.h)"); cMakeCode.pr( @@ -385,7 +385,7 @@ CodeBuilder generateCMakeCode( // Set the compiler flags // We can detect a few common libraries and use the proper target_link_libraries to find them - for (String compilerFlag : targetConfig.compilerFlags) { + for (String compilerFlag : targetConfig.compilerFlags.get()) { messageReporter .nowhere() .warning( diff --git a/core/src/main/java/org/lflang/generator/c/CCompiler.java b/core/src/main/java/org/lflang/generator/c/CCompiler.java index f35b698c51..65ddfaa398 100644 --- a/core/src/main/java/org/lflang/generator/c/CCompiler.java +++ b/core/src/main/java/org/lflang/generator/c/CCompiler.java @@ -41,7 +41,7 @@ import org.lflang.generator.GeneratorUtils; import org.lflang.generator.LFGeneratorContext; import org.lflang.target.property.BuildConfig; -import org.lflang.target.PlatformConfig.Platform; +import org.lflang.target.property.PlatformProperty.Platform; import org.lflang.util.FileUtil; import org.lflang.util.LFCommand; @@ -122,10 +122,10 @@ public boolean runCCompiler(GeneratorBase generator, LFGeneratorContext context) if (targetConfig.compiler != null) { if (cppMode) { // Set the CXX environment variable to change the C++ compiler. - compile.replaceEnvironmentVariable("CXX", targetConfig.compiler); + compile.replaceEnvironmentVariable("CXX", targetConfig.compiler.get()); } else { // Set the CC environment variable to change the C compiler. - compile.replaceEnvironmentVariable("CC", targetConfig.compiler); + compile.replaceEnvironmentVariable("CC", targetConfig.compiler.get()); } } @@ -217,7 +217,7 @@ public LFCommand compileCmakeCommand() { } static Stream cmakeCompileDefinitions(TargetConfig targetConfig) { - return targetConfig.compileDefinitions.entrySet().stream() + return targetConfig.compileDefinitions.get().entrySet().stream() .map(entry -> "-D" + entry.getKey() + "=" + entry.getValue()); } @@ -404,11 +404,11 @@ public LFCommand compileCCommand(String fileToCompile, boolean noBinary) { } // Add compile definitions - targetConfig.compileDefinitions.forEach( + targetConfig.compileDefinitions.get().forEach( (key, value) -> compileArgs.add("-D" + key + "=" + value)); // Finally, add the compiler flags in target parameters (if any) - compileArgs.addAll(targetConfig.compilerFlags); + compileArgs.addAll(targetConfig.compilerFlags.get()); // Only set the output file name if it hasn't already been set // using a target property or Args line flag. @@ -426,7 +426,7 @@ public LFCommand compileCCommand(String fileToCompile, boolean noBinary) { } LFCommand command = - commandFactory.createCommand(targetConfig.compiler, compileArgs, fileConfig.getOutPath()); + commandFactory.createCommand(targetConfig.compiler.get(), compileArgs, fileConfig.getOutPath()); if (command == null) { messageReporter .nowhere() 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 70a2056f13..d00578d9c5 100644 --- a/core/src/main/java/org/lflang/generator/c/CGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CGenerator.java @@ -54,7 +54,7 @@ import org.lflang.Target; import org.lflang.TargetConfig; import org.lflang.TargetProperty; -import org.lflang.target.PlatformConfig.PlatformOption; +import org.lflang.target.property.PlatformProperty.PlatformOption; import org.lflang.ast.ASTUtils; import org.lflang.ast.DelayedConnectionTransformation; import org.lflang.federated.extensions.CExtensionUtils; @@ -88,8 +88,8 @@ import org.lflang.lf.ReactorDecl; import org.lflang.lf.StateVar; import org.lflang.lf.Variable; -import org.lflang.target.PlatformConfig.Platform; -import org.lflang.target.SchedulerConfig.SchedulerOption; +import org.lflang.target.property.PlatformProperty.Platform; +import org.lflang.target.property.SchedulerProperty.SchedulerOption; import org.lflang.util.ArduinoUtil; import org.lflang.util.FileUtil; @@ -466,7 +466,7 @@ public void doGenerate(Resource resource, LFGeneratorContext context) { //noinspection ThrowableNotThrown,ResultOfMethodCallIgnored Exceptions.sneakyThrow(e); } - if (!targetConfig.noCompile) { + if (!targetConfig.noCompile.get()) { ArduinoUtil arduinoUtil = new ArduinoUtil(context, commandFactory, messageReporter); arduinoUtil.buildArduino(fileConfig, targetConfig); context.finish(GeneratorResult.Status.COMPILED, null); @@ -502,8 +502,8 @@ public void doGenerate(Resource resource, LFGeneratorContext context) { // take over and do the rest of compilation. try { String compileDefs = - targetConfig.compileDefinitions.keySet().stream() - .map(key -> key + "=" + targetConfig.compileDefinitions.get(key)) + targetConfig.compileDefinitions.get().keySet().stream() + .map(key -> key + "=" + targetConfig.compileDefinitions.get().get(key)) .collect(Collectors.joining("\n")) + "\n"; FileUtil.writeToFile( @@ -517,8 +517,8 @@ public void doGenerate(Resource resource, LFGeneratorContext context) { // immediately compile the generated code. try { String compileDefs = - targetConfig.compileDefinitions.keySet().stream() - .map(key -> "\"-D" + key + "=" + targetConfig.compileDefinitions.get(key) + "\"") + targetConfig.compileDefinitions.get().keySet().stream() + .map(key -> "\"-D" + key + "=" + targetConfig.compileDefinitions.get().get(key) + "\"") .collect(Collectors.joining(",\n")); String settings = "{\n" + "\"cmake.configureArgs\": [\n" + compileDefs + "\n]\n}\n"; Path vscodePath = fileConfig.getSrcGenPath().resolve(".vscode"); @@ -537,7 +537,7 @@ public void doGenerate(Resource resource, LFGeneratorContext context) { // If this code generator is directly compiling the code, compile it now so that we // clean it up after, removing the #line directives after errors have been reported. - if (!targetConfig.noCompile + if (!targetConfig.noCompile.get() && targetConfig.dockerOptions == null && IterableExtensions.isNullOrEmpty(targetConfig.buildCommands.get()) // This code is unreachable in LSP_FAST mode, so that check is omitted. @@ -581,7 +581,7 @@ public void doGenerate(Resource resource, LFGeneratorContext context) { // If a build directive has been given, invoke it now. // Note that the code does not get cleaned in this case. - if (!targetConfig.noCompile) { + if (!targetConfig.noCompile.get()) { if (!IterableExtensions.isNullOrEmpty(targetConfig.buildCommands.get())) { CUtil.runBuildCommand( fileConfig, @@ -1959,15 +1959,15 @@ protected DockerGenerator getDockerGenerator(LFGeneratorContext context) { // Perform set up that does not generate code protected void setUpGeneralParameters() { accommodatePhysicalActionsIfPresent(); - targetConfig.compileDefinitions.put( - "LOG_LEVEL", String.valueOf(targetConfig.logLevel.ordinal())); + targetConfig.compileDefinitions.get().put( + "LOG_LEVEL", String.valueOf(targetConfig.logLevel.get().ordinal())); targetConfig.compileAdditionalSources.addAll(CCoreFilesUtils.getCTargetSrc()); // Create the main reactor instance if there is a main reactor. this.main = ASTUtils.createMainReactorInstance(mainDef, reactors, messageReporter, targetConfig); if (hasModalReactors) { // So that each separate compile knows about modal reactors, do this: - targetConfig.compileDefinitions.put("MODAL_REACTORS", "TRUE"); + targetConfig.compileDefinitions.get().put("MODAL_REACTORS", "TRUE"); } if (targetConfig.threading && targetConfig.platformOptions.get().platform == Platform.ARDUINO @@ -1983,7 +1983,7 @@ protected void setUpGeneralParameters() { } if (targetConfig.platformOptions.get().platform == Platform.ARDUINO - && !targetConfig.noCompile + && !targetConfig.noCompile.get() && targetConfig.platformOptions.get().board == null) { messageReporter .nowhere() @@ -1992,13 +1992,13 @@ protected void setUpGeneralParameters() { + " board name (FQBN) in the target property. For example, platform: {name:" + " arduino, board: arduino:avr:leonardo}. Entering \"no-compile\" mode and" + " generating target code only."); - targetConfig.noCompile = true; + targetConfig.noCompile.override(true); } if (targetConfig.platformOptions.get().platform == Platform.ZEPHYR && targetConfig.threading && targetConfig.platformOptions.get().userThreads >= 0) { - targetConfig.compileDefinitions.put( + targetConfig.compileDefinitions.get().put( PlatformOption.USER_THREADS.name(), String.valueOf(targetConfig.platformOptions.get().userThreads)); } else if (targetConfig.platformOptions.get().userThreads > 0) { @@ -2012,8 +2012,8 @@ protected void setUpGeneralParameters() { if (targetConfig.threading) { // FIXME: This logic is duplicated in CMake pickScheduler(); // FIXME: this and pickScheduler should be combined. - targetConfig.compileDefinitions.put("SCHEDULER", targetConfig.schedulerType.get().name()); - targetConfig.compileDefinitions.put( + targetConfig.compileDefinitions.get().put("SCHEDULER", targetConfig.schedulerType.get().name()); + targetConfig.compileDefinitions.get().put( "NUMBER_OF_WORKERS", String.valueOf(targetConfig.workers)); } pickCompilePlatform(); @@ -2021,7 +2021,7 @@ protected void setUpGeneralParameters() { protected void handleProtoFiles() { // Handle .proto files. - for (String file : targetConfig.protoFiles) { + for (String file : targetConfig.protoFiles.get()) { this.processProtoFile(file); } } @@ -2054,7 +2054,7 @@ protected String generateTopLevelPreambles(Reactor reactor) { .flatMap(it -> ASTUtils.allFileLevelPreambles(it).stream()) .collect(Collectors.toSet()) .forEach(it -> builder.pr(toText(it.getCode()))); - for (String file : targetConfig.protoFiles) { + for (String file : targetConfig.protoFiles.get()) { var dotIndex = file.lastIndexOf("."); var rootFilename = file; if (dotIndex > 0) { diff --git a/core/src/main/java/org/lflang/generator/c/CMainFunctionGenerator.java b/core/src/main/java/org/lflang/generator/c/CMainFunctionGenerator.java index 9dd130471c..824de835b8 100644 --- a/core/src/main/java/org/lflang/generator/c/CMainFunctionGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CMainFunctionGenerator.java @@ -4,7 +4,7 @@ import java.util.List; import org.lflang.TargetConfig; import org.lflang.generator.CodeBuilder; -import org.lflang.target.PlatformConfig.Platform; +import org.lflang.target.property.PlatformProperty.Platform; import org.lflang.util.StringUtil; public class CMainFunctionGenerator { @@ -105,10 +105,10 @@ private void parseTargetParameters() { runCommand.add("-k"); runCommand.add("true"); } - if (targetConfig.timeout != null) { + if (targetConfig.timeout.get() != null) { runCommand.add("-o"); - runCommand.add(targetConfig.timeout.getMagnitude() + ""); - runCommand.add(targetConfig.timeout.unit.getCanonicalName()); + runCommand.add(targetConfig.timeout.get().getMagnitude() + ""); + runCommand.add(targetConfig.timeout.get().unit.getCanonicalName()); } // The runCommand has a first entry that is ignored but needed. if (runCommand.size() > 0) { 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 da3794d44e..fd087e081a 100644 --- a/core/src/main/java/org/lflang/generator/c/CPreambleGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CPreambleGenerator.java @@ -5,7 +5,7 @@ import java.nio.file.Path; import org.lflang.TargetConfig; import org.lflang.generator.CodeBuilder; -import org.lflang.target.PlatformConfig.Platform; +import org.lflang.target.property.PlatformProperty.Platform; import org.lflang.util.StringUtil; /** @@ -61,7 +61,7 @@ public static String generateIncludeStatements(TargetConfig targetConfig, boolea public static String generateDefineDirectives( TargetConfig targetConfig, Path srcGenPath, boolean hasModalReactors) { - int logLevel = targetConfig.logLevel.ordinal(); + int logLevel = targetConfig.logLevel.get().ordinal(); var coordinationType = targetConfig.coordination; var tracing = targetConfig.tracing.get(); CodeBuilder code = new CodeBuilder(); @@ -70,7 +70,7 @@ public static String generateDefineDirectives( code.pr("#define TARGET_FILES_DIRECTORY " + addDoubleQuotes(srcGenPath.toString())); if (tracing != null) { - targetConfig.compileDefinitions.put("LF_TRACE", tracing.traceFileName); + targetConfig.compileDefinitions.get().put("LF_TRACE", tracing.traceFileName); } // if (clockSyncIsOn) { // code.pr(generateClockSyncDefineDirective( @@ -79,14 +79,14 @@ public static String generateDefineDirectives( // )); // } if (targetConfig.threading) { - targetConfig.compileDefinitions.put("LF_THREADED", "1"); + targetConfig.compileDefinitions.get().put("LF_THREADED", "1"); } else { - targetConfig.compileDefinitions.put("LF_UNTHREADED", "1"); + targetConfig.compileDefinitions.get().put("LF_UNTHREADED", "1"); } if (targetConfig.threading) { - targetConfig.compileDefinitions.put("LF_THREADED", "1"); + targetConfig.compileDefinitions.get().put("LF_THREADED", "1"); } else { - targetConfig.compileDefinitions.put("LF_UNTHREADED", "1"); + targetConfig.compileDefinitions.get().put("LF_UNTHREADED", "1"); } code.newLine(); return code.toString(); 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 25ab8b59b9..7bdb13706f 100644 --- a/core/src/main/java/org/lflang/generator/c/CTriggerObjectsGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CTriggerObjectsGenerator.java @@ -23,7 +23,7 @@ import org.lflang.generator.ReactorInstance; import org.lflang.generator.RuntimeRange; import org.lflang.generator.SendRange; -import org.lflang.target.LoggingConfigurator.LogLevel; +import org.lflang.target.property.LoggingProperty.LogLevel; /** * Generate code for the "_lf_initialize_trigger_objects" function @@ -879,7 +879,7 @@ private static String deferredReactionOutputs( // val selfRef = CUtil.reactorRef(reaction.getParent()); var name = reaction.getParent().getFullName(); // Insert a string name to facilitate debugging. - if (targetConfig.logLevel.compareTo(LogLevel.LOG) >= 0) { + if (targetConfig.logLevel.get().compareTo(LogLevel.LOG) >= 0) { code.pr( CUtil.reactionRef(reaction) + ".name = " diff --git a/core/src/main/java/org/lflang/generator/python/PythonGenerator.java b/core/src/main/java/org/lflang/generator/python/PythonGenerator.java index 16615bb59e..e9998d268c 100644 --- a/core/src/main/java/org/lflang/generator/python/PythonGenerator.java +++ b/core/src/main/java/org/lflang/generator/python/PythonGenerator.java @@ -107,9 +107,9 @@ public PythonGenerator(LFGeneratorContext context) { private PythonGenerator( LFGeneratorContext context, PythonTypes types, CCmakeGenerator cmakeGenerator) { super(context, false, types, cmakeGenerator, new PythonDelayBodyGenerator(types)); - this.targetConfig.compiler = "gcc"; - this.targetConfig.compilerFlags = new ArrayList<>(); - this.targetConfig.linkerFlags = ""; + this.targetConfig.compiler.override("gcc"); // FIXME: why? + this.targetConfig.compilerFlags.get().clear(); + this.targetConfig.linkerFlags = ""; // FIXME: why? this.types = types; } @@ -277,7 +277,7 @@ protected String generateTopLevelPreambles(Reactor ignored) { @Override protected void handleProtoFiles() { - for (String name : targetConfig.protoFiles) { + for (String name : targetConfig.protoFiles.get()) { this.processProtoFile(name); int dotIndex = name.lastIndexOf("."); String rootFilename = dotIndex > 0 ? name.substring(0, dotIndex) : name; diff --git a/core/src/main/java/org/lflang/generator/rust/CargoDependencySpec.java b/core/src/main/java/org/lflang/generator/rust/CargoDependencySpec.java index c1e6fad3f3..02976257fd 100644 --- a/core/src/main/java/org/lflang/generator/rust/CargoDependencySpec.java +++ b/core/src/main/java/org/lflang/generator/rust/CargoDependencySpec.java @@ -44,6 +44,7 @@ import org.lflang.target.property.type.TargetPropertyType; import org.lflang.util.StringUtil; import org.lflang.validation.LFValidator; +import org.lflang.validation.ValidationReporter; /** * Info about a cargo dependency. See {@link TargetProperty#CARGO_DEPENDENCIES}. @@ -278,17 +279,20 @@ public boolean validate(Element e) { } @Override - public void check(Element element, String name, LFValidator v) { + public boolean check(Element element, String name, ValidationReporter v) { + var valid = true; for (KeyValuePair pair : element.getKeyvalue().getPairs()) { try { parseValue(pair); } catch (InvalidLfSourceException e) { - MessageReporter messageReporter = v.getErrorReporter(); EObject object = e.getNode(); String message = e.getProblem(); - messageReporter.at(object).error(message); + // FIXME: use ValidatorMessageReporter + // v.at(object).error(message); + valid = false; } } + return valid; } @Override diff --git a/core/src/main/java/org/lflang/generator/rust/RustTargetConfig.java b/core/src/main/java/org/lflang/generator/rust/RustTargetConfig.java index dc9a766ba8..c453763399 100644 --- a/core/src/main/java/org/lflang/generator/rust/RustTargetConfig.java +++ b/core/src/main/java/org/lflang/generator/rust/RustTargetConfig.java @@ -24,16 +24,11 @@ package org.lflang.generator.rust; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import org.eclipse.emf.ecore.EObject; -import org.lflang.MessageReporter; import org.lflang.target.property.BuildConfig.BuildType; -import org.lflang.target.property.BuildTypeConfig; +import org.lflang.target.property.BuildTypeProperty; +import org.lflang.target.property.CargoDependenciesProperty; +import org.lflang.target.property.CargoFeaturesProperty; +import org.lflang.target.property.RustIncludeProperty; /** * Rust-specific part of a {@link org.lflang.TargetConfig}. @@ -43,60 +38,20 @@ public final class RustTargetConfig { /** List of Cargo features of the generated crate to enable. */ - private List cargoFeatures = new ArrayList<>(); + public final CargoFeaturesProperty cargoFeatures = new CargoFeaturesProperty(); /** Map of Cargo dependency to dependency properties. */ - private Map cargoDependencies = new HashMap<>(); + public final CargoDependenciesProperty cargoDependencies = new CargoDependenciesProperty(); /** List of top-level modules, those are absolute paths. */ - private final List rustTopLevelModules = new ArrayList<>(); + public final RustIncludeProperty rustTopLevelModules = new RustIncludeProperty(); /** Cargo profile, default is debug (corresponds to cargo dev profile). */ private BuildType profile = BuildType.DEBUG; - public void setCargoFeatures(List cargoFeatures) { - this.cargoFeatures = cargoFeatures; - } - - public void setCargoDependencies(Map cargoDependencies) { - this.cargoDependencies = cargoDependencies; - } - - public void addAndCheckTopLevelModule(Path path, EObject errorOwner, MessageReporter err) { - String fileName = path.getFileName().toString(); - if (!Files.exists(path)) { - err.at(errorOwner).error("File not found"); - } else if (Files.isRegularFile(path) && !fileName.endsWith(".rs")) { - err.at(errorOwner).error("Not a rust file"); - } else if (fileName.equals("main.rs")) { - err.at(errorOwner).error("Cannot use 'main.rs' as a module name (reserved)"); - } else if (fileName.equals("reactors") || fileName.equals("reactors.rs")) { - err.at(errorOwner).error("Cannot use 'reactors' as a module name (reserved)"); - } else if (Files.isDirectory(path) && !Files.exists(path.resolve("mod.rs"))) { - err.at(errorOwner).error("Cannot find module descriptor in directory"); - } - this.rustTopLevelModules.add(path); - } - - public List getCargoFeatures() { - return cargoFeatures; - } - - /** Returns a map of cargo dependencies. */ - public Map getCargoDependencies() { - return cargoDependencies; - } - - /** - * Returns the list of top-level module files to include in main.rs. Those files were checked to - * exists previously. - */ - public List getRustTopLevelModules() { - return rustTopLevelModules; - } /** The build type to use. Corresponds to a Cargo profile. */ - public BuildType getBuildType(BuildTypeConfig cmakeBuildType) { + public BuildType getBuildType(BuildTypeProperty cmakeBuildType) { // FIXME: this is because Rust uses a different default. // Can we just use the same? if (cmakeBuildType.isSetByUser()) { diff --git a/core/src/main/java/org/lflang/target/LoggingConfigurator.java b/core/src/main/java/org/lflang/target/LoggingConfigurator.java deleted file mode 100644 index 5f0b537fd8..0000000000 --- a/core/src/main/java/org/lflang/target/LoggingConfigurator.java +++ /dev/null @@ -1,23 +0,0 @@ -package org.lflang.target; - -public class LoggingConfigurator { - - /** - * Log levels in descending order of severity. - * - * @author Marten Lohstroh - */ - public enum LogLevel { - ERROR, - WARN, - INFO, - LOG, - DEBUG; - - /** Return the name in lower case. */ - @Override - public String toString() { - return this.name().toLowerCase(); - } - } -} diff --git a/core/src/main/java/org/lflang/target/property/AuthProperty.java b/core/src/main/java/org/lflang/target/property/AuthProperty.java new file mode 100644 index 0000000000..6106948282 --- /dev/null +++ b/core/src/main/java/org/lflang/target/property/AuthProperty.java @@ -0,0 +1,16 @@ +package org.lflang.target.property; + +import java.util.Arrays; +import java.util.List; + +import org.lflang.Target; +import org.lflang.target.property.DefaultBooleanProperty; + +public class AuthProperty extends DefaultBooleanProperty { + + @Override + public List supportedTargets() { + return Arrays.asList(Target.C, Target.CCPP); + } + +} diff --git a/core/src/main/java/org/lflang/target/property/BuildCommandsProperty.java b/core/src/main/java/org/lflang/target/property/BuildCommandsProperty.java new file mode 100644 index 0000000000..33d46e7639 --- /dev/null +++ b/core/src/main/java/org/lflang/target/property/BuildCommandsProperty.java @@ -0,0 +1,40 @@ +package org.lflang.target.property; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.lflang.Target; +import org.lflang.TargetPropertyConfig; +import org.lflang.ast.ASTUtils; +import org.lflang.lf.Element; +import org.lflang.target.property.type.UnionType; + +public class BuildCommandsProperty extends TargetPropertyConfig> { + + + public BuildCommandsProperty() { + super(UnionType.STRING_OR_STRING_ARRAY); + } + + @Override + public List initialize() { + return new ArrayList<>(); + } + + @Override + public List parse(Element value) { + return ASTUtils.elementToListOfStrings(value); + } + + @Override + public List supportedTargets() { + return Arrays.asList(Target.C, Target.CCPP); + } + + @Override + public Element export() { + return ASTUtils.toElement(this.value.toString()); + } + +} diff --git a/core/src/main/java/org/lflang/target/property/BuildTypeConfig.java b/core/src/main/java/org/lflang/target/property/BuildTypeProperty.java similarity index 72% rename from core/src/main/java/org/lflang/target/property/BuildTypeConfig.java rename to core/src/main/java/org/lflang/target/property/BuildTypeProperty.java index 28e2e37cfe..eeca094465 100644 --- a/core/src/main/java/org/lflang/target/property/BuildTypeConfig.java +++ b/core/src/main/java/org/lflang/target/property/BuildTypeProperty.java @@ -1,7 +1,10 @@ package org.lflang.target.property; +import java.util.Arrays; +import java.util.List; import java.util.Properties; +import org.lflang.Target; import org.lflang.TargetProperty; import org.lflang.TargetPropertyConfig; import org.lflang.ast.ASTUtils; @@ -9,7 +12,11 @@ import org.lflang.target.property.BuildConfig.BuildType; import org.lflang.target.property.type.UnionType; -public class BuildTypeConfig extends TargetPropertyConfig { +public class BuildTypeProperty extends TargetPropertyConfig { + + public BuildTypeProperty() { + super(UnionType.BUILD_TYPE_UNION); + } @Override public Element export() { @@ -26,6 +33,11 @@ public BuildType parse(Element value) { return (BuildType) UnionType.BUILD_TYPE_UNION.forName(ASTUtils.elementToSingleString(value)); } + @Override + public List supportedTargets() { + return Arrays.asList(Target.C, Target.CCPP, Target.CPP, Target.Rust); + } + @Override public void update(Properties cliArgs) { super.update(cliArgs); diff --git a/core/src/main/java/org/lflang/target/property/CargoDependenciesProperty.java b/core/src/main/java/org/lflang/target/property/CargoDependenciesProperty.java new file mode 100644 index 0000000000..40f957d6c0 --- /dev/null +++ b/core/src/main/java/org/lflang/target/property/CargoDependenciesProperty.java @@ -0,0 +1,57 @@ +package org.lflang.target.property; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.lflang.Target; +import org.lflang.TargetPropertyConfig; +import org.lflang.generator.rust.CargoDependencySpec; +import org.lflang.generator.rust.CargoDependencySpec.CargoDependenciesPropertyType; +import org.lflang.lf.Element; +import org.lflang.lf.KeyValuePair; +import org.lflang.lf.KeyValuePairs; +import org.lflang.lf.LfFactory; + +public class CargoDependenciesProperty extends TargetPropertyConfig> { + + public CargoDependenciesProperty() { + super(CargoDependenciesPropertyType.INSTANCE); + } + + @Override + public Map initialize() { + return new HashMap<>(); + } + + @Override + protected Map parse(Element value) { + return CargoDependencySpec.parseAll(value); + } + + @Override + public List supportedTargets() { + return Arrays.asList(Target.Rust); + } + + @Override + public Element export() { + var deps = this.value; + if (deps.size() == 0) { + return null; + } else { + Element e = LfFactory.eINSTANCE.createElement(); + KeyValuePairs kvp = LfFactory.eINSTANCE.createKeyValuePairs(); + for (var ent : deps.entrySet()) { + KeyValuePair pair = LfFactory.eINSTANCE.createKeyValuePair(); + pair.setName(ent.getKey()); + pair.setValue(CargoDependencySpec.extractSpec(ent.getValue())); + kvp.getPairs().add(pair); + } + e.setKeyvalue(kvp); + return e; + } + } + +} diff --git a/core/src/main/java/org/lflang/target/property/CargoFeaturesProperty.java b/core/src/main/java/org/lflang/target/property/CargoFeaturesProperty.java new file mode 100644 index 0000000000..e870154681 --- /dev/null +++ b/core/src/main/java/org/lflang/target/property/CargoFeaturesProperty.java @@ -0,0 +1,15 @@ +package org.lflang.target.property; + +import java.util.Arrays; +import java.util.List; + +import org.lflang.Target; + +public class CargoFeaturesProperty extends DefaultStringListProperty { + + @Override + public List supportedTargets() { + return Arrays.asList(Target.Rust); + } + +} diff --git a/core/src/main/java/org/lflang/target/ClockSyncModeConfig.java b/core/src/main/java/org/lflang/target/property/ClockSyncModeProperty.java similarity index 76% rename from core/src/main/java/org/lflang/target/ClockSyncModeConfig.java rename to core/src/main/java/org/lflang/target/property/ClockSyncModeProperty.java index f0372002db..dd541fed0f 100644 --- a/core/src/main/java/org/lflang/target/ClockSyncModeConfig.java +++ b/core/src/main/java/org/lflang/target/property/ClockSyncModeProperty.java @@ -1,6 +1,11 @@ -package org.lflang.target; +package org.lflang.target.property; +import java.util.Arrays; +import java.util.List; +import java.util.Objects; + +import org.lflang.Target; import org.lflang.TargetConfig; import org.lflang.TargetPropertyConfig; import org.lflang.ast.ASTUtils; @@ -9,12 +14,16 @@ import org.lflang.lf.LfPackage.Literals; import org.lflang.lf.Model; import org.lflang.lf.Reactor; -import org.lflang.target.ClockSyncModeConfig.ClockSyncMode; +import org.lflang.target.property.ClockSyncModeProperty.ClockSyncMode; import org.lflang.target.property.type.UnionType; import org.lflang.validation.ValidationReporter; -public class ClockSyncModeConfig extends TargetPropertyConfig { +public class ClockSyncModeProperty extends TargetPropertyConfig { + + public ClockSyncModeProperty() { + super(UnionType.CLOCK_SYNC_UNION); + } @Override public ClockSyncMode initialize() { @@ -27,15 +36,17 @@ public ClockSyncMode parse(Element value) { UnionType.CLOCK_SYNC_UNION.validate(value); var mode = (ClockSyncMode) UnionType.CLOCK_SYNC_UNION.forName(ASTUtils.elementToSingleString(value)); - if (mode != null) { - return mode; - } else { - return ClockSyncMode.INIT; - } + return Objects.requireNonNullElse(mode, ClockSyncMode.INIT); + } + + @Override + public List supportedTargets() { + return Arrays.asList(Target.C, Target.CCPP, Target.Python); } @Override public void validate(KeyValuePair pair, Model ast, TargetConfig config, ValidationReporter reporter) { + super.validate(pair, ast, config, reporter); if (pair != null) { boolean federatedExists = false; for (Reactor reactor : ast.getReactors()) { diff --git a/core/src/main/java/org/lflang/target/property/ClockSyncOptionsConfig.java b/core/src/main/java/org/lflang/target/property/ClockSyncOptionsProperty.java similarity index 92% rename from core/src/main/java/org/lflang/target/property/ClockSyncOptionsConfig.java rename to core/src/main/java/org/lflang/target/property/ClockSyncOptionsProperty.java index 9e984318a4..4b790b409f 100644 --- a/core/src/main/java/org/lflang/target/property/ClockSyncOptionsConfig.java +++ b/core/src/main/java/org/lflang/target/property/ClockSyncOptionsProperty.java @@ -1,6 +1,9 @@ package org.lflang.target.property; -import org.lflang.TargetConfig; +import java.util.Arrays; +import java.util.List; + +import org.lflang.Target; import org.lflang.TargetProperty.DictionaryElement; import org.lflang.TargetPropertyConfig; import org.lflang.TimeUnit; @@ -10,14 +13,16 @@ import org.lflang.lf.KeyValuePair; import org.lflang.lf.KeyValuePairs; import org.lflang.lf.LfFactory; -import org.lflang.lf.Model; -import org.lflang.target.property.ClockSyncOptionsConfig.ClockSyncOptions; +import org.lflang.target.property.ClockSyncOptionsProperty.ClockSyncOptions; import org.lflang.target.property.type.DictionaryType; import org.lflang.target.property.type.PrimitiveType; import org.lflang.target.property.type.TargetPropertyType; -import org.lflang.validation.ValidationReporter; -public class ClockSyncOptionsConfig extends TargetPropertyConfig { +public class ClockSyncOptionsProperty extends TargetPropertyConfig { + + public ClockSyncOptionsProperty() { + super(DictionaryType.CLOCK_SYNC_OPTION_DICT); + } @Override public ClockSyncOptions initialize() { @@ -46,8 +51,8 @@ public ClockSyncOptions parse(Element value) { } @Override - public void validate(KeyValuePair pair, Model ast, TargetConfig config, ValidationReporter reporter) { - + public List supportedTargets() { + return Arrays.asList(Target.C, Target.CCPP, Target.Python); } @Override diff --git a/core/src/main/java/org/lflang/target/property/type/CmakeIncludeConfig.java b/core/src/main/java/org/lflang/target/property/CmakeIncludeProperty.java similarity index 69% rename from core/src/main/java/org/lflang/target/property/type/CmakeIncludeConfig.java rename to core/src/main/java/org/lflang/target/property/CmakeIncludeProperty.java index ebfac71d55..4dd02b840b 100644 --- a/core/src/main/java/org/lflang/target/property/type/CmakeIncludeConfig.java +++ b/core/src/main/java/org/lflang/target/property/CmakeIncludeProperty.java @@ -1,14 +1,21 @@ -package org.lflang.target.property.type; +package org.lflang.target.property; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import org.lflang.MessageReporter; +import org.lflang.Target; import org.lflang.TargetPropertyConfig; import org.lflang.ast.ASTUtils; import org.lflang.lf.Element; +import org.lflang.target.property.type.UnionType; -public class CmakeIncludeConfig extends TargetPropertyConfig> { +public class CmakeIncludeProperty extends TargetPropertyConfig> { + + public CmakeIncludeProperty() { + super(UnionType.FILE_OR_FILE_ARRAY); + } @Override public List initialize() { @@ -30,6 +37,11 @@ protected List parse(Element value) { return ASTUtils.elementToListOfStrings(value); } + @Override + public List supportedTargets() { + return Arrays.asList(Target.CPP, Target.C, Target.CCPP); + } + @Override public Element export() { return ASTUtils.toElement(this.value); diff --git a/core/src/main/java/org/lflang/target/property/CompileDefinitionsConfig.java b/core/src/main/java/org/lflang/target/property/CompileDefinitionsConfig.java new file mode 100644 index 0000000000..773bb7298a --- /dev/null +++ b/core/src/main/java/org/lflang/target/property/CompileDefinitionsConfig.java @@ -0,0 +1,38 @@ +package org.lflang.target.property.type; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.lflang.Target; +import org.lflang.TargetPropertyConfig; +import org.lflang.ast.ASTUtils; +import org.lflang.lf.Element; + +public class CompileDefinitionsConfig extends TargetPropertyConfig> { + + public CompileDefinitionsConfig() { + super(StringDictionaryType.COMPILE_DEFINITION); + } + + @Override + public Map initialize() { + return new HashMap<>(); + } + + @Override + protected Map parse(Element value) { + return ASTUtils.elementToStringMaps(value); + } + + @Override + public List supportedTargets() { + return Arrays.asList(Target.C, Target.CCPP, Target.Python); + } + + @Override + public Element export() { + return ASTUtils.toElement(this.value); + } +} diff --git a/core/src/main/java/org/lflang/target/property/CompilerFlagsProperty.java b/core/src/main/java/org/lflang/target/property/CompilerFlagsProperty.java new file mode 100644 index 0000000000..da1df83b44 --- /dev/null +++ b/core/src/main/java/org/lflang/target/property/CompilerFlagsProperty.java @@ -0,0 +1,15 @@ +package org.lflang.target.property; + +import java.util.Arrays; +import java.util.List; + +import org.lflang.Target; + +public class CompilerFlagsProperty extends DefaultStringListProperty { + + @Override + public List supportedTargets() { + return Arrays.asList(Target.C, Target.CCPP); + } + +} diff --git a/core/src/main/java/org/lflang/target/CoordinationModeConfig.java b/core/src/main/java/org/lflang/target/property/CoordinationModeProperty.java similarity index 69% rename from core/src/main/java/org/lflang/target/CoordinationModeConfig.java rename to core/src/main/java/org/lflang/target/property/CoordinationModeProperty.java index b541b4a164..75397af897 100644 --- a/core/src/main/java/org/lflang/target/CoordinationModeConfig.java +++ b/core/src/main/java/org/lflang/target/property/CoordinationModeProperty.java @@ -1,16 +1,24 @@ -package org.lflang.target; +package org.lflang.target.property; +import java.util.Arrays; +import java.util.List; + +import org.lflang.Target; import org.lflang.TargetConfig; import org.lflang.TargetPropertyConfig; import org.lflang.ast.ASTUtils; import org.lflang.lf.Element; import org.lflang.lf.KeyValuePair; import org.lflang.lf.Model; -import org.lflang.target.CoordinationModeConfig.CoordinationMode; +import org.lflang.target.property.CoordinationModeProperty.CoordinationMode; import org.lflang.target.property.type.UnionType; import org.lflang.validation.ValidationReporter; -public class CoordinationModeConfig extends TargetPropertyConfig { +public class CoordinationModeProperty extends TargetPropertyConfig { + + public CoordinationModeProperty() { + super(UnionType.COORDINATION_UNION); + } @Override public CoordinationMode initialize() { @@ -22,6 +30,11 @@ public CoordinationMode parse(Element value) { return (CoordinationMode) UnionType.COORDINATION_UNION.forName(ASTUtils.elementToSingleString(value)); } + @Override + public List supportedTargets() { + return Arrays.asList(Target.C, Target.CCPP, Target.Python); + } + @Override public void validate(KeyValuePair pair, Model ast, TargetConfig config, ValidationReporter reporter) {} diff --git a/core/src/main/java/org/lflang/target/CoordinationOptionsConfig.java b/core/src/main/java/org/lflang/target/property/CoordinationOptionsProperty.java similarity index 87% rename from core/src/main/java/org/lflang/target/CoordinationOptionsConfig.java rename to core/src/main/java/org/lflang/target/property/CoordinationOptionsProperty.java index 755ffc73ff..3f0ea42e04 100644 --- a/core/src/main/java/org/lflang/target/CoordinationOptionsConfig.java +++ b/core/src/main/java/org/lflang/target/property/CoordinationOptionsProperty.java @@ -1,7 +1,9 @@ -package org.lflang.target; +package org.lflang.target.property; -import org.lflang.TargetConfig; +import java.util.Arrays; +import java.util.List; +import org.lflang.Target; import org.lflang.TargetProperty.DictionaryElement; import org.lflang.TargetPropertyConfig; import org.lflang.TimeValue; @@ -10,14 +12,17 @@ import org.lflang.lf.KeyValuePair; import org.lflang.lf.KeyValuePairs; import org.lflang.lf.LfFactory; -import org.lflang.lf.Model; -import org.lflang.target.CoordinationOptionsConfig.CoordinationOptions; + +import org.lflang.target.property.CoordinationOptionsProperty.CoordinationOptions; import org.lflang.target.property.type.DictionaryType; import org.lflang.target.property.type.PrimitiveType; import org.lflang.target.property.type.TargetPropertyType; -import org.lflang.validation.ValidationReporter; -public class CoordinationOptionsConfig extends TargetPropertyConfig { +public class CoordinationOptionsProperty extends TargetPropertyConfig { + + public CoordinationOptionsProperty() { + super(DictionaryType.COORDINATION_OPTION_DICT); + } @Override public CoordinationOptions initialize() { @@ -43,8 +48,8 @@ public CoordinationOptions parse(Element value) { } @Override - public void validate(KeyValuePair pair, Model ast, TargetConfig config, ValidationReporter reporter) { - // FIXME + public List supportedTargets() { + return Arrays.asList(Target.C, Target.CCPP, Target.Python, Target.TS); } @Override diff --git a/core/src/main/java/org/lflang/target/AuthConfig.java b/core/src/main/java/org/lflang/target/property/DefaultBooleanProperty.java similarity index 53% rename from core/src/main/java/org/lflang/target/AuthConfig.java rename to core/src/main/java/org/lflang/target/property/DefaultBooleanProperty.java index 2c97897f7b..e546e704bb 100644 --- a/core/src/main/java/org/lflang/target/AuthConfig.java +++ b/core/src/main/java/org/lflang/target/property/DefaultBooleanProperty.java @@ -1,10 +1,17 @@ -package org.lflang.target; +package org.lflang.target.property; + import org.lflang.TargetPropertyConfig; import org.lflang.ast.ASTUtils; import org.lflang.lf.Element; +import org.lflang.target.property.type.PrimitiveType; + -public class AuthConfig extends TargetPropertyConfig { +public abstract class DefaultBooleanProperty extends TargetPropertyConfig { + + public DefaultBooleanProperty() { + super(PrimitiveType.BOOLEAN); + } @Override public Boolean initialize() { @@ -18,7 +25,6 @@ public Boolean parse(Element value) { @Override public Element export() { - return ASTUtils.toElement(this.value.toString()); + return ASTUtils.toElement(value); } - } diff --git a/core/src/main/java/org/lflang/target/property/DefaultFileListProperty.java b/core/src/main/java/org/lflang/target/property/DefaultFileListProperty.java new file mode 100644 index 0000000000..b69b053ea3 --- /dev/null +++ b/core/src/main/java/org/lflang/target/property/DefaultFileListProperty.java @@ -0,0 +1,39 @@ +package org.lflang.target.property; + + +import java.util.ArrayList; +import java.util.List; + +import org.lflang.TargetPropertyConfig; +import org.lflang.ast.ASTUtils; +import org.lflang.lf.Element; +import org.lflang.target.property.type.UnionType; + + +public abstract class DefaultFileListProperty extends TargetPropertyConfig> { + + public DefaultFileListProperty() { + super(UnionType.FILE_OR_FILE_ARRAY); + } + + @Override + public void override(List value) { // FIXME: should this be override or update? + this.setByUser = true; + this.value.addAll(value); + } + + @Override + public List initialize() { + return new ArrayList<>(); + } + + @Override + public List parse(Element value) { + return ASTUtils.elementToListOfStrings(value); + } + + @Override + public Element export() { + return ASTUtils.toElement(value); + } +} diff --git a/core/src/main/java/org/lflang/target/property/DefaultStringConfig.java b/core/src/main/java/org/lflang/target/property/DefaultStringConfig.java new file mode 100644 index 0000000000..094c7c1728 --- /dev/null +++ b/core/src/main/java/org/lflang/target/property/DefaultStringConfig.java @@ -0,0 +1,33 @@ +package org.lflang.target.property; + + +import java.util.List; + +import org.lflang.Target; +import org.lflang.TargetPropertyConfig; +import org.lflang.ast.ASTUtils; +import org.lflang.lf.Element; +import org.lflang.target.property.type.PrimitiveType; + + +public abstract class DefaultStringConfig extends TargetPropertyConfig { + + public DefaultStringConfig() { + super(PrimitiveType.STRING); + } + + @Override + public String initialize() { + return ""; + } + + @Override + public String parse(Element value) { + return ASTUtils.elementToSingleString(value); + } + + @Override + public Element export() { + return ASTUtils.toElement(value); + } +} diff --git a/core/src/main/java/org/lflang/target/property/BuildCommandsConfig.java b/core/src/main/java/org/lflang/target/property/DefaultStringListProperty.java similarity index 61% rename from core/src/main/java/org/lflang/target/property/BuildCommandsConfig.java rename to core/src/main/java/org/lflang/target/property/DefaultStringListProperty.java index 22458f8a76..e7bb90b4cb 100644 --- a/core/src/main/java/org/lflang/target/property/BuildCommandsConfig.java +++ b/core/src/main/java/org/lflang/target/property/DefaultStringListProperty.java @@ -1,13 +1,20 @@ package org.lflang.target.property; + import java.util.ArrayList; import java.util.List; import org.lflang.TargetPropertyConfig; import org.lflang.ast.ASTUtils; import org.lflang.lf.Element; +import org.lflang.target.property.type.UnionType; + -public class BuildCommandsConfig extends TargetPropertyConfig> { +public abstract class DefaultStringListProperty extends TargetPropertyConfig> { + + public DefaultStringListProperty() { + super(UnionType.STRING_OR_STRING_ARRAY); + } @Override public List initialize() { @@ -21,7 +28,7 @@ public List parse(Element value) { @Override public Element export() { - return ASTUtils.toElement(this.value.toString()); + return ASTUtils.toElement(value); } } diff --git a/core/src/main/java/org/lflang/target/DockerConfig.java b/core/src/main/java/org/lflang/target/property/DockerProperty.java similarity index 89% rename from core/src/main/java/org/lflang/target/DockerConfig.java rename to core/src/main/java/org/lflang/target/property/DockerProperty.java index ebc319b768..b5136cfd7b 100644 --- a/core/src/main/java/org/lflang/target/DockerConfig.java +++ b/core/src/main/java/org/lflang/target/property/DockerProperty.java @@ -1,26 +1,31 @@ -package org.lflang.target; +package org.lflang.target.property; +import java.util.Arrays; +import java.util.List; import java.util.Properties; -import org.lflang.TargetConfig; +import org.lflang.Target; import org.lflang.TargetProperty; import org.lflang.TargetPropertyConfig; import org.lflang.TargetProperty.DictionaryElement; import org.lflang.ast.ASTUtils; import org.lflang.lf.KeyValuePairs; import org.lflang.lf.LfFactory; -import org.lflang.target.DockerConfig.DockerOptions; +import org.lflang.target.property.DockerProperty.DockerOptions; import org.lflang.target.property.type.DictionaryType; import org.lflang.target.property.type.PrimitiveType; import org.lflang.target.property.type.TargetPropertyType; import org.lflang.lf.Element; import org.lflang.lf.KeyValuePair; -import org.lflang.lf.Model; -import org.lflang.validation.ValidationReporter; +import org.lflang.target.property.type.UnionType; -public class DockerConfig extends TargetPropertyConfig { +public class DockerProperty extends TargetPropertyConfig { + + public DockerProperty() { + super(UnionType.DOCKER_UNION); + } @Override public DockerOptions initialize() { @@ -63,8 +68,8 @@ public DockerOptions parse(Element value) { } @Override - public void validate(KeyValuePair pair, Model ast, TargetConfig config, ValidationReporter reporter) { - + public List supportedTargets() { + return Arrays.asList(Target.C, Target.CCPP, Target.Python, Target.TS); } @Override diff --git a/core/src/main/java/org/lflang/target/property/ExportDependencyGraphProperty.java b/core/src/main/java/org/lflang/target/property/ExportDependencyGraphProperty.java new file mode 100644 index 0000000000..b71ba34311 --- /dev/null +++ b/core/src/main/java/org/lflang/target/property/ExportDependencyGraphProperty.java @@ -0,0 +1,14 @@ +package org.lflang.target.property; + +import java.util.List; + +import org.lflang.Target; + +public class ExportDependencyGraphProperty extends DefaultBooleanProperty { + + @Override + public List supportedTargets() { + return List.of(Target.CPP, Target.Rust); + } + +} diff --git a/core/src/main/java/org/lflang/target/property/ExportToYamlProperty.java b/core/src/main/java/org/lflang/target/property/ExportToYamlProperty.java new file mode 100644 index 0000000000..6abb07ccd3 --- /dev/null +++ b/core/src/main/java/org/lflang/target/property/ExportToYamlProperty.java @@ -0,0 +1,14 @@ +package org.lflang.target.property; + +import java.util.List; + +import org.lflang.Target; + +public class ExportToYamlProperty extends DefaultBooleanProperty { + + @Override + public List supportedTargets() { + return List.of(Target.CPP); + } + +} diff --git a/core/src/main/java/org/lflang/target/property/ExternalRuntimePathConfig.java b/core/src/main/java/org/lflang/target/property/ExternalRuntimePathConfig.java new file mode 100644 index 0000000000..0e606019a4 --- /dev/null +++ b/core/src/main/java/org/lflang/target/property/ExternalRuntimePathConfig.java @@ -0,0 +1,14 @@ +package org.lflang.target.property.type; + +import java.util.List; + +import org.lflang.Target; +import org.lflang.target.property.DefaultStringConfig; + +public class ExternalRuntimePathConfig extends DefaultStringConfig { + + @Override + public List supportedTargets() { + return List.of(Target.CPP); + } +} diff --git a/core/src/main/java/org/lflang/target/FastModeConfig.java b/core/src/main/java/org/lflang/target/property/FastProperty.java similarity index 77% rename from core/src/main/java/org/lflang/target/FastModeConfig.java rename to core/src/main/java/org/lflang/target/property/FastProperty.java index 72ded2c473..f15493068b 100644 --- a/core/src/main/java/org/lflang/target/FastModeConfig.java +++ b/core/src/main/java/org/lflang/target/property/FastProperty.java @@ -1,27 +1,24 @@ -package org.lflang.target; +package org.lflang.target.property; +import java.util.List; + +import org.lflang.Target; import org.lflang.TargetConfig; -import org.lflang.TargetPropertyConfig; -import org.lflang.ast.ASTUtils; import org.lflang.lf.Action; import org.lflang.lf.ActionOrigin; -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.validation.ValidationReporter; +import org.lflang.target.property.DefaultBooleanProperty; -public class FastModeConfig extends TargetPropertyConfig { +import org.lflang.validation.ValidationReporter; - @Override - public Boolean initialize() { - return false; - } +public class FastProperty extends DefaultBooleanProperty { @Override - public Boolean parse(Element value) { - return ASTUtils.toBoolean(value); + public List supportedTargets() { + return Target.ALL; } @Override @@ -53,12 +50,5 @@ public void validate(KeyValuePair pair, Model ast, TargetConfig config, Validati } } } - } - - @Override - public Element export() { - return ASTUtils.toElement(this.value); - } - } diff --git a/core/src/main/java/org/lflang/target/property/FilesProperty.java b/core/src/main/java/org/lflang/target/property/FilesProperty.java new file mode 100644 index 0000000000..61750c8c37 --- /dev/null +++ b/core/src/main/java/org/lflang/target/property/FilesProperty.java @@ -0,0 +1,14 @@ +package org.lflang.target.property; + +import java.util.List; + +import org.lflang.Target; + +public class FilesProperty extends DefaultFileListProperty { + + @Override + public List supportedTargets() { + return List.of(Target.C, Target.CCPP, Target.Python); + } + +} diff --git a/core/src/main/java/org/lflang/target/KeepaliveConfig.java b/core/src/main/java/org/lflang/target/property/KeepaliveProperty.java similarity index 61% rename from core/src/main/java/org/lflang/target/KeepaliveConfig.java rename to core/src/main/java/org/lflang/target/property/KeepaliveProperty.java index c7059b946d..4c1db334a5 100644 --- a/core/src/main/java/org/lflang/target/KeepaliveConfig.java +++ b/core/src/main/java/org/lflang/target/property/KeepaliveProperty.java @@ -1,41 +1,37 @@ -package org.lflang.target; +package org.lflang.target.property; +import static org.lflang.TargetProperty.KEEPALIVE; + +import java.util.List; import java.util.Properties; import org.lflang.Target; import org.lflang.TargetConfig; -import org.lflang.TargetProperty; -import org.lflang.TargetPropertyConfig; -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.property.DefaultBooleanProperty; import org.lflang.validation.ValidationReporter; -public class KeepaliveConfig extends TargetPropertyConfig { - - @Override - public Boolean initialize() { - return false; - } +public class KeepaliveProperty extends DefaultBooleanProperty { @Override public void update(Properties cliArgs) { super.update(cliArgs); - var key = TargetProperty.KEEPALIVE.toString(); + var key = KEEPALIVE.toString(); if (cliArgs.containsKey(key)) { - this.override(Boolean.parseBoolean(cliArgs.getProperty(TargetProperty.KEEPALIVE.description))); + this.override(Boolean.parseBoolean(cliArgs.getProperty(KEEPALIVE.toString()))); } } @Override - public Boolean parse(Element value) { - return ASTUtils.toBoolean(value); + public List supportedTargets() { + return Target.ALL; } @Override public void validate(KeyValuePair pair, Model ast, TargetConfig config, ValidationReporter reporter) { + super.validate(pair, ast, config, reporter); if (pair != null && config.target == Target.CPP) { reporter.warning( "The keepalive property is inferred automatically by the C++ " @@ -45,8 +41,4 @@ public void validate(KeyValuePair pair, Model ast, TargetConfig config, Validati } } - @Override - public Element export() { - return ASTUtils.toElement(this.value); - } } diff --git a/core/src/main/java/org/lflang/target/property/LoggingProperty.java b/core/src/main/java/org/lflang/target/property/LoggingProperty.java new file mode 100644 index 0000000000..386b712402 --- /dev/null +++ b/core/src/main/java/org/lflang/target/property/LoggingProperty.java @@ -0,0 +1,58 @@ +package org.lflang.target.property; + + +import java.util.List; + +import org.lflang.Target; +import org.lflang.TargetPropertyConfig; +import org.lflang.ast.ASTUtils; +import org.lflang.lf.Element; +import org.lflang.target.property.LoggingProperty.LogLevel; +import org.lflang.target.property.type.UnionType; + +public class LoggingProperty extends TargetPropertyConfig { + + public LoggingProperty() { + super(UnionType.LOGGING_UNION); + } + + @Override + public LogLevel initialize() { + return LogLevel.INFO; + } + + @Override + protected LogLevel parse(Element value) { + return (LogLevel) UnionType.LOGGING_UNION.forName(ASTUtils.elementToSingleString(value)); + } + + @Override + public List supportedTargets() { + return Target.ALL; + } + + @Override + public Element export() { + return ASTUtils.toElement(value.toString()); + } + + /** + * Log levels in descending order of severity. + * + * @author Marten Lohstroh + */ + public enum LogLevel { + ERROR, + WARN, + INFO, + LOG, + DEBUG; + + /** Return the name in lower case. */ + @Override + public String toString() { + return this.name().toLowerCase(); + } + } + +} diff --git a/core/src/main/java/org/lflang/target/property/NoCompileProperty.java b/core/src/main/java/org/lflang/target/property/NoCompileProperty.java new file mode 100644 index 0000000000..1e7ac01ef2 --- /dev/null +++ b/core/src/main/java/org/lflang/target/property/NoCompileProperty.java @@ -0,0 +1,15 @@ +package org.lflang.target.property; + +import java.util.Arrays; +import java.util.List; + +import org.lflang.Target; + +public class NoCompileProperty extends DefaultBooleanProperty { + + @Override + public List supportedTargets() { + return Arrays.asList(Target.C, Target.CPP, Target.CCPP, Target.Python); + } + +} diff --git a/core/src/main/java/org/lflang/target/property/NoRuntimeValidationProperty.java b/core/src/main/java/org/lflang/target/property/NoRuntimeValidationProperty.java new file mode 100644 index 0000000000..d5132341d6 --- /dev/null +++ b/core/src/main/java/org/lflang/target/property/NoRuntimeValidationProperty.java @@ -0,0 +1,14 @@ +package org.lflang.target.property; + +import java.util.List; + +import org.lflang.Target; + +public class NoRuntimeValidationProperty extends DefaultBooleanProperty { + + @Override + public List supportedTargets() { + return List.of(Target.CPP); + } + +} diff --git a/core/src/main/java/org/lflang/target/PlatformConfig.java b/core/src/main/java/org/lflang/target/property/PlatformProperty.java similarity index 95% rename from core/src/main/java/org/lflang/target/PlatformConfig.java rename to core/src/main/java/org/lflang/target/property/PlatformProperty.java index 28b8d82a33..2980d96964 100644 --- a/core/src/main/java/org/lflang/target/PlatformConfig.java +++ b/core/src/main/java/org/lflang/target/property/PlatformProperty.java @@ -1,7 +1,9 @@ -package org.lflang.target; +package org.lflang.target.property; import java.util.Arrays; +import java.util.List; +import org.lflang.Target; import org.lflang.TargetConfig; import org.lflang.TargetProperty; import org.lflang.TargetProperty.DictionaryElement; @@ -9,7 +11,7 @@ import org.lflang.lf.KeyValuePairs; import org.lflang.lf.LfFactory; import org.lflang.lf.LfPackage.Literals; -import org.lflang.target.PlatformConfig.PlatformOptions; +import org.lflang.target.property.PlatformProperty.PlatformOptions; import org.lflang.target.property.type.DictionaryType; import org.lflang.target.property.type.PrimitiveType; import org.lflang.target.property.type.TargetPropertyType; @@ -20,7 +22,11 @@ import org.lflang.target.property.type.UnionType; import org.lflang.validation.ValidationReporter; -public class PlatformConfig extends TargetPropertyConfig { +public class PlatformProperty extends TargetPropertyConfig { + + public PlatformProperty() { + super(UnionType.PLATFORM_STRING_OR_DICTIONARY); + } @Override public PlatformOptions initialize() { @@ -76,8 +82,14 @@ public PlatformOptions parse(Element value) { // FIXME: pass in err return config; } + @Override + public List supportedTargets() { + return Target.ALL; + } + @Override public void validate(KeyValuePair pair, Model ast, TargetConfig config, ValidationReporter reporter) { + super.validate(pair, ast, config, reporter); var threading = TargetProperty.getKeyValuePair(ast, TargetProperty.THREADING); if (threading != null) { if (pair != null && ASTUtils.toBoolean(threading.getValue())) { diff --git a/core/src/main/java/org/lflang/target/property/PrintStatisticsProperty.java b/core/src/main/java/org/lflang/target/property/PrintStatisticsProperty.java new file mode 100644 index 0000000000..019eb1eb22 --- /dev/null +++ b/core/src/main/java/org/lflang/target/property/PrintStatisticsProperty.java @@ -0,0 +1,14 @@ +package org.lflang.target.property; + +import java.util.List; + +import org.lflang.Target; + +public class PrintStatisticsProperty extends DefaultBooleanProperty { + + @Override + public List supportedTargets() { + return List.of(Target.CPP); + } + +} diff --git a/core/src/main/java/org/lflang/target/property/ProtobufsProperty.java b/core/src/main/java/org/lflang/target/property/ProtobufsProperty.java new file mode 100644 index 0000000000..bf17e49383 --- /dev/null +++ b/core/src/main/java/org/lflang/target/property/ProtobufsProperty.java @@ -0,0 +1,14 @@ +package org.lflang.target.property; + +import java.util.List; + +import org.lflang.Target; + +public class ProtobufsProperty extends DefaultFileListProperty { + + @Override + public List supportedTargets() { + return List.of(Target.C, Target.CCPP, Target.TS, Target.Python); + } + +} diff --git a/core/src/main/java/org/lflang/target/Ros2DependenciesConfig.java b/core/src/main/java/org/lflang/target/property/Ros2DependenciesProperty.java similarity index 73% rename from core/src/main/java/org/lflang/target/Ros2DependenciesConfig.java rename to core/src/main/java/org/lflang/target/property/Ros2DependenciesProperty.java index c8fb599a85..2f5450dd12 100644 --- a/core/src/main/java/org/lflang/target/Ros2DependenciesConfig.java +++ b/core/src/main/java/org/lflang/target/property/Ros2DependenciesProperty.java @@ -1,9 +1,9 @@ -package org.lflang.target; +package org.lflang.target.property; import java.util.ArrayList; import java.util.List; -import org.lflang.MessageReporter; +import org.lflang.Target; import org.lflang.TargetConfig; import org.lflang.TargetProperty; import org.lflang.TargetPropertyConfig; @@ -12,10 +12,14 @@ import org.lflang.lf.KeyValuePair; import org.lflang.lf.LfPackage.Literals; import org.lflang.lf.Model; +import org.lflang.target.property.type.ArrayType; import org.lflang.validation.ValidationReporter; -public class Ros2DependenciesConfig extends TargetPropertyConfig> { +public class Ros2DependenciesProperty extends TargetPropertyConfig> { + public Ros2DependenciesProperty() { + super(ArrayType.STRING_ARRAY); + } @Override public List initialize() { @@ -27,8 +31,14 @@ public List parse(Element value) { return ASTUtils.elementToListOfStrings(value); } + @Override + public List supportedTargets() { + return List.of(Target.CPP); + } + @Override public void validate(KeyValuePair pair, Model ast, TargetConfig config, ValidationReporter reporter) { + super.validate(pair, ast, config, reporter); var ros2enabled = TargetProperty.getKeyValuePair(ast, TargetProperty.ROS2); if (pair != null && (ros2enabled == null || !ASTUtils.toBoolean(ros2enabled.getValue()))) { reporter.warning( diff --git a/core/src/main/java/org/lflang/target/property/Ros2Property.java b/core/src/main/java/org/lflang/target/property/Ros2Property.java new file mode 100644 index 0000000000..39fc2e78e8 --- /dev/null +++ b/core/src/main/java/org/lflang/target/property/Ros2Property.java @@ -0,0 +1,14 @@ +package org.lflang.target.property; + +import java.util.List; + +import org.lflang.Target; + +public class Ros2Property extends DefaultBooleanProperty { + + @Override + public List supportedTargets() { + return List.of(Target.CPP); + } + +} diff --git a/core/src/main/java/org/lflang/target/property/RuntimeVersionProperty.java b/core/src/main/java/org/lflang/target/property/RuntimeVersionProperty.java new file mode 100644 index 0000000000..2be751f27c --- /dev/null +++ b/core/src/main/java/org/lflang/target/property/RuntimeVersionProperty.java @@ -0,0 +1,13 @@ +package org.lflang.target.property; + +import java.util.List; + +import org.lflang.Target; + +public class RuntimeVersionProperty extends DefaultStringConfig { + + @Override + public List supportedTargets() { + return List.of(Target.CPP); + } +} diff --git a/core/src/main/java/org/lflang/target/property/RustIncludeProperty.java b/core/src/main/java/org/lflang/target/property/RustIncludeProperty.java new file mode 100644 index 0000000000..79fb107be9 --- /dev/null +++ b/core/src/main/java/org/lflang/target/property/RustIncludeProperty.java @@ -0,0 +1,97 @@ +package org.lflang.target.property; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.emf.ecore.EObject; + +import org.lflang.MessageReporter; +import org.lflang.Target; +import org.lflang.TargetPropertyConfig; +import org.lflang.ast.ASTUtils; +import org.lflang.lf.Array; +import org.lflang.lf.Element; +import org.lflang.lf.LfFactory; +import org.lflang.target.property.type.UnionType; +import org.lflang.util.FileUtil; +import org.lflang.util.StringUtil; + +public class RustIncludeProperty extends TargetPropertyConfig> { + + public RustIncludeProperty() { + super(UnionType.FILE_OR_FILE_ARRAY); + } + + @Override + public List supportedTargets() { + return List.of(Target.Rust); + } + + @Override + public List initialize() { + return new ArrayList<>(); + } + + @Override + public List parse(Element value) { + Path referencePath; + try { + referencePath = FileUtil.toPath(value.eResource().getURI()).toAbsolutePath(); + } catch (IllegalArgumentException e) { + // FIXME: need err + //err.at(value).error("Invalid path? " + e.getMessage()); + throw e; + } + + // we'll resolve relative paths to check that the files + // are as expected. + + if (value.getLiteral() != null) { + Path resolved = referencePath.resolveSibling(StringUtil.removeQuotes(value.getLiteral())); + this.addAndCheckTopLevelModule(resolved, value, err); + } else if (value.getArray() != null) { + for (Element element : value.getArray().getElements()) { + String literal = StringUtil.removeQuotes(element.getLiteral()); + Path resolved = referencePath.resolveSibling(literal); + this.addAndCheckTopLevelModule(resolved, element, err); + } + } + } + + @Override + public Element export() { + // do not check paths here, and simply copy the absolute path over + List paths = this.value; + if (paths.isEmpty()) { + return null; + } else if (paths.size() == 1) { + return ASTUtils.toElement(paths.get(0).toString()); + } else { + Element e = LfFactory.eINSTANCE.createElement(); + Array arr = LfFactory.eINSTANCE.createArray(); + for (Path p : paths) { + arr.getElements().add(ASTUtils.toElement(p.toString())); + } + e.setArray(arr); + return e; + } + } + + private void addAndCheckTopLevelModule(Path path, EObject errorOwner, MessageReporter err) { + String fileName = path.getFileName().toString(); + if (!Files.exists(path)) { + err.at(errorOwner).error("File not found"); + } else if (Files.isRegularFile(path) && !fileName.endsWith(".rs")) { + err.at(errorOwner).error("Not a rust file"); + } else if (fileName.equals("main.rs")) { + err.at(errorOwner).error("Cannot use 'main.rs' as a module name (reserved)"); + } else if (fileName.equals("reactors") || fileName.equals("reactors.rs")) { + err.at(errorOwner).error("Cannot use 'reactors' as a module name (reserved)"); + } else if (Files.isDirectory(path) && !Files.exists(path.resolve("mod.rs"))) { + err.at(errorOwner).error("Cannot find module descriptor in directory"); + } + this.value.add(path); + } +} diff --git a/core/src/main/java/org/lflang/target/SchedulerConfig.java b/core/src/main/java/org/lflang/target/property/SchedulerProperty.java similarity index 90% rename from core/src/main/java/org/lflang/target/SchedulerConfig.java rename to core/src/main/java/org/lflang/target/property/SchedulerProperty.java index 9f90ea6d6c..66a6d83b47 100644 --- a/core/src/main/java/org/lflang/target/SchedulerConfig.java +++ b/core/src/main/java/org/lflang/target/property/SchedulerProperty.java @@ -1,10 +1,11 @@ -package org.lflang.target; +package org.lflang.target.property; import java.nio.file.Path; +import java.util.Arrays; import java.util.List; import java.util.Properties; -import org.lflang.MessageReporter; +import org.lflang.Target; import org.lflang.TargetConfig; import org.lflang.TargetProperty; import org.lflang.TargetPropertyConfig; @@ -14,14 +15,19 @@ import org.lflang.lf.LfPackage.Literals; import org.lflang.lf.Model; -import org.lflang.target.SchedulerConfig.SchedulerOption; +import org.lflang.target.property.SchedulerProperty.SchedulerOption; import org.lflang.target.property.type.UnionType; import org.lflang.validation.ValidationReporter; import com.google.common.collect.ImmutableList; -public class SchedulerConfig extends TargetPropertyConfig { +public class SchedulerProperty extends TargetPropertyConfig { + + + public SchedulerProperty() { + super(UnionType.SCHEDULER_UNION); + } @Override public SchedulerOption initialize() { @@ -48,6 +54,11 @@ public SchedulerOption parse(Element value) { } } + @Override + public List supportedTargets() { + return Arrays.asList(Target.C, Target.CCPP, Target.Python); + } + @Override public Element export() { return ASTUtils.toElement(this.value.toString()); @@ -55,6 +66,7 @@ public Element export() { @Override public void validate(KeyValuePair pair, Model ast, TargetConfig config, ValidationReporter reporter) { + super.validate(pair, ast, config, reporter); if (pair != null) { String schedulerName = ASTUtils.elementToSingleString(pair.getValue()); try { diff --git a/core/src/main/java/org/lflang/target/property/SingleFileProjectProperty.java b/core/src/main/java/org/lflang/target/property/SingleFileProjectProperty.java new file mode 100644 index 0000000000..f779be00a1 --- /dev/null +++ b/core/src/main/java/org/lflang/target/property/SingleFileProjectProperty.java @@ -0,0 +1,14 @@ +package org.lflang.target.property; + +import java.util.List; + +import org.lflang.Target; + +public class SingleFileProjectProperty extends DefaultBooleanProperty { + + @Override + public List supportedTargets() { + return List.of(Target.Rust); + } + +} diff --git a/core/src/main/java/org/lflang/target/property/ThreadingProperty.java b/core/src/main/java/org/lflang/target/property/ThreadingProperty.java new file mode 100644 index 0000000000..023480ed28 --- /dev/null +++ b/core/src/main/java/org/lflang/target/property/ThreadingProperty.java @@ -0,0 +1,19 @@ +package org.lflang.target.property; + +import java.util.List; + +import org.lflang.Target; + +public class ThreadingProperty extends DefaultBooleanProperty { + + @Override + public List supportedTargets() { + return List.of(Target.C, Target.CCPP, Target.Python); + } + + + @Override + public Boolean initialize() { + return true; + } +} diff --git a/core/src/main/java/org/lflang/target/property/TimeOutProperty.java b/core/src/main/java/org/lflang/target/property/TimeOutProperty.java new file mode 100644 index 0000000000..6aec1948fd --- /dev/null +++ b/core/src/main/java/org/lflang/target/property/TimeOutProperty.java @@ -0,0 +1,39 @@ +package org.lflang.target.property; + + +import java.util.List; + +import org.lflang.Target; +import org.lflang.TargetPropertyConfig; +import org.lflang.TimeValue; +import org.lflang.ast.ASTUtils; +import org.lflang.lf.Element; +import org.lflang.target.property.type.PrimitiveType; + + +public class TimeOutProperty extends TargetPropertyConfig { + + public TimeOutProperty() { + super(PrimitiveType.TIME_VALUE); + } + + @Override + public TimeValue initialize() { + return null; + } + + @Override + public TimeValue parse(Element value) { + return ASTUtils.toTimeValue(value); + } + + @Override + public List supportedTargets() { + return Target.ALL; + } + + @Override + public Element export() { + return ASTUtils.toElement(value); + } +} diff --git a/core/src/main/java/org/lflang/target/TracingConfig.java b/core/src/main/java/org/lflang/target/property/TracingProperty.java similarity index 91% rename from core/src/main/java/org/lflang/target/TracingConfig.java rename to core/src/main/java/org/lflang/target/property/TracingProperty.java index cee56c3ddd..1bca01000d 100644 --- a/core/src/main/java/org/lflang/target/TracingConfig.java +++ b/core/src/main/java/org/lflang/target/property/TracingProperty.java @@ -1,13 +1,15 @@ -package org.lflang.target; +package org.lflang.target.property; +import java.util.List; import java.util.Objects; import java.util.Properties; +import org.lflang.Target; import org.lflang.TargetConfig; import org.lflang.TargetProperty; import org.lflang.TargetProperty.DictionaryElement; import org.lflang.TargetPropertyConfig; -import org.lflang.target.TracingConfig.TracingOptions; +import org.lflang.target.property.TracingProperty.TracingOptions; import org.lflang.target.property.type.DictionaryType; import org.lflang.target.property.type.PrimitiveType; import org.lflang.target.property.type.TargetPropertyType; @@ -18,11 +20,16 @@ import org.lflang.lf.LfFactory; import org.lflang.lf.LfPackage.Literals; import org.lflang.lf.Model; +import org.lflang.target.property.type.UnionType; import org.lflang.validation.ValidationReporter; -public class TracingConfig extends TargetPropertyConfig { +public class TracingProperty extends TargetPropertyConfig { + public TracingProperty() { + super(UnionType.TRACING_UNION); + } + @Override public TracingOptions initialize() { return new TracingOptions(false); @@ -60,6 +67,11 @@ public TracingOptions parse(Element value) { return options; } + @Override + public List supportedTargets() { + return List.of(Target.C, Target.CCPP, Target.CPP, Target.Python); + } + @Override public void validate(KeyValuePair pair, Model ast, TargetConfig config, ValidationReporter reporter) { if (pair != null && this.parse(pair.getValue()) != null) { diff --git a/core/src/main/java/org/lflang/target/property/VerifyProperty.java b/core/src/main/java/org/lflang/target/property/VerifyProperty.java new file mode 100644 index 0000000000..0a6549bbc3 --- /dev/null +++ b/core/src/main/java/org/lflang/target/property/VerifyProperty.java @@ -0,0 +1,15 @@ +package org.lflang.target.property.type; + +import java.util.List; + +import org.lflang.Target; +import org.lflang.target.property.DefaultBooleanProperty; + +public class VerifyProperty extends DefaultBooleanProperty { + + @Override + public List supportedTargets() { + return List.of(Target.C); + } + +} diff --git a/core/src/main/java/org/lflang/target/property/WorkersProperty.java b/core/src/main/java/org/lflang/target/property/WorkersProperty.java new file mode 100644 index 0000000000..50e1a8bc0e --- /dev/null +++ b/core/src/main/java/org/lflang/target/property/WorkersProperty.java @@ -0,0 +1,37 @@ +package org.lflang.target.property; + +import java.util.List; + +import org.lflang.Target; +import org.lflang.TargetPropertyConfig; +import org.lflang.ast.ASTUtils; +import org.lflang.lf.Element; +import org.lflang.target.property.type.PrimitiveType; + +public class WorkersProperty extends TargetPropertyConfig { + + public WorkersProperty() { + super(PrimitiveType.NON_NEGATIVE_INTEGER); + } + + @Override + public Integer initialize() { + return 0; + } + + @Override + protected Integer parse(Element value) { + return ASTUtils.toInteger(value); + } + + @Override + public List supportedTargets() { + return List.of(Target.C, Target.CCPP, Target.Python, Target.CPP, Target.Rust); + } + + @Override + public Element export() { + return ASTUtils.toElement(value); + } + +} diff --git a/core/src/main/java/org/lflang/target/property/type/ArrayType.java b/core/src/main/java/org/lflang/target/property/type/ArrayType.java index 8b6621535a..9a40560047 100644 --- a/core/src/main/java/org/lflang/target/property/type/ArrayType.java +++ b/core/src/main/java/org/lflang/target/property/type/ArrayType.java @@ -5,6 +5,7 @@ import org.lflang.lf.Array; import org.lflang.lf.Element; import org.lflang.validation.LFValidator; +import org.lflang.validation.ValidationReporter; /** * An array type of which the elements confirm to a given type. @@ -32,16 +33,17 @@ private ArrayType(TargetPropertyType type) { * the correct type. */ @Override - public void check(Element e, String name, LFValidator v) { + public boolean check(Element e, String name, ValidationReporter v) { Array array = e.getArray(); - if (array == null) { - TargetPropertyType.produceError(name, this.toString(), v); - } else { + if (array != null) { List elements = array.getElements(); + var valid = true; for (int i = 0; i < elements.size(); i++) { - this.type.check(elements.get(i), name + "[" + i + "]", v); + valid &= this.type.check(elements.get(i), name + "[" + i + "]", v); } + return valid; } + return false; } /** Return true of the given element is an array. */ diff --git a/core/src/main/java/org/lflang/target/property/type/CompilerConfig.java b/core/src/main/java/org/lflang/target/property/type/CompilerConfig.java new file mode 100644 index 0000000000..80248bb0d6 --- /dev/null +++ b/core/src/main/java/org/lflang/target/property/type/CompilerConfig.java @@ -0,0 +1,14 @@ +package org.lflang.target.property.type; + +import java.util.List; + +import org.lflang.Target; +import org.lflang.target.property.DefaultStringConfig; + +public class CompilerConfig extends DefaultStringConfig { + + @Override + public List supportedTargets() { + return Target.ALL; + } +} diff --git a/core/src/main/java/org/lflang/target/property/type/DictionaryType.java b/core/src/main/java/org/lflang/target/property/type/DictionaryType.java index 7f4ba7e44f..97691d2248 100644 --- a/core/src/main/java/org/lflang/target/property/type/DictionaryType.java +++ b/core/src/main/java/org/lflang/target/property/type/DictionaryType.java @@ -10,12 +10,12 @@ import org.lflang.lf.Element; import org.lflang.lf.KeyValuePair; import org.lflang.lf.KeyValuePairs; -import org.lflang.target.CoordinationOptionsConfig.CoordinationOption; -import org.lflang.target.DockerConfig.DockerOption; -import org.lflang.target.PlatformConfig.PlatformOption; -import org.lflang.target.TracingConfig.TracingOption; -import org.lflang.target.property.ClockSyncOptionsConfig.ClockSyncOption; -import org.lflang.validation.LFValidator; +import org.lflang.target.property.CoordinationOptionsProperty.CoordinationOption; +import org.lflang.target.property.DockerProperty.DockerOption; +import org.lflang.target.property.PlatformProperty.PlatformOption; +import org.lflang.target.property.TracingProperty.TracingOption; +import org.lflang.target.property.ClockSyncOptionsProperty.ClockSyncOption; +import org.lflang.validation.ValidationReporter; /** * A dictionary type with a predefined set of possible keys and assignable types. @@ -53,11 +53,10 @@ public DictionaryElement forName(String name) { /** Recursively check that the passed in element conforms to the rules of this dictionary. */ @Override - public void check(Element e, String name, LFValidator v) { + public boolean check(Element e, String name, ValidationReporter v) { KeyValuePairs kv = e.getKeyvalue(); - if (kv == null) { - TargetPropertyType.produceError(name, this.toString(), v); - } else { + if (kv != null) { + var valid = true; for (KeyValuePair pair : kv.getPairs()) { String key = pair.getName(); Element val = pair.getValue(); @@ -68,13 +67,14 @@ public void check(Element e, String name, LFValidator v) { if (match.isPresent()) { // Make sure the type is correct, too. TargetPropertyType type = match.get().getType(); - type.check(val, name + "." + key, v); + valid &= type.check(val, name + "." + key, v); } else { - // No match found; report error. - TargetPropertyType.produceError(name, this.toString(), v); + valid = false; } + return valid; } } + return false; } /** Return true if the given element represents a dictionary, false otherwise. */ diff --git a/core/src/main/java/org/lflang/target/property/type/PrimitiveType.java b/core/src/main/java/org/lflang/target/property/type/PrimitiveType.java index 0e3a6a5be3..868669243d 100644 --- a/core/src/main/java/org/lflang/target/property/type/PrimitiveType.java +++ b/core/src/main/java/org/lflang/target/property/type/PrimitiveType.java @@ -4,7 +4,7 @@ import org.lflang.ast.ASTUtils; import org.lflang.lf.Element; -import org.lflang.validation.LFValidator; +import org.lflang.validation.ValidationReporter; /** * Primitive types for target properties, each with a description used in error messages and @@ -64,12 +64,12 @@ public enum PrimitiveType implements TargetPropertyType { * @param description A textual description of the type that should start with "a/an". * @param validator A predicate that returns true if a given Element conforms to this type. */ - private PrimitiveType(String description, Predicate validator) { + PrimitiveType(String description, Predicate validator) { this.description = description; this.validator = validator; } - /** Return true if the the given Element is a valid instance of this type. */ + /** Return true if the given Element is a valid instance of this type. */ public boolean validate(Element e) { return this.validator.test(e); } @@ -82,24 +82,8 @@ public boolean validate(Element e) { * @param name The name of the target property. * @param v The LFValidator to append errors to. */ - public void check(Element e, String name, LFValidator v) { - if (!this.validate(e)) { - TargetPropertyType.produceError(name, this.description, v); - } - // If this is a file, perform an additional check to make sure - // the file actually exists. - // FIXME: premature because we first need a mechanism for looking up files! - // Looking in the same directory is too restrictive. Disabling this check for now. - /* - if (this == FILE) { - String file = ASTUtils.toSingleString(e); - - if (!FileConfig.fileExists(file, FileConfig.toPath(e.eResource().getURI()).toFile().getParent())) { - v.targetPropertyWarnings - .add("Could not find file: '" + file + "'."); - } - } - */ + public boolean check(Element e, String name, ValidationReporter v) { + return this.validate(e); } /** Return a textual description of this type. */ diff --git a/core/src/main/java/org/lflang/target/property/type/StringDictionaryType.java b/core/src/main/java/org/lflang/target/property/type/StringDictionaryType.java index cec3a7f9df..dda0d6065e 100644 --- a/core/src/main/java/org/lflang/target/property/type/StringDictionaryType.java +++ b/core/src/main/java/org/lflang/target/property/type/StringDictionaryType.java @@ -4,6 +4,7 @@ import org.lflang.lf.KeyValuePair; import org.lflang.lf.KeyValuePairs; import org.lflang.validation.LFValidator; +import org.lflang.validation.ValidationReporter; /** Dictionary type that allows for keys that will be interpreted as strings and string values. */ public enum StringDictionaryType implements TargetPropertyType { @@ -18,18 +19,19 @@ public boolean validate(Element e) { } @Override - public void check(Element e, String name, LFValidator v) { + public boolean check(Element e, String name, ValidationReporter v) { KeyValuePairs kv = e.getKeyvalue(); - if (kv == null) { - TargetPropertyType.produceError(name, this.toString(), v); - } else { + if (kv != null) { + var valid = true; for (KeyValuePair pair : kv.getPairs()) { String key = pair.getName(); Element val = pair.getValue(); // Make sure the type is string - PrimitiveType.STRING.check(val, name + "." + key, v); + valid &= PrimitiveType.STRING.check(val, name + "." + key, v); } + return valid; } + return false; } } \ No newline at end of file diff --git a/core/src/main/java/org/lflang/target/property/type/TargetPropertyType.java b/core/src/main/java/org/lflang/target/property/type/TargetPropertyType.java index 390d4aa1e7..06f0a5cbbb 100644 --- a/core/src/main/java/org/lflang/target/property/type/TargetPropertyType.java +++ b/core/src/main/java/org/lflang/target/property/type/TargetPropertyType.java @@ -5,6 +5,7 @@ import org.lflang.ast.ASTUtils; import org.lflang.lf.Element; import org.lflang.validation.LFValidator; +import org.lflang.validation.ValidationReporter; /** * An interface for types associated with target properties. @@ -14,7 +15,7 @@ public interface TargetPropertyType { /** - * Return true if the the given Element is a valid instance of this type. + * Return true if the given Element is a valid instance of this type. * * @param e The Element to validate. * @return True if the element conforms to this type, false otherwise. @@ -29,20 +30,8 @@ public interface TargetPropertyType { * @param name The name of the target property. * @param v A reference to the validator to report errors to. */ - public void check(Element e, String name, LFValidator v); + public boolean check(Element e, String name, ValidationReporter v); - /** - * Helper function to produce an error during type checking. - * - * @param name The description of the target property. - * @param description The description of the type. - * @param v A reference to the validator to report errors to. - */ - public static void produceError(String name, String description, LFValidator v) { - - v.reportTargetPropertyError( - "Target property '" + name + "' is required to be " + description + "."); - } } diff --git a/core/src/main/java/org/lflang/target/property/type/UnionType.java b/core/src/main/java/org/lflang/target/property/type/UnionType.java index 4703605b09..351eef2b8e 100644 --- a/core/src/main/java/org/lflang/target/property/type/UnionType.java +++ b/core/src/main/java/org/lflang/target/property/type/UnionType.java @@ -8,13 +8,13 @@ import org.lflang.Target; import org.lflang.ast.ASTUtils; import org.lflang.lf.Element; -import org.lflang.target.ClockSyncModeConfig.ClockSyncMode; -import org.lflang.target.CoordinationModeConfig.CoordinationMode; -import org.lflang.target.LoggingConfigurator.LogLevel; -import org.lflang.target.PlatformConfig.Platform; -import org.lflang.target.SchedulerConfig.SchedulerOption; +import org.lflang.target.property.ClockSyncModeProperty.ClockSyncMode; +import org.lflang.target.property.CoordinationModeProperty.CoordinationMode; +import org.lflang.target.property.PlatformProperty.Platform; +import org.lflang.target.property.SchedulerProperty.SchedulerOption; import org.lflang.target.property.BuildConfig.BuildType; -import org.lflang.validation.LFValidator; +import org.lflang.target.property.LoggingProperty.LogLevel; +import org.lflang.validation.ValidationReporter; /** * A type that can assume one of several types. @@ -64,24 +64,23 @@ public Enum forName(String name) { /** Recursively check that the passed in element conforms to the rules of this union. */ @Override - public void check(Element e, String name, LFValidator v) { + public boolean check(Element e, String name, ValidationReporter v) { Optional> match = this.match(e); + var found = false; if (match.isPresent()) { // Go deeper if the element is an array or dictionary. Enum type = match.get(); if (type instanceof DictionaryType) { - ((DictionaryType) type).check(e, name, v); + found = ((DictionaryType) type).check(e, name, v); } else if (type instanceof ArrayType) { - ((ArrayType) type).check(e, name, v); + found = ((ArrayType) type).check(e, name, v); } else if (type instanceof PrimitiveType) { - ((PrimitiveType) type).check(e, name, v); + found = ((PrimitiveType) type).check(e, name, v); } else if (!(type instanceof Enum)) { throw new RuntimeException("Encountered an unknown type."); } - } else { - // No match found; report error. - TargetPropertyType.produceError(name, this.toString(), v); } + return found; } /** diff --git a/core/src/main/java/org/lflang/validation/LFValidator.java b/core/src/main/java/org/lflang/validation/LFValidator.java index dddb837917..a742b8185d 100644 --- a/core/src/main/java/org/lflang/validation/LFValidator.java +++ b/core/src/main/java/org/lflang/validation/LFValidator.java @@ -550,20 +550,7 @@ public void checkKeyValuePair(KeyValuePair param) { + options, Literals.KEY_VALUE_PAIR__NAME); } else { - // Check whether the property is supported by the target. - if (!prop.supportedBy.contains(this.target)) { - warning( - "The target parameter: " - + param.getName() - + " is not supported by the " - + this.target - + " target and will thus be ignored.", - Literals.KEY_VALUE_PAIR__NAME); - } - // Run checks on the property. After running the check, errors/warnings - // are retrievable from the targetPropertyErrors collection. - prop.type.check(param.getValue(), param.getName(), this); } // Retrieve the errors that resulted from the check. @@ -1121,7 +1108,7 @@ public void checkTargetDecl(TargetDecl target) throws IOException { public void checkTargetProperties(KeyValuePairs targetProperties) { Arrays.stream(TargetProperty.values()).forEach(p -> { p.validate(targetProperties, this.info.model, this.targetConfig, - new ValidationReporter() { + new ValidationReporter() { // FIXME: this is redundant because there already is a ValidatorMessageReporter class that I was unaware of. @Override public void error(String message, EObject source, EStructuralFeature feature) { error(message, source, feature); diff --git a/core/src/main/java/org/lflang/validation/ValidationReporter.java b/core/src/main/java/org/lflang/validation/ValidationReporter.java index ddd25754e3..a2eba3a7ee 100644 --- a/core/src/main/java/org/lflang/validation/ValidationReporter.java +++ b/core/src/main/java/org/lflang/validation/ValidationReporter.java @@ -7,4 +7,5 @@ public interface ValidationReporter { void error(String message, EObject source, EStructuralFeature feature); void warning(String message, EObject source, EStructuralFeature feature); + } \ No newline at end of file diff --git a/core/src/main/java/org/lflang/validation/ValidatorMessageReporter.java b/core/src/main/java/org/lflang/validation/ValidatorMessageReporter.java index 3ef4e05798..387ad37a0f 100644 --- a/core/src/main/java/org/lflang/validation/ValidatorMessageReporter.java +++ b/core/src/main/java/org/lflang/validation/ValidatorMessageReporter.java @@ -84,6 +84,9 @@ protected void report(Path path, Range range, DiagnosticSeverity severity, Strin reportOnNode(validatorState.getCurrentObject(), severity, fullMessage); } + + + @Override protected void reportOnNode(EObject node, DiagnosticSeverity severity, String message) { switch (severity) { diff --git a/core/src/main/kotlin/org/lflang/generator/cpp/CppExtensions.kt b/core/src/main/kotlin/org/lflang/generator/cpp/CppExtensions.kt index bd0d0a3a46..4a1215a5f2 100644 --- a/core/src/main/kotlin/org/lflang/generator/cpp/CppExtensions.kt +++ b/core/src/main/kotlin/org/lflang/generator/cpp/CppExtensions.kt @@ -13,7 +13,7 @@ import org.lflang.lf.TriggerRef import org.lflang.lf.VarRef import org.lflang.lf.Visibility import org.lflang.lf.WidthSpec -import org.lflang.target.LoggingConfigurator.LogLevel +import org.lflang.target.LoggingProperty.LogLevel /************* * Copyright (c) 2019-2021, TU Dresden. diff --git a/core/src/main/kotlin/org/lflang/generator/cpp/CppGenerator.kt b/core/src/main/kotlin/org/lflang/generator/cpp/CppGenerator.kt index 359811e8d9..e4041e4a41 100644 --- a/core/src/main/kotlin/org/lflang/generator/cpp/CppGenerator.kt +++ b/core/src/main/kotlin/org/lflang/generator/cpp/CppGenerator.kt @@ -105,8 +105,7 @@ class CppGenerator( } } - private fun fetchReactorCpp() { - val version = targetConfig.runtimeVersion + private fun fetchReactorCpp(version: String) { val libPath = fileConfig.srcGenBasePath.resolve("reactor-cpp-$version") // abort if the directory already exists if (Files.isDirectory(libPath)) { @@ -134,9 +133,9 @@ class CppGenerator( true) // copy or download reactor-cpp - if (targetConfig.externalRuntimePath == null) { - if (targetConfig.runtimeVersion != null) { - fetchReactorCpp() + if (!targetConfig.externalRuntimePath.isSetByUser) { + if (targetConfig.runtimeVersion.isSetByUser) { + fetchReactorCpp(targetConfig.runtimeVersion.get()) } else { FileUtil.copyFromClassPath( "$libDir/reactor-cpp", diff --git a/core/src/main/kotlin/org/lflang/generator/cpp/CppPlatformGenerator.kt b/core/src/main/kotlin/org/lflang/generator/cpp/CppPlatformGenerator.kt index eefa2fa0cd..07e11cfc18 100644 --- a/core/src/main/kotlin/org/lflang/generator/cpp/CppPlatformGenerator.kt +++ b/core/src/main/kotlin/org/lflang/generator/cpp/CppPlatformGenerator.kt @@ -26,8 +26,8 @@ abstract class CppPlatformGenerator(protected val generator: CppGenerator) { protected val cmakeArgs: List get() = listOf( "-DCMAKE_BUILD_TYPE=${targetConfig.buildType}", - "-DREACTOR_CPP_VALIDATE=${if (targetConfig.noRuntimeValidation) "OFF" else "ON"}", - "-DREACTOR_CPP_PRINT_STATISTICS=${if (targetConfig.printStatistics) "ON" else "OFF"}", + "-DREACTOR_CPP_VALIDATE=${if (targetConfig.noRuntimeValidation.get()) "OFF" else "ON"}", + "-DREACTOR_CPP_PRINT_STATISTICS=${if (targetConfig.printStatistics.get()) "ON" else "OFF"}", "-DREACTOR_CPP_TRACE=${if (targetConfig.tracing != null) "ON" else "OFF"}", "-DREACTOR_CPP_LOG_LEVEL=${targetConfig.logLevel.severity}", "-DLF_SRC_PKG_PATH=${fileConfig.srcPkgPath}", diff --git a/core/src/main/kotlin/org/lflang/generator/cpp/CppRos2NodeGenerator.kt b/core/src/main/kotlin/org/lflang/generator/cpp/CppRos2NodeGenerator.kt index f3fac39e42..3284f14924 100644 --- a/core/src/main/kotlin/org/lflang/generator/cpp/CppRos2NodeGenerator.kt +++ b/core/src/main/kotlin/org/lflang/generator/cpp/CppRos2NodeGenerator.kt @@ -59,7 +59,7 @@ class CppRos2NodeGenerator( | : Node("$nodeName", node_options) { | unsigned workers = ${if (targetConfig.workers != 0) targetConfig.workers else "std::thread::hardware_concurrency()"}; | bool fast{${targetConfig.fastMode}}; - | reactor::Duration lf_timeout{${targetConfig.timeout?.toCppCode() ?: "reactor::Duration::max()"}}; + | reactor::Duration lf_timeout{${targetConfig.timeout.get()?.toCppCode() ?: "reactor::Duration::max()"}}; | | // provide a globally accessible reference to this node | // FIXME: this is pretty hacky... diff --git a/core/src/main/kotlin/org/lflang/generator/cpp/CppRos2PackageGenerator.kt b/core/src/main/kotlin/org/lflang/generator/cpp/CppRos2PackageGenerator.kt index aaca9b4378..4d34e69d31 100644 --- a/core/src/main/kotlin/org/lflang/generator/cpp/CppRos2PackageGenerator.kt +++ b/core/src/main/kotlin/org/lflang/generator/cpp/CppRos2PackageGenerator.kt @@ -9,7 +9,7 @@ import java.nio.file.Path class CppRos2PackageGenerator(generator: CppGenerator, private val nodeName: String) { private val fileConfig = generator.fileConfig private val targetConfig = generator.targetConfig - val reactorCppSuffix = targetConfig.runtimeVersion ?: "default" + val reactorCppSuffix = targetConfig.runtimeVersion.get() ?: "default" val reactorCppName = "reactor-cpp-$reactorCppSuffix" private val dependencies = listOf("rclcpp", "rclcpp_components", reactorCppName) + (targetConfig.ros2Dependencies ?: listOf()) diff --git a/core/src/main/kotlin/org/lflang/generator/cpp/CppStandaloneCmakeGenerator.kt b/core/src/main/kotlin/org/lflang/generator/cpp/CppStandaloneCmakeGenerator.kt index 86f3486cb1..732536e2af 100644 --- a/core/src/main/kotlin/org/lflang/generator/cpp/CppStandaloneCmakeGenerator.kt +++ b/core/src/main/kotlin/org/lflang/generator/cpp/CppStandaloneCmakeGenerator.kt @@ -136,9 +136,9 @@ class CppStandaloneCmakeGenerator(private val targetConfig: TargetConfig, privat val includeFiles = targetConfig.cmakeIncludes.get()?.map { fileConfig.srcPath.resolve(it).toUnixString() } val reactorCppTarget = when { - targetConfig.externalRuntimePath != null -> "reactor-cpp" - targetConfig.runtimeVersion != null -> "reactor-cpp-${targetConfig.runtimeVersion}" - else -> "reactor-cpp-default" + targetConfig.externalRuntimePath.isSetByUser -> "reactor-cpp" + targetConfig.runtimeVersion.isSetByUser -> "reactor-cpp-${targetConfig.runtimeVersion}" + else -> "reactor-cpp-default" } return with(PrependOperator) { 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 9b3d9208c8..d2bef81a4f 100644 --- a/core/src/main/kotlin/org/lflang/generator/rust/RustModel.kt +++ b/core/src/main/kotlin/org/lflang/generator/rust/RustModel.kt @@ -477,7 +477,7 @@ object RustModelBuilder { if (userSpec == null) { // default configuration for the runtime crate - val userRtVersion: String? = targetConfig.runtimeVersion + val userRtVersion: String? = targetConfig.runtimeVersion.get() // enable parallel feature if asked val parallelFeature = listOf(PARALLEL_RT_FEATURE).takeIf { targetConfig.threading } diff --git a/core/src/testFixtures/java/org/lflang/tests/Configurators.java b/core/src/testFixtures/java/org/lflang/tests/Configurators.java index 784286e1f0..436e9585ca 100644 --- a/core/src/testFixtures/java/org/lflang/tests/Configurators.java +++ b/core/src/testFixtures/java/org/lflang/tests/Configurators.java @@ -25,8 +25,8 @@ package org.lflang.tests; import org.lflang.TargetProperty; -import org.lflang.target.LoggingConfigurator.LogLevel; -import org.lflang.target.PlatformConfig.Platform; +import org.lflang.target.property.PlatformProperty.Platform; +import org.lflang.target.property.LoggingProperty.LogLevel; import org.lflang.tests.TestRegistry.TestCategory; /** @@ -73,7 +73,7 @@ public static boolean makeZephyrCompatibleUnthreaded(LFTest test) { test.getContext().getTargetConfig().platformOptions.get().board = "qemu_cortex_m3"; // FIXME: Zephyr emulations fails with debug log-levels. - test.getContext().getTargetConfig().logLevel = LogLevel.WARN; + test.getContext().getTargetConfig().logLevel.override(LogLevel.WARN); test.getContext().getArgs().setProperty("logging", "warning"); return true; } @@ -85,7 +85,7 @@ public static boolean makeZephyrCompatible(LFTest test) { test.getContext().getTargetConfig().platformOptions.get().board = "qemu_cortex_m3"; // FIXME: Zephyr emulations fails with debug log-levels. - test.getContext().getTargetConfig().logLevel = LogLevel.WARN; + test.getContext().getTargetConfig().logLevel.override(LogLevel.WARN); test.getContext().getArgs().setProperty("logging", "warning"); return true; From ce8199a3f8da3a6df6fff026388585788c309b42 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Tue, 26 Sep 2023 22:50:15 -0700 Subject: [PATCH 005/145] Checkpoint after fixing most issues in TargetProperty --- .../main/java/org/lflang/TargetConfig.java | 15 +- .../main/java/org/lflang/TargetProperty.java | 666 +++++++++--------- .../java/org/lflang/TargetPropertyConfig.java | 4 +- .../org/lflang/generator/GeneratorUtils.java | 2 +- .../lflang/target/property/AuthProperty.java | 1 - .../property/BuildCommandsProperty.java | 2 +- .../target/property/BuildTypeProperty.java | 2 +- .../property/CargoDependenciesProperty.java | 2 +- .../property/ClockSyncModeProperty.java | 2 +- .../property/ClockSyncOptionsProperty.java | 2 +- .../target/property/CmakeIncludeProperty.java | 2 +- .../property/CompileDefinitionsConfig.java | 2 +- .../property/CoordinationModeProperty.java | 2 +- .../property/CoordinationOptionsProperty.java | 2 +- .../property/DefaultBooleanProperty.java | 2 +- .../property/DefaultFileListProperty.java | 2 +- .../target/property/DefaultStringConfig.java | 2 +- .../property/DefaultStringListProperty.java | 2 +- .../target/property/DockerProperty.java | 2 +- .../target/property/LoggingProperty.java | 2 +- .../target/property/PlatformProperty.java | 2 +- .../property/Ros2DependenciesProperty.java | 2 +- .../target/property/RustIncludeProperty.java | 2 +- .../target/property/SchedulerProperty.java | 2 +- .../target/property/ThreadingProperty.java | 2 +- .../target/property/TimeOutProperty.java | 2 +- .../target/property/TracingProperty.java | 2 +- .../target/property/WorkersProperty.java | 2 +- 28 files changed, 364 insertions(+), 370 deletions(-) diff --git a/core/src/main/java/org/lflang/TargetConfig.java b/core/src/main/java/org/lflang/TargetConfig.java index cfa95768ec..7641c8ec8f 100644 --- a/core/src/main/java/org/lflang/TargetConfig.java +++ b/core/src/main/java/org/lflang/TargetConfig.java @@ -40,6 +40,7 @@ import org.lflang.target.property.CoordinationOptionsProperty; import org.lflang.target.property.DockerProperty; import org.lflang.target.property.FastProperty; +import org.lflang.target.property.FedSetupProperty; import org.lflang.target.property.KeepaliveProperty; import org.lflang.target.property.PlatformProperty; import org.lflang.target.property.Ros2DependenciesProperty; @@ -103,21 +104,13 @@ public TargetConfig(Properties cliArgs, TargetDecl target, MessageReporter messa this(target); if (target.getConfig() != null) { List pairs = target.getConfig().getPairs(); - TargetProperty.set(this, pairs != null ? pairs : List.of(), messageReporter); + TargetProperty.setAll(this, pairs != null ? pairs : List.of(), messageReporter); } - // FIXME: work these into the TargetProperty.set call above. - if (cliArgs != null) { - TargetProperty.override(this, cliArgs, messageReporter); + TargetProperty.overrideAll(this, cliArgs, messageReporter); } - if (cliArgs.containsKey("no-compile")) { - this.noCompile = true; - } - if (cliArgs.containsKey("verify")) { - this.verify = true; - } if (cliArgs.containsKey("logging")) { this.logLevel = LogLevel.valueOf(cliArgs.getProperty("logging").toUpperCase()); @@ -310,6 +303,6 @@ public TargetConfig(Properties cliArgs, TargetDecl target, MessageReporter messa new RustTargetConfig(); // FIXME: https://issue.lf-lang.org/1558 /** Path to a C file used by the Python target to setup federated execution. */ - public String fedSetupPreamble = null; // FIXME: https://issue.lf-lang.org/1558 + public FedSetupProperty fedSetupPreamble = new FedSetupProperty(); } diff --git a/core/src/main/java/org/lflang/TargetProperty.java b/core/src/main/java/org/lflang/TargetProperty.java index 11a9f44253..51c3924fef 100644 --- a/core/src/main/java/org/lflang/TargetProperty.java +++ b/core/src/main/java/org/lflang/TargetProperty.java @@ -34,17 +34,12 @@ import org.lflang.ast.ASTUtils; import org.lflang.generator.InvalidLfSourceException; -import org.lflang.generator.rust.CargoDependencySpec; -import org.lflang.generator.rust.CargoDependencySpec.CargoDependenciesPropertyType; -import org.lflang.lf.Element; import org.lflang.lf.KeyValuePair; import org.lflang.lf.KeyValuePairs; import org.lflang.lf.LfFactory; import org.lflang.lf.Model; import org.lflang.lf.TargetDecl; import org.lflang.target.property.type.TargetPropertyType; -import org.lflang.target.property.type.PrimitiveType; -import org.lflang.util.StringUtil; import org.lflang.validation.ValidationReporter; /** @@ -57,367 +52,374 @@ public enum TargetProperty { /** Directive to allow including OpenSSL libraries and process HMAC authentication. */ AUTH(config -> config.auth), - /** Directive to let the generator use the custom build command. */ - BUILD(config -> config.buildCommands), - - /** - * Directive to specify the target build type such as 'Release' or 'Debug'. This is also used in - * the Rust target to select a Cargo profile. - */ - BUILD_TYPE(config -> config.buildType), - - /** Directive to let the federate execution handle clock synchronization in software. */ - CLOCK_SYNC(config -> config.clockSync), - /** Key-value pairs giving options for clock synchronization. */ - CLOCK_SYNC_OPTIONS(config -> config.clockSyncOptions), - - /** - * Directive to specify a cmake to be included by the generated build systems. - * - *

This gives full control over the C/C++ build as any cmake parameters can be adjusted in the - * included file. - */ - CMAKE_INCLUDE(config -> config.cmakeIncludes), - /** Directive to specify the target compiler. */ - COMPILER(config -> config.compiler), - /** Directive to specify compile-time definitions. */ - COMPILE_DEFINITIONS(config -> config.compileDefinitions), - /** - * Directive to generate a Dockerfile. This is either a boolean, true or false, or a dictionary of - * options. - */ + /** Directive to let the generator use the custom build command. */ + BUILD(config -> config.buildCommands), + + /** + * Directive to specify the target build type such as 'Release' or 'Debug'. This is also used in + * the Rust target to select a Cargo profile. + */ + BUILD_TYPE(config -> config.buildType), + + /** Directive to let the federate execution handle clock synchronization in software. */ + CLOCK_SYNC(config -> config.clockSync), + /** Key-value pairs giving options for clock synchronization. */ + CLOCK_SYNC_OPTIONS(config -> config.clockSyncOptions), + + /** + * Directive to specify a cmake to be included by the generated build systems. + * + *

This gives full control over the C/C++ build as any cmake parameters can be adjusted in + * the + * included file. + */ + CMAKE_INCLUDE(config -> config.cmakeIncludes), + /** Directive to specify the target compiler. */ + COMPILER(config -> config.compiler), + /** Directive to specify compile-time definitions. */ + COMPILE_DEFINITIONS(config -> config.compileDefinitions), + /** + * Directive to generate a Dockerfile. This is either a boolean, true or false, or a dictionary of + * options. + */ /** Directive to specify the coordination mode */ COORDINATION(config -> config.coordination), /** Key-value pairs giving options for clock synchronization. */ COORDINATION_OPTIONS(config -> config.coordinationOptions), DOCKER(config -> config.dockerOptions), - /** Directive for specifying a path to an external runtime to be used for the compiled binary. */ - EXTERNAL_RUNTIME_PATH(config -> config.externalRuntimePath), - /** - * Directive to let the execution engine allow logical time to elapse faster than physical time. - */ - FAST(config -> config.fastMode), - /** - * Directive to stage particular files on the class path to be processed by the code generator. - */ - FILES(config -> config.files), - - /** Flags to be passed on to the target compiler. */ - FLAGS(config -> config.compilerFlags), - - /** - * Directive to let the execution engine remain active also if there are no more events in the - * event queue. - */ - KEEPALIVE(config -> config.keepalive), - - /** Directive to specify the grain at which to report log messages during execution. */ - LOGGING(config -> config.logLevel), - - /** Directive to not invoke the target compiler. */ - NO_COMPILE(config -> config.noCompile), - - /** Directive to disable validation of reactor rules at runtime. */ - NO_RUNTIME_VALIDATION(config -> config.noRuntimeValidation), - - /** - * Directive to specify the platform for cross code generation. This is either a string of the - * platform or a dictionary of options that includes the string name. - */ - PLATFORM((TargetConfig config) -> config.platformOptions), - - /** Directive to instruct the runtime to collect and print execution statistics. */ - PRINT_STATISTICS(config -> config.printStatistics), - - /** - * Directive for specifying .proto files that need to be compiled and their code included in the - * sources. - */ - PROTOBUFS(config -> config.protoFiles), - - /** Directive to specify that ROS2 specific code is generated, */ - ROS2(config -> config.ros2), - - /** Directive to specify additional ROS2 packages that this LF program depends on. */ - ROS2_DEPENDENCIES((TargetConfig config) -> config.ros2Dependencies), - - /** Directive for specifying a specific version of the reactor runtime library. */ - RUNTIME_VERSION(config -> config.runtimeVersion), - - /** Directive for specifying a specific runtime scheduler, if supported. */ - SCHEDULER((TargetConfig config) -> config.schedulerType), - /** Directive to specify that all code is generated in a single file. */ - SINGLE_FILE_PROJECT(config -> config.singleFileProject), - - /** Directive to indicate whether the runtime should use multi-threading. */ - THREADING(config -> config.threading), + /** Directive for specifying a path to an external runtime to be used for the compiled binary. */ + EXTERNAL_RUNTIME_PATH(config -> config.externalRuntimePath), + /** + * Directive to let the execution engine allow logical time to elapse faster than physical time. + */ + FAST(config -> config.fastMode), + /** + * Directive to stage particular files on the class path to be processed by the code generator. + */ + FILES(config -> config.files), + + /** Flags to be passed on to the target compiler. */ + FLAGS(config -> config.compilerFlags), + + /** + * Directive to let the execution engine remain active also if there are no more events in the + * event queue. + */ + KEEPALIVE(config -> config.keepalive), + + /** Directive to specify the grain at which to report log messages during execution. */ + LOGGING(config -> config.logLevel), + + /** Directive to not invoke the target compiler. */ + NO_COMPILE(config -> config.noCompile), + + /** Directive to disable validation of reactor rules at runtime. */ + NO_RUNTIME_VALIDATION(config -> config.noRuntimeValidation), + + /** + * Directive to specify the platform for cross code generation. This is either a string of the + * platform or a dictionary of options that includes the string name. + */ + PLATFORM((TargetConfig config) -> config.platformOptions), + + /** Directive to instruct the runtime to collect and print execution statistics. */ + PRINT_STATISTICS(config -> config.printStatistics), + + /** + * Directive for specifying .proto files that need to be compiled and their code included in the + * sources. + */ + PROTOBUFS(config -> config.protoFiles), + + /** Directive to specify that ROS2 specific code is generated, */ + ROS2(config -> config.ros2), + + /** Directive to specify additional ROS2 packages that this LF program depends on. */ + ROS2_DEPENDENCIES((TargetConfig config) -> config.ros2Dependencies), + + /** Directive for specifying a specific version of the reactor runtime library. */ + RUNTIME_VERSION(config -> config.runtimeVersion), + + /** Directive for specifying a specific runtime scheduler, if supported. */ + SCHEDULER((TargetConfig config) -> config.schedulerType), + /** Directive to specify that all code is generated in a single file. */ + SINGLE_FILE_PROJECT(config -> config.singleFileProject), + + /** Directive to indicate whether the runtime should use multi-threading. */ + THREADING(config -> config.threading), /** Directive to check the generated verification model. */ VERIFY(config -> config.verify), - /** Directive to specify the number of worker threads used by the runtime. */ - WORKERS(config -> config.workers), - - /** Directive to specify the execution timeout. */ - TIMEOUT(config -> config.timeout), - - /** Directive to enable tracing. */ - TRACING(config -> config.tracing), - - /** - * Directive to let the runtime export its internal dependency graph. - * - *

This is a debugging feature and currently only used for C++ and Rust programs. - */ - EXPORT_DEPENDENCY_GRAPH(config -> config.exportDependencyGraph), - - /** - * Directive to let the runtime export the program structure to a yaml file. - * - *

This is a debugging feature and currently only used for C++ programs. - */ - EXPORT_TO_YAML(config -> config.exportToYaml), - - /** - * List of module files to link into the crate as top-level. For instance, a {@code target Rust { - * rust-modules: [ "foo.rs" ] }} will cause the file to be copied into the generated project, and - * the generated {@code main.rs} will include it with a {@code mod foo;}. If one of the paths is a - * directory, it must contain a {@code mod.rs} file, and all its contents are copied. - */ - RUST_INCLUDE(config -> config.rust.rustTopLevelModules), - - /** Directive for specifying Cargo features of the generated program to enable. */ - CARGO_FEATURES(config -> config.rust.cargoFeatures), - - /** - * Dependency specifications for Cargo. This property looks like this: - * - *

{@code
-       * cargo-dependencies: {
-       *    // Name-of-the-crate: "version"
-       *    rand: "0.8",
-       *    // Equivalent to using an explicit map:
-       *    rand: {
-       *      version: "0.8"
-       *    },
-       *    // The map allows specifying more details
-       *    rand: {
-       *      // A path to a local unpublished crate.
-       *      // Note 'path' is mutually exclusive with 'version'.
-       *      path: "/home/me/Git/local-rand-clone"
-       *    },
-       *    rand: {
-       *      version: "0.8",
-       *      // you can specify cargo features
-       *      features: ["some-cargo-feature",]
-       *    }
-       * }
-       * }
- */ - CARGO_DEPENDENCIES(config -> config.rust.cargoDependencies), - - /** - * Directs the C or Python target to include the associated C file used for setting up federated - * execution before processing the first tag. - */ - FED_SETUP( - "_fed_setup", - PrimitiveType.FILE, - Arrays.asList(Target.C, Target.CCPP, Target.Python), - (config) -> ASTUtils.toElement(config.fedSetupPreamble), - (config, value, err) -> - config.fedSetupPreamble = StringUtil.removeQuotes(ASTUtils.elementToSingleString(value))); - - public final PropertyGetter propertyGetter; + /** Directive to specify the number of worker threads used by the runtime. */ + WORKERS(config -> config.workers), + + /** Directive to specify the execution timeout. */ + TIMEOUT(config -> config.timeout), + + /** Directive to enable tracing. */ + TRACING(config -> config.tracing), + + /** + * Directive to let the runtime export its internal dependency graph. + * + *

This is a debugging feature and currently only used for C++ and Rust programs. + */ + EXPORT_DEPENDENCY_GRAPH(config -> config.exportDependencyGraph), + + /** + * Directive to let the runtime export the program structure to a yaml file. + * + *

This is a debugging feature and currently only used for C++ programs. + */ + EXPORT_TO_YAML(config -> config.exportToYaml), + + /** + * List of module files to link into the crate as top-level. For instance, a + * {@code target Rust { + * rust-modules: [ "foo.rs" ] }} will cause the file to be copied into the generated project, + * and + * the generated {@code main.rs} will include it with a {@code mod foo;}. If one of the paths is + * a + * directory, it must contain a {@code mod.rs} file, and all its contents are copied. + */ + RUST_INCLUDE(config -> config.rust.rustTopLevelModules), + + /** Directive for specifying Cargo features of the generated program to enable. */ + CARGO_FEATURES(config -> config.rust.cargoFeatures), + + /** + * Dependency specifications for Cargo. This property looks like this: + * + *

{@code
+     * cargo-dependencies: {
+     *    // Name-of-the-crate: "version"
+     *    rand: "0.8",
+     *    // Equivalent to using an explicit map:
+     *    rand: {
+     *      version: "0.8"
+     *    },
+     *    // The map allows specifying more details
+     *    rand: {
+     *      // A path to a local unpublished crate.
+     *      // Note 'path' is mutually exclusive with 'version'.
+     *      path: "/home/me/Git/local-rand-clone"
+     *    },
+     *    rand: {
+     *      version: "0.8",
+     *      // you can specify cargo features
+     *      features: ["some-cargo-feature",]
+     *    }
+     * }
+     * }
+ */ + CARGO_DEPENDENCIES(config -> config.rust.cargoDependencies), + + /** + * Directs the C or Python target to include the associated C file used for setting up federated + * execution before processing the first tag. + */ + FED_SETUP(config -> config.fedSetupPreamble); + + public final PropertyGetter get; @FunctionalInterface - private interface PropertyGetter { - TargetPropertyConfig get(TargetConfig config); - } - - TargetProperty(PropertyGetter propertyGetter) { - this.propertyGetter = propertyGetter; - } - - public static void override(TargetConfig config, Properties properties, MessageReporter err) { - for (Object key : properties.keySet()) { - TargetProperty p = forName(key.toString()); - if (p != null) { - try { - p.propertyGetter.get(config).override(properties.get(key)); - } catch (InvalidLfSourceException e) { - err.at(e.getNode()).error(e.getProblem()); - } - } - } - } - - /** - * Set the given configuration using the given target properties. - * - * @param config The configuration object to update. - * @param properties AST node that holds all the target properties. - * @param err Error reporter on which property format errors will be reported - */ - public static void set(TargetConfig config, List properties, MessageReporter err) { - properties.forEach( - property -> { - TargetProperty p = forName(property.getName()); - if (p != null) { - // Mark the specified target property as set by the user - config.setByUser.add(p); - try { - p.setter.parseIntoTargetConfig(config, property.getValue(), err); - } catch (InvalidLfSourceException e) { - err.at(e.getNode()).error(e.getProblem()); + private interface PropertyGetter { + + TargetPropertyConfig get(TargetConfig config); + } + + TargetProperty(PropertyGetter propertyGetter) { + this.get = propertyGetter; + } + + public static void overrideAll(TargetConfig config, Properties properties, MessageReporter err) { + for (Object key : properties.keySet()) { + TargetProperty p = forName(key.toString()); + if (p != null) { + try { + p.get.get(config).override(properties.get(key)); + } catch (InvalidLfSourceException e) { + err.at(e.getNode()).error(e.getProblem()); + } } - } - }); - } - - /** - * Extracts all properties as a list of key-value pairs from a TargetConfig. Only extracts - * properties explicitly set by user. - * - * @param config The TargetConfig to extract from. - * @return The extracted properties. - */ - public static List extractProperties(TargetConfig config) { - var res = new LinkedList(); - for (TargetProperty p : config.setByUser) { - KeyValuePair kv = LfFactory.eINSTANCE.createKeyValuePair(); - kv.setName(p.toString()); - kv.setValue(p.getter.getPropertyElement(config)); - if (kv.getValue() != null) res.add(kv); + } } - return res; - } - - /** - * Constructs a TargetDecl by extracting the fields of the given TargetConfig. - * - * @param target The target to generate for. - * @param config The TargetConfig to extract from. - * @return A generated TargetDecl. - */ - public static TargetDecl extractTargetDecl(Target target, TargetConfig config) { - TargetDecl decl = LfFactory.eINSTANCE.createTargetDecl(); - KeyValuePairs kvp = LfFactory.eINSTANCE.createKeyValuePairs(); - for (KeyValuePair p : extractProperties(config)) { - kvp.getPairs().add(p); + + /** + * Set the given configuration using the given target properties. + * + * @param config The configuration object to update. + * @param properties AST node that holds all the target properties. + * @param err Error reporter on which property format errors will be reported + */ + public static void setAll(TargetConfig config, List properties, MessageReporter err) { + properties.forEach( + property -> { + TargetProperty p = forName(property.getName()); + if (p != null) { + try { + p.get.get(config).set(property.getValue(), err); + } catch (InvalidLfSourceException e) { + err.at(e.getNode()).error(e.getProblem()); + } + } + }); + } + + /** + * Extracts all properties as a list of key-value pairs from a TargetConfig. Only extracts + * properties explicitly set by user. + * + * @param config The TargetConfig to extract from. + * @return The extracted properties. + */ + public static List extractProperties(TargetConfig config) { + var res = new LinkedList(); + for (TargetProperty p : config.setByUser) { // FIXME: do not use setByUser + KeyValuePair kv = LfFactory.eINSTANCE.createKeyValuePair(); + kv.setName(p.toString()); + kv.setValue(p.get.get(config).export()); + if (kv.getValue() != null) { + res.add(kv); + } + } + return res; + } + + /** + * Constructs a TargetDecl by extracting the fields of the given TargetConfig. + * + * @param target The target to generate for. + * @param config The TargetConfig to extract from. + * @return A generated TargetDecl. + */ + public static TargetDecl extractTargetDecl(Target target, TargetConfig config) { + TargetDecl decl = LfFactory.eINSTANCE.createTargetDecl(); + KeyValuePairs kvp = LfFactory.eINSTANCE.createKeyValuePairs(); + for (KeyValuePair p : extractProperties(config)) { + kvp.getPairs().add(p); + } + decl.setName(target.toString()); + decl.setConfig(kvp); + return decl; } - decl.setName(target.toString()); - decl.setConfig(kvp); - return decl; - } public static KeyValuePair getKeyValuePair(KeyValuePairs targetProperties, TargetProperty property) { List properties = targetProperties.getPairs().stream() - .filter(pair -> pair.getName().equals(property.description)) + .filter(pair -> pair.getName().equals(property.toString())) .toList(); assert (properties.size() <= 1); return properties.size() > 0 ? properties.get(0) : null; } public static KeyValuePair getKeyValuePair(Model ast, TargetProperty property) { - return getKeyValuePair(ast.getTarget().getConfig(), property); + return getKeyValuePair(ast.getTarget().getConfig(), property); } public void validate(KeyValuePairs pairs, Model ast, TargetConfig config, ValidationReporter reporter) { - this.propertyGetter.get(config).validate(getKeyValuePair(pairs, this), ast, config, reporter); + this.get.get(config).validate(getKeyValuePair(pairs, this), ast, config, reporter); } - /** - * Update the given configuration using the given target properties. - * - * @param config The configuration object to update. - * @param properties AST node that holds all the target properties. - * @param relativePath The path from the main resource to the resource from which the new - * properties originate. - */ - public static void update( - TargetConfig config, List properties, Path relativePath, MessageReporter err) { - properties.forEach( - property -> { - TargetProperty p = forName(property.getName()); - if (p != null) { - // Mark the specified target property as set by the user - config.setByUser.add(p); - var value = property.getValue(); - if (property.getName().equals("files")) { - var array = LfFactory.eINSTANCE.createArray(); - ASTUtils.elementToListOfStrings(property.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); - } - p.updater.parseIntoTargetConfig(config, value, err); - } - }); - } - - /** - * Update one of the target properties, given by 'propertyName'. For convenience, a list of target - * properties (e.g., taken from a file or resource) can be passed without any filtering. This - * function will do nothing if the list of target properties doesn't include the property given by - * 'propertyName'. - * - * @param config The target config to apply the update to. - * @param property The target property. - * @param properties AST node that holds all the target properties. - * @param err Error reporter on which property format errors will be reported - */ - public static void updateOne( - TargetConfig config, - TargetProperty property, - List properties, - MessageReporter err) { - properties.stream() - .filter(p -> {return p.getName().equals(property.toString());}) - .findFirst() - .map(KeyValuePair::getValue) - .ifPresent(value -> property.updater.parseIntoTargetConfig(config, value, err)); - } - - /** - * Return the entry that matches the given string. - * - * @param name The string to match against. - */ - public static TargetProperty forName(String name) { - return Target.match(name, TargetProperty.values()); - } - - /** - * Return a list with all target properties. - * - * @return All existing target properties. - */ - public static List getOptions() { - return Arrays.asList(TargetProperty.values()); - } + /** + * Update the given configuration using the given target properties. + * + * @param config The configuration object to update. + * @param properties AST node that holds all the target properties. + * @param relativePath The path from the main resource to the resource from which the new + * properties originate. + */ + public static void update( + TargetConfig config, List properties, Path relativePath, MessageReporter err) { + properties.forEach( + property -> { + TargetProperty p = forName(property.getName()); + if (p != null) { + // Mark the specified target property as set by the user + config.setByUser.add(p); + var value = property.getValue(); + if (property.getName().equals("files")) { + var array = LfFactory.eINSTANCE.createArray(); + ASTUtils.elementToListOfStrings(property.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); + } + // FIXME: figure out different between update and override + // p.updater.parseIntoTargetConfig(config, value, err); + } + }); + } + + /** + * Update one of the target properties, given by 'propertyName'. For convenience, a list of + * target + * properties (e.g., taken from a file or resource) can be passed without any filtering. This + * function will do nothing if the list of target properties doesn't include the property given + * by + * 'propertyName'. + * + * @param config The target config to apply the update to. + * @param property The target property. + * @param properties AST node that holds all the target properties. + * @param err Error reporter on which property format errors will be reported + */ + public static void updateOne( + TargetConfig config, + TargetProperty property, + List properties, + MessageReporter err) { + // FIXME +// properties.stream() +// .filter(p -> {return p.getName().equals(property.toString());}) +// .findFirst() +// .map(KeyValuePair::getValue) +// .ifPresent(value -> property.updater.parseIntoTargetConfig(config, value, err)); + } + + /** + * Return the entry that matches the given string. + * + * @param name The string to match against. + */ + public static TargetProperty forName(String name) { + return Target.match(name, TargetProperty.values()); + } + + /** + * Return a list with all target properties. + * + * @return All existing target properties. + */ + public static List getOptions() { + return Arrays.asList(TargetProperty.values()); + } /** * Return the name of the property in as it appears in the target declaration. * It may be an invalid identifier in other languages (may contains dashes {@code -}). */ - @Override - public String toString() { - return this.name().toLowerCase().replaceAll("_", "-"); - } + @Override + public String toString() { + // Work around because this sole property does not follow the naming convention. + if (this.equals(FED_SETUP)) { + return "_fed_setup"; + } + return this.name().toLowerCase().replaceAll("_", "-"); + } - /** Interface for dictionary elements. It associates an entry with a type. */ - public interface DictionaryElement { + /** Interface for dictionary elements. It associates an entry with a type. */ + public interface DictionaryElement { - TargetPropertyType getType(); - } + TargetPropertyType getType(); + } } diff --git a/core/src/main/java/org/lflang/TargetPropertyConfig.java b/core/src/main/java/org/lflang/TargetPropertyConfig.java index d32aab84ce..44752d5e4e 100644 --- a/core/src/main/java/org/lflang/TargetPropertyConfig.java +++ b/core/src/main/java/org/lflang/TargetPropertyConfig.java @@ -21,7 +21,7 @@ */ public abstract class TargetPropertyConfig { - protected T value = initialize(); + protected T value = initialValue(); protected boolean setByUser; @@ -37,7 +37,7 @@ public void override(T value) { this.value = value; } - public abstract T initialize(); // FIXME: rename to initialValue + public abstract T initialValue(); /** * Parse the given element into the given target config. May use the error reporter to report diff --git a/core/src/main/java/org/lflang/generator/GeneratorUtils.java b/core/src/main/java/org/lflang/generator/GeneratorUtils.java index bac3ff1e5c..b281a98026 100644 --- a/core/src/main/java/org/lflang/generator/GeneratorUtils.java +++ b/core/src/main/java/org/lflang/generator/GeneratorUtils.java @@ -123,7 +123,7 @@ public static LFResource getLFResource( var targetConfig = new TargetConfig(target); if (config != null) { List pairs = config.getPairs(); - TargetProperty.set(targetConfig, pairs != null ? pairs : List.of(), messageReporter); + TargetProperty.setAll(targetConfig, pairs != null ? pairs : List.of(), messageReporter); } FileConfig fc = LFGenerator.createFileConfig( diff --git a/core/src/main/java/org/lflang/target/property/AuthProperty.java b/core/src/main/java/org/lflang/target/property/AuthProperty.java index 6106948282..d20ad37c2c 100644 --- a/core/src/main/java/org/lflang/target/property/AuthProperty.java +++ b/core/src/main/java/org/lflang/target/property/AuthProperty.java @@ -4,7 +4,6 @@ import java.util.List; import org.lflang.Target; -import org.lflang.target.property.DefaultBooleanProperty; public class AuthProperty extends DefaultBooleanProperty { diff --git a/core/src/main/java/org/lflang/target/property/BuildCommandsProperty.java b/core/src/main/java/org/lflang/target/property/BuildCommandsProperty.java index 33d46e7639..3bb2b7873e 100644 --- a/core/src/main/java/org/lflang/target/property/BuildCommandsProperty.java +++ b/core/src/main/java/org/lflang/target/property/BuildCommandsProperty.java @@ -18,7 +18,7 @@ public BuildCommandsProperty() { } @Override - public List initialize() { + public List initialValue() { return new ArrayList<>(); } diff --git a/core/src/main/java/org/lflang/target/property/BuildTypeProperty.java b/core/src/main/java/org/lflang/target/property/BuildTypeProperty.java index eeca094465..23e3ed2f12 100644 --- a/core/src/main/java/org/lflang/target/property/BuildTypeProperty.java +++ b/core/src/main/java/org/lflang/target/property/BuildTypeProperty.java @@ -24,7 +24,7 @@ public Element export() { } @Override - public BuildType initialize() { + public BuildType initialValue() { return BuildType.RELEASE; } 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 40f957d6c0..51bf43b379 100644 --- a/core/src/main/java/org/lflang/target/property/CargoDependenciesProperty.java +++ b/core/src/main/java/org/lflang/target/property/CargoDependenciesProperty.java @@ -21,7 +21,7 @@ public CargoDependenciesProperty() { } @Override - public Map initialize() { + public Map initialValue() { return new HashMap<>(); } 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 dd541fed0f..3d7eb6923a 100644 --- a/core/src/main/java/org/lflang/target/property/ClockSyncModeProperty.java +++ b/core/src/main/java/org/lflang/target/property/ClockSyncModeProperty.java @@ -26,7 +26,7 @@ public ClockSyncModeProperty() { } @Override - public ClockSyncMode initialize() { + public ClockSyncMode initialValue() { return ClockSyncMode.INIT; } 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 4b790b409f..8767d0d503 100644 --- a/core/src/main/java/org/lflang/target/property/ClockSyncOptionsProperty.java +++ b/core/src/main/java/org/lflang/target/property/ClockSyncOptionsProperty.java @@ -25,7 +25,7 @@ public ClockSyncOptionsProperty() { } @Override - public ClockSyncOptions initialize() { + public ClockSyncOptions initialValue() { return new ClockSyncOptions(); } diff --git a/core/src/main/java/org/lflang/target/property/CmakeIncludeProperty.java b/core/src/main/java/org/lflang/target/property/CmakeIncludeProperty.java index 4dd02b840b..5a5b96ed37 100644 --- a/core/src/main/java/org/lflang/target/property/CmakeIncludeProperty.java +++ b/core/src/main/java/org/lflang/target/property/CmakeIncludeProperty.java @@ -18,7 +18,7 @@ public CmakeIncludeProperty() { } @Override - public List initialize() { + public List initialValue() { return new ArrayList<>(); } diff --git a/core/src/main/java/org/lflang/target/property/CompileDefinitionsConfig.java b/core/src/main/java/org/lflang/target/property/CompileDefinitionsConfig.java index 773bb7298a..92f6b569df 100644 --- a/core/src/main/java/org/lflang/target/property/CompileDefinitionsConfig.java +++ b/core/src/main/java/org/lflang/target/property/CompileDefinitionsConfig.java @@ -17,7 +17,7 @@ public CompileDefinitionsConfig() { } @Override - public Map initialize() { + public Map initialValue() { return new HashMap<>(); } diff --git a/core/src/main/java/org/lflang/target/property/CoordinationModeProperty.java b/core/src/main/java/org/lflang/target/property/CoordinationModeProperty.java index 75397af897..3a02e7a7b4 100644 --- a/core/src/main/java/org/lflang/target/property/CoordinationModeProperty.java +++ b/core/src/main/java/org/lflang/target/property/CoordinationModeProperty.java @@ -21,7 +21,7 @@ public CoordinationModeProperty() { } @Override - public CoordinationMode initialize() { + public CoordinationMode initialValue() { return CoordinationMode.CENTRALIZED; } 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 3f0ea42e04..a61e54831b 100644 --- a/core/src/main/java/org/lflang/target/property/CoordinationOptionsProperty.java +++ b/core/src/main/java/org/lflang/target/property/CoordinationOptionsProperty.java @@ -25,7 +25,7 @@ public CoordinationOptionsProperty() { } @Override - public CoordinationOptions initialize() { + public CoordinationOptions initialValue() { return new CoordinationOptions(); } diff --git a/core/src/main/java/org/lflang/target/property/DefaultBooleanProperty.java b/core/src/main/java/org/lflang/target/property/DefaultBooleanProperty.java index e546e704bb..088cf71cf4 100644 --- a/core/src/main/java/org/lflang/target/property/DefaultBooleanProperty.java +++ b/core/src/main/java/org/lflang/target/property/DefaultBooleanProperty.java @@ -14,7 +14,7 @@ public DefaultBooleanProperty() { } @Override - public Boolean initialize() { + public Boolean initialValue() { return false; } diff --git a/core/src/main/java/org/lflang/target/property/DefaultFileListProperty.java b/core/src/main/java/org/lflang/target/property/DefaultFileListProperty.java index b69b053ea3..5323c0ac78 100644 --- a/core/src/main/java/org/lflang/target/property/DefaultFileListProperty.java +++ b/core/src/main/java/org/lflang/target/property/DefaultFileListProperty.java @@ -23,7 +23,7 @@ public void override(List value) { // FIXME: should this be override or } @Override - public List initialize() { + public List initialValue() { return new ArrayList<>(); } diff --git a/core/src/main/java/org/lflang/target/property/DefaultStringConfig.java b/core/src/main/java/org/lflang/target/property/DefaultStringConfig.java index 094c7c1728..a4a909ea20 100644 --- a/core/src/main/java/org/lflang/target/property/DefaultStringConfig.java +++ b/core/src/main/java/org/lflang/target/property/DefaultStringConfig.java @@ -17,7 +17,7 @@ public DefaultStringConfig() { } @Override - public String initialize() { + public String initialValue() { return ""; } diff --git a/core/src/main/java/org/lflang/target/property/DefaultStringListProperty.java b/core/src/main/java/org/lflang/target/property/DefaultStringListProperty.java index e7bb90b4cb..936b724cbd 100644 --- a/core/src/main/java/org/lflang/target/property/DefaultStringListProperty.java +++ b/core/src/main/java/org/lflang/target/property/DefaultStringListProperty.java @@ -17,7 +17,7 @@ public DefaultStringListProperty() { } @Override - public List initialize() { + public List initialValue() { return new ArrayList<>(); } 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 b5136cfd7b..5676584915 100644 --- a/core/src/main/java/org/lflang/target/property/DockerProperty.java +++ b/core/src/main/java/org/lflang/target/property/DockerProperty.java @@ -28,7 +28,7 @@ public DockerProperty() { } @Override - public DockerOptions initialize() { + public DockerOptions initialValue() { return new DockerOptions(false); } diff --git a/core/src/main/java/org/lflang/target/property/LoggingProperty.java b/core/src/main/java/org/lflang/target/property/LoggingProperty.java index 386b712402..8a4a1fabc9 100644 --- a/core/src/main/java/org/lflang/target/property/LoggingProperty.java +++ b/core/src/main/java/org/lflang/target/property/LoggingProperty.java @@ -17,7 +17,7 @@ public LoggingProperty() { } @Override - public LogLevel initialize() { + public LogLevel initialValue() { return LogLevel.INFO; } 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 2980d96964..3ef0cf5581 100644 --- a/core/src/main/java/org/lflang/target/property/PlatformProperty.java +++ b/core/src/main/java/org/lflang/target/property/PlatformProperty.java @@ -29,7 +29,7 @@ public PlatformProperty() { } @Override - public PlatformOptions initialize() { + public PlatformOptions initialValue() { return new PlatformOptions(); } 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 2f5450dd12..f2be54b1ab 100644 --- a/core/src/main/java/org/lflang/target/property/Ros2DependenciesProperty.java +++ b/core/src/main/java/org/lflang/target/property/Ros2DependenciesProperty.java @@ -22,7 +22,7 @@ public Ros2DependenciesProperty() { } @Override - public List initialize() { + public List initialValue() { return new ArrayList<>(); } diff --git a/core/src/main/java/org/lflang/target/property/RustIncludeProperty.java b/core/src/main/java/org/lflang/target/property/RustIncludeProperty.java index 79fb107be9..d95fa2a68d 100644 --- a/core/src/main/java/org/lflang/target/property/RustIncludeProperty.java +++ b/core/src/main/java/org/lflang/target/property/RustIncludeProperty.java @@ -30,7 +30,7 @@ public List supportedTargets() { } @Override - public List initialize() { + public List initialValue() { return new ArrayList<>(); } 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 66a6d83b47..5a81e4486c 100644 --- a/core/src/main/java/org/lflang/target/property/SchedulerProperty.java +++ b/core/src/main/java/org/lflang/target/property/SchedulerProperty.java @@ -30,7 +30,7 @@ public SchedulerProperty() { } @Override - public SchedulerOption initialize() { + public SchedulerOption initialValue() { return SchedulerOption.getDefault(); } diff --git a/core/src/main/java/org/lflang/target/property/ThreadingProperty.java b/core/src/main/java/org/lflang/target/property/ThreadingProperty.java index 023480ed28..b0abbae4c6 100644 --- a/core/src/main/java/org/lflang/target/property/ThreadingProperty.java +++ b/core/src/main/java/org/lflang/target/property/ThreadingProperty.java @@ -13,7 +13,7 @@ public List supportedTargets() { @Override - public Boolean initialize() { + public Boolean initialValue() { return true; } } diff --git a/core/src/main/java/org/lflang/target/property/TimeOutProperty.java b/core/src/main/java/org/lflang/target/property/TimeOutProperty.java index 6aec1948fd..da84484ea2 100644 --- a/core/src/main/java/org/lflang/target/property/TimeOutProperty.java +++ b/core/src/main/java/org/lflang/target/property/TimeOutProperty.java @@ -18,7 +18,7 @@ public TimeOutProperty() { } @Override - public TimeValue initialize() { + public TimeValue initialValue() { return 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 1bca01000d..9484b380d3 100644 --- a/core/src/main/java/org/lflang/target/property/TracingProperty.java +++ b/core/src/main/java/org/lflang/target/property/TracingProperty.java @@ -31,7 +31,7 @@ public TracingProperty() { } @Override - public TracingOptions initialize() { + public TracingOptions initialValue() { return new TracingOptions(false); } 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 50e1a8bc0e..a28a5a9ec0 100644 --- a/core/src/main/java/org/lflang/target/property/WorkersProperty.java +++ b/core/src/main/java/org/lflang/target/property/WorkersProperty.java @@ -15,7 +15,7 @@ public WorkersProperty() { } @Override - public Integer initialize() { + public Integer initialValue() { return 0; } From 413f8a1b590e09401b66be14668748fdcc79f2fc Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Wed, 27 Sep 2023 00:40:53 -0700 Subject: [PATCH 006/145] Fixes and cleanups --- .../main/java/org/lflang/TargetConfig.java | 50 ++---------- .../main/java/org/lflang/TargetProperty.java | 80 +++++++------------ .../java/org/lflang/TargetPropertyConfig.java | 35 ++++---- .../federated/generator/FedTargetConfig.java | 4 +- .../org/lflang/generator/GeneratorUtils.java | 2 +- .../generator/rust/RustTargetConfig.java | 2 +- .../property/BuildCommandsProperty.java | 4 +- .../target/property/BuildTypeProperty.java | 4 +- .../property/CargoDependenciesProperty.java | 4 +- .../property/ClockSyncModeProperty.java | 4 +- .../property/ClockSyncOptionsProperty.java | 4 +- .../target/property/CmakeIncludeProperty.java | 28 ++++--- .../property/CompileDefinitionsConfig.java | 4 +- .../property/CoordinationModeProperty.java | 4 +- .../property/CoordinationOptionsProperty.java | 4 +- .../property/DefaultBooleanProperty.java | 10 ++- .../property/DefaultFileListProperty.java | 6 +- .../target/property/DefaultStringConfig.java | 10 ++- .../property/DefaultStringListProperty.java | 33 +++++++- .../target/property/DockerProperty.java | 4 +- .../property/ExternalRuntimePathConfig.java | 14 ---- .../property/ExternalRuntimePathProperty.java | 13 +++ .../target/property/LoggingProperty.java | 12 ++- .../target/property/PlatformProperty.java | 4 +- .../property/Ros2DependenciesProperty.java | 4 +- .../target/property/RustIncludeProperty.java | 4 +- .../target/property/SchedulerProperty.java | 4 +- .../target/property/TimeOutProperty.java | 4 +- .../target/property/TracingProperty.java | 6 +- .../target/property/WorkersProperty.java | 10 ++- .../org/lflang/generator/cpp/CppGenerator.kt | 4 +- .../cpp/CppStandaloneCmakeGenerator.kt | 6 +- 32 files changed, 190 insertions(+), 191 deletions(-) delete mode 100644 core/src/main/java/org/lflang/target/property/ExternalRuntimePathConfig.java create mode 100644 core/src/main/java/org/lflang/target/property/ExternalRuntimePathProperty.java diff --git a/core/src/main/java/org/lflang/TargetConfig.java b/core/src/main/java/org/lflang/TargetConfig.java index 7641c8ec8f..72d3077ad3 100644 --- a/core/src/main/java/org/lflang/TargetConfig.java +++ b/core/src/main/java/org/lflang/TargetConfig.java @@ -25,12 +25,10 @@ package org.lflang; import java.util.ArrayList; -import java.util.HashSet; + import java.util.List; import java.util.Properties; -import java.util.Set; -import org.lflang.generator.LFGeneratorContext.BuildParm; import org.lflang.generator.rust.RustTargetConfig; import org.lflang.lf.KeyValuePair; import org.lflang.lf.TargetDecl; @@ -46,7 +44,6 @@ import org.lflang.target.property.Ros2DependenciesProperty; import org.lflang.target.property.SchedulerProperty; import org.lflang.target.property.LoggingProperty; -import org.lflang.target.property.LoggingProperty.LogLevel; import org.lflang.target.property.TracingProperty; import org.lflang.target.property.BuildCommandsProperty; import org.lflang.target.property.ClockSyncOptionsProperty; @@ -68,7 +65,7 @@ import org.lflang.target.property.CmakeIncludeProperty; import org.lflang.target.property.type.CompileDefinitionsConfig; import org.lflang.target.property.type.CompilerConfig; -import org.lflang.target.property.type.ExternalRuntimePathConfig; +import org.lflang.target.property.ExternalRuntimePathProperty; import org.lflang.target.property.type.VerifyProperty; /** @@ -104,52 +101,15 @@ public TargetConfig(Properties cliArgs, TargetDecl target, MessageReporter messa this(target); if (target.getConfig() != null) { List pairs = target.getConfig().getPairs(); - TargetProperty.setAll(this, pairs != null ? pairs : List.of(), messageReporter); + TargetProperty.load(this, pairs != null ? pairs : List.of(), messageReporter); } if (cliArgs != null) { - TargetProperty.overrideAll(this, cliArgs, messageReporter); - } - - - if (cliArgs.containsKey("logging")) { - this.logLevel = LogLevel.valueOf(cliArgs.getProperty("logging").toUpperCase()); - this.setByUser.add(TargetProperty.LOGGING); - } - if (cliArgs.containsKey("workers")) { - this.workers = Integer.parseInt(cliArgs.getProperty("workers")); - this.setByUser.add(TargetProperty.WORKERS); - } - if (cliArgs.containsKey("threading")) { - this.threading = Boolean.parseBoolean(cliArgs.getProperty("threading")); - this.setByUser.add(TargetProperty.THREADING); + TargetProperty.load(this, cliArgs, messageReporter); } - if (cliArgs.containsKey("target-flags")) { - this.compilerFlags.clear(); - if (!cliArgs.getProperty("target-flags").isEmpty()) { - this.compilerFlags.addAll(List.of(cliArgs.getProperty("target-flags").split(" "))); - } - this.setByUser.add(TargetProperty.FLAGS); - } - if (cliArgs.containsKey("runtime-version")) { - this.runtimeVersion = cliArgs.getProperty("runtime-version"); - this.setByUser.add(TargetProperty.RUNTIME_VERSION); - } - if (cliArgs.containsKey("external-runtime-path")) { - this.externalRuntimePath = cliArgs.getProperty("external-runtime-path"); - this.setByUser.add(TargetProperty.EXTERNAL_RUNTIME_PATH); - } - - if (cliArgs.containsKey(BuildParm.PRINT_STATISTICS.getKey())) { - this.printStatistics = true; - this.setByUser.add(TargetProperty.PRINT_STATISTICS); - } } - /** Keep track of every target property that is explicitly set by the user. */ - public Set setByUser = new HashSet<>(); - /** * A list of custom build commands that replace the default build process of directly invoking a * designated compiler. A common usage of this target property is to set the command to build on @@ -201,7 +161,7 @@ public TargetConfig(Properties cliArgs, TargetDecl target, MessageReporter messa public CoordinationOptionsProperty coordinationOptions = new CoordinationOptionsProperty(); /** Link to an external runtime library instead of the default one. */ - public ExternalRuntimePathConfig externalRuntimePath = new ExternalRuntimePathConfig(); + public ExternalRuntimePathProperty externalRuntimePath = new ExternalRuntimePathProperty(); /** * If true, configure the execution environment such that it does not wait for physical time to diff --git a/core/src/main/java/org/lflang/TargetProperty.java b/core/src/main/java/org/lflang/TargetProperty.java index 51c3924fef..c5d1b2d11c 100644 --- a/core/src/main/java/org/lflang/TargetProperty.java +++ b/core/src/main/java/org/lflang/TargetProperty.java @@ -31,6 +31,7 @@ import java.util.List; import java.util.Objects; import java.util.Properties; +import java.util.stream.Collectors; import org.lflang.ast.ASTUtils; import org.lflang.generator.InvalidLfSourceException; @@ -78,15 +79,15 @@ public enum TargetProperty { COMPILER(config -> config.compiler), /** Directive to specify compile-time definitions. */ COMPILE_DEFINITIONS(config -> config.compileDefinitions), - /** - * Directive to generate a Dockerfile. This is either a boolean, true or false, or a dictionary of - * options. - */ + /** Directive to specify the coordination mode */ COORDINATION(config -> config.coordination), /** Key-value pairs giving options for clock synchronization. */ COORDINATION_OPTIONS(config -> config.coordinationOptions), - + /** + * Directive to generate a Dockerfile. This is either a boolean, true or false, or a dictionary of + * options. + */ DOCKER(config -> config.dockerOptions), /** Directive for specifying a path to an external runtime to be used for the compiled binary. */ EXTERNAL_RUNTIME_PATH(config -> config.externalRuntimePath), @@ -221,24 +222,23 @@ public enum TargetProperty { */ FED_SETUP(config -> config.fedSetupPreamble); - public final PropertyGetter get; + public final ConfigLoader property; @FunctionalInterface - private interface PropertyGetter { - - TargetPropertyConfig get(TargetConfig config); + private interface ConfigLoader { + TargetPropertyConfig of(TargetConfig config); } - TargetProperty(PropertyGetter propertyGetter) { - this.get = propertyGetter; + TargetProperty(ConfigLoader property) { + this.property = property; } - public static void overrideAll(TargetConfig config, Properties properties, MessageReporter err) { + public static void load(TargetConfig config, Properties properties, MessageReporter err) { for (Object key : properties.keySet()) { TargetProperty p = forName(key.toString()); if (p != null) { try { - p.get.get(config).override(properties.get(key)); + p.property.of(config).set(properties.get(key).toString(), err); } catch (InvalidLfSourceException e) { err.at(e.getNode()).error(e.getProblem()); } @@ -253,13 +253,13 @@ public static void overrideAll(TargetConfig config, Properties properties, Messa * @param properties AST node that holds all the target properties. * @param err Error reporter on which property format errors will be reported */ - public static void setAll(TargetConfig config, List properties, MessageReporter err) { + public static void load(TargetConfig config, List properties, MessageReporter err) { properties.forEach( property -> { TargetProperty p = forName(property.getName()); if (p != null) { try { - p.get.get(config).set(property.getValue(), err); + p.property.of(config).set(property.getValue(), err); } catch (InvalidLfSourceException e) { err.at(e.getNode()).error(e.getProblem()); } @@ -276,10 +276,10 @@ public static void setAll(TargetConfig config, List properties, Me */ public static List extractProperties(TargetConfig config) { var res = new LinkedList(); - for (TargetProperty p : config.setByUser) { // FIXME: do not use setByUser + for (TargetProperty p : TargetProperty.loaded(config)) { KeyValuePair kv = LfFactory.eINSTANCE.createKeyValuePair(); kv.setName(p.toString()); - kv.setValue(p.get.get(config).export()); + kv.setValue(p.property.of(config).toAstElement()); if (kv.getValue() != null) { res.add(kv); } @@ -287,6 +287,12 @@ public static List extractProperties(TargetConfig config) { return res; } + public static List loaded(TargetConfig config) { + return Arrays.stream(TargetProperty.values()).filter( + it -> it.property.of(config).isSet() + ).collect(Collectors.toList()); + } + /** * Constructs a TargetDecl by extracting the fields of the given TargetConfig. * @@ -305,12 +311,12 @@ public static TargetDecl extractTargetDecl(Target target, TargetConfig config) { return decl; } - public static KeyValuePair getKeyValuePair(KeyValuePairs targetProperties, TargetProperty property) { + private static KeyValuePair getKeyValuePair(KeyValuePairs targetProperties, TargetProperty property) { List properties = targetProperties.getPairs().stream() .filter(pair -> pair.getName().equals(property.toString())) .toList(); - assert (properties.size() <= 1); + assert properties.size() <= 1; return properties.size() > 0 ? properties.get(0) : null; } @@ -319,7 +325,7 @@ public static KeyValuePair getKeyValuePair(Model ast, TargetProperty property) { } public void validate(KeyValuePairs pairs, Model ast, TargetConfig config, ValidationReporter reporter) { - this.get.get(config).validate(getKeyValuePair(pairs, this), ast, config, reporter); + this.property.of(config).validate(getKeyValuePair(pairs, this), ast, config, reporter); } /** @@ -336,8 +342,6 @@ public static void update( property -> { TargetProperty p = forName(property.getName()); if (p != null) { - // Mark the specified target property as set by the user - config.setByUser.add(p); var value = property.getValue(); if (property.getName().equals("files")) { var array = LfFactory.eINSTANCE.createArray(); @@ -354,38 +358,11 @@ public static void update( value = LfFactory.eINSTANCE.createElement(); value.setArray(array); } - // FIXME: figure out different between update and override - // p.updater.parseIntoTargetConfig(config, value, err); + p.property.of(config).set(value, err); } }); } - /** - * Update one of the target properties, given by 'propertyName'. For convenience, a list of - * target - * properties (e.g., taken from a file or resource) can be passed without any filtering. This - * function will do nothing if the list of target properties doesn't include the property given - * by - * 'propertyName'. - * - * @param config The target config to apply the update to. - * @param property The target property. - * @param properties AST node that holds all the target properties. - * @param err Error reporter on which property format errors will be reported - */ - public static void updateOne( - TargetConfig config, - TargetProperty property, - List properties, - MessageReporter err) { - // FIXME -// properties.stream() -// .filter(p -> {return p.getName().equals(property.toString());}) -// .findFirst() -// .map(KeyValuePair::getValue) -// .ifPresent(value -> property.updater.parseIntoTargetConfig(config, value, err)); - } - /** * Return the entry that matches the given string. * @@ -410,7 +387,7 @@ public static List getOptions() { */ @Override public String toString() { - // Work around because this sole property does not follow the naming convention. + // Workaround because this sole property does not follow the naming convention. if (this.equals(FED_SETUP)) { return "_fed_setup"; } @@ -419,7 +396,6 @@ public String toString() { /** Interface for dictionary elements. It associates an entry with a type. */ public interface DictionaryElement { - TargetPropertyType getType(); } } diff --git a/core/src/main/java/org/lflang/TargetPropertyConfig.java b/core/src/main/java/org/lflang/TargetPropertyConfig.java index 44752d5e4e..99be6d6b04 100644 --- a/core/src/main/java/org/lflang/TargetPropertyConfig.java +++ b/core/src/main/java/org/lflang/TargetPropertyConfig.java @@ -1,7 +1,6 @@ package org.lflang; import java.util.List; -import java.util.Properties; import org.lflang.lf.Element; import org.lflang.lf.KeyValuePair; @@ -23,7 +22,7 @@ public abstract class TargetPropertyConfig { protected T value = initialValue(); - protected boolean setByUser; + protected boolean isSet; /* The type of values that can be assigned to this property. */ public final TargetPropertyType type; @@ -33,7 +32,7 @@ public TargetPropertyConfig(TargetPropertyType type) { } public void override(T value) { - this.setByUser = true; + this.isSet = true; this.value = value; } @@ -44,21 +43,25 @@ public void override(T value) { * format errors. */ public void set(Element value, MessageReporter err) { - var parsed = this.parse(value); // FIXME pass in error reporter. Maybe also rename to load? + var parsed = this.fromAst(value, err); if (parsed != null) { - this.setByUser = true; + this.isSet = true; this.value = parsed; } } - public void update(Element value, MessageReporter err) { // FIXME: diff with override?? - this.setByUser = true; - this.set(value, err); + public void set(String value, MessageReporter err) { + var parsed = this.fromString(value, err); + if (parsed != null) { + this.isSet = true; + this.value = parsed; + } } - public void update(Properties cliArgs) { - this.setByUser = true; - } // FIXME: this is incomplete + public void reset() { + this.value = initialValue(); + this.isSet = false; + } /** * Return the current configuration. @@ -67,7 +70,9 @@ public T get() { return value; } - protected abstract T parse(Element value); + protected abstract T fromAst(Element value, MessageReporter err); + + protected abstract T fromString(String value, MessageReporter err); public abstract List supportedTargets(); @@ -102,10 +107,10 @@ public void validate(KeyValuePair pair, Model ast, TargetConfig config, Validati * Read this property from the target config and build an element which represents it for the AST. * May return null if the given value of this property is the same as the default. */ - public abstract Element export(); + public abstract Element toAstElement(); - public boolean isSetByUser() { - return setByUser; + public boolean isSet() { + return isSet; } @Override diff --git a/core/src/main/java/org/lflang/federated/generator/FedTargetConfig.java b/core/src/main/java/org/lflang/federated/generator/FedTargetConfig.java index 4eef59c7e9..87b4fec960 100644 --- a/core/src/main/java/org/lflang/federated/generator/FedTargetConfig.java +++ b/core/src/main/java/org/lflang/federated/generator/FedTargetConfig.java @@ -75,7 +75,7 @@ private Path getRelativePath(Resource source, Resource target) { /** Method for the removal of things that should not appear in the target config of a federate. */ private void clearPropertiesToIgnore() { - this.setByUser.remove(TargetProperty.CLOCK_SYNC); - this.setByUser.remove(TargetProperty.CLOCK_SYNC_OPTIONS); + this.clockSync.reset(); + this.clockSyncOptions.reset(); } } diff --git a/core/src/main/java/org/lflang/generator/GeneratorUtils.java b/core/src/main/java/org/lflang/generator/GeneratorUtils.java index b281a98026..545d8576a9 100644 --- a/core/src/main/java/org/lflang/generator/GeneratorUtils.java +++ b/core/src/main/java/org/lflang/generator/GeneratorUtils.java @@ -123,7 +123,7 @@ public static LFResource getLFResource( var targetConfig = new TargetConfig(target); if (config != null) { List pairs = config.getPairs(); - TargetProperty.setAll(targetConfig, pairs != null ? pairs : List.of(), messageReporter); + TargetProperty.load(targetConfig, pairs != null ? pairs : List.of(), messageReporter); } FileConfig fc = LFGenerator.createFileConfig( diff --git a/core/src/main/java/org/lflang/generator/rust/RustTargetConfig.java b/core/src/main/java/org/lflang/generator/rust/RustTargetConfig.java index c453763399..7d13203c86 100644 --- a/core/src/main/java/org/lflang/generator/rust/RustTargetConfig.java +++ b/core/src/main/java/org/lflang/generator/rust/RustTargetConfig.java @@ -54,7 +54,7 @@ public final class RustTargetConfig { public BuildType getBuildType(BuildTypeProperty cmakeBuildType) { // FIXME: this is because Rust uses a different default. // Can we just use the same? - if (cmakeBuildType.isSetByUser()) { + if (cmakeBuildType.isSet()) { return cmakeBuildType.get(); } return profile; diff --git a/core/src/main/java/org/lflang/target/property/BuildCommandsProperty.java b/core/src/main/java/org/lflang/target/property/BuildCommandsProperty.java index 3bb2b7873e..2285d13a27 100644 --- a/core/src/main/java/org/lflang/target/property/BuildCommandsProperty.java +++ b/core/src/main/java/org/lflang/target/property/BuildCommandsProperty.java @@ -23,7 +23,7 @@ public List initialValue() { } @Override - public List parse(Element value) { + public List fromAstElement(Element value) { return ASTUtils.elementToListOfStrings(value); } @@ -33,7 +33,7 @@ public List supportedTargets() { } @Override - public Element export() { + public Element toAstElement() { return ASTUtils.toElement(this.value.toString()); } diff --git a/core/src/main/java/org/lflang/target/property/BuildTypeProperty.java b/core/src/main/java/org/lflang/target/property/BuildTypeProperty.java index 23e3ed2f12..1ce941c42b 100644 --- a/core/src/main/java/org/lflang/target/property/BuildTypeProperty.java +++ b/core/src/main/java/org/lflang/target/property/BuildTypeProperty.java @@ -19,7 +19,7 @@ public BuildTypeProperty() { } @Override - public Element export() { + public Element toAstElement() { return ASTUtils.toElement(this.value.toString()); } @@ -29,7 +29,7 @@ public BuildType initialValue() { } @Override - public BuildType parse(Element value) { + public BuildType fromAstElement(Element value) { return (BuildType) UnionType.BUILD_TYPE_UNION.forName(ASTUtils.elementToSingleString(value)); } 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 51bf43b379..9672567c7f 100644 --- a/core/src/main/java/org/lflang/target/property/CargoDependenciesProperty.java +++ b/core/src/main/java/org/lflang/target/property/CargoDependenciesProperty.java @@ -26,7 +26,7 @@ public Map initialValue() { } @Override - protected Map parse(Element value) { + protected Map fromAstElement(Element value) { return CargoDependencySpec.parseAll(value); } @@ -36,7 +36,7 @@ public List supportedTargets() { } @Override - public Element export() { + public Element toAstElement() { var deps = this.value; if (deps.size() == 0) { return null; 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 3d7eb6923a..d9d8d14810 100644 --- a/core/src/main/java/org/lflang/target/property/ClockSyncModeProperty.java +++ b/core/src/main/java/org/lflang/target/property/ClockSyncModeProperty.java @@ -31,7 +31,7 @@ public ClockSyncMode initialValue() { } @Override - public ClockSyncMode parse(Element value) { + public ClockSyncMode fromAstElement(Element value) { UnionType.CLOCK_SYNC_UNION.validate(value); var mode = (ClockSyncMode) @@ -64,7 +64,7 @@ public void validate(KeyValuePair pair, Model ast, TargetConfig config, Validati } @Override - public Element export() { + public Element toAstElement() { return ASTUtils.toElement(this.value.toString()); } 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 8767d0d503..1d658a67e6 100644 --- a/core/src/main/java/org/lflang/target/property/ClockSyncOptionsProperty.java +++ b/core/src/main/java/org/lflang/target/property/ClockSyncOptionsProperty.java @@ -30,7 +30,7 @@ public ClockSyncOptions initialValue() { } @Override - public ClockSyncOptions parse(Element value) { + public ClockSyncOptions fromAstElement(Element value) { var options = new ClockSyncOptions(); for (KeyValuePair entry : value.getKeyvalue().getPairs()) { ClockSyncOption option = @@ -56,7 +56,7 @@ public List supportedTargets() { } @Override - public Element export() { + public Element toAstElement() { Element e = LfFactory.eINSTANCE.createElement(); KeyValuePairs kvp = LfFactory.eINSTANCE.createKeyValuePairs(); for (ClockSyncOption opt : ClockSyncOption.values()) { diff --git a/core/src/main/java/org/lflang/target/property/CmakeIncludeProperty.java b/core/src/main/java/org/lflang/target/property/CmakeIncludeProperty.java index 5a5b96ed37..29ff2f8f6d 100644 --- a/core/src/main/java/org/lflang/target/property/CmakeIncludeProperty.java +++ b/core/src/main/java/org/lflang/target/property/CmakeIncludeProperty.java @@ -22,28 +22,38 @@ public List initialValue() { return new ArrayList<>(); } + @Override - public void update(Element value, MessageReporter err) { - super.update(value, err); - // FIXME: This merging of lists is potentially dangerous since - // the incoming list of cmake-includes can belong to a .lf file that is - // located in a different location, and keeping just filename - // strings like this without absolute paths is incorrect. - this.value.addAll(ASTUtils.elementToListOfStrings(value)); + public void set(Element value, MessageReporter err) { + if (!this.isSet) { + super.set(value, err); + } else { + // NOTE: This merging of lists is potentially dangerous since + // the incoming list of cmake-includes can belong to a .lf file that is + // located in a different location, and keeping just filename + // strings like this without absolute paths is incorrect. + this.value.addAll(ASTUtils.elementToListOfStrings(value)); + } + } @Override - protected List parse(Element value) { + protected List fromAst(Element value, MessageReporter err) { return ASTUtils.elementToListOfStrings(value); } + @Override + protected List fromString(String value, MessageReporter err) { + return null; // FIXME: not sure about this one + } + @Override public List supportedTargets() { return Arrays.asList(Target.CPP, Target.C, Target.CCPP); } @Override - public Element export() { + public Element toAstElement() { return ASTUtils.toElement(this.value); } } diff --git a/core/src/main/java/org/lflang/target/property/CompileDefinitionsConfig.java b/core/src/main/java/org/lflang/target/property/CompileDefinitionsConfig.java index 92f6b569df..d5927c1a0b 100644 --- a/core/src/main/java/org/lflang/target/property/CompileDefinitionsConfig.java +++ b/core/src/main/java/org/lflang/target/property/CompileDefinitionsConfig.java @@ -22,7 +22,7 @@ public Map initialValue() { } @Override - protected Map parse(Element value) { + protected Map fromAstElement(Element value) { return ASTUtils.elementToStringMaps(value); } @@ -32,7 +32,7 @@ public List supportedTargets() { } @Override - public Element export() { + public Element toAstElement() { return ASTUtils.toElement(this.value); } } diff --git a/core/src/main/java/org/lflang/target/property/CoordinationModeProperty.java b/core/src/main/java/org/lflang/target/property/CoordinationModeProperty.java index 3a02e7a7b4..96efe0de31 100644 --- a/core/src/main/java/org/lflang/target/property/CoordinationModeProperty.java +++ b/core/src/main/java/org/lflang/target/property/CoordinationModeProperty.java @@ -26,7 +26,7 @@ public CoordinationMode initialValue() { } @Override - public CoordinationMode parse(Element value) { + public CoordinationMode fromAstElement(Element value) { return (CoordinationMode) UnionType.COORDINATION_UNION.forName(ASTUtils.elementToSingleString(value)); } @@ -39,7 +39,7 @@ public List supportedTargets() { public void validate(KeyValuePair pair, Model ast, TargetConfig config, ValidationReporter reporter) {} @Override - public Element export() { + public Element toAstElement() { return ASTUtils.toElement(this.value.toString()); } 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 a61e54831b..2844e4e0f2 100644 --- a/core/src/main/java/org/lflang/target/property/CoordinationOptionsProperty.java +++ b/core/src/main/java/org/lflang/target/property/CoordinationOptionsProperty.java @@ -30,7 +30,7 @@ public CoordinationOptions initialValue() { } @Override - public CoordinationOptions parse(Element value) { + public CoordinationOptions fromAstElement(Element value) { var options = new CoordinationOptions(); for (KeyValuePair entry : value.getKeyvalue().getPairs()) { CoordinationOption option = @@ -53,7 +53,7 @@ public List supportedTargets() { } @Override - public Element export() { + public Element toAstElement() { Element e = LfFactory.eINSTANCE.createElement(); KeyValuePairs kvp = LfFactory.eINSTANCE.createKeyValuePairs(); for (CoordinationOption opt : CoordinationOption.values()) { diff --git a/core/src/main/java/org/lflang/target/property/DefaultBooleanProperty.java b/core/src/main/java/org/lflang/target/property/DefaultBooleanProperty.java index 088cf71cf4..4e141f624e 100644 --- a/core/src/main/java/org/lflang/target/property/DefaultBooleanProperty.java +++ b/core/src/main/java/org/lflang/target/property/DefaultBooleanProperty.java @@ -1,6 +1,7 @@ package org.lflang.target.property; +import org.lflang.MessageReporter; import org.lflang.TargetPropertyConfig; import org.lflang.ast.ASTUtils; import org.lflang.lf.Element; @@ -19,12 +20,17 @@ public Boolean initialValue() { } @Override - public Boolean parse(Element value) { + public Boolean fromAst(Element value, MessageReporter err) { return ASTUtils.toBoolean(value); } @Override - public Element export() { + protected Boolean fromString(String value, MessageReporter err) { + return Boolean.parseBoolean(value); + } + + @Override + public Element toAstElement() { return ASTUtils.toElement(value); } } diff --git a/core/src/main/java/org/lflang/target/property/DefaultFileListProperty.java b/core/src/main/java/org/lflang/target/property/DefaultFileListProperty.java index 5323c0ac78..a743c5b218 100644 --- a/core/src/main/java/org/lflang/target/property/DefaultFileListProperty.java +++ b/core/src/main/java/org/lflang/target/property/DefaultFileListProperty.java @@ -18,7 +18,7 @@ public DefaultFileListProperty() { @Override public void override(List value) { // FIXME: should this be override or update? - this.setByUser = true; + this.isSet = true; this.value.addAll(value); } @@ -28,12 +28,12 @@ public List initialValue() { } @Override - public List parse(Element value) { + public List fromAstElement(Element value) { return ASTUtils.elementToListOfStrings(value); } @Override - public Element export() { + public Element toAstElement() { return ASTUtils.toElement(value); } } diff --git a/core/src/main/java/org/lflang/target/property/DefaultStringConfig.java b/core/src/main/java/org/lflang/target/property/DefaultStringConfig.java index a4a909ea20..c81efba9d2 100644 --- a/core/src/main/java/org/lflang/target/property/DefaultStringConfig.java +++ b/core/src/main/java/org/lflang/target/property/DefaultStringConfig.java @@ -3,6 +3,7 @@ import java.util.List; +import org.lflang.MessageReporter; import org.lflang.Target; import org.lflang.TargetPropertyConfig; import org.lflang.ast.ASTUtils; @@ -22,12 +23,17 @@ public String initialValue() { } @Override - public String parse(Element value) { + public String fromAst(Element value, MessageReporter err) { return ASTUtils.elementToSingleString(value); } @Override - public Element export() { + protected String fromString(String value, MessageReporter err) { + return value; + } + + @Override + public Element toAstElement() { return ASTUtils.toElement(value); } } diff --git a/core/src/main/java/org/lflang/target/property/DefaultStringListProperty.java b/core/src/main/java/org/lflang/target/property/DefaultStringListProperty.java index 936b724cbd..fcbd5ced73 100644 --- a/core/src/main/java/org/lflang/target/property/DefaultStringListProperty.java +++ b/core/src/main/java/org/lflang/target/property/DefaultStringListProperty.java @@ -4,12 +4,15 @@ import java.util.ArrayList; import java.util.List; +import org.lflang.MessageReporter; import org.lflang.TargetPropertyConfig; import org.lflang.ast.ASTUtils; import org.lflang.lf.Element; import org.lflang.target.property.type.UnionType; - +/** + * Note: {@code set} implements an "append" semantics. + */ public abstract class DefaultStringListProperty extends TargetPropertyConfig> { public DefaultStringListProperty() { @@ -22,12 +25,36 @@ public List initialValue() { } @Override - public List parse(Element value) { + public void set(Element value, MessageReporter err) { + if (!this.isSet) { + super.set(value, err); + } else { + this.value.addAll(this.fromAst(value, err)); + } + } + + @Override + public void set(String string, MessageReporter err) { + if (!this.isSet) { + super.set(string, err); + } else { + this.value.addAll(this.fromString(string, err)); + } + } + + @Override + public List fromAst(Element value, MessageReporter err) { return ASTUtils.elementToListOfStrings(value); } @Override - public Element export() { + protected List fromString(String value, MessageReporter err) { + return List.of(value.split(" ")); + } + + + @Override + public Element toAstElement() { return ASTUtils.toElement(value); } 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 5676584915..c3890c786b 100644 --- a/core/src/main/java/org/lflang/target/property/DockerProperty.java +++ b/core/src/main/java/org/lflang/target/property/DockerProperty.java @@ -46,7 +46,7 @@ public void update(Properties cliArgs) { } @Override - public DockerOptions parse(Element value) { + public DockerOptions fromAstElement(Element value) { var options = new DockerOptions(false); if (value.getLiteral() != null) { if (ASTUtils.toBoolean(value)) { @@ -73,7 +73,7 @@ public List supportedTargets() { } @Override - public Element export() { + public Element toAstElement() { if (!this.value.enabled) { return null; } else if (this.value.equals(new DockerOptions(true))) { diff --git a/core/src/main/java/org/lflang/target/property/ExternalRuntimePathConfig.java b/core/src/main/java/org/lflang/target/property/ExternalRuntimePathConfig.java deleted file mode 100644 index 0e606019a4..0000000000 --- a/core/src/main/java/org/lflang/target/property/ExternalRuntimePathConfig.java +++ /dev/null @@ -1,14 +0,0 @@ -package org.lflang.target.property.type; - -import java.util.List; - -import org.lflang.Target; -import org.lflang.target.property.DefaultStringConfig; - -public class ExternalRuntimePathConfig extends DefaultStringConfig { - - @Override - public List supportedTargets() { - return List.of(Target.CPP); - } -} diff --git a/core/src/main/java/org/lflang/target/property/ExternalRuntimePathProperty.java b/core/src/main/java/org/lflang/target/property/ExternalRuntimePathProperty.java new file mode 100644 index 0000000000..a7e4c7a18c --- /dev/null +++ b/core/src/main/java/org/lflang/target/property/ExternalRuntimePathProperty.java @@ -0,0 +1,13 @@ +package org.lflang.target.property; + +import java.util.List; + +import org.lflang.Target; + +public class ExternalRuntimePathProperty extends DefaultStringConfig { + + @Override + public List supportedTargets() { + return List.of(Target.CPP); + } +} diff --git a/core/src/main/java/org/lflang/target/property/LoggingProperty.java b/core/src/main/java/org/lflang/target/property/LoggingProperty.java index 8a4a1fabc9..50d7420a30 100644 --- a/core/src/main/java/org/lflang/target/property/LoggingProperty.java +++ b/core/src/main/java/org/lflang/target/property/LoggingProperty.java @@ -1,8 +1,8 @@ package org.lflang.target.property; - import java.util.List; +import org.lflang.MessageReporter; import org.lflang.Target; import org.lflang.TargetPropertyConfig; import org.lflang.ast.ASTUtils; @@ -22,8 +22,12 @@ public LogLevel initialValue() { } @Override - protected LogLevel parse(Element value) { - return (LogLevel) UnionType.LOGGING_UNION.forName(ASTUtils.elementToSingleString(value)); + protected LogLevel fromAst(Element value, MessageReporter err) { + return fromString(ASTUtils.elementToSingleString(value), err); + } + + protected LogLevel fromString(String string, MessageReporter err) { + return LogLevel.valueOf(string.toUpperCase()); } @Override @@ -32,7 +36,7 @@ public List supportedTargets() { } @Override - public Element export() { + public Element toAstElement() { return ASTUtils.toElement(value.toString()); } 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 3ef0cf5581..aca5e46c2f 100644 --- a/core/src/main/java/org/lflang/target/property/PlatformProperty.java +++ b/core/src/main/java/org/lflang/target/property/PlatformProperty.java @@ -34,7 +34,7 @@ public PlatformOptions initialValue() { } @Override - public PlatformOptions parse(Element value) { // FIXME: pass in err + public PlatformOptions fromAstElement(Element value) { // FIXME: pass in err var config = new PlatformOptions(); if (value.getLiteral() != null) { config.platform = @@ -120,7 +120,7 @@ public void validate(KeyValuePair pair, Model ast, TargetConfig config, Validati } @Override - public Element export() { + public Element toAstElement() { Element e = LfFactory.eINSTANCE.createElement(); KeyValuePairs kvp = LfFactory.eINSTANCE.createKeyValuePairs(); for (PlatformOption opt : PlatformOption.values()) { 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 f2be54b1ab..4da5a94feb 100644 --- a/core/src/main/java/org/lflang/target/property/Ros2DependenciesProperty.java +++ b/core/src/main/java/org/lflang/target/property/Ros2DependenciesProperty.java @@ -27,7 +27,7 @@ public List initialValue() { } @Override - public List parse(Element value) { + public List fromAstElement(Element value) { return ASTUtils.elementToListOfStrings(value); } @@ -49,7 +49,7 @@ public void validate(KeyValuePair pair, Model ast, TargetConfig config, Validati } @Override - public Element export() { + public Element toAstElement() { return ASTUtils.toElement(value); } diff --git a/core/src/main/java/org/lflang/target/property/RustIncludeProperty.java b/core/src/main/java/org/lflang/target/property/RustIncludeProperty.java index d95fa2a68d..5bb31617bd 100644 --- a/core/src/main/java/org/lflang/target/property/RustIncludeProperty.java +++ b/core/src/main/java/org/lflang/target/property/RustIncludeProperty.java @@ -35,7 +35,7 @@ public List initialValue() { } @Override - public List parse(Element value) { + public List fromAstElement(Element value) { Path referencePath; try { referencePath = FileUtil.toPath(value.eResource().getURI()).toAbsolutePath(); @@ -61,7 +61,7 @@ public List parse(Element value) { } @Override - public Element export() { + public Element toAstElement() { // do not check paths here, and simply copy the absolute path over List paths = this.value; if (paths.isEmpty()) { 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 5a81e4486c..99000267d0 100644 --- a/core/src/main/java/org/lflang/target/property/SchedulerProperty.java +++ b/core/src/main/java/org/lflang/target/property/SchedulerProperty.java @@ -44,7 +44,7 @@ public void update(Properties cliArgs) { } @Override - public SchedulerOption parse(Element value) { + public SchedulerOption fromAstElement(Element value) { var scheduler = (SchedulerOption) UnionType.SCHEDULER_UNION.forName(ASTUtils.elementToSingleString(value)); if (scheduler != null) { @@ -60,7 +60,7 @@ public List supportedTargets() { } @Override - public Element export() { + public Element toAstElement() { return ASTUtils.toElement(this.value.toString()); } diff --git a/core/src/main/java/org/lflang/target/property/TimeOutProperty.java b/core/src/main/java/org/lflang/target/property/TimeOutProperty.java index da84484ea2..7ef3947727 100644 --- a/core/src/main/java/org/lflang/target/property/TimeOutProperty.java +++ b/core/src/main/java/org/lflang/target/property/TimeOutProperty.java @@ -23,7 +23,7 @@ public TimeValue initialValue() { } @Override - public TimeValue parse(Element value) { + public TimeValue fromAstElement(Element value) { return ASTUtils.toTimeValue(value); } @@ -33,7 +33,7 @@ public List supportedTargets() { } @Override - public Element export() { + public Element toAstElement() { return ASTUtils.toElement(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 9484b380d3..cfdb4ad024 100644 --- a/core/src/main/java/org/lflang/target/property/TracingProperty.java +++ b/core/src/main/java/org/lflang/target/property/TracingProperty.java @@ -45,7 +45,7 @@ public void update(Properties cliArgs) { } @Override - public TracingOptions parse(Element value) { + public TracingOptions fromAstElement(Element value) { var options = new TracingOptions(false); if (value.getLiteral() != null) { if (!ASTUtils.toBoolean(value)) { @@ -74,7 +74,7 @@ public List supportedTargets() { @Override public void validate(KeyValuePair pair, Model ast, TargetConfig config, ValidationReporter reporter) { - if (pair != null && this.parse(pair.getValue()) != null) { + if (pair != null && this.fromAstElement(pair.getValue()) != null) { // If tracing is anything but "false" and threading is off, error. var threading = TargetProperty.getKeyValuePair(ast, TargetProperty.THREADING); if (threading != null) { @@ -93,7 +93,7 @@ public void validate(KeyValuePair pair, Model ast, TargetConfig config, Validati } @Override - public Element export() { + public Element toAstElement() { if (!this.value.isEnabled()) { return null; } else if (this.value.equals(new TracingOptions(true))) { 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 a28a5a9ec0..8b4a77a931 100644 --- a/core/src/main/java/org/lflang/target/property/WorkersProperty.java +++ b/core/src/main/java/org/lflang/target/property/WorkersProperty.java @@ -2,6 +2,7 @@ import java.util.List; +import org.lflang.MessageReporter; import org.lflang.Target; import org.lflang.TargetPropertyConfig; import org.lflang.ast.ASTUtils; @@ -20,7 +21,12 @@ public Integer initialValue() { } @Override - protected Integer parse(Element value) { + protected Integer fromString(String value, MessageReporter err) { + return Integer.parseInt(value); // FIXME: check for exception + } + + @Override + protected Integer fromAst(Element value, MessageReporter err) { return ASTUtils.toInteger(value); } @@ -30,7 +36,7 @@ public List supportedTargets() { } @Override - public Element export() { + public Element toAstElement() { return ASTUtils.toElement(value); } diff --git a/core/src/main/kotlin/org/lflang/generator/cpp/CppGenerator.kt b/core/src/main/kotlin/org/lflang/generator/cpp/CppGenerator.kt index e4041e4a41..55aaeebd8b 100644 --- a/core/src/main/kotlin/org/lflang/generator/cpp/CppGenerator.kt +++ b/core/src/main/kotlin/org/lflang/generator/cpp/CppGenerator.kt @@ -133,8 +133,8 @@ class CppGenerator( true) // copy or download reactor-cpp - if (!targetConfig.externalRuntimePath.isSetByUser) { - if (targetConfig.runtimeVersion.isSetByUser) { + if (!targetConfig.externalRuntimePath.isSet) { + if (targetConfig.runtimeVersion.isSet) { fetchReactorCpp(targetConfig.runtimeVersion.get()) } else { FileUtil.copyFromClassPath( diff --git a/core/src/main/kotlin/org/lflang/generator/cpp/CppStandaloneCmakeGenerator.kt b/core/src/main/kotlin/org/lflang/generator/cpp/CppStandaloneCmakeGenerator.kt index 732536e2af..61e3375c36 100644 --- a/core/src/main/kotlin/org/lflang/generator/cpp/CppStandaloneCmakeGenerator.kt +++ b/core/src/main/kotlin/org/lflang/generator/cpp/CppStandaloneCmakeGenerator.kt @@ -136,9 +136,9 @@ class CppStandaloneCmakeGenerator(private val targetConfig: TargetConfig, privat val includeFiles = targetConfig.cmakeIncludes.get()?.map { fileConfig.srcPath.resolve(it).toUnixString() } val reactorCppTarget = when { - targetConfig.externalRuntimePath.isSetByUser -> "reactor-cpp" - targetConfig.runtimeVersion.isSetByUser -> "reactor-cpp-${targetConfig.runtimeVersion}" - else -> "reactor-cpp-default" + targetConfig.externalRuntimePath.isSet -> "reactor-cpp" + targetConfig.runtimeVersion.isSet -> "reactor-cpp-${targetConfig.runtimeVersion}" + else -> "reactor-cpp-default" } return with(PrependOperator) { From 159b94ad65de568c129381b83592b321d073ad36 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Wed, 27 Sep 2023 21:02:57 -0700 Subject: [PATCH 007/145] Various fixes --- .../lflang/cli/StandaloneMessageReporter.java | 6 +- cli/lfc/src/main/java/org/lflang/cli/Lfc.java | 2 +- .../org/lflang/tests/runtime/CppRos2Test.java | 2 +- .../org/lflang/DefaultMessageReporter.java | 4 +- .../main/java/org/lflang/MessageReporter.java | 6 +- .../java/org/lflang/MessageReporterBase.java | 13 +- .../main/java/org/lflang/TargetConfig.java | 41 +- .../main/java/org/lflang/TargetProperty.java | 737 ++++++++++-------- .../java/org/lflang/TargetPropertyConfig.java | 59 +- .../org/lflang/analyses/statespace/Event.java | 4 +- .../statespace/StateSpaceExplorer.java | 43 +- .../main/java/org/lflang/ast/ASTUtils.java | 6 +- .../util/SynthesisMessageReporter.java | 4 +- .../federated/extensions/CExtension.java | 8 +- .../federated/extensions/CExtensionUtils.java | 64 +- .../federated/generator/FedGenerator.java | 3 +- .../LineAdjustingMessageReporter.java | 10 +- .../SynchronizedMessageReporter.java | 3 +- .../FedROS2CPPSerialization.java | 2 +- .../org/lflang/generator/GeneratorBase.java | 5 +- .../org/lflang/generator/GeneratorUtils.java | 6 +- .../LanguageServerMessageReporter.java | 4 +- .../lflang/generator/c/CCmakeGenerator.java | 10 +- .../org/lflang/generator/c/CCompiler.java | 9 +- .../c/CEnvironmentFunctionGenerator.java | 3 +- .../org/lflang/generator/c/CGenerator.java | 60 +- .../generator/c/CPreambleGenerator.java | 6 +- .../generator/c/CTriggerObjectsGenerator.java | 2 +- .../generator/python/PythonGenerator.java | 5 +- .../generator/rust/CargoDependencySpec.java | 7 +- .../generator/rust/RustTargetConfig.java | 2 - .../lflang/target/property/AuthProperty.java | 10 +- .../property/BuildCommandsProperty.java | 55 +- .../lflang/target/property/BuildConfig.java | 46 +- .../target/property/BuildTypeProperty.java | 65 +- .../property/CargoDependenciesProperty.java | 85 +- .../property/CargoFeaturesProperty.java | 10 +- .../property/ClockSyncModeProperty.java | 127 ++- .../property/ClockSyncOptionsProperty.java | 248 +++--- .../target/property/CmakeIncludeProperty.java | 83 +- .../property/CompileDefinitionsConfig.java | 38 - .../property/CompileDefinitionsProperty.java | 44 ++ .../property/CompilerFlagsProperty.java | 10 +- .../target/property/CompilerProperty.java | 12 + .../property/CoordinationModeProperty.java | 80 +- .../property/CoordinationOptionsProperty.java | 170 ++-- .../property/DefaultBooleanProperty.java | 48 +- .../property/DefaultFileListProperty.java | 58 +- .../target/property/DefaultStringConfig.java | 51 +- .../property/DefaultStringListProperty.java | 86 +- .../target/property/DockerProperty.java | 237 +++--- .../ExportDependencyGraphProperty.java | 10 +- .../target/property/ExportToYamlProperty.java | 10 +- .../property/ExternalRuntimePathProperty.java | 9 +- .../lflang/target/property/FastProperty.java | 66 +- .../target/property/FedSetupProperty.java | 42 + .../lflang/target/property/FilesProperty.java | 10 +- .../target/property/KeepaliveProperty.java | 48 +- .../target/property/LoggingProperty.java | 90 ++- .../target/property/NoCompileProperty.java | 10 +- .../property/NoRuntimeValidationProperty.java | 10 +- .../target/property/PlatformProperty.java | 441 +++++------ .../property/PrintStatisticsProperty.java | 10 +- .../target/property/ProtobufsProperty.java | 10 +- .../property/Ros2DependenciesProperty.java | 75 +- .../lflang/target/property/Ros2Property.java | 10 +- .../property/RuntimeVersionProperty.java | 9 +- .../target/property/RustIncludeProperty.java | 140 ++-- .../target/property/SchedulerProperty.java | 226 +++--- .../property/SingleFileProjectProperty.java | 10 +- .../target/property/ThreadingProperty.java | 18 +- .../target/property/TimeOutProperty.java | 55 +- .../target/property/TracingProperty.java | 278 ++++--- .../target/property/VerifyProperty.java | 10 +- .../target/property/WorkersProperty.java | 58 +- .../target/property/type/ArrayType.java | 96 ++- .../target/property/type/CompilerConfig.java | 14 - .../target/property/type/DictionaryType.java | 127 ++- .../target/property/type/PrimitiveType.java | 153 ++-- .../property/type/StringDictionaryType.java | 47 +- .../property/type/TargetPropertyType.java | 43 +- .../target/property/type/UnionType.java | 203 +++-- .../org/lflang/validation/LFValidator.java | 73 +- .../lflang/validation/ValidationReporter.java | 11 - .../validation/ValidatorMessageReporter.java | 13 +- .../org/lflang/generator/cpp/CppExtensions.kt | 14 +- .../org/lflang/generator/cpp/CppGenerator.kt | 4 +- .../generator/cpp/CppPlatformGenerator.kt | 2 +- .../generator/cpp/CppRos2NodeGenerator.kt | 2 +- .../generator/cpp/CppStandaloneGenerator.kt | 2 +- .../cpp/CppStandaloneMainGenerator.kt | 10 +- .../lflang/generator/rust/RustGenerator.kt | 8 +- .../org/lflang/generator/rust/RustModel.kt | 26 +- .../org/lflang/generator/ts/TSGenerator.kt | 14 +- .../ts/TSParameterPreambleGenerator.kt | 5 +- .../compiler/LinguaFrancaValidationTest.java | 41 +- .../java/org/lflang/tests/Configurators.java | 9 +- 97 files changed, 2613 insertions(+), 2658 deletions(-) delete mode 100644 core/src/main/java/org/lflang/target/property/CompileDefinitionsConfig.java create mode 100644 core/src/main/java/org/lflang/target/property/CompileDefinitionsProperty.java create mode 100644 core/src/main/java/org/lflang/target/property/CompilerProperty.java create mode 100644 core/src/main/java/org/lflang/target/property/FedSetupProperty.java delete mode 100644 core/src/main/java/org/lflang/target/property/type/CompilerConfig.java delete mode 100644 core/src/main/java/org/lflang/validation/ValidationReporter.java diff --git a/cli/base/src/main/java/org/lflang/cli/StandaloneMessageReporter.java b/cli/base/src/main/java/org/lflang/cli/StandaloneMessageReporter.java index 1ecffbdedb..91eed67715 100644 --- a/cli/base/src/main/java/org/lflang/cli/StandaloneMessageReporter.java +++ b/cli/base/src/main/java/org/lflang/cli/StandaloneMessageReporter.java @@ -30,6 +30,7 @@ import com.google.inject.Inject; import java.nio.file.Path; import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.EStructuralFeature; import org.eclipse.lsp4j.DiagnosticSeverity; import org.eclipse.xtext.diagnostics.Severity; import org.lflang.MessageReporterBase; @@ -52,8 +53,9 @@ static Severity convertSeverity(DiagnosticSeverity severity) { } @Override - protected void reportOnNode(EObject node, DiagnosticSeverity severity, String message) { - issueAcceptor.accept(convertSeverity(severity), message, node, null, 0, null); + protected void reportOnNode( + EObject node, EStructuralFeature feature, DiagnosticSeverity severity, String message) { + issueAcceptor.accept(convertSeverity(severity), message, node, feature, 0, null); } @Override 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 82b1979c16..66130238d3 100644 --- a/cli/lfc/src/main/java/org/lflang/cli/Lfc.java +++ b/cli/lfc/src/main/java/org/lflang/cli/Lfc.java @@ -10,11 +10,11 @@ import org.eclipse.xtext.generator.JavaIoFileSystemAccess; import org.eclipse.xtext.util.CancelIndicator; import org.lflang.FileConfig; -import org.lflang.target.property.type.UnionType; import org.lflang.ast.ASTUtils; import org.lflang.generator.LFGeneratorContext; import org.lflang.generator.LFGeneratorContext.BuildParm; import org.lflang.generator.MainContext; +import org.lflang.target.property.type.UnionType; import picocli.CommandLine.Command; import picocli.CommandLine.Option; diff --git a/core/src/integrationTest/java/org/lflang/tests/runtime/CppRos2Test.java b/core/src/integrationTest/java/org/lflang/tests/runtime/CppRos2Test.java index 4b0dc28cec..a0ad550577 100644 --- a/core/src/integrationTest/java/org/lflang/tests/runtime/CppRos2Test.java +++ b/core/src/integrationTest/java/org/lflang/tests/runtime/CppRos2Test.java @@ -30,7 +30,7 @@ public void runWithRos2() { Message.DESC_ROS2, it -> true, it -> { - it.getContext().getTargetConfig().ros2 = true; + it.getContext().getTargetConfig().ros2.override(true); return true; }, TestLevel.EXECUTION, diff --git a/core/src/main/java/org/lflang/DefaultMessageReporter.java b/core/src/main/java/org/lflang/DefaultMessageReporter.java index 9ea3ede28a..0f83571e60 100644 --- a/core/src/main/java/org/lflang/DefaultMessageReporter.java +++ b/core/src/main/java/org/lflang/DefaultMessageReporter.java @@ -2,6 +2,7 @@ import java.nio.file.Path; import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.EStructuralFeature; import org.eclipse.lsp4j.DiagnosticSeverity; import org.lflang.generator.Range; @@ -18,7 +19,8 @@ protected void report(Path path, Range range, DiagnosticSeverity severity, Strin } @Override - protected void reportOnNode(EObject node, DiagnosticSeverity severity, String message) { + protected void reportOnNode( + EObject node, EStructuralFeature feature, DiagnosticSeverity severity, String message) { reportWithoutPosition(severity, message); } diff --git a/core/src/main/java/org/lflang/MessageReporter.java b/core/src/main/java/org/lflang/MessageReporter.java index 949c708592..16148c059a 100644 --- a/core/src/main/java/org/lflang/MessageReporter.java +++ b/core/src/main/java/org/lflang/MessageReporter.java @@ -2,6 +2,7 @@ import java.nio.file.Path; import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.EStructuralFeature; import org.eclipse.lsp4j.DiagnosticSeverity; import org.lflang.generator.Position; import org.lflang.generator.Range; @@ -31,7 +32,10 @@ public interface MessageReporter { Stage2 at(Path file, Range range); /** Position the message on the given node (must be non-null). */ - Stage2 at(EObject object); + Stage2 at(EObject node); + + /** Position the message on the given node and structural feature (both must be non-null). */ + Stage2 at(EObject node, EStructuralFeature feature); /** * Position the message in the file (non-null), at an unknown line. Implementations usually will diff --git a/core/src/main/java/org/lflang/MessageReporterBase.java b/core/src/main/java/org/lflang/MessageReporterBase.java index 0ee7b0286e..b195a80319 100644 --- a/core/src/main/java/org/lflang/MessageReporterBase.java +++ b/core/src/main/java/org/lflang/MessageReporterBase.java @@ -2,6 +2,7 @@ import java.nio.file.Path; import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.EStructuralFeature; import org.eclipse.lsp4j.DiagnosticSeverity; import org.lflang.generator.Range; @@ -42,6 +43,11 @@ public Stage2 at(EObject node) { return wrap((severity, message) -> reportOnNode(node, severity, message)); } + @Override + public Stage2 at(EObject node, EStructuralFeature feature) { + return null; + } + @Override public Stage2 nowhere() { return wrap(this::reportWithoutPosition); @@ -55,7 +61,12 @@ protected abstract void report( Path path, Range range, DiagnosticSeverity severity, String message); /** Implementation of the reporting methods that use a node as position. */ - protected abstract void reportOnNode(EObject node, DiagnosticSeverity severity, String message); + protected void reportOnNode(EObject node, DiagnosticSeverity severity, String message) { + reportOnNode(node, null, severity, message); + } + + protected abstract void reportOnNode( + EObject node, EStructuralFeature feature, DiagnosticSeverity severity, String message); /** Implementation of the reporting methods for {@link #nowhere()}. */ protected abstract void reportWithoutPosition(DiagnosticSeverity severity, String message); diff --git a/core/src/main/java/org/lflang/TargetConfig.java b/core/src/main/java/org/lflang/TargetConfig.java index 72d3077ad3..06fa8008b0 100644 --- a/core/src/main/java/org/lflang/TargetConfig.java +++ b/core/src/main/java/org/lflang/TargetConfig.java @@ -25,47 +25,45 @@ package org.lflang; import java.util.ArrayList; - import java.util.List; import java.util.Properties; - import org.lflang.generator.rust.RustTargetConfig; import org.lflang.lf.KeyValuePair; import org.lflang.lf.TargetDecl; import org.lflang.target.property.AuthProperty; +import org.lflang.target.property.BuildCommandsProperty; +import org.lflang.target.property.BuildTypeProperty; import org.lflang.target.property.ClockSyncModeProperty; +import org.lflang.target.property.ClockSyncOptionsProperty; +import org.lflang.target.property.CmakeIncludeProperty; +import org.lflang.target.property.CompileDefinitionsProperty; +import org.lflang.target.property.CompilerFlagsProperty; +import org.lflang.target.property.CompilerProperty; import org.lflang.target.property.CoordinationModeProperty; import org.lflang.target.property.CoordinationOptionsProperty; import org.lflang.target.property.DockerProperty; +import org.lflang.target.property.ExportDependencyGraphProperty; +import org.lflang.target.property.ExportToYamlProperty; +import org.lflang.target.property.ExternalRuntimePathProperty; import org.lflang.target.property.FastProperty; import org.lflang.target.property.FedSetupProperty; +import org.lflang.target.property.FilesProperty; import org.lflang.target.property.KeepaliveProperty; -import org.lflang.target.property.PlatformProperty; -import org.lflang.target.property.Ros2DependenciesProperty; -import org.lflang.target.property.SchedulerProperty; import org.lflang.target.property.LoggingProperty; -import org.lflang.target.property.TracingProperty; -import org.lflang.target.property.BuildCommandsProperty; -import org.lflang.target.property.ClockSyncOptionsProperty; -import org.lflang.target.property.BuildTypeProperty; -import org.lflang.target.property.CompilerFlagsProperty; -import org.lflang.target.property.ExportDependencyGraphProperty; -import org.lflang.target.property.ExportToYamlProperty; -import org.lflang.target.property.FilesProperty; import org.lflang.target.property.NoCompileProperty; import org.lflang.target.property.NoRuntimeValidationProperty; +import org.lflang.target.property.PlatformProperty; import org.lflang.target.property.PrintStatisticsProperty; import org.lflang.target.property.ProtobufsProperty; +import org.lflang.target.property.Ros2DependenciesProperty; import org.lflang.target.property.Ros2Property; import org.lflang.target.property.RuntimeVersionProperty; +import org.lflang.target.property.SchedulerProperty; import org.lflang.target.property.SingleFileProjectProperty; import org.lflang.target.property.ThreadingProperty; import org.lflang.target.property.TimeOutProperty; +import org.lflang.target.property.TracingProperty; import org.lflang.target.property.WorkersProperty; -import org.lflang.target.property.CmakeIncludeProperty; -import org.lflang.target.property.type.CompileDefinitionsConfig; -import org.lflang.target.property.type.CompilerConfig; -import org.lflang.target.property.ExternalRuntimePathProperty; import org.lflang.target.property.type.VerifyProperty; /** @@ -107,7 +105,6 @@ public TargetConfig(Properties cliArgs, TargetDecl target, MessageReporter messa if (cliArgs != null) { TargetProperty.load(this, cliArgs, messageReporter); } - } /** @@ -132,7 +129,7 @@ public TargetConfig(Properties cliArgs, TargetDecl target, MessageReporter messa public CmakeIncludeProperty cmakeIncludes = new CmakeIncludeProperty(); /** The compiler to invoke, unless a build command has been specified. */ - public CompilerConfig compiler = new CompilerConfig(); + public CompilerProperty compiler = new CompilerProperty(); /** Additional sources to add to the compile command if appropriate. */ public List compileAdditionalSources = new ArrayList<>(); @@ -143,7 +140,7 @@ public TargetConfig(Properties cliArgs, TargetDecl target, MessageReporter messa *

The first string is the definition itself, and the second string is the value to attribute * to that definition, if any. The second value could be left empty. */ - public CompileDefinitionsConfig compileDefinitions = new CompileDefinitionsConfig(); + public CompileDefinitionsProperty compileDefinitions = new CompileDefinitionsProperty(); /** Flags to pass to the compiler, unless a build command has been specified. */ public CompilerFlagsProperty compilerFlags = new CompilerFlagsProperty(); @@ -259,10 +256,8 @@ public TargetConfig(Properties cliArgs, TargetDecl target, MessageReporter messa public ExportToYamlProperty exportToYaml = new ExportToYamlProperty(); /** Rust-specific configuration. */ - public final RustTargetConfig rust = - new RustTargetConfig(); // FIXME: https://issue.lf-lang.org/1558 + public final RustTargetConfig rust = new RustTargetConfig(); /** Path to a C file used by the Python target to setup federated execution. */ public FedSetupProperty fedSetupPreamble = new FedSetupProperty(); - } diff --git a/core/src/main/java/org/lflang/TargetProperty.java b/core/src/main/java/org/lflang/TargetProperty.java index c5d1b2d11c..005405bc49 100644 --- a/core/src/main/java/org/lflang/TargetProperty.java +++ b/core/src/main/java/org/lflang/TargetProperty.java @@ -32,7 +32,6 @@ import java.util.Objects; import java.util.Properties; import java.util.stream.Collectors; - import org.lflang.ast.ASTUtils; import org.lflang.generator.InvalidLfSourceException; import org.lflang.lf.KeyValuePair; @@ -40,8 +39,45 @@ import org.lflang.lf.LfFactory; import org.lflang.lf.Model; import org.lflang.lf.TargetDecl; +import org.lflang.target.property.AuthProperty; +import org.lflang.target.property.BuildCommandsProperty; +import org.lflang.target.property.BuildTypeProperty; +import org.lflang.target.property.CargoDependenciesProperty; +import org.lflang.target.property.CargoFeaturesProperty; +import org.lflang.target.property.ClockSyncModeProperty; +import org.lflang.target.property.ClockSyncOptionsProperty; +import org.lflang.target.property.CmakeIncludeProperty; +import org.lflang.target.property.CompileDefinitionsProperty; +import org.lflang.target.property.CompilerFlagsProperty; +import org.lflang.target.property.CompilerProperty; +import org.lflang.target.property.CoordinationModeProperty; +import org.lflang.target.property.CoordinationOptionsProperty; +import org.lflang.target.property.DockerProperty; +import org.lflang.target.property.ExportDependencyGraphProperty; +import org.lflang.target.property.ExportToYamlProperty; +import org.lflang.target.property.ExternalRuntimePathProperty; +import org.lflang.target.property.FastProperty; +import org.lflang.target.property.FedSetupProperty; +import org.lflang.target.property.FilesProperty; +import org.lflang.target.property.KeepaliveProperty; +import org.lflang.target.property.LoggingProperty; +import org.lflang.target.property.NoCompileProperty; +import org.lflang.target.property.NoRuntimeValidationProperty; +import org.lflang.target.property.PlatformProperty; +import org.lflang.target.property.PrintStatisticsProperty; +import org.lflang.target.property.ProtobufsProperty; +import org.lflang.target.property.Ros2DependenciesProperty; +import org.lflang.target.property.RuntimeVersionProperty; +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.TimeOutProperty; +import org.lflang.target.property.TracingProperty; +import org.lflang.target.property.WorkersProperty; import org.lflang.target.property.type.TargetPropertyType; -import org.lflang.validation.ValidationReporter; +import org.lflang.target.property.type.VerifyProperty; +import org.lflang.validation.ValidatorMessageReporter; /** * A target properties along with a type and a list of supporting targets that supports it, as well @@ -51,351 +87,372 @@ */ public enum TargetProperty { - /** Directive to allow including OpenSSL libraries and process HMAC authentication. */ - AUTH(config -> config.auth), - /** Directive to let the generator use the custom build command. */ - BUILD(config -> config.buildCommands), - - /** - * Directive to specify the target build type such as 'Release' or 'Debug'. This is also used in - * the Rust target to select a Cargo profile. - */ - BUILD_TYPE(config -> config.buildType), - - /** Directive to let the federate execution handle clock synchronization in software. */ - CLOCK_SYNC(config -> config.clockSync), - /** Key-value pairs giving options for clock synchronization. */ - CLOCK_SYNC_OPTIONS(config -> config.clockSyncOptions), - - /** - * Directive to specify a cmake to be included by the generated build systems. - * - *

This gives full control over the C/C++ build as any cmake parameters can be adjusted in - * the - * included file. - */ - CMAKE_INCLUDE(config -> config.cmakeIncludes), - /** Directive to specify the target compiler. */ - COMPILER(config -> config.compiler), - /** Directive to specify compile-time definitions. */ - COMPILE_DEFINITIONS(config -> config.compileDefinitions), - - /** Directive to specify the coordination mode */ - COORDINATION(config -> config.coordination), - /** Key-value pairs giving options for clock synchronization. */ - COORDINATION_OPTIONS(config -> config.coordinationOptions), - /** - * Directive to generate a Dockerfile. This is either a boolean, true or false, or a dictionary of - * options. - */ - DOCKER(config -> config.dockerOptions), - /** Directive for specifying a path to an external runtime to be used for the compiled binary. */ - EXTERNAL_RUNTIME_PATH(config -> config.externalRuntimePath), - /** - * Directive to let the execution engine allow logical time to elapse faster than physical time. - */ - FAST(config -> config.fastMode), - /** - * Directive to stage particular files on the class path to be processed by the code generator. - */ - FILES(config -> config.files), - - /** Flags to be passed on to the target compiler. */ - FLAGS(config -> config.compilerFlags), - - /** - * Directive to let the execution engine remain active also if there are no more events in the - * event queue. - */ - KEEPALIVE(config -> config.keepalive), - - /** Directive to specify the grain at which to report log messages during execution. */ - LOGGING(config -> config.logLevel), - - /** Directive to not invoke the target compiler. */ - NO_COMPILE(config -> config.noCompile), - - /** Directive to disable validation of reactor rules at runtime. */ - NO_RUNTIME_VALIDATION(config -> config.noRuntimeValidation), - - /** - * Directive to specify the platform for cross code generation. This is either a string of the - * platform or a dictionary of options that includes the string name. - */ - PLATFORM((TargetConfig config) -> config.platformOptions), - - /** Directive to instruct the runtime to collect and print execution statistics. */ - PRINT_STATISTICS(config -> config.printStatistics), - - /** - * Directive for specifying .proto files that need to be compiled and their code included in the - * sources. - */ - PROTOBUFS(config -> config.protoFiles), - - /** Directive to specify that ROS2 specific code is generated, */ - ROS2(config -> config.ros2), - - /** Directive to specify additional ROS2 packages that this LF program depends on. */ - ROS2_DEPENDENCIES((TargetConfig config) -> config.ros2Dependencies), - - /** Directive for specifying a specific version of the reactor runtime library. */ - RUNTIME_VERSION(config -> config.runtimeVersion), - - /** Directive for specifying a specific runtime scheduler, if supported. */ - SCHEDULER((TargetConfig config) -> config.schedulerType), - /** Directive to specify that all code is generated in a single file. */ - SINGLE_FILE_PROJECT(config -> config.singleFileProject), - - /** Directive to indicate whether the runtime should use multi-threading. */ - THREADING(config -> config.threading), - /** Directive to check the generated verification model. */ - VERIFY(config -> config.verify), - - /** Directive to specify the number of worker threads used by the runtime. */ - WORKERS(config -> config.workers), - - /** Directive to specify the execution timeout. */ - TIMEOUT(config -> config.timeout), - - /** Directive to enable tracing. */ - TRACING(config -> config.tracing), - - /** - * Directive to let the runtime export its internal dependency graph. - * - *

This is a debugging feature and currently only used for C++ and Rust programs. - */ - EXPORT_DEPENDENCY_GRAPH(config -> config.exportDependencyGraph), - - /** - * Directive to let the runtime export the program structure to a yaml file. - * - *

This is a debugging feature and currently only used for C++ programs. - */ - EXPORT_TO_YAML(config -> config.exportToYaml), - - /** - * List of module files to link into the crate as top-level. For instance, a - * {@code target Rust { - * rust-modules: [ "foo.rs" ] }} will cause the file to be copied into the generated project, - * and - * the generated {@code main.rs} will include it with a {@code mod foo;}. If one of the paths is - * a - * directory, it must contain a {@code mod.rs} file, and all its contents are copied. - */ - RUST_INCLUDE(config -> config.rust.rustTopLevelModules), - - /** Directive for specifying Cargo features of the generated program to enable. */ - CARGO_FEATURES(config -> config.rust.cargoFeatures), - - /** - * Dependency specifications for Cargo. This property looks like this: - * - *

{@code
-     * cargo-dependencies: {
-     *    // Name-of-the-crate: "version"
-     *    rand: "0.8",
-     *    // Equivalent to using an explicit map:
-     *    rand: {
-     *      version: "0.8"
-     *    },
-     *    // The map allows specifying more details
-     *    rand: {
-     *      // A path to a local unpublished crate.
-     *      // Note 'path' is mutually exclusive with 'version'.
-     *      path: "/home/me/Git/local-rand-clone"
-     *    },
-     *    rand: {
-     *      version: "0.8",
-     *      // you can specify cargo features
-     *      features: ["some-cargo-feature",]
-     *    }
-     * }
-     * }
- */ - CARGO_DEPENDENCIES(config -> config.rust.cargoDependencies), - - /** - * Directs the C or Python target to include the associated C file used for setting up federated - * execution before processing the first tag. - */ - FED_SETUP(config -> config.fedSetupPreamble); - - public final ConfigLoader property; - - @FunctionalInterface - private interface ConfigLoader { - TargetPropertyConfig of(TargetConfig config); - } - - TargetProperty(ConfigLoader property) { - this.property = property; + /** Directive to allow including OpenSSL libraries and process HMAC authentication. */ + AUTH(AuthProperty.class, config -> config.auth), + /** Directive to let the generator use the custom build command. */ + BUILD(BuildCommandsProperty.class, config -> config.buildCommands), + + /** + * Directive to specify the target build type such as 'Release' or 'Debug'. This is also used in + * the Rust target to select a Cargo profile. + */ + BUILD_TYPE(BuildTypeProperty.class, config -> config.buildType), + + /** Directive to let the federate execution handle clock synchronization in software. */ + CLOCK_SYNC(ClockSyncModeProperty.class, config -> config.clockSync), + /** Key-value pairs giving options for clock synchronization. */ + CLOCK_SYNC_OPTIONS(ClockSyncOptionsProperty.class, config -> config.clockSyncOptions), + + /** + * Directive to specify a cmake to be included by the generated build systems. + * + *

This gives full control over the C/C++ build as any cmake parameters can be adjusted in the + * included file. + */ + CMAKE_INCLUDE(CmakeIncludeProperty.class, config -> config.cmakeIncludes), + /** Directive to specify the target compiler. */ + COMPILER(CompilerProperty.class, config -> config.compiler), + /** Directive to specify compile-time definitions. */ + COMPILE_DEFINITIONS(CompileDefinitionsProperty.class, config -> config.compileDefinitions), + + /** Directive to specify the coordination mode */ + COORDINATION(CoordinationModeProperty.class, config -> config.coordination), + /** Key-value pairs giving options for clock synchronization. */ + COORDINATION_OPTIONS(CoordinationOptionsProperty.class, config -> config.coordinationOptions), + /** + * Directive to generate a Dockerfile. This is either a boolean, true or false, or a dictionary of + * options. + */ + DOCKER(DockerProperty.class, config -> config.dockerOptions), + /** Directive for specifying a path to an external runtime to be used for the compiled binary. */ + EXTERNAL_RUNTIME_PATH(ExternalRuntimePathProperty.class, config -> config.externalRuntimePath), + /** + * Directive to let the execution engine allow logical time to elapse faster than physical time. + */ + FAST(FastProperty.class, config -> config.fastMode), + /** + * Directive to stage particular files on the class path to be processed by the code generator. + */ + FILES(FilesProperty.class, config -> config.files), + + /** Flags to be passed on to the target compiler. */ + FLAGS(CompilerFlagsProperty.class, config -> config.compilerFlags), + + /** + * Directive to let the execution engine remain active also if there are no more events in the + * event queue. + */ + KEEPALIVE(KeepaliveProperty.class, config -> config.keepalive), + + /** Directive to specify the grain at which to report log messages during execution. */ + LOGGING(LoggingProperty.class, config -> config.logLevel), + + /** Directive to not invoke the target compiler. */ + NO_COMPILE(NoCompileProperty.class, config -> config.noCompile), + + /** Directive to disable validation of reactor rules at runtime. */ + NO_RUNTIME_VALIDATION(NoRuntimeValidationProperty.class, config -> config.noRuntimeValidation), + + /** + * Directive to specify the platform for cross code generation. This is either a string of the + * platform or a dictionary of options that includes the string name. + */ + PLATFORM(PlatformProperty.class, config -> config.platformOptions), + + /** Directive to instruct the runtime to collect and print execution statistics. */ + PRINT_STATISTICS(PrintStatisticsProperty.class, config -> config.printStatistics), + + /** + * Directive for specifying .proto files that need to be compiled and their code included in the + * sources. + */ + PROTOBUFS(ProtobufsProperty.class, config -> config.protoFiles), + + /** Directive to specify that ROS2 specific code is generated, */ + ROS2(Ros2DependenciesProperty.class, config -> config.ros2), + + /** Directive to specify additional ROS2 packages that this LF program depends on. */ + ROS2_DEPENDENCIES(Ros2DependenciesProperty.class, config -> config.ros2Dependencies), + + /** Directive for specifying a specific version of the reactor runtime library. */ + RUNTIME_VERSION(RuntimeVersionProperty.class, config -> config.runtimeVersion), + + /** Directive for specifying a specific runtime scheduler, if supported. */ + SCHEDULER(SchedulerProperty.class, config -> config.schedulerType), + /** Directive to specify that all code is generated in a single file. */ + SINGLE_FILE_PROJECT(SingleFileProjectProperty.class, config -> config.singleFileProject), + + /** Directive to indicate whether the runtime should use multi-threading. */ + THREADING(ThreadingProperty.class, config -> config.threading), + /** Directive to check the generated verification model. */ + VERIFY(VerifyProperty.class, config -> config.verify), + + /** Directive to specify the number of worker threads used by the runtime. */ + WORKERS(WorkersProperty.class, config -> config.workers), + + /** Directive to specify the execution timeout. */ + TIMEOUT(TimeOutProperty.class, config -> config.timeout), + + /** Directive to enable tracing. */ + TRACING(TracingProperty.class, config -> config.tracing), + + /** + * Directive to let the runtime export its internal dependency graph. + * + *

This is a debugging feature and currently only used for C++ and Rust programs. + */ + EXPORT_DEPENDENCY_GRAPH( + ExportDependencyGraphProperty.class, config -> config.exportDependencyGraph), + + /** + * Directive to let the runtime export the program structure to a yaml file. + * + *

This is a debugging feature and currently only used for C++ programs. + */ + EXPORT_TO_YAML(ExportToYamlProperty.class, config -> config.exportToYaml), + + /** + * List of module files to link into the crate as top-level. For instance, a {@code target Rust { + * rust-modules: [ "foo.rs" ] }} will cause the file to be copied into the generated project, and + * the generated {@code main.rs} will include it with a {@code mod foo;}. If one of the paths is a + * directory, it must contain a {@code mod.rs} file, and all its contents are copied. + */ + RUST_INCLUDE(RustIncludeProperty.class, config -> config.rust.rustTopLevelModules), + + /** Directive for specifying Cargo features of the generated program to enable. */ + CARGO_FEATURES(CargoFeaturesProperty.class, config -> config.rust.cargoFeatures), + + /** + * Dependency specifications for Cargo. This property looks like this: + * + *

{@code
+   * cargo-dependencies: {
+   *    // Name-of-the-crate: "version"
+   *    rand: "0.8",
+   *    // Equivalent to using an explicit map:
+   *    rand: {
+   *      version: "0.8"
+   *    },
+   *    // The map allows specifying more details
+   *    rand: {
+   *      // A path to a local unpublished crate.
+   *      // Note 'path' is mutually exclusive with 'version'.
+   *      path: "/home/me/Git/local-rand-clone"
+   *    },
+   *    rand: {
+   *      version: "0.8",
+   *      // you can specify cargo features
+   *      features: ["some-cargo-feature",]
+   *    }
+   * }
+   * }
+ */ + CARGO_DEPENDENCIES(CargoDependenciesProperty.class, config -> config.rust.cargoDependencies), + + /** + * Directs the C or Python target to include the associated C file used for setting up federated + * execution before processing the first tag. + */ + FED_SETUP(FedSetupProperty.class, config -> config.fedSetupPreamble); + + public final ConfigLoader property; + + public final Class> propertyClass; + + @FunctionalInterface + private interface ConfigLoader { + TargetPropertyConfig of(TargetConfig config); + } + + TargetProperty(Class> cls, ConfigLoader property) { + this.propertyClass = cls; + this.property = property; + } + + public static TargetPropertyConfig getPropertyInstance(TargetProperty p) { + try { + return p.propertyClass.newInstance(); + } catch (InstantiationException e) { + throw new RuntimeException(e); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); } - - public static void load(TargetConfig config, Properties properties, MessageReporter err) { - for (Object key : properties.keySet()) { - TargetProperty p = forName(key.toString()); - if (p != null) { - try { - p.property.of(config).set(properties.get(key).toString(), err); - } catch (InvalidLfSourceException e) { - err.at(e.getNode()).error(e.getProblem()); - } - } + } + + public static void load(TargetConfig config, Properties properties, MessageReporter err) { + for (Object key : properties.keySet()) { + TargetProperty p = forName(key.toString()); + if (p != null) { + try { + p.property.of(config).set(properties.get(key).toString(), err); + } catch (InvalidLfSourceException e) { + err.at(e.getNode()).error(e.getProblem()); } + } } - - /** - * Set the given configuration using the given target properties. - * - * @param config The configuration object to update. - * @param properties AST node that holds all the target properties. - * @param err Error reporter on which property format errors will be reported - */ - public static void load(TargetConfig config, List properties, MessageReporter err) { - properties.forEach( - property -> { - TargetProperty p = forName(property.getName()); - if (p != null) { - try { - p.property.of(config).set(property.getValue(), err); - } catch (InvalidLfSourceException e) { - err.at(e.getNode()).error(e.getProblem()); - } - } - }); - } - - /** - * Extracts all properties as a list of key-value pairs from a TargetConfig. Only extracts - * properties explicitly set by user. - * - * @param config The TargetConfig to extract from. - * @return The extracted properties. - */ - public static List extractProperties(TargetConfig config) { - var res = new LinkedList(); - for (TargetProperty p : TargetProperty.loaded(config)) { - KeyValuePair kv = LfFactory.eINSTANCE.createKeyValuePair(); - kv.setName(p.toString()); - kv.setValue(p.property.of(config).toAstElement()); - if (kv.getValue() != null) { - res.add(kv); + } + + /** + * Set the given configuration using the given target properties. + * + * @param config The configuration object to update. + * @param properties AST node that holds all the target properties. + * @param err Error reporter on which property format errors will be reported + */ + public static void load(TargetConfig config, List properties, MessageReporter err) { + properties.forEach( + property -> { + TargetProperty p = forName(property.getName()); + if (p != null) { + try { + p.property.of(config).set(property.getValue(), err); + } catch (InvalidLfSourceException e) { + err.at(e.getNode()).error(e.getProblem()); } - } - return res; - } - - public static List loaded(TargetConfig config) { - return Arrays.stream(TargetProperty.values()).filter( - it -> it.property.of(config).isSet() - ).collect(Collectors.toList()); - } - - /** - * Constructs a TargetDecl by extracting the fields of the given TargetConfig. - * - * @param target The target to generate for. - * @param config The TargetConfig to extract from. - * @return A generated TargetDecl. - */ - public static TargetDecl extractTargetDecl(Target target, TargetConfig config) { - TargetDecl decl = LfFactory.eINSTANCE.createTargetDecl(); - KeyValuePairs kvp = LfFactory.eINSTANCE.createKeyValuePairs(); - for (KeyValuePair p : extractProperties(config)) { - kvp.getPairs().add(p); - } - decl.setName(target.toString()); - decl.setConfig(kvp); - return decl; + } + }); + } + + /** + * Extracts all properties as a list of key-value pairs from a TargetConfig. Only extracts + * properties explicitly set by user. + * + * @param config The TargetConfig to extract from. + * @return The extracted properties. + */ + public static List extractProperties(TargetConfig config) { + var res = new LinkedList(); + for (TargetProperty p : TargetProperty.loaded(config)) { + KeyValuePair kv = LfFactory.eINSTANCE.createKeyValuePair(); + kv.setName(p.toString()); + kv.setValue(p.property.of(config).toAstElement()); + if (kv.getValue() != null) { + res.add(kv); + } } - - private static KeyValuePair getKeyValuePair(KeyValuePairs targetProperties, TargetProperty property) { - List properties = - targetProperties.getPairs().stream() - .filter(pair -> pair.getName().equals(property.toString())) - .toList(); - assert properties.size() <= 1; - return properties.size() > 0 ? properties.get(0) : null; - } - - public static KeyValuePair getKeyValuePair(Model ast, TargetProperty property) { - return getKeyValuePair(ast.getTarget().getConfig(), property); - } - - public void validate(KeyValuePairs pairs, Model ast, TargetConfig config, ValidationReporter reporter) { - this.property.of(config).validate(getKeyValuePair(pairs, this), ast, config, reporter); + return res; + } + + public static List loaded(TargetConfig config) { + return Arrays.stream(TargetProperty.values()) + .filter(it -> it.property.of(config).isSet()) + .collect(Collectors.toList()); + } + + /** + * Constructs a TargetDecl by extracting the fields of the given TargetConfig. + * + * @param target The target to generate for. + * @param config The TargetConfig to extract from. + * @return A generated TargetDecl. + */ + public static TargetDecl extractTargetDecl(Target target, TargetConfig config) { + TargetDecl decl = LfFactory.eINSTANCE.createTargetDecl(); + KeyValuePairs kvp = LfFactory.eINSTANCE.createKeyValuePairs(); + for (KeyValuePair p : extractProperties(config)) { + kvp.getPairs().add(p); } - - /** - * Update the given configuration using the given target properties. - * - * @param config The configuration object to update. - * @param properties AST node that holds all the target properties. - * @param relativePath The path from the main resource to the resource from which the new - * properties originate. - */ - public static void update( - TargetConfig config, List properties, Path relativePath, MessageReporter err) { - properties.forEach( - property -> { - TargetProperty p = forName(property.getName()); - if (p != null) { - var value = property.getValue(); - if (property.getName().equals("files")) { - var array = LfFactory.eINSTANCE.createArray(); - ASTUtils.elementToListOfStrings(property.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); - } - p.property.of(config).set(value, err); - } + decl.setName(target.toString()); + decl.setConfig(kvp); + return decl; + } + + private static KeyValuePair getKeyValuePair( + KeyValuePairs targetProperties, TargetProperty property) { + List properties = + targetProperties.getPairs().stream() + .filter(pair -> pair.getName().equals(property.toString())) + .toList(); + assert properties.size() <= 1; + return properties.size() > 0 ? properties.get(0) : null; + } + + public static KeyValuePair getKeyValuePair(Model ast, TargetProperty property) { + return getKeyValuePair(ast.getTarget().getConfig(), property); + } + + public static void validate( + KeyValuePairs pairs, Model ast, TargetConfig config, ValidatorMessageReporter reporter) { + Arrays.stream(TargetProperty.values()) + .forEach( + p -> { + var pair = getKeyValuePair(pairs, p); + if (pair != null) { + p.property.of(config).checkSupport(pair, config, reporter); + p.property.of(config).checkType(pair, config, reporter); + p.property.of(config).validate(pair, ast, config, reporter); + } }); + } + + /** + * Update the given configuration using the given target properties. + * + * @param config The configuration object to update. + * @param properties AST node that holds all the target properties. + * @param relativePath The path from the main resource to the resource from which the new + * properties originate. + */ + public static void update( + TargetConfig config, List properties, Path relativePath, MessageReporter err) { + properties.forEach( + property -> { + TargetProperty p = forName(property.getName()); + if (p != null) { + var value = property.getValue(); + if (property.getName().equals("files")) { + var array = LfFactory.eINSTANCE.createArray(); + ASTUtils.elementToListOfStrings(property.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); + } + p.property.of(config).set(value, err); + } + }); + } + + /** + * Return the entry that matches the given string. + * + * @param name The string to match against. + */ + public static TargetProperty forName(String name) { + return Target.match(name, TargetProperty.values()); + } + + /** + * Return a list with all target properties. + * + * @return All existing target properties. + */ + public static List getOptions() { + return Arrays.asList(TargetProperty.values()); + } + + /** + * Return the name of the property in as it appears in the target declaration. It may be an + * invalid identifier in other languages (may contains dashes {@code -}). + */ + @Override + public String toString() { + // Workaround because this sole property does not follow the naming convention. + if (this.equals(FED_SETUP)) { + return "_fed_setup"; } + return this.name().toLowerCase().replaceAll("_", "-"); + } - /** - * Return the entry that matches the given string. - * - * @param name The string to match against. - */ - public static TargetProperty forName(String name) { - return Target.match(name, TargetProperty.values()); - } - - /** - * Return a list with all target properties. - * - * @return All existing target properties. - */ - public static List getOptions() { - return Arrays.asList(TargetProperty.values()); - } - - /** - * Return the name of the property in as it appears in the target declaration. - * It may be an invalid identifier in other languages (may contains dashes {@code -}). - */ - @Override - public String toString() { - // Workaround because this sole property does not follow the naming convention. - if (this.equals(FED_SETUP)) { - return "_fed_setup"; - } - return this.name().toLowerCase().replaceAll("_", "-"); - } - - /** Interface for dictionary elements. It associates an entry with a type. */ - public interface DictionaryElement { - TargetPropertyType getType(); - } + /** Interface for dictionary elements. It associates an entry with a type. */ + public interface DictionaryElement { + TargetPropertyType getType(); + } } diff --git a/core/src/main/java/org/lflang/TargetPropertyConfig.java b/core/src/main/java/org/lflang/TargetPropertyConfig.java index 99be6d6b04..4382d0ecf4 100644 --- a/core/src/main/java/org/lflang/TargetPropertyConfig.java +++ b/core/src/main/java/org/lflang/TargetPropertyConfig.java @@ -1,21 +1,15 @@ package org.lflang; import java.util.List; - 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.property.type.TargetPropertyType; -import org.lflang.validation.ValidationReporter; /** - * Extend this class to manage a non-trivial target property configuration, i.e.: - *
    - *
  • it requires additional validation (override {@code validate});
  • - *
  • it uses elaborate datastructures (define as inner classes); or
  • - *
  • it performs non-trivial updates (override {@code update}.
  • - *
+ * Extend this class to manage the configuration of a target property. + * * @param The type of the configuration value. */ public abstract class TargetPropertyConfig { @@ -63,9 +57,7 @@ public void reset() { this.isSet = false; } - /** - * Return the current configuration. - */ + /** Return the current configuration. */ public T get() { return value; } @@ -77,30 +69,33 @@ public T get() { public abstract List supportedTargets(); public final boolean isSupported(Target target) { - if (supportedTargets().contains(target)) { - return true; - } - return false; + return supportedTargets().contains(target); + } + + public void validate( + KeyValuePair pair, Model ast, TargetConfig config, MessageReporter reporter) { + // FIXME: Make abstract? + // FIXME: consider not passing in config } - // FIXME: config may not be needed. - public void validate(KeyValuePair pair, Model ast, TargetConfig config, ValidationReporter reporter) { - // Check whether the property is supported by the target. + public void checkSupport(KeyValuePair pair, TargetConfig config, MessageReporter reporter) { if (!this.isSupported(config.target)) { - reporter.warning( - "The target parameter: " - + pair.getName() - + " is not supported by the " - + config.target - + " target and will thus be ignored.", - pair, - Literals.KEY_VALUE_PAIR__NAME); + reporter + .at(pair, Literals.KEY_VALUE_PAIR__NAME) + .warning( + String.format( + "The target parameter: %s is not supported by the %s target and will thus be" + + " ignored.", + pair.getName(), config.target)); } + } + public void checkType(KeyValuePair pair, TargetConfig config, MessageReporter reporter) { if (!this.type.check(pair.getValue(), pair.getName(), reporter)) { - reporter.error("Target property '" + pair.getName() + "' is required to be " + type + ".", pair, Literals.KEY_VALUE_PAIR__VALUE); + reporter + .at(pair, Literals.KEY_VALUE_PAIR__VALUE) + .error("Target property '" + pair.getName() + "' is required to be " + type + "."); } - } /** @@ -114,5 +109,11 @@ public boolean isSet() { } @Override - public String toString() { return value.toString(); } + public String toString() { + return value.toString(); + } + + public void markSet() { + this.isSet = true; + } } diff --git a/core/src/main/java/org/lflang/analyses/statespace/Event.java b/core/src/main/java/org/lflang/analyses/statespace/Event.java index d8613e5138..7f8b54b20b 100644 --- a/core/src/main/java/org/lflang/analyses/statespace/Event.java +++ b/core/src/main/java/org/lflang/analyses/statespace/Event.java @@ -5,7 +5,7 @@ /** A node in the state space diagram representing a step in the execution of an LF program. */ public class Event implements Comparable { - private TriggerInstance trigger; + private final TriggerInstance trigger; private Tag tag; public Event(TriggerInstance trigger, Tag tag) { @@ -45,7 +45,7 @@ public Tag getTag() { return tag; } - public TriggerInstance getTrigger() { + public TriggerInstance getTrigger() { return trigger; } } diff --git a/core/src/main/java/org/lflang/analyses/statespace/StateSpaceExplorer.java b/core/src/main/java/org/lflang/analyses/statespace/StateSpaceExplorer.java index 48f407914f..40f4a521ea 100644 --- a/core/src/main/java/org/lflang/analyses/statespace/StateSpaceExplorer.java +++ b/core/src/main/java/org/lflang/analyses/statespace/StateSpaceExplorer.java @@ -4,6 +4,7 @@ import java.util.HashMap; import java.util.HashSet; import java.util.Set; +import java.util.stream.Collectors; import org.lflang.TimeUnit; import org.lflang.TimeValue; import org.lflang.generator.ActionInstance; @@ -91,37 +92,36 @@ public void explore(Tag horizon, boolean findLoop) { boolean stop = true; if (this.eventQ.size() > 0) { stop = false; - currentTag = (eventQ.peek()).getTag(); + currentTag = eventQ.peek().getTag(); } // A list of reactions invoked at the current logical tag Set reactionsInvoked; - // A temporary list of reactions processed in the current LOOP ITERATION - Set reactionsTemp; while (!stop) { // Pop the events from the earliest tag off the event queue. - ArrayList currentEvents = new ArrayList(); - // FIXME: Use stream methods here? - while (eventQ.size() > 0 && eventQ.peek().getTag().compareTo(currentTag) == 0) { - Event e = eventQ.poll(); - currentEvents.add(e); - } + + final var now = currentTag; + var currentEvents = + eventQ.stream() + .filter(e -> e.getTag().equals(now)) + .collect(Collectors.toCollection(ArrayList::new)); // Collect all the reactions invoked in this current LOOP ITERATION // triggered by the earliest events. // Using a hash set here to make sure the reactions invoked // are unique. Sometimes multiple events can trigger the same reaction, // and we do not want to record duplicate reaction invocations. - reactionsTemp = new HashSet(); + + // A temporary list of reactions processed in the current LOOP ITERATION + Set reactionsTemp = new HashSet<>(); for (Event e : currentEvents) { Set dependentReactions = e.getTrigger().getDependentReactions(); reactionsTemp.addAll(dependentReactions); // If the event is a timer firing, enqueue the next firing. - if (e.getTrigger() instanceof TimerInstance) { - TimerInstance timer = (TimerInstance) e.getTrigger(); + if (e.getTrigger() instanceof TimerInstance timer) { eventQ.add( new Event( timer, @@ -185,22 +185,21 @@ public void explore(Tag horizon, boolean findLoop) { //// Now we are done with the node at the previous tag, //// work on the new node at the current timestamp. // Copy the reactions in reactionsTemp. - reactionsInvoked = new HashSet(reactionsTemp); + reactionsInvoked = new HashSet<>(reactionsTemp); // Create a new state in the SSD for the current tag, // add the reactions triggered to the state, // and add a snapshot of the event queue (with new events // generated by reaction invocations in the curren tag) // to the state. - StateSpaceNode node = + + // Initialize currentNode. + currentNode = new StateSpaceNode( currentTag, // Current tag reactionsInvoked, // Reactions invoked at this tag - new ArrayList(eventQ) // A snapshot of the event queue + new ArrayList<>(eventQ) // A snapshot of the event queue ); - - // Initialize currentNode. - currentNode = node; } // When we advance to a new TIMESTAMP (not a new tag), // create a new node in the state space diagram @@ -248,7 +247,7 @@ else if (previousTag != null && currentTag.timestamp > previousTag.timestamp) { //// Now we are done with the node at the previous tag, //// work on the new node at the current timestamp. // Copy the reactions in reactionsTemp. - reactionsInvoked = new HashSet(reactionsTemp); + reactionsInvoked = new HashSet<>(reactionsTemp); // Create a new state in the SSD for the current tag, // add the reactions triggered to the state, @@ -259,7 +258,7 @@ else if (previousTag != null && currentTag.timestamp > previousTag.timestamp) { new StateSpaceNode( currentTag, // Current tag reactionsInvoked, // Reactions invoked at this tag - new ArrayList(eventQ) // A snapshot of the event queue + new ArrayList<>(eventQ) // A snapshot of the event queue ); // Update the previous node. @@ -274,7 +273,7 @@ else if (previousTag != null && currentTag.timestamp == previousTag.timestamp) { // to the existing state space node. currentNode.getReactionsInvoked().addAll(reactionsTemp); // Update the eventQ snapshot. - currentNode.setEventQcopy(new ArrayList(eventQ)); + currentNode.setEventQcopy(new ArrayList<>(eventQ)); } else { throw new AssertionError("Unreachable"); } @@ -313,7 +312,5 @@ else if (previousTag != null && currentTag.timestamp == previousTag.timestamp) { // that means there is only one node in the diagram. // Set the current node as the head. if (this.diagram.head == null) this.diagram.head = currentNode; - - return; } } diff --git a/core/src/main/java/org/lflang/ast/ASTUtils.java b/core/src/main/java/org/lflang/ast/ASTUtils.java index 390f964369..fc054e5018 100644 --- a/core/src/main/java/org/lflang/ast/ASTUtils.java +++ b/core/src/main/java/org/lflang/ast/ASTUtils.java @@ -614,8 +614,10 @@ public static ReactorInstance createMainReactorInstance( if (breadth == 0) { messageReporter.nowhere().warning("The program has no reactions"); } else { - targetConfig.compileDefinitions.get().put( - "LF_REACTION_GRAPH_BREADTH", String.valueOf(reactionInstanceGraph.getBreadth())); + targetConfig + .compileDefinitions + .get() + .put("LF_REACTION_GRAPH_BREADTH", String.valueOf(reactionInstanceGraph.getBreadth())); } return main; } diff --git a/core/src/main/java/org/lflang/diagram/synthesis/util/SynthesisMessageReporter.java b/core/src/main/java/org/lflang/diagram/synthesis/util/SynthesisMessageReporter.java index dea894d833..dab0eb6265 100644 --- a/core/src/main/java/org/lflang/diagram/synthesis/util/SynthesisMessageReporter.java +++ b/core/src/main/java/org/lflang/diagram/synthesis/util/SynthesisMessageReporter.java @@ -29,6 +29,7 @@ import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.EStructuralFeature; import org.eclipse.lsp4j.DiagnosticSeverity; import org.lflang.MessageReporterBase; import org.lflang.generator.Range; @@ -55,7 +56,8 @@ protected void report(Path path, Range range, DiagnosticSeverity severity, Strin } @Override - protected void reportOnNode(EObject node, DiagnosticSeverity severity, String message) { + protected void reportOnNode( + EObject node, EStructuralFeature feature, DiagnosticSeverity severity, String message) { reportWithoutPosition(severity, message); } } 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 78a1abc910..07dce71ca1 100644 --- a/core/src/main/java/org/lflang/federated/extensions/CExtension.java +++ b/core/src/main/java/org/lflang/federated/extensions/CExtension.java @@ -36,7 +36,6 @@ import org.lflang.InferredType; import org.lflang.MessageReporter; import org.lflang.Target; -import org.lflang.TargetProperty; import org.lflang.TimeValue; import org.lflang.ast.ASTUtils; import org.lflang.federated.generator.FedASTUtils; @@ -83,18 +82,15 @@ public void initializeTargetConfig( generateCMakeInclude(federate, fileConfig); federate.targetConfig.keepalive.override(true); - federate.targetConfig.setByUser.add(TargetProperty.KEEPALIVE); // If there are federates, copy the required files for that. // Also, create the RTI C file and the launcher script. // Handle target parameters. // If the program is federated, then ensure that threading is enabled. - federate.targetConfig.threading = true; - federate.targetConfig.setByUser.add(TargetProperty.THREADING); + federate.targetConfig.threading.override(true); // Include the fed setup file for this federate in the target property - federate.targetConfig.fedSetupPreamble = getPreamblePath(federate); - federate.targetConfig.setByUser.add(TargetProperty.FED_SETUP); + federate.targetConfig.fedSetupPreamble.override(getPreamblePath(federate)); } /** Generate a cmake-include file for {@code federate} if needed. */ diff --git a/core/src/main/java/org/lflang/federated/extensions/CExtensionUtils.java b/core/src/main/java/org/lflang/federated/extensions/CExtensionUtils.java index 6bc46556c8..bbb7cc8b88 100644 --- a/core/src/main/java/org/lflang/federated/extensions/CExtensionUtils.java +++ b/core/src/main/java/org/lflang/federated/extensions/CExtensionUtils.java @@ -8,7 +8,6 @@ import java.util.regex.Pattern; import org.lflang.InferredType; import org.lflang.MessageReporter; -import org.lflang.TargetProperty; import org.lflang.ast.ASTUtils; import org.lflang.federated.generator.FedFileConfig; import org.lflang.federated.generator.FederateInstance; @@ -173,16 +172,15 @@ public static void handleCompileDefinitions( int numOfFederates, RtiConfig rtiConfig, MessageReporter messageReporter) { - federate.targetConfig.setByUser.add(TargetProperty.COMPILE_DEFINITIONS); - federate.targetConfig.compileDefinitions.get().put("FEDERATED", ""); - federate.targetConfig.compileDefinitions.get().put( - "FEDERATED_" + federate.targetConfig.coordination.toString().toUpperCase(), ""); + var defs = federate.targetConfig.compileDefinitions.get(); + defs.put("FEDERATED", ""); + defs.put("FEDERATED_" + federate.targetConfig.coordination.toString().toUpperCase(), ""); if (federate.targetConfig.auth.get()) { - federate.targetConfig.compileDefinitions.get().put("FEDERATED_AUTHENTICATED", ""); + defs.put("FEDERATED_AUTHENTICATED", ""); } - federate.targetConfig.compileDefinitions.get().put( - "NUMBER_OF_FEDERATES", String.valueOf(numOfFederates)); - federate.targetConfig.compileDefinitions.get().put("EXECUTABLE_PREAMBLE", ""); + defs.put("NUMBER_OF_FEDERATES", String.valueOf(numOfFederates)); + defs.put("EXECUTABLE_PREAMBLE", ""); + federate.targetConfig.compileDefinitions.markSet(); handleAdvanceMessageInterval(federate); @@ -190,11 +188,15 @@ public static void handleCompileDefinitions( } private static void handleAdvanceMessageInterval(FederateInstance federate) { - var advanceMessageInterval = federate.targetConfig.coordinationOptions.get().advanceMessageInterval; - federate.targetConfig.setByUser.remove(TargetProperty.COORDINATION_OPTIONS); + var advanceMessageInterval = + federate.targetConfig.coordinationOptions.get().advanceMessageInterval; + federate.targetConfig.coordinationOptions.reset(); if (advanceMessageInterval != null) { - federate.targetConfig.compileDefinitions.get().put( - "ADVANCE_MESSAGE_INTERVAL", String.valueOf(advanceMessageInterval.toNanoSeconds())); + federate + .targetConfig + .compileDefinitions + .get() + .put("ADVANCE_MESSAGE_INTERVAL", String.valueOf(advanceMessageInterval.toNanoSeconds())); } } @@ -225,12 +227,8 @@ public static void initializeClockSynchronization( .nowhere() .info("Will collect clock sync statistics for federate " + federate.id); // Add libm to the compiler flags - // FIXME: This is a linker flag not compile flag but we don't have a way to add linker - // flags - // FIXME: This is probably going to fail on MacOS (especially using clang) - // because libm functions are builtin federate.targetConfig.compilerFlags.get().add("-lm"); - federate.targetConfig.setByUser.add(TargetProperty.FLAGS); + federate.targetConfig.compilerFlags.markSet(); } messageReporter .nowhere() @@ -255,12 +253,21 @@ public static void addClockSyncCompileDefinitions(FederateInstance federate) { ClockSyncOptions options = federate.targetConfig.clockSyncOptions.get(); federate.targetConfig.compileDefinitions.get().put("_LF_CLOCK_SYNC_INITIAL", ""); - federate.targetConfig.compileDefinitions.get().put( - "_LF_CLOCK_SYNC_PERIOD_NS", String.valueOf(options.period.toNanoSeconds())); - federate.targetConfig.compileDefinitions.get().put( - "_LF_CLOCK_SYNC_EXCHANGES_PER_INTERVAL", String.valueOf(options.trials)); - federate.targetConfig.compileDefinitions.get().put( - "_LF_CLOCK_SYNC_ATTENUATION", String.valueOf(options.attenuation)); + federate + .targetConfig + .compileDefinitions + .get() + .put("_LF_CLOCK_SYNC_PERIOD_NS", String.valueOf(options.period.toNanoSeconds())); + federate + .targetConfig + .compileDefinitions + .get() + .put("_LF_CLOCK_SYNC_EXCHANGES_PER_INTERVAL", String.valueOf(options.trials)); + federate + .targetConfig + .compileDefinitions + .get() + .put("_LF_CLOCK_SYNC_ATTENUATION", String.valueOf(options.attenuation)); if (mode == ClockSyncMode.ON) { federate.targetConfig.compileDefinitions.get().put("_LF_CLOCK_SYNC_ON", ""); @@ -292,9 +299,12 @@ public static void generateCMakeInclude(FederateInstance federate, FedFileConfig srcWriter.write(cmakeIncludeCode.getCode()); } - federate.targetConfig.cmakeIncludes.get().add( - fileConfig.getSrcPath().relativize(cmakeIncludePath).toString()); - federate.targetConfig.setByUser.add(TargetProperty.CMAKE_INCLUDE); + federate + .targetConfig + .cmakeIncludes + .get() + .add(fileConfig.getSrcPath().relativize(cmakeIncludePath).toString()); + federate.targetConfig.cmakeIncludes.markSet(); } /** 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 f3b74c495d..2990cbc169 100644 --- a/core/src/main/java/org/lflang/federated/generator/FedGenerator.java +++ b/core/src/main/java/org/lflang/federated/generator/FedGenerator.java @@ -693,6 +693,7 @@ private void replaceFedConnection(FedConnectionInstance connection, Resource res } } - FedASTUtils.makeCommunication(connection, resource, targetConfig.coordination.get(), messageReporter); + FedASTUtils.makeCommunication( + connection, resource, targetConfig.coordination.get(), messageReporter); } } diff --git a/core/src/main/java/org/lflang/federated/generator/LineAdjustingMessageReporter.java b/core/src/main/java/org/lflang/federated/generator/LineAdjustingMessageReporter.java index 9a08f007cb..6579e4e7da 100644 --- a/core/src/main/java/org/lflang/federated/generator/LineAdjustingMessageReporter.java +++ b/core/src/main/java/org/lflang/federated/generator/LineAdjustingMessageReporter.java @@ -3,6 +3,7 @@ import java.nio.file.Path; import java.util.Map; import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.EStructuralFeature; import org.lflang.MessageReporter; import org.lflang.generator.CodeMap; import org.lflang.generator.Position; @@ -19,8 +20,13 @@ public LineAdjustingMessageReporter(MessageReporter parent, Map c } @Override - public Stage2 at(EObject object) { - return parent.at(object); + public Stage2 at(EObject node, EStructuralFeature feature) { + return parent.at(node, feature); + } + + @Override + public Stage2 at(EObject node) { + return parent.at(node); } @Override diff --git a/core/src/main/java/org/lflang/federated/generator/SynchronizedMessageReporter.java b/core/src/main/java/org/lflang/federated/generator/SynchronizedMessageReporter.java index e51a118d70..6583ba97ab 100644 --- a/core/src/main/java/org/lflang/federated/generator/SynchronizedMessageReporter.java +++ b/core/src/main/java/org/lflang/federated/generator/SynchronizedMessageReporter.java @@ -2,6 +2,7 @@ import java.nio.file.Path; import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.EStructuralFeature; import org.eclipse.lsp4j.DiagnosticSeverity; import org.lflang.MessageReporter; import org.lflang.MessageReporterBase; @@ -17,7 +18,7 @@ public SynchronizedMessageReporter(MessageReporter parent) { @Override protected synchronized void reportOnNode( - EObject node, DiagnosticSeverity severity, String message) { + EObject node, EStructuralFeature feature, DiagnosticSeverity severity, String message) { parent.at(node).report(severity, message); } diff --git a/core/src/main/java/org/lflang/federated/serialization/FedROS2CPPSerialization.java b/core/src/main/java/org/lflang/federated/serialization/FedROS2CPPSerialization.java index 4807f42fbc..48e9e2ec92 100644 --- a/core/src/main/java/org/lflang/federated/serialization/FedROS2CPPSerialization.java +++ b/core/src/main/java/org/lflang/federated/serialization/FedROS2CPPSerialization.java @@ -52,7 +52,7 @@ public boolean isCompatible(GeneratorBase generator) { .nowhere() .error("ROS serialization is currently only supported for the C target."); return false; - } else if (!generator.getTargetConfig().compiler.equalsIgnoreCase("g++")) { + } else if (!generator.getTargetConfig().compiler.get().equalsIgnoreCase("g++")) { generator .messageReporter .nowhere() diff --git a/core/src/main/java/org/lflang/generator/GeneratorBase.java b/core/src/main/java/org/lflang/generator/GeneratorBase.java index 9a31d5d235..ae75109aa6 100644 --- a/core/src/main/java/org/lflang/generator/GeneratorBase.java +++ b/core/src/main/java/org/lflang/generator/GeneratorBase.java @@ -252,7 +252,7 @@ public void doGenerate(Resource resource, LFGeneratorContext context) { // Check for the existence and support of watchdogs hasWatchdogs = IterableExtensions.exists(reactors, it -> !it.getWatchdogs().isEmpty()); - checkWatchdogSupport(targetConfig.threading && getTarget() == Target.C); + checkWatchdogSupport(targetConfig.threading.get() && getTarget() == Target.C); additionalPostProcessingForModes(); } @@ -318,7 +318,8 @@ protected void setReactorsAndInstantiationGraph(LFGeneratorContext.Mode mode) { */ protected void copyUserFiles(TargetConfig targetConfig, FileConfig fileConfig) { var dst = this.context.getFileConfig().getSrcGenPath(); - FileUtil.copyFilesOrDirectories(targetConfig.files, dst, fileConfig, messageReporter, false); + FileUtil.copyFilesOrDirectories( + targetConfig.files.get(), dst, fileConfig, messageReporter, false); } /** diff --git a/core/src/main/java/org/lflang/generator/GeneratorUtils.java b/core/src/main/java/org/lflang/generator/GeneratorUtils.java index 545d8576a9..b7a35ca6a2 100644 --- a/core/src/main/java/org/lflang/generator/GeneratorUtils.java +++ b/core/src/main/java/org/lflang/generator/GeneratorUtils.java @@ -55,11 +55,9 @@ public static void accommodatePhysicalActionsIfPresent( for (Resource resource : resources) { for (Action action : findAll(resource, Action.class)) { if (action.getOrigin() == ActionOrigin.PHYSICAL - && - // Check if the user has explicitly set keepalive to false - !targetConfig.setByUser.contains(TargetProperty.KEEPALIVE) + && !targetConfig.keepalive.isSet() && !targetConfig.keepalive.get()) { - // If not, set it to true + // Keepalive was explicitly set to false; set it to true. targetConfig.keepalive.override(true); String message = String.format( diff --git a/core/src/main/java/org/lflang/generator/LanguageServerMessageReporter.java b/core/src/main/java/org/lflang/generator/LanguageServerMessageReporter.java index 0fd51333b1..a9fcff9f22 100644 --- a/core/src/main/java/org/lflang/generator/LanguageServerMessageReporter.java +++ b/core/src/main/java/org/lflang/generator/LanguageServerMessageReporter.java @@ -8,6 +8,7 @@ import java.util.Optional; import org.eclipse.emf.common.util.URI; import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.EStructuralFeature; import org.eclipse.lsp4j.Diagnostic; import org.eclipse.lsp4j.DiagnosticSeverity; import org.eclipse.lsp4j.PublishDiagnosticsParams; @@ -47,7 +48,8 @@ public LanguageServerMessageReporter(EObject parseRoot) { } @Override - protected void reportOnNode(EObject node, DiagnosticSeverity severity, String message) { + protected void reportOnNode( + EObject node, EStructuralFeature feature, DiagnosticSeverity severity, String message) { reportWithoutPosition(severity, message); } 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 471bd78dcf..0c9b273467 100644 --- a/core/src/main/java/org/lflang/generator/c/CCmakeGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CCmakeGenerator.java @@ -251,7 +251,9 @@ CodeBuilder generateCMakeCode( if (targetConfig.platformOptions.get().platform != Platform.AUTO) { cMakeCode.pr( - "set(CMAKE_SYSTEM_NAME " + targetConfig.platformOptions.get().platform.getcMakeName() + ")"); + "set(CMAKE_SYSTEM_NAME " + + targetConfig.platformOptions.get().platform.getcMakeName() + + ")"); } cMakeCode.newLine(); @@ -326,7 +328,7 @@ CodeBuilder generateCMakeCode( cMakeCode.newLine(); } - if (targetConfig.threading) { + if (targetConfig.threading.get()) { // If threaded computation is requested, add the threads option. cMakeCode.pr("# Find threads and link to it"); cMakeCode.pr("find_package(Threads REQUIRED)"); @@ -344,7 +346,7 @@ CodeBuilder generateCMakeCode( // Add additional flags so runtime can distinguish between multi-threaded and single-threaded // mode - if (targetConfig.threading) { + if (targetConfig.threading.get()) { cMakeCode.pr("# Set flag to indicate a multi-threaded runtime"); cMakeCode.pr("target_compile_definitions( ${LF_MAIN_TARGET} PUBLIC LF_THREADED=1)"); } else { @@ -355,7 +357,7 @@ CodeBuilder generateCMakeCode( if (CppMode) cMakeCode.pr("enable_language(CXX)"); - if (targetConfig.compiler != null && !targetConfig.compiler.isBlank()) { + if (!targetConfig.compiler.isSet()) { if (CppMode) { // Set the CXX compiler to what the user has requested. cMakeCode.pr("set(CMAKE_CXX_COMPILER " + targetConfig.compiler + ")"); diff --git a/core/src/main/java/org/lflang/generator/c/CCompiler.java b/core/src/main/java/org/lflang/generator/c/CCompiler.java index 65ddfaa398..deabdc42a5 100644 --- a/core/src/main/java/org/lflang/generator/c/CCompiler.java +++ b/core/src/main/java/org/lflang/generator/c/CCompiler.java @@ -404,8 +404,10 @@ public LFCommand compileCCommand(String fileToCompile, boolean noBinary) { } // Add compile definitions - targetConfig.compileDefinitions.get().forEach( - (key, value) -> compileArgs.add("-D" + key + "=" + value)); + targetConfig + .compileDefinitions + .get() + .forEach((key, value) -> compileArgs.add("-D" + key + "=" + value)); // Finally, add the compiler flags in target parameters (if any) compileArgs.addAll(targetConfig.compilerFlags.get()); @@ -426,7 +428,8 @@ public LFCommand compileCCommand(String fileToCompile, boolean noBinary) { } LFCommand command = - commandFactory.createCommand(targetConfig.compiler.get(), compileArgs, fileConfig.getOutPath()); + commandFactory.createCommand( + targetConfig.compiler.get(), compileArgs, fileConfig.getOutPath()); if (command == null) { messageReporter .nowhere() diff --git a/core/src/main/java/org/lflang/generator/c/CEnvironmentFunctionGenerator.java b/core/src/main/java/org/lflang/generator/c/CEnvironmentFunctionGenerator.java index 90a09b3dc1..d04eae4540 100644 --- a/core/src/main/java/org/lflang/generator/c/CEnvironmentFunctionGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CEnvironmentFunctionGenerator.java @@ -95,8 +95,7 @@ private String generateCreateEnvironments() { if (enclave.isMainOrFederated()) { traceFileName = "\"" + tracing.traceFileName + ".lft\""; } else { - traceFileName = - "\"" + tracing.traceFileName + enclave.getName() + ".lft\""; + traceFileName = "\"" + tracing.traceFileName + enclave.getName() + ".lft\""; } } else { if (enclave.isMainOrFederated()) { 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 d00578d9c5..4ee4b0f6d3 100644 --- a/core/src/main/java/org/lflang/generator/c/CGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CGenerator.java @@ -53,8 +53,6 @@ import org.lflang.FileConfig; import org.lflang.Target; import org.lflang.TargetConfig; -import org.lflang.TargetProperty; -import org.lflang.target.property.PlatformProperty.PlatformOption; import org.lflang.ast.ASTUtils; import org.lflang.ast.DelayedConnectionTransformation; import org.lflang.federated.extensions.CExtensionUtils; @@ -89,6 +87,7 @@ import org.lflang.lf.StateVar; import org.lflang.lf.Variable; import org.lflang.target.property.PlatformProperty.Platform; +import org.lflang.target.property.PlatformProperty.PlatformOption; import org.lflang.target.property.SchedulerProperty.SchedulerOption; import org.lflang.util.ArduinoUtil; import org.lflang.util.FileUtil; @@ -347,9 +346,8 @@ 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. - if (!targetConfig.threading - && !targetConfig.setByUser.contains(TargetProperty.THREADING)) { - targetConfig.threading = true; + if (!targetConfig.threading.get() && !targetConfig.threading.isSet()) { + targetConfig.threading.override(true); String message = "Using the threaded C runtime to allow for asynchronous handling of physical action" + " " @@ -459,7 +457,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.threading); + FileUtil.arduinoDeleteHelper(src, targetConfig.threading.get()); FileUtil.relativeIncludeHelper(src, include, messageReporter); FileUtil.relativeIncludeHelper(include, include, messageReporter); } catch (IOException e) { @@ -518,7 +516,8 @@ public void doGenerate(Resource resource, LFGeneratorContext context) { try { String compileDefs = targetConfig.compileDefinitions.get().keySet().stream() - .map(key -> "\"-D" + key + "=" + targetConfig.compileDefinitions.get().get(key) + "\"") + .map( + key -> "\"-D" + key + "=" + targetConfig.compileDefinitions.get().get(key) + "\"") .collect(Collectors.joining(",\n")); String settings = "{\n" + "\"cmake.configureArgs\": [\n" + compileDefs + "\n]\n}\n"; Path vscodePath = fileConfig.getSrcGenPath().resolve(".vscode"); @@ -698,7 +697,7 @@ private void pickScheduler() { if (!targetConfig.schedulerType.get().prioritizesDeadline()) { // Check if a deadline is assigned to any reaction if (hasDeadlines(reactors)) { - if (!targetConfig.setByUser.contains(TargetProperty.SCHEDULER)) { + if (!targetConfig.schedulerType.isSet()) { targetConfig.schedulerType.override(SchedulerOption.GEDF_NP); } } @@ -745,7 +744,8 @@ private void inspectReactorEResource(ReactorDecl reactor) { // Merge the CMake includes from the imported file into the target config lfResource .getTargetConfig() - .cmakeIncludes.get() + .cmakeIncludes + .get() .forEach( incl -> { if (!this.targetConfig.cmakeIncludes.get().contains(incl)) { @@ -772,12 +772,10 @@ protected void copyUserFiles(TargetConfig targetConfig, FileConfig fileConfig) { FileUtil.copyFilesOrDirectories( targetConfig.cmakeIncludes.get(), destination, fileConfig, messageReporter, true); - // FIXME: Unclear what the following does, but it does not appear to belong here. - if (!StringExtensions.isNullOrEmpty(targetConfig.fedSetupPreamble)) { + if (!StringExtensions.isNullOrEmpty(targetConfig.fedSetupPreamble.get())) { try { - FileUtil.copyFile( - fileConfig.srcFile.getParent().resolve(targetConfig.fedSetupPreamble), - destination.resolve(targetConfig.fedSetupPreamble)); + var file = targetConfig.fedSetupPreamble.get(); + FileUtil.copyFile(fileConfig.srcFile.getParent().resolve(file), destination.resolve(file)); } catch (IOException e) { messageReporter .nowhere() @@ -1959,8 +1957,10 @@ protected DockerGenerator getDockerGenerator(LFGeneratorContext context) { // Perform set up that does not generate code protected void setUpGeneralParameters() { accommodatePhysicalActionsIfPresent(); - targetConfig.compileDefinitions.get().put( - "LOG_LEVEL", String.valueOf(targetConfig.logLevel.get().ordinal())); + targetConfig + .compileDefinitions + .get() + .put("LOG_LEVEL", String.valueOf(targetConfig.logLevel.get().ordinal())); targetConfig.compileAdditionalSources.addAll(CCoreFilesUtils.getCTargetSrc()); // Create the main reactor instance if there is a main reactor. this.main = @@ -1969,7 +1969,7 @@ protected void setUpGeneralParameters() { // So that each separate compile knows about modal reactors, do this: targetConfig.compileDefinitions.get().put("MODAL_REACTORS", "TRUE"); } - if (targetConfig.threading + if (targetConfig.threading.get() && targetConfig.platformOptions.get().platform == Platform.ARDUINO && (targetConfig.platformOptions.get().board == null || !targetConfig.platformOptions.get().board.contains("mbed"))) { @@ -1979,7 +1979,7 @@ protected void setUpGeneralParameters() { .info( "Threading is incompatible on your current Arduino flavor. Setting threading to" + " false."); - targetConfig.threading = false; + targetConfig.threading.override(false); } if (targetConfig.platformOptions.get().platform == Platform.ARDUINO @@ -1996,11 +1996,14 @@ protected void setUpGeneralParameters() { } if (targetConfig.platformOptions.get().platform == Platform.ZEPHYR - && targetConfig.threading + && targetConfig.threading.get() && targetConfig.platformOptions.get().userThreads >= 0) { - targetConfig.compileDefinitions.get().put( - PlatformOption.USER_THREADS.name(), - String.valueOf(targetConfig.platformOptions.get().userThreads)); + targetConfig + .compileDefinitions + .get() + .put( + PlatformOption.USER_THREADS.name(), + String.valueOf(targetConfig.platformOptions.get().userThreads)); } else if (targetConfig.platformOptions.get().userThreads > 0) { messageReporter .nowhere() @@ -2009,12 +2012,17 @@ protected void setUpGeneralParameters() { + " This option will be ignored."); } - if (targetConfig.threading) { // FIXME: This logic is duplicated in CMake + if (targetConfig.threading.get()) { // FIXME: This logic is duplicated in CMake pickScheduler(); // FIXME: this and pickScheduler should be combined. - targetConfig.compileDefinitions.get().put("SCHEDULER", targetConfig.schedulerType.get().name()); - targetConfig.compileDefinitions.get().put( - "NUMBER_OF_WORKERS", String.valueOf(targetConfig.workers)); + targetConfig + .compileDefinitions + .get() + .put("SCHEDULER", targetConfig.schedulerType.get().name()); + targetConfig + .compileDefinitions + .get() + .put("NUMBER_OF_WORKERS", String.valueOf(targetConfig.workers)); } pickCompilePlatform(); } 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 fd087e081a..fbba2f01a0 100644 --- a/core/src/main/java/org/lflang/generator/c/CPreambleGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CPreambleGenerator.java @@ -37,7 +37,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.threading) { + if (targetConfig.threading.get()) { code.pr("#include \"include/core/threaded/scheduler.h\""); } @@ -78,12 +78,12 @@ public static String generateDefineDirectives( // targetConfig.clockSyncOptions // )); // } - if (targetConfig.threading) { + if (targetConfig.threading.get()) { targetConfig.compileDefinitions.get().put("LF_THREADED", "1"); } else { targetConfig.compileDefinitions.get().put("LF_UNTHREADED", "1"); } - if (targetConfig.threading) { + if (targetConfig.threading.get()) { targetConfig.compileDefinitions.get().put("LF_THREADED", "1"); } else { targetConfig.compileDefinitions.get().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 7bdb13706f..b7485eb5bd 100644 --- a/core/src/main/java/org/lflang/generator/c/CTriggerObjectsGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CTriggerObjectsGenerator.java @@ -100,7 +100,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.threading) { + if (!targetConfig.threading.get()) { return ""; } var code = new CodeBuilder(); diff --git a/core/src/main/java/org/lflang/generator/python/PythonGenerator.java b/core/src/main/java/org/lflang/generator/python/PythonGenerator.java index e9998d268c..92d0f8a840 100644 --- a/core/src/main/java/org/lflang/generator/python/PythonGenerator.java +++ b/core/src/main/java/org/lflang/generator/python/PythonGenerator.java @@ -39,7 +39,6 @@ import org.lflang.AttributeUtils; import org.lflang.FileConfig; import org.lflang.Target; -import org.lflang.TargetProperty; import org.lflang.ast.ASTUtils; import org.lflang.generator.CodeBuilder; import org.lflang.generator.CodeMap; @@ -366,8 +365,8 @@ public boolean isOSCompatible() { public void doGenerate(Resource resource, LFGeneratorContext context) { // Set the threading to false by default, unless the user has // specifically asked for it. - if (!targetConfig.setByUser.contains(TargetProperty.THREADING)) { - targetConfig.threading = false; + if (!targetConfig.threading.isSet()) { + targetConfig.threading.override(false); } int cGeneratedPercentProgress = (IntegratedBuilder.VALIDATED_PERCENT_PROGRESS + 100) / 2; code.pr( diff --git a/core/src/main/java/org/lflang/generator/rust/CargoDependencySpec.java b/core/src/main/java/org/lflang/generator/rust/CargoDependencySpec.java index 02976257fd..50bf482024 100644 --- a/core/src/main/java/org/lflang/generator/rust/CargoDependencySpec.java +++ b/core/src/main/java/org/lflang/generator/rust/CargoDependencySpec.java @@ -43,8 +43,6 @@ import org.lflang.lf.LfFactory; import org.lflang.target.property.type.TargetPropertyType; import org.lflang.util.StringUtil; -import org.lflang.validation.LFValidator; -import org.lflang.validation.ValidationReporter; /** * Info about a cargo dependency. See {@link TargetProperty#CARGO_DEPENDENCIES}. @@ -279,7 +277,7 @@ public boolean validate(Element e) { } @Override - public boolean check(Element element, String name, ValidationReporter v) { + public boolean check(Element element, String name, MessageReporter v) { var valid = true; for (KeyValuePair pair : element.getKeyvalue().getPairs()) { try { @@ -287,8 +285,7 @@ public boolean check(Element element, String name, ValidationReporter v) { } catch (InvalidLfSourceException e) { EObject object = e.getNode(); String message = e.getProblem(); - // FIXME: use ValidatorMessageReporter - // v.at(object).error(message); + v.at(object).error(message); valid = false; } } diff --git a/core/src/main/java/org/lflang/generator/rust/RustTargetConfig.java b/core/src/main/java/org/lflang/generator/rust/RustTargetConfig.java index 7d13203c86..bc287260fd 100644 --- a/core/src/main/java/org/lflang/generator/rust/RustTargetConfig.java +++ b/core/src/main/java/org/lflang/generator/rust/RustTargetConfig.java @@ -49,7 +49,6 @@ public final class RustTargetConfig { /** Cargo profile, default is debug (corresponds to cargo dev profile). */ private BuildType profile = BuildType.DEBUG; - /** The build type to use. Corresponds to a Cargo profile. */ public BuildType getBuildType(BuildTypeProperty cmakeBuildType) { // FIXME: this is because Rust uses a different default. @@ -59,5 +58,4 @@ public BuildType getBuildType(BuildTypeProperty cmakeBuildType) { } return profile; } - } diff --git a/core/src/main/java/org/lflang/target/property/AuthProperty.java b/core/src/main/java/org/lflang/target/property/AuthProperty.java index d20ad37c2c..03eeb124a6 100644 --- a/core/src/main/java/org/lflang/target/property/AuthProperty.java +++ b/core/src/main/java/org/lflang/target/property/AuthProperty.java @@ -2,14 +2,12 @@ import java.util.Arrays; import java.util.List; - import org.lflang.Target; public class AuthProperty extends DefaultBooleanProperty { - @Override - public List supportedTargets() { - return Arrays.asList(Target.C, Target.CCPP); - } - + @Override + public List supportedTargets() { + return Arrays.asList(Target.C, Target.CCPP); + } } diff --git a/core/src/main/java/org/lflang/target/property/BuildCommandsProperty.java b/core/src/main/java/org/lflang/target/property/BuildCommandsProperty.java index 2285d13a27..1005001ef6 100644 --- a/core/src/main/java/org/lflang/target/property/BuildCommandsProperty.java +++ b/core/src/main/java/org/lflang/target/property/BuildCommandsProperty.java @@ -3,7 +3,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; - +import org.lflang.MessageReporter; import org.lflang.Target; import org.lflang.TargetPropertyConfig; import org.lflang.ast.ASTUtils; @@ -12,29 +12,32 @@ public class BuildCommandsProperty extends TargetPropertyConfig> { - - public BuildCommandsProperty() { - super(UnionType.STRING_OR_STRING_ARRAY); - } - - @Override - public List initialValue() { - return new ArrayList<>(); - } - - @Override - public List fromAstElement(Element value) { - return ASTUtils.elementToListOfStrings(value); - } - - @Override - public List supportedTargets() { - return Arrays.asList(Target.C, Target.CCPP); - } - - @Override - public Element toAstElement() { - return ASTUtils.toElement(this.value.toString()); - } - + public BuildCommandsProperty() { + super(UnionType.STRING_OR_STRING_ARRAY); + } + + @Override + public List initialValue() { + return new ArrayList<>(); + } + + @Override + public List fromAst(Element value, MessageReporter err) { + return ASTUtils.elementToListOfStrings(value); + } + + @Override + protected List fromString(String value, MessageReporter err) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public List supportedTargets() { + return Arrays.asList(Target.C, Target.CCPP); + } + + @Override + public Element toAstElement() { + return ASTUtils.toElement(this.value.toString()); + } } diff --git a/core/src/main/java/org/lflang/target/property/BuildConfig.java b/core/src/main/java/org/lflang/target/property/BuildConfig.java index e9af8402c9..5d1ea7c8e3 100644 --- a/core/src/main/java/org/lflang/target/property/BuildConfig.java +++ b/core/src/main/java/org/lflang/target/property/BuildConfig.java @@ -2,31 +2,31 @@ public class BuildConfig { - /** - * Enumeration of Cmake build types. These are also mapped to Cargo profiles for the Rust target - * (see {@link org.lflang.generator.rust.RustTargetConfig}) - * - * @author Christian Menard - */ - public enum BuildType { - RELEASE("Release"), - DEBUG("Debug"), - TEST("Test"), - REL_WITH_DEB_INFO("RelWithDebInfo"), - MIN_SIZE_REL("MinSizeRel"); + /** + * Enumeration of Cmake build types. These are also mapped to Cargo profiles for the Rust target + * (see {@link org.lflang.generator.rust.RustTargetConfig}) + * + * @author Christian Menard + */ + public enum BuildType { + RELEASE("Release"), + DEBUG("Debug"), + TEST("Test"), + REL_WITH_DEB_INFO("RelWithDebInfo"), + MIN_SIZE_REL("MinSizeRel"); - /** Alias used in toString method. */ - private final String alias; + /** Alias used in toString method. */ + private final String alias; - /** Private constructor for Cmake build types. */ - BuildType(String alias) { - this.alias = alias; - } + /** Private constructor for Cmake build types. */ + BuildType(String alias) { + this.alias = alias; + } - /** Return the alias. */ - @Override - public String toString() { - return this.alias; - } + /** Return the alias. */ + @Override + public String toString() { + return this.alias; } + } } diff --git a/core/src/main/java/org/lflang/target/property/BuildTypeProperty.java b/core/src/main/java/org/lflang/target/property/BuildTypeProperty.java index 1ce941c42b..d4d3e2cee6 100644 --- a/core/src/main/java/org/lflang/target/property/BuildTypeProperty.java +++ b/core/src/main/java/org/lflang/target/property/BuildTypeProperty.java @@ -2,10 +2,8 @@ import java.util.Arrays; import java.util.List; -import java.util.Properties; - +import org.lflang.MessageReporter; import org.lflang.Target; -import org.lflang.TargetProperty; import org.lflang.TargetPropertyConfig; import org.lflang.ast.ASTUtils; import org.lflang.lf.Element; @@ -14,37 +12,32 @@ public class BuildTypeProperty extends TargetPropertyConfig { - public BuildTypeProperty() { - super(UnionType.BUILD_TYPE_UNION); - } - - @Override - public Element toAstElement() { - return ASTUtils.toElement(this.value.toString()); - } - - @Override - public BuildType initialValue() { - return BuildType.RELEASE; - } - - @Override - public BuildType fromAstElement(Element value) { - return (BuildType) UnionType.BUILD_TYPE_UNION.forName(ASTUtils.elementToSingleString(value)); - } - - @Override - public List supportedTargets() { - return Arrays.asList(Target.C, Target.CCPP, Target.CPP, Target.Rust); - } - - @Override - public void update(Properties cliArgs) { - super.update(cliArgs); - var key = TargetProperty.BUILD_TYPE.toString(); - if (cliArgs.containsKey(key)) { - this.value = - (BuildType) UnionType.BUILD_TYPE_UNION.forName(cliArgs.getProperty(key)); - } - } + public BuildTypeProperty() { + super(UnionType.BUILD_TYPE_UNION); + } + + @Override + public Element toAstElement() { + return ASTUtils.toElement(this.value.toString()); + } + + @Override + public BuildType initialValue() { + return BuildType.RELEASE; + } + + @Override + public BuildType fromAst(Element value, MessageReporter err) { + return fromString(ASTUtils.elementToSingleString(value), err); + } + + @Override + protected BuildType fromString(String value, MessageReporter err) { + return (BuildType) UnionType.BUILD_TYPE_UNION.forName(value); + } + + @Override + public List supportedTargets() { + return Arrays.asList(Target.C, Target.CCPP, Target.CPP, Target.Rust); + } } 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 9672567c7f..431bac4935 100644 --- a/core/src/main/java/org/lflang/target/property/CargoDependenciesProperty.java +++ b/core/src/main/java/org/lflang/target/property/CargoDependenciesProperty.java @@ -4,7 +4,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; - +import org.lflang.MessageReporter; import org.lflang.Target; import org.lflang.TargetPropertyConfig; import org.lflang.generator.rust.CargoDependencySpec; @@ -14,44 +14,49 @@ import org.lflang.lf.KeyValuePairs; import org.lflang.lf.LfFactory; -public class CargoDependenciesProperty extends TargetPropertyConfig> { - - public CargoDependenciesProperty() { - super(CargoDependenciesPropertyType.INSTANCE); - } - - @Override - public Map initialValue() { - return new HashMap<>(); - } - - @Override - protected Map fromAstElement(Element value) { - return CargoDependencySpec.parseAll(value); +public class CargoDependenciesProperty + extends TargetPropertyConfig> { + + public CargoDependenciesProperty() { + super(CargoDependenciesPropertyType.INSTANCE); + } + + @Override + public Map initialValue() { + return new HashMap<>(); + } + + @Override + protected Map fromAst(Element value, MessageReporter err) { + return CargoDependencySpec.parseAll(value); + } + + @Override + protected Map fromString(String value, MessageReporter err) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public List supportedTargets() { + return Arrays.asList(Target.Rust); + } + + @Override + public Element toAstElement() { + var deps = this.value; + if (deps.size() == 0) { + return null; + } else { + Element e = LfFactory.eINSTANCE.createElement(); + KeyValuePairs kvp = LfFactory.eINSTANCE.createKeyValuePairs(); + for (var ent : deps.entrySet()) { + KeyValuePair pair = LfFactory.eINSTANCE.createKeyValuePair(); + pair.setName(ent.getKey()); + pair.setValue(CargoDependencySpec.extractSpec(ent.getValue())); + kvp.getPairs().add(pair); + } + e.setKeyvalue(kvp); + return e; } - - @Override - public List supportedTargets() { - return Arrays.asList(Target.Rust); - } - - @Override - public Element toAstElement() { - var deps = this.value; - if (deps.size() == 0) { - return null; - } else { - Element e = LfFactory.eINSTANCE.createElement(); - KeyValuePairs kvp = LfFactory.eINSTANCE.createKeyValuePairs(); - for (var ent : deps.entrySet()) { - KeyValuePair pair = LfFactory.eINSTANCE.createKeyValuePair(); - pair.setName(ent.getKey()); - pair.setValue(CargoDependencySpec.extractSpec(ent.getValue())); - kvp.getPairs().add(pair); - } - e.setKeyvalue(kvp); - return e; - } - } - + } } diff --git a/core/src/main/java/org/lflang/target/property/CargoFeaturesProperty.java b/core/src/main/java/org/lflang/target/property/CargoFeaturesProperty.java index e870154681..92d8d498be 100644 --- a/core/src/main/java/org/lflang/target/property/CargoFeaturesProperty.java +++ b/core/src/main/java/org/lflang/target/property/CargoFeaturesProperty.java @@ -2,14 +2,12 @@ import java.util.Arrays; import java.util.List; - import org.lflang.Target; public class CargoFeaturesProperty extends DefaultStringListProperty { - @Override - public List supportedTargets() { - return Arrays.asList(Target.Rust); - } - + @Override + public List supportedTargets() { + return Arrays.asList(Target.Rust); + } } 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 d9d8d14810..2e286f4bec 100644 --- a/core/src/main/java/org/lflang/target/property/ClockSyncModeProperty.java +++ b/core/src/main/java/org/lflang/target/property/ClockSyncModeProperty.java @@ -1,10 +1,8 @@ package org.lflang.target.property; - -import java.util.Arrays; import java.util.List; import java.util.Objects; - +import org.lflang.MessageReporter; import org.lflang.Target; import org.lflang.TargetConfig; import org.lflang.TargetPropertyConfig; @@ -16,79 +14,78 @@ import org.lflang.lf.Reactor; import org.lflang.target.property.ClockSyncModeProperty.ClockSyncMode; import org.lflang.target.property.type.UnionType; -import org.lflang.validation.ValidationReporter; public class ClockSyncModeProperty extends TargetPropertyConfig { + public ClockSyncModeProperty() { + super(UnionType.CLOCK_SYNC_UNION); + } - public ClockSyncModeProperty() { - super(UnionType.CLOCK_SYNC_UNION); - } + @Override + public ClockSyncMode initialValue() { + return ClockSyncMode.INIT; + } - @Override - public ClockSyncMode initialValue() { - return ClockSyncMode.INIT; - } + @Override + public ClockSyncMode fromAst(Element value, MessageReporter err) { + UnionType.CLOCK_SYNC_UNION.validate(value); + var mode = fromString(ASTUtils.elementToSingleString(value), err); + return Objects.requireNonNullElse(mode, ClockSyncMode.INIT); + } - @Override - public ClockSyncMode fromAstElement(Element value) { + @Override + protected ClockSyncMode fromString(String value, MessageReporter err) { + return (ClockSyncMode) UnionType.CLOCK_SYNC_UNION.forName(value); + } - UnionType.CLOCK_SYNC_UNION.validate(value); - var mode = (ClockSyncMode) - UnionType.CLOCK_SYNC_UNION.forName(ASTUtils.elementToSingleString(value)); - return Objects.requireNonNullElse(mode, ClockSyncMode.INIT); - } + @Override + public List supportedTargets() { + return List.of(Target.C, Target.CCPP, Target.Python); + } - @Override - public List supportedTargets() { - return Arrays.asList(Target.C, Target.CCPP, Target.Python); - } - - @Override - public void validate(KeyValuePair pair, Model ast, TargetConfig config, ValidationReporter reporter) { - super.validate(pair, ast, config, reporter); - if (pair != null) { - boolean federatedExists = false; - for (Reactor reactor : ast.getReactors()) { - if (reactor.isFederated()) { - federatedExists = true; - } - } - if (!federatedExists) { - reporter.warning( - "The clock-sync target property is incompatible with non-federated programs.", - pair, - Literals.KEY_VALUE_PAIR__NAME); - } + @Override + public void validate( + KeyValuePair pair, Model ast, TargetConfig config, MessageReporter reporter) { + super.validate(pair, ast, config, 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."); + } } + } - @Override - public Element toAstElement() { - return ASTUtils.toElement(this.value.toString()); - } - - + @Override + public Element toAstElement() { + return ASTUtils.toElement(this.value.toString()); + } - /** - * Enumeration of clock synchronization modes. - * - *
    - *
  • OFF: The clock synchronization is universally off. - *
  • STARTUP: Clock synchronization occurs at startup only. - *
  • ON: Clock synchronization occurs at startup and at runtime. - *
- * - * @author Edward A. Lee - */ - public enum ClockSyncMode { - OFF, - INIT, - ON; - /** Return the name in lower case. */ - @Override - public String toString() { - return this.name().toLowerCase(); - } + /** + * Enumeration of clock synchronization modes. + * + *
    + *
  • OFF: The clock synchronization is universally off. + *
  • STARTUP: Clock synchronization occurs at startup only. + *
  • ON: Clock synchronization occurs at startup and at runtime. + *
+ * + * @author Edward A. Lee + */ + public enum ClockSyncMode { + OFF, + INIT, + ON; + /** Return the name in lower case. */ + @Override + public String toString() { + return this.name().toLowerCase(); } + } } 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 1d658a67e6..4f13bf5878 100644 --- a/core/src/main/java/org/lflang/target/property/ClockSyncOptionsProperty.java +++ b/core/src/main/java/org/lflang/target/property/ClockSyncOptionsProperty.java @@ -2,7 +2,7 @@ import java.util.Arrays; import java.util.List; - +import org.lflang.MessageReporter; import org.lflang.Target; import org.lflang.TargetProperty.DictionaryElement; import org.lflang.TargetPropertyConfig; @@ -20,143 +20,143 @@ public class ClockSyncOptionsProperty extends TargetPropertyConfig { - public ClockSyncOptionsProperty() { - super(DictionaryType.CLOCK_SYNC_OPTION_DICT); - } - - @Override - public ClockSyncOptions initialValue() { - return new ClockSyncOptions(); + public ClockSyncOptionsProperty() { + super(DictionaryType.CLOCK_SYNC_OPTION_DICT); + } + + @Override + public ClockSyncOptions initialValue() { + return new ClockSyncOptions(); + } + + @Override + public ClockSyncOptions fromAst(Element value, MessageReporter err) { + var options = new ClockSyncOptions(); + for (KeyValuePair entry : value.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 -> {} + } } - - @Override - public ClockSyncOptions fromAstElement(Element value) { - var options = new ClockSyncOptions(); - for (KeyValuePair entry : value.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 -> { - } - } + return options; + } + + @Override + protected ClockSyncOptions fromString(String value, MessageReporter err) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public List supportedTargets() { + return Arrays.asList(Target.C, Target.CCPP, Target.Python); + } + + @Override + public Element toAstElement() { + Element e = LfFactory.eINSTANCE.createElement(); + KeyValuePairs kvp = LfFactory.eINSTANCE.createKeyValuePairs(); + for (ClockSyncOption opt : ClockSyncOption.values()) { + KeyValuePair pair = LfFactory.eINSTANCE.createKeyValuePair(); + pair.setName(opt.toString()); + switch (opt) { + case ATTENUATION -> pair.setValue(ASTUtils.toElement(value.attenuation)); + case COLLECT_STATS -> pair.setValue(ASTUtils.toElement(value.collectStats)); + case LOCAL_FEDERATES_ON -> pair.setValue(ASTUtils.toElement(value.localFederatesOn)); + case PERIOD -> { + if (value.period == null) { + continue; // don't set if null + } + pair.setValue(ASTUtils.toElement(value.period)); } - return options; - } - - @Override - public List supportedTargets() { - return Arrays.asList(Target.C, Target.CCPP, Target.Python); - } - - @Override - public Element toAstElement() { - Element e = LfFactory.eINSTANCE.createElement(); - KeyValuePairs kvp = LfFactory.eINSTANCE.createKeyValuePairs(); - for (ClockSyncOption opt : ClockSyncOption.values()) { - KeyValuePair pair = LfFactory.eINSTANCE.createKeyValuePair(); - pair.setName(opt.toString()); - switch (opt) { - case ATTENUATION -> pair.setValue(ASTUtils.toElement(value.attenuation)); - case COLLECT_STATS -> pair.setValue(ASTUtils.toElement(value.collectStats)); - case LOCAL_FEDERATES_ON -> pair.setValue(ASTUtils.toElement(value.localFederatesOn)); - case PERIOD -> { - if (value.period == null) { - continue; // don't set if null - } - pair.setValue(ASTUtils.toElement(value.period)); - } - case TEST_OFFSET -> { - if (value.testOffset == null) { - continue; // don't set if null - } - pair.setValue(ASTUtils.toElement(value.testOffset)); - } - case TRIALS -> pair.setValue(ASTUtils.toElement(value.trials)); - } - kvp.getPairs().add(pair); + case TEST_OFFSET -> { + if (value.testOffset == null) { + continue; // don't set if null + } + pair.setValue(ASTUtils.toElement(value.testOffset)); } - e.setKeyvalue(kvp); - // kvp will never be empty - return e; - } - - /** Settings related to clock synchronization. */ - public static class ClockSyncOptions { - - /** - * Dampen the adjustments to the clock synchronization offset by this rate. The default is 10. - */ - public int attenuation = 10; - - /** - * Whether to collect statistics while performing clock synchronization. This setting is only - * considered when clock synchronization has been activated. The default is true. - */ - public boolean collectStats = true; - - /** Enable clock synchronization for federates on the same machine. Default is false. */ - public boolean localFederatesOn = false; - - /** - * Interval at which clock synchronization is initiated by the RTI (will be passed to it as an - * argument on the command-line). The default is 5 milliseconds. - */ - public TimeValue period = new TimeValue(5, TimeUnit.MILLI); - - /** - * Indicate the number of exchanges to be had per each clock synchronization round. See - * /lib/core/federated/clock-sync.h for more details. The default is 10. - */ - public int trials = 10; - - /** - * Used to create an artificial clock synchronization error for the purpose of testing. The - * default is null. - */ - public TimeValue testOffset; + case TRIALS -> pair.setValue(ASTUtils.toElement(value.trials)); + } + kvp.getPairs().add(pair); } + e.setKeyvalue(kvp); + // kvp will never be empty + return e; + } + /** Settings related to clock synchronization. */ + public static class ClockSyncOptions { + /** + * Dampen the adjustments to the clock synchronization offset by this rate. The default is 10. + */ + public int attenuation = 10; /** - * Clock synchronization options. - * - * @author Marten Lohstroh + * Whether to collect statistics while performing clock synchronization. This setting is only + * considered when clock synchronization has been activated. The default is true. */ - public enum ClockSyncOption implements DictionaryElement { - ATTENUATION("attenuation", PrimitiveType.NON_NEGATIVE_INTEGER), - LOCAL_FEDERATES_ON("local-federates-on", PrimitiveType.BOOLEAN), - PERIOD("period", PrimitiveType.TIME_VALUE), - TEST_OFFSET("test-offset", PrimitiveType.TIME_VALUE), - TRIALS("trials", PrimitiveType.NON_NEGATIVE_INTEGER), - COLLECT_STATS("collect-stats", PrimitiveType.BOOLEAN); + public boolean collectStats = true; - public final PrimitiveType type; + /** Enable clock synchronization for federates on the same machine. Default is false. */ + public boolean localFederatesOn = false; - private final String description; + /** + * Interval at which clock synchronization is initiated by the RTI (will be passed to it as an + * argument on the command-line). The default is 5 milliseconds. + */ + public TimeValue period = new TimeValue(5, TimeUnit.MILLI); - ClockSyncOption(String alias, PrimitiveType type) { - this.description = alias; - this.type = type; - } + /** + * Indicate the number of exchanges to be had per each clock synchronization round. See + * /lib/core/federated/clock-sync.h for more details. The default is 10. + */ + public int trials = 10; - /** Return the description of this dictionary element. */ - @Override - public String toString() { - return this.description; - } + /** + * Used to create an artificial clock synchronization error for the purpose of testing. The + * default is null. + */ + public TimeValue testOffset; + } + + /** + * Clock synchronization options. + * + * @author Marten Lohstroh + */ + public enum ClockSyncOption implements DictionaryElement { + ATTENUATION("attenuation", PrimitiveType.NON_NEGATIVE_INTEGER), + LOCAL_FEDERATES_ON("local-federates-on", PrimitiveType.BOOLEAN), + PERIOD("period", PrimitiveType.TIME_VALUE), + TEST_OFFSET("test-offset", PrimitiveType.TIME_VALUE), + TRIALS("trials", PrimitiveType.NON_NEGATIVE_INTEGER), + COLLECT_STATS("collect-stats", PrimitiveType.BOOLEAN); + + public final PrimitiveType type; + + private final String description; + + ClockSyncOption(String alias, PrimitiveType type) { + this.description = alias; + this.type = type; + } - /** Return the type associated with this dictionary element. */ - public TargetPropertyType getType() { - return this.type; - } + /** Return the description of this dictionary element. */ + @Override + public String toString() { + return this.description; } + /** Return the type associated with this dictionary element. */ + public TargetPropertyType getType() { + return this.type; + } + } } diff --git a/core/src/main/java/org/lflang/target/property/CmakeIncludeProperty.java b/core/src/main/java/org/lflang/target/property/CmakeIncludeProperty.java index 29ff2f8f6d..6ffcb81336 100644 --- a/core/src/main/java/org/lflang/target/property/CmakeIncludeProperty.java +++ b/core/src/main/java/org/lflang/target/property/CmakeIncludeProperty.java @@ -3,7 +3,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; - import org.lflang.MessageReporter; import org.lflang.Target; import org.lflang.TargetPropertyConfig; @@ -13,47 +12,45 @@ public class CmakeIncludeProperty extends TargetPropertyConfig> { - public CmakeIncludeProperty() { - super(UnionType.FILE_OR_FILE_ARRAY); - } - - @Override - public List initialValue() { - return new ArrayList<>(); - } - - - @Override - public void set(Element value, MessageReporter err) { - if (!this.isSet) { - super.set(value, err); - } else { - // NOTE: This merging of lists is potentially dangerous since - // the incoming list of cmake-includes can belong to a .lf file that is - // located in a different location, and keeping just filename - // strings like this without absolute paths is incorrect. - this.value.addAll(ASTUtils.elementToListOfStrings(value)); - } - - } - - @Override - protected List fromAst(Element value, MessageReporter err) { - return ASTUtils.elementToListOfStrings(value); - } - - @Override - protected List fromString(String value, MessageReporter err) { - return null; // FIXME: not sure about this one - } - - @Override - public List supportedTargets() { - return Arrays.asList(Target.CPP, Target.C, Target.CCPP); - } - - @Override - public Element toAstElement() { - return ASTUtils.toElement(this.value); + public CmakeIncludeProperty() { + super(UnionType.FILE_OR_FILE_ARRAY); + } + + @Override + public List initialValue() { + return new ArrayList<>(); + } + + @Override + public void set(Element value, MessageReporter err) { + if (!this.isSet) { + super.set(value, err); + } else { + // NOTE: This merging of lists is potentially dangerous since + // the incoming list of cmake-includes can belong to a .lf file that is + // located in a different location, and keeping just filename + // strings like this without absolute paths is incorrect. + this.value.addAll(ASTUtils.elementToListOfStrings(value)); } + } + + @Override + protected List fromAst(Element value, MessageReporter err) { + return ASTUtils.elementToListOfStrings(value); + } + + @Override + protected List fromString(String value, MessageReporter err) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public List supportedTargets() { + return Arrays.asList(Target.CPP, Target.C, Target.CCPP); + } + + @Override + public Element toAstElement() { + return ASTUtils.toElement(this.value); + } } diff --git a/core/src/main/java/org/lflang/target/property/CompileDefinitionsConfig.java b/core/src/main/java/org/lflang/target/property/CompileDefinitionsConfig.java deleted file mode 100644 index d5927c1a0b..0000000000 --- a/core/src/main/java/org/lflang/target/property/CompileDefinitionsConfig.java +++ /dev/null @@ -1,38 +0,0 @@ -package org.lflang.target.property.type; - -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.lflang.Target; -import org.lflang.TargetPropertyConfig; -import org.lflang.ast.ASTUtils; -import org.lflang.lf.Element; - -public class CompileDefinitionsConfig extends TargetPropertyConfig> { - - public CompileDefinitionsConfig() { - super(StringDictionaryType.COMPILE_DEFINITION); - } - - @Override - public Map initialValue() { - return new HashMap<>(); - } - - @Override - protected Map fromAstElement(Element value) { - return ASTUtils.elementToStringMaps(value); - } - - @Override - public List supportedTargets() { - return Arrays.asList(Target.C, Target.CCPP, Target.Python); - } - - @Override - public Element toAstElement() { - return ASTUtils.toElement(this.value); - } -} diff --git a/core/src/main/java/org/lflang/target/property/CompileDefinitionsProperty.java b/core/src/main/java/org/lflang/target/property/CompileDefinitionsProperty.java new file mode 100644 index 0000000000..8b77b37935 --- /dev/null +++ b/core/src/main/java/org/lflang/target/property/CompileDefinitionsProperty.java @@ -0,0 +1,44 @@ +package org.lflang.target.property; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.lflang.MessageReporter; +import org.lflang.Target; +import org.lflang.TargetPropertyConfig; +import org.lflang.ast.ASTUtils; +import org.lflang.lf.Element; +import org.lflang.target.property.type.StringDictionaryType; + +public class CompileDefinitionsProperty extends TargetPropertyConfig> { + + public CompileDefinitionsProperty() { + super(StringDictionaryType.COMPILE_DEFINITION); + } + + @Override + public Map initialValue() { + return new HashMap<>(); + } + + @Override + protected Map fromAst(Element value, MessageReporter err) { + return ASTUtils.elementToStringMaps(value); + } + + @Override + protected Map fromString(String value, MessageReporter err) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public List supportedTargets() { + return Arrays.asList(Target.C, Target.CCPP, Target.Python); + } + + @Override + public Element toAstElement() { + return ASTUtils.toElement(this.value); + } +} diff --git a/core/src/main/java/org/lflang/target/property/CompilerFlagsProperty.java b/core/src/main/java/org/lflang/target/property/CompilerFlagsProperty.java index da1df83b44..df7ec8c9d8 100644 --- a/core/src/main/java/org/lflang/target/property/CompilerFlagsProperty.java +++ b/core/src/main/java/org/lflang/target/property/CompilerFlagsProperty.java @@ -2,14 +2,12 @@ import java.util.Arrays; import java.util.List; - import org.lflang.Target; public class CompilerFlagsProperty extends DefaultStringListProperty { - @Override - public List supportedTargets() { - return Arrays.asList(Target.C, Target.CCPP); - } - + @Override + public List supportedTargets() { + return Arrays.asList(Target.C, Target.CCPP); + } } diff --git a/core/src/main/java/org/lflang/target/property/CompilerProperty.java b/core/src/main/java/org/lflang/target/property/CompilerProperty.java new file mode 100644 index 0000000000..9c35d5d260 --- /dev/null +++ b/core/src/main/java/org/lflang/target/property/CompilerProperty.java @@ -0,0 +1,12 @@ +package org.lflang.target.property; + +import java.util.List; +import org.lflang.Target; + +public class CompilerProperty extends DefaultStringConfig { + + @Override + public List supportedTargets() { + return Target.ALL; + } +} diff --git a/core/src/main/java/org/lflang/target/property/CoordinationModeProperty.java b/core/src/main/java/org/lflang/target/property/CoordinationModeProperty.java index 96efe0de31..357ea9a818 100644 --- a/core/src/main/java/org/lflang/target/property/CoordinationModeProperty.java +++ b/core/src/main/java/org/lflang/target/property/CoordinationModeProperty.java @@ -2,7 +2,7 @@ import java.util.Arrays; import java.util.List; - +import org.lflang.MessageReporter; import org.lflang.Target; import org.lflang.TargetConfig; import org.lflang.TargetPropertyConfig; @@ -12,51 +12,55 @@ import org.lflang.lf.Model; import org.lflang.target.property.CoordinationModeProperty.CoordinationMode; import org.lflang.target.property.type.UnionType; -import org.lflang.validation.ValidationReporter; public class CoordinationModeProperty extends TargetPropertyConfig { - public CoordinationModeProperty() { - super(UnionType.COORDINATION_UNION); - } + public CoordinationModeProperty() { + super(UnionType.COORDINATION_UNION); + } - @Override - public CoordinationMode initialValue() { - return CoordinationMode.CENTRALIZED; - } + @Override + public CoordinationMode initialValue() { + return CoordinationMode.CENTRALIZED; + } - @Override - public CoordinationMode fromAstElement(Element value) { - return (CoordinationMode) UnionType.COORDINATION_UNION.forName(ASTUtils.elementToSingleString(value)); - } + @Override + public CoordinationMode fromAst(Element value, MessageReporter err) { + return fromString(ASTUtils.elementToSingleString(value), err); + } - @Override - public List supportedTargets() { - return Arrays.asList(Target.C, Target.CCPP, Target.Python); - } + @Override + protected CoordinationMode fromString(String value, MessageReporter err) { + return (CoordinationMode) UnionType.COORDINATION_UNION.forName(value); + } - @Override - public void validate(KeyValuePair pair, Model ast, TargetConfig config, ValidationReporter reporter) {} + @Override + public List supportedTargets() { + return Arrays.asList(Target.C, Target.CCPP, Target.Python); + } - @Override - public Element toAstElement() { - return ASTUtils.toElement(this.value.toString()); - } + @Override + public void validate( + KeyValuePair pair, Model ast, TargetConfig config, MessageReporter reporter) {} - /** - * Enumeration of coordination types. - * - * @author Marten Lohstroh - */ - public enum CoordinationMode { - CENTRALIZED, - DECENTRALIZED; - - /** Return the name in lower case. */ - @Override - public String toString() { - return this.name().toLowerCase(); - } - } + @Override + public Element toAstElement() { + return ASTUtils.toElement(this.value.toString()); + } + /** + * Enumeration of coordination types. + * + * @author Marten Lohstroh + */ + public enum CoordinationMode { + CENTRALIZED, + DECENTRALIZED; + + /** Return the name in lower case. */ + @Override + public String toString() { + return this.name().toLowerCase(); + } + } } 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 2844e4e0f2..23af1705ba 100644 --- a/core/src/main/java/org/lflang/target/property/CoordinationOptionsProperty.java +++ b/core/src/main/java/org/lflang/target/property/CoordinationOptionsProperty.java @@ -2,7 +2,8 @@ import java.util.Arrays; import java.util.List; - +import java.util.Objects; +import org.lflang.MessageReporter; import org.lflang.Target; import org.lflang.TargetProperty.DictionaryElement; import org.lflang.TargetPropertyConfig; @@ -12,7 +13,6 @@ import org.lflang.lf.KeyValuePair; import org.lflang.lf.KeyValuePairs; import org.lflang.lf.LfFactory; - import org.lflang.target.property.CoordinationOptionsProperty.CoordinationOptions; import org.lflang.target.property.type.DictionaryType; import org.lflang.target.property.type.PrimitiveType; @@ -20,104 +20,100 @@ public class CoordinationOptionsProperty extends TargetPropertyConfig { - public CoordinationOptionsProperty() { - super(DictionaryType.COORDINATION_OPTION_DICT); - } - - @Override - public CoordinationOptions initialValue() { - return new CoordinationOptions(); + public CoordinationOptionsProperty() { + super(DictionaryType.COORDINATION_OPTION_DICT); + } + + @Override + public CoordinationOptions initialValue() { + return new CoordinationOptions(); + } + + @Override + public CoordinationOptions fromAst(Element value, MessageReporter err) { + var options = new CoordinationOptions(); + for (KeyValuePair entry : value.getKeyvalue().getPairs()) { + CoordinationOption option = + (CoordinationOption) DictionaryType.COORDINATION_OPTION_DICT.forName(entry.getName()); + if (Objects.requireNonNull(option) == CoordinationOption.ADVANCE_MESSAGE_INTERVAL) { + options.advanceMessageInterval = ASTUtils.toTimeValue(entry.getValue()); + } } - - @Override - public CoordinationOptions fromAstElement(Element value) { - var options = new CoordinationOptions(); - for (KeyValuePair entry : value.getKeyvalue().getPairs()) { - CoordinationOption option = - (CoordinationOption) DictionaryType.COORDINATION_OPTION_DICT.forName(entry.getName()); - switch (option) { - case ADVANCE_MESSAGE_INTERVAL: - options.advanceMessageInterval = - ASTUtils.toTimeValue(entry.getValue()); - break; - default: - break; - } + return options; + } + + @Override + protected CoordinationOptions fromString(String value, MessageReporter err) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public List supportedTargets() { + return Arrays.asList(Target.C, Target.CCPP, Target.Python, Target.TS); + } + + @Override + public Element toAstElement() { + Element e = LfFactory.eINSTANCE.createElement(); + KeyValuePairs kvp = LfFactory.eINSTANCE.createKeyValuePairs(); + for (CoordinationOption opt : CoordinationOption.values()) { + KeyValuePair pair = LfFactory.eINSTANCE.createKeyValuePair(); + pair.setName(opt.toString()); + if (opt == CoordinationOption.ADVANCE_MESSAGE_INTERVAL) { + if (this.value.advanceMessageInterval == null) { + continue; } - return options; + pair.setValue(ASTUtils.toElement(value.advanceMessageInterval)); + } + kvp.getPairs().add(pair); } - - @Override - public List supportedTargets() { - return Arrays.asList(Target.C, Target.CCPP, Target.Python, Target.TS); + e.setKeyvalue(kvp); + if (kvp.getPairs().isEmpty()) { + return null; } + return e; + } - @Override - public Element toAstElement() { - Element e = LfFactory.eINSTANCE.createElement(); - KeyValuePairs kvp = LfFactory.eINSTANCE.createKeyValuePairs(); - for (CoordinationOption opt : CoordinationOption.values()) { - KeyValuePair pair = LfFactory.eINSTANCE.createKeyValuePair(); - pair.setName(opt.toString()); - switch (opt) { - case ADVANCE_MESSAGE_INTERVAL: - if (this.value.advanceMessageInterval == null) { - continue; - } - pair.setValue( - ASTUtils.toElement(value.advanceMessageInterval)); - break; - } - kvp.getPairs().add(pair); - } - e.setKeyvalue(kvp); - if (kvp.getPairs().isEmpty()) { - return null; - } - return e; - } - - /** Settings related to coordination of federated execution. */ - public static class CoordinationOptions { - - /** - * For centralized coordination, if a federate has a physical action that can trigger an output, - * directly or indirectly, then it will send NET (next event tag) messages to the RTI - * periodically as its physical clock advances. This option sets the amount of time to wait - * between sending such messages. Increasing this value results in downstream federates that lag - * further behind physical time (if the "after" delays are insufficient). The default is null, - * which means it is up the implementation to choose an interval. - */ - public TimeValue advanceMessageInterval = null; - } + /** Settings related to coordination of federated execution. */ + public static class CoordinationOptions { /** - * Coordination options. - * - * @author Edward A. Lee + * For centralized coordination, if a federate has a physical action that can trigger an output, + * directly or indirectly, then it will send NET (next event tag) messages to the RTI + * periodically as its physical clock advances. This option sets the amount of time to wait + * between sending such messages. Increasing this value results in downstream federates that lag + * further behind physical time (if the "after" delays are insufficient). The default is null, + * which means it is up the implementation to choose an interval. */ - public enum CoordinationOption implements DictionaryElement { - ADVANCE_MESSAGE_INTERVAL("advance-message-interval", PrimitiveType.TIME_VALUE); + public TimeValue advanceMessageInterval = null; + } - public final PrimitiveType type; + /** + * Coordination options. + * + * @author Edward A. Lee + */ + public enum CoordinationOption implements DictionaryElement { + ADVANCE_MESSAGE_INTERVAL("advance-message-interval", PrimitiveType.TIME_VALUE); - private final String description; + public final PrimitiveType type; - private CoordinationOption(String alias, PrimitiveType type) { - this.description = alias; - this.type = type; - } + private final String description; - /** Return the description of this dictionary element. */ - @Override - public String toString() { - return this.description; - } + CoordinationOption(String alias, PrimitiveType type) { + this.description = alias; + this.type = type; + } - /** Return the type associated with this dictionary element. */ - public TargetPropertyType getType() { - return this.type; - } + /** Return the description of this dictionary element. */ + @Override + public String toString() { + return this.description; } + /** Return the type associated with this dictionary element. */ + public TargetPropertyType getType() { + return this.type; + } + } } diff --git a/core/src/main/java/org/lflang/target/property/DefaultBooleanProperty.java b/core/src/main/java/org/lflang/target/property/DefaultBooleanProperty.java index 4e141f624e..2a5b29eeb5 100644 --- a/core/src/main/java/org/lflang/target/property/DefaultBooleanProperty.java +++ b/core/src/main/java/org/lflang/target/property/DefaultBooleanProperty.java @@ -1,36 +1,34 @@ package org.lflang.target.property; - import org.lflang.MessageReporter; import org.lflang.TargetPropertyConfig; import org.lflang.ast.ASTUtils; import org.lflang.lf.Element; import org.lflang.target.property.type.PrimitiveType; - public abstract class DefaultBooleanProperty extends TargetPropertyConfig { - public DefaultBooleanProperty() { - super(PrimitiveType.BOOLEAN); - } - - @Override - public Boolean initialValue() { - return false; - } - - @Override - public Boolean fromAst(Element value, MessageReporter err) { - return ASTUtils.toBoolean(value); - } - - @Override - protected Boolean fromString(String value, MessageReporter err) { - return Boolean.parseBoolean(value); - } - - @Override - public Element toAstElement() { - return ASTUtils.toElement(value); - } + public DefaultBooleanProperty() { + super(PrimitiveType.BOOLEAN); + } + + @Override + public Boolean initialValue() { + return false; + } + + @Override + public Boolean fromAst(Element value, MessageReporter err) { + return ASTUtils.toBoolean(value); + } + + @Override + protected Boolean fromString(String value, MessageReporter err) { + return Boolean.parseBoolean(value); + } + + @Override + public Element toAstElement() { + return ASTUtils.toElement(value); + } } diff --git a/core/src/main/java/org/lflang/target/property/DefaultFileListProperty.java b/core/src/main/java/org/lflang/target/property/DefaultFileListProperty.java index a743c5b218..cf35d54ea7 100644 --- a/core/src/main/java/org/lflang/target/property/DefaultFileListProperty.java +++ b/core/src/main/java/org/lflang/target/property/DefaultFileListProperty.java @@ -1,39 +1,45 @@ package org.lflang.target.property; - import java.util.ArrayList; import java.util.List; - +import org.lflang.MessageReporter; import org.lflang.TargetPropertyConfig; import org.lflang.ast.ASTUtils; import org.lflang.lf.Element; import org.lflang.target.property.type.UnionType; - public abstract class DefaultFileListProperty extends TargetPropertyConfig> { - public DefaultFileListProperty() { - super(UnionType.FILE_OR_FILE_ARRAY); - } - - @Override - public void override(List value) { // FIXME: should this be override or update? - this.isSet = true; - this.value.addAll(value); - } - - @Override - public List initialValue() { - return new ArrayList<>(); - } - - @Override - public List fromAstElement(Element value) { - return ASTUtils.elementToListOfStrings(value); - } - - @Override - public Element toAstElement() { - return ASTUtils.toElement(value); + public DefaultFileListProperty() { + super(UnionType.FILE_OR_FILE_ARRAY); + } + + @Override + public List initialValue() { + return new ArrayList<>(); + } + + @Override + public void set(Element value, MessageReporter err) { + if (!this.isSet) { + super.set(value, err); + } else { + this.value.addAll(fromAst(value, err)); } + } + + @Override + public List fromAst(Element value, MessageReporter err) { + return ASTUtils.elementToListOfStrings(value); + } + + @Override + protected List fromString(String value, MessageReporter err) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Element toAstElement() { + return ASTUtils.toElement(value); + } } diff --git a/core/src/main/java/org/lflang/target/property/DefaultStringConfig.java b/core/src/main/java/org/lflang/target/property/DefaultStringConfig.java index c81efba9d2..fde1825686 100644 --- a/core/src/main/java/org/lflang/target/property/DefaultStringConfig.java +++ b/core/src/main/java/org/lflang/target/property/DefaultStringConfig.java @@ -1,39 +1,34 @@ package org.lflang.target.property; - -import java.util.List; - import org.lflang.MessageReporter; -import org.lflang.Target; import org.lflang.TargetPropertyConfig; import org.lflang.ast.ASTUtils; import org.lflang.lf.Element; import org.lflang.target.property.type.PrimitiveType; - public abstract class DefaultStringConfig extends TargetPropertyConfig { - public DefaultStringConfig() { - super(PrimitiveType.STRING); - } - - @Override - public String initialValue() { - return ""; - } - - @Override - public String fromAst(Element value, MessageReporter err) { - return ASTUtils.elementToSingleString(value); - } - - @Override - protected String fromString(String value, MessageReporter err) { - return value; - } - - @Override - public Element toAstElement() { - return ASTUtils.toElement(value); - } + public DefaultStringConfig() { + super(PrimitiveType.STRING); + } + + @Override + public String initialValue() { + return ""; + } + + @Override + public String fromAst(Element value, MessageReporter err) { + return ASTUtils.elementToSingleString(value); + } + + @Override + protected String fromString(String value, MessageReporter err) { + return value; + } + + @Override + public Element toAstElement() { + return ASTUtils.toElement(value); + } } diff --git a/core/src/main/java/org/lflang/target/property/DefaultStringListProperty.java b/core/src/main/java/org/lflang/target/property/DefaultStringListProperty.java index fcbd5ced73..549496bb7e 100644 --- a/core/src/main/java/org/lflang/target/property/DefaultStringListProperty.java +++ b/core/src/main/java/org/lflang/target/property/DefaultStringListProperty.java @@ -1,61 +1,55 @@ package org.lflang.target.property; - import java.util.ArrayList; import java.util.List; - import org.lflang.MessageReporter; import org.lflang.TargetPropertyConfig; import org.lflang.ast.ASTUtils; import org.lflang.lf.Element; import org.lflang.target.property.type.UnionType; -/** - * Note: {@code set} implements an "append" semantics. - */ +/** Note: {@code set} implements an "append" semantics. */ public abstract class DefaultStringListProperty extends TargetPropertyConfig> { - public DefaultStringListProperty() { - super(UnionType.STRING_OR_STRING_ARRAY); - } - - @Override - public List initialValue() { - return new ArrayList<>(); + public DefaultStringListProperty() { + super(UnionType.STRING_OR_STRING_ARRAY); + } + + @Override + public List initialValue() { + return new ArrayList<>(); + } + + @Override + public void set(Element value, MessageReporter err) { + if (!this.isSet) { + super.set(value, err); + } else { + this.value.addAll(this.fromAst(value, err)); } - - @Override - public void set(Element value, MessageReporter err) { - if (!this.isSet) { - super.set(value, err); - } else { - this.value.addAll(this.fromAst(value, err)); - } - } - - @Override - public void set(String string, MessageReporter err) { - if (!this.isSet) { - super.set(string, err); - } else { - this.value.addAll(this.fromString(string, err)); - } + } + + @Override + public void set(String string, MessageReporter err) { + if (!this.isSet) { + super.set(string, err); + } else { + this.value.addAll(this.fromString(string, err)); } - - @Override - public List fromAst(Element value, MessageReporter err) { - return ASTUtils.elementToListOfStrings(value); - } - - @Override - protected List fromString(String value, MessageReporter err) { - return List.of(value.split(" ")); - } - - - @Override - public Element toAstElement() { - return ASTUtils.toElement(value); - } - + } + + @Override + public List fromAst(Element value, MessageReporter err) { + return ASTUtils.elementToListOfStrings(value); + } + + @Override + protected List fromString(String value, MessageReporter err) { + return List.of(value.split(" ")); + } + + @Override + public Element toAstElement() { + return ASTUtils.toElement(value); + } } 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 c3890c786b..83864ac96e 100644 --- a/core/src/main/java/org/lflang/target/property/DockerProperty.java +++ b/core/src/main/java/org/lflang/target/property/DockerProperty.java @@ -1,163 +1,144 @@ package org.lflang.target.property; - import java.util.Arrays; import java.util.List; -import java.util.Properties; - +import java.util.Objects; +import org.lflang.MessageReporter; import org.lflang.Target; -import org.lflang.TargetProperty; -import org.lflang.TargetPropertyConfig; import org.lflang.TargetProperty.DictionaryElement; +import org.lflang.TargetPropertyConfig; import org.lflang.ast.ASTUtils; +import org.lflang.lf.Element; +import org.lflang.lf.KeyValuePair; import org.lflang.lf.KeyValuePairs; import org.lflang.lf.LfFactory; import org.lflang.target.property.DockerProperty.DockerOptions; import org.lflang.target.property.type.DictionaryType; import org.lflang.target.property.type.PrimitiveType; import org.lflang.target.property.type.TargetPropertyType; -import org.lflang.lf.Element; -import org.lflang.lf.KeyValuePair; import org.lflang.target.property.type.UnionType; - public class DockerProperty extends TargetPropertyConfig { - public DockerProperty() { - super(UnionType.DOCKER_UNION); - } - - @Override - public DockerOptions initialValue() { - return new DockerOptions(false); - } - - @Override - public void update(Properties cliArgs) { - var key = TargetProperty.DOCKER.toString(); - if (cliArgs.containsKey(key)) { - var arg = cliArgs.getProperty(key); - if (Boolean.parseBoolean(arg)) { - this.value.enabled = true; - } else { - this.value.enabled = false; - } + public DockerProperty() { + super(UnionType.DOCKER_UNION); + } + + @Override + public DockerOptions initialValue() { + return new DockerOptions(false); + } + + @Override + public DockerOptions fromAst(Element value, MessageReporter err) { + var options = new DockerOptions(false); + if (value.getLiteral() != null) { + if (ASTUtils.toBoolean(value)) { + options.enabled = true; + } + } else { + for (KeyValuePair entry : value.getKeyvalue().getPairs()) { + DockerOption option = (DockerOption) DictionaryType.DOCKER_DICT.forName(entry.getName()); + if (Objects.requireNonNull(option) == DockerOption.FROM) { + options.from = ASTUtils.elementToSingleString(entry.getValue()); } + } } - - @Override - public DockerOptions fromAstElement(Element value) { - var options = new DockerOptions(false); - if (value.getLiteral() != null) { - if (ASTUtils.toBoolean(value)) { - options.enabled = true; - } - } else { - for (KeyValuePair entry : value.getKeyvalue().getPairs()) { - DockerOption option = (DockerOption) DictionaryType.DOCKER_DICT.forName(entry.getName()); - switch (option) { - case FROM: - options.from = ASTUtils.elementToSingleString(entry.getValue()); - break; - default: - break; - } - } + return options; + } + + @Override + protected DockerOptions fromString(String value, MessageReporter err) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public List supportedTargets() { + return Arrays.asList(Target.C, Target.CCPP, Target.Python, Target.TS); + } + + @Override + public Element toAstElement() { + if (!this.value.enabled) { + return null; + } else if (this.value.equals(new DockerOptions(true))) { + // default configuration + return ASTUtils.toElement(true); + } else { + Element e = LfFactory.eINSTANCE.createElement(); + KeyValuePairs kvp = LfFactory.eINSTANCE.createKeyValuePairs(); + for (DockerOption opt : DockerOption.values()) { + KeyValuePair pair = LfFactory.eINSTANCE.createKeyValuePair(); + pair.setName(opt.toString()); + if (opt == DockerOption.FROM) { + if (this.value.from == null) { + continue; + } + pair.setValue(ASTUtils.toElement(this.value.from)); } - return options; + kvp.getPairs().add(pair); + } + e.setKeyvalue(kvp); + if (kvp.getPairs().isEmpty()) { + return null; + } + return e; } + } - @Override - public List supportedTargets() { - return Arrays.asList(Target.C, Target.CCPP, Target.Python, Target.TS); - } + /** Settings related to Docker options. */ + public static class DockerOptions { - @Override - public Element toAstElement() { - if (!this.value.enabled) { - return null; - } else if (this.value.equals(new DockerOptions(true))) { - // default configuration - return ASTUtils.toElement(true); - } else { - Element e = LfFactory.eINSTANCE.createElement(); - KeyValuePairs kvp = LfFactory.eINSTANCE.createKeyValuePairs(); - for (DockerOption opt : DockerOption.values()) { - KeyValuePair pair = LfFactory.eINSTANCE.createKeyValuePair(); - pair.setName(opt.toString()); - switch (opt) { - case FROM: - if (this.value.from == null) { - continue; - } - pair.setValue(ASTUtils.toElement(this.value.from)); - break; - } - kvp.getPairs().add(pair); - } - e.setKeyvalue(kvp); - if (kvp.getPairs().isEmpty()) { - return null; - } - return e; - } - } - - /** Settings related to Docker options. */ - public static class DockerOptions { - - public boolean enabled; - - public DockerOptions(boolean enabled) { - this.enabled = enabled; - } + public boolean enabled; - /** - * The base image and tag from which to build the Docker image. The default is "alpine:latest". - */ - public String from = "alpine:latest"; - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - DockerOptions that = (DockerOptions) o; - return from.equals(that.from); - } + public DockerOptions(boolean enabled) { + this.enabled = enabled; } - - /** - * Docker options. - * - * @author Edward A. Lee + * The base image and tag from which to build the Docker image. The default is "alpine:latest". */ - public enum DockerOption implements DictionaryElement { - FROM("FROM", PrimitiveType.STRING); + public String from = "alpine:latest"; - public final PrimitiveType type; + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + DockerOptions that = (DockerOptions) o; + return from.equals(that.from); + } + } - private final String description; + /** + * Docker options. + * + * @author Edward A. Lee + */ + public enum DockerOption implements DictionaryElement { + FROM("FROM", PrimitiveType.STRING); - private DockerOption(String alias, PrimitiveType type) { - this.description = alias; - this.type = type; - } + public final PrimitiveType type; - /** Return the description of this dictionary element. */ - @Override - public String toString() { - return this.description; - } + private final String description; - /** Return the type associated with this dictionary element. */ - public TargetPropertyType getType() { - return this.type; - } + DockerOption(String alias, PrimitiveType type) { + this.description = alias; + this.type = type; + } + + /** Return the description of this dictionary element. */ + @Override + public String toString() { + return this.description; + } + + /** Return the type associated with this dictionary element. */ + public TargetPropertyType getType() { + return this.type; } + } } diff --git a/core/src/main/java/org/lflang/target/property/ExportDependencyGraphProperty.java b/core/src/main/java/org/lflang/target/property/ExportDependencyGraphProperty.java index b71ba34311..8e38f8881f 100644 --- a/core/src/main/java/org/lflang/target/property/ExportDependencyGraphProperty.java +++ b/core/src/main/java/org/lflang/target/property/ExportDependencyGraphProperty.java @@ -1,14 +1,12 @@ package org.lflang.target.property; import java.util.List; - import org.lflang.Target; public class ExportDependencyGraphProperty extends DefaultBooleanProperty { - @Override - public List supportedTargets() { - return List.of(Target.CPP, Target.Rust); - } - + @Override + public List supportedTargets() { + return List.of(Target.CPP, Target.Rust); + } } diff --git a/core/src/main/java/org/lflang/target/property/ExportToYamlProperty.java b/core/src/main/java/org/lflang/target/property/ExportToYamlProperty.java index 6abb07ccd3..d67fad9788 100644 --- a/core/src/main/java/org/lflang/target/property/ExportToYamlProperty.java +++ b/core/src/main/java/org/lflang/target/property/ExportToYamlProperty.java @@ -1,14 +1,12 @@ package org.lflang.target.property; import java.util.List; - import org.lflang.Target; public class ExportToYamlProperty extends DefaultBooleanProperty { - @Override - public List supportedTargets() { - return List.of(Target.CPP); - } - + @Override + public List supportedTargets() { + return List.of(Target.CPP); + } } diff --git a/core/src/main/java/org/lflang/target/property/ExternalRuntimePathProperty.java b/core/src/main/java/org/lflang/target/property/ExternalRuntimePathProperty.java index a7e4c7a18c..92532597ba 100644 --- a/core/src/main/java/org/lflang/target/property/ExternalRuntimePathProperty.java +++ b/core/src/main/java/org/lflang/target/property/ExternalRuntimePathProperty.java @@ -1,13 +1,12 @@ package org.lflang.target.property; import java.util.List; - import org.lflang.Target; public class ExternalRuntimePathProperty extends DefaultStringConfig { - @Override - public List supportedTargets() { - return List.of(Target.CPP); - } + @Override + public List supportedTargets() { + return List.of(Target.CPP); + } } 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 f15493068b..0f343472b3 100644 --- a/core/src/main/java/org/lflang/target/property/FastProperty.java +++ b/core/src/main/java/org/lflang/target/property/FastProperty.java @@ -1,7 +1,7 @@ package org.lflang.target.property; import java.util.List; - +import org.lflang.MessageReporter; import org.lflang.Target; import org.lflang.TargetConfig; import org.lflang.lf.Action; @@ -10,45 +10,41 @@ import org.lflang.lf.LfPackage.Literals; import org.lflang.lf.Model; import org.lflang.lf.Reactor; -import org.lflang.target.property.DefaultBooleanProperty; - -import org.lflang.validation.ValidationReporter; public class FastProperty extends DefaultBooleanProperty { - @Override - public List supportedTargets() { - return Target.ALL; - } + @Override + public List supportedTargets() { + return Target.ALL; + } - @Override - public void validate(KeyValuePair pair, Model ast, TargetConfig config, ValidationReporter 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.error( - "The fast target property is incompatible with federated programs.", - pair, - Literals.KEY_VALUE_PAIR__NAME); - break; - } - } + @Override + public void validate( + KeyValuePair pair, Model ast, TargetConfig config, 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; + } + } - // 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.error( - "The fast target property is incompatible with physical actions.", - pair, - Literals.KEY_VALUE_PAIR__NAME); - break; - } - } - } + // 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("The fast target property is incompatible with physical actions."); + break; + } } + } } + } } diff --git a/core/src/main/java/org/lflang/target/property/FedSetupProperty.java b/core/src/main/java/org/lflang/target/property/FedSetupProperty.java new file mode 100644 index 0000000000..fb7290c680 --- /dev/null +++ b/core/src/main/java/org/lflang/target/property/FedSetupProperty.java @@ -0,0 +1,42 @@ +package org.lflang.target.property; + +import java.util.List; +import org.lflang.MessageReporter; +import org.lflang.Target; +import org.lflang.TargetPropertyConfig; +import org.lflang.ast.ASTUtils; +import org.lflang.lf.Element; +import org.lflang.target.property.type.PrimitiveType; +import org.lflang.util.StringUtil; + +public class FedSetupProperty extends TargetPropertyConfig { + + public FedSetupProperty() { + super(PrimitiveType.FILE); + } + + @Override + public String initialValue() { + return null; + } + + @Override + protected String fromAst(Element value, MessageReporter err) { + return StringUtil.removeQuotes(ASTUtils.elementToSingleString(value)); + } + + @Override + protected String fromString(String value, MessageReporter err) { + return value; + } + + @Override + public List supportedTargets() { + return List.of(Target.C, Target.CCPP, Target.Python); + } + + @Override + public Element toAstElement() { + return ASTUtils.toElement(value); + } +} diff --git a/core/src/main/java/org/lflang/target/property/FilesProperty.java b/core/src/main/java/org/lflang/target/property/FilesProperty.java index 61750c8c37..8723a8441c 100644 --- a/core/src/main/java/org/lflang/target/property/FilesProperty.java +++ b/core/src/main/java/org/lflang/target/property/FilesProperty.java @@ -1,14 +1,12 @@ package org.lflang.target.property; import java.util.List; - import org.lflang.Target; public class FilesProperty extends DefaultFileListProperty { - @Override - public List supportedTargets() { - return List.of(Target.C, Target.CCPP, Target.Python); - } - + @Override + public List supportedTargets() { + return List.of(Target.C, Target.CCPP, Target.Python); + } } diff --git a/core/src/main/java/org/lflang/target/property/KeepaliveProperty.java b/core/src/main/java/org/lflang/target/property/KeepaliveProperty.java index 4c1db334a5..8490b74d2f 100644 --- a/core/src/main/java/org/lflang/target/property/KeepaliveProperty.java +++ b/core/src/main/java/org/lflang/target/property/KeepaliveProperty.java @@ -1,44 +1,30 @@ package org.lflang.target.property; -import static org.lflang.TargetProperty.KEEPALIVE; - import java.util.List; -import java.util.Properties; - +import org.lflang.MessageReporter; import org.lflang.Target; import org.lflang.TargetConfig; import org.lflang.lf.KeyValuePair; import org.lflang.lf.LfPackage.Literals; import org.lflang.lf.Model; -import org.lflang.target.property.DefaultBooleanProperty; -import org.lflang.validation.ValidationReporter; public class KeepaliveProperty extends DefaultBooleanProperty { - @Override - public void update(Properties cliArgs) { - super.update(cliArgs); - var key = KEEPALIVE.toString(); - if (cliArgs.containsKey(key)) { - this.override(Boolean.parseBoolean(cliArgs.getProperty(KEEPALIVE.toString()))); - } - } - - @Override - public List supportedTargets() { - return Target.ALL; + @Override + public List supportedTargets() { + return Target.ALL; + } + + @Override + public void validate( + KeyValuePair pair, Model ast, TargetConfig config, MessageReporter reporter) { + super.validate(pair, ast, config, reporter); + if (pair != null && config.target == Target.CPP) { + reporter + .at(pair, Literals.KEY_VALUE_PAIR__NAME) + .warning( + "The keepalive property is inferred automatically by the C++ " + + "runtime and the value given here is ignored"); } - - @Override - public void validate(KeyValuePair pair, Model ast, TargetConfig config, ValidationReporter reporter) { - super.validate(pair, ast, config, reporter); - if (pair != null && config.target == Target.CPP) { - reporter.warning( - "The keepalive property is inferred automatically by the C++ " - + "runtime and the value given here is ignored", - pair, - Literals.KEY_VALUE_PAIR__NAME); - } - } - + } } diff --git a/core/src/main/java/org/lflang/target/property/LoggingProperty.java b/core/src/main/java/org/lflang/target/property/LoggingProperty.java index 50d7420a30..7930adce4d 100644 --- a/core/src/main/java/org/lflang/target/property/LoggingProperty.java +++ b/core/src/main/java/org/lflang/target/property/LoggingProperty.java @@ -1,7 +1,6 @@ package org.lflang.target.property; import java.util.List; - import org.lflang.MessageReporter; import org.lflang.Target; import org.lflang.TargetPropertyConfig; @@ -12,51 +11,50 @@ public class LoggingProperty extends TargetPropertyConfig { - public LoggingProperty() { - super(UnionType.LOGGING_UNION); - } - + public LoggingProperty() { + super(UnionType.LOGGING_UNION); + } + + @Override + public LogLevel initialValue() { + return LogLevel.INFO; + } + + @Override + protected LogLevel fromAst(Element value, MessageReporter err) { + return fromString(ASTUtils.elementToSingleString(value), err); + } + + protected LogLevel fromString(String string, MessageReporter err) { + return LogLevel.valueOf(string.toUpperCase()); + } + + @Override + public List supportedTargets() { + return Target.ALL; + } + + @Override + public Element toAstElement() { + return ASTUtils.toElement(value.toString()); + } + + /** + * Log levels in descending order of severity. + * + * @author Marten Lohstroh + */ + public enum LogLevel { + ERROR, + WARN, + INFO, + LOG, + DEBUG; + + /** Return the name in lower case. */ @Override - public LogLevel initialValue() { - return LogLevel.INFO; + public String toString() { + return this.name().toLowerCase(); } - - @Override - protected LogLevel fromAst(Element value, MessageReporter err) { - return fromString(ASTUtils.elementToSingleString(value), err); - } - - protected LogLevel fromString(String string, MessageReporter err) { - return LogLevel.valueOf(string.toUpperCase()); - } - - @Override - public List supportedTargets() { - return Target.ALL; - } - - @Override - public Element toAstElement() { - return ASTUtils.toElement(value.toString()); - } - - /** - * Log levels in descending order of severity. - * - * @author Marten Lohstroh - */ - public enum LogLevel { - ERROR, - WARN, - INFO, - LOG, - DEBUG; - - /** Return the name in lower case. */ - @Override - public String toString() { - return this.name().toLowerCase(); - } - } - + } } diff --git a/core/src/main/java/org/lflang/target/property/NoCompileProperty.java b/core/src/main/java/org/lflang/target/property/NoCompileProperty.java index 1e7ac01ef2..555cbfaa3e 100644 --- a/core/src/main/java/org/lflang/target/property/NoCompileProperty.java +++ b/core/src/main/java/org/lflang/target/property/NoCompileProperty.java @@ -2,14 +2,12 @@ import java.util.Arrays; import java.util.List; - import org.lflang.Target; public class NoCompileProperty extends DefaultBooleanProperty { - @Override - public List supportedTargets() { - return Arrays.asList(Target.C, Target.CPP, Target.CCPP, Target.Python); - } - + @Override + public List supportedTargets() { + return Arrays.asList(Target.C, Target.CPP, Target.CCPP, Target.Python); + } } diff --git a/core/src/main/java/org/lflang/target/property/NoRuntimeValidationProperty.java b/core/src/main/java/org/lflang/target/property/NoRuntimeValidationProperty.java index d5132341d6..d183484195 100644 --- a/core/src/main/java/org/lflang/target/property/NoRuntimeValidationProperty.java +++ b/core/src/main/java/org/lflang/target/property/NoRuntimeValidationProperty.java @@ -1,14 +1,12 @@ package org.lflang.target.property; import java.util.List; - import org.lflang.Target; public class NoRuntimeValidationProperty extends DefaultBooleanProperty { - @Override - public List supportedTargets() { - return List.of(Target.CPP); - } - + @Override + public List supportedTargets() { + return List.of(Target.CPP); + } } 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 aca5e46c2f..efd7887127 100644 --- a/core/src/main/java/org/lflang/target/property/PlatformProperty.java +++ b/core/src/main/java/org/lflang/target/property/PlatformProperty.java @@ -2,264 +2,265 @@ import java.util.Arrays; import java.util.List; - +import org.lflang.MessageReporter; import org.lflang.Target; import org.lflang.TargetConfig; import org.lflang.TargetProperty; import org.lflang.TargetProperty.DictionaryElement; +import org.lflang.TargetPropertyConfig; import org.lflang.ast.ASTUtils; +import org.lflang.lf.Element; +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.target.property.PlatformProperty.PlatformOptions; import org.lflang.target.property.type.DictionaryType; import org.lflang.target.property.type.PrimitiveType; import org.lflang.target.property.type.TargetPropertyType; -import org.lflang.TargetPropertyConfig; -import org.lflang.lf.Element; -import org.lflang.lf.KeyValuePair; -import org.lflang.lf.Model; import org.lflang.target.property.type.UnionType; -import org.lflang.validation.ValidationReporter; public class PlatformProperty extends TargetPropertyConfig { - public PlatformProperty() { - super(UnionType.PLATFORM_STRING_OR_DICTIONARY); - } - - @Override - public PlatformOptions initialValue() { - return new PlatformOptions(); - } - - @Override - public PlatformOptions fromAstElement(Element value) { // FIXME: pass in err - var config = new PlatformOptions(); - if (value.getLiteral() != null) { - config.platform = - (Platform) UnionType.PLATFORM_UNION.forName(ASTUtils.elementToSingleString(value)); - if (config.platform == null) { - String s = - "Unidentified Platform Type, LF supports the following platform types: " - + Arrays.asList(Platform.values()); - //err.at(value).error(s); - throw new AssertionError(s); - } - } else { - for (KeyValuePair entry : value.getKeyvalue().getPairs()) { - PlatformOption option = - (PlatformOption) DictionaryType.PLATFORM_DICT.forName(entry.getName()); - switch (option) { - case NAME -> { - Platform p = - (Platform) - UnionType.PLATFORM_UNION.forName( - ASTUtils.elementToSingleString(entry.getValue())); - if (p == null) { - String s = - "Unidentified Platform Type, LF supports the following platform types: " - + Arrays.asList(Platform.values()); - //err.at(entry).error(s); // FIXME - throw new AssertionError(s); - } - config.platform = p; - } - case BAUDRATE -> config.baudRate = ASTUtils.toInteger(entry.getValue()); - case BOARD -> config.board = ASTUtils.elementToSingleString(entry.getValue()); - case FLASH -> config.flash = ASTUtils.toBoolean(entry.getValue()); - case PORT -> config.port = ASTUtils.elementToSingleString(entry.getValue()); - case USER_THREADS -> config.userThreads = ASTUtils.toInteger(entry.getValue()); - default -> { - } - } - } - } - // If the platform does not support threading, disable it. -// if (!config.platform.isMultiThreaded()) { -// config.threading = false; // FIXME: this should instead be dealt with in the validator -// } - return config; - } - - @Override - public List supportedTargets() { - return Target.ALL; - } - - @Override - public void validate(KeyValuePair pair, Model ast, TargetConfig config, ValidationReporter reporter) { - super.validate(pair, ast, config, reporter); - var threading = TargetProperty.getKeyValuePair(ast, TargetProperty.THREADING); - if (threading != null) { - if (pair != null && ASTUtils.toBoolean(threading.getValue())) { - var lit = ASTUtils.elementToSingleString(pair.getValue()); - var dic = pair.getValue().getKeyvalue(); - if (lit != null && lit.equalsIgnoreCase(Platform.RP2040.toString())) { - reporter.error( - "Platform " + Platform.RP2040 + " does not support threading", - pair, - Literals.KEY_VALUE_PAIR__VALUE); - } - if (dic != null) { - var rp = - dic.getPairs().stream() - .filter( - kv -> - kv.getName().equalsIgnoreCase("name") - && ASTUtils.elementToSingleString(kv.getValue()) - .equalsIgnoreCase(Platform.RP2040.toString())) - .findFirst(); - rp.ifPresent(keyValuePair -> reporter.error( - "Platform " + Platform.RP2040 + " does not support threading", - keyValuePair, - Literals.KEY_VALUE_PAIR__VALUE)); - } + public PlatformProperty() { + super(UnionType.PLATFORM_STRING_OR_DICTIONARY); + } + + @Override + public PlatformOptions initialValue() { + return new PlatformOptions(); + } + + @Override + public PlatformOptions fromAst(Element value, MessageReporter err) { + var config = new PlatformOptions(); + if (value.getLiteral() != null) { + config.platform = + (Platform) UnionType.PLATFORM_UNION.forName(ASTUtils.elementToSingleString(value)); + if (config.platform == null) { + String s = + "Unidentified Platform Type, LF supports the following platform types: " + + Arrays.asList(Platform.values()); + // err.at(value).error(s); + throw new AssertionError(s); + } + } else { + for (KeyValuePair entry : value.getKeyvalue().getPairs()) { + PlatformOption option = + (PlatformOption) DictionaryType.PLATFORM_DICT.forName(entry.getName()); + switch (option) { + case NAME -> { + Platform p = + (Platform) + UnionType.PLATFORM_UNION.forName( + ASTUtils.elementToSingleString(entry.getValue())); + if (p == null) { + String s = + "Unidentified Platform Type, LF supports the following platform types: " + + Arrays.asList(Platform.values()); + err.at(entry).error(s); + throw new AssertionError(s); } + config.platform = p; + } + case BAUDRATE -> config.baudRate = ASTUtils.toInteger(entry.getValue()); + case BOARD -> config.board = ASTUtils.elementToSingleString(entry.getValue()); + case FLASH -> config.flash = ASTUtils.toBoolean(entry.getValue()); + case PORT -> config.port = ASTUtils.elementToSingleString(entry.getValue()); + case USER_THREADS -> config.userThreads = ASTUtils.toInteger(entry.getValue()); + default -> {} } + } } - @Override - public Element toAstElement() { - Element e = LfFactory.eINSTANCE.createElement(); - KeyValuePairs kvp = LfFactory.eINSTANCE.createKeyValuePairs(); - for (PlatformOption opt : PlatformOption.values()) { - KeyValuePair pair = LfFactory.eINSTANCE.createKeyValuePair(); - pair.setName(opt.toString()); - switch (opt) { - case NAME -> pair.setValue(ASTUtils.toElement(value.platform.toString())); - case BAUDRATE -> pair.setValue(ASTUtils.toElement(value.baudRate)); - case BOARD -> pair.setValue(ASTUtils.toElement(value.board)); - case FLASH -> pair.setValue(ASTUtils.toElement(value.flash)); - case PORT -> pair.setValue(ASTUtils.toElement(value.port)); - case USER_THREADS -> pair.setValue(ASTUtils.toElement(value.userThreads)); - } - kvp.getPairs().add(pair); + return config; + } + + @Override + protected PlatformOptions fromString(String value, MessageReporter err) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public List supportedTargets() { + return Target.ALL; + } + + @Override + public void validate( + KeyValuePair pair, Model ast, TargetConfig config, MessageReporter reporter) { + super.validate(pair, ast, config, reporter); + + var threading = TargetProperty.getKeyValuePair(ast, TargetProperty.THREADING); + if (threading != null) { + if (pair != null && ASTUtils.toBoolean(threading.getValue())) { + var lit = ASTUtils.elementToSingleString(pair.getValue()); + var dic = pair.getValue().getKeyvalue(); + if (lit != null && lit.equalsIgnoreCase(Platform.RP2040.toString())) { + reporter + .at(pair, Literals.KEY_VALUE_PAIR__VALUE) + .error("Platform " + Platform.RP2040 + " does not support threading"); } - e.setKeyvalue(kvp); - if (kvp.getPairs().isEmpty()) { - return null; + if (dic != null) { + var rp = + dic.getPairs().stream() + .filter( + kv -> + kv.getName().equalsIgnoreCase("name") + && ASTUtils.elementToSingleString(kv.getValue()) + .equalsIgnoreCase(Platform.RP2040.toString())) + .findFirst(); + rp.ifPresent( + keyValuePair -> + reporter + .at(keyValuePair, Literals.KEY_VALUE_PAIR__VALUE) + .error("Platform " + Platform.RP2040 + " does not support threading")); } - return e; + } } - - - /** Settings related to Platform Options. */ - public static class PlatformOptions { - - /** - * The base platform we build our LF Files on. Should be set to AUTO by default unless - * developing for specific OS/Embedded Platform - */ - public Platform platform = Platform.AUTO; - - /** - * The string value used to determine what type of embedded board we work with and can be used - * to simplify the build process. This string has the form "board_name[:option]*" (zero or more - * options separated by colons). For example, "pico:usb" specifies a Raspberry Pi Pico where - * stdin and stdout go through a USB serial port. - */ - public String board = null; - - /** - * The string value used to determine the port on which to flash the compiled program (i.e. - * /dev/cu.usbmodem21301) - */ - public String port = null; - - /** - * The baud rate used as a parameter to certain embedded platforms. 9600 is a standard rate - * amongst systems like Arduino, so it's the default value. - */ - public int baudRate = 9600; - - /** - * The boolean statement used to determine whether we should automatically attempt to flash once - * we compile. This may require the use of board and port values depending on the infrastructure - * you use to flash the boards. - */ - public boolean flash = false; - - /** - * The int value is used to determine the number of needed threads for the user application in - * Zephyr. - */ - public int userThreads = 0; + } + + @Override + public Element toAstElement() { + Element e = LfFactory.eINSTANCE.createElement(); + KeyValuePairs kvp = LfFactory.eINSTANCE.createKeyValuePairs(); + for (PlatformOption opt : PlatformOption.values()) { + KeyValuePair pair = LfFactory.eINSTANCE.createKeyValuePair(); + pair.setName(opt.toString()); + switch (opt) { + case NAME -> pair.setValue(ASTUtils.toElement(value.platform.toString())); + case BAUDRATE -> pair.setValue(ASTUtils.toElement(value.baudRate)); + case BOARD -> pair.setValue(ASTUtils.toElement(value.board)); + case FLASH -> pair.setValue(ASTUtils.toElement(value.flash)); + case PORT -> pair.setValue(ASTUtils.toElement(value.port)); + case USER_THREADS -> pair.setValue(ASTUtils.toElement(value.userThreads)); + } + kvp.getPairs().add(pair); } + e.setKeyvalue(kvp); + if (kvp.getPairs().isEmpty()) { + return null; + } + return e; + } + /** Settings related to Platform Options. */ + public static class PlatformOptions { // FIXME: use a record for this - /** Enumeration of supported platforms */ - public enum Platform { - AUTO, - ARDUINO, - NRF52("Nrf52", true), - RP2040("Rp2040", false), - LINUX("Linux", true), - MAC("Darwin", true), - ZEPHYR("Zephyr", true), - WINDOWS("Windows", true); - - final String cMakeName; - - private boolean multiThreaded = true; - - Platform() { - this.cMakeName = this.toString(); - } + /** + * The base platform we build our LF Files on. Should be set to AUTO by default unless + * developing for specific OS/Embedded Platform + */ + public Platform platform = Platform.AUTO; - Platform(String cMakeName, boolean isMultiThreaded) { - this.cMakeName = cMakeName; - this.multiThreaded = isMultiThreaded; - } + /** + * The string value used to determine what type of embedded board we work with and can be used + * to simplify the build process. This string has the form "board_name[:option]*" (zero or more + * options separated by colons). For example, "pico:usb" specifies a Raspberry Pi Pico where + * stdin and stdout go through a USB serial port. + */ + public String board = null; - /** Return the name in lower case. */ - @Override - public String toString() { - return this.name().toLowerCase(); - } + /** + * The string value used to determine the port on which to flash the compiled program (i.e. + * /dev/cu.usbmodem21301) + */ + public String port = null; - /** Get the CMake name for the platform. */ - public String getcMakeName() { - return this.cMakeName; - } + /** + * The baud rate used as a parameter to certain embedded platforms. 9600 is a standard rate + * amongst systems like Arduino, so it's the default value. + */ + public int baudRate = 9600; - public boolean isMultiThreaded() { - return this.multiThreaded; - } - } + /** + * The boolean statement used to determine whether we should automatically attempt to flash once + * we compile. This may require the use of board and port values depending on the infrastructure + * you use to flash the boards. + */ + public boolean flash = false; /** - * Platform options. - * - * @author Anirudh Rengarajan + * The int value is used to determine the number of needed threads for the user application in + * Zephyr. */ - public enum PlatformOption implements DictionaryElement { - NAME("name", PrimitiveType.STRING), - BAUDRATE("baud-rate", PrimitiveType.NON_NEGATIVE_INTEGER), - BOARD("board", PrimitiveType.STRING), - FLASH("flash", PrimitiveType.BOOLEAN), - PORT("port", PrimitiveType.STRING), - USER_THREADS("user-threads", PrimitiveType.NON_NEGATIVE_INTEGER); + public int userThreads = 0; + } + + /** Enumeration of supported platforms */ + public enum Platform { + AUTO, + ARDUINO, + NRF52("Nrf52", true), + RP2040("Rp2040", false), + LINUX("Linux", true), + MAC("Darwin", true), + ZEPHYR("Zephyr", true), + WINDOWS("Windows", true); + + final String cMakeName; + + private boolean multiThreaded = + true; // FIXME: this is never read. If we set it, we can simplify the validator method in + // the encapsulating class. + + Platform() { + this.cMakeName = this.toString(); + } - public final PrimitiveType type; + Platform(String cMakeName, boolean isMultiThreaded) { + this.cMakeName = cMakeName; + this.multiThreaded = isMultiThreaded; + } - private final String description; + /** Return the name in lower case. */ + @Override + public String toString() { + return this.name().toLowerCase(); + } - PlatformOption(String alias, PrimitiveType type) { - this.description = alias; - this.type = type; - } + /** Get the CMake name for the platform. */ + public String getcMakeName() { + return this.cMakeName; + } - /** Return the description of this dictionary element. */ - @Override - public String toString() { - return this.description; - } + public boolean isMultiThreaded() { + return this.multiThreaded; + } + } + + /** + * Platform options. + * + * @author Anirudh Rengarajan + */ + public enum PlatformOption implements DictionaryElement { + NAME("name", PrimitiveType.STRING), + BAUDRATE("baud-rate", PrimitiveType.NON_NEGATIVE_INTEGER), + BOARD("board", PrimitiveType.STRING), + FLASH("flash", PrimitiveType.BOOLEAN), + PORT("port", PrimitiveType.STRING), + USER_THREADS("user-threads", PrimitiveType.NON_NEGATIVE_INTEGER); + + public final PrimitiveType type; + + private final String description; + + PlatformOption(String alias, PrimitiveType type) { + this.description = alias; + this.type = type; + } - /** Return the type associated with this dictionary element. */ - public TargetPropertyType getType() { - return this.type; - } + /** Return the description of this dictionary element. */ + @Override + public String toString() { + return this.description; } + /** Return the type associated with this dictionary element. */ + public TargetPropertyType getType() { + return this.type; + } + } } diff --git a/core/src/main/java/org/lflang/target/property/PrintStatisticsProperty.java b/core/src/main/java/org/lflang/target/property/PrintStatisticsProperty.java index 019eb1eb22..7cd00e165a 100644 --- a/core/src/main/java/org/lflang/target/property/PrintStatisticsProperty.java +++ b/core/src/main/java/org/lflang/target/property/PrintStatisticsProperty.java @@ -1,14 +1,12 @@ package org.lflang.target.property; import java.util.List; - import org.lflang.Target; public class PrintStatisticsProperty extends DefaultBooleanProperty { - @Override - public List supportedTargets() { - return List.of(Target.CPP); - } - + @Override + public List supportedTargets() { + return List.of(Target.CPP); + } } diff --git a/core/src/main/java/org/lflang/target/property/ProtobufsProperty.java b/core/src/main/java/org/lflang/target/property/ProtobufsProperty.java index bf17e49383..00bcc10772 100644 --- a/core/src/main/java/org/lflang/target/property/ProtobufsProperty.java +++ b/core/src/main/java/org/lflang/target/property/ProtobufsProperty.java @@ -1,14 +1,12 @@ package org.lflang.target.property; import java.util.List; - import org.lflang.Target; public class ProtobufsProperty extends DefaultFileListProperty { - @Override - public List supportedTargets() { - return List.of(Target.C, Target.CCPP, Target.TS, Target.Python); - } - + @Override + public List supportedTargets() { + return List.of(Target.C, Target.CCPP, Target.TS, Target.Python); + } } 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 4da5a94feb..58deea240d 100644 --- a/core/src/main/java/org/lflang/target/property/Ros2DependenciesProperty.java +++ b/core/src/main/java/org/lflang/target/property/Ros2DependenciesProperty.java @@ -2,7 +2,7 @@ import java.util.ArrayList; import java.util.List; - +import org.lflang.MessageReporter; import org.lflang.Target; import org.lflang.TargetConfig; import org.lflang.TargetProperty; @@ -13,44 +13,47 @@ import org.lflang.lf.LfPackage.Literals; import org.lflang.lf.Model; import org.lflang.target.property.type.ArrayType; -import org.lflang.validation.ValidationReporter; public class Ros2DependenciesProperty extends TargetPropertyConfig> { - public Ros2DependenciesProperty() { - super(ArrayType.STRING_ARRAY); - } - - @Override - public List initialValue() { - return new ArrayList<>(); - } - - @Override - public List fromAstElement(Element value) { - return ASTUtils.elementToListOfStrings(value); - } - - @Override - public List supportedTargets() { - return List.of(Target.CPP); - } - - @Override - public void validate(KeyValuePair pair, Model ast, TargetConfig config, ValidationReporter reporter) { - super.validate(pair, ast, config, reporter); - var ros2enabled = TargetProperty.getKeyValuePair(ast, TargetProperty.ROS2); - if (pair != null && (ros2enabled == null || !ASTUtils.toBoolean(ros2enabled.getValue()))) { - reporter.warning( - "Ignoring ros2-dependencies as ros2 compilation is disabled", - pair, - Literals.KEY_VALUE_PAIR__NAME); - } - } - - @Override - public Element toAstElement() { - return ASTUtils.toElement(value); + public Ros2DependenciesProperty() { + super(ArrayType.STRING_ARRAY); + } + + @Override + public List initialValue() { + return new ArrayList<>(); + } + + @Override + public List fromAst(Element value, MessageReporter err) { + return ASTUtils.elementToListOfStrings(value); + } + + @Override + protected List fromString(String value, MessageReporter err) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public List supportedTargets() { + return List.of(Target.CPP); + } + + @Override + public void validate( + KeyValuePair pair, Model ast, TargetConfig config, MessageReporter reporter) { + super.validate(pair, ast, config, reporter); + var ros2enabled = TargetProperty.getKeyValuePair(ast, TargetProperty.ROS2); + if (pair != null && (ros2enabled == null || !ASTUtils.toBoolean(ros2enabled.getValue()))) { + reporter + .at(pair, Literals.KEY_VALUE_PAIR__NAME) + .warning("Ignoring ros2-dependencies as ros2 compilation is disabled"); } + } + @Override + public Element toAstElement() { + return ASTUtils.toElement(value); + } } diff --git a/core/src/main/java/org/lflang/target/property/Ros2Property.java b/core/src/main/java/org/lflang/target/property/Ros2Property.java index 39fc2e78e8..1a5bf9728d 100644 --- a/core/src/main/java/org/lflang/target/property/Ros2Property.java +++ b/core/src/main/java/org/lflang/target/property/Ros2Property.java @@ -1,14 +1,12 @@ package org.lflang.target.property; import java.util.List; - import org.lflang.Target; public class Ros2Property extends DefaultBooleanProperty { - @Override - public List supportedTargets() { - return List.of(Target.CPP); - } - + @Override + public List supportedTargets() { + return List.of(Target.CPP); + } } diff --git a/core/src/main/java/org/lflang/target/property/RuntimeVersionProperty.java b/core/src/main/java/org/lflang/target/property/RuntimeVersionProperty.java index 2be751f27c..27bbffb737 100644 --- a/core/src/main/java/org/lflang/target/property/RuntimeVersionProperty.java +++ b/core/src/main/java/org/lflang/target/property/RuntimeVersionProperty.java @@ -1,13 +1,12 @@ package org.lflang.target.property; import java.util.List; - import org.lflang.Target; public class RuntimeVersionProperty extends DefaultStringConfig { - @Override - public List supportedTargets() { - return List.of(Target.CPP); - } + @Override + public List supportedTargets() { + return List.of(Target.CPP); + } } diff --git a/core/src/main/java/org/lflang/target/property/RustIncludeProperty.java b/core/src/main/java/org/lflang/target/property/RustIncludeProperty.java index 5bb31617bd..853ff81ac8 100644 --- a/core/src/main/java/org/lflang/target/property/RustIncludeProperty.java +++ b/core/src/main/java/org/lflang/target/property/RustIncludeProperty.java @@ -4,9 +4,7 @@ import java.nio.file.Path; import java.util.ArrayList; import java.util.List; - import org.eclipse.emf.ecore.EObject; - import org.lflang.MessageReporter; import org.lflang.Target; import org.lflang.TargetPropertyConfig; @@ -20,78 +18,90 @@ public class RustIncludeProperty extends TargetPropertyConfig> { - public RustIncludeProperty() { - super(UnionType.FILE_OR_FILE_ARRAY); - } + public RustIncludeProperty() { + super(UnionType.FILE_OR_FILE_ARRAY); + } - @Override - public List supportedTargets() { - return List.of(Target.Rust); - } + @Override + public List supportedTargets() { + return List.of(Target.Rust); + } - @Override - public List initialValue() { - return new ArrayList<>(); - } + @Override + public List initialValue() { + return new ArrayList<>(); + } - @Override - public List fromAstElement(Element value) { - Path referencePath; - try { - referencePath = FileUtil.toPath(value.eResource().getURI()).toAbsolutePath(); - } catch (IllegalArgumentException e) { - // FIXME: need err - //err.at(value).error("Invalid path? " + e.getMessage()); - throw e; - } + @Override + public List fromAst(Element value, MessageReporter err) { + var list = new ArrayList(); + Path referencePath; + try { + referencePath = FileUtil.toPath(value.eResource().getURI()).toAbsolutePath(); + } catch (IllegalArgumentException e) { + err.at(value).error("Invalid path? " + e.getMessage()); + throw e; + } - // we'll resolve relative paths to check that the files - // are as expected. + // we'll resolve relative paths to check that the files + // are as expected. - if (value.getLiteral() != null) { - Path resolved = referencePath.resolveSibling(StringUtil.removeQuotes(value.getLiteral())); - this.addAndCheckTopLevelModule(resolved, value, err); - } else if (value.getArray() != null) { - for (Element element : value.getArray().getElements()) { - String literal = StringUtil.removeQuotes(element.getLiteral()); - Path resolved = referencePath.resolveSibling(literal); - this.addAndCheckTopLevelModule(resolved, element, err); - } + if (value.getLiteral() != null) { + Path resolved = referencePath.resolveSibling(StringUtil.removeQuotes(value.getLiteral())); + if (this.checkTopLevelModule(resolved, value, err)) { + list.add(resolved); + } + } else if (value.getArray() != null) { + for (Element element : value.getArray().getElements()) { + String literal = StringUtil.removeQuotes(element.getLiteral()); + Path resolved = referencePath.resolveSibling(literal); + if (this.checkTopLevelModule(resolved, value, err)) { + list.add(resolved); } + } } + return list; + } - @Override - public Element toAstElement() { - // do not check paths here, and simply copy the absolute path over - List paths = this.value; - if (paths.isEmpty()) { - return null; - } else if (paths.size() == 1) { - return ASTUtils.toElement(paths.get(0).toString()); - } else { - Element e = LfFactory.eINSTANCE.createElement(); - Array arr = LfFactory.eINSTANCE.createArray(); - for (Path p : paths) { - arr.getElements().add(ASTUtils.toElement(p.toString())); - } - e.setArray(arr); - return e; - } + @Override + protected List fromString(String value, MessageReporter err) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Element toAstElement() { + // do not check paths here, and simply copy the absolute path over + List paths = this.value; + if (paths.isEmpty()) { + return null; + } else if (paths.size() == 1) { + return ASTUtils.toElement(paths.get(0).toString()); + } else { + Element e = LfFactory.eINSTANCE.createElement(); + Array arr = LfFactory.eINSTANCE.createArray(); + for (Path p : paths) { + arr.getElements().add(ASTUtils.toElement(p.toString())); + } + e.setArray(arr); + return e; } + } - private void addAndCheckTopLevelModule(Path path, EObject errorOwner, MessageReporter err) { - String fileName = path.getFileName().toString(); - if (!Files.exists(path)) { - err.at(errorOwner).error("File not found"); - } else if (Files.isRegularFile(path) && !fileName.endsWith(".rs")) { - err.at(errorOwner).error("Not a rust file"); - } else if (fileName.equals("main.rs")) { - err.at(errorOwner).error("Cannot use 'main.rs' as a module name (reserved)"); - } else if (fileName.equals("reactors") || fileName.equals("reactors.rs")) { - err.at(errorOwner).error("Cannot use 'reactors' as a module name (reserved)"); - } else if (Files.isDirectory(path) && !Files.exists(path.resolve("mod.rs"))) { - err.at(errorOwner).error("Cannot find module descriptor in directory"); - } - this.value.add(path); + private boolean checkTopLevelModule(Path path, EObject errorOwner, MessageReporter err) { + String fileName = path.getFileName().toString(); + if (!Files.exists(path)) { + err.at(errorOwner).error("File not found"); + } else if (Files.isRegularFile(path) && !fileName.endsWith(".rs")) { + err.at(errorOwner).error("Not a rust file"); + } else if (fileName.equals("main.rs")) { + err.at(errorOwner).error("Cannot use 'main.rs' as a module name (reserved)"); + } else if (fileName.equals("reactors") || fileName.equals("reactors.rs")) { + err.at(errorOwner).error("Cannot use 'reactors' as a module name (reserved)"); + } else if (Files.isDirectory(path) && !Files.exists(path.resolve("mod.rs"))) { + err.at(errorOwner).error("Cannot find module descriptor in directory"); + } else { + return true; } + return false; + } } 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 99000267d0..f2747456c2 100644 --- a/core/src/main/java/org/lflang/target/property/SchedulerProperty.java +++ b/core/src/main/java/org/lflang/target/property/SchedulerProperty.java @@ -1,151 +1,137 @@ package org.lflang.target.property; +import com.google.common.collect.ImmutableList; import java.nio.file.Path; import java.util.Arrays; import java.util.List; -import java.util.Properties; - +import org.lflang.MessageReporter; import org.lflang.Target; import org.lflang.TargetConfig; -import org.lflang.TargetProperty; import org.lflang.TargetPropertyConfig; 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.property.SchedulerProperty.SchedulerOption; import org.lflang.target.property.type.UnionType; -import org.lflang.validation.ValidationReporter; - - -import com.google.common.collect.ImmutableList; public class SchedulerProperty extends TargetPropertyConfig { - - public SchedulerProperty() { - super(UnionType.SCHEDULER_UNION); - } - - @Override - public SchedulerOption initialValue() { - return SchedulerOption.getDefault(); + public SchedulerProperty() { + super(UnionType.SCHEDULER_UNION); + } + + @Override + public SchedulerOption initialValue() { + return SchedulerOption.getDefault(); + } + + @Override + public SchedulerOption fromAst(Element value, MessageReporter err) { + var scheduler = fromString(ASTUtils.elementToSingleString(value), err); + if (scheduler != null) { + return scheduler; + } else { + return SchedulerOption.getDefault(); } - - @Override - public void update(Properties cliArgs) { - super.update(cliArgs); - var key = TargetProperty.SCHEDULER.toString(); - if (cliArgs.containsKey(key)) { - value = SchedulerOption.valueOf(cliArgs.getProperty("scheduler")); + } + + @Override + protected SchedulerOption fromString(String value, MessageReporter err) { + return (SchedulerOption) UnionType.SCHEDULER_UNION.forName(value); + } + + @Override + public List supportedTargets() { + return Arrays.asList(Target.C, Target.CCPP, Target.Python); + } + + @Override + public Element toAstElement() { + return ASTUtils.toElement(this.value.toString()); + } + + @Override + public void validate( + KeyValuePair pair, Model ast, TargetConfig config, MessageReporter reporter) { + super.validate(pair, ast, config, reporter); + if (pair != null) { + String schedulerName = ASTUtils.elementToSingleString(pair.getValue()); + try { + if (!SchedulerOption.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 + } } - - @Override - public SchedulerOption fromAstElement(Element value) { - var scheduler = (SchedulerOption) - UnionType.SCHEDULER_UNION.forName(ASTUtils.elementToSingleString(value)); - if (scheduler != null) { - return scheduler; - } else { - return SchedulerOption.getDefault(); - } + } + + /** + * Supported schedulers. + * + * @author Soroush Bateni + */ + public enum SchedulerOption { + NP(false), // Non-preemptive + ADAPTIVE( + false, + List.of( + Path.of("scheduler_adaptive.c"), + Path.of("worker_assignments.h"), + Path.of("worker_states.h"), + Path.of("data_collection.h"))), + GEDF_NP(true), // Global EDF non-preemptive + GEDF_NP_CI(true); // Global EDF non-preemptive with chain ID + + /** Indicate whether the scheduler prioritizes reactions by deadline. */ + private final boolean prioritizesDeadline; + + /** Relative paths to files required by this scheduler. */ + private final List relativePaths; + + SchedulerOption(boolean prioritizesDeadline) { + this(prioritizesDeadline, null); } - @Override - public List supportedTargets() { - return Arrays.asList(Target.C, Target.CCPP, Target.Python); + SchedulerOption(boolean prioritizesDeadline, List relativePaths) { + this.prioritizesDeadline = prioritizesDeadline; + this.relativePaths = relativePaths; } - @Override - public Element toAstElement() { - return ASTUtils.toElement(this.value.toString()); + /** Return true if the scheduler prioritizes reactions by deadline. */ + public boolean prioritizesDeadline() { + return this.prioritizesDeadline; } - @Override - public void validate(KeyValuePair pair, Model ast, TargetConfig config, ValidationReporter reporter) { - super.validate(pair, ast, config, reporter); - if (pair != null) { - String schedulerName = ASTUtils.elementToSingleString(pair.getValue()); - try { - if (!SchedulerOption.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.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.", - pair, - Literals.KEY_VALUE_PAIR__VALUE); - } - } - } catch (IllegalArgumentException e) { - // the given scheduler is invalid, but this is already checked by - // checkTargetProperties - } - } - + public List getRelativePaths() { + return relativePaths != null + ? ImmutableList.copyOf(relativePaths) + : List.of(Path.of("scheduler_" + this + ".c")); } - - /** - * Supported schedulers. - * - * @author Soroush Bateni - */ - public enum SchedulerOption { - NP(false), // Non-preemptive - ADAPTIVE( - false, - List.of( - Path.of("scheduler_adaptive.c"), - Path.of("worker_assignments.h"), - Path.of("worker_states.h"), - Path.of("data_collection.h"))), - GEDF_NP(true), // Global EDF non-preemptive - GEDF_NP_CI(true); // Global EDF non-preemptive with chain ID - - - /** Indicate whether the scheduler prioritizes reactions by deadline. */ - private final boolean prioritizesDeadline; - - /** Relative paths to files required by this scheduler. */ - private final List relativePaths; - - SchedulerOption(boolean prioritizesDeadline) { - this(prioritizesDeadline, null); - } - - SchedulerOption(boolean prioritizesDeadline, List relativePaths) { - this.prioritizesDeadline = prioritizesDeadline; - this.relativePaths = relativePaths; - } - - /** Return true if the scheduler prioritizes reactions by deadline. */ - public boolean prioritizesDeadline() { - return this.prioritizesDeadline; - } - - public List getRelativePaths() { - return relativePaths != null - ? ImmutableList.copyOf(relativePaths) - : List.of(Path.of("scheduler_" + this + ".c")); - } - - public static SchedulerOption getDefault() { - return NP; - } + public static SchedulerOption getDefault() { + return NP; } + } } diff --git a/core/src/main/java/org/lflang/target/property/SingleFileProjectProperty.java b/core/src/main/java/org/lflang/target/property/SingleFileProjectProperty.java index f779be00a1..3e68141ab4 100644 --- a/core/src/main/java/org/lflang/target/property/SingleFileProjectProperty.java +++ b/core/src/main/java/org/lflang/target/property/SingleFileProjectProperty.java @@ -1,14 +1,12 @@ package org.lflang.target.property; import java.util.List; - import org.lflang.Target; public class SingleFileProjectProperty extends DefaultBooleanProperty { - @Override - public List supportedTargets() { - return List.of(Target.Rust); - } - + @Override + public List supportedTargets() { + return List.of(Target.Rust); + } } diff --git a/core/src/main/java/org/lflang/target/property/ThreadingProperty.java b/core/src/main/java/org/lflang/target/property/ThreadingProperty.java index b0abbae4c6..7f596160df 100644 --- a/core/src/main/java/org/lflang/target/property/ThreadingProperty.java +++ b/core/src/main/java/org/lflang/target/property/ThreadingProperty.java @@ -1,19 +1,17 @@ package org.lflang.target.property; import java.util.List; - import org.lflang.Target; public class ThreadingProperty extends DefaultBooleanProperty { - @Override - public List supportedTargets() { - return List.of(Target.C, Target.CCPP, Target.Python); - } - + @Override + public List supportedTargets() { + return List.of(Target.C, Target.CCPP, Target.Python); + } - @Override - public Boolean initialValue() { - return true; - } + @Override + public Boolean initialValue() { + return true; + } } diff --git a/core/src/main/java/org/lflang/target/property/TimeOutProperty.java b/core/src/main/java/org/lflang/target/property/TimeOutProperty.java index 7ef3947727..55c591f8a0 100644 --- a/core/src/main/java/org/lflang/target/property/TimeOutProperty.java +++ b/core/src/main/java/org/lflang/target/property/TimeOutProperty.java @@ -1,8 +1,7 @@ package org.lflang.target.property; - import java.util.List; - +import org.lflang.MessageReporter; import org.lflang.Target; import org.lflang.TargetPropertyConfig; import org.lflang.TimeValue; @@ -10,30 +9,34 @@ import org.lflang.lf.Element; import org.lflang.target.property.type.PrimitiveType; - public class TimeOutProperty extends TargetPropertyConfig { - public TimeOutProperty() { - super(PrimitiveType.TIME_VALUE); - } - - @Override - public TimeValue initialValue() { - return null; - } - - @Override - public TimeValue fromAstElement(Element value) { - return ASTUtils.toTimeValue(value); - } - - @Override - public List supportedTargets() { - return Target.ALL; - } - - @Override - public Element toAstElement() { - return ASTUtils.toElement(value); - } + public TimeOutProperty() { + super(PrimitiveType.TIME_VALUE); + } + + @Override + public TimeValue initialValue() { + return null; + } + + @Override + public TimeValue fromAst(Element value, MessageReporter err) { + return ASTUtils.toTimeValue(value); + } + + @Override + protected TimeValue fromString(String value, MessageReporter err) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public List supportedTargets() { + return Target.ALL; + } + + @Override + public Element toAstElement() { + return ASTUtils.toElement(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 cfdb4ad024..3d6cca84ad 100644 --- a/core/src/main/java/org/lflang/target/property/TracingProperty.java +++ b/core/src/main/java/org/lflang/target/property/TracingProperty.java @@ -2,17 +2,12 @@ import java.util.List; import java.util.Objects; -import java.util.Properties; - +import org.lflang.MessageReporter; import org.lflang.Target; import org.lflang.TargetConfig; import org.lflang.TargetProperty; import org.lflang.TargetProperty.DictionaryElement; import org.lflang.TargetPropertyConfig; -import org.lflang.target.property.TracingProperty.TracingOptions; -import org.lflang.target.property.type.DictionaryType; -import org.lflang.target.property.type.PrimitiveType; -import org.lflang.target.property.type.TargetPropertyType; import org.lflang.ast.ASTUtils; import org.lflang.lf.Element; import org.lflang.lf.KeyValuePair; @@ -20,167 +15,162 @@ import org.lflang.lf.LfFactory; import org.lflang.lf.LfPackage.Literals; import org.lflang.lf.Model; +import org.lflang.target.property.TracingProperty.TracingOptions; +import org.lflang.target.property.type.DictionaryType; +import org.lflang.target.property.type.PrimitiveType; +import org.lflang.target.property.type.TargetPropertyType; import org.lflang.target.property.type.UnionType; -import org.lflang.validation.ValidationReporter; public class TracingProperty extends TargetPropertyConfig { - - public TracingProperty() { - super(UnionType.TRACING_UNION); - } - - @Override - public TracingOptions initialValue() { - return new TracingOptions(false); - } - - @Override - public void update(Properties cliArgs) { - super.update(cliArgs); - var key = TargetProperty.TRACING.toString(); - if (cliArgs.containsKey(key)) { - this.value.enabled = true; - } - } - - @Override - public TracingOptions fromAstElement(Element value) { - var options = new TracingOptions(false); - if (value.getLiteral() != null) { - if (!ASTUtils.toBoolean(value)) { - options.enabled = false; - } - } else { - for (KeyValuePair entry : value.getKeyvalue().getPairs()) { - TracingOption option = - (TracingOption) DictionaryType.TRACING_DICT.forName(entry.getName()); - switch (option) { - case TRACE_FILE_NAME: - options.traceFileName = ASTUtils.elementToSingleString(entry.getValue()); - break; - default: - break; - } - } + public TracingProperty() { + super(UnionType.TRACING_UNION); + } + + @Override + public TracingOptions initialValue() { + return new TracingOptions(false); + } + + @Override + public TracingOptions fromAst(Element value, MessageReporter err) { + var options = new TracingOptions(false); + if (value.getLiteral() != null) { + if (!ASTUtils.toBoolean(value)) { + options.enabled = false; + } + } else { + for (KeyValuePair entry : value.getKeyvalue().getPairs()) { + TracingOption option = (TracingOption) DictionaryType.TRACING_DICT.forName(entry.getName()); + switch (option) { + case TRACE_FILE_NAME: + options.traceFileName = ASTUtils.elementToSingleString(entry.getValue()); + break; + default: + break; } - return options; - } - - @Override - public List supportedTargets() { - return List.of(Target.C, Target.CCPP, Target.CPP, Target.Python); + } } - - @Override - public void validate(KeyValuePair pair, Model ast, TargetConfig config, ValidationReporter reporter) { - if (pair != null && this.fromAstElement(pair.getValue()) != null) { - // If tracing is anything but "false" and threading is off, error. - var threading = TargetProperty.getKeyValuePair(ast, TargetProperty.THREADING); - if (threading != null) { - if (!ASTUtils.toBoolean(threading.getValue())) { - reporter.error( - "Cannot enable tracing because threading support is disabled", - pair, - Literals.KEY_VALUE_PAIR__NAME); - reporter.error( - "Cannot disable treading support because tracing is enabled", - threading, - Literals.KEY_VALUE_PAIR__NAME); - } - } + return options; + } + + @Override + protected TracingOptions fromString(String value, MessageReporter err) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public List supportedTargets() { + return List.of(Target.C, Target.CCPP, Target.CPP, Target.Python); + } + + @Override + public void validate( + KeyValuePair pair, Model ast, TargetConfig config, 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, TargetProperty.THREADING); + if (threading != null) { + if (!ASTUtils.toBoolean(threading.getValue())) { + 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) + .error("Cannot disable treading support because tracing is enabled"); } + } } - - @Override - public Element toAstElement() { - if (!this.value.isEnabled()) { - return null; - } else if (this.value.equals(new TracingOptions(true))) { - // default values - return ASTUtils.toElement(true); - } else { - Element e = LfFactory.eINSTANCE.createElement(); - KeyValuePairs kvp = LfFactory.eINSTANCE.createKeyValuePairs(); - for (TracingOption opt : TracingOption.values()) { - KeyValuePair pair = LfFactory.eINSTANCE.createKeyValuePair(); - pair.setName(opt.toString()); - switch (opt) { - case TRACE_FILE_NAME: - if (this.value.traceFileName == null) { - continue; - } - pair.setValue(ASTUtils.toElement(this.value.traceFileName)); - } - kvp.getPairs().add(pair); - } - e.setKeyvalue(kvp); - if (kvp.getPairs().isEmpty()) { - return null; + } + + @Override + public Element toAstElement() { + if (!this.value.isEnabled()) { + return null; + } else if (this.value.equals(new TracingOptions(true))) { + // default values + return ASTUtils.toElement(true); + } else { + Element e = LfFactory.eINSTANCE.createElement(); + KeyValuePairs kvp = LfFactory.eINSTANCE.createKeyValuePairs(); + for (TracingOption opt : TracingOption.values()) { + KeyValuePair pair = LfFactory.eINSTANCE.createKeyValuePair(); + pair.setName(opt.toString()); + switch (opt) { + case TRACE_FILE_NAME: + if (this.value.traceFileName == null) { + continue; } - return e; + pair.setValue(ASTUtils.toElement(this.value.traceFileName)); } + kvp.getPairs().add(pair); + } + e.setKeyvalue(kvp); + if (kvp.getPairs().isEmpty()) { + return null; + } + return e; } + } - /** Settings related to tracing options. */ - public static class TracingOptions { + /** Settings related to tracing options. */ + public static class TracingOptions { - protected boolean enabled = false; + protected boolean enabled = false; - TracingOptions(boolean enabled) { - this.enabled = enabled; - } - - /** - * The name to use as the root of the trace file produced. This defaults to the name of the .lf - * file. - */ - public String traceFileName = null; + TracingOptions(boolean enabled) { + this.enabled = enabled; + } - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - TracingOptions that = (TracingOptions) o; - return Objects.equals(traceFileName, that.traceFileName); // traceFileName may be null - } + /** + * The name to use as the root of the trace file produced. This defaults to the name of the .lf + * file. + */ + public String traceFileName = null; - public boolean isEnabled() { - return enabled; - } + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + TracingOptions that = (TracingOptions) o; + return Objects.equals(traceFileName, that.traceFileName); // traceFileName may be null } + public boolean isEnabled() { + return enabled; + } + } - /** - * Tracing options. - * - * @author Edward A. Lee - */ - public enum TracingOption implements DictionaryElement { - TRACE_FILE_NAME("trace-file-name", PrimitiveType.STRING); + /** + * Tracing options. + * + * @author Edward A. Lee + */ + public enum TracingOption implements DictionaryElement { + TRACE_FILE_NAME("trace-file-name", PrimitiveType.STRING); - public final PrimitiveType type; + public final PrimitiveType type; - private final String description; + private final String description; - private TracingOption(String alias, PrimitiveType type) { - this.description = alias; - this.type = type; - } + private TracingOption(String alias, PrimitiveType type) { + this.description = alias; + this.type = type; + } - /** Return the description of this dictionary element. */ - @Override - public String toString() { - return this.description; - } + /** Return the description of this dictionary element. */ + @Override + public String toString() { + return this.description; + } - /** Return the type associated with this dictionary element. */ - public TargetPropertyType getType() { - return this.type; - } + /** Return the type associated with this dictionary element. */ + public TargetPropertyType getType() { + return this.type; } + } } diff --git a/core/src/main/java/org/lflang/target/property/VerifyProperty.java b/core/src/main/java/org/lflang/target/property/VerifyProperty.java index 0a6549bbc3..62116fc851 100644 --- a/core/src/main/java/org/lflang/target/property/VerifyProperty.java +++ b/core/src/main/java/org/lflang/target/property/VerifyProperty.java @@ -1,15 +1,13 @@ package org.lflang.target.property.type; import java.util.List; - import org.lflang.Target; import org.lflang.target.property.DefaultBooleanProperty; public class VerifyProperty extends DefaultBooleanProperty { - @Override - public List supportedTargets() { - return List.of(Target.C); - } - + @Override + public List supportedTargets() { + return List.of(Target.C); + } } 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 8b4a77a931..1ea091e567 100644 --- a/core/src/main/java/org/lflang/target/property/WorkersProperty.java +++ b/core/src/main/java/org/lflang/target/property/WorkersProperty.java @@ -1,7 +1,6 @@ package org.lflang.target.property; import java.util.List; - import org.lflang.MessageReporter; import org.lflang.Target; import org.lflang.TargetPropertyConfig; @@ -11,33 +10,32 @@ public class WorkersProperty extends TargetPropertyConfig { - public WorkersProperty() { - super(PrimitiveType.NON_NEGATIVE_INTEGER); - } - - @Override - public Integer initialValue() { - return 0; - } - - @Override - protected Integer fromString(String value, MessageReporter err) { - return Integer.parseInt(value); // FIXME: check for exception - } - - @Override - protected Integer fromAst(Element value, MessageReporter err) { - return ASTUtils.toInteger(value); - } - - @Override - public List supportedTargets() { - return List.of(Target.C, Target.CCPP, Target.Python, Target.CPP, Target.Rust); - } - - @Override - public Element toAstElement() { - return ASTUtils.toElement(value); - } - + public WorkersProperty() { + super(PrimitiveType.NON_NEGATIVE_INTEGER); + } + + @Override + public Integer initialValue() { + return 0; + } + + @Override + protected Integer fromString(String value, MessageReporter err) { + return Integer.parseInt(value); // FIXME: check for exception + } + + @Override + protected Integer fromAst(Element value, MessageReporter err) { + return ASTUtils.toInteger(value); + } + + @Override + public List supportedTargets() { + return List.of(Target.C, Target.CCPP, Target.Python, Target.CPP, Target.Rust); + } + + @Override + public Element toAstElement() { + return ASTUtils.toElement(value); + } } diff --git a/core/src/main/java/org/lflang/target/property/type/ArrayType.java b/core/src/main/java/org/lflang/target/property/type/ArrayType.java index 9a40560047..742292c3c7 100644 --- a/core/src/main/java/org/lflang/target/property/type/ArrayType.java +++ b/core/src/main/java/org/lflang/target/property/type/ArrayType.java @@ -1,11 +1,9 @@ package org.lflang.target.property.type; import java.util.List; - +import org.lflang.MessageReporter; import org.lflang.lf.Array; import org.lflang.lf.Element; -import org.lflang.validation.LFValidator; -import org.lflang.validation.ValidationReporter; /** * An array type of which the elements confirm to a given type. @@ -13,51 +11,51 @@ * @author Marten Lohstroh */ public enum ArrayType implements TargetPropertyType { - STRING_ARRAY(PrimitiveType.STRING), - FILE_ARRAY(PrimitiveType.FILE); - - /** Type parameter of this array type. */ - public TargetPropertyType type; - - /** - * Private constructor to create a new array type. - * - * @param type The type of elements in the array. - */ - private ArrayType(TargetPropertyType type) { - this.type = type; - } - - /** - * Check that the passed in element represents an array and ensure that its elements are all of - * the correct type. - */ - @Override - public boolean check(Element e, String name, ValidationReporter v) { - Array array = e.getArray(); - if (array != null) { - List elements = array.getElements(); - var valid = true; - for (int i = 0; i < elements.size(); i++) { - valid &= this.type.check(elements.get(i), name + "[" + i + "]", v); - } - return valid; - } - return false; - } - - /** Return true of the given element is an array. */ - @Override - public boolean validate(Element e) { - if (e.getArray() != null) { - return true; - } - return false; + STRING_ARRAY(PrimitiveType.STRING), + FILE_ARRAY(PrimitiveType.FILE); + + /** Type parameter of this array type. */ + public TargetPropertyType type; + + /** + * Private constructor to create a new array type. + * + * @param type The type of elements in the array. + */ + private ArrayType(TargetPropertyType type) { + this.type = type; + } + + /** + * Check that the passed in element represents an array and ensure that its elements are all of + * the correct type. + */ + @Override + public boolean check(Element e, String name, MessageReporter r) { + Array array = e.getArray(); + if (array != null) { + List elements = array.getElements(); + var valid = true; + for (int i = 0; i < elements.size(); i++) { + valid &= this.type.check(elements.get(i), name + "[" + i + "]", r); + } + return valid; } - - /** Return a human-readable description of this type. */ - @Override - public String toString() { - return "an array of which each element is " + this.type.toString(); + return false; + } + + /** Return true of the given element is an array. */ + @Override + public boolean validate(Element e) { + if (e.getArray() != null) { + return true; } -} \ No newline at end of file + return false; + } + + /** Return a human-readable description of this type. */ + @Override + public String toString() { + return "an array of which each element is " + this.type.toString(); + } +} diff --git a/core/src/main/java/org/lflang/target/property/type/CompilerConfig.java b/core/src/main/java/org/lflang/target/property/type/CompilerConfig.java deleted file mode 100644 index 80248bb0d6..0000000000 --- a/core/src/main/java/org/lflang/target/property/type/CompilerConfig.java +++ /dev/null @@ -1,14 +0,0 @@ -package org.lflang.target.property.type; - -import java.util.List; - -import org.lflang.Target; -import org.lflang.target.property.DefaultStringConfig; - -public class CompilerConfig extends DefaultStringConfig { - - @Override - public List supportedTargets() { - return Target.ALL; - } -} diff --git a/core/src/main/java/org/lflang/target/property/type/DictionaryType.java b/core/src/main/java/org/lflang/target/property/type/DictionaryType.java index 97691d2248..cbcb58d4c8 100644 --- a/core/src/main/java/org/lflang/target/property/type/DictionaryType.java +++ b/core/src/main/java/org/lflang/target/property/type/DictionaryType.java @@ -4,18 +4,17 @@ import java.util.List; import java.util.Optional; import java.util.stream.Collectors; - +import org.lflang.MessageReporter; import org.lflang.Target; import org.lflang.TargetProperty.DictionaryElement; import org.lflang.lf.Element; import org.lflang.lf.KeyValuePair; import org.lflang.lf.KeyValuePairs; +import org.lflang.target.property.ClockSyncOptionsProperty.ClockSyncOption; import org.lflang.target.property.CoordinationOptionsProperty.CoordinationOption; import org.lflang.target.property.DockerProperty.DockerOption; import org.lflang.target.property.PlatformProperty.PlatformOption; import org.lflang.target.property.TracingProperty.TracingOption; -import org.lflang.target.property.ClockSyncOptionsProperty.ClockSyncOption; -import org.lflang.validation.ValidationReporter; /** * A dictionary type with a predefined set of possible keys and assignable types. @@ -23,73 +22,73 @@ * @author Marten Lohstroh */ public enum DictionaryType implements TargetPropertyType { - CLOCK_SYNC_OPTION_DICT(Arrays.asList(ClockSyncOption.values())), - DOCKER_DICT(Arrays.asList(DockerOption.values())), - PLATFORM_DICT(Arrays.asList(PlatformOption.values())), - COORDINATION_OPTION_DICT(Arrays.asList(CoordinationOption.values())), - TRACING_DICT(Arrays.asList(TracingOption.values())); + CLOCK_SYNC_OPTION_DICT(Arrays.asList(ClockSyncOption.values())), + DOCKER_DICT(Arrays.asList(DockerOption.values())), + PLATFORM_DICT(Arrays.asList(PlatformOption.values())), + COORDINATION_OPTION_DICT(Arrays.asList(CoordinationOption.values())), + TRACING_DICT(Arrays.asList(TracingOption.values())); - /** The keys and assignable types that are allowed in this dictionary. */ - public List options; + /** The keys and assignable types that are allowed in this dictionary. */ + public List options; - /** - * A dictionary type restricted to sets of predefined keys and types of values. - * - * @param options The dictionary elements allowed by this type. - */ - private DictionaryType(List options) { - this.options = options; - } + /** + * A dictionary type restricted to sets of predefined keys and types of values. + * + * @param options The dictionary elements allowed by this type. + */ + private DictionaryType(List options) { + this.options = options; + } - /** - * Return the dictionary element of which the key matches the given string. - * - * @param name The string to match against. - * @return The matching dictionary element (or null if there is none). - */ - public DictionaryElement forName(String name) { - return Target.match(name, options); - } + /** + * Return the dictionary element of which the key matches the given string. + * + * @param name The string to match against. + * @return The matching dictionary element (or null if there is none). + */ + public DictionaryElement forName(String name) { + return Target.match(name, options); + } - /** Recursively check that the passed in element conforms to the rules of this dictionary. */ - @Override - public boolean check(Element e, String name, ValidationReporter v) { - KeyValuePairs kv = e.getKeyvalue(); - if (kv != null) { - var valid = true; - for (KeyValuePair pair : kv.getPairs()) { - String key = pair.getName(); - Element val = pair.getValue(); - Optional match = - this.options.stream() - .filter(element -> key.equalsIgnoreCase(element.toString())) - .findAny(); - if (match.isPresent()) { - // Make sure the type is correct, too. - TargetPropertyType type = match.get().getType(); - valid &= type.check(val, name + "." + key, v); - } else { - valid = false; - } - return valid; - } + /** Recursively check that the passed in element conforms to the rules of this dictionary. */ + @Override + public boolean check(Element e, String name, MessageReporter v) { + KeyValuePairs kv = e.getKeyvalue(); + if (kv != null) { + var valid = true; + for (KeyValuePair pair : kv.getPairs()) { + String key = pair.getName(); + Element val = pair.getValue(); + Optional match = + this.options.stream() + .filter(element -> key.equalsIgnoreCase(element.toString())) + .findAny(); + if (match.isPresent()) { + // Make sure the type is correct, too. + TargetPropertyType type = match.get().getType(); + valid &= type.check(val, name + "." + key, v); + } else { + valid = false; } - return false; + return valid; + } } + return false; + } - /** Return true if the given element represents a dictionary, false otherwise. */ - @Override - public boolean validate(Element e) { - if (e.getKeyvalue() != null) { - return true; - } - return false; + /** Return true if the given element represents a dictionary, false otherwise. */ + @Override + public boolean validate(Element e) { + if (e.getKeyvalue() != null) { + return true; } + return false; + } - /** Return a human-readable description of this type. */ - @Override - public String toString() { - return "a dictionary with one or more of the following keys: " - + options.stream().map(option -> option.toString()).collect(Collectors.joining(", ")); - } -} \ No newline at end of file + /** Return a human-readable description of this type. */ + @Override + public String toString() { + return "a dictionary with one or more of the following keys: " + + options.stream().map(option -> option.toString()).collect(Collectors.joining(", ")); + } +} diff --git a/core/src/main/java/org/lflang/target/property/type/PrimitiveType.java b/core/src/main/java/org/lflang/target/property/type/PrimitiveType.java index 868669243d..8afc08c12f 100644 --- a/core/src/main/java/org/lflang/target/property/type/PrimitiveType.java +++ b/core/src/main/java/org/lflang/target/property/type/PrimitiveType.java @@ -1,10 +1,9 @@ package org.lflang.target.property.type; import java.util.function.Predicate; - +import org.lflang.MessageReporter; import org.lflang.ast.ASTUtils; import org.lflang.lf.Element; -import org.lflang.validation.ValidationReporter; /** * Primitive types for target properties, each with a description used in error messages and @@ -13,86 +12,86 @@ * @author Marten Lohstroh */ public enum PrimitiveType implements TargetPropertyType { - BOOLEAN( - "'true' or 'false'", - v -> - ASTUtils.elementToSingleString(v).equalsIgnoreCase("true") - || ASTUtils.elementToSingleString(v).equalsIgnoreCase("false")), - INTEGER( - "an integer", - v -> { - try { - Integer.parseInt(ASTUtils.elementToSingleString(v)); - } catch (NumberFormatException e) { - return false; - } - return true; - }), - NON_NEGATIVE_INTEGER( - "a non-negative integer", - v -> { - try { - int result = Integer.parseInt(ASTUtils.elementToSingleString(v)); - if (result < 0) return false; - } catch (NumberFormatException e) { - return false; - } - return true; - }), - TIME_VALUE( - "a time value with units", - v -> - v.getKeyvalue() == null - && v.getArray() == null - && v.getLiteral() == null - && v.getId() == null - && (v.getTime() == 0 || v.getUnit() != null)), - STRING( - "a string", - v -> v.getLiteral() != null && !isCharLiteral(v.getLiteral()) || v.getId() != null), - FILE("a path to a file", STRING.validator); + BOOLEAN( + "'true' or 'false'", + v -> + ASTUtils.elementToSingleString(v).equalsIgnoreCase("true") + || ASTUtils.elementToSingleString(v).equalsIgnoreCase("false")), + INTEGER( + "an integer", + v -> { + try { + Integer.parseInt(ASTUtils.elementToSingleString(v)); + } catch (NumberFormatException e) { + return false; + } + return true; + }), + NON_NEGATIVE_INTEGER( + "a non-negative integer", + v -> { + try { + int result = Integer.parseInt(ASTUtils.elementToSingleString(v)); + if (result < 0) return false; + } catch (NumberFormatException e) { + return false; + } + return true; + }), + TIME_VALUE( + "a time value with units", + v -> + v.getKeyvalue() == null + && v.getArray() == null + && v.getLiteral() == null + && v.getId() == null + && (v.getTime() == 0 || v.getUnit() != null)), + STRING( + "a string", + v -> v.getLiteral() != null && !isCharLiteral(v.getLiteral()) || v.getId() != null), + FILE("a path to a file", STRING.validator); - /** A description of this type, featured in error messages. */ - private final String description; + /** A description of this type, featured in error messages. */ + private final String description; - /** A predicate for determining whether a given Element conforms to this type. */ - public final Predicate validator; + /** A predicate for determining whether a given Element conforms to this type. */ + public final Predicate validator; - /** - * Private constructor to create a new primitive type. - * - * @param description A textual description of the type that should start with "a/an". - * @param validator A predicate that returns true if a given Element conforms to this type. - */ - PrimitiveType(String description, Predicate validator) { - this.description = description; - this.validator = validator; - } + /** + * Private constructor to create a new primitive type. + * + * @param description A textual description of the type that should start with "a/an". + * @param validator A predicate that returns true if a given Element conforms to this type. + */ + PrimitiveType(String description, Predicate validator) { + this.description = description; + this.validator = validator; + } - /** Return true if the given Element is a valid instance of this type. */ - public boolean validate(Element e) { - return this.validator.test(e); - } + /** Return true if the given Element is a valid instance of this type. */ + public boolean validate(Element e) { + return this.validator.test(e); + } - /** - * Check (recursively) the given Element against its associated type(s) and add found problems - * to the given list of errors. - * - * @param e The element to type check. - * @param name The name of the target property. - * @param v The LFValidator to append errors to. - */ - public boolean check(Element e, String name, ValidationReporter v) { - return this.validate(e); - } + /** + * Check (recursively) the given Element against its associated type(s) and add found problems to + * the given list of errors. + * + * @param e The element to type check. + * @param name The name of the target property. + * @param v The LFValidator to append errors to. + */ + public boolean check(Element e, String name, MessageReporter v) { + return this.validate(e); + } - /** Return a textual description of this type. */ - @Override - public String toString() { - return this.description; - } + /** Return a textual description of this type. */ + @Override + public String toString() { + return this.description; + } - private static boolean isCharLiteral(String s) { - return s.length() > 2 && '\'' == s.charAt(0) && '\'' == s.charAt(s.length() - 1); - } + private static boolean isCharLiteral(String s) { + return s.length() > 2 && '\'' == s.charAt(0) && '\'' == s.charAt(s.length() - 1); + } } diff --git a/core/src/main/java/org/lflang/target/property/type/StringDictionaryType.java b/core/src/main/java/org/lflang/target/property/type/StringDictionaryType.java index dda0d6065e..8047b56bd1 100644 --- a/core/src/main/java/org/lflang/target/property/type/StringDictionaryType.java +++ b/core/src/main/java/org/lflang/target/property/type/StringDictionaryType.java @@ -1,37 +1,36 @@ package org.lflang.target.property.type; +import org.lflang.MessageReporter; import org.lflang.lf.Element; import org.lflang.lf.KeyValuePair; import org.lflang.lf.KeyValuePairs; -import org.lflang.validation.LFValidator; -import org.lflang.validation.ValidationReporter; /** Dictionary type that allows for keys that will be interpreted as strings and string values. */ public enum StringDictionaryType implements TargetPropertyType { - COMPILE_DEFINITION(); + COMPILE_DEFINITION(); - @Override - public boolean validate(Element e) { - if (e.getKeyvalue() != null) { - return true; - } - return false; + @Override + public boolean validate(Element e) { + if (e.getKeyvalue() != null) { + return true; } + return false; + } - @Override - public boolean check(Element e, String name, ValidationReporter v) { - KeyValuePairs kv = e.getKeyvalue(); - if (kv != null) { - var valid = true; - for (KeyValuePair pair : kv.getPairs()) { - String key = pair.getName(); - Element val = pair.getValue(); + @Override + public boolean check(Element e, String name, MessageReporter v) { + KeyValuePairs kv = e.getKeyvalue(); + if (kv != null) { + var valid = true; + for (KeyValuePair pair : kv.getPairs()) { + String key = pair.getName(); + Element val = pair.getValue(); - // Make sure the type is string - valid &= PrimitiveType.STRING.check(val, name + "." + key, v); - } - return valid; - } - return false; + // Make sure the type is string + valid &= PrimitiveType.STRING.check(val, name + "." + key, v); + } + return valid; } -} \ No newline at end of file + return false; + } +} diff --git a/core/src/main/java/org/lflang/target/property/type/TargetPropertyType.java b/core/src/main/java/org/lflang/target/property/type/TargetPropertyType.java index 06f0a5cbbb..d4c5009262 100644 --- a/core/src/main/java/org/lflang/target/property/type/TargetPropertyType.java +++ b/core/src/main/java/org/lflang/target/property/type/TargetPropertyType.java @@ -1,11 +1,7 @@ package org.lflang.target.property.type; -import java.util.function.Predicate; - -import org.lflang.ast.ASTUtils; +import org.lflang.MessageReporter; import org.lflang.lf.Element; -import org.lflang.validation.LFValidator; -import org.lflang.validation.ValidationReporter; /** * An interface for types associated with target properties. @@ -14,24 +10,21 @@ */ public interface TargetPropertyType { - /** - * Return true if the given Element is a valid instance of this type. - * - * @param e The Element to validate. - * @return True if the element conforms to this type, false otherwise. - */ - public boolean validate(Element e); - - /** - * Check (recursively) the given Element against its associated type(s) and add found problems - * to the given list of errors. - * - * @param e The Element to type check. - * @param name The name of the target property. - * @param v A reference to the validator to report errors to. - */ - public boolean check(Element e, String name, ValidationReporter v); - + /** + * Return true if the given Element is a valid instance of this type. + * + * @param e The Element to validate. + * @return True if the element conforms to this type, false otherwise. + */ + public boolean validate(Element e); + + /** + * Check (recursively) the given Element against its associated type(s) and add found problems to + * the given list of errors. + * + * @param e The Element to type check. + * @param name The name of the target property. + * @param r A reference to the validator to report errors to. + */ + public boolean check(Element e, String name, MessageReporter r); } - - diff --git a/core/src/main/java/org/lflang/target/property/type/UnionType.java b/core/src/main/java/org/lflang/target/property/type/UnionType.java index 351eef2b8e..2e046e68ae 100644 --- a/core/src/main/java/org/lflang/target/property/type/UnionType.java +++ b/core/src/main/java/org/lflang/target/property/type/UnionType.java @@ -4,17 +4,16 @@ import java.util.List; import java.util.Optional; import java.util.stream.Collectors; - +import org.lflang.MessageReporter; import org.lflang.Target; import org.lflang.ast.ASTUtils; import org.lflang.lf.Element; +import org.lflang.target.property.BuildConfig.BuildType; import org.lflang.target.property.ClockSyncModeProperty.ClockSyncMode; import org.lflang.target.property.CoordinationModeProperty.CoordinationMode; +import org.lflang.target.property.LoggingProperty.LogLevel; import org.lflang.target.property.PlatformProperty.Platform; import org.lflang.target.property.SchedulerProperty.SchedulerOption; -import org.lflang.target.property.BuildConfig.BuildType; -import org.lflang.target.property.LoggingProperty.LogLevel; -import org.lflang.validation.ValidationReporter; /** * A type that can assume one of several types. @@ -22,115 +21,115 @@ * @author Marten Lohstroh */ public enum UnionType implements TargetPropertyType { - STRING_OR_STRING_ARRAY(Arrays.asList(PrimitiveType.STRING, ArrayType.STRING_ARRAY), null), - PLATFORM_STRING_OR_DICTIONARY( - Arrays.asList(PrimitiveType.STRING, DictionaryType.PLATFORM_DICT), null), - FILE_OR_FILE_ARRAY(Arrays.asList(PrimitiveType.FILE, ArrayType.FILE_ARRAY), null), - BUILD_TYPE_UNION(Arrays.asList(BuildType.values()), null), - COORDINATION_UNION(Arrays.asList(CoordinationMode.values()), CoordinationMode.CENTRALIZED), - SCHEDULER_UNION(Arrays.asList(SchedulerOption.values()), SchedulerOption.getDefault()), - LOGGING_UNION(Arrays.asList(LogLevel.values()), LogLevel.INFO), - PLATFORM_UNION(Arrays.asList(Platform.values()), Platform.AUTO), - CLOCK_SYNC_UNION(Arrays.asList(ClockSyncMode.values()), ClockSyncMode.INIT), - DOCKER_UNION(Arrays.asList(PrimitiveType.BOOLEAN, DictionaryType.DOCKER_DICT), null), - TRACING_UNION(Arrays.asList(PrimitiveType.BOOLEAN, DictionaryType.TRACING_DICT), null); + STRING_OR_STRING_ARRAY(Arrays.asList(PrimitiveType.STRING, ArrayType.STRING_ARRAY), null), + PLATFORM_STRING_OR_DICTIONARY( + Arrays.asList(PrimitiveType.STRING, DictionaryType.PLATFORM_DICT), null), + FILE_OR_FILE_ARRAY(Arrays.asList(PrimitiveType.FILE, ArrayType.FILE_ARRAY), null), + BUILD_TYPE_UNION(Arrays.asList(BuildType.values()), null), + COORDINATION_UNION(Arrays.asList(CoordinationMode.values()), CoordinationMode.CENTRALIZED), + SCHEDULER_UNION(Arrays.asList(SchedulerOption.values()), SchedulerOption.getDefault()), + LOGGING_UNION(Arrays.asList(LogLevel.values()), LogLevel.INFO), + PLATFORM_UNION(Arrays.asList(Platform.values()), Platform.AUTO), + CLOCK_SYNC_UNION(Arrays.asList(ClockSyncMode.values()), ClockSyncMode.INIT), + DOCKER_UNION(Arrays.asList(PrimitiveType.BOOLEAN, DictionaryType.DOCKER_DICT), null), + TRACING_UNION(Arrays.asList(PrimitiveType.BOOLEAN, DictionaryType.TRACING_DICT), null); - /** The constituents of this type union. */ - public final List> options; + /** The constituents of this type union. */ + public final List> options; - /** The default type, if there is one. */ - private final Enum defaultOption; + /** The default type, if there is one. */ + private final Enum defaultOption; - /** - * Private constructor for creating unions types. - * - * @param options The types that that are part of the union. - * @param defaultOption The default type. - */ - private UnionType(List> options, Enum defaultOption) { - this.options = options; - this.defaultOption = defaultOption; - } + /** + * Private constructor for creating unions types. + * + * @param options The types that that are part of the union. + * @param defaultOption The default type. + */ + private UnionType(List> options, Enum defaultOption) { + this.options = options; + this.defaultOption = defaultOption; + } - /** - * Return the type among those in this type union that matches the given name. - * - * @param name The string to match against. - * @return The matching dictionary element (or null if there is none). - */ - public Enum forName(String name) { - return Target.match(name, options); - } + /** + * Return the type among those in this type union that matches the given name. + * + * @param name The string to match against. + * @return The matching dictionary element (or null if there is none). + */ + public Enum forName(String name) { + return Target.match(name, options); + } - /** Recursively check that the passed in element conforms to the rules of this union. */ - @Override - public boolean check(Element e, String name, ValidationReporter v) { - Optional> match = this.match(e); - var found = false; - if (match.isPresent()) { - // Go deeper if the element is an array or dictionary. - Enum type = match.get(); - if (type instanceof DictionaryType) { - found = ((DictionaryType) type).check(e, name, v); - } else if (type instanceof ArrayType) { - found = ((ArrayType) type).check(e, name, v); - } else if (type instanceof PrimitiveType) { - found = ((PrimitiveType) type).check(e, name, v); - } else if (!(type instanceof Enum)) { - throw new RuntimeException("Encountered an unknown type."); - } - } - return found; + /** Recursively check that the passed in element conforms to the rules of this union. */ + @Override + public boolean check(Element e, String name, MessageReporter r) { + Optional> match = this.match(e); + var found = false; + if (match.isPresent()) { + // Go deeper if the element is an array or dictionary. + Enum type = match.get(); + if (type instanceof DictionaryType) { + found = ((DictionaryType) type).check(e, name, r); + } else if (type instanceof ArrayType) { + found = ((ArrayType) type).check(e, name, r); + } else if (type instanceof PrimitiveType) { + found = ((PrimitiveType) type).check(e, name, r); + } else if (!(type instanceof Enum)) { + throw new RuntimeException("Encountered an unknown type."); + } } + return found; + } - /** - * Internal method for matching a given element against the allowable types. - * - * @param e AST node that represents the value of a target property. - * @return The matching type wrapped in an Optional object. - */ - private Optional> match(Element e) { - return this.options.stream() - .filter( - option -> { - if (option instanceof TargetPropertyType) { - return ((TargetPropertyType) option).validate(e); - } else { - return ASTUtils.elementToSingleString(e).equalsIgnoreCase(option.toString()); - } - }) - .findAny(); - } + /** + * Internal method for matching a given element against the allowable types. + * + * @param e AST node that represents the value of a target property. + * @return The matching type wrapped in an Optional object. + */ + private Optional> match(Element e) { + return this.options.stream() + .filter( + option -> { + if (option instanceof TargetPropertyType) { + return ((TargetPropertyType) option).validate(e); + } else { + return ASTUtils.elementToSingleString(e).equalsIgnoreCase(option.toString()); + } + }) + .findAny(); + } - /** - * Return true if this union has an option that matches the given element. - * - * @param e The element to match against this type. - */ - @Override - public boolean validate(Element e) { - if (this.match(e).isPresent()) { - return true; - } - return false; + /** + * Return true if this union has an option that matches the given element. + * + * @param e The element to match against this type. + */ + @Override + public boolean validate(Element e) { + if (this.match(e).isPresent()) { + return true; } + return false; + } - /** - * Return a human-readable description of this type. If three is a default option, then indicate - * it. - */ - @Override - public String toString() { - return "one of the following: " - + options.stream() + /** + * Return a human-readable description of this type. If three is a default option, then indicate + * it. + */ + @Override + public String toString() { + return "one of the following: " + + options.stream() .map( option -> { - if (option == this.defaultOption) { - return option.toString() + " (default)"; - } else { - return option.toString(); - } + if (option == this.defaultOption) { + return option.toString() + " (default)"; + } else { + return option.toString(); + } }) .collect(Collectors.joining(", ")); - } -} \ No newline at end of file + } +} diff --git a/core/src/main/java/org/lflang/validation/LFValidator.java b/core/src/main/java/org/lflang/validation/LFValidator.java index a742b8185d..eb2f0be22d 100644 --- a/core/src/main/java/org/lflang/validation/LFValidator.java +++ b/core/src/main/java/org/lflang/validation/LFValidator.java @@ -85,7 +85,6 @@ import org.lflang.lf.Initializer; import org.lflang.lf.Input; import org.lflang.lf.Instantiation; -import org.lflang.lf.KeyValuePair; import org.lflang.lf.KeyValuePairs; import org.lflang.lf.LfPackage.Literals; import org.lflang.lf.Literal; @@ -529,43 +528,6 @@ public void checkInstantiation(Instantiation instantiation) { } } - /** Check target parameters, which are key-value pairs. */ - @Check(CheckType.FAST) - public void checkKeyValuePair(KeyValuePair param) { - // Check only if the container's container is a Target. - if (param.eContainer().eContainer() instanceof TargetDecl) { - TargetProperty prop = TargetProperty.forName(param.getName()); - - // Make sure the key is valid. - if (prop == null) { - String options = - TargetProperty.getOptions().stream() - .map(p -> p.description) - .sorted() - .collect(Collectors.joining(", ")); - warning( - "Unrecognized target parameter: " - + param.getName() - + ". Recognized parameters are: " - + options, - Literals.KEY_VALUE_PAIR__NAME); - } else { - - } - - // Retrieve the errors that resulted from the check. - for (String it : targetPropertyErrors) { - error(it, Literals.KEY_VALUE_PAIR__VALUE); - } - targetPropertyErrors.clear(); - - for (String it : targetPropertyWarnings) { - error(it, Literals.KEY_VALUE_PAIR__VALUE); - } - targetPropertyWarnings.clear(); - } - } - @Check(CheckType.FAST) public void checkModel(Model model) { // Since we're doing a fast check, we only want to update @@ -1096,7 +1058,6 @@ public void checkTargetDecl(TargetDecl target) throws IOException { if (Character.isDigit(lfFileName.charAt(0))) { errorReporter.nowhere().error("LF file names must not start with a number"); } - } /** @@ -1106,29 +1067,8 @@ public void checkTargetDecl(TargetDecl target) throws IOException { */ @Check(CheckType.NORMAL) public void checkTargetProperties(KeyValuePairs targetProperties) { - Arrays.stream(TargetProperty.values()).forEach(p -> { - p.validate(targetProperties, this.info.model, this.targetConfig, - new ValidationReporter() { // FIXME: this is redundant because there already is a ValidatorMessageReporter class that I was unaware of. - @Override - public void error(String message, EObject source, EStructuralFeature feature) { - error(message, source, feature); - } - - @Override - public void warning(String message, EObject source, EStructuralFeature feature) { - warning(message, source, feature); - } - }); - }); - } - - private KeyValuePair getKeyValuePair(KeyValuePairs targetProperties, TargetProperty property) { - List properties = - targetProperties.getPairs().stream() - .filter(pair -> pair.getName().equals(property.description)) - .toList(); - assert (properties.size() <= 1); - return properties.size() > 0 ? properties.get(0) : null; + TargetProperty.validate( + targetProperties, this.info.model, this.targetConfig, getErrorReporter()); } @Check(CheckType.FAST) @@ -1543,11 +1483,6 @@ public ValidationMessageAcceptor getMessageAcceptor() { return messageAcceptor == null ? this : messageAcceptor; } - /** Report an error on the value of a target property */ - public void reportTargetPropertyError(String message) { - this.targetPropertyErrors.add(message); - } - ////////////////////////////////////////////////////////////// //// Protected methods. @@ -1848,10 +1783,6 @@ private boolean sameType(Type type1, Type type2) { /** The declared target. */ private Target target; - private List targetPropertyErrors = new ArrayList<>(); - - private List targetPropertyWarnings = new ArrayList<>(); - ////////////////////////////////////////////////////////////// //// Private static constants. diff --git a/core/src/main/java/org/lflang/validation/ValidationReporter.java b/core/src/main/java/org/lflang/validation/ValidationReporter.java deleted file mode 100644 index a2eba3a7ee..0000000000 --- a/core/src/main/java/org/lflang/validation/ValidationReporter.java +++ /dev/null @@ -1,11 +0,0 @@ -package org.lflang.validation; - -import org.eclipse.emf.ecore.EObject; -import org.eclipse.emf.ecore.EStructuralFeature; - -public interface ValidationReporter { - void error(String message, EObject source, EStructuralFeature feature); - - void warning(String message, EObject source, EStructuralFeature feature); - -} \ No newline at end of file diff --git a/core/src/main/java/org/lflang/validation/ValidatorMessageReporter.java b/core/src/main/java/org/lflang/validation/ValidatorMessageReporter.java index 387ad37a0f..36a796c81b 100644 --- a/core/src/main/java/org/lflang/validation/ValidatorMessageReporter.java +++ b/core/src/main/java/org/lflang/validation/ValidatorMessageReporter.java @@ -28,6 +28,7 @@ import java.nio.file.Path; import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.EStructuralFeature; import org.eclipse.lsp4j.DiagnosticSeverity; import org.eclipse.xtext.validation.ValidationMessageAcceptor; import org.lflang.MessageReporterBase; @@ -84,18 +85,16 @@ protected void report(Path path, Range range, DiagnosticSeverity severity, Strin reportOnNode(validatorState.getCurrentObject(), severity, fullMessage); } - - - @Override - protected void reportOnNode(EObject node, DiagnosticSeverity severity, String message) { + protected void reportOnNode( + EObject node, EStructuralFeature feature, DiagnosticSeverity severity, String message) { switch (severity) { case Error -> acceptor.acceptError( - message, node, null, ValidationMessageAcceptor.INSIGNIFICANT_INDEX, null); + message, node, feature, ValidationMessageAcceptor.INSIGNIFICANT_INDEX, null); case Warning -> acceptor.acceptWarning( - message, node, null, ValidationMessageAcceptor.INSIGNIFICANT_INDEX, null); + message, node, feature, ValidationMessageAcceptor.INSIGNIFICANT_INDEX, null); case Information, Hint -> acceptor.acceptInfo( - message, node, null, ValidationMessageAcceptor.INSIGNIFICANT_INDEX, null); + message, node, feature, ValidationMessageAcceptor.INSIGNIFICANT_INDEX, null); } } } diff --git a/core/src/main/kotlin/org/lflang/generator/cpp/CppExtensions.kt b/core/src/main/kotlin/org/lflang/generator/cpp/CppExtensions.kt index 4a1215a5f2..b525c8e481 100644 --- a/core/src/main/kotlin/org/lflang/generator/cpp/CppExtensions.kt +++ b/core/src/main/kotlin/org/lflang/generator/cpp/CppExtensions.kt @@ -13,7 +13,7 @@ import org.lflang.lf.TriggerRef import org.lflang.lf.VarRef import org.lflang.lf.Visibility import org.lflang.lf.WidthSpec -import org.lflang.target.LoggingProperty.LogLevel +import org.lflang.target.property.LoggingProperty /************* * Copyright (c) 2019-2021, TU Dresden. @@ -139,13 +139,13 @@ val InferredType.cppType: String /** Convert a log level to a severity number understood by the reactor-cpp runtime. */ -val LogLevel.severity +val LoggingProperty.LogLevel.severity get() = when (this) { - LogLevel.ERROR -> 1 - LogLevel.WARN -> 2 - LogLevel.INFO -> 3 - LogLevel.LOG -> 4 - LogLevel.DEBUG -> 4 + LoggingProperty.LogLevel.ERROR -> 1 + LoggingProperty.LogLevel.WARN -> 2 + LoggingProperty.LogLevel.INFO -> 3 + LoggingProperty.LogLevel.LOG -> 4 + LoggingProperty.LogLevel.DEBUG -> 4 } fun Reactor.hasBankIndexParameter() = parameters.firstOrNull { it.name == "bank_index" } != null diff --git a/core/src/main/kotlin/org/lflang/generator/cpp/CppGenerator.kt b/core/src/main/kotlin/org/lflang/generator/cpp/CppGenerator.kt index 55aaeebd8b..b98dc1d79c 100644 --- a/core/src/main/kotlin/org/lflang/generator/cpp/CppGenerator.kt +++ b/core/src/main/kotlin/org/lflang/generator/cpp/CppGenerator.kt @@ -71,7 +71,7 @@ class CppGenerator( // create a platform-specific generator val platformGenerator: CppPlatformGenerator = - if (targetConfig.ros2) CppRos2Generator(this) else CppStandaloneGenerator(this) + if (targetConfig.ros2.get()) CppRos2Generator(this) else CppStandaloneGenerator(this) // generate all core files generateFiles(platformGenerator.srcGenPath) @@ -79,7 +79,7 @@ class CppGenerator( // generate platform specific files platformGenerator.generatePlatformFiles() - if (targetConfig.noCompile || errorsOccurred()) { + if (targetConfig.noCompile.get() || errorsOccurred()) { println("Exiting before invoking target compiler.") context.finish(GeneratorResult.GENERATED_NO_EXECUTABLE.apply(context, codeMaps)) } else if (context.mode == Mode.LSP_MEDIUM) { diff --git a/core/src/main/kotlin/org/lflang/generator/cpp/CppPlatformGenerator.kt b/core/src/main/kotlin/org/lflang/generator/cpp/CppPlatformGenerator.kt index 07e11cfc18..68e226cbbf 100644 --- a/core/src/main/kotlin/org/lflang/generator/cpp/CppPlatformGenerator.kt +++ b/core/src/main/kotlin/org/lflang/generator/cpp/CppPlatformGenerator.kt @@ -29,7 +29,7 @@ abstract class CppPlatformGenerator(protected val generator: CppGenerator) { "-DREACTOR_CPP_VALIDATE=${if (targetConfig.noRuntimeValidation.get()) "OFF" else "ON"}", "-DREACTOR_CPP_PRINT_STATISTICS=${if (targetConfig.printStatistics.get()) "ON" else "OFF"}", "-DREACTOR_CPP_TRACE=${if (targetConfig.tracing != null) "ON" else "OFF"}", - "-DREACTOR_CPP_LOG_LEVEL=${targetConfig.logLevel.severity}", + "-DREACTOR_CPP_LOG_LEVEL=${targetConfig.logLevel.get().severity}", "-DLF_SRC_PKG_PATH=${fileConfig.srcPkgPath}", ) } diff --git a/core/src/main/kotlin/org/lflang/generator/cpp/CppRos2NodeGenerator.kt b/core/src/main/kotlin/org/lflang/generator/cpp/CppRos2NodeGenerator.kt index 3284f14924..ae9925d5e5 100644 --- a/core/src/main/kotlin/org/lflang/generator/cpp/CppRos2NodeGenerator.kt +++ b/core/src/main/kotlin/org/lflang/generator/cpp/CppRos2NodeGenerator.kt @@ -57,7 +57,7 @@ class CppRos2NodeGenerator( | |$nodeName::$nodeName(const rclcpp::NodeOptions& node_options) | : Node("$nodeName", node_options) { - | unsigned workers = ${if (targetConfig.workers != 0) targetConfig.workers else "std::thread::hardware_concurrency()"}; + | unsigned workers = ${if (targetConfig.workers.get() != 0) targetConfig.workers.get() else "std::thread::hardware_concurrency()"}; | bool fast{${targetConfig.fastMode}}; | reactor::Duration lf_timeout{${targetConfig.timeout.get()?.toCppCode() ?: "reactor::Duration::max()"}}; | diff --git a/core/src/main/kotlin/org/lflang/generator/cpp/CppStandaloneGenerator.kt b/core/src/main/kotlin/org/lflang/generator/cpp/CppStandaloneGenerator.kt index 192a5c62a4..94b18181a4 100644 --- a/core/src/main/kotlin/org/lflang/generator/cpp/CppStandaloneGenerator.kt +++ b/core/src/main/kotlin/org/lflang/generator/cpp/CppStandaloneGenerator.kt @@ -172,7 +172,7 @@ class CppStandaloneGenerator(generator: CppGenerator) : // prepare cmake if (targetConfig.compiler != null) { - cmd.setEnvironmentVariable("CXX", targetConfig.compiler) + cmd.setEnvironmentVariable("CXX", targetConfig.compiler.get()) } return cmd } diff --git a/core/src/main/kotlin/org/lflang/generator/cpp/CppStandaloneMainGenerator.kt b/core/src/main/kotlin/org/lflang/generator/cpp/CppStandaloneMainGenerator.kt index 07cd3f8ba2..41679daf4e 100644 --- a/core/src/main/kotlin/org/lflang/generator/cpp/CppStandaloneMainGenerator.kt +++ b/core/src/main/kotlin/org/lflang/generator/cpp/CppStandaloneMainGenerator.kt @@ -58,9 +58,9 @@ class CppStandaloneMainGenerator( |int main(int argc, char **argv) { | cxxopts::Options options("${fileConfig.name}", "Reactor Program"); | - | unsigned workers = ${if (targetConfig.workers != 0) targetConfig.workers else "std::thread::hardware_concurrency()"}; - | bool fast{${targetConfig.fastMode}}; - | reactor::Duration timeout = ${targetConfig.timeout?.toCppCode() ?: "reactor::Duration::max()"}; + | unsigned workers = ${if (targetConfig.workers.isSet) targetConfig.workers.get() else "std::thread::hardware_concurrency()"}; + | bool fast{${targetConfig.fastMode.get()}}; + | reactor::Duration timeout = ${if (targetConfig.timeout.isSet) targetConfig.timeout.get().toCppCode() else "reactor::Duration::max()"}; | | // the timeout variable needs to be tested beyond fitting the Duration-type | options @@ -96,8 +96,8 @@ class CppStandaloneMainGenerator( | | // assemble reactor program | e.assemble(); - ${" |".. if (targetConfig.exportDependencyGraph) "e.export_dependency_graph(\"${main.name}.dot\");" else ""} - ${" |".. if (targetConfig.exportToYaml) "e.dump_to_yaml(\"${main.name}.yaml\");" else ""} + ${" |".. if (targetConfig.exportDependencyGraph.get()) "e.export_dependency_graph(\"${main.name}.dot\");" else ""} + ${" |".. if (targetConfig.exportToYaml.get()) "e.dump_to_yaml(\"${main.name}.yaml\");" else ""} | | // start execution | auto thread = e.startup(); diff --git a/core/src/main/kotlin/org/lflang/generator/rust/RustGenerator.kt b/core/src/main/kotlin/org/lflang/generator/rust/RustGenerator.kt index b733db66de..bf4a84f9f3 100644 --- a/core/src/main/kotlin/org/lflang/generator/rust/RustGenerator.kt +++ b/core/src/main/kotlin/org/lflang/generator/rust/RustGenerator.kt @@ -78,7 +78,7 @@ class RustGenerator( val gen = RustModelBuilder.makeGenerationInfo(targetConfig, reactors, messageReporter) val codeMaps: Map = RustEmitter.generateRustProject(fileConfig, gen) - if (targetConfig.noCompile || errorsOccurred()) { + if (targetConfig.noCompile.get() || errorsOccurred()) { context.finish(GeneratorResult.GENERATED_NO_EXECUTABLE.apply(context, codeMaps)) println("Exiting before invoking target compiler.") } else { @@ -104,12 +104,12 @@ class RustGenerator( this += buildType.cargoProfileName } - if (targetConfig.rust.cargoFeatures.isNotEmpty()) { + if (targetConfig.rust.cargoFeatures.get().isNotEmpty()) { this += "--features" - this += targetConfig.rust.cargoFeatures.joinWithCommas() + this += targetConfig.rust.cargoFeatures.get().joinWithCommas() } - this += targetConfig.compilerFlags + this += targetConfig.compilerFlags.get() this += listOf("--message-format", "json-diagnostic-rendered-ansi") } 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 d2bef81a4f..b3d69ea548 100644 --- a/core/src/main/kotlin/org/lflang/generator/rust/RustModel.kt +++ b/core/src/main/kotlin/org/lflang/generator/rust/RustModel.kt @@ -428,7 +428,7 @@ object RustModelBuilder { val mainReactor = reactorsInfos.lastOrNull { it.isMain } ?: reactorsInfos.last() - val dependencies = targetConfig.rust.cargoDependencies.toMutableMap() + val dependencies = targetConfig.rust.cargoDependencies.get().toMutableMap() dependencies.compute(RustEmitterBase.runtimeCrateFullName) { _, spec -> computeDefaultRuntimeConfiguration(spec, targetConfig, messageReporter) } @@ -439,8 +439,8 @@ object RustModelBuilder { version = "1.0.0", authors = listOf(System.getProperty("user.name")), dependencies = dependencies, - modulesToIncludeInMain = targetConfig.rust.rustTopLevelModules, - enabledCargoFeatures = targetConfig.rust.cargoFeatures.toSet() + modulesToIncludeInMain = targetConfig.rust.rustTopLevelModules.get(), + enabledCargoFeatures = targetConfig.rust.cargoFeatures.get().toSet() ), reactors = reactorsInfos, mainReactor = mainReactor, @@ -479,14 +479,14 @@ object RustModelBuilder { val userRtVersion: String? = targetConfig.runtimeVersion.get() // enable parallel feature if asked - val parallelFeature = listOf(PARALLEL_RT_FEATURE).takeIf { targetConfig.threading } + val parallelFeature = listOf(PARALLEL_RT_FEATURE).takeIf { targetConfig.threading.get() } val spec = newCargoSpec( features = parallelFeature, ) if (targetConfig.externalRuntimePath != null) { - spec.localPath = targetConfig.externalRuntimePath + spec.localPath = targetConfig.externalRuntimePath.get() } else if (userRtVersion != null) { spec.gitRepo = RustEmitterBase.runtimeGitUrl spec.rev = userRtVersion @@ -497,7 +497,7 @@ object RustModelBuilder { return spec } else { if (targetConfig.externalRuntimePath != null) { - userSpec.localPath = targetConfig.externalRuntimePath + userSpec.localPath = targetConfig.externalRuntimePath.get() } if (userSpec.localPath == null && userSpec.gitRepo == null) { @@ -505,11 +505,11 @@ object RustModelBuilder { } // enable parallel feature if asked - if (targetConfig.threading) { + if (targetConfig.threading.get()) { userSpec.features += PARALLEL_RT_FEATURE } - if (!targetConfig.threading && PARALLEL_RT_FEATURE in userSpec.features) { + if (!targetConfig.threading.get() && PARALLEL_RT_FEATURE in userSpec.features) { messageReporter.nowhere().warning("Threading cannot be disabled as it was enabled manually as a runtime feature.") } @@ -520,11 +520,11 @@ object RustModelBuilder { private fun TargetConfig.toRustProperties(): RustTargetProperties = RustTargetProperties( keepAlive = this.keepalive.get(), - timeout = this.timeout?.toRustTimeExpr(), - timeoutLf = this.timeout, - singleFile = this.singleFileProject, - workers = this.workers, - dumpDependencyGraph = this.exportDependencyGraph, + timeout = this.timeout.get()?.toRustTimeExpr(), + timeoutLf = this.timeout.get(), + singleFile = this.singleFileProject.get(), + workers = this.workers.get(), + dumpDependencyGraph = this.exportDependencyGraph.get(), ) private fun makeReactorInfos(reactors: List): List = diff --git a/core/src/main/kotlin/org/lflang/generator/ts/TSGenerator.kt b/core/src/main/kotlin/org/lflang/generator/ts/TSGenerator.kt index a9f1e60be4..c4a3213bdc 100644 --- a/core/src/main/kotlin/org/lflang/generator/ts/TSGenerator.kt +++ b/core/src/main/kotlin/org/lflang/generator/ts/TSGenerator.kt @@ -94,8 +94,8 @@ class TSGenerator( init { // Set defaults for federate compilation. - targetConfig.compiler = "gcc" - targetConfig.compilerFlags.add("-O2") + targetConfig.compiler.override("gcc") + targetConfig.compilerFlags.get().add("-O2") } /** Generate TypeScript code from the Lingua Franca model contained by the @@ -131,7 +131,7 @@ class TSGenerator( // For small programs, everything up until this point is virtually instantaneous. This is the point where cancellation, // progress reporting, and IDE responsiveness become real considerations. - if (context.mode != LFGeneratorContext.Mode.LSP_MEDIUM && targetConfig.noCompile) { + if (context.mode != LFGeneratorContext.Mode.LSP_MEDIUM && targetConfig.noCompile.get()) { context.finish(GeneratorResult.GENERATED_NO_EXECUTABLE.apply(context, null)) } else { context.reportProgress( @@ -142,7 +142,7 @@ class TSGenerator( context.unsuccessfulFinish() return } - if (targetConfig.protoFiles.size != 0) { + if (targetConfig.protoFiles.get().size != 0) { protoc() } else { println("No .proto files have been imported. Skipping protocol buffer compilation.") @@ -246,7 +246,7 @@ class TSGenerator( val tsCode = StringBuilder() val preambleGenerator = TSImportPreambleGenerator(fileConfig.srcFile, - targetConfig.protoFiles, preambles) + targetConfig.protoFiles.get(), preambles) tsCode.append(preambleGenerator.generatePreamble()) val parameterGenerator = TSParameterPreambleGenerator(fileConfig, targetConfig, reactors) @@ -348,7 +348,7 @@ class TSGenerator( } private fun installProtoBufsIfNeeded(pnpmIsAvailable: Boolean, cwd: Path, cancelIndicator: CancelIndicator) { - if (targetConfig.protoFiles.size != 0) { + if (targetConfig.protoFiles.get().size != 0) { commandFactory.createCommand( if (pnpmIsAvailable) "pnpm" else "npm", listOf("install", "google-protobuf"), @@ -375,7 +375,7 @@ class TSGenerator( "--ts_out=$tsOutPath" ) ) - protocArgs.addAll(targetConfig.protoFiles) + protocArgs.addAll(targetConfig.protoFiles.get()) val protoc = commandFactory.createCommand("protoc", protocArgs, fileConfig.srcPath) if (protoc == null) { diff --git a/core/src/main/kotlin/org/lflang/generator/ts/TSParameterPreambleGenerator.kt b/core/src/main/kotlin/org/lflang/generator/ts/TSParameterPreambleGenerator.kt index 305369832e..dc68c7f2f9 100644 --- a/core/src/main/kotlin/org/lflang/generator/ts/TSParameterPreambleGenerator.kt +++ b/core/src/main/kotlin/org/lflang/generator/ts/TSParameterPreambleGenerator.kt @@ -27,7 +27,6 @@ package org.lflang.generator.ts import org.lflang.FileConfig import org.lflang.TargetConfig -import org.lflang.joinWithCommasLn import org.lflang.joinWithLn import org.lflang.lf.Parameter import org.lflang.lf.Reactor @@ -50,7 +49,7 @@ class TSParameterPreambleGenerator( ) { private fun getTimeoutTimeValue(): String = - targetConfig.timeout?.toTsTime() ?: "undefined" + targetConfig.timeout.get()?.toTsTime() ?: "undefined" private fun getParameters(): List { var mainReactor: Reactor? = null @@ -236,7 +235,7 @@ class TSParameterPreambleGenerator( | throw new Error("'logging' command line argument is malformed."); | } |} else { - | Log.global.level = Log.levels.${targetConfig.logLevel.name}; // Default from target property. + | Log.global.level = Log.levels.${targetConfig.logLevel.get().name}; // Default from target property. |} | |// Help parameter (not a constructor parameter, but a command line option) 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 628d8cef4b..498fcecdc9 100644 --- a/core/src/test/java/org/lflang/tests/compiler/LinguaFrancaValidationTest.java +++ b/core/src/test/java/org/lflang/tests/compiler/LinguaFrancaValidationTest.java @@ -46,16 +46,16 @@ import org.junit.jupiter.api.extension.ExtendWith; import org.lflang.Target; import org.lflang.TargetProperty; -import org.lflang.target.property.type.ArrayType; import org.lflang.TargetProperty.DictionaryElement; import org.lflang.TimeValue; import org.lflang.lf.LfPackage; import org.lflang.lf.Model; import org.lflang.lf.Visibility; +import org.lflang.target.property.type.ArrayType; import org.lflang.target.property.type.DictionaryType; +import org.lflang.target.property.type.PrimitiveType; import org.lflang.target.property.type.StringDictionaryType; import org.lflang.target.property.type.TargetPropertyType; -import org.lflang.target.property.type.PrimitiveType; import org.lflang.target.property.type.UnionType; import org.lflang.tests.LFInjectorProvider; import org.lflang.util.StringUtil; @@ -1444,7 +1444,7 @@ private List synthesizeExamples(TargetPropertyType type, boolean correct * the resulting model. */ private Model createModel(TargetProperty key, String value) throws Exception { - String target = key.supportedBy.get(0).getDisplayName(); + var target = TargetProperty.getPropertyInstance(key).supportedTargets().stream().findFirst(); return parseWithoutError( """ target %s {%s: %s}; @@ -1461,22 +1461,23 @@ private Model createModel(TargetProperty key, String value) throws Exception { public Collection checkTargetProperties() throws Exception { List result = new ArrayList<>(); - for (TargetProperty prop : TargetProperty.getOptions()) { - if (prop == TargetProperty.CARGO_DEPENDENCIES) { + for (TargetProperty property : TargetProperty.getOptions()) { + if (property == TargetProperty.CARGO_DEPENDENCIES) { // we test that separately as it has better error messages continue; } - List knownCorrect = synthesizeExamples(prop.type, true); + var type = TargetProperty.getPropertyInstance(property).type; + List knownCorrect = synthesizeExamples(type, true); for (String it : knownCorrect) { var test = DynamicTest.dynamicTest( - "Property %s (%s) - known good assignment: %s".formatted(prop, prop.type, it), + "Property %s (%s) - known good assignment: %s".formatted(property, type, it), () -> { - Model model = createModel(prop, it); + Model model = createModel(property, it); validator.assertNoErrors(model); // Also make sure warnings are produced when files are not present. - if (prop.type == PrimitiveType.FILE) { + if (type == PrimitiveType.FILE) { validator.assertWarning( model, LfPackage.eINSTANCE.getKeyValuePair(), @@ -1502,47 +1503,47 @@ public Collection checkTargetProperties() throws Exception { // ] // } - List knownIncorrect = synthesizeExamples(prop.type, false); + List knownIncorrect = synthesizeExamples(type, false); if (!(knownIncorrect == null || knownIncorrect.isEmpty())) { for (String it : knownIncorrect) { var test = DynamicTest.dynamicTest( - "Property %s (%s) - known bad assignment: %s".formatted(prop, prop.type, it), + "Property %s (%s) - known bad assignment: %s".formatted(property, type, it), () -> { - if (prop.type instanceof StringDictionaryType) { + if (type instanceof StringDictionaryType) { validator.assertError( - createModel(prop, it), + createModel(property, it), LfPackage.eINSTANCE.getKeyValuePair(), null, - String.format("Target property '%s.", prop), + String.format("Target property '%s.", property), "' is required to be a string."); } else { validator.assertError( - createModel(prop, it), + createModel(property, it), LfPackage.eINSTANCE.getKeyValuePair(), null, String.format( - "Target property '%s' is required to be %s.", prop, prop.type)); + "Target property '%s' is required to be %s.", property, type)); } }); result.add(test); } } else { // No type was synthesized. It must be a composite type. - List> list = compositeTypeToKnownBad.get(prop.type); + List> list = compositeTypeToKnownBad.get(type); if (list != null) { for (List it : list) { var test = DynamicTest.dynamicTest( - "Property %s (%s) - known bad assignment: %s".formatted(prop, prop.type, it), + "Property %s (%s) - known bad assignment: %s".formatted(property, type, it), () -> validator.assertError( - createModel(prop, it.get(0).toString()), + createModel(property, it.get(0).toString()), LfPackage.eINSTANCE.getKeyValuePair(), null, String.format( "Target property '%s%s' is required to be %s.", - prop, it.get(1), it.get(2)))); + property, it.get(1), it.get(2)))); result.add(test); } } diff --git a/core/src/testFixtures/java/org/lflang/tests/Configurators.java b/core/src/testFixtures/java/org/lflang/tests/Configurators.java index 436e9585ca..0bd79016ca 100644 --- a/core/src/testFixtures/java/org/lflang/tests/Configurators.java +++ b/core/src/testFixtures/java/org/lflang/tests/Configurators.java @@ -24,9 +24,8 @@ package org.lflang.tests; -import org.lflang.TargetProperty; -import org.lflang.target.property.PlatformProperty.Platform; import org.lflang.target.property.LoggingProperty.LogLevel; +import org.lflang.target.property.PlatformProperty.Platform; import org.lflang.tests.TestRegistry.TestCategory; /** @@ -66,8 +65,8 @@ public static boolean disableThreading(LFTest test) { public static boolean makeZephyrCompatibleUnthreaded(LFTest test) { test.getContext().getArgs().setProperty("tracing", "false"); - test.getContext().getTargetConfig().setByUser.add(TargetProperty.THREADING); - test.getContext().getTargetConfig().threading = false; + test.getContext().getTargetConfig().threading.override(false); + // FIXME: use a record and override. test.getContext().getTargetConfig().platformOptions.get().platform = Platform.ZEPHYR; test.getContext().getTargetConfig().platformOptions.get().flash = false; test.getContext().getTargetConfig().platformOptions.get().board = "qemu_cortex_m3"; @@ -118,7 +117,7 @@ public static boolean compatibleWithThreadingOff(TestCategory category) { || category == TestCategory.ZEPHYR_THREADED; // SERIALIZATION and TARGET tests are excluded on Windows. - excluded |= TestBase.isWindows() && (category == TestCategory.TARGET); + excluded |= TestBase.isWindows() && category == TestCategory.TARGET; return !excluded; } } From 39b0161289efbb5740d2f2d10d915ce3c1276248 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Wed, 27 Sep 2023 21:40:36 -0700 Subject: [PATCH 008/145] Apply formatter --- core/src/main/java/org/lflang/generator/c/CCmakeGenerator.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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 e3c03da378..c24fc60ac2 100644 --- a/core/src/main/java/org/lflang/generator/c/CCmakeGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CCmakeGenerator.java @@ -328,7 +328,8 @@ CodeBuilder generateCMakeCode( cMakeCode.newLine(); } - if (targetConfig.threading.get() && targetConfig.platformOptions.get().platform != Platform.ZEPHYR) { + if (targetConfig.threading.get() + && targetConfig.platformOptions.get().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)"); From 3eb35de90ff3af25815732ccdef72cf5181c0e8c Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Thu, 28 Sep 2023 00:43:53 -0700 Subject: [PATCH 009/145] Some fixes and a fixme --- .../main/java/org/lflang/TargetProperty.java | 27 ++++++++++++++++--- .../launcher/FedLauncherGenerator.java | 2 +- .../org/lflang/generator/c/CGenerator.java | 4 +-- .../generator/c/CPreambleGenerator.java | 7 +++-- .../generator/cpp/CppPlatformGenerator.kt | 2 +- .../compiler/LinguaFrancaValidationTest.java | 7 ++--- 6 files changed, 34 insertions(+), 15 deletions(-) diff --git a/core/src/main/java/org/lflang/TargetProperty.java b/core/src/main/java/org/lflang/TargetProperty.java index 005405bc49..25a705ea0a 100644 --- a/core/src/main/java/org/lflang/TargetProperty.java +++ b/core/src/main/java/org/lflang/TargetProperty.java @@ -37,6 +37,7 @@ 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.AuthProperty; @@ -333,6 +334,11 @@ public static List extractProperties(TargetConfig config) { return res; } + /** + * Return all the target properties that have been set. + * + * @param config The configuration to find the properties in. + */ public static List loaded(TargetConfig config) { return Arrays.stream(TargetProperty.values()) .filter(it -> it.property.of(config).isSet()) @@ -373,14 +379,27 @@ public static KeyValuePair getKeyValuePair(Model ast, TargetProperty property) { public static void validate( KeyValuePairs pairs, Model ast, TargetConfig config, ValidatorMessageReporter reporter) { - Arrays.stream(TargetProperty.values()) + pairs.getPairs().stream() .forEach( - p -> { - var pair = getKeyValuePair(pairs, p); - if (pair != null) { + pair -> { + var match = + Arrays.stream(TargetProperty.values()) + .filter(prop -> prop.name().equalsIgnoreCase(pair.getName())) + .findAny(); + if (match.isPresent()) { + var p = match.get(); p.property.of(config).checkSupport(pair, config, reporter); p.property.of(config).checkType(pair, config, reporter); p.property.of(config).validate(pair, ast, config, reporter); + } else { + // FIXME: not showing up... + reporter + .at(pair, Literals.KEY_VALUE_PAIR__NAME) + .warning( + "Unrecognized target parameter: " + + pair.getName() + + ". Recognized parameters are: " + + TargetProperty.values()); } }); } diff --git a/core/src/main/java/org/lflang/federated/launcher/FedLauncherGenerator.java b/core/src/main/java/org/lflang/federated/launcher/FedLauncherGenerator.java index da4081b753..61d3deef77 100644 --- a/core/src/main/java/org/lflang/federated/launcher/FedLauncherGenerator.java +++ b/core/src/main/java/org/lflang/federated/launcher/FedLauncherGenerator.java @@ -337,7 +337,7 @@ private String getRtiCommand(List federates, boolean isRemote) if (targetConfig.auth.get()) { commands.add(" -a \\"); } - if (targetConfig.tracing != null) { + if (targetConfig.tracing.get().isEnabled()) { commands.add(" -t \\"); } commands.addAll( 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 4ee4b0f6d3..6138f6d54a 100644 --- a/core/src/main/java/org/lflang/generator/c/CGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CGenerator.java @@ -1404,7 +1404,7 @@ private void recordBuiltinTriggers(ReactorInstance instance) { foundOne = true; enclaveInfo.numShutdownReactions += reactor.getTotalWidth(); - if (targetConfig.tracing != null) { + if (targetConfig.tracing.get().isEnabled()) { var description = CUtil.getShortenedName(reactor); var reactorRef = CUtil.reactorRef(reactor); var envTraceRef = CUtil.getEnvironmentStruct(reactor) + ".trace"; @@ -1687,7 +1687,7 @@ public static String variableStructType(TriggerInstance portOrAction) { * @param instance The reactor instance. */ private void generateTraceTableEntries(ReactorInstance instance) { - if (targetConfig.tracing != null) { + if (targetConfig.tracing.get().isEnabled()) { initializeTriggerObjects.pr(CTracingGenerator.generateTraceTableEntries(instance)); } } 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 fbba2f01a0..0c0cc7c911 100644 --- a/core/src/main/java/org/lflang/generator/c/CPreambleGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CPreambleGenerator.java @@ -26,7 +26,7 @@ public class CPreambleGenerator { /** Add necessary source files specific to the target language. */ public static String generateIncludeStatements(TargetConfig targetConfig, boolean cppMode) { - var tracing = targetConfig.tracing; + CodeBuilder code = new CodeBuilder(); if (cppMode || targetConfig.platformOptions.get().platform == Platform.ARDUINO) { code.pr("extern \"C\" {"); @@ -41,7 +41,7 @@ public static String generateIncludeStatements(TargetConfig targetConfig, boolea code.pr("#include \"include/core/threaded/scheduler.h\""); } - if (tracing != null) { + if (targetConfig.tracing.get().isEnabled()) { code.pr("#include \"include/core/trace.h\""); } code.pr("#include \"include/core/mixed_radix.h\""); @@ -62,14 +62,13 @@ public static String generateIncludeStatements(TargetConfig targetConfig, boolea public static String generateDefineDirectives( TargetConfig targetConfig, Path srcGenPath, boolean hasModalReactors) { int logLevel = targetConfig.logLevel.get().ordinal(); - var coordinationType = targetConfig.coordination; var tracing = targetConfig.tracing.get(); CodeBuilder code = new CodeBuilder(); // TODO: Get rid of all of these code.pr("#define LOG_LEVEL " + logLevel); code.pr("#define TARGET_FILES_DIRECTORY " + addDoubleQuotes(srcGenPath.toString())); - if (tracing != null) { + if (tracing.isEnabled()) { targetConfig.compileDefinitions.get().put("LF_TRACE", tracing.traceFileName); } // if (clockSyncIsOn) { diff --git a/core/src/main/kotlin/org/lflang/generator/cpp/CppPlatformGenerator.kt b/core/src/main/kotlin/org/lflang/generator/cpp/CppPlatformGenerator.kt index 68e226cbbf..8e44d95940 100644 --- a/core/src/main/kotlin/org/lflang/generator/cpp/CppPlatformGenerator.kt +++ b/core/src/main/kotlin/org/lflang/generator/cpp/CppPlatformGenerator.kt @@ -28,7 +28,7 @@ abstract class CppPlatformGenerator(protected val generator: CppGenerator) { "-DCMAKE_BUILD_TYPE=${targetConfig.buildType}", "-DREACTOR_CPP_VALIDATE=${if (targetConfig.noRuntimeValidation.get()) "OFF" else "ON"}", "-DREACTOR_CPP_PRINT_STATISTICS=${if (targetConfig.printStatistics.get()) "ON" else "OFF"}", - "-DREACTOR_CPP_TRACE=${if (targetConfig.tracing != null) "ON" else "OFF"}", + "-DREACTOR_CPP_TRACE=${if (targetConfig.tracing.get().isEnabled) "ON" else "OFF"}", "-DREACTOR_CPP_LOG_LEVEL=${targetConfig.logLevel.get().severity}", "-DLF_SRC_PKG_PATH=${fileConfig.srcPkgPath}", ) 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 498fcecdc9..5039b92ab8 100644 --- a/core/src/test/java/org/lflang/tests/compiler/LinguaFrancaValidationTest.java +++ b/core/src/test/java/org/lflang/tests/compiler/LinguaFrancaValidationTest.java @@ -1444,7 +1444,8 @@ private List synthesizeExamples(TargetPropertyType type, boolean correct * the resulting model. */ private Model createModel(TargetProperty key, String value) throws Exception { - var target = TargetProperty.getPropertyInstance(key).supportedTargets().stream().findFirst(); + var target = + TargetProperty.getPropertyInstance(key).supportedTargets().stream().findFirst().get(); return parseWithoutError( """ target %s {%s: %s}; @@ -1781,13 +1782,13 @@ public void testOverflowingDeadline() throws Exception { public void testInvalidTargetParam() throws Exception { String testCase = """ - target C { beefyDesktop: true } + target C { foobarbaz: true } main reactor {} """; List issues = validator.validate(parseWithoutError(testCase)); Assertions.assertTrue( issues.size() == 1 - && issues.get(0).getMessage().contains("Unrecognized target parameter: beefyDesktop")); + && issues.get(0).getMessage().contains("Unrecognized target parameter: foobarbaz")); } @Test From a3531a18a90cbd1dde5b1279f01802984b7fd8a4 Mon Sep 17 00:00:00 2001 From: Christian Menard Date: Thu, 28 Sep 2023 11:29:13 +0200 Subject: [PATCH 010/145] fix NPE --- 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 6138f6d54a..e0726cd21e 100644 --- a/core/src/main/java/org/lflang/generator/c/CGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CGenerator.java @@ -634,7 +634,7 @@ private void generateCodeFor(String lfModuleName) throws IOException { code.pr(envFuncGen.generateDefinitions()); - if (targetConfig.fedSetupPreamble != null) { + if (targetConfig.fedSetupPreamble.isSet()) { if (targetLanguageIsCpp()) code.pr("extern \"C\" {"); code.pr("#include \"" + targetConfig.fedSetupPreamble + "\""); if (targetLanguageIsCpp()) code.pr("}"); From b7b457dfe6e1ed926db92dd6052968f6374c80e6 Mon Sep 17 00:00:00 2001 From: Christian Menard Date: Thu, 28 Sep 2023 11:30:12 +0200 Subject: [PATCH 011/145] IntelliJ code suggestions --- core/src/main/java/org/lflang/TargetProperty.java | 4 +--- .../org/lflang/tests/compiler/LinguaFrancaValidationTest.java | 4 ++-- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/core/src/main/java/org/lflang/TargetProperty.java b/core/src/main/java/org/lflang/TargetProperty.java index 25a705ea0a..d87df988c6 100644 --- a/core/src/main/java/org/lflang/TargetProperty.java +++ b/core/src/main/java/org/lflang/TargetProperty.java @@ -273,9 +273,7 @@ private interface ConfigLoader { public static TargetPropertyConfig getPropertyInstance(TargetProperty p) { try { return p.propertyClass.newInstance(); - } catch (InstantiationException e) { - throw new RuntimeException(e); - } catch (IllegalAccessException e) { + } catch (InstantiationException | IllegalAccessException e) { throw new RuntimeException(e); } } 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 5039b92ab8..e012eb6788 100644 --- a/core/src/test/java/org/lflang/tests/compiler/LinguaFrancaValidationTest.java +++ b/core/src/test/java/org/lflang/tests/compiler/LinguaFrancaValidationTest.java @@ -1350,7 +1350,7 @@ private List synthesizeExamples(UnionType type, boolean correct) { if (correct) { for (Enum it : type.options) { if (it instanceof TargetPropertyType) { - synthesizeExamples((TargetPropertyType) it, correct).forEach(ex -> examples.add(ex)); + examples.addAll(synthesizeExamples((TargetPropertyType) it, correct)); } else { examples.add(it.toString()); } @@ -1358,7 +1358,7 @@ private List synthesizeExamples(UnionType type, boolean correct) { } else { // Return some obviously bad examples for the common // case where the options are from an ordinary Enum. - if (!type.options.stream().anyMatch(it -> it instanceof TargetPropertyType)) { + if (type.options.stream().noneMatch(it -> it instanceof TargetPropertyType)) { return List.of("foo", "\"bar\"", "1", "-1", "{x: 42}", "[1, 2, 3]"); } } From c617b49e993a1cbcf30b57a765d84cd5869b442d Mon Sep 17 00:00:00 2001 From: Christian Menard Date: Thu, 28 Sep 2023 11:52:20 +0200 Subject: [PATCH 012/145] fix error reporting on estructural elements --- core/src/main/java/org/lflang/MessageReporterBase.java | 2 +- core/src/main/java/org/lflang/TargetProperty.java | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/core/src/main/java/org/lflang/MessageReporterBase.java b/core/src/main/java/org/lflang/MessageReporterBase.java index b195a80319..edd39d2799 100644 --- a/core/src/main/java/org/lflang/MessageReporterBase.java +++ b/core/src/main/java/org/lflang/MessageReporterBase.java @@ -45,7 +45,7 @@ public Stage2 at(EObject node) { @Override public Stage2 at(EObject node, EStructuralFeature feature) { - return null; + return wrap((severity, message) -> reportOnNode(node, feature, severity, message)); } @Override diff --git a/core/src/main/java/org/lflang/TargetProperty.java b/core/src/main/java/org/lflang/TargetProperty.java index d87df988c6..84dfbd0c17 100644 --- a/core/src/main/java/org/lflang/TargetProperty.java +++ b/core/src/main/java/org/lflang/TargetProperty.java @@ -390,7 +390,6 @@ public static void validate( p.property.of(config).checkType(pair, config, reporter); p.property.of(config).validate(pair, ast, config, reporter); } else { - // FIXME: not showing up... reporter .at(pair, Literals.KEY_VALUE_PAIR__NAME) .warning( From ed6d91b518377e6ac1780489a6532252591ffdc1 Mon Sep 17 00:00:00 2001 From: Christian Menard Date: Thu, 28 Sep 2023 11:55:10 +0200 Subject: [PATCH 013/145] correctly list all the valid target properties --- .../main/java/org/lflang/TargetProperty.java | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/org/lflang/TargetProperty.java b/core/src/main/java/org/lflang/TargetProperty.java index 84dfbd0c17..508a6332ec 100644 --- a/core/src/main/java/org/lflang/TargetProperty.java +++ b/core/src/main/java/org/lflang/TargetProperty.java @@ -270,6 +270,17 @@ private interface ConfigLoader { this.property = property; } + /** + * Return key ot the property as it will be used in LF code. + * + *

Keys are of the form foo-bar. + * + * @return the property's key + */ + public String getKey() { + return name().toLowerCase().replace('_', '-'); + } + public static TargetPropertyConfig getPropertyInstance(TargetProperty p) { try { return p.propertyClass.newInstance(); @@ -375,6 +386,11 @@ public static KeyValuePair getKeyValuePair(Model ast, TargetProperty property) { return getKeyValuePair(ast.getTarget().getConfig(), property); } + /** Return a list containing the keys of all properties */ + public static List getPropertyKeys() { + return Arrays.stream(TargetProperty.values()).map(TargetProperty::getKey).toList(); + } + public static void validate( KeyValuePairs pairs, Model ast, TargetConfig config, ValidatorMessageReporter reporter) { pairs.getPairs().stream() @@ -396,7 +412,7 @@ public static void validate( "Unrecognized target parameter: " + pair.getName() + ". Recognized parameters are: " - + TargetProperty.values()); + + getPropertyKeys()); } }); } From 20d911b4d63b42ca69b180cb5c29c19a3c17271b Mon Sep 17 00:00:00 2001 From: Christian Menard Date: Thu, 28 Sep 2023 11:59:17 +0200 Subject: [PATCH 014/145] null safety --- core/src/main/java/org/lflang/TargetPropertyConfig.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/org/lflang/TargetPropertyConfig.java b/core/src/main/java/org/lflang/TargetPropertyConfig.java index 4382d0ecf4..35fc6936a5 100644 --- a/core/src/main/java/org/lflang/TargetPropertyConfig.java +++ b/core/src/main/java/org/lflang/TargetPropertyConfig.java @@ -110,7 +110,7 @@ public boolean isSet() { @Override public String toString() { - return value.toString(); + return value == null ? null : value.toString(); } public void markSet() { From b3e6d9639fd914a18d7104fb71361e07719f8d39 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Thu, 28 Sep 2023 08:36:59 -0700 Subject: [PATCH 015/145] Fix conflict --- core/src/main/java/org/lflang/TargetProperty.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/org/lflang/TargetProperty.java b/core/src/main/java/org/lflang/TargetProperty.java index 508a6332ec..7740516559 100644 --- a/core/src/main/java/org/lflang/TargetProperty.java +++ b/core/src/main/java/org/lflang/TargetProperty.java @@ -25,6 +25,7 @@ package org.lflang; +import java.lang.reflect.InvocationTargetException; import java.nio.file.Path; import java.util.Arrays; import java.util.LinkedList; @@ -283,8 +284,8 @@ public String getKey() { public static TargetPropertyConfig getPropertyInstance(TargetProperty p) { try { - return p.propertyClass.newInstance(); - } catch (InstantiationException | IllegalAccessException e) { + return p.propertyClass.getDeclaredConstructor().newInstance(); + } catch (ReflectiveOperationException e) { throw new RuntimeException(e); } } From a22550bcaabbf4dd0c6b48d228aa3b8ec92dadc3 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Fri, 29 Sep 2023 00:16:52 -0700 Subject: [PATCH 016/145] Minor bugfixes --- .../main/java/org/lflang/TargetConfig.java | 71 ++++++++++--------- .../main/java/org/lflang/TargetProperty.java | 6 +- .../federated/generator/FedGenerator.java | 7 +- .../federated/generator/FedTargetConfig.java | 3 +- .../target/property/DockerProperty.java | 1 + .../target/property/TracingProperty.java | 4 +- .../target/property/type/UnionType.java | 2 + .../compiler/LinguaFrancaValidationTest.java | 21 ++---- 8 files changed, 56 insertions(+), 59 deletions(-) diff --git a/core/src/main/java/org/lflang/TargetConfig.java b/core/src/main/java/org/lflang/TargetConfig.java index 06fa8008b0..4e35f7a587 100644 --- a/core/src/main/java/org/lflang/TargetConfig.java +++ b/core/src/main/java/org/lflang/TargetConfig.java @@ -99,7 +99,7 @@ public TargetConfig(Properties cliArgs, TargetDecl target, MessageReporter messa this(target); if (target.getConfig() != null) { List pairs = target.getConfig().getPairs(); - TargetProperty.load(this, pairs != null ? pairs : List.of(), messageReporter); + TargetProperty.load(this, pairs, messageReporter); } if (cliArgs != null) { @@ -112,7 +112,7 @@ public TargetConfig(Properties cliArgs, TargetDecl target, MessageReporter messa * designated compiler. A common usage of this target property is to set the command to build on * the basis of a Makefile. */ - public BuildCommandsProperty buildCommands = new BuildCommandsProperty(); + public final BuildCommandsProperty buildCommands = new BuildCommandsProperty(); /** * The mode of clock synchronization to be used in federated programs. The default is 'initial'. @@ -123,16 +123,16 @@ public TargetConfig(Properties cliArgs, TargetDecl target, MessageReporter messa public final ClockSyncOptionsProperty clockSyncOptions = new ClockSyncOptionsProperty(); /** Parameter passed to cmake. The default is 'Release'. */ - public BuildTypeProperty buildType = new BuildTypeProperty(); + public final BuildTypeProperty buildType = new BuildTypeProperty(); /** Optional additional extensions to include in the generated CMakeLists.txt. */ - public CmakeIncludeProperty cmakeIncludes = new CmakeIncludeProperty(); + public final CmakeIncludeProperty cmakeIncludes = new CmakeIncludeProperty(); /** The compiler to invoke, unless a build command has been specified. */ - public CompilerProperty compiler = new CompilerProperty(); + public final CompilerProperty compiler = new CompilerProperty(); /** Additional sources to add to the compile command if appropriate. */ - public List compileAdditionalSources = new ArrayList<>(); + public final List compileAdditionalSources = new ArrayList<>(); /** * Additional (preprocessor) definitions to add to the compile command if appropriate. @@ -140,55 +140,55 @@ public TargetConfig(Properties cliArgs, TargetDecl target, MessageReporter messa *

The first string is the definition itself, and the second string is the value to attribute * to that definition, if any. The second value could be left empty. */ - public CompileDefinitionsProperty compileDefinitions = new CompileDefinitionsProperty(); + public final CompileDefinitionsProperty compileDefinitions = new CompileDefinitionsProperty(); /** Flags to pass to the compiler, unless a build command has been specified. */ - public CompilerFlagsProperty compilerFlags = new CompilerFlagsProperty(); + public final CompilerFlagsProperty compilerFlags = new CompilerFlagsProperty(); /** * The type of coordination used during the execution of a federated program. The default is * 'centralized'. */ - public CoordinationModeProperty coordination = new CoordinationModeProperty(); + public final CoordinationModeProperty coordination = new CoordinationModeProperty(); /** Docker options. */ - public DockerProperty dockerOptions = new DockerProperty(); + public final DockerProperty dockerOptions = new DockerProperty(); /** Coordination options. */ - public CoordinationOptionsProperty coordinationOptions = new CoordinationOptionsProperty(); + public final CoordinationOptionsProperty coordinationOptions = new CoordinationOptionsProperty(); /** Link to an external runtime library instead of the default one. */ - public ExternalRuntimePathProperty externalRuntimePath = new ExternalRuntimePathProperty(); + public final ExternalRuntimePathProperty externalRuntimePath = new ExternalRuntimePathProperty(); /** * If true, configure the execution environment such that it does not wait for physical time to * match logical time. The default is false. */ - public FastProperty fastMode = new FastProperty(); + public final FastProperty fastMode = new FastProperty(); /** List of files to be copied to src-gen. */ - public FilesProperty files = new FilesProperty(); + public final FilesProperty files = new FilesProperty(); /** * If true, configure the execution environment to keep executing if there are no more events on * the event queue. The default is false. */ - public KeepaliveProperty keepalive = new KeepaliveProperty(); + public final KeepaliveProperty keepalive = new KeepaliveProperty(); /** The level of logging during execution. The default is INFO. */ - public LoggingProperty logLevel = new LoggingProperty(); + public final LoggingProperty logLevel = new LoggingProperty(); /** Flags to pass to the linker, unless a build command has been specified. */ public String linkerFlags = ""; /** If true, do not invoke the target compiler or build command. The default is false. */ - public NoCompileProperty noCompile = new NoCompileProperty(); + public final NoCompileProperty noCompile = new NoCompileProperty(); /** If true, do not perform runtime validation. The default is false. */ - public NoRuntimeValidationProperty noRuntimeValidation = new NoRuntimeValidationProperty(); + public final NoRuntimeValidationProperty noRuntimeValidation = new NoRuntimeValidationProperty(); /** If true, check the generated verification model. The default is false. */ - public VerifyProperty verify = new VerifyProperty(); + public final VerifyProperty verify = new VerifyProperty(); /** * Set the target platform config. This tells the build system what platform-specific support @@ -197,46 +197,46 @@ public TargetConfig(Properties cliArgs, TargetDecl target, MessageReporter messa *

This is now a wrapped class to account for overloaded definitions of defining platform * (either a string or dictionary of values) */ - public PlatformProperty platformOptions = new PlatformProperty(); + public final PlatformProperty platformOptions = new PlatformProperty(); /** If true, instruct the runtime to collect and print execution statistics. */ - public PrintStatisticsProperty printStatistics = new PrintStatisticsProperty(); + public final PrintStatisticsProperty printStatistics = new PrintStatisticsProperty(); /** List of proto files to be processed by the code generator. */ - public ProtobufsProperty protoFiles = new ProtobufsProperty(); + public final ProtobufsProperty protoFiles = new ProtobufsProperty(); /** If true, generate ROS2 specific code. */ - public Ros2Property ros2 = new Ros2Property(); + public final Ros2Property ros2 = new Ros2Property(); /** Additional ROS2 packages that the LF program depends on. */ - public Ros2DependenciesProperty ros2Dependencies = new Ros2DependenciesProperty(); + public final Ros2DependenciesProperty ros2Dependencies = new Ros2DependenciesProperty(); /** The version of the runtime library to be used in the generated target. */ - public RuntimeVersionProperty runtimeVersion = new RuntimeVersionProperty(); + public final RuntimeVersionProperty runtimeVersion = new RuntimeVersionProperty(); /** Whether all reactors are to be generated into a single target language file. */ - public SingleFileProjectProperty singleFileProject = new SingleFileProjectProperty(); + public final SingleFileProjectProperty singleFileProject = new SingleFileProjectProperty(); /** What runtime scheduler to use. */ - public SchedulerProperty schedulerType = new SchedulerProperty(); + public final SchedulerProperty schedulerType = new SchedulerProperty(); /** * The number of worker threads to deploy. The default is zero, which indicates that the runtime * is allowed to freely choose the number of workers. */ - public WorkersProperty workers = new WorkersProperty(); + public final WorkersProperty workers = new WorkersProperty(); /** Indicate whether HMAC authentication is used. */ - public AuthProperty auth = new AuthProperty(); + public final AuthProperty auth = new AuthProperty(); /** Indicate whether the runtime should use multithreaded execution. */ - public ThreadingProperty threading = new ThreadingProperty(); + public final ThreadingProperty threading = new ThreadingProperty(); /** The timeout to be observed during execution of the program. */ - public TimeOutProperty timeout = new TimeOutProperty(); + public final TimeOutProperty timeout = new TimeOutProperty(); /** If non-null, configure the runtime environment to perform tracing. The default is null. */ - public TracingProperty tracing = new TracingProperty(); + public final TracingProperty tracing = new TracingProperty(); /** * If true, the resulting binary will output a graph visualizing all reaction dependencies. @@ -244,7 +244,8 @@ public TargetConfig(Properties cliArgs, TargetDecl target, MessageReporter messa *

This option is currently only used for C++ and Rust. This export function is a valuable tool * for debugging LF programs and helps to understand the dependencies inferred by the runtime. */ - public ExportDependencyGraphProperty exportDependencyGraph = new ExportDependencyGraphProperty(); + public final ExportDependencyGraphProperty exportDependencyGraph = + new ExportDependencyGraphProperty(); /** * If true, the resulting binary will output a yaml file describing the whole reactor structure of @@ -253,11 +254,11 @@ public TargetConfig(Properties cliArgs, TargetDecl target, MessageReporter messa *

This option is currently only used for C++. This export function is a valuable tool for * debugging LF programs and performing external analysis. */ - public ExportToYamlProperty exportToYaml = new ExportToYamlProperty(); + public final ExportToYamlProperty exportToYaml = new ExportToYamlProperty(); /** Rust-specific configuration. */ public final RustTargetConfig rust = new RustTargetConfig(); /** Path to a C file used by the Python target to setup federated execution. */ - public FedSetupProperty fedSetupPreamble = new FedSetupProperty(); + public final FedSetupProperty fedSetupPreamble = new FedSetupProperty(); } diff --git a/core/src/main/java/org/lflang/TargetProperty.java b/core/src/main/java/org/lflang/TargetProperty.java index 7740516559..a5095b9d45 100644 --- a/core/src/main/java/org/lflang/TargetProperty.java +++ b/core/src/main/java/org/lflang/TargetProperty.java @@ -25,7 +25,6 @@ package org.lflang; -import java.lang.reflect.InvocationTargetException; import java.nio.file.Path; import java.util.Arrays; import java.util.LinkedList; @@ -311,6 +310,9 @@ public static void load(TargetConfig config, Properties properties, MessageRepor * @param err Error reporter on which property format errors will be reported */ public static void load(TargetConfig config, List properties, MessageReporter err) { + if (properties == null) { + return; + } properties.forEach( property -> { TargetProperty p = forName(property.getName()); @@ -399,7 +401,7 @@ public static void validate( pair -> { var match = Arrays.stream(TargetProperty.values()) - .filter(prop -> prop.name().equalsIgnoreCase(pair.getName())) + .filter(prop -> prop.toString().equalsIgnoreCase(pair.getName())) .findAny(); if (match.isPresent()) { var p = match.get(); 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 b23ef6a085..91583b8865 100644 --- a/core/src/main/java/org/lflang/federated/generator/FedGenerator.java +++ b/core/src/main/java/org/lflang/federated/generator/FedGenerator.java @@ -193,11 +193,14 @@ private void generateLaunchScript() { * @param subContexts The subcontexts in which the federates have been compiled. */ private void createDockerFiles(LFGeneratorContext context, List subContexts) { - if (context.getTargetConfig().dockerOptions == null) return; + if (!context.getTargetConfig().dockerOptions.isSet()) return; final List services = new ArrayList<>(); // 1. create a Dockerfile for each federate for (SubContext subContext : subContexts) { // Inherit Docker options from main context - subContext.getTargetConfig().dockerOptions = context.getTargetConfig().dockerOptions; + subContext + .getTargetConfig() + .dockerOptions + .override(context.getTargetConfig().dockerOptions.get()); var dockerGenerator = dockerGeneratorFactory(subContext); var dockerData = dockerGenerator.generateDockerData(); try { diff --git a/core/src/main/java/org/lflang/federated/generator/FedTargetConfig.java b/core/src/main/java/org/lflang/federated/generator/FedTargetConfig.java index 87b4fec960..852cb762e1 100644 --- a/core/src/main/java/org/lflang/federated/generator/FedTargetConfig.java +++ b/core/src/main/java/org/lflang/federated/generator/FedTargetConfig.java @@ -36,7 +36,8 @@ public FedTargetConfig(LFGeneratorContext context, Resource federateResource) { mergeImportedConfig( federateResource, context.getFileConfig().resource, context.getErrorReporter()); - clearPropertiesToIgnore(); + clearPropertiesToIgnore(); // FIXME: add boolean inherit() function to TargetPropertyConfig + // instead ((FedFileConfig) context.getFileConfig()).relativizePaths(this); } 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 83864ac96e..82171a81cb 100644 --- a/core/src/main/java/org/lflang/target/property/DockerProperty.java +++ b/core/src/main/java/org/lflang/target/property/DockerProperty.java @@ -38,6 +38,7 @@ public DockerOptions fromAst(Element value, MessageReporter err) { } } else { for (KeyValuePair entry : value.getKeyvalue().getPairs()) { + options.enabled = true; DockerOption option = (DockerOption) DictionaryType.DOCKER_DICT.forName(entry.getName()); if (Objects.requireNonNull(option) == DockerOption.FROM) { options.from = ASTUtils.elementToSingleString(entry.getValue()); 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 3d6cca84ad..4bb9c54d40 100644 --- a/core/src/main/java/org/lflang/target/property/TracingProperty.java +++ b/core/src/main/java/org/lflang/target/property/TracingProperty.java @@ -36,8 +36,8 @@ public TracingOptions initialValue() { public TracingOptions fromAst(Element value, MessageReporter err) { var options = new TracingOptions(false); if (value.getLiteral() != null) { - if (!ASTUtils.toBoolean(value)) { - options.enabled = false; + if (ASTUtils.toBoolean(value)) { + options.enabled = true; } } else { for (KeyValuePair entry : value.getKeyvalue().getPairs()) { diff --git a/core/src/main/java/org/lflang/target/property/type/UnionType.java b/core/src/main/java/org/lflang/target/property/type/UnionType.java index 2e046e68ae..511f0b7d9c 100644 --- a/core/src/main/java/org/lflang/target/property/type/UnionType.java +++ b/core/src/main/java/org/lflang/target/property/type/UnionType.java @@ -77,6 +77,8 @@ public boolean check(Element e, String name, MessageReporter r) { found = ((PrimitiveType) type).check(e, name, r); } else if (!(type instanceof Enum)) { throw new RuntimeException("Encountered an unknown type."); + } else { + found = true; } } return found; 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 e012eb6788..db0bb6428d 100644 --- a/core/src/test/java/org/lflang/tests/compiler/LinguaFrancaValidationTest.java +++ b/core/src/test/java/org/lflang/tests/compiler/LinguaFrancaValidationTest.java @@ -1489,21 +1489,6 @@ public Collection checkTargetProperties() throws Exception { result.add(test); } - // Extra checks for filenames. (This piece of code was commented out in the original xtend - // file) - // Temporarily disabled because we need a more sophisticated check that looks for files in - // different places. - // if (prop.type == prop.type == ArrayType.FILE_ARRAY || - // prop.type == UnionType.FILE_OR_FILE_ARRAY) { - // val model = prop.createModel( - // synthesizeExamples(ArrayType.FILE_ARRAY, true).get(0)) - // primitiveTypeToKnownGood.get(PrimitiveType.FILE).forEach [ - // model.assertWarning( - // LfPackage.eINSTANCE.keyValuePair, - // null, '''Could not find file: '«it.withoutQuotes»'.''') - // ] - // } - List knownIncorrect = synthesizeExamples(type, false); if (!(knownIncorrect == null || knownIncorrect.isEmpty())) { for (String it : knownIncorrect) { @@ -1537,14 +1522,16 @@ public Collection checkTargetProperties() throws Exception { var test = DynamicTest.dynamicTest( "Property %s (%s) - known bad assignment: %s".formatted(property, type, it), - () -> + () -> { + System.out.println(it); validator.assertError( createModel(property, it.get(0).toString()), LfPackage.eINSTANCE.getKeyValuePair(), null, String.format( "Target property '%s%s' is required to be %s.", - property, it.get(1), it.get(2)))); + property, it.get(1), it.get(2))); + }); result.add(test); } } From 44abb6b19dd9e06ebea36fce659e8ff5df85f22d Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Fri, 29 Sep 2023 00:31:35 -0700 Subject: [PATCH 017/145] Only generate docker when enabled --- .../lflang/federated/generator/FedGenerator.java | 7 ++++--- .../org/lflang/generator/c/CDockerGenerator.java | 2 +- .../java/org/lflang/generator/c/CGenerator.java | 4 ++-- .../org/lflang/generator/ts/TSGenerator.kt | 2 +- .../compiler/LinguaFrancaValidationTest.java | 16 ++++++++-------- 5 files changed, 16 insertions(+), 15 deletions(-) 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 91583b8865..67540c745f 100644 --- a/core/src/main/java/org/lflang/federated/generator/FedGenerator.java +++ b/core/src/main/java/org/lflang/federated/generator/FedGenerator.java @@ -193,7 +193,7 @@ private void generateLaunchScript() { * @param subContexts The subcontexts in which the federates have been compiled. */ private void createDockerFiles(LFGeneratorContext context, List subContexts) { - if (!context.getTargetConfig().dockerOptions.isSet()) return; + if (!context.getTargetConfig().dockerOptions.get().enabled) return; final List services = new ArrayList<>(); // 1. create a Dockerfile for each federate for (SubContext subContext : subContexts) { // Inherit Docker options from main context @@ -294,7 +294,8 @@ private Map compileFederates( new LineAdjustingMessageReporter(threadSafeErrorReporter, lf2lfCodeMapMap); var props = new Properties(); - if (targetConfig.dockerOptions != null && targetConfig.target.buildsUsingDocker()) { + if (targetConfig.dockerOptions.get().enabled + && targetConfig.target.buildsUsingDocker()) { props.put("no-compile", "true"); } props.put("docker", "false"); @@ -420,7 +421,7 @@ private void analyzeFederates(Reactor federation, LFGeneratorContext context) { rtiConfig.setHost(federation.getHost().getAddr()); } // If the federation is dockerized, use "rti" as the hostname. - if (rtiConfig.getHost().equals("localhost") && targetConfig.dockerOptions != null) { + if (rtiConfig.getHost().equals("localhost") && targetConfig.dockerOptions.get().enabled) { rtiConfig.setHost("rti"); } diff --git a/core/src/main/java/org/lflang/generator/c/CDockerGenerator.java b/core/src/main/java/org/lflang/generator/c/CDockerGenerator.java index f6dc1bf200..0474b06ea9 100644 --- a/core/src/main/java/org/lflang/generator/c/CDockerGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CDockerGenerator.java @@ -35,7 +35,7 @@ protected String generateDockerFileContent() { : StringUtil.joinObjects(config.buildCommands.get(), " "); var compiler = config.target == Target.CCPP ? "g++" : "gcc"; var baseImage = DEFAULT_BASE_IMAGE; - if (config.dockerOptions != null && config.dockerOptions.get().from != null) { + if (config.dockerOptions.get().enabled && config.dockerOptions.get().from != null) { baseImage = config.dockerOptions.get().from; } return String.join( 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 e0726cd21e..f6a2daa7ae 100644 --- a/core/src/main/java/org/lflang/generator/c/CGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CGenerator.java @@ -419,7 +419,7 @@ public void doGenerate(Resource resource, LFGeneratorContext context) { } // Create docker file. - if (targetConfig.dockerOptions != null && mainDef != null) { + if (targetConfig.dockerOptions.get().enabled && mainDef != null) { try { var dockerData = getDockerGenerator(context).generateDockerData(); dockerData.writeDockerFile(); @@ -537,7 +537,7 @@ public void doGenerate(Resource resource, LFGeneratorContext context) { // If this code generator is directly compiling the code, compile it now so that we // clean it up after, removing the #line directives after errors have been reported. if (!targetConfig.noCompile.get() - && targetConfig.dockerOptions == null + && !targetConfig.dockerOptions.get().enabled && IterableExtensions.isNullOrEmpty(targetConfig.buildCommands.get()) // This code is unreachable in LSP_FAST mode, so that check is omitted. && context.getMode() != LFGeneratorContext.Mode.LSP_MEDIUM) { diff --git a/core/src/main/kotlin/org/lflang/generator/ts/TSGenerator.kt b/core/src/main/kotlin/org/lflang/generator/ts/TSGenerator.kt index c4a3213bdc..add6402ed3 100644 --- a/core/src/main/kotlin/org/lflang/generator/ts/TSGenerator.kt +++ b/core/src/main/kotlin/org/lflang/generator/ts/TSGenerator.kt @@ -123,7 +123,7 @@ class TSGenerator( val codeMaps = HashMap() generateCode(codeMaps, resource.model.preambles) - if (targetConfig.dockerOptions != null) { + if (targetConfig.dockerOptions.get().enabled) { val dockerData = TSDockerGenerator(context).generateDockerData(); dockerData.writeDockerFile() DockerComposeGenerator(context).writeDockerComposeFile(listOf(dockerData)) 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 db0bb6428d..6b9e9fa4a2 100644 --- a/core/src/test/java/org/lflang/tests/compiler/LinguaFrancaValidationTest.java +++ b/core/src/test/java/org/lflang/tests/compiler/LinguaFrancaValidationTest.java @@ -1523,14 +1523,14 @@ public Collection checkTargetProperties() throws Exception { DynamicTest.dynamicTest( "Property %s (%s) - known bad assignment: %s".formatted(property, type, it), () -> { - System.out.println(it); - validator.assertError( - createModel(property, it.get(0).toString()), - LfPackage.eINSTANCE.getKeyValuePair(), - null, - String.format( - "Target property '%s%s' is required to be %s.", - property, it.get(1), it.get(2))); + System.out.println(it); + validator.assertError( + createModel(property, it.get(0).toString()), + LfPackage.eINSTANCE.getKeyValuePair(), + null, + String.format( + "Target property '%s%s' is required to be %s.", + property, it.get(1), it.get(2))); }); result.add(test); } From 43479be4ff357584ac0ad13b903675633f05784a Mon Sep 17 00:00:00 2001 From: Christian Menard Date: Fri, 29 Sep 2023 16:28:45 +0200 Subject: [PATCH 018/145] clean up build types, no need for a separate config class --- .../org/lflang/generator/c/CCompiler.java | 4 +-- .../generator/rust/RustTargetConfig.java | 4 +-- .../lflang/target/property/BuildConfig.java | 32 ------------------- .../target/property/BuildTypeProperty.java | 30 ++++++++++++++++- .../target/property/type/UnionType.java | 4 +-- .../generator/cpp/CppStandaloneGenerator.kt | 2 +- .../generator/rust/RustCargoTomlEmitter.kt | 2 +- .../lflang/generator/rust/RustGenerator.kt | 2 +- .../org/lflang/generator/rust/RustModel.kt | 2 +- 9 files changed, 39 insertions(+), 43 deletions(-) delete mode 100644 core/src/main/java/org/lflang/target/property/BuildConfig.java diff --git a/core/src/main/java/org/lflang/generator/c/CCompiler.java b/core/src/main/java/org/lflang/generator/c/CCompiler.java index deabdc42a5..a8bfa1f328 100644 --- a/core/src/main/java/org/lflang/generator/c/CCompiler.java +++ b/core/src/main/java/org/lflang/generator/c/CCompiler.java @@ -40,7 +40,7 @@ import org.lflang.generator.GeneratorCommandFactory; import org.lflang.generator.GeneratorUtils; import org.lflang.generator.LFGeneratorContext; -import org.lflang.target.property.BuildConfig; +import org.lflang.target.property.BuildTypeProperty; import org.lflang.target.property.PlatformProperty.Platform; import org.lflang.util.FileUtil; import org.lflang.util.LFCommand; @@ -261,7 +261,7 @@ private static List cmakeOptions(TargetConfig targetConfig, FileConfig f } /** Return the cmake config name corresponding to a given build type. */ - private String buildTypeToCmakeConfig(BuildConfig.BuildType type) { + private String buildTypeToCmakeConfig(BuildTypeProperty.BuildType type) { if (type == null) { return "Release"; } diff --git a/core/src/main/java/org/lflang/generator/rust/RustTargetConfig.java b/core/src/main/java/org/lflang/generator/rust/RustTargetConfig.java index bc287260fd..006163db13 100644 --- a/core/src/main/java/org/lflang/generator/rust/RustTargetConfig.java +++ b/core/src/main/java/org/lflang/generator/rust/RustTargetConfig.java @@ -24,7 +24,7 @@ package org.lflang.generator.rust; -import org.lflang.target.property.BuildConfig.BuildType; +import org.lflang.target.property.BuildTypeProperty.BuildType; import org.lflang.target.property.BuildTypeProperty; import org.lflang.target.property.CargoDependenciesProperty; import org.lflang.target.property.CargoFeaturesProperty; @@ -47,7 +47,7 @@ public final class RustTargetConfig { public final RustIncludeProperty rustTopLevelModules = new RustIncludeProperty(); /** Cargo profile, default is debug (corresponds to cargo dev profile). */ - private BuildType profile = BuildType.DEBUG; + private BuildType profile = BuildTypeProperty.BuildType.DEBUG; /** The build type to use. Corresponds to a Cargo profile. */ public BuildType getBuildType(BuildTypeProperty cmakeBuildType) { diff --git a/core/src/main/java/org/lflang/target/property/BuildConfig.java b/core/src/main/java/org/lflang/target/property/BuildConfig.java deleted file mode 100644 index 5d1ea7c8e3..0000000000 --- a/core/src/main/java/org/lflang/target/property/BuildConfig.java +++ /dev/null @@ -1,32 +0,0 @@ -package org.lflang.target.property; - -public class BuildConfig { - - /** - * Enumeration of Cmake build types. These are also mapped to Cargo profiles for the Rust target - * (see {@link org.lflang.generator.rust.RustTargetConfig}) - * - * @author Christian Menard - */ - public enum BuildType { - RELEASE("Release"), - DEBUG("Debug"), - TEST("Test"), - REL_WITH_DEB_INFO("RelWithDebInfo"), - MIN_SIZE_REL("MinSizeRel"); - - /** Alias used in toString method. */ - private final String alias; - - /** Private constructor for Cmake build types. */ - BuildType(String alias) { - this.alias = alias; - } - - /** Return the alias. */ - @Override - public String toString() { - return this.alias; - } - } -} diff --git a/core/src/main/java/org/lflang/target/property/BuildTypeProperty.java b/core/src/main/java/org/lflang/target/property/BuildTypeProperty.java index d4d3e2cee6..3007c9391c 100644 --- a/core/src/main/java/org/lflang/target/property/BuildTypeProperty.java +++ b/core/src/main/java/org/lflang/target/property/BuildTypeProperty.java @@ -7,7 +7,7 @@ import org.lflang.TargetPropertyConfig; import org.lflang.ast.ASTUtils; import org.lflang.lf.Element; -import org.lflang.target.property.BuildConfig.BuildType; +import org.lflang.target.property.BuildTypeProperty.BuildType; import org.lflang.target.property.type.UnionType; public class BuildTypeProperty extends TargetPropertyConfig { @@ -40,4 +40,32 @@ protected BuildType fromString(String value, MessageReporter err) { public List supportedTargets() { return Arrays.asList(Target.C, Target.CCPP, Target.CPP, Target.Rust); } + + /** + * Enumeration of Cmake build types. These are also mapped to Cargo profiles for the Rust target + * (see {@link org.lflang.generator.rust.RustTargetConfig}) + * + * @author Christian Menard + */ + public enum BuildType { + RELEASE("Release"), + DEBUG("Debug"), + TEST("Test"), + REL_WITH_DEB_INFO("RelWithDebInfo"), + MIN_SIZE_REL("MinSizeRel"); + + /** Alias used in toString method. */ + private final String alias; + + /** Private constructor for Cmake build types. */ + BuildType(String alias) { + this.alias = alias; + } + + /** Return the alias. */ + @Override + public String toString() { + return this.alias; + } + } } diff --git a/core/src/main/java/org/lflang/target/property/type/UnionType.java b/core/src/main/java/org/lflang/target/property/type/UnionType.java index 511f0b7d9c..a4f1cdbb36 100644 --- a/core/src/main/java/org/lflang/target/property/type/UnionType.java +++ b/core/src/main/java/org/lflang/target/property/type/UnionType.java @@ -8,7 +8,7 @@ import org.lflang.Target; import org.lflang.ast.ASTUtils; import org.lflang.lf.Element; -import org.lflang.target.property.BuildConfig.BuildType; +import org.lflang.target.property.BuildTypeProperty; import org.lflang.target.property.ClockSyncModeProperty.ClockSyncMode; import org.lflang.target.property.CoordinationModeProperty.CoordinationMode; import org.lflang.target.property.LoggingProperty.LogLevel; @@ -25,7 +25,7 @@ public enum UnionType implements TargetPropertyType { PLATFORM_STRING_OR_DICTIONARY( Arrays.asList(PrimitiveType.STRING, DictionaryType.PLATFORM_DICT), null), FILE_OR_FILE_ARRAY(Arrays.asList(PrimitiveType.FILE, ArrayType.FILE_ARRAY), null), - BUILD_TYPE_UNION(Arrays.asList(BuildType.values()), null), + BUILD_TYPE_UNION(Arrays.asList(BuildTypeProperty.BuildType.values()), null), COORDINATION_UNION(Arrays.asList(CoordinationMode.values()), CoordinationMode.CENTRALIZED), SCHEDULER_UNION(Arrays.asList(SchedulerOption.values()), SchedulerOption.getDefault()), LOGGING_UNION(Arrays.asList(LogLevel.values()), LogLevel.INFO), diff --git a/core/src/main/kotlin/org/lflang/generator/cpp/CppStandaloneGenerator.kt b/core/src/main/kotlin/org/lflang/generator/cpp/CppStandaloneGenerator.kt index 94b18181a4..b7c9bd8982 100644 --- a/core/src/main/kotlin/org/lflang/generator/cpp/CppStandaloneGenerator.kt +++ b/core/src/main/kotlin/org/lflang/generator/cpp/CppStandaloneGenerator.kt @@ -1,6 +1,6 @@ package org.lflang.generator.cpp -import org.lflang.target.property.BuildConfig.BuildType +import org.lflang.target.property.BuildTypeProperty.BuildType import org.lflang.generator.CodeMap import org.lflang.generator.LFGeneratorContext import org.lflang.toUnixString diff --git a/core/src/main/kotlin/org/lflang/generator/rust/RustCargoTomlEmitter.kt b/core/src/main/kotlin/org/lflang/generator/rust/RustCargoTomlEmitter.kt index 2a733438ec..e7690e78e5 100644 --- a/core/src/main/kotlin/org/lflang/generator/rust/RustCargoTomlEmitter.kt +++ b/core/src/main/kotlin/org/lflang/generator/rust/RustCargoTomlEmitter.kt @@ -24,7 +24,7 @@ package org.lflang.generator.rust -import org.lflang.target.property.BuildConfig.BuildType.* +import org.lflang.target.property.BuildTypeProperty.BuildType.* import org.lflang.escapeStringLiteral import org.lflang.generator.PrependOperator.rangeTo import org.lflang.joinWithCommas diff --git a/core/src/main/kotlin/org/lflang/generator/rust/RustGenerator.kt b/core/src/main/kotlin/org/lflang/generator/rust/RustGenerator.kt index bf4a84f9f3..0c11c1538e 100644 --- a/core/src/main/kotlin/org/lflang/generator/rust/RustGenerator.kt +++ b/core/src/main/kotlin/org/lflang/generator/rust/RustGenerator.kt @@ -26,7 +26,7 @@ package org.lflang.generator.rust import org.eclipse.emf.ecore.resource.Resource import org.lflang.Target -import org.lflang.target.property.BuildConfig.BuildType +import org.lflang.target.property.BuildTypeProperty.BuildType import org.lflang.generator.GeneratorUtils.canGenerate import org.lflang.generator.CodeMap import org.lflang.generator.GeneratorBase 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 b3d69ea548..eaa1e93fec 100644 --- a/core/src/main/kotlin/org/lflang/generator/rust/RustModel.kt +++ b/core/src/main/kotlin/org/lflang/generator/rust/RustModel.kt @@ -26,7 +26,7 @@ package org.lflang.generator.rust import org.lflang.* -import org.lflang.target.property.BuildConfig.BuildType +import org.lflang.target.property.BuildTypeProperty.BuildType import org.lflang.ast.ASTUtils import org.lflang.generator.* import org.lflang.lf.* From d9a05a052f2b1abae2eee3fbd8f90ee8f8124da4 Mon Sep 17 00:00:00 2001 From: Christian Menard Date: Fri, 29 Sep 2023 16:54:36 +0200 Subject: [PATCH 019/145] cleanup --- core/src/main/java/org/lflang/TargetProperty.java | 4 ++-- core/src/main/java/org/lflang/TargetPropertyConfig.java | 8 ++++---- .../java/org/lflang/target/property/type/ArrayType.java | 9 +++------ .../org/lflang/target/property/type/DictionaryType.java | 2 +- .../lflang/target/property/type/TargetPropertyType.java | 4 ++-- .../java/org/lflang/target/property/type/UnionType.java | 2 +- 6 files changed, 13 insertions(+), 16 deletions(-) diff --git a/core/src/main/java/org/lflang/TargetProperty.java b/core/src/main/java/org/lflang/TargetProperty.java index a5095b9d45..118afbdd44 100644 --- a/core/src/main/java/org/lflang/TargetProperty.java +++ b/core/src/main/java/org/lflang/TargetProperty.java @@ -405,8 +405,8 @@ public static void validate( .findAny(); if (match.isPresent()) { var p = match.get(); - p.property.of(config).checkSupport(pair, config, reporter); - p.property.of(config).checkType(pair, config, reporter); + p.property.of(config).checkSupport(pair, config.target, reporter); + p.property.of(config).checkType(pair, reporter); p.property.of(config).validate(pair, ast, config, reporter); } else { reporter diff --git a/core/src/main/java/org/lflang/TargetPropertyConfig.java b/core/src/main/java/org/lflang/TargetPropertyConfig.java index 35fc6936a5..4a41df7b39 100644 --- a/core/src/main/java/org/lflang/TargetPropertyConfig.java +++ b/core/src/main/java/org/lflang/TargetPropertyConfig.java @@ -78,19 +78,19 @@ public void validate( // FIXME: consider not passing in config } - public void checkSupport(KeyValuePair pair, TargetConfig config, MessageReporter reporter) { - if (!this.isSupported(config.target)) { + public void checkSupport(KeyValuePair pair, Target target, MessageReporter reporter) { + if (!this.isSupported(target)) { reporter .at(pair, Literals.KEY_VALUE_PAIR__NAME) .warning( String.format( "The target parameter: %s is not supported by the %s target and will thus be" + " ignored.", - pair.getName(), config.target)); + pair.getName(), target)); } } - public void checkType(KeyValuePair pair, TargetConfig config, MessageReporter reporter) { + public void checkType(KeyValuePair pair, MessageReporter reporter) { if (!this.type.check(pair.getValue(), pair.getName(), reporter)) { reporter .at(pair, Literals.KEY_VALUE_PAIR__VALUE) diff --git a/core/src/main/java/org/lflang/target/property/type/ArrayType.java b/core/src/main/java/org/lflang/target/property/type/ArrayType.java index 742292c3c7..96d176f54d 100644 --- a/core/src/main/java/org/lflang/target/property/type/ArrayType.java +++ b/core/src/main/java/org/lflang/target/property/type/ArrayType.java @@ -15,14 +15,14 @@ public enum ArrayType implements TargetPropertyType { FILE_ARRAY(PrimitiveType.FILE); /** Type parameter of this array type. */ - public TargetPropertyType type; + public final TargetPropertyType type; /** * Private constructor to create a new array type. * * @param type The type of elements in the array. */ - private ArrayType(TargetPropertyType type) { + ArrayType(TargetPropertyType type) { this.type = type; } @@ -47,10 +47,7 @@ public boolean check(Element e, String name, MessageReporter r) { /** Return true of the given element is an array. */ @Override public boolean validate(Element e) { - if (e.getArray() != null) { - return true; - } - return false; + return e.getArray() != null; } /** Return a human-readable description of this type. */ diff --git a/core/src/main/java/org/lflang/target/property/type/DictionaryType.java b/core/src/main/java/org/lflang/target/property/type/DictionaryType.java index cbcb58d4c8..0c15ffe0be 100644 --- a/core/src/main/java/org/lflang/target/property/type/DictionaryType.java +++ b/core/src/main/java/org/lflang/target/property/type/DictionaryType.java @@ -36,7 +36,7 @@ public enum DictionaryType implements TargetPropertyType { * * @param options The dictionary elements allowed by this type. */ - private DictionaryType(List options) { + DictionaryType(List options) { this.options = options; } diff --git a/core/src/main/java/org/lflang/target/property/type/TargetPropertyType.java b/core/src/main/java/org/lflang/target/property/type/TargetPropertyType.java index d4c5009262..7c555e743c 100644 --- a/core/src/main/java/org/lflang/target/property/type/TargetPropertyType.java +++ b/core/src/main/java/org/lflang/target/property/type/TargetPropertyType.java @@ -16,7 +16,7 @@ public interface TargetPropertyType { * @param e The Element to validate. * @return True if the element conforms to this type, false otherwise. */ - public boolean validate(Element e); + boolean validate(Element e); /** * Check (recursively) the given Element against its associated type(s) and add found problems to @@ -26,5 +26,5 @@ public interface TargetPropertyType { * @param name The name of the target property. * @param r A reference to the validator to report errors to. */ - public boolean check(Element e, String name, MessageReporter r); + boolean check(Element e, String name, MessageReporter r); } diff --git a/core/src/main/java/org/lflang/target/property/type/UnionType.java b/core/src/main/java/org/lflang/target/property/type/UnionType.java index a4f1cdbb36..979a6b7011 100644 --- a/core/src/main/java/org/lflang/target/property/type/UnionType.java +++ b/core/src/main/java/org/lflang/target/property/type/UnionType.java @@ -46,7 +46,7 @@ public enum UnionType implements TargetPropertyType { * @param options The types that that are part of the union. * @param defaultOption The default type. */ - private UnionType(List> options, Enum defaultOption) { + UnionType(List> options, Enum defaultOption) { this.options = options; this.defaultOption = defaultOption; } From 1760afc11d5cd7b2447a8b11ca63acf769f92274 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Fri, 29 Sep 2023 10:58:01 -0700 Subject: [PATCH 020/145] Minor fixes --- .../org/lflang/federated/extensions/CExtensionUtils.java | 2 +- .../org/lflang/generator/cpp/CppRos2PackageGenerator.kt | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/core/src/main/java/org/lflang/federated/extensions/CExtensionUtils.java b/core/src/main/java/org/lflang/federated/extensions/CExtensionUtils.java index bbb7cc8b88..daf075ed45 100644 --- a/core/src/main/java/org/lflang/federated/extensions/CExtensionUtils.java +++ b/core/src/main/java/org/lflang/federated/extensions/CExtensionUtils.java @@ -174,7 +174,7 @@ public static void handleCompileDefinitions( MessageReporter messageReporter) { var defs = federate.targetConfig.compileDefinitions.get(); defs.put("FEDERATED", ""); - defs.put("FEDERATED_" + federate.targetConfig.coordination.toString().toUpperCase(), ""); + defs.put("FEDERATED_" + federate.targetConfig.coordination.get().toString().toUpperCase(), ""); if (federate.targetConfig.auth.get()) { defs.put("FEDERATED_AUTHENTICATED", ""); } diff --git a/core/src/main/kotlin/org/lflang/generator/cpp/CppRos2PackageGenerator.kt b/core/src/main/kotlin/org/lflang/generator/cpp/CppRos2PackageGenerator.kt index 4d34e69d31..49311d121a 100644 --- a/core/src/main/kotlin/org/lflang/generator/cpp/CppRos2PackageGenerator.kt +++ b/core/src/main/kotlin/org/lflang/generator/cpp/CppRos2PackageGenerator.kt @@ -9,10 +9,11 @@ import java.nio.file.Path class CppRos2PackageGenerator(generator: CppGenerator, private val nodeName: String) { private val fileConfig = generator.fileConfig private val targetConfig = generator.targetConfig - val reactorCppSuffix = targetConfig.runtimeVersion.get() ?: "default" + val reactorCppSuffix: String = if (targetConfig.runtimeVersion.isSet) targetConfig.runtimeVersion.get() else "default" val reactorCppName = "reactor-cpp-$reactorCppSuffix" private val dependencies = - listOf("rclcpp", "rclcpp_components", reactorCppName) + (targetConfig.ros2Dependencies ?: listOf()) + listOf("rclcpp", "rclcpp_components", reactorCppName) + ( + if (targetConfig.ros2Dependencies.isSet) targetConfig.ros2Dependencies.get() else listOf()) @Suppress("PrivatePropertyName") // allows us to use capital S as variable name below private val S = '$' // a little trick to escape the dollar sign with $S From 341912d3b31c22c72b44fd4393cecf60981d55c4 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Fri, 29 Sep 2023 12:47:56 -0700 Subject: [PATCH 021/145] Fix docker problem --- .../lflang/federated/generator/FedGenerator.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) 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 67540c745f..3921438e08 100644 --- a/core/src/main/java/org/lflang/federated/generator/FedGenerator.java +++ b/core/src/main/java/org/lflang/federated/generator/FedGenerator.java @@ -59,6 +59,7 @@ import org.lflang.lf.TargetDecl; import org.lflang.lf.VarRef; import org.lflang.target.property.CoordinationModeProperty.CoordinationMode; +import org.lflang.target.property.DockerProperty.DockerOptions; import org.lflang.util.Averager; public class FedGenerator { @@ -293,18 +294,17 @@ private Map compileFederates( MessageReporter subContextMessageReporter = new LineAdjustingMessageReporter(threadSafeErrorReporter, lf2lfCodeMapMap); - var props = new Properties(); - if (targetConfig.dockerOptions.get().enabled - && targetConfig.target.buildsUsingDocker()) { - props.put("no-compile", "true"); - } - props.put("docker", "false"); - TargetConfig subConfig = new TargetConfig( - props, + new Properties(), GeneratorUtils.findTargetDecl(subFileConfig.resource), subContextMessageReporter); + if (targetConfig.dockerOptions.get().enabled + && targetConfig.target.buildsUsingDocker()) { + subConfig.noCompile.override(true); + } + subConfig.dockerOptions.get().enabled = false; + SubContext subContext = new SubContext(context, IntegratedBuilder.VALIDATED_PERCENT_PROGRESS, 100) { @Override From af926162a9f62ea86fdc359085b799ca5c6abe20 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Fri, 29 Sep 2023 13:41:50 -0700 Subject: [PATCH 022/145] Another obscure nullcheck --- .../main/java/org/lflang/generator/c/CPreambleGenerator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 0c0cc7c911..95146df77b 100644 --- a/core/src/main/java/org/lflang/generator/c/CPreambleGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CPreambleGenerator.java @@ -49,7 +49,7 @@ public static String generateIncludeStatements(TargetConfig targetConfig, boolea code.pr("#include \"include/core/environment.h\""); code.pr("int lf_reactor_c_main(int argc, const char* argv[]);"); - if (targetConfig.fedSetupPreamble != null) { + if (!targetConfig.fedSetupPreamble.isSet()) { code.pr("#include \"include/core/federated/federate.h\""); code.pr("#include \"include/core/federated/net_common.h\""); } From 282b4895673e6db6f5883b06b3c65257a39af58b Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Fri, 29 Sep 2023 13:42:22 -0700 Subject: [PATCH 023/145] Remove negation --- .../main/java/org/lflang/generator/c/CPreambleGenerator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 95146df77b..6a241b37aa 100644 --- a/core/src/main/java/org/lflang/generator/c/CPreambleGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CPreambleGenerator.java @@ -49,7 +49,7 @@ public static String generateIncludeStatements(TargetConfig targetConfig, boolea code.pr("#include \"include/core/environment.h\""); code.pr("int lf_reactor_c_main(int argc, const char* argv[]);"); - if (!targetConfig.fedSetupPreamble.isSet()) { + if (targetConfig.fedSetupPreamble.isSet()) { code.pr("#include \"include/core/federated/federate.h\""); code.pr("#include \"include/core/federated/net_common.h\""); } From dd2b6e8d5f664396e93f6aea4d73124a25ce4d50 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Fri, 29 Sep 2023 16:46:11 -0700 Subject: [PATCH 024/145] Fix Rust issue --- .../org/lflang/federated/generator/FedGenerator.java | 1 - .../java/org/lflang/generator/rust/RustTargetConfig.java | 2 +- .../main/kotlin/org/lflang/generator/rust/RustModel.kt | 9 ++++----- 3 files changed, 5 insertions(+), 7 deletions(-) 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 3921438e08..c1524d48e0 100644 --- a/core/src/main/java/org/lflang/federated/generator/FedGenerator.java +++ b/core/src/main/java/org/lflang/federated/generator/FedGenerator.java @@ -59,7 +59,6 @@ import org.lflang.lf.TargetDecl; import org.lflang.lf.VarRef; import org.lflang.target.property.CoordinationModeProperty.CoordinationMode; -import org.lflang.target.property.DockerProperty.DockerOptions; import org.lflang.util.Averager; public class FedGenerator { diff --git a/core/src/main/java/org/lflang/generator/rust/RustTargetConfig.java b/core/src/main/java/org/lflang/generator/rust/RustTargetConfig.java index 006163db13..e67dc59dcb 100644 --- a/core/src/main/java/org/lflang/generator/rust/RustTargetConfig.java +++ b/core/src/main/java/org/lflang/generator/rust/RustTargetConfig.java @@ -24,8 +24,8 @@ package org.lflang.generator.rust; -import org.lflang.target.property.BuildTypeProperty.BuildType; import org.lflang.target.property.BuildTypeProperty; +import org.lflang.target.property.BuildTypeProperty.BuildType; import org.lflang.target.property.CargoDependenciesProperty; import org.lflang.target.property.CargoFeaturesProperty; import org.lflang.target.property.RustIncludeProperty; 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 eaa1e93fec..2ab9af11e8 100644 --- a/core/src/main/kotlin/org/lflang/generator/rust/RustModel.kt +++ b/core/src/main/kotlin/org/lflang/generator/rust/RustModel.kt @@ -477,7 +477,6 @@ object RustModelBuilder { if (userSpec == null) { // default configuration for the runtime crate - val userRtVersion: String? = targetConfig.runtimeVersion.get() // enable parallel feature if asked val parallelFeature = listOf(PARALLEL_RT_FEATURE).takeIf { targetConfig.threading.get() } @@ -485,18 +484,18 @@ object RustModelBuilder { features = parallelFeature, ) - if (targetConfig.externalRuntimePath != null) { + if (targetConfig.externalRuntimePath.isSet) { spec.localPath = targetConfig.externalRuntimePath.get() - } else if (userRtVersion != null) { + } else if (targetConfig.runtimeVersion.isSet) { spec.gitRepo = RustEmitterBase.runtimeGitUrl - spec.rev = userRtVersion + spec.rev = targetConfig.runtimeVersion.get() } else { spec.useDefaultRuntimePath() } return spec } else { - if (targetConfig.externalRuntimePath != null) { + if (targetConfig.externalRuntimePath.isSet) { userSpec.localPath = targetConfig.externalRuntimePath.get() } From 79e3a6a05d20c2b90a662eb173aa9fc7a4a5cfcc Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Fri, 29 Sep 2023 18:57:11 -0700 Subject: [PATCH 025/145] Point to epoch message-reporter branch --- .github/workflows/build.yml | 1 + core/src/testFixtures/java/org/lflang/tests/TestBase.java | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index da1990ca3f..f444bc02f8 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -36,4 +36,5 @@ jobs: with: lingua-franca-ref: ${{ github.head_ref || github.ref_name }} lingua-franca-repo: ${{ github.event.pull_request.head.repo.full_name }} + epoch-ref: message-reporter upload-artifacts: false diff --git a/core/src/testFixtures/java/org/lflang/tests/TestBase.java b/core/src/testFixtures/java/org/lflang/tests/TestBase.java index 04a699068c..df97b3ea5d 100644 --- a/core/src/testFixtures/java/org/lflang/tests/TestBase.java +++ b/core/src/testFixtures/java/org/lflang/tests/TestBase.java @@ -438,7 +438,7 @@ private void validate(LFTest test) throws TestError { /** Override to add some LFC arguments to all runs of this test class. */ protected void addExtraLfcArgs(Properties args, TargetConfig targetConfig) { args.setProperty("build-type", "Test"); - if (targetConfig.logLevel == null) args.setProperty("logging", "Debug"); + if (!targetConfig.logLevel.isSet()) args.setProperty("logging", "Debug"); } /** From 3b216d83e343ecb2a71ccb491faacc2c7d5b36c6 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Sat, 30 Sep 2023 14:49:09 -0700 Subject: [PATCH 026/145] Various bug fixes and improved, more localized error reporting --- .../main/java/org/lflang/TargetProperty.java | 3 +- .../target/property/type/ArrayType.java | 2 +- .../target/property/type/DictionaryType.java | 2 +- .../target/property/type/PrimitiveType.java | 8 +- .../property/type/StringDictionaryType.java | 8 +- .../target/property/type/UnionType.java | 3 +- .../compiler/LinguaFrancaValidationTest.java | 83 ++++++++++--------- 7 files changed, 62 insertions(+), 47 deletions(-) diff --git a/core/src/main/java/org/lflang/TargetProperty.java b/core/src/main/java/org/lflang/TargetProperty.java index 118afbdd44..fe6e37bde1 100644 --- a/core/src/main/java/org/lflang/TargetProperty.java +++ b/core/src/main/java/org/lflang/TargetProperty.java @@ -68,6 +68,7 @@ import org.lflang.target.property.PrintStatisticsProperty; import org.lflang.target.property.ProtobufsProperty; import org.lflang.target.property.Ros2DependenciesProperty; +import org.lflang.target.property.Ros2Property; import org.lflang.target.property.RuntimeVersionProperty; import org.lflang.target.property.RustIncludeProperty; import org.lflang.target.property.SchedulerProperty; @@ -170,7 +171,7 @@ public enum TargetProperty { PROTOBUFS(ProtobufsProperty.class, config -> config.protoFiles), /** Directive to specify that ROS2 specific code is generated, */ - ROS2(Ros2DependenciesProperty.class, config -> config.ros2), + ROS2(Ros2Property.class, config -> config.ros2), /** Directive to specify additional ROS2 packages that this LF program depends on. */ ROS2_DEPENDENCIES(Ros2DependenciesProperty.class, config -> config.ros2Dependencies), diff --git a/core/src/main/java/org/lflang/target/property/type/ArrayType.java b/core/src/main/java/org/lflang/target/property/type/ArrayType.java index 96d176f54d..5b0bd9202e 100644 --- a/core/src/main/java/org/lflang/target/property/type/ArrayType.java +++ b/core/src/main/java/org/lflang/target/property/type/ArrayType.java @@ -37,7 +37,7 @@ public boolean check(Element e, String name, MessageReporter r) { List elements = array.getElements(); var valid = true; for (int i = 0; i < elements.size(); i++) { - valid &= this.type.check(elements.get(i), name + "[" + i + "]", r); + valid &= this.type.check(elements.get(i), "Entry", r); } return valid; } diff --git a/core/src/main/java/org/lflang/target/property/type/DictionaryType.java b/core/src/main/java/org/lflang/target/property/type/DictionaryType.java index 0c15ffe0be..63107eb98c 100644 --- a/core/src/main/java/org/lflang/target/property/type/DictionaryType.java +++ b/core/src/main/java/org/lflang/target/property/type/DictionaryType.java @@ -66,7 +66,7 @@ public boolean check(Element e, String name, MessageReporter v) { if (match.isPresent()) { // Make sure the type is correct, too. TargetPropertyType type = match.get().getType(); - valid &= type.check(val, name + "." + key, v); + valid &= type.check(val, "Entry", v); } else { valid = false; } diff --git a/core/src/main/java/org/lflang/target/property/type/PrimitiveType.java b/core/src/main/java/org/lflang/target/property/type/PrimitiveType.java index 8afc08c12f..95427f9700 100644 --- a/core/src/main/java/org/lflang/target/property/type/PrimitiveType.java +++ b/core/src/main/java/org/lflang/target/property/type/PrimitiveType.java @@ -82,7 +82,13 @@ public boolean validate(Element e) { * @param v The LFValidator to append errors to. */ public boolean check(Element e, String name, MessageReporter v) { - return this.validate(e); + var valid = this.validate(e); + if (!valid) { + v.at(e).error(String.format("%s is required to be %s.", name, this)); + return false; + } else { + return true; + } } /** Return a textual description of this type. */ diff --git a/core/src/main/java/org/lflang/target/property/type/StringDictionaryType.java b/core/src/main/java/org/lflang/target/property/type/StringDictionaryType.java index 8047b56bd1..886fb79e14 100644 --- a/core/src/main/java/org/lflang/target/property/type/StringDictionaryType.java +++ b/core/src/main/java/org/lflang/target/property/type/StringDictionaryType.java @@ -27,10 +27,16 @@ public boolean check(Element e, String name, MessageReporter v) { Element val = pair.getValue(); // Make sure the type is string - valid &= PrimitiveType.STRING.check(val, name + "." + key, v); + valid &= PrimitiveType.STRING.check(val, "Entry", v); } return valid; } return false; } + + @Override + public String toString() { + return "a dictionary that maps strings keys to string values"; + } + } diff --git a/core/src/main/java/org/lflang/target/property/type/UnionType.java b/core/src/main/java/org/lflang/target/property/type/UnionType.java index 979a6b7011..8b51f972c9 100644 --- a/core/src/main/java/org/lflang/target/property/type/UnionType.java +++ b/core/src/main/java/org/lflang/target/property/type/UnionType.java @@ -67,6 +67,7 @@ public boolean check(Element e, String name, MessageReporter r) { Optional> match = this.match(e); var found = false; if (match.isPresent()) { + found = true; // Go deeper if the element is an array or dictionary. Enum type = match.get(); if (type instanceof DictionaryType) { @@ -77,8 +78,6 @@ public boolean check(Element e, String name, MessageReporter r) { found = ((PrimitiveType) type).check(e, name, r); } else if (!(type instanceof Enum)) { throw new RuntimeException("Encountered an unknown type."); - } else { - found = true; } } return found; 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 6b9e9fa4a2..26cc8af11f 100644 --- a/core/src/test/java/org/lflang/tests/compiler/LinguaFrancaValidationTest.java +++ b/core/src/test/java/org/lflang/tests/compiler/LinguaFrancaValidationTest.java @@ -1285,43 +1285,43 @@ public void recognizeHostNames() throws Exception { Map.of( ArrayType.STRING_ARRAY, List.of( - List.of("[1 msec]", "[0]", PrimitiveType.STRING), - List.of("[foo, {bar: baz}]", "[1]", PrimitiveType.STRING), - List.of("{bar: baz}", "", ArrayType.STRING_ARRAY)), + List.of("[1 msec]", LfPackage.eINSTANCE.getElement(), PrimitiveType.STRING), + List.of("[foo, {bar: baz}]", LfPackage.eINSTANCE.getElement(), PrimitiveType.STRING), + List.of("{bar: baz}", LfPackage.eINSTANCE.getKeyValuePair(), ArrayType.STRING_ARRAY)), UnionType.STRING_OR_STRING_ARRAY, List.of( - List.of("[1 msec]", "[0]", PrimitiveType.STRING), - List.of("[foo, {bar: baz}]", "[1]", PrimitiveType.STRING), - List.of("{bar: baz}", "", UnionType.STRING_OR_STRING_ARRAY)), + List.of("[1 msec]", LfPackage.eINSTANCE.getElement(), PrimitiveType.STRING), + List.of("[foo, {bar: baz}]", LfPackage.eINSTANCE.getElement(), PrimitiveType.STRING), + List.of("{bar: baz}", LfPackage.eINSTANCE.getKeyValuePair(), UnionType.STRING_OR_STRING_ARRAY)), UnionType.PLATFORM_STRING_OR_DICTIONARY, List.of( - List.of("[bar, baz]", "", UnionType.PLATFORM_STRING_OR_DICTIONARY), - List.of("{name: [1, 2, 3]}", ".name", PrimitiveType.STRING), - List.of("{name: {bar: baz}}", ".name", PrimitiveType.STRING), - List.of("{board: [1, 2, 3]}", ".board", PrimitiveType.STRING), - List.of("{board: {bar: baz}}", ".board", PrimitiveType.STRING), + List.of("[bar, baz]", LfPackage.eINSTANCE.getKeyValuePair(), UnionType.PLATFORM_STRING_OR_DICTIONARY), + List.of("{name: [1, 2, 3]}", LfPackage.eINSTANCE.getElement(), PrimitiveType.STRING), + List.of("{name: {bar: baz}}", LfPackage.eINSTANCE.getElement(), PrimitiveType.STRING), + List.of("{board: [1, 2, 3]}", LfPackage.eINSTANCE.getElement(), PrimitiveType.STRING), + List.of("{board: {bar: baz}}", LfPackage.eINSTANCE.getElement(), PrimitiveType.STRING), List.of( - "{baud-rate: [1, 2, 3]}", ".baud-rate", PrimitiveType.NON_NEGATIVE_INTEGER), + "{baud-rate: [1, 2, 3]}", LfPackage.eINSTANCE.getElement(), PrimitiveType.NON_NEGATIVE_INTEGER), List.of( - "{baud-rate: {bar: baz}}", ".baud-rate", PrimitiveType.NON_NEGATIVE_INTEGER)), + "{baud-rate: {bar: baz}}", LfPackage.eINSTANCE.getElement(), PrimitiveType.NON_NEGATIVE_INTEGER)), UnionType.FILE_OR_FILE_ARRAY, List.of( - List.of("[1 msec]", "[0]", PrimitiveType.FILE), - List.of("[foo, {bar: baz}]", "[1]", PrimitiveType.FILE), - List.of("{bar: baz}", "", UnionType.FILE_OR_FILE_ARRAY)), + List.of("[1 msec]", LfPackage.eINSTANCE.getElement(), PrimitiveType.FILE), + List.of("[foo, {bar: baz}]", LfPackage.eINSTANCE.getElement(), PrimitiveType.FILE), + List.of("{bar: baz}", LfPackage.eINSTANCE.getKeyValuePair(), UnionType.FILE_OR_FILE_ARRAY)), UnionType.DOCKER_UNION, List.of( - List.of("foo", "", UnionType.DOCKER_UNION), - List.of("[1]", "", UnionType.DOCKER_UNION), - List.of("{bar: baz}", "", DictionaryType.DOCKER_DICT), - List.of("{FROM: [1, 2, 3]}", ".FROM", PrimitiveType.STRING)), + List.of("foo", LfPackage.eINSTANCE.getKeyValuePair(), UnionType.DOCKER_UNION), + List.of("[1]", LfPackage.eINSTANCE.getKeyValuePair(), UnionType.DOCKER_UNION), + List.of("{bar: baz}", LfPackage.eINSTANCE.getKeyValuePair(), DictionaryType.DOCKER_DICT), + List.of("{FROM: [1, 2, 3]}", LfPackage.eINSTANCE.getElement(), PrimitiveType.STRING)), UnionType.TRACING_UNION, List.of( - List.of("foo", "", UnionType.TRACING_UNION), - List.of("[1]", "", UnionType.TRACING_UNION), - List.of("{bar: baz}", "", DictionaryType.TRACING_DICT), + List.of("foo", LfPackage.eINSTANCE.getKeyValuePair(), UnionType.TRACING_UNION), + List.of("[1]", LfPackage.eINSTANCE.getKeyValuePair(), UnionType.TRACING_UNION), + List.of("{bar: baz}", LfPackage.eINSTANCE.getKeyValuePair(), DictionaryType.TRACING_DICT), List.of( - "{trace-file-name: [1, 2, 3]}", ".trace-file-name", PrimitiveType.STRING))); + "{trace-file-name: [1, 2, 3]}", LfPackage.eINSTANCE.getElement(), PrimitiveType.STRING))); /** * Given an array type, return a list of good or bad examples, depending on the value of the @@ -1496,21 +1496,12 @@ public Collection checkTargetProperties() throws Exception { DynamicTest.dynamicTest( "Property %s (%s) - known bad assignment: %s".formatted(property, type, it), () -> { - if (type instanceof StringDictionaryType) { - validator.assertError( - createModel(property, it), - LfPackage.eINSTANCE.getKeyValuePair(), - null, - String.format("Target property '%s.", property), - "' is required to be a string."); - } else { validator.assertError( createModel(property, it), LfPackage.eINSTANCE.getKeyValuePair(), null, String.format( "Target property '%s' is required to be %s.", property, type)); - } }); result.add(test); } @@ -1524,14 +1515,26 @@ public Collection checkTargetProperties() throws Exception { "Property %s (%s) - known bad assignment: %s".formatted(property, type, it), () -> { System.out.println(it); - validator.assertError( - createModel(property, it.get(0).toString()), - LfPackage.eINSTANCE.getKeyValuePair(), - null, - String.format( - "Target property '%s%s' is required to be %s.", - property, it.get(1), it.get(2))); + //var issues = validator.validate(createModel(property, it.get(0).toString())); + if (it.get(1).equals(LfPackage.eINSTANCE.getElement())) { + validator.assertError( + createModel(property, it.get(0).toString()), + LfPackage.eINSTANCE.getElement(), + null, + String.format( + "Entry is required to be %s.", it.get(2))); + } else { + validator.assertError( + createModel(property, it.get(0).toString()), + LfPackage.eINSTANCE.getKeyValuePair(), + null, + String.format( + "Target property '%s' is required to be %s.", property, type)); + } + }); + // String.format( + // "Target property '%s' is required to be %s.", property, type) result.add(test); } } From 20e7b3f5a9e33014b97b7553d178a63ef6684769 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Sat, 30 Sep 2023 15:06:46 -0700 Subject: [PATCH 027/145] Apply formatter --- .../property/type/StringDictionaryType.java | 1 - .../compiler/LinguaFrancaValidationTest.java | 88 +++++++++++++------ 2 files changed, 60 insertions(+), 29 deletions(-) diff --git a/core/src/main/java/org/lflang/target/property/type/StringDictionaryType.java b/core/src/main/java/org/lflang/target/property/type/StringDictionaryType.java index 886fb79e14..afe44cabf2 100644 --- a/core/src/main/java/org/lflang/target/property/type/StringDictionaryType.java +++ b/core/src/main/java/org/lflang/target/property/type/StringDictionaryType.java @@ -38,5 +38,4 @@ public boolean check(Element e, String name, MessageReporter v) { public String toString() { return "a dictionary that maps strings keys to string values"; } - } 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 26cc8af11f..43154df8b5 100644 --- a/core/src/test/java/org/lflang/tests/compiler/LinguaFrancaValidationTest.java +++ b/core/src/test/java/org/lflang/tests/compiler/LinguaFrancaValidationTest.java @@ -1286,42 +1286,74 @@ public void recognizeHostNames() throws Exception { ArrayType.STRING_ARRAY, List.of( List.of("[1 msec]", LfPackage.eINSTANCE.getElement(), PrimitiveType.STRING), - List.of("[foo, {bar: baz}]", LfPackage.eINSTANCE.getElement(), PrimitiveType.STRING), - List.of("{bar: baz}", LfPackage.eINSTANCE.getKeyValuePair(), ArrayType.STRING_ARRAY)), + List.of( + "[foo, {bar: baz}]", LfPackage.eINSTANCE.getElement(), PrimitiveType.STRING), + List.of( + "{bar: baz}", LfPackage.eINSTANCE.getKeyValuePair(), ArrayType.STRING_ARRAY)), UnionType.STRING_OR_STRING_ARRAY, List.of( List.of("[1 msec]", LfPackage.eINSTANCE.getElement(), PrimitiveType.STRING), - List.of("[foo, {bar: baz}]", LfPackage.eINSTANCE.getElement(), PrimitiveType.STRING), - List.of("{bar: baz}", LfPackage.eINSTANCE.getKeyValuePair(), UnionType.STRING_OR_STRING_ARRAY)), + List.of( + "[foo, {bar: baz}]", LfPackage.eINSTANCE.getElement(), PrimitiveType.STRING), + List.of( + "{bar: baz}", + LfPackage.eINSTANCE.getKeyValuePair(), + UnionType.STRING_OR_STRING_ARRAY)), UnionType.PLATFORM_STRING_OR_DICTIONARY, List.of( - List.of("[bar, baz]", LfPackage.eINSTANCE.getKeyValuePair(), UnionType.PLATFORM_STRING_OR_DICTIONARY), - List.of("{name: [1, 2, 3]}", LfPackage.eINSTANCE.getElement(), PrimitiveType.STRING), - List.of("{name: {bar: baz}}", LfPackage.eINSTANCE.getElement(), PrimitiveType.STRING), - List.of("{board: [1, 2, 3]}", LfPackage.eINSTANCE.getElement(), PrimitiveType.STRING), - List.of("{board: {bar: baz}}", LfPackage.eINSTANCE.getElement(), PrimitiveType.STRING), List.of( - "{baud-rate: [1, 2, 3]}", LfPackage.eINSTANCE.getElement(), PrimitiveType.NON_NEGATIVE_INTEGER), + "[bar, baz]", + LfPackage.eINSTANCE.getKeyValuePair(), + UnionType.PLATFORM_STRING_OR_DICTIONARY), + List.of( + "{name: [1, 2, 3]}", LfPackage.eINSTANCE.getElement(), PrimitiveType.STRING), + List.of( + "{name: {bar: baz}}", LfPackage.eINSTANCE.getElement(), PrimitiveType.STRING), + List.of( + "{board: [1, 2, 3]}", LfPackage.eINSTANCE.getElement(), PrimitiveType.STRING), + List.of( + "{board: {bar: baz}}", + LfPackage.eINSTANCE.getElement(), + PrimitiveType.STRING), + List.of( + "{baud-rate: [1, 2, 3]}", + LfPackage.eINSTANCE.getElement(), + PrimitiveType.NON_NEGATIVE_INTEGER), List.of( - "{baud-rate: {bar: baz}}", LfPackage.eINSTANCE.getElement(), PrimitiveType.NON_NEGATIVE_INTEGER)), + "{baud-rate: {bar: baz}}", + LfPackage.eINSTANCE.getElement(), + PrimitiveType.NON_NEGATIVE_INTEGER)), UnionType.FILE_OR_FILE_ARRAY, List.of( List.of("[1 msec]", LfPackage.eINSTANCE.getElement(), PrimitiveType.FILE), - List.of("[foo, {bar: baz}]", LfPackage.eINSTANCE.getElement(), PrimitiveType.FILE), - List.of("{bar: baz}", LfPackage.eINSTANCE.getKeyValuePair(), UnionType.FILE_OR_FILE_ARRAY)), + List.of( + "[foo, {bar: baz}]", LfPackage.eINSTANCE.getElement(), PrimitiveType.FILE), + List.of( + "{bar: baz}", + LfPackage.eINSTANCE.getKeyValuePair(), + UnionType.FILE_OR_FILE_ARRAY)), UnionType.DOCKER_UNION, List.of( List.of("foo", LfPackage.eINSTANCE.getKeyValuePair(), UnionType.DOCKER_UNION), List.of("[1]", LfPackage.eINSTANCE.getKeyValuePair(), UnionType.DOCKER_UNION), - List.of("{bar: baz}", LfPackage.eINSTANCE.getKeyValuePair(), DictionaryType.DOCKER_DICT), - List.of("{FROM: [1, 2, 3]}", LfPackage.eINSTANCE.getElement(), PrimitiveType.STRING)), + List.of( + "{bar: baz}", + LfPackage.eINSTANCE.getKeyValuePair(), + DictionaryType.DOCKER_DICT), + List.of( + "{FROM: [1, 2, 3]}", LfPackage.eINSTANCE.getElement(), PrimitiveType.STRING)), UnionType.TRACING_UNION, List.of( List.of("foo", LfPackage.eINSTANCE.getKeyValuePair(), UnionType.TRACING_UNION), List.of("[1]", LfPackage.eINSTANCE.getKeyValuePair(), UnionType.TRACING_UNION), - List.of("{bar: baz}", LfPackage.eINSTANCE.getKeyValuePair(), DictionaryType.TRACING_DICT), List.of( - "{trace-file-name: [1, 2, 3]}", LfPackage.eINSTANCE.getElement(), PrimitiveType.STRING))); + "{bar: baz}", + LfPackage.eINSTANCE.getKeyValuePair(), + DictionaryType.TRACING_DICT), + List.of( + "{trace-file-name: [1, 2, 3]}", + LfPackage.eINSTANCE.getElement(), + PrimitiveType.STRING))); /** * Given an array type, return a list of good or bad examples, depending on the value of the @@ -1496,12 +1528,12 @@ public Collection checkTargetProperties() throws Exception { DynamicTest.dynamicTest( "Property %s (%s) - known bad assignment: %s".formatted(property, type, it), () -> { - validator.assertError( - createModel(property, it), - LfPackage.eINSTANCE.getKeyValuePair(), - null, - String.format( - "Target property '%s' is required to be %s.", property, type)); + validator.assertError( + createModel(property, it), + LfPackage.eINSTANCE.getKeyValuePair(), + null, + String.format( + "Target property '%s' is required to be %s.", property, type)); }); result.add(test); } @@ -1515,14 +1547,14 @@ public Collection checkTargetProperties() throws Exception { "Property %s (%s) - known bad assignment: %s".formatted(property, type, it), () -> { System.out.println(it); - //var issues = validator.validate(createModel(property, it.get(0).toString())); + // var issues = validator.validate(createModel(property, + // it.get(0).toString())); if (it.get(1).equals(LfPackage.eINSTANCE.getElement())) { validator.assertError( createModel(property, it.get(0).toString()), LfPackage.eINSTANCE.getElement(), null, - String.format( - "Entry is required to be %s.", it.get(2))); + String.format("Entry is required to be %s.", it.get(2))); } else { validator.assertError( createModel(property, it.get(0).toString()), @@ -1531,10 +1563,10 @@ public Collection checkTargetProperties() throws Exception { String.format( "Target property '%s' is required to be %s.", property, type)); } - }); // String.format( - // "Target property '%s' is required to be %s.", property, type) + // "Target property '%s' is required to be %s.", property, + // type) result.add(test); } } From 97a3924794337e0341c8c342b2a78636f93edb80 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Sat, 30 Sep 2023 16:01:34 -0700 Subject: [PATCH 028/145] Change CLI arg --- cli/lfc/src/test/java/org/lflang/cli/LfcCliTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 fd65ffad78..07f717ccbb 100644 --- a/cli/lfc/src/test/java/org/lflang/cli/LfcCliTest.java +++ b/cli/lfc/src/test/java/org/lflang/cli/LfcCliTest.java @@ -276,7 +276,7 @@ public void testGeneratorArgs(@TempDir Path tempDir) throws IOException { "--build-type", "Release", "--clean", - "--target-compiler", + "--compiler", "gcc", "--external-runtime-path", "src", From b56085302e95d8feec4e506a6baada274684cf29 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Sat, 30 Sep 2023 17:49:20 -0700 Subject: [PATCH 029/145] Adjust compiler CLI arg --- cli/lfc/src/main/java/org/lflang/cli/Lfc.java | 2 +- cli/lfc/src/test/java/org/lflang/cli/LfcCliTest.java | 4 ++-- .../main/java/org/lflang/generator/LFGeneratorContext.java | 2 +- 3 files changed, 4 insertions(+), 4 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 66130238d3..6409b7c0ba 100644 --- a/cli/lfc/src/main/java/org/lflang/cli/Lfc.java +++ b/cli/lfc/src/main/java/org/lflang/cli/Lfc.java @@ -261,7 +261,7 @@ public Properties getGeneratorArgs() { } if (targetCompiler != null) { - props.setProperty(BuildParm.TARGET_COMPILER.getKey(), targetCompiler); + props.setProperty(BuildParm.COMPILER.getKey(), targetCompiler); } if (quiet) { 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 07f717ccbb..2408971256 100644 --- a/cli/lfc/src/test/java/org/lflang/cli/LfcCliTest.java +++ b/cli/lfc/src/test/java/org/lflang/cli/LfcCliTest.java @@ -67,7 +67,7 @@ public class LfcCliTest { "properties": { "build-type": "Release", "clean": true, - "target-compiler": "gcc", + "compiler": "gcc", "external-runtime-path": "src", "federated": true, "logging": "info", @@ -246,7 +246,7 @@ public void verifyGeneratorArgs(Path tempDir, String[] args) { Properties properties = fixture.lfc.getGeneratorArgs(); assertEquals(properties.getProperty(BuildParm.BUILD_TYPE.getKey()), "Release"); assertEquals(properties.getProperty(BuildParm.CLEAN.getKey()), "true"); - assertEquals(properties.getProperty(BuildParm.TARGET_COMPILER.getKey()), "gcc"); + assertEquals(properties.getProperty(BuildParm.COMPILER.getKey()), "gcc"); assertEquals(properties.getProperty(BuildParm.EXTERNAL_RUNTIME_PATH.getKey()), "src"); assertEquals(properties.getProperty(BuildParm.LOGGING.getKey()), "info"); assertEquals(properties.getProperty(BuildParm.LINT.getKey()), "true"); diff --git a/core/src/main/java/org/lflang/generator/LFGeneratorContext.java b/core/src/main/java/org/lflang/generator/LFGeneratorContext.java index 4353e3c46e..142a51a209 100644 --- a/core/src/main/java/org/lflang/generator/LFGeneratorContext.java +++ b/core/src/main/java/org/lflang/generator/LFGeneratorContext.java @@ -35,7 +35,7 @@ enum BuildParm { RTI("Specify the location of the RTI."), RUNTIME_VERSION("Specify the version of the runtime library used for compiling LF programs."), SCHEDULER("Specify the runtime scheduler (if supported)."), - TARGET_COMPILER("Target compiler to invoke."), + COMPILER("Target compiler to invoke."), THREADING("Specify whether the runtime should use multi-threading (true/false)."), VERSION("Print version information."), WORKERS("Specify the default number of worker threads."); From e98fc812531c6a1713b5cf1f9a06a6f35931504f Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Sat, 30 Sep 2023 22:41:04 -0700 Subject: [PATCH 030/145] Improve API and add comments --- .../org/lflang/AbstractTargetProperty.java | 189 ++++++++++++++++++ .../main/java/org/lflang/TargetConfig.java | 4 +- .../main/java/org/lflang/TargetProperty.java | 14 +- .../java/org/lflang/TargetPropertyConfig.java | 119 ----------- .../federated/extensions/CExtension.java | 2 +- .../federated/extensions/CExtensionUtils.java | 27 ++- .../extensions/FedTargetExtension.java | 2 +- .../federated/extensions/PythonExtension.java | 2 +- .../federated/extensions/TSExtension.java | 2 +- .../federated/generator/FedASTUtils.java | 2 +- .../federated/generator/FedGenerator.java | 2 +- .../property/AbstractBooleanProperty.java | 34 ++++ ...rty.java => AbstractFileListProperty.java} | 20 +- .../target/property/AbstractStringConfig.java | 34 ++++ .../property/AbstractStringListProperty.java | 61 ++++++ .../lflang/target/property/AuthProperty.java | 2 +- .../property/BuildCommandsProperty.java | 12 +- .../target/property/BuildTypeProperty.java | 14 +- .../property/CargoDependenciesProperty.java | 12 +- .../property/CargoFeaturesProperty.java | 2 +- .../property/ClockSyncModeProperty.java | 22 +- .../property/ClockSyncOptionsProperty.java | 26 +-- .../target/property/CmakeIncludeProperty.java | 24 ++- .../property/CompileDefinitionsProperty.java | 18 +- .../property/CompilerFlagsProperty.java | 2 +- .../target/property/CompilerProperty.java | 2 +- .../property/CoordinationOptionsProperty.java | 14 +- ...roperty.java => CoordinationProperty.java} | 25 +-- .../property/DefaultBooleanProperty.java | 34 ---- .../target/property/DefaultStringConfig.java | 34 ---- .../property/DefaultStringListProperty.java | 55 ----- .../target/property/DockerProperty.java | 22 +- .../ExportDependencyGraphProperty.java | 2 +- .../target/property/ExportToYamlProperty.java | 2 +- .../property/ExternalRuntimePathProperty.java | 2 +- .../lflang/target/property/FastProperty.java | 6 +- .../target/property/FedSetupProperty.java | 14 +- .../lflang/target/property/FilesProperty.java | 2 +- .../target/property/KeepaliveProperty.java | 10 +- .../target/property/LoggingProperty.java | 12 +- .../target/property/NoCompileProperty.java | 2 +- .../property/NoRuntimeValidationProperty.java | 2 +- .../target/property/PlatformProperty.java | 34 ++-- .../property/PrintStatisticsProperty.java | 2 +- .../target/property/ProtobufsProperty.java | 2 +- .../property/Ros2DependenciesProperty.java | 17 +- .../lflang/target/property/Ros2Property.java | 2 +- .../property/RuntimeVersionProperty.java | 2 +- .../target/property/RustIncludeProperty.java | 26 +-- .../target/property/SchedulerProperty.java | 19 +- .../property/SingleFileProjectProperty.java | 2 +- .../target/property/ThreadingProperty.java | 2 +- .../target/property/TimeOutProperty.java | 12 +- .../target/property/TracingProperty.java | 26 ++- .../target/property/VerifyProperty.java | 4 +- .../target/property/WorkersProperty.java | 14 +- .../target/property/type/UnionType.java | 2 +- 57 files changed, 557 insertions(+), 497 deletions(-) create mode 100644 core/src/main/java/org/lflang/AbstractTargetProperty.java delete mode 100644 core/src/main/java/org/lflang/TargetPropertyConfig.java create mode 100644 core/src/main/java/org/lflang/target/property/AbstractBooleanProperty.java rename core/src/main/java/org/lflang/target/property/{DefaultFileListProperty.java => AbstractFileListProperty.java} (51%) create mode 100644 core/src/main/java/org/lflang/target/property/AbstractStringConfig.java create mode 100644 core/src/main/java/org/lflang/target/property/AbstractStringListProperty.java rename core/src/main/java/org/lflang/target/property/{CoordinationModeProperty.java => CoordinationProperty.java} (56%) delete mode 100644 core/src/main/java/org/lflang/target/property/DefaultBooleanProperty.java delete mode 100644 core/src/main/java/org/lflang/target/property/DefaultStringConfig.java delete mode 100644 core/src/main/java/org/lflang/target/property/DefaultStringListProperty.java diff --git a/core/src/main/java/org/lflang/AbstractTargetProperty.java b/core/src/main/java/org/lflang/AbstractTargetProperty.java new file mode 100644 index 0000000000..bb39cd3943 --- /dev/null +++ b/core/src/main/java/org/lflang/AbstractTargetProperty.java @@ -0,0 +1,189 @@ +package org.lflang; + +import java.util.List; +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.property.type.TargetPropertyType; + +/** + * A base class for target properties. + * + *

After implementing this class to create a new target property, add a corresponding entry to + * {@code TargetConfig} and hook it into the {@code TargetProperty} enum. + * + * @param The data type of the value assigned to the target property. + */ +public abstract class AbstractTargetProperty { + + /** The type of values that can be assigned to this property. */ + public final TargetPropertyType type; + + /** Whether (after initialization) this property has been set. */ + protected boolean isSet; + + /** + * The value assigned to the target property, initialized using the {@code initialValue()} method. + */ + private T value = initialValue(); + + /** + * Construct a new target property. + * + * @param type The type of the value that can be assigned to the property. + */ + public AbstractTargetProperty(TargetPropertyType type) { + this.type = type; + } + + /** + * If this target property is not supported by the given target, report a warning through the + * message reporter at the location of the given key-value pair. + * + * @param pair The ast node that matches this target property. + * @param target The target to check against. + * @param reporter The reporter to issue a warning through if this property is not supported by + * the given target. + */ + public void checkSupport(KeyValuePair pair, Target target, MessageReporter reporter) { + if (!this.isSupported(target)) { + reporter + .at(pair, Literals.KEY_VALUE_PAIR__NAME) + .warning( + String.format( + "The target parameter: %s is not supported by the %s target and will thus be" + + " ignored.", + pair.getName(), target)); + } + } + + /** + * If the given key-value pair does not match the type required by this target property, report an + * error through the given reporter. + * + * @param pair The ast node that matches this target property. + * @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)) { + reporter + .at(pair, Literals.KEY_VALUE_PAIR__VALUE) + .error("Target property '" + pair.getName() + "' is required to be " + type + "."); + } + } + + /** + * Return {@code true} if this target property has been set (past initialization), {@code false} + * otherwise. + */ + public boolean isSet() { + return isSet; + } + + /** + * Return {@code true} if this target property is supported by the given target, {@code false} + * otherwise. + * + * @param target The target to check against. + */ + public final boolean isSupported(Target target) { + return supportedTargets().contains(target); + } + + /** + * Manually override the value of this target property. + * + * @param value The value to assign to this target property. + */ + public void override(T value) { + this.isSet = true; + this.value = value; + } + + /** Reset this target property to its initial value. */ + public void reset() { + this.value = initialValue(); + this.isSet = false; + } + + /** + * Parse the given AST node into the given target config. Encountered errors are reported via the + * given reporter. + * + * @param node The AST node to derive a newly assigned value from. + * @param reporter A reporter for reporting errors. + */ + public void set(Element node, MessageReporter reporter) { + var parsed = this.fromAst(node, reporter); + if (parsed != null) { + this.isSet = true; + this.value = parsed; + } + } + + /** + * Parse the given element into the given target config. May use the error reporter to report + * format errors. + */ + public void set(String value, MessageReporter err) { + var parsed = this.fromString(value, err); + if (parsed != null) { + this.isSet = true; + this.value = parsed; + } + } + + @Override + public String toString() { + return value == null ? null : value.toString(); // FIXME: do not return null + } + + /** + * 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 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(); + + /** Return the value currently assigned to this target property. */ + public T get() { + return value; + } + + /** + * Given an AST node, produce a corresponding value that is assignable to this target property, or + * report an error via the given reporter in case any problems are encountered. + * + * @param node The AST node to derive a value of type {@code T} from. + * @param reporter A reporter for reporting errors. + * @return A value of type {@code T}. + */ + protected abstract T fromAst(Element node, MessageReporter reporter); + + /** + * Given a string, produce a corresponding value that is assignable to this target property, or + * report an error via the given reporter in case any problems are encountered. + * + * @param string The string to derive a value of type {@code T} from. + * @param reporter A reporter for reporting errors. + * @return A value of type {@code T}. + */ + protected abstract T fromString(String string, MessageReporter reporter); + + public abstract List supportedTargets(); + + /** + * Return an AST node that represents this target property and the value currently assigned to it. + */ + public abstract Element toAstElement(); +} diff --git a/core/src/main/java/org/lflang/TargetConfig.java b/core/src/main/java/org/lflang/TargetConfig.java index 4e35f7a587..6a0958fbca 100644 --- a/core/src/main/java/org/lflang/TargetConfig.java +++ b/core/src/main/java/org/lflang/TargetConfig.java @@ -39,8 +39,8 @@ import org.lflang.target.property.CompileDefinitionsProperty; import org.lflang.target.property.CompilerFlagsProperty; import org.lflang.target.property.CompilerProperty; -import org.lflang.target.property.CoordinationModeProperty; import org.lflang.target.property.CoordinationOptionsProperty; +import org.lflang.target.property.CoordinationProperty; import org.lflang.target.property.DockerProperty; import org.lflang.target.property.ExportDependencyGraphProperty; import org.lflang.target.property.ExportToYamlProperty; @@ -149,7 +149,7 @@ public TargetConfig(Properties cliArgs, TargetDecl target, MessageReporter messa * The type of coordination used during the execution of a federated program. The default is * 'centralized'. */ - public final CoordinationModeProperty coordination = new CoordinationModeProperty(); + public final CoordinationProperty coordination = new CoordinationProperty(); /** Docker options. */ public final DockerProperty dockerOptions = new DockerProperty(); diff --git a/core/src/main/java/org/lflang/TargetProperty.java b/core/src/main/java/org/lflang/TargetProperty.java index fe6e37bde1..81b22ff7ba 100644 --- a/core/src/main/java/org/lflang/TargetProperty.java +++ b/core/src/main/java/org/lflang/TargetProperty.java @@ -51,8 +51,8 @@ import org.lflang.target.property.CompileDefinitionsProperty; import org.lflang.target.property.CompilerFlagsProperty; import org.lflang.target.property.CompilerProperty; -import org.lflang.target.property.CoordinationModeProperty; import org.lflang.target.property.CoordinationOptionsProperty; +import org.lflang.target.property.CoordinationProperty; import org.lflang.target.property.DockerProperty; import org.lflang.target.property.ExportDependencyGraphProperty; import org.lflang.target.property.ExportToYamlProperty; @@ -118,7 +118,7 @@ public enum TargetProperty { COMPILE_DEFINITIONS(CompileDefinitionsProperty.class, config -> config.compileDefinitions), /** Directive to specify the coordination mode */ - COORDINATION(CoordinationModeProperty.class, config -> config.coordination), + COORDINATION(CoordinationProperty.class, config -> config.coordination), /** Key-value pairs giving options for clock synchronization. */ COORDINATION_OPTIONS(CoordinationOptionsProperty.class, config -> config.coordinationOptions), /** @@ -259,14 +259,14 @@ public enum TargetProperty { public final ConfigLoader property; - public final Class> propertyClass; + public final Class> propertyClass; @FunctionalInterface private interface ConfigLoader { - TargetPropertyConfig of(TargetConfig config); + AbstractTargetProperty of(TargetConfig config); } - TargetProperty(Class> cls, ConfigLoader property) { + TargetProperty(Class> cls, ConfigLoader property) { this.propertyClass = cls; this.property = property; } @@ -282,7 +282,7 @@ public String getKey() { return name().toLowerCase().replace('_', '-'); } - public static TargetPropertyConfig getPropertyInstance(TargetProperty p) { + public static AbstractTargetProperty getPropertyInstance(TargetProperty p) { try { return p.propertyClass.getDeclaredConstructor().newInstance(); } catch (ReflectiveOperationException e) { @@ -408,7 +408,7 @@ public static void validate( var p = match.get(); p.property.of(config).checkSupport(pair, config.target, reporter); p.property.of(config).checkType(pair, reporter); - p.property.of(config).validate(pair, ast, config, reporter); + p.property.of(config).validate(pair, ast, reporter); } else { reporter .at(pair, Literals.KEY_VALUE_PAIR__NAME) diff --git a/core/src/main/java/org/lflang/TargetPropertyConfig.java b/core/src/main/java/org/lflang/TargetPropertyConfig.java deleted file mode 100644 index 4a41df7b39..0000000000 --- a/core/src/main/java/org/lflang/TargetPropertyConfig.java +++ /dev/null @@ -1,119 +0,0 @@ -package org.lflang; - -import java.util.List; -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.property.type.TargetPropertyType; - -/** - * Extend this class to manage the configuration of a target property. - * - * @param The type of the configuration value. - */ -public abstract class TargetPropertyConfig { - - protected T value = initialValue(); - - protected boolean isSet; - - /* The type of values that can be assigned to this property. */ - public final TargetPropertyType type; - - public TargetPropertyConfig(TargetPropertyType type) { - this.type = type; - } - - public void override(T value) { - this.isSet = true; - this.value = value; - } - - public abstract T initialValue(); - - /** - * Parse the given element into the given target config. May use the error reporter to report - * format errors. - */ - public void set(Element value, MessageReporter err) { - var parsed = this.fromAst(value, err); - if (parsed != null) { - this.isSet = true; - this.value = parsed; - } - } - - public void set(String value, MessageReporter err) { - var parsed = this.fromString(value, err); - if (parsed != null) { - this.isSet = true; - this.value = parsed; - } - } - - public void reset() { - this.value = initialValue(); - this.isSet = false; - } - - /** Return the current configuration. */ - public T get() { - return value; - } - - protected abstract T fromAst(Element value, MessageReporter err); - - protected abstract T fromString(String value, MessageReporter err); - - public abstract List supportedTargets(); - - public final boolean isSupported(Target target) { - return supportedTargets().contains(target); - } - - public void validate( - KeyValuePair pair, Model ast, TargetConfig config, MessageReporter reporter) { - // FIXME: Make abstract? - // FIXME: consider not passing in config - } - - public void checkSupport(KeyValuePair pair, Target target, MessageReporter reporter) { - if (!this.isSupported(target)) { - reporter - .at(pair, Literals.KEY_VALUE_PAIR__NAME) - .warning( - String.format( - "The target parameter: %s is not supported by the %s target and will thus be" - + " ignored.", - pair.getName(), target)); - } - } - - public void checkType(KeyValuePair pair, MessageReporter reporter) { - if (!this.type.check(pair.getValue(), pair.getName(), reporter)) { - reporter - .at(pair, Literals.KEY_VALUE_PAIR__VALUE) - .error("Target property '" + pair.getName() + "' is required to be " + type + "."); - } - } - - /** - * Read this property from the target config and build an element which represents it for the AST. - * May return null if the given value of this property is the same as the default. - */ - public abstract Element toAstElement(); - - public boolean isSet() { - return isSet; - } - - @Override - public String toString() { - return value == null ? null : value.toString(); - } - - public void markSet() { - this.isSet = true; - } -} 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 07dce71ca1..f5de233de4 100644 --- a/core/src/main/java/org/lflang/federated/extensions/CExtension.java +++ b/core/src/main/java/org/lflang/federated/extensions/CExtension.java @@ -56,7 +56,7 @@ import org.lflang.lf.Port; import org.lflang.lf.Reactor; import org.lflang.lf.VarRef; -import org.lflang.target.property.CoordinationModeProperty.CoordinationMode; +import org.lflang.target.property.CoordinationProperty.CoordinationMode; /** * An extension class to the CGenerator that enables certain federated functionalities. diff --git a/core/src/main/java/org/lflang/federated/extensions/CExtensionUtils.java b/core/src/main/java/org/lflang/federated/extensions/CExtensionUtils.java index daf075ed45..7712093240 100644 --- a/core/src/main/java/org/lflang/federated/extensions/CExtensionUtils.java +++ b/core/src/main/java/org/lflang/federated/extensions/CExtensionUtils.java @@ -172,15 +172,17 @@ public static void handleCompileDefinitions( int numOfFederates, RtiConfig rtiConfig, MessageReporter messageReporter) { - var defs = federate.targetConfig.compileDefinitions.get(); - defs.put("FEDERATED", ""); - defs.put("FEDERATED_" + federate.targetConfig.coordination.get().toString().toUpperCase(), ""); + var definitions = federate.targetConfig.compileDefinitions; + definitions.add("FEDERATED", ""); + definitions.add( + String.format( + "FEDERATED_%s", federate.targetConfig.coordination.get().toString().toUpperCase()), + ""); if (federate.targetConfig.auth.get()) { - defs.put("FEDERATED_AUTHENTICATED", ""); + definitions.add("FEDERATED_AUTHENTICATED", ""); } - defs.put("NUMBER_OF_FEDERATES", String.valueOf(numOfFederates)); - defs.put("EXECUTABLE_PREAMBLE", ""); - federate.targetConfig.compileDefinitions.markSet(); + definitions.add("NUMBER_OF_FEDERATES", String.valueOf(numOfFederates)); + definitions.add("EXECUTABLE_PREAMBLE", ""); handleAdvanceMessageInterval(federate); @@ -227,8 +229,7 @@ public static void initializeClockSynchronization( .nowhere() .info("Will collect clock sync statistics for federate " + federate.id); // Add libm to the compiler flags - federate.targetConfig.compilerFlags.get().add("-lm"); - federate.targetConfig.compilerFlags.markSet(); + federate.targetConfig.compilerFlags.add("-lm"); } messageReporter .nowhere() @@ -299,12 +300,8 @@ public static void generateCMakeInclude(FederateInstance federate, FedFileConfig srcWriter.write(cmakeIncludeCode.getCode()); } - federate - .targetConfig - .cmakeIncludes - .get() - .add(fileConfig.getSrcPath().relativize(cmakeIncludePath).toString()); - federate.targetConfig.cmakeIncludes.markSet(); + federate.targetConfig.cmakeIncludes.add( + fileConfig.getSrcPath().relativize(cmakeIncludePath).toString()); } /** diff --git a/core/src/main/java/org/lflang/federated/extensions/FedTargetExtension.java b/core/src/main/java/org/lflang/federated/extensions/FedTargetExtension.java index 4b20b09ba5..a580ec693a 100644 --- a/core/src/main/java/org/lflang/federated/extensions/FedTargetExtension.java +++ b/core/src/main/java/org/lflang/federated/extensions/FedTargetExtension.java @@ -13,7 +13,7 @@ import org.lflang.lf.Reaction; import org.lflang.lf.Reactor; import org.lflang.lf.VarRef; -import org.lflang.target.property.CoordinationModeProperty.CoordinationMode; +import org.lflang.target.property.CoordinationProperty.CoordinationMode; public interface FedTargetExtension { diff --git a/core/src/main/java/org/lflang/federated/extensions/PythonExtension.java b/core/src/main/java/org/lflang/federated/extensions/PythonExtension.java index ab05d80f7e..c0fae10f32 100644 --- a/core/src/main/java/org/lflang/federated/extensions/PythonExtension.java +++ b/core/src/main/java/org/lflang/federated/extensions/PythonExtension.java @@ -42,7 +42,7 @@ import org.lflang.lf.Action; import org.lflang.lf.Reaction; import org.lflang.lf.VarRef; -import org.lflang.target.property.CoordinationModeProperty.CoordinationMode; +import org.lflang.target.property.CoordinationProperty.CoordinationMode; /** * An extension class to the PythonGenerator that enables certain federated functionalities. diff --git a/core/src/main/java/org/lflang/federated/extensions/TSExtension.java b/core/src/main/java/org/lflang/federated/extensions/TSExtension.java index 2505686ec4..a2a2e54ebd 100644 --- a/core/src/main/java/org/lflang/federated/extensions/TSExtension.java +++ b/core/src/main/java/org/lflang/federated/extensions/TSExtension.java @@ -25,7 +25,7 @@ import org.lflang.lf.Reactor; import org.lflang.lf.VarRef; import org.lflang.lf.Variable; -import org.lflang.target.property.CoordinationModeProperty.CoordinationMode; +import org.lflang.target.property.CoordinationProperty.CoordinationMode; public class TSExtension implements FedTargetExtension { @Override diff --git a/core/src/main/java/org/lflang/federated/generator/FedASTUtils.java b/core/src/main/java/org/lflang/federated/generator/FedASTUtils.java index b970b15cd6..28290a1a6d 100644 --- a/core/src/main/java/org/lflang/federated/generator/FedASTUtils.java +++ b/core/src/main/java/org/lflang/federated/generator/FedASTUtils.java @@ -70,7 +70,7 @@ import org.lflang.lf.Type; import org.lflang.lf.VarRef; import org.lflang.lf.Variable; -import org.lflang.target.property.CoordinationModeProperty.CoordinationMode; +import org.lflang.target.property.CoordinationProperty.CoordinationMode; /** * A helper class for AST transformations needed for federated execution. 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 c1524d48e0..af3f383e2c 100644 --- a/core/src/main/java/org/lflang/federated/generator/FedGenerator.java +++ b/core/src/main/java/org/lflang/federated/generator/FedGenerator.java @@ -58,7 +58,7 @@ import org.lflang.lf.Reactor; import org.lflang.lf.TargetDecl; import org.lflang.lf.VarRef; -import org.lflang.target.property.CoordinationModeProperty.CoordinationMode; +import org.lflang.target.property.CoordinationProperty.CoordinationMode; import org.lflang.util.Averager; public class FedGenerator { diff --git a/core/src/main/java/org/lflang/target/property/AbstractBooleanProperty.java b/core/src/main/java/org/lflang/target/property/AbstractBooleanProperty.java new file mode 100644 index 0000000000..8d65a0674b --- /dev/null +++ b/core/src/main/java/org/lflang/target/property/AbstractBooleanProperty.java @@ -0,0 +1,34 @@ +package org.lflang.target.property; + +import org.lflang.AbstractTargetProperty; +import org.lflang.MessageReporter; +import org.lflang.ast.ASTUtils; +import org.lflang.lf.Element; +import org.lflang.target.property.type.PrimitiveType; + +public abstract class AbstractBooleanProperty extends AbstractTargetProperty { + + public AbstractBooleanProperty() { + super(PrimitiveType.BOOLEAN); + } + + @Override + public Boolean initialValue() { + return false; + } + + @Override + public Boolean fromAst(Element node, MessageReporter reporter) { + return ASTUtils.toBoolean(node); + } + + @Override + protected Boolean fromString(String string, MessageReporter reporter) { + return Boolean.parseBoolean(string); + } + + @Override + public Element toAstElement() { + return ASTUtils.toElement(get()); + } +} diff --git a/core/src/main/java/org/lflang/target/property/DefaultFileListProperty.java b/core/src/main/java/org/lflang/target/property/AbstractFileListProperty.java similarity index 51% rename from core/src/main/java/org/lflang/target/property/DefaultFileListProperty.java rename to core/src/main/java/org/lflang/target/property/AbstractFileListProperty.java index cf35d54ea7..cd462ab2ec 100644 --- a/core/src/main/java/org/lflang/target/property/DefaultFileListProperty.java +++ b/core/src/main/java/org/lflang/target/property/AbstractFileListProperty.java @@ -2,15 +2,15 @@ import java.util.ArrayList; import java.util.List; +import org.lflang.AbstractTargetProperty; import org.lflang.MessageReporter; -import org.lflang.TargetPropertyConfig; import org.lflang.ast.ASTUtils; import org.lflang.lf.Element; import org.lflang.target.property.type.UnionType; -public abstract class DefaultFileListProperty extends TargetPropertyConfig> { +public abstract class AbstractFileListProperty extends AbstractTargetProperty> { - public DefaultFileListProperty() { + public AbstractFileListProperty() { super(UnionType.FILE_OR_FILE_ARRAY); } @@ -20,26 +20,26 @@ public List initialValue() { } @Override - public void set(Element value, MessageReporter err) { + public void set(Element node, MessageReporter reporter) { if (!this.isSet) { - super.set(value, err); + super.set(node, reporter); } else { - this.value.addAll(fromAst(value, err)); + this.get().addAll(fromAst(node, reporter)); } } @Override - public List fromAst(Element value, MessageReporter err) { - return ASTUtils.elementToListOfStrings(value); + public List fromAst(Element node, MessageReporter reporter) { + return ASTUtils.elementToListOfStrings(node); } @Override - protected List fromString(String value, MessageReporter err) { + protected List fromString(String string, MessageReporter reporter) { throw new UnsupportedOperationException("Not supported yet."); } @Override public Element toAstElement() { - return ASTUtils.toElement(value); + return ASTUtils.toElement(get()); } } diff --git a/core/src/main/java/org/lflang/target/property/AbstractStringConfig.java b/core/src/main/java/org/lflang/target/property/AbstractStringConfig.java new file mode 100644 index 0000000000..619a7f135d --- /dev/null +++ b/core/src/main/java/org/lflang/target/property/AbstractStringConfig.java @@ -0,0 +1,34 @@ +package org.lflang.target.property; + +import org.lflang.AbstractTargetProperty; +import org.lflang.MessageReporter; +import org.lflang.ast.ASTUtils; +import org.lflang.lf.Element; +import org.lflang.target.property.type.PrimitiveType; + +public abstract class AbstractStringConfig extends AbstractTargetProperty { + + public AbstractStringConfig() { + super(PrimitiveType.STRING); + } + + @Override + public String initialValue() { + return ""; + } + + @Override + public String fromAst(Element node, MessageReporter reporter) { + return ASTUtils.elementToSingleString(node); + } + + @Override + protected String fromString(String string, MessageReporter reporter) { + return string; + } + + @Override + public Element toAstElement() { + return ASTUtils.toElement(this.get()); + } +} diff --git a/core/src/main/java/org/lflang/target/property/AbstractStringListProperty.java b/core/src/main/java/org/lflang/target/property/AbstractStringListProperty.java new file mode 100644 index 0000000000..43afc06e91 --- /dev/null +++ b/core/src/main/java/org/lflang/target/property/AbstractStringListProperty.java @@ -0,0 +1,61 @@ +package org.lflang.target.property; + +import java.util.ArrayList; +import java.util.List; +import org.lflang.AbstractTargetProperty; +import org.lflang.MessageReporter; +import org.lflang.ast.ASTUtils; +import org.lflang.lf.Element; +import org.lflang.target.property.type.UnionType; + +/** Note: {@code set} implements an "append" semantics. */ +public abstract class AbstractStringListProperty extends AbstractTargetProperty> { + + public AbstractStringListProperty() { + super(UnionType.STRING_OR_STRING_ARRAY); + } + + public void add(String entry) { + this.isSet = true; + var value = this.get(); + value.add(entry); + } + + @Override + public List initialValue() { + return new ArrayList<>(); + } + + @Override + public void set(Element node, MessageReporter reporter) { + if (!this.isSet) { + super.set(node, reporter); + } else { + this.get().addAll(this.fromAst(node, reporter)); + } + } + + @Override + public void set(String string, MessageReporter err) { + if (!this.isSet) { + super.set(string, err); + } else { + this.get().addAll(this.fromString(string, err)); + } + } + + @Override + public List fromAst(Element node, MessageReporter reporter) { + return ASTUtils.elementToListOfStrings(node); + } + + @Override + protected List fromString(String string, MessageReporter reporter) { + return List.of(string.split(" ")); + } + + @Override + public Element toAstElement() { + return ASTUtils.toElement(get()); + } +} diff --git a/core/src/main/java/org/lflang/target/property/AuthProperty.java b/core/src/main/java/org/lflang/target/property/AuthProperty.java index 03eeb124a6..f8132c116f 100644 --- a/core/src/main/java/org/lflang/target/property/AuthProperty.java +++ b/core/src/main/java/org/lflang/target/property/AuthProperty.java @@ -4,7 +4,7 @@ import java.util.List; import org.lflang.Target; -public class AuthProperty extends DefaultBooleanProperty { +public class AuthProperty extends AbstractBooleanProperty { @Override public List supportedTargets() { diff --git a/core/src/main/java/org/lflang/target/property/BuildCommandsProperty.java b/core/src/main/java/org/lflang/target/property/BuildCommandsProperty.java index 1005001ef6..da459ab500 100644 --- a/core/src/main/java/org/lflang/target/property/BuildCommandsProperty.java +++ b/core/src/main/java/org/lflang/target/property/BuildCommandsProperty.java @@ -3,14 +3,14 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import org.lflang.AbstractTargetProperty; import org.lflang.MessageReporter; import org.lflang.Target; -import org.lflang.TargetPropertyConfig; import org.lflang.ast.ASTUtils; import org.lflang.lf.Element; import org.lflang.target.property.type.UnionType; -public class BuildCommandsProperty extends TargetPropertyConfig> { +public class BuildCommandsProperty extends AbstractTargetProperty> { public BuildCommandsProperty() { super(UnionType.STRING_OR_STRING_ARRAY); @@ -22,12 +22,12 @@ public List initialValue() { } @Override - public List fromAst(Element value, MessageReporter err) { - return ASTUtils.elementToListOfStrings(value); + public List fromAst(Element node, MessageReporter reporter) { + return ASTUtils.elementToListOfStrings(node); } @Override - protected List fromString(String value, MessageReporter err) { + protected List fromString(String string, MessageReporter reporter) { throw new UnsupportedOperationException("Not supported yet."); } @@ -38,6 +38,6 @@ public List supportedTargets() { @Override public Element toAstElement() { - return ASTUtils.toElement(this.value.toString()); + return ASTUtils.toElement(this.get().toString()); } } diff --git a/core/src/main/java/org/lflang/target/property/BuildTypeProperty.java b/core/src/main/java/org/lflang/target/property/BuildTypeProperty.java index 3007c9391c..86e79f4c99 100644 --- a/core/src/main/java/org/lflang/target/property/BuildTypeProperty.java +++ b/core/src/main/java/org/lflang/target/property/BuildTypeProperty.java @@ -2,15 +2,15 @@ import java.util.Arrays; import java.util.List; +import org.lflang.AbstractTargetProperty; import org.lflang.MessageReporter; import org.lflang.Target; -import org.lflang.TargetPropertyConfig; import org.lflang.ast.ASTUtils; import org.lflang.lf.Element; import org.lflang.target.property.BuildTypeProperty.BuildType; import org.lflang.target.property.type.UnionType; -public class BuildTypeProperty extends TargetPropertyConfig { +public class BuildTypeProperty extends AbstractTargetProperty { public BuildTypeProperty() { super(UnionType.BUILD_TYPE_UNION); @@ -18,7 +18,7 @@ public BuildTypeProperty() { @Override public Element toAstElement() { - return ASTUtils.toElement(this.value.toString()); + return ASTUtils.toElement(this.get().toString()); } @Override @@ -27,13 +27,13 @@ public BuildType initialValue() { } @Override - public BuildType fromAst(Element value, MessageReporter err) { - return fromString(ASTUtils.elementToSingleString(value), err); + public BuildType fromAst(Element node, MessageReporter reporter) { + return fromString(ASTUtils.elementToSingleString(node), reporter); } @Override - protected BuildType fromString(String value, MessageReporter err) { - return (BuildType) UnionType.BUILD_TYPE_UNION.forName(value); + protected BuildType fromString(String string, MessageReporter reporter) { + return (BuildType) UnionType.BUILD_TYPE_UNION.forName(string); } @Override 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 431bac4935..5761073267 100644 --- a/core/src/main/java/org/lflang/target/property/CargoDependenciesProperty.java +++ b/core/src/main/java/org/lflang/target/property/CargoDependenciesProperty.java @@ -4,9 +4,9 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import org.lflang.AbstractTargetProperty; import org.lflang.MessageReporter; import org.lflang.Target; -import org.lflang.TargetPropertyConfig; import org.lflang.generator.rust.CargoDependencySpec; import org.lflang.generator.rust.CargoDependencySpec.CargoDependenciesPropertyType; import org.lflang.lf.Element; @@ -15,7 +15,7 @@ import org.lflang.lf.LfFactory; public class CargoDependenciesProperty - extends TargetPropertyConfig> { + extends AbstractTargetProperty> { public CargoDependenciesProperty() { super(CargoDependenciesPropertyType.INSTANCE); @@ -27,12 +27,12 @@ public Map initialValue() { } @Override - protected Map fromAst(Element value, MessageReporter err) { - return CargoDependencySpec.parseAll(value); + protected Map fromAst(Element node, MessageReporter reporter) { + return CargoDependencySpec.parseAll(node); } @Override - protected Map fromString(String value, MessageReporter err) { + protected Map fromString(String string, MessageReporter reporter) { throw new UnsupportedOperationException("Not supported yet."); } @@ -43,7 +43,7 @@ public List supportedTargets() { @Override public Element toAstElement() { - var deps = this.value; + var deps = this.get(); if (deps.size() == 0) { return null; } else { diff --git a/core/src/main/java/org/lflang/target/property/CargoFeaturesProperty.java b/core/src/main/java/org/lflang/target/property/CargoFeaturesProperty.java index 92d8d498be..290b0961d3 100644 --- a/core/src/main/java/org/lflang/target/property/CargoFeaturesProperty.java +++ b/core/src/main/java/org/lflang/target/property/CargoFeaturesProperty.java @@ -4,7 +4,7 @@ import java.util.List; import org.lflang.Target; -public class CargoFeaturesProperty extends DefaultStringListProperty { +public class CargoFeaturesProperty extends AbstractStringListProperty { @Override public List supportedTargets() { 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 2e286f4bec..1b18b20817 100644 --- a/core/src/main/java/org/lflang/target/property/ClockSyncModeProperty.java +++ b/core/src/main/java/org/lflang/target/property/ClockSyncModeProperty.java @@ -2,10 +2,9 @@ import java.util.List; import java.util.Objects; +import org.lflang.AbstractTargetProperty; import org.lflang.MessageReporter; import org.lflang.Target; -import org.lflang.TargetConfig; -import org.lflang.TargetPropertyConfig; import org.lflang.ast.ASTUtils; import org.lflang.lf.Element; import org.lflang.lf.KeyValuePair; @@ -15,7 +14,7 @@ import org.lflang.target.property.ClockSyncModeProperty.ClockSyncMode; import org.lflang.target.property.type.UnionType; -public class ClockSyncModeProperty extends TargetPropertyConfig { +public class ClockSyncModeProperty extends AbstractTargetProperty { public ClockSyncModeProperty() { super(UnionType.CLOCK_SYNC_UNION); @@ -27,15 +26,15 @@ public ClockSyncMode initialValue() { } @Override - public ClockSyncMode fromAst(Element value, MessageReporter err) { - UnionType.CLOCK_SYNC_UNION.validate(value); - var mode = fromString(ASTUtils.elementToSingleString(value), err); + public ClockSyncMode fromAst(Element node, MessageReporter reporter) { + UnionType.CLOCK_SYNC_UNION.validate(node); + var mode = fromString(ASTUtils.elementToSingleString(node), reporter); return Objects.requireNonNullElse(mode, ClockSyncMode.INIT); } @Override - protected ClockSyncMode fromString(String value, MessageReporter err) { - return (ClockSyncMode) UnionType.CLOCK_SYNC_UNION.forName(value); + protected ClockSyncMode fromString(String string, MessageReporter reporter) { + return (ClockSyncMode) UnionType.CLOCK_SYNC_UNION.forName(string); } @Override @@ -44,9 +43,8 @@ public List supportedTargets() { } @Override - public void validate( - KeyValuePair pair, Model ast, TargetConfig config, MessageReporter reporter) { - super.validate(pair, ast, config, reporter); + 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()) { @@ -64,7 +62,7 @@ public void validate( @Override public Element toAstElement() { - return ASTUtils.toElement(this.value.toString()); + return ASTUtils.toElement(this.get().toString()); } /** 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 4f13bf5878..6428580624 100644 --- a/core/src/main/java/org/lflang/target/property/ClockSyncOptionsProperty.java +++ b/core/src/main/java/org/lflang/target/property/ClockSyncOptionsProperty.java @@ -2,10 +2,10 @@ import java.util.Arrays; import java.util.List; +import org.lflang.AbstractTargetProperty; import org.lflang.MessageReporter; import org.lflang.Target; import org.lflang.TargetProperty.DictionaryElement; -import org.lflang.TargetPropertyConfig; import org.lflang.TimeUnit; import org.lflang.TimeValue; import org.lflang.ast.ASTUtils; @@ -18,7 +18,7 @@ import org.lflang.target.property.type.PrimitiveType; import org.lflang.target.property.type.TargetPropertyType; -public class ClockSyncOptionsProperty extends TargetPropertyConfig { +public class ClockSyncOptionsProperty extends AbstractTargetProperty { public ClockSyncOptionsProperty() { super(DictionaryType.CLOCK_SYNC_OPTION_DICT); @@ -30,9 +30,9 @@ public ClockSyncOptions initialValue() { } @Override - public ClockSyncOptions fromAst(Element value, MessageReporter err) { + public ClockSyncOptions fromAst(Element node, MessageReporter reporter) { var options = new ClockSyncOptions(); - for (KeyValuePair entry : value.getKeyvalue().getPairs()) { + for (KeyValuePair entry : node.getKeyvalue().getPairs()) { ClockSyncOption option = (ClockSyncOption) DictionaryType.CLOCK_SYNC_OPTION_DICT.forName(entry.getName()); switch (option) { @@ -49,7 +49,7 @@ public ClockSyncOptions fromAst(Element value, MessageReporter err) { } @Override - protected ClockSyncOptions fromString(String value, MessageReporter err) { + protected ClockSyncOptions fromString(String string, MessageReporter reporter) { throw new UnsupportedOperationException("Not supported yet."); } @@ -66,22 +66,22 @@ public Element toAstElement() { KeyValuePair pair = LfFactory.eINSTANCE.createKeyValuePair(); pair.setName(opt.toString()); switch (opt) { - case ATTENUATION -> pair.setValue(ASTUtils.toElement(value.attenuation)); - case COLLECT_STATS -> pair.setValue(ASTUtils.toElement(value.collectStats)); - case LOCAL_FEDERATES_ON -> pair.setValue(ASTUtils.toElement(value.localFederatesOn)); + case ATTENUATION -> pair.setValue(ASTUtils.toElement(get().attenuation)); + case COLLECT_STATS -> pair.setValue(ASTUtils.toElement(get().collectStats)); + case LOCAL_FEDERATES_ON -> pair.setValue(ASTUtils.toElement(get().localFederatesOn)); case PERIOD -> { - if (value.period == null) { + if (get().period == null) { continue; // don't set if null } - pair.setValue(ASTUtils.toElement(value.period)); + pair.setValue(ASTUtils.toElement(get().period)); } case TEST_OFFSET -> { - if (value.testOffset == null) { + if (get().testOffset == null) { continue; // don't set if null } - pair.setValue(ASTUtils.toElement(value.testOffset)); + pair.setValue(ASTUtils.toElement(get().testOffset)); } - case TRIALS -> pair.setValue(ASTUtils.toElement(value.trials)); + case TRIALS -> pair.setValue(ASTUtils.toElement(get().trials)); } kvp.getPairs().add(pair); } diff --git a/core/src/main/java/org/lflang/target/property/CmakeIncludeProperty.java b/core/src/main/java/org/lflang/target/property/CmakeIncludeProperty.java index 6ffcb81336..179a80e7a6 100644 --- a/core/src/main/java/org/lflang/target/property/CmakeIncludeProperty.java +++ b/core/src/main/java/org/lflang/target/property/CmakeIncludeProperty.java @@ -3,44 +3,50 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import org.lflang.AbstractTargetProperty; import org.lflang.MessageReporter; import org.lflang.Target; -import org.lflang.TargetPropertyConfig; import org.lflang.ast.ASTUtils; import org.lflang.lf.Element; import org.lflang.target.property.type.UnionType; -public class CmakeIncludeProperty extends TargetPropertyConfig> { +public class CmakeIncludeProperty extends AbstractTargetProperty> { public CmakeIncludeProperty() { super(UnionType.FILE_OR_FILE_ARRAY); } + public void add(String entry) { + this.isSet = true; + var value = this.get(); + value.add(entry); + } + @Override public List initialValue() { return new ArrayList<>(); } @Override - public void set(Element value, MessageReporter err) { + public void set(Element node, MessageReporter reporter) { if (!this.isSet) { - super.set(value, err); + super.set(node, reporter); } else { // NOTE: This merging of lists is potentially dangerous since // the incoming list of cmake-includes can belong to a .lf file that is // located in a different location, and keeping just filename // strings like this without absolute paths is incorrect. - this.value.addAll(ASTUtils.elementToListOfStrings(value)); + this.get().addAll(ASTUtils.elementToListOfStrings(node)); } } @Override - protected List fromAst(Element value, MessageReporter err) { - return ASTUtils.elementToListOfStrings(value); + protected List fromAst(Element node, MessageReporter reporter) { + return ASTUtils.elementToListOfStrings(node); } @Override - protected List fromString(String value, MessageReporter err) { + protected List fromString(String string, MessageReporter reporter) { throw new UnsupportedOperationException("Not supported yet."); } @@ -51,6 +57,6 @@ public List supportedTargets() { @Override public Element toAstElement() { - return ASTUtils.toElement(this.value); + return ASTUtils.toElement(this.get()); } } diff --git a/core/src/main/java/org/lflang/target/property/CompileDefinitionsProperty.java b/core/src/main/java/org/lflang/target/property/CompileDefinitionsProperty.java index 8b77b37935..584091d15c 100644 --- a/core/src/main/java/org/lflang/target/property/CompileDefinitionsProperty.java +++ b/core/src/main/java/org/lflang/target/property/CompileDefinitionsProperty.java @@ -4,31 +4,37 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import org.lflang.AbstractTargetProperty; import org.lflang.MessageReporter; import org.lflang.Target; -import org.lflang.TargetPropertyConfig; import org.lflang.ast.ASTUtils; import org.lflang.lf.Element; import org.lflang.target.property.type.StringDictionaryType; -public class CompileDefinitionsProperty extends TargetPropertyConfig> { +public class CompileDefinitionsProperty extends AbstractTargetProperty> { public CompileDefinitionsProperty() { super(StringDictionaryType.COMPILE_DEFINITION); } + public void add(String k, String v) { + this.isSet = true; + var value = this.get(); + value.put(k, v); + } + @Override public Map initialValue() { return new HashMap<>(); } @Override - protected Map fromAst(Element value, MessageReporter err) { - return ASTUtils.elementToStringMaps(value); + protected Map fromAst(Element node, MessageReporter reporter) { + return ASTUtils.elementToStringMaps(node); } @Override - protected Map fromString(String value, MessageReporter err) { + protected Map fromString(String string, MessageReporter reporter) { throw new UnsupportedOperationException("Not supported yet."); } @@ -39,6 +45,6 @@ public List supportedTargets() { @Override public Element toAstElement() { - return ASTUtils.toElement(this.value); + return ASTUtils.toElement(this.get()); } } diff --git a/core/src/main/java/org/lflang/target/property/CompilerFlagsProperty.java b/core/src/main/java/org/lflang/target/property/CompilerFlagsProperty.java index df7ec8c9d8..4ebd7a6131 100644 --- a/core/src/main/java/org/lflang/target/property/CompilerFlagsProperty.java +++ b/core/src/main/java/org/lflang/target/property/CompilerFlagsProperty.java @@ -4,7 +4,7 @@ import java.util.List; import org.lflang.Target; -public class CompilerFlagsProperty extends DefaultStringListProperty { +public class CompilerFlagsProperty extends AbstractStringListProperty { @Override public List supportedTargets() { diff --git a/core/src/main/java/org/lflang/target/property/CompilerProperty.java b/core/src/main/java/org/lflang/target/property/CompilerProperty.java index 9c35d5d260..286938df10 100644 --- a/core/src/main/java/org/lflang/target/property/CompilerProperty.java +++ b/core/src/main/java/org/lflang/target/property/CompilerProperty.java @@ -3,7 +3,7 @@ import java.util.List; import org.lflang.Target; -public class CompilerProperty extends DefaultStringConfig { +public class CompilerProperty extends AbstractStringConfig { @Override public List supportedTargets() { 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 23af1705ba..7d01e5af7d 100644 --- a/core/src/main/java/org/lflang/target/property/CoordinationOptionsProperty.java +++ b/core/src/main/java/org/lflang/target/property/CoordinationOptionsProperty.java @@ -3,10 +3,10 @@ import java.util.Arrays; import java.util.List; import java.util.Objects; +import org.lflang.AbstractTargetProperty; import org.lflang.MessageReporter; import org.lflang.Target; import org.lflang.TargetProperty.DictionaryElement; -import org.lflang.TargetPropertyConfig; import org.lflang.TimeValue; import org.lflang.ast.ASTUtils; import org.lflang.lf.Element; @@ -18,7 +18,7 @@ import org.lflang.target.property.type.PrimitiveType; import org.lflang.target.property.type.TargetPropertyType; -public class CoordinationOptionsProperty extends TargetPropertyConfig { +public class CoordinationOptionsProperty extends AbstractTargetProperty { public CoordinationOptionsProperty() { super(DictionaryType.COORDINATION_OPTION_DICT); @@ -30,9 +30,9 @@ public CoordinationOptions initialValue() { } @Override - public CoordinationOptions fromAst(Element value, MessageReporter err) { + public CoordinationOptions fromAst(Element node, MessageReporter reporter) { var options = new CoordinationOptions(); - for (KeyValuePair entry : value.getKeyvalue().getPairs()) { + for (KeyValuePair entry : node.getKeyvalue().getPairs()) { CoordinationOption option = (CoordinationOption) DictionaryType.COORDINATION_OPTION_DICT.forName(entry.getName()); if (Objects.requireNonNull(option) == CoordinationOption.ADVANCE_MESSAGE_INTERVAL) { @@ -43,7 +43,7 @@ public CoordinationOptions fromAst(Element value, MessageReporter err) { } @Override - protected CoordinationOptions fromString(String value, MessageReporter err) { + protected CoordinationOptions fromString(String string, MessageReporter reporter) { throw new UnsupportedOperationException("Not supported yet."); } @@ -60,10 +60,10 @@ public Element toAstElement() { KeyValuePair pair = LfFactory.eINSTANCE.createKeyValuePair(); pair.setName(opt.toString()); if (opt == CoordinationOption.ADVANCE_MESSAGE_INTERVAL) { - if (this.value.advanceMessageInterval == null) { + if (this.get().advanceMessageInterval == null) { continue; } - pair.setValue(ASTUtils.toElement(value.advanceMessageInterval)); + pair.setValue(ASTUtils.toElement(get().advanceMessageInterval)); } kvp.getPairs().add(pair); } diff --git a/core/src/main/java/org/lflang/target/property/CoordinationModeProperty.java b/core/src/main/java/org/lflang/target/property/CoordinationProperty.java similarity index 56% rename from core/src/main/java/org/lflang/target/property/CoordinationModeProperty.java rename to core/src/main/java/org/lflang/target/property/CoordinationProperty.java index 357ea9a818..d550fe5dc2 100644 --- a/core/src/main/java/org/lflang/target/property/CoordinationModeProperty.java +++ b/core/src/main/java/org/lflang/target/property/CoordinationProperty.java @@ -2,20 +2,17 @@ import java.util.Arrays; import java.util.List; +import org.lflang.AbstractTargetProperty; import org.lflang.MessageReporter; import org.lflang.Target; -import org.lflang.TargetConfig; -import org.lflang.TargetPropertyConfig; import org.lflang.ast.ASTUtils; import org.lflang.lf.Element; -import org.lflang.lf.KeyValuePair; -import org.lflang.lf.Model; -import org.lflang.target.property.CoordinationModeProperty.CoordinationMode; +import org.lflang.target.property.CoordinationProperty.CoordinationMode; import org.lflang.target.property.type.UnionType; -public class CoordinationModeProperty extends TargetPropertyConfig { +public class CoordinationProperty extends AbstractTargetProperty { - public CoordinationModeProperty() { + public CoordinationProperty() { super(UnionType.COORDINATION_UNION); } @@ -25,13 +22,13 @@ public CoordinationMode initialValue() { } @Override - public CoordinationMode fromAst(Element value, MessageReporter err) { - return fromString(ASTUtils.elementToSingleString(value), err); + public CoordinationMode fromAst(Element node, MessageReporter reporter) { + return fromString(ASTUtils.elementToSingleString(node), reporter); } @Override - protected CoordinationMode fromString(String value, MessageReporter err) { - return (CoordinationMode) UnionType.COORDINATION_UNION.forName(value); + protected CoordinationMode fromString(String string, MessageReporter reporter) { + return (CoordinationMode) UnionType.COORDINATION_UNION.forName(string); } @Override @@ -39,13 +36,9 @@ public List supportedTargets() { return Arrays.asList(Target.C, Target.CCPP, Target.Python); } - @Override - public void validate( - KeyValuePair pair, Model ast, TargetConfig config, MessageReporter reporter) {} - @Override public Element toAstElement() { - return ASTUtils.toElement(this.value.toString()); + return ASTUtils.toElement(this.get().toString()); } /** diff --git a/core/src/main/java/org/lflang/target/property/DefaultBooleanProperty.java b/core/src/main/java/org/lflang/target/property/DefaultBooleanProperty.java deleted file mode 100644 index 2a5b29eeb5..0000000000 --- a/core/src/main/java/org/lflang/target/property/DefaultBooleanProperty.java +++ /dev/null @@ -1,34 +0,0 @@ -package org.lflang.target.property; - -import org.lflang.MessageReporter; -import org.lflang.TargetPropertyConfig; -import org.lflang.ast.ASTUtils; -import org.lflang.lf.Element; -import org.lflang.target.property.type.PrimitiveType; - -public abstract class DefaultBooleanProperty extends TargetPropertyConfig { - - public DefaultBooleanProperty() { - super(PrimitiveType.BOOLEAN); - } - - @Override - public Boolean initialValue() { - return false; - } - - @Override - public Boolean fromAst(Element value, MessageReporter err) { - return ASTUtils.toBoolean(value); - } - - @Override - protected Boolean fromString(String value, MessageReporter err) { - return Boolean.parseBoolean(value); - } - - @Override - public Element toAstElement() { - return ASTUtils.toElement(value); - } -} diff --git a/core/src/main/java/org/lflang/target/property/DefaultStringConfig.java b/core/src/main/java/org/lflang/target/property/DefaultStringConfig.java deleted file mode 100644 index fde1825686..0000000000 --- a/core/src/main/java/org/lflang/target/property/DefaultStringConfig.java +++ /dev/null @@ -1,34 +0,0 @@ -package org.lflang.target.property; - -import org.lflang.MessageReporter; -import org.lflang.TargetPropertyConfig; -import org.lflang.ast.ASTUtils; -import org.lflang.lf.Element; -import org.lflang.target.property.type.PrimitiveType; - -public abstract class DefaultStringConfig extends TargetPropertyConfig { - - public DefaultStringConfig() { - super(PrimitiveType.STRING); - } - - @Override - public String initialValue() { - return ""; - } - - @Override - public String fromAst(Element value, MessageReporter err) { - return ASTUtils.elementToSingleString(value); - } - - @Override - protected String fromString(String value, MessageReporter err) { - return value; - } - - @Override - public Element toAstElement() { - return ASTUtils.toElement(value); - } -} diff --git a/core/src/main/java/org/lflang/target/property/DefaultStringListProperty.java b/core/src/main/java/org/lflang/target/property/DefaultStringListProperty.java deleted file mode 100644 index 549496bb7e..0000000000 --- a/core/src/main/java/org/lflang/target/property/DefaultStringListProperty.java +++ /dev/null @@ -1,55 +0,0 @@ -package org.lflang.target.property; - -import java.util.ArrayList; -import java.util.List; -import org.lflang.MessageReporter; -import org.lflang.TargetPropertyConfig; -import org.lflang.ast.ASTUtils; -import org.lflang.lf.Element; -import org.lflang.target.property.type.UnionType; - -/** Note: {@code set} implements an "append" semantics. */ -public abstract class DefaultStringListProperty extends TargetPropertyConfig> { - - public DefaultStringListProperty() { - super(UnionType.STRING_OR_STRING_ARRAY); - } - - @Override - public List initialValue() { - return new ArrayList<>(); - } - - @Override - public void set(Element value, MessageReporter err) { - if (!this.isSet) { - super.set(value, err); - } else { - this.value.addAll(this.fromAst(value, err)); - } - } - - @Override - public void set(String string, MessageReporter err) { - if (!this.isSet) { - super.set(string, err); - } else { - this.value.addAll(this.fromString(string, err)); - } - } - - @Override - public List fromAst(Element value, MessageReporter err) { - return ASTUtils.elementToListOfStrings(value); - } - - @Override - protected List fromString(String value, MessageReporter err) { - return List.of(value.split(" ")); - } - - @Override - public Element toAstElement() { - return ASTUtils.toElement(value); - } -} 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 82171a81cb..fb8b7d3920 100644 --- a/core/src/main/java/org/lflang/target/property/DockerProperty.java +++ b/core/src/main/java/org/lflang/target/property/DockerProperty.java @@ -3,10 +3,10 @@ import java.util.Arrays; import java.util.List; import java.util.Objects; +import org.lflang.AbstractTargetProperty; import org.lflang.MessageReporter; import org.lflang.Target; import org.lflang.TargetProperty.DictionaryElement; -import org.lflang.TargetPropertyConfig; import org.lflang.ast.ASTUtils; import org.lflang.lf.Element; import org.lflang.lf.KeyValuePair; @@ -18,7 +18,7 @@ import org.lflang.target.property.type.TargetPropertyType; import org.lflang.target.property.type.UnionType; -public class DockerProperty extends TargetPropertyConfig { +public class DockerProperty extends AbstractTargetProperty { public DockerProperty() { super(UnionType.DOCKER_UNION); @@ -30,14 +30,14 @@ public DockerOptions initialValue() { } @Override - public DockerOptions fromAst(Element value, MessageReporter err) { + public DockerOptions fromAst(Element node, MessageReporter reporter) { var options = new DockerOptions(false); - if (value.getLiteral() != null) { - if (ASTUtils.toBoolean(value)) { + if (node.getLiteral() != null) { + if (ASTUtils.toBoolean(node)) { options.enabled = true; } } else { - for (KeyValuePair entry : value.getKeyvalue().getPairs()) { + for (KeyValuePair entry : node.getKeyvalue().getPairs()) { options.enabled = true; DockerOption option = (DockerOption) DictionaryType.DOCKER_DICT.forName(entry.getName()); if (Objects.requireNonNull(option) == DockerOption.FROM) { @@ -49,7 +49,7 @@ public DockerOptions fromAst(Element value, MessageReporter err) { } @Override - protected DockerOptions fromString(String value, MessageReporter err) { + protected DockerOptions fromString(String string, MessageReporter reporter) { throw new UnsupportedOperationException("Not supported yet."); } @@ -60,9 +60,9 @@ public List supportedTargets() { @Override public Element toAstElement() { - if (!this.value.enabled) { + if (!this.get().enabled) { return null; - } else if (this.value.equals(new DockerOptions(true))) { + } else if (this.get().equals(new DockerOptions(true))) { // default configuration return ASTUtils.toElement(true); } else { @@ -72,10 +72,10 @@ public Element toAstElement() { KeyValuePair pair = LfFactory.eINSTANCE.createKeyValuePair(); pair.setName(opt.toString()); if (opt == DockerOption.FROM) { - if (this.value.from == null) { + if (this.get().from == null) { continue; } - pair.setValue(ASTUtils.toElement(this.value.from)); + pair.setValue(ASTUtils.toElement(this.get().from)); } kvp.getPairs().add(pair); } diff --git a/core/src/main/java/org/lflang/target/property/ExportDependencyGraphProperty.java b/core/src/main/java/org/lflang/target/property/ExportDependencyGraphProperty.java index 8e38f8881f..427f4eab17 100644 --- a/core/src/main/java/org/lflang/target/property/ExportDependencyGraphProperty.java +++ b/core/src/main/java/org/lflang/target/property/ExportDependencyGraphProperty.java @@ -3,7 +3,7 @@ import java.util.List; import org.lflang.Target; -public class ExportDependencyGraphProperty extends DefaultBooleanProperty { +public class ExportDependencyGraphProperty extends AbstractBooleanProperty { @Override public List supportedTargets() { diff --git a/core/src/main/java/org/lflang/target/property/ExportToYamlProperty.java b/core/src/main/java/org/lflang/target/property/ExportToYamlProperty.java index d67fad9788..f9349afa6d 100644 --- a/core/src/main/java/org/lflang/target/property/ExportToYamlProperty.java +++ b/core/src/main/java/org/lflang/target/property/ExportToYamlProperty.java @@ -3,7 +3,7 @@ import java.util.List; import org.lflang.Target; -public class ExportToYamlProperty extends DefaultBooleanProperty { +public class ExportToYamlProperty extends AbstractBooleanProperty { @Override public List supportedTargets() { diff --git a/core/src/main/java/org/lflang/target/property/ExternalRuntimePathProperty.java b/core/src/main/java/org/lflang/target/property/ExternalRuntimePathProperty.java index 92532597ba..fa418aa29b 100644 --- a/core/src/main/java/org/lflang/target/property/ExternalRuntimePathProperty.java +++ b/core/src/main/java/org/lflang/target/property/ExternalRuntimePathProperty.java @@ -3,7 +3,7 @@ import java.util.List; import org.lflang.Target; -public class ExternalRuntimePathProperty extends DefaultStringConfig { +public class ExternalRuntimePathProperty extends AbstractStringConfig { @Override public List supportedTargets() { 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 0f343472b3..941ae2ed04 100644 --- a/core/src/main/java/org/lflang/target/property/FastProperty.java +++ b/core/src/main/java/org/lflang/target/property/FastProperty.java @@ -3,7 +3,6 @@ import java.util.List; import org.lflang.MessageReporter; import org.lflang.Target; -import org.lflang.TargetConfig; import org.lflang.lf.Action; import org.lflang.lf.ActionOrigin; import org.lflang.lf.KeyValuePair; @@ -11,7 +10,7 @@ import org.lflang.lf.Model; import org.lflang.lf.Reactor; -public class FastProperty extends DefaultBooleanProperty { +public class FastProperty extends AbstractBooleanProperty { @Override public List supportedTargets() { @@ -19,8 +18,7 @@ public List supportedTargets() { } @Override - public void validate( - KeyValuePair pair, Model ast, TargetConfig config, MessageReporter reporter) { + public void validate(KeyValuePair pair, Model ast, MessageReporter reporter) { if (pair != null) { // Check for federated for (Reactor reactor : ast.getReactors()) { diff --git a/core/src/main/java/org/lflang/target/property/FedSetupProperty.java b/core/src/main/java/org/lflang/target/property/FedSetupProperty.java index fb7290c680..3b2c539d47 100644 --- a/core/src/main/java/org/lflang/target/property/FedSetupProperty.java +++ b/core/src/main/java/org/lflang/target/property/FedSetupProperty.java @@ -1,15 +1,15 @@ package org.lflang.target.property; import java.util.List; +import org.lflang.AbstractTargetProperty; import org.lflang.MessageReporter; import org.lflang.Target; -import org.lflang.TargetPropertyConfig; import org.lflang.ast.ASTUtils; import org.lflang.lf.Element; import org.lflang.target.property.type.PrimitiveType; import org.lflang.util.StringUtil; -public class FedSetupProperty extends TargetPropertyConfig { +public class FedSetupProperty extends AbstractTargetProperty { public FedSetupProperty() { super(PrimitiveType.FILE); @@ -21,13 +21,13 @@ public String initialValue() { } @Override - protected String fromAst(Element value, MessageReporter err) { - return StringUtil.removeQuotes(ASTUtils.elementToSingleString(value)); + protected String fromAst(Element node, MessageReporter reporter) { + return StringUtil.removeQuotes(ASTUtils.elementToSingleString(node)); } @Override - protected String fromString(String value, MessageReporter err) { - return value; + protected String fromString(String string, MessageReporter reporter) { + return string; } @Override @@ -37,6 +37,6 @@ public List supportedTargets() { @Override public Element toAstElement() { - return ASTUtils.toElement(value); + return ASTUtils.toElement(get()); } } diff --git a/core/src/main/java/org/lflang/target/property/FilesProperty.java b/core/src/main/java/org/lflang/target/property/FilesProperty.java index 8723a8441c..d7d5578431 100644 --- a/core/src/main/java/org/lflang/target/property/FilesProperty.java +++ b/core/src/main/java/org/lflang/target/property/FilesProperty.java @@ -3,7 +3,7 @@ import java.util.List; import org.lflang.Target; -public class FilesProperty extends DefaultFileListProperty { +public class FilesProperty extends AbstractFileListProperty { @Override public List supportedTargets() { diff --git a/core/src/main/java/org/lflang/target/property/KeepaliveProperty.java b/core/src/main/java/org/lflang/target/property/KeepaliveProperty.java index 8490b74d2f..3c85a9c478 100644 --- a/core/src/main/java/org/lflang/target/property/KeepaliveProperty.java +++ b/core/src/main/java/org/lflang/target/property/KeepaliveProperty.java @@ -3,12 +3,12 @@ import java.util.List; import org.lflang.MessageReporter; import org.lflang.Target; -import org.lflang.TargetConfig; +import org.lflang.ast.ASTUtils; import org.lflang.lf.KeyValuePair; import org.lflang.lf.LfPackage.Literals; import org.lflang.lf.Model; -public class KeepaliveProperty extends DefaultBooleanProperty { +public class KeepaliveProperty extends AbstractBooleanProperty { @Override public List supportedTargets() { @@ -16,10 +16,8 @@ public List supportedTargets() { } @Override - public void validate( - KeyValuePair pair, Model ast, TargetConfig config, MessageReporter reporter) { - super.validate(pair, ast, config, reporter); - if (pair != null && config.target == Target.CPP) { + public void validate(KeyValuePair pair, Model ast, MessageReporter reporter) { + if (pair != null && ASTUtils.getTarget(ast) == Target.CPP) { reporter .at(pair, Literals.KEY_VALUE_PAIR__NAME) .warning( diff --git a/core/src/main/java/org/lflang/target/property/LoggingProperty.java b/core/src/main/java/org/lflang/target/property/LoggingProperty.java index 7930adce4d..9c59b03f4d 100644 --- a/core/src/main/java/org/lflang/target/property/LoggingProperty.java +++ b/core/src/main/java/org/lflang/target/property/LoggingProperty.java @@ -1,15 +1,15 @@ package org.lflang.target.property; import java.util.List; +import org.lflang.AbstractTargetProperty; import org.lflang.MessageReporter; import org.lflang.Target; -import org.lflang.TargetPropertyConfig; import org.lflang.ast.ASTUtils; import org.lflang.lf.Element; import org.lflang.target.property.LoggingProperty.LogLevel; import org.lflang.target.property.type.UnionType; -public class LoggingProperty extends TargetPropertyConfig { +public class LoggingProperty extends AbstractTargetProperty { public LoggingProperty() { super(UnionType.LOGGING_UNION); @@ -21,11 +21,11 @@ public LogLevel initialValue() { } @Override - protected LogLevel fromAst(Element value, MessageReporter err) { - return fromString(ASTUtils.elementToSingleString(value), err); + protected LogLevel fromAst(Element node, MessageReporter reporter) { + return fromString(ASTUtils.elementToSingleString(node), reporter); } - protected LogLevel fromString(String string, MessageReporter err) { + protected LogLevel fromString(String string, MessageReporter reporter) { return LogLevel.valueOf(string.toUpperCase()); } @@ -36,7 +36,7 @@ public List supportedTargets() { @Override public Element toAstElement() { - return ASTUtils.toElement(value.toString()); + return ASTUtils.toElement(get().toString()); } /** diff --git a/core/src/main/java/org/lflang/target/property/NoCompileProperty.java b/core/src/main/java/org/lflang/target/property/NoCompileProperty.java index 555cbfaa3e..fa8c949d6f 100644 --- a/core/src/main/java/org/lflang/target/property/NoCompileProperty.java +++ b/core/src/main/java/org/lflang/target/property/NoCompileProperty.java @@ -4,7 +4,7 @@ import java.util.List; import org.lflang.Target; -public class NoCompileProperty extends DefaultBooleanProperty { +public class NoCompileProperty extends AbstractBooleanProperty { @Override public List supportedTargets() { diff --git a/core/src/main/java/org/lflang/target/property/NoRuntimeValidationProperty.java b/core/src/main/java/org/lflang/target/property/NoRuntimeValidationProperty.java index d183484195..dd0e91613c 100644 --- a/core/src/main/java/org/lflang/target/property/NoRuntimeValidationProperty.java +++ b/core/src/main/java/org/lflang/target/property/NoRuntimeValidationProperty.java @@ -3,7 +3,7 @@ import java.util.List; import org.lflang.Target; -public class NoRuntimeValidationProperty extends DefaultBooleanProperty { +public class NoRuntimeValidationProperty extends AbstractBooleanProperty { @Override public List supportedTargets() { 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 efd7887127..78ac245a61 100644 --- a/core/src/main/java/org/lflang/target/property/PlatformProperty.java +++ b/core/src/main/java/org/lflang/target/property/PlatformProperty.java @@ -2,12 +2,11 @@ import java.util.Arrays; import java.util.List; +import org.lflang.AbstractTargetProperty; import org.lflang.MessageReporter; import org.lflang.Target; -import org.lflang.TargetConfig; import org.lflang.TargetProperty; import org.lflang.TargetProperty.DictionaryElement; -import org.lflang.TargetPropertyConfig; import org.lflang.ast.ASTUtils; import org.lflang.lf.Element; import org.lflang.lf.KeyValuePair; @@ -21,7 +20,7 @@ import org.lflang.target.property.type.TargetPropertyType; import org.lflang.target.property.type.UnionType; -public class PlatformProperty extends TargetPropertyConfig { +public class PlatformProperty extends AbstractTargetProperty { public PlatformProperty() { super(UnionType.PLATFORM_STRING_OR_DICTIONARY); @@ -33,11 +32,11 @@ public PlatformOptions initialValue() { } @Override - public PlatformOptions fromAst(Element value, MessageReporter err) { + public PlatformOptions fromAst(Element node, MessageReporter reporter) { var config = new PlatformOptions(); - if (value.getLiteral() != null) { + if (node.getLiteral() != null) { config.platform = - (Platform) UnionType.PLATFORM_UNION.forName(ASTUtils.elementToSingleString(value)); + (Platform) UnionType.PLATFORM_UNION.forName(ASTUtils.elementToSingleString(node)); if (config.platform == null) { String s = "Unidentified Platform Type, LF supports the following platform types: " @@ -46,7 +45,7 @@ public PlatformOptions fromAst(Element value, MessageReporter err) { throw new AssertionError(s); } } else { - for (KeyValuePair entry : value.getKeyvalue().getPairs()) { + for (KeyValuePair entry : node.getKeyvalue().getPairs()) { PlatformOption option = (PlatformOption) DictionaryType.PLATFORM_DICT.forName(entry.getName()); switch (option) { @@ -59,7 +58,7 @@ public PlatformOptions fromAst(Element value, MessageReporter err) { String s = "Unidentified Platform Type, LF supports the following platform types: " + Arrays.asList(Platform.values()); - err.at(entry).error(s); + reporter.at(entry).error(s); throw new AssertionError(s); } config.platform = p; @@ -78,7 +77,7 @@ public PlatformOptions fromAst(Element value, MessageReporter err) { } @Override - protected PlatformOptions fromString(String value, MessageReporter err) { + protected PlatformOptions fromString(String string, MessageReporter reporter) { throw new UnsupportedOperationException("Not supported yet."); } @@ -88,10 +87,7 @@ public List supportedTargets() { } @Override - public void validate( - KeyValuePair pair, Model ast, TargetConfig config, MessageReporter reporter) { - super.validate(pair, ast, config, reporter); - + public void validate(KeyValuePair pair, Model ast, MessageReporter reporter) { var threading = TargetProperty.getKeyValuePair(ast, TargetProperty.THREADING); if (threading != null) { if (pair != null && ASTUtils.toBoolean(threading.getValue())) { @@ -129,12 +125,12 @@ public Element toAstElement() { KeyValuePair pair = LfFactory.eINSTANCE.createKeyValuePair(); pair.setName(opt.toString()); switch (opt) { - case NAME -> pair.setValue(ASTUtils.toElement(value.platform.toString())); - case BAUDRATE -> pair.setValue(ASTUtils.toElement(value.baudRate)); - case BOARD -> pair.setValue(ASTUtils.toElement(value.board)); - case FLASH -> pair.setValue(ASTUtils.toElement(value.flash)); - case PORT -> pair.setValue(ASTUtils.toElement(value.port)); - case USER_THREADS -> pair.setValue(ASTUtils.toElement(value.userThreads)); + case NAME -> pair.setValue(ASTUtils.toElement(get().platform.toString())); + case BAUDRATE -> pair.setValue(ASTUtils.toElement(get().baudRate)); + case BOARD -> pair.setValue(ASTUtils.toElement(get().board)); + case FLASH -> pair.setValue(ASTUtils.toElement(get().flash)); + case PORT -> pair.setValue(ASTUtils.toElement(get().port)); + case USER_THREADS -> pair.setValue(ASTUtils.toElement(get().userThreads)); } kvp.getPairs().add(pair); } diff --git a/core/src/main/java/org/lflang/target/property/PrintStatisticsProperty.java b/core/src/main/java/org/lflang/target/property/PrintStatisticsProperty.java index 7cd00e165a..c100f3fc2c 100644 --- a/core/src/main/java/org/lflang/target/property/PrintStatisticsProperty.java +++ b/core/src/main/java/org/lflang/target/property/PrintStatisticsProperty.java @@ -3,7 +3,7 @@ import java.util.List; import org.lflang.Target; -public class PrintStatisticsProperty extends DefaultBooleanProperty { +public class PrintStatisticsProperty extends AbstractBooleanProperty { @Override public List supportedTargets() { diff --git a/core/src/main/java/org/lflang/target/property/ProtobufsProperty.java b/core/src/main/java/org/lflang/target/property/ProtobufsProperty.java index 00bcc10772..d8e0541bff 100644 --- a/core/src/main/java/org/lflang/target/property/ProtobufsProperty.java +++ b/core/src/main/java/org/lflang/target/property/ProtobufsProperty.java @@ -3,7 +3,7 @@ import java.util.List; import org.lflang.Target; -public class ProtobufsProperty extends DefaultFileListProperty { +public class ProtobufsProperty extends AbstractFileListProperty { @Override public List supportedTargets() { 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 58deea240d..4545b64c5c 100644 --- a/core/src/main/java/org/lflang/target/property/Ros2DependenciesProperty.java +++ b/core/src/main/java/org/lflang/target/property/Ros2DependenciesProperty.java @@ -2,11 +2,10 @@ import java.util.ArrayList; import java.util.List; +import org.lflang.AbstractTargetProperty; import org.lflang.MessageReporter; import org.lflang.Target; -import org.lflang.TargetConfig; import org.lflang.TargetProperty; -import org.lflang.TargetPropertyConfig; import org.lflang.ast.ASTUtils; import org.lflang.lf.Element; import org.lflang.lf.KeyValuePair; @@ -14,7 +13,7 @@ import org.lflang.lf.Model; import org.lflang.target.property.type.ArrayType; -public class Ros2DependenciesProperty extends TargetPropertyConfig> { +public class Ros2DependenciesProperty extends AbstractTargetProperty> { public Ros2DependenciesProperty() { super(ArrayType.STRING_ARRAY); @@ -26,12 +25,12 @@ public List initialValue() { } @Override - public List fromAst(Element value, MessageReporter err) { - return ASTUtils.elementToListOfStrings(value); + public List fromAst(Element node, MessageReporter reporter) { + return ASTUtils.elementToListOfStrings(node); } @Override - protected List fromString(String value, MessageReporter err) { + protected List fromString(String string, MessageReporter reporter) { throw new UnsupportedOperationException("Not supported yet."); } @@ -41,9 +40,7 @@ public List supportedTargets() { } @Override - public void validate( - KeyValuePair pair, Model ast, TargetConfig config, MessageReporter reporter) { - super.validate(pair, ast, config, reporter); + public void validate(KeyValuePair pair, Model ast, MessageReporter reporter) { var ros2enabled = TargetProperty.getKeyValuePair(ast, TargetProperty.ROS2); if (pair != null && (ros2enabled == null || !ASTUtils.toBoolean(ros2enabled.getValue()))) { reporter @@ -54,6 +51,6 @@ public void validate( @Override public Element toAstElement() { - return ASTUtils.toElement(value); + return ASTUtils.toElement(get()); } } diff --git a/core/src/main/java/org/lflang/target/property/Ros2Property.java b/core/src/main/java/org/lflang/target/property/Ros2Property.java index 1a5bf9728d..b768f67d5d 100644 --- a/core/src/main/java/org/lflang/target/property/Ros2Property.java +++ b/core/src/main/java/org/lflang/target/property/Ros2Property.java @@ -3,7 +3,7 @@ import java.util.List; import org.lflang.Target; -public class Ros2Property extends DefaultBooleanProperty { +public class Ros2Property extends AbstractBooleanProperty { @Override public List supportedTargets() { diff --git a/core/src/main/java/org/lflang/target/property/RuntimeVersionProperty.java b/core/src/main/java/org/lflang/target/property/RuntimeVersionProperty.java index 27bbffb737..c46a5db83e 100644 --- a/core/src/main/java/org/lflang/target/property/RuntimeVersionProperty.java +++ b/core/src/main/java/org/lflang/target/property/RuntimeVersionProperty.java @@ -3,7 +3,7 @@ import java.util.List; import org.lflang.Target; -public class RuntimeVersionProperty extends DefaultStringConfig { +public class RuntimeVersionProperty extends AbstractStringConfig { @Override public List supportedTargets() { diff --git a/core/src/main/java/org/lflang/target/property/RustIncludeProperty.java b/core/src/main/java/org/lflang/target/property/RustIncludeProperty.java index 853ff81ac8..c448cba296 100644 --- a/core/src/main/java/org/lflang/target/property/RustIncludeProperty.java +++ b/core/src/main/java/org/lflang/target/property/RustIncludeProperty.java @@ -5,9 +5,9 @@ import java.util.ArrayList; import java.util.List; import org.eclipse.emf.ecore.EObject; +import org.lflang.AbstractTargetProperty; import org.lflang.MessageReporter; import org.lflang.Target; -import org.lflang.TargetPropertyConfig; import org.lflang.ast.ASTUtils; import org.lflang.lf.Array; import org.lflang.lf.Element; @@ -16,7 +16,7 @@ import org.lflang.util.FileUtil; import org.lflang.util.StringUtil; -public class RustIncludeProperty extends TargetPropertyConfig> { +public class RustIncludeProperty extends AbstractTargetProperty> { public RustIncludeProperty() { super(UnionType.FILE_OR_FILE_ARRAY); @@ -33,29 +33,29 @@ public List initialValue() { } @Override - public List fromAst(Element value, MessageReporter err) { + public List fromAst(Element node, MessageReporter reporter) { var list = new ArrayList(); Path referencePath; try { - referencePath = FileUtil.toPath(value.eResource().getURI()).toAbsolutePath(); + referencePath = FileUtil.toPath(node.eResource().getURI()).toAbsolutePath(); } catch (IllegalArgumentException e) { - err.at(value).error("Invalid path? " + e.getMessage()); + reporter.at(node).error("Invalid path? " + e.getMessage()); throw e; } // we'll resolve relative paths to check that the files // are as expected. - if (value.getLiteral() != null) { - Path resolved = referencePath.resolveSibling(StringUtil.removeQuotes(value.getLiteral())); - if (this.checkTopLevelModule(resolved, value, err)) { + if (node.getLiteral() != null) { + Path resolved = referencePath.resolveSibling(StringUtil.removeQuotes(node.getLiteral())); + if (this.checkTopLevelModule(resolved, node, reporter)) { list.add(resolved); } - } else if (value.getArray() != null) { - for (Element element : value.getArray().getElements()) { + } else if (node.getArray() != null) { + for (Element element : node.getArray().getElements()) { String literal = StringUtil.removeQuotes(element.getLiteral()); Path resolved = referencePath.resolveSibling(literal); - if (this.checkTopLevelModule(resolved, value, err)) { + if (this.checkTopLevelModule(resolved, node, reporter)) { list.add(resolved); } } @@ -64,14 +64,14 @@ public List fromAst(Element value, MessageReporter err) { } @Override - protected List fromString(String value, MessageReporter err) { + protected List fromString(String string, MessageReporter reporter) { throw new UnsupportedOperationException("Not supported yet."); } @Override public Element toAstElement() { // do not check paths here, and simply copy the absolute path over - List paths = this.value; + List paths = this.get(); if (paths.isEmpty()) { return null; } else if (paths.size() == 1) { 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 f2747456c2..55b574e4b0 100644 --- a/core/src/main/java/org/lflang/target/property/SchedulerProperty.java +++ b/core/src/main/java/org/lflang/target/property/SchedulerProperty.java @@ -4,10 +4,9 @@ import java.nio.file.Path; import java.util.Arrays; import java.util.List; +import org.lflang.AbstractTargetProperty; import org.lflang.MessageReporter; import org.lflang.Target; -import org.lflang.TargetConfig; -import org.lflang.TargetPropertyConfig; import org.lflang.ast.ASTUtils; import org.lflang.lf.Element; import org.lflang.lf.KeyValuePair; @@ -16,7 +15,7 @@ import org.lflang.target.property.SchedulerProperty.SchedulerOption; import org.lflang.target.property.type.UnionType; -public class SchedulerProperty extends TargetPropertyConfig { +public class SchedulerProperty extends AbstractTargetProperty { public SchedulerProperty() { super(UnionType.SCHEDULER_UNION); @@ -28,8 +27,8 @@ public SchedulerOption initialValue() { } @Override - public SchedulerOption fromAst(Element value, MessageReporter err) { - var scheduler = fromString(ASTUtils.elementToSingleString(value), err); + public SchedulerOption fromAst(Element node, MessageReporter reporter) { + var scheduler = fromString(ASTUtils.elementToSingleString(node), reporter); if (scheduler != null) { return scheduler; } else { @@ -38,8 +37,8 @@ public SchedulerOption fromAst(Element value, MessageReporter err) { } @Override - protected SchedulerOption fromString(String value, MessageReporter err) { - return (SchedulerOption) UnionType.SCHEDULER_UNION.forName(value); + protected SchedulerOption fromString(String string, MessageReporter reporter) { + return (SchedulerOption) UnionType.SCHEDULER_UNION.forName(string); } @Override @@ -49,13 +48,11 @@ public List supportedTargets() { @Override public Element toAstElement() { - return ASTUtils.toElement(this.value.toString()); + return ASTUtils.toElement(this.get().toString()); } @Override - public void validate( - KeyValuePair pair, Model ast, TargetConfig config, MessageReporter reporter) { - super.validate(pair, ast, config, reporter); + public void validate(KeyValuePair pair, Model ast, MessageReporter reporter) { if (pair != null) { String schedulerName = ASTUtils.elementToSingleString(pair.getValue()); try { diff --git a/core/src/main/java/org/lflang/target/property/SingleFileProjectProperty.java b/core/src/main/java/org/lflang/target/property/SingleFileProjectProperty.java index 3e68141ab4..651526a642 100644 --- a/core/src/main/java/org/lflang/target/property/SingleFileProjectProperty.java +++ b/core/src/main/java/org/lflang/target/property/SingleFileProjectProperty.java @@ -3,7 +3,7 @@ import java.util.List; import org.lflang.Target; -public class SingleFileProjectProperty extends DefaultBooleanProperty { +public class SingleFileProjectProperty extends AbstractBooleanProperty { @Override public List supportedTargets() { diff --git a/core/src/main/java/org/lflang/target/property/ThreadingProperty.java b/core/src/main/java/org/lflang/target/property/ThreadingProperty.java index 7f596160df..483eb26603 100644 --- a/core/src/main/java/org/lflang/target/property/ThreadingProperty.java +++ b/core/src/main/java/org/lflang/target/property/ThreadingProperty.java @@ -3,7 +3,7 @@ import java.util.List; import org.lflang.Target; -public class ThreadingProperty extends DefaultBooleanProperty { +public class ThreadingProperty extends AbstractBooleanProperty { @Override public List supportedTargets() { diff --git a/core/src/main/java/org/lflang/target/property/TimeOutProperty.java b/core/src/main/java/org/lflang/target/property/TimeOutProperty.java index 55c591f8a0..d5bd2310bf 100644 --- a/core/src/main/java/org/lflang/target/property/TimeOutProperty.java +++ b/core/src/main/java/org/lflang/target/property/TimeOutProperty.java @@ -1,15 +1,15 @@ package org.lflang.target.property; import java.util.List; +import org.lflang.AbstractTargetProperty; import org.lflang.MessageReporter; import org.lflang.Target; -import org.lflang.TargetPropertyConfig; import org.lflang.TimeValue; import org.lflang.ast.ASTUtils; import org.lflang.lf.Element; import org.lflang.target.property.type.PrimitiveType; -public class TimeOutProperty extends TargetPropertyConfig { +public class TimeOutProperty extends AbstractTargetProperty { public TimeOutProperty() { super(PrimitiveType.TIME_VALUE); @@ -21,12 +21,12 @@ public TimeValue initialValue() { } @Override - public TimeValue fromAst(Element value, MessageReporter err) { - return ASTUtils.toTimeValue(value); + public TimeValue fromAst(Element node, MessageReporter reporter) { + return ASTUtils.toTimeValue(node); } @Override - protected TimeValue fromString(String value, MessageReporter err) { + protected TimeValue fromString(String string, MessageReporter reporter) { throw new UnsupportedOperationException("Not supported yet."); } @@ -37,6 +37,6 @@ public List supportedTargets() { @Override public Element toAstElement() { - return ASTUtils.toElement(value); + return ASTUtils.toElement(get()); } } 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 4bb9c54d40..1505d14a59 100644 --- a/core/src/main/java/org/lflang/target/property/TracingProperty.java +++ b/core/src/main/java/org/lflang/target/property/TracingProperty.java @@ -2,12 +2,11 @@ import java.util.List; import java.util.Objects; +import org.lflang.AbstractTargetProperty; import org.lflang.MessageReporter; import org.lflang.Target; -import org.lflang.TargetConfig; import org.lflang.TargetProperty; import org.lflang.TargetProperty.DictionaryElement; -import org.lflang.TargetPropertyConfig; import org.lflang.ast.ASTUtils; import org.lflang.lf.Element; import org.lflang.lf.KeyValuePair; @@ -21,7 +20,7 @@ import org.lflang.target.property.type.TargetPropertyType; import org.lflang.target.property.type.UnionType; -public class TracingProperty extends TargetPropertyConfig { +public class TracingProperty extends AbstractTargetProperty { public TracingProperty() { super(UnionType.TRACING_UNION); @@ -33,14 +32,14 @@ public TracingOptions initialValue() { } @Override - public TracingOptions fromAst(Element value, MessageReporter err) { + public TracingOptions fromAst(Element node, MessageReporter reporter) { var options = new TracingOptions(false); - if (value.getLiteral() != null) { - if (ASTUtils.toBoolean(value)) { + if (node.getLiteral() != null) { + if (ASTUtils.toBoolean(node)) { options.enabled = true; } } else { - for (KeyValuePair entry : value.getKeyvalue().getPairs()) { + for (KeyValuePair entry : node.getKeyvalue().getPairs()) { TracingOption option = (TracingOption) DictionaryType.TRACING_DICT.forName(entry.getName()); switch (option) { case TRACE_FILE_NAME: @@ -55,7 +54,7 @@ public TracingOptions fromAst(Element value, MessageReporter err) { } @Override - protected TracingOptions fromString(String value, MessageReporter err) { + protected TracingOptions fromString(String string, MessageReporter reporter) { throw new UnsupportedOperationException("Not supported yet."); } @@ -65,8 +64,7 @@ public List supportedTargets() { } @Override - public void validate( - KeyValuePair pair, Model ast, TargetConfig config, 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, TargetProperty.THREADING); @@ -85,9 +83,9 @@ public void validate( @Override public Element toAstElement() { - if (!this.value.isEnabled()) { + if (!this.get().isEnabled()) { return null; - } else if (this.value.equals(new TracingOptions(true))) { + } else if (this.get().equals(new TracingOptions(true))) { // default values return ASTUtils.toElement(true); } else { @@ -98,10 +96,10 @@ public Element toAstElement() { pair.setName(opt.toString()); switch (opt) { case TRACE_FILE_NAME: - if (this.value.traceFileName == null) { + if (this.get().traceFileName == null) { continue; } - pair.setValue(ASTUtils.toElement(this.value.traceFileName)); + pair.setValue(ASTUtils.toElement(this.get().traceFileName)); } kvp.getPairs().add(pair); } diff --git a/core/src/main/java/org/lflang/target/property/VerifyProperty.java b/core/src/main/java/org/lflang/target/property/VerifyProperty.java index 62116fc851..1065e4e147 100644 --- a/core/src/main/java/org/lflang/target/property/VerifyProperty.java +++ b/core/src/main/java/org/lflang/target/property/VerifyProperty.java @@ -2,9 +2,9 @@ import java.util.List; import org.lflang.Target; -import org.lflang.target.property.DefaultBooleanProperty; +import org.lflang.target.property.AbstractBooleanProperty; -public class VerifyProperty extends DefaultBooleanProperty { +public class VerifyProperty extends AbstractBooleanProperty { @Override public List supportedTargets() { 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 1ea091e567..823c6d8369 100644 --- a/core/src/main/java/org/lflang/target/property/WorkersProperty.java +++ b/core/src/main/java/org/lflang/target/property/WorkersProperty.java @@ -1,14 +1,14 @@ package org.lflang.target.property; import java.util.List; +import org.lflang.AbstractTargetProperty; import org.lflang.MessageReporter; import org.lflang.Target; -import org.lflang.TargetPropertyConfig; import org.lflang.ast.ASTUtils; import org.lflang.lf.Element; import org.lflang.target.property.type.PrimitiveType; -public class WorkersProperty extends TargetPropertyConfig { +public class WorkersProperty extends AbstractTargetProperty { public WorkersProperty() { super(PrimitiveType.NON_NEGATIVE_INTEGER); @@ -20,13 +20,13 @@ public Integer initialValue() { } @Override - protected Integer fromString(String value, MessageReporter err) { - return Integer.parseInt(value); // FIXME: check for exception + protected Integer fromString(String string, MessageReporter reporter) { + return Integer.parseInt(string); // FIXME: check for exception } @Override - protected Integer fromAst(Element value, MessageReporter err) { - return ASTUtils.toInteger(value); + protected Integer fromAst(Element node, MessageReporter reporter) { + return ASTUtils.toInteger(node); } @Override @@ -36,6 +36,6 @@ public List supportedTargets() { @Override public Element toAstElement() { - return ASTUtils.toElement(value); + return ASTUtils.toElement(get()); } } diff --git a/core/src/main/java/org/lflang/target/property/type/UnionType.java b/core/src/main/java/org/lflang/target/property/type/UnionType.java index 8b51f972c9..b044455115 100644 --- a/core/src/main/java/org/lflang/target/property/type/UnionType.java +++ b/core/src/main/java/org/lflang/target/property/type/UnionType.java @@ -10,7 +10,7 @@ import org.lflang.lf.Element; import org.lflang.target.property.BuildTypeProperty; import org.lflang.target.property.ClockSyncModeProperty.ClockSyncMode; -import org.lflang.target.property.CoordinationModeProperty.CoordinationMode; +import org.lflang.target.property.CoordinationProperty.CoordinationMode; import org.lflang.target.property.LoggingProperty.LogLevel; import org.lflang.target.property.PlatformProperty.Platform; import org.lflang.target.property.SchedulerProperty.SchedulerOption; From 8703527b331d0f839d9c5b56d33ec88c17ddf616 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Sat, 30 Sep 2023 22:42:54 -0700 Subject: [PATCH 031/145] Address FIXME --- core/src/main/java/org/lflang/AbstractTargetProperty.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/org/lflang/AbstractTargetProperty.java b/core/src/main/java/org/lflang/AbstractTargetProperty.java index bb39cd3943..c36e147a32 100644 --- a/core/src/main/java/org/lflang/AbstractTargetProperty.java +++ b/core/src/main/java/org/lflang/AbstractTargetProperty.java @@ -137,7 +137,7 @@ public void set(String value, MessageReporter err) { @Override public String toString() { - return value == null ? null : value.toString(); // FIXME: do not return null + return value == null ? "" : value.toString(); } /** From 21ce2e4bc0d4f6ebc5c98c43ed0a6fdfe63dafec Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Sat, 30 Sep 2023 22:45:24 -0700 Subject: [PATCH 032/145] Add comment --- core/src/main/java/org/lflang/AbstractTargetProperty.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/core/src/main/java/org/lflang/AbstractTargetProperty.java b/core/src/main/java/org/lflang/AbstractTargetProperty.java index c36e147a32..49a603e443 100644 --- a/core/src/main/java/org/lflang/AbstractTargetProperty.java +++ b/core/src/main/java/org/lflang/AbstractTargetProperty.java @@ -180,6 +180,9 @@ public T get() { */ protected abstract T fromString(String string, MessageReporter reporter); + /** + * Return a list of targets that support this target property. + */ public abstract List supportedTargets(); /** From c1b2ff71917d1e54d9c6eeca8f4fe5824b09e1aa Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Sat, 30 Sep 2023 22:47:48 -0700 Subject: [PATCH 033/145] Move TargetConfig class --- .../java/org/lflang/tests/runtime/PythonTest.java | 2 +- .../org/lflang/tests/serialization/SerializationTest.java | 2 +- core/src/main/java/org/lflang/TargetProperty.java | 1 + core/src/main/java/org/lflang/ast/ASTUtils.java | 2 +- .../java/org/lflang/federated/generator/FedGenerator.java | 2 +- .../org/lflang/federated/generator/FedTargetConfig.java | 2 +- .../org/lflang/federated/generator/FederateInstance.java | 2 +- .../org/lflang/federated/launcher/FedLauncherGenerator.java | 2 +- core/src/main/java/org/lflang/generator/GeneratorBase.java | 2 +- core/src/main/java/org/lflang/generator/GeneratorUtils.java | 2 +- .../main/java/org/lflang/generator/LFGeneratorContext.java | 2 +- core/src/main/java/org/lflang/generator/LFResource.java | 2 +- core/src/main/java/org/lflang/generator/MainContext.java | 2 +- core/src/main/java/org/lflang/generator/SubContext.java | 2 +- .../main/java/org/lflang/generator/c/CCmakeGenerator.java | 2 +- core/src/main/java/org/lflang/generator/c/CCompiler.java | 2 +- .../lflang/generator/c/CEnvironmentFunctionGenerator.java | 2 +- core/src/main/java/org/lflang/generator/c/CGenerator.java | 2 +- .../java/org/lflang/generator/c/CMainFunctionGenerator.java | 2 +- .../java/org/lflang/generator/c/CPreambleGenerator.java | 2 +- .../java/org/lflang/generator/c/CReactionGenerator.java | 2 +- .../org/lflang/generator/c/CTriggerObjectsGenerator.java | 2 +- core/src/main/java/org/lflang/generator/c/CUtil.java | 2 +- .../lflang/generator/python/PythonPreambleGenerator.java | 2 +- .../java/org/lflang/generator/rust/RustTargetConfig.java | 3 ++- .../src/main/java/org/lflang/{ => target}/TargetConfig.java | 6 +++++- core/src/main/java/org/lflang/util/ArduinoUtil.java | 2 +- core/src/main/java/org/lflang/validation/LFValidator.java | 2 +- .../kotlin/org/lflang/generator/cpp/CppPlatformGenerator.kt | 2 +- .../kotlin/org/lflang/generator/cpp/CppRos2NodeGenerator.kt | 2 +- .../org/lflang/generator/cpp/CppStandaloneCmakeGenerator.kt | 2 +- .../org/lflang/generator/cpp/CppStandaloneMainGenerator.kt | 2 +- .../main/kotlin/org/lflang/generator/rust/RustFileConfig.kt | 1 - core/src/main/kotlin/org/lflang/generator/rust/RustModel.kt | 1 + .../org/lflang/generator/ts/TSConstructorGenerator.kt | 2 +- .../org/lflang/generator/ts/TSParameterPreambleGenerator.kt | 2 +- .../kotlin/org/lflang/generator/ts/TSReactorGenerator.kt | 1 + core/src/testFixtures/java/org/lflang/tests/TestBase.java | 2 +- 38 files changed, 42 insertions(+), 35 deletions(-) rename core/src/main/java/org/lflang/{ => target}/TargetConfig.java (98%) diff --git a/core/src/integrationTest/java/org/lflang/tests/runtime/PythonTest.java b/core/src/integrationTest/java/org/lflang/tests/runtime/PythonTest.java index 5b72c406d9..c227018d16 100644 --- a/core/src/integrationTest/java/org/lflang/tests/runtime/PythonTest.java +++ b/core/src/integrationTest/java/org/lflang/tests/runtime/PythonTest.java @@ -29,7 +29,7 @@ import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.lflang.Target; -import org.lflang.TargetConfig; +import org.lflang.target.TargetConfig; import org.lflang.tests.RuntimeTest; /** diff --git a/core/src/integrationTest/java/org/lflang/tests/serialization/SerializationTest.java b/core/src/integrationTest/java/org/lflang/tests/serialization/SerializationTest.java index 8f92c63437..d72495e540 100644 --- a/core/src/integrationTest/java/org/lflang/tests/serialization/SerializationTest.java +++ b/core/src/integrationTest/java/org/lflang/tests/serialization/SerializationTest.java @@ -4,7 +4,7 @@ import org.junit.jupiter.api.Assumptions; import org.junit.jupiter.api.Test; import org.lflang.Target; -import org.lflang.TargetConfig; +import org.lflang.target.TargetConfig; import org.lflang.tests.Configurators; import org.lflang.tests.TestBase; import org.lflang.tests.TestRegistry.TestCategory; diff --git a/core/src/main/java/org/lflang/TargetProperty.java b/core/src/main/java/org/lflang/TargetProperty.java index 81b22ff7ba..96b93073cb 100644 --- a/core/src/main/java/org/lflang/TargetProperty.java +++ b/core/src/main/java/org/lflang/TargetProperty.java @@ -40,6 +40,7 @@ import org.lflang.lf.LfPackage.Literals; import org.lflang.lf.Model; import org.lflang.lf.TargetDecl; +import org.lflang.target.TargetConfig; import org.lflang.target.property.AuthProperty; import org.lflang.target.property.BuildCommandsProperty; import org.lflang.target.property.BuildTypeProperty; diff --git a/core/src/main/java/org/lflang/ast/ASTUtils.java b/core/src/main/java/org/lflang/ast/ASTUtils.java index fc054e5018..694cddfb00 100644 --- a/core/src/main/java/org/lflang/ast/ASTUtils.java +++ b/core/src/main/java/org/lflang/ast/ASTUtils.java @@ -61,7 +61,7 @@ import org.lflang.InferredType; import org.lflang.MessageReporter; import org.lflang.Target; -import org.lflang.TargetConfig; +import org.lflang.target.TargetConfig; import org.lflang.TimeUnit; import org.lflang.TimeValue; import org.lflang.generator.CodeMap; 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 af3f383e2c..ad7b4f7137 100644 --- a/core/src/main/java/org/lflang/federated/generator/FedGenerator.java +++ b/core/src/main/java/org/lflang/federated/generator/FedGenerator.java @@ -31,7 +31,7 @@ import org.lflang.LFStandaloneSetup; import org.lflang.MessageReporter; import org.lflang.Target; -import org.lflang.TargetConfig; +import org.lflang.target.TargetConfig; import org.lflang.ast.ASTUtils; import org.lflang.federated.launcher.FedLauncherGenerator; import org.lflang.federated.launcher.RtiConfig; diff --git a/core/src/main/java/org/lflang/federated/generator/FedTargetConfig.java b/core/src/main/java/org/lflang/federated/generator/FedTargetConfig.java index 852cb762e1..74e3893b02 100644 --- a/core/src/main/java/org/lflang/federated/generator/FedTargetConfig.java +++ b/core/src/main/java/org/lflang/federated/generator/FedTargetConfig.java @@ -5,7 +5,7 @@ import java.nio.file.Path; import org.eclipse.emf.ecore.resource.Resource; import org.lflang.MessageReporter; -import org.lflang.TargetConfig; +import org.lflang.target.TargetConfig; import org.lflang.TargetProperty; import org.lflang.generator.GeneratorUtils; import org.lflang.generator.LFGeneratorContext; diff --git a/core/src/main/java/org/lflang/federated/generator/FederateInstance.java b/core/src/main/java/org/lflang/federated/generator/FederateInstance.java index 1b3f9f5669..9602f98047 100644 --- a/core/src/main/java/org/lflang/federated/generator/FederateInstance.java +++ b/core/src/main/java/org/lflang/federated/generator/FederateInstance.java @@ -37,7 +37,7 @@ import java.util.stream.Collectors; import java.util.stream.Stream; import org.lflang.MessageReporter; -import org.lflang.TargetConfig; +import org.lflang.target.TargetConfig; import org.lflang.TimeValue; import org.lflang.ast.ASTUtils; import org.lflang.federated.serialization.SupportedSerializers; diff --git a/core/src/main/java/org/lflang/federated/launcher/FedLauncherGenerator.java b/core/src/main/java/org/lflang/federated/launcher/FedLauncherGenerator.java index 61d3deef77..d9a7417964 100644 --- a/core/src/main/java/org/lflang/federated/launcher/FedLauncherGenerator.java +++ b/core/src/main/java/org/lflang/federated/launcher/FedLauncherGenerator.java @@ -34,7 +34,7 @@ import java.util.ArrayList; import java.util.List; import org.lflang.MessageReporter; -import org.lflang.TargetConfig; +import org.lflang.target.TargetConfig; import org.lflang.federated.generator.FedFileConfig; import org.lflang.federated.generator.FederateInstance; import org.lflang.target.property.ClockSyncModeProperty.ClockSyncMode; diff --git a/core/src/main/java/org/lflang/generator/GeneratorBase.java b/core/src/main/java/org/lflang/generator/GeneratorBase.java index 183dd6a0e5..544a31cabd 100644 --- a/core/src/main/java/org/lflang/generator/GeneratorBase.java +++ b/core/src/main/java/org/lflang/generator/GeneratorBase.java @@ -43,7 +43,7 @@ import org.lflang.MainConflictChecker; import org.lflang.MessageReporter; import org.lflang.Target; -import org.lflang.TargetConfig; +import org.lflang.target.TargetConfig; import org.lflang.analyses.uclid.UclidGenerator; import org.lflang.ast.ASTUtils; import org.lflang.ast.AstTransformation; diff --git a/core/src/main/java/org/lflang/generator/GeneratorUtils.java b/core/src/main/java/org/lflang/generator/GeneratorUtils.java index b7a35ca6a2..deca5153ac 100644 --- a/core/src/main/java/org/lflang/generator/GeneratorUtils.java +++ b/core/src/main/java/org/lflang/generator/GeneratorUtils.java @@ -12,7 +12,7 @@ import org.eclipse.xtext.xbase.lib.IteratorExtensions; import org.lflang.FileConfig; import org.lflang.MessageReporter; -import org.lflang.TargetConfig; +import org.lflang.target.TargetConfig; import org.lflang.TargetProperty; import org.lflang.ast.ASTUtils; import org.lflang.generator.LFGeneratorContext.Mode; diff --git a/core/src/main/java/org/lflang/generator/LFGeneratorContext.java b/core/src/main/java/org/lflang/generator/LFGeneratorContext.java index 142a51a209..03b050f9a3 100644 --- a/core/src/main/java/org/lflang/generator/LFGeneratorContext.java +++ b/core/src/main/java/org/lflang/generator/LFGeneratorContext.java @@ -8,7 +8,7 @@ import org.eclipse.xtext.generator.IGeneratorContext; import org.lflang.FileConfig; import org.lflang.MessageReporter; -import org.lflang.TargetConfig; +import org.lflang.target.TargetConfig; /** * An {@code LFGeneratorContext} is the context of a Lingua Franca build process. It is the point of diff --git a/core/src/main/java/org/lflang/generator/LFResource.java b/core/src/main/java/org/lflang/generator/LFResource.java index 42367dd24f..02fe98d032 100644 --- a/core/src/main/java/org/lflang/generator/LFResource.java +++ b/core/src/main/java/org/lflang/generator/LFResource.java @@ -2,7 +2,7 @@ import org.eclipse.emf.ecore.resource.Resource; import org.lflang.FileConfig; -import org.lflang.TargetConfig; +import org.lflang.target.TargetConfig; /** * A class that keeps metadata for discovered resources during code generation and the supporting diff --git a/core/src/main/java/org/lflang/generator/MainContext.java b/core/src/main/java/org/lflang/generator/MainContext.java index 7357929c06..cfd92cb527 100644 --- a/core/src/main/java/org/lflang/generator/MainContext.java +++ b/core/src/main/java/org/lflang/generator/MainContext.java @@ -11,7 +11,7 @@ import org.lflang.DefaultMessageReporter; import org.lflang.FileConfig; import org.lflang.MessageReporter; -import org.lflang.TargetConfig; +import org.lflang.target.TargetConfig; import org.lflang.generator.IntegratedBuilder.ReportProgress; /** diff --git a/core/src/main/java/org/lflang/generator/SubContext.java b/core/src/main/java/org/lflang/generator/SubContext.java index 9c2bb24e5c..5c0198ec6e 100644 --- a/core/src/main/java/org/lflang/generator/SubContext.java +++ b/core/src/main/java/org/lflang/generator/SubContext.java @@ -4,7 +4,7 @@ import org.eclipse.xtext.util.CancelIndicator; import org.lflang.FileConfig; import org.lflang.MessageReporter; -import org.lflang.TargetConfig; +import org.lflang.target.TargetConfig; /** * A {@code SubContext} is the context of a process within a build process. For example, compilation 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 c24fc60ac2..8fd4ad0077 100644 --- a/core/src/main/java/org/lflang/generator/c/CCmakeGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CCmakeGenerator.java @@ -33,7 +33,7 @@ import java.util.stream.Stream; import org.lflang.FileConfig; import org.lflang.MessageReporter; -import org.lflang.TargetConfig; +import org.lflang.target.TargetConfig; import org.lflang.generator.CodeBuilder; import org.lflang.target.property.PlatformProperty.Platform; import org.lflang.util.FileUtil; diff --git a/core/src/main/java/org/lflang/generator/c/CCompiler.java b/core/src/main/java/org/lflang/generator/c/CCompiler.java index a8bfa1f328..b917082431 100644 --- a/core/src/main/java/org/lflang/generator/c/CCompiler.java +++ b/core/src/main/java/org/lflang/generator/c/CCompiler.java @@ -35,7 +35,7 @@ import java.util.stream.Stream; import org.lflang.FileConfig; import org.lflang.MessageReporter; -import org.lflang.TargetConfig; +import org.lflang.target.TargetConfig; import org.lflang.generator.GeneratorBase; import org.lflang.generator.GeneratorCommandFactory; import org.lflang.generator.GeneratorUtils; diff --git a/core/src/main/java/org/lflang/generator/c/CEnvironmentFunctionGenerator.java b/core/src/main/java/org/lflang/generator/c/CEnvironmentFunctionGenerator.java index d04eae4540..a559d1188c 100644 --- a/core/src/main/java/org/lflang/generator/c/CEnvironmentFunctionGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CEnvironmentFunctionGenerator.java @@ -2,7 +2,7 @@ import java.util.ArrayList; import java.util.List; -import org.lflang.TargetConfig; +import org.lflang.target.TargetConfig; import org.lflang.generator.CodeBuilder; import org.lflang.generator.ReactorInstance; 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 f6a2daa7ae..ee04d6d795 100644 --- a/core/src/main/java/org/lflang/generator/c/CGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CGenerator.java @@ -52,7 +52,7 @@ import org.eclipse.xtext.xbase.lib.StringExtensions; import org.lflang.FileConfig; import org.lflang.Target; -import org.lflang.TargetConfig; +import org.lflang.target.TargetConfig; import org.lflang.ast.ASTUtils; import org.lflang.ast.DelayedConnectionTransformation; import org.lflang.federated.extensions.CExtensionUtils; diff --git a/core/src/main/java/org/lflang/generator/c/CMainFunctionGenerator.java b/core/src/main/java/org/lflang/generator/c/CMainFunctionGenerator.java index 824de835b8..4b48277726 100644 --- a/core/src/main/java/org/lflang/generator/c/CMainFunctionGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CMainFunctionGenerator.java @@ -2,7 +2,7 @@ import java.util.ArrayList; import java.util.List; -import org.lflang.TargetConfig; +import org.lflang.target.TargetConfig; import org.lflang.generator.CodeBuilder; import org.lflang.target.property.PlatformProperty.Platform; import org.lflang.util.StringUtil; 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 6a241b37aa..954102a9cf 100644 --- a/core/src/main/java/org/lflang/generator/c/CPreambleGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CPreambleGenerator.java @@ -3,7 +3,7 @@ import static org.lflang.util.StringUtil.addDoubleQuotes; import java.nio.file.Path; -import org.lflang.TargetConfig; +import org.lflang.target.TargetConfig; import org.lflang.generator.CodeBuilder; import org.lflang.target.property.PlatformProperty.Platform; import org.lflang.util.StringUtil; diff --git a/core/src/main/java/org/lflang/generator/c/CReactionGenerator.java b/core/src/main/java/org/lflang/generator/c/CReactionGenerator.java index c43cfa61f0..d55e74ab9a 100644 --- a/core/src/main/java/org/lflang/generator/c/CReactionGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CReactionGenerator.java @@ -11,7 +11,7 @@ import java.util.Set; import org.lflang.InferredType; import org.lflang.MessageReporter; -import org.lflang.TargetConfig; +import org.lflang.target.TargetConfig; import org.lflang.ast.ASTUtils; import org.lflang.federated.extensions.CExtensionUtils; import org.lflang.generator.CodeBuilder; 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 0db0c8c351..43391623df 100644 --- a/core/src/main/java/org/lflang/generator/c/CTriggerObjectsGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CTriggerObjectsGenerator.java @@ -14,7 +14,7 @@ import java.util.HashSet; import java.util.stream.Collectors; import org.lflang.AttributeUtils; -import org.lflang.TargetConfig; +import org.lflang.target.TargetConfig; import org.lflang.ast.ASTUtils; import org.lflang.federated.extensions.CExtensionUtils; import org.lflang.generator.CodeBuilder; diff --git a/core/src/main/java/org/lflang/generator/c/CUtil.java b/core/src/main/java/org/lflang/generator/c/CUtil.java index a92ef82c93..b3fa8ab04c 100644 --- a/core/src/main/java/org/lflang/generator/c/CUtil.java +++ b/core/src/main/java/org/lflang/generator/c/CUtil.java @@ -39,7 +39,7 @@ import org.lflang.FileConfig; import org.lflang.InferredType; import org.lflang.MessageReporter; -import org.lflang.TargetConfig; +import org.lflang.target.TargetConfig; import org.lflang.ast.ASTUtils; import org.lflang.generator.ActionInstance; import org.lflang.generator.GeneratorCommandFactory; diff --git a/core/src/main/java/org/lflang/generator/python/PythonPreambleGenerator.java b/core/src/main/java/org/lflang/generator/python/PythonPreambleGenerator.java index bd1291425f..bf304c3106 100644 --- a/core/src/main/java/org/lflang/generator/python/PythonPreambleGenerator.java +++ b/core/src/main/java/org/lflang/generator/python/PythonPreambleGenerator.java @@ -3,7 +3,7 @@ import java.nio.file.Path; import java.util.ArrayList; import java.util.List; -import org.lflang.TargetConfig; +import org.lflang.target.TargetConfig; import org.lflang.ast.ASTUtils; import org.lflang.generator.CodeBuilder; import org.lflang.generator.c.CPreambleGenerator; diff --git a/core/src/main/java/org/lflang/generator/rust/RustTargetConfig.java b/core/src/main/java/org/lflang/generator/rust/RustTargetConfig.java index e67dc59dcb..9ad8b08716 100644 --- a/core/src/main/java/org/lflang/generator/rust/RustTargetConfig.java +++ b/core/src/main/java/org/lflang/generator/rust/RustTargetConfig.java @@ -24,6 +24,7 @@ package org.lflang.generator.rust; +import org.lflang.target.TargetConfig; import org.lflang.target.property.BuildTypeProperty; import org.lflang.target.property.BuildTypeProperty.BuildType; import org.lflang.target.property.CargoDependenciesProperty; @@ -31,7 +32,7 @@ import org.lflang.target.property.RustIncludeProperty; /** - * Rust-specific part of a {@link org.lflang.TargetConfig}. + * Rust-specific part of a {@link TargetConfig}. * * @author Clément Fournier - TU Dresden, INSA Rennes */ diff --git a/core/src/main/java/org/lflang/TargetConfig.java b/core/src/main/java/org/lflang/target/TargetConfig.java similarity index 98% rename from core/src/main/java/org/lflang/TargetConfig.java rename to core/src/main/java/org/lflang/target/TargetConfig.java index 6a0958fbca..ba44b39b2b 100644 --- a/core/src/main/java/org/lflang/TargetConfig.java +++ b/core/src/main/java/org/lflang/target/TargetConfig.java @@ -22,11 +22,15 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ***************/ -package org.lflang; +package org.lflang.target; import java.util.ArrayList; import java.util.List; import java.util.Properties; + +import org.lflang.MessageReporter; +import org.lflang.Target; +import org.lflang.TargetProperty; import org.lflang.generator.rust.RustTargetConfig; import org.lflang.lf.KeyValuePair; import org.lflang.lf.TargetDecl; diff --git a/core/src/main/java/org/lflang/util/ArduinoUtil.java b/core/src/main/java/org/lflang/util/ArduinoUtil.java index 4903f8c719..04fd119131 100644 --- a/core/src/main/java/org/lflang/util/ArduinoUtil.java +++ b/core/src/main/java/org/lflang/util/ArduinoUtil.java @@ -8,7 +8,7 @@ import org.eclipse.xtext.xbase.lib.Exceptions; import org.lflang.FileConfig; import org.lflang.MessageReporter; -import org.lflang.TargetConfig; +import org.lflang.target.TargetConfig; import org.lflang.generator.GeneratorCommandFactory; import org.lflang.generator.LFGeneratorContext; diff --git a/core/src/main/java/org/lflang/validation/LFValidator.java b/core/src/main/java/org/lflang/validation/LFValidator.java index 6d93ef2492..5c269ae310 100644 --- a/core/src/main/java/org/lflang/validation/LFValidator.java +++ b/core/src/main/java/org/lflang/validation/LFValidator.java @@ -59,7 +59,7 @@ import org.lflang.InferredType; import org.lflang.ModelInfo; import org.lflang.Target; -import org.lflang.TargetConfig; +import org.lflang.target.TargetConfig; import org.lflang.TargetProperty; import org.lflang.TimeValue; import org.lflang.ast.ASTUtils; diff --git a/core/src/main/kotlin/org/lflang/generator/cpp/CppPlatformGenerator.kt b/core/src/main/kotlin/org/lflang/generator/cpp/CppPlatformGenerator.kt index 8e44d95940..82b881ea25 100644 --- a/core/src/main/kotlin/org/lflang/generator/cpp/CppPlatformGenerator.kt +++ b/core/src/main/kotlin/org/lflang/generator/cpp/CppPlatformGenerator.kt @@ -1,7 +1,7 @@ package org.lflang.generator.cpp import org.lflang.MessageReporter -import org.lflang.TargetConfig +import org.lflang.target.TargetConfig import org.lflang.generator.GeneratorCommandFactory import org.lflang.generator.LFGeneratorContext import org.lflang.toDefinition diff --git a/core/src/main/kotlin/org/lflang/generator/cpp/CppRos2NodeGenerator.kt b/core/src/main/kotlin/org/lflang/generator/cpp/CppRos2NodeGenerator.kt index ae9925d5e5..15c523e4f8 100644 --- a/core/src/main/kotlin/org/lflang/generator/cpp/CppRos2NodeGenerator.kt +++ b/core/src/main/kotlin/org/lflang/generator/cpp/CppRos2NodeGenerator.kt @@ -1,6 +1,6 @@ package org.lflang.generator.cpp -import org.lflang.TargetConfig +import org.lflang.target.TargetConfig import org.lflang.lf.Reactor import org.lflang.toUnixString diff --git a/core/src/main/kotlin/org/lflang/generator/cpp/CppStandaloneCmakeGenerator.kt b/core/src/main/kotlin/org/lflang/generator/cpp/CppStandaloneCmakeGenerator.kt index 61e3375c36..b456145342 100644 --- a/core/src/main/kotlin/org/lflang/generator/cpp/CppStandaloneCmakeGenerator.kt +++ b/core/src/main/kotlin/org/lflang/generator/cpp/CppStandaloneCmakeGenerator.kt @@ -25,7 +25,7 @@ package org.lflang.generator.cpp import org.lflang.FileConfig -import org.lflang.TargetConfig +import org.lflang.target.TargetConfig import org.lflang.generator.PrependOperator import org.lflang.joinWithLn import org.lflang.toUnixString diff --git a/core/src/main/kotlin/org/lflang/generator/cpp/CppStandaloneMainGenerator.kt b/core/src/main/kotlin/org/lflang/generator/cpp/CppStandaloneMainGenerator.kt index 41679daf4e..0504be555c 100644 --- a/core/src/main/kotlin/org/lflang/generator/cpp/CppStandaloneMainGenerator.kt +++ b/core/src/main/kotlin/org/lflang/generator/cpp/CppStandaloneMainGenerator.kt @@ -1,6 +1,6 @@ package org.lflang.generator.cpp -import org.lflang.TargetConfig +import org.lflang.target.TargetConfig import org.lflang.generator.PrependOperator import org.lflang.inferredType import org.lflang.lf.Parameter diff --git a/core/src/main/kotlin/org/lflang/generator/rust/RustFileConfig.kt b/core/src/main/kotlin/org/lflang/generator/rust/RustFileConfig.kt index 6e12986e03..9c68cd3f85 100644 --- a/core/src/main/kotlin/org/lflang/generator/rust/RustFileConfig.kt +++ b/core/src/main/kotlin/org/lflang/generator/rust/RustFileConfig.kt @@ -26,7 +26,6 @@ package org.lflang.generator.rust import org.eclipse.emf.ecore.resource.Resource import org.lflang.FileConfig -import org.lflang.TargetConfig import org.lflang.camelToSnakeCase import org.lflang.generator.CodeMap import org.lflang.util.FileUtil 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 2ab9af11e8..f0fbf1ad10 100644 --- a/core/src/main/kotlin/org/lflang/generator/rust/RustModel.kt +++ b/core/src/main/kotlin/org/lflang/generator/rust/RustModel.kt @@ -31,6 +31,7 @@ import org.lflang.ast.ASTUtils import org.lflang.generator.* import org.lflang.lf.* import org.lflang.lf.Timer +import org.lflang.target.TargetConfig import java.nio.file.Path import java.util.* diff --git a/core/src/main/kotlin/org/lflang/generator/ts/TSConstructorGenerator.kt b/core/src/main/kotlin/org/lflang/generator/ts/TSConstructorGenerator.kt index 2d1376fae9..fe25d3207b 100644 --- a/core/src/main/kotlin/org/lflang/generator/ts/TSConstructorGenerator.kt +++ b/core/src/main/kotlin/org/lflang/generator/ts/TSConstructorGenerator.kt @@ -1,7 +1,7 @@ package org.lflang.generator.ts import org.lflang.MessageReporter -import org.lflang.TargetConfig +import org.lflang.target.TargetConfig import org.lflang.generator.PrependOperator import org.lflang.generator.getTargetInitializer import org.lflang.lf.Parameter diff --git a/core/src/main/kotlin/org/lflang/generator/ts/TSParameterPreambleGenerator.kt b/core/src/main/kotlin/org/lflang/generator/ts/TSParameterPreambleGenerator.kt index dc68c7f2f9..4efc48d045 100644 --- a/core/src/main/kotlin/org/lflang/generator/ts/TSParameterPreambleGenerator.kt +++ b/core/src/main/kotlin/org/lflang/generator/ts/TSParameterPreambleGenerator.kt @@ -26,7 +26,7 @@ package org.lflang.generator.ts import org.lflang.FileConfig -import org.lflang.TargetConfig +import org.lflang.target.TargetConfig import org.lflang.joinWithLn import org.lflang.lf.Parameter import org.lflang.lf.Reactor diff --git a/core/src/main/kotlin/org/lflang/generator/ts/TSReactorGenerator.kt b/core/src/main/kotlin/org/lflang/generator/ts/TSReactorGenerator.kt index 73da56bf4c..f9520bbecb 100644 --- a/core/src/main/kotlin/org/lflang/generator/ts/TSReactorGenerator.kt +++ b/core/src/main/kotlin/org/lflang/generator/ts/TSReactorGenerator.kt @@ -3,6 +3,7 @@ package org.lflang.generator.ts import org.lflang.* import org.lflang.generator.PrependOperator import org.lflang.lf.* +import org.lflang.target.TargetConfig import java.util.* /** diff --git a/core/src/testFixtures/java/org/lflang/tests/TestBase.java b/core/src/testFixtures/java/org/lflang/tests/TestBase.java index df97b3ea5d..23fdac9afa 100644 --- a/core/src/testFixtures/java/org/lflang/tests/TestBase.java +++ b/core/src/testFixtures/java/org/lflang/tests/TestBase.java @@ -39,7 +39,7 @@ import org.lflang.LFRuntimeModule; import org.lflang.LFStandaloneSetup; import org.lflang.Target; -import org.lflang.TargetConfig; +import org.lflang.target.TargetConfig; import org.lflang.generator.GeneratorResult; import org.lflang.generator.LFGenerator; import org.lflang.generator.LFGeneratorContext; From 764bde2d70614a948879cbc591a8a3ab79c56ec1 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Sat, 30 Sep 2023 23:31:36 -0700 Subject: [PATCH 034/145] Comments and minor changes --- .../org/lflang/AbstractTargetProperty.java | 4 +-- .../main/java/org/lflang/TargetProperty.java | 33 +++++++++++-------- .../main/java/org/lflang/ast/ASTUtils.java | 2 +- .../federated/generator/FedGenerator.java | 2 +- .../federated/generator/FedTargetConfig.java | 2 +- .../federated/generator/FederateInstance.java | 2 +- .../launcher/FedLauncherGenerator.java | 2 +- .../org/lflang/generator/GeneratorBase.java | 2 +- .../org/lflang/generator/GeneratorUtils.java | 5 +-- .../org/lflang/generator/MainContext.java | 2 +- .../lflang/generator/c/CCmakeGenerator.java | 2 +- .../org/lflang/generator/c/CCompiler.java | 2 +- .../c/CEnvironmentFunctionGenerator.java | 2 +- .../org/lflang/generator/c/CGenerator.java | 2 +- .../generator/c/CMainFunctionGenerator.java | 2 +- .../generator/c/CPreambleGenerator.java | 2 +- .../generator/c/CReactionGenerator.java | 2 +- .../generator/c/CTriggerObjectsGenerator.java | 2 +- .../java/org/lflang/generator/c/CUtil.java | 2 +- .../python/PythonPreambleGenerator.java | 2 +- .../java/org/lflang/target/TargetConfig.java | 7 ++-- .../property/ClockSyncOptionsProperty.java | 2 +- .../property/CoordinationOptionsProperty.java | 2 +- .../target/property/DockerProperty.java | 2 +- .../target/property/PlatformProperty.java | 2 +- .../target/property/TracingProperty.java | 2 +- .../target/property/type/DictionaryType.java | 6 +++- .../java/org/lflang/util/ArduinoUtil.java | 2 +- .../org/lflang/validation/LFValidator.java | 9 ++--- .../compiler/LinguaFrancaValidationTest.java | 2 +- .../java/org/lflang/tests/TestBase.java | 2 +- 31 files changed, 59 insertions(+), 55 deletions(-) diff --git a/core/src/main/java/org/lflang/AbstractTargetProperty.java b/core/src/main/java/org/lflang/AbstractTargetProperty.java index 49a603e443..2ed2ebb752 100644 --- a/core/src/main/java/org/lflang/AbstractTargetProperty.java +++ b/core/src/main/java/org/lflang/AbstractTargetProperty.java @@ -180,9 +180,7 @@ public T get() { */ protected abstract T fromString(String string, MessageReporter reporter); - /** - * Return a list of targets that support this target property. - */ + /** Return a list of targets that support this target property. */ public abstract List supportedTargets(); /** diff --git a/core/src/main/java/org/lflang/TargetProperty.java b/core/src/main/java/org/lflang/TargetProperty.java index 96b93073cb..c2e948da6b 100644 --- a/core/src/main/java/org/lflang/TargetProperty.java +++ b/core/src/main/java/org/lflang/TargetProperty.java @@ -78,7 +78,6 @@ import org.lflang.target.property.TimeOutProperty; import org.lflang.target.property.TracingProperty; import org.lflang.target.property.WorkersProperty; -import org.lflang.target.property.type.TargetPropertyType; import org.lflang.target.property.type.VerifyProperty; import org.lflang.validation.ValidatorMessageReporter; @@ -360,7 +359,7 @@ public static List loaded(TargetConfig config) { } /** - * Constructs a TargetDecl by extracting the fields of the given TargetConfig. + * Constructs a {@code TargetDecl} by extracting the fields of the given {@code TargetConfig}. * * @param target The target to generate for. * @param config The TargetConfig to extract from. @@ -377,8 +376,15 @@ public static TargetDecl extractTargetDecl(Target target, TargetConfig config) { return decl; } - private static KeyValuePair getKeyValuePair( - KeyValuePairs targetProperties, TargetProperty property) { + /** + * 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.toString())) @@ -387,15 +393,19 @@ private static KeyValuePair getKeyValuePair( return properties.size() > 0 ? properties.get(0) : null; } - public static KeyValuePair getKeyValuePair(Model ast, TargetProperty property) { - return getKeyValuePair(ast.getTarget().getConfig(), property); - } - /** Return a list containing the keys of all properties */ public static List getPropertyKeys() { - return Arrays.stream(TargetProperty.values()).map(TargetProperty::getKey).toList(); + return Arrays.stream(TargetProperty.values()).map(TargetProperty::toString).toList(); } + /** + * Validate the given key-value pairs 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 config A target configuration used to retrieve the corresponding target properties. + * @param reporter A reporter to report errors and warnings through. + */ public static void validate( KeyValuePairs pairs, Model ast, TargetConfig config, ValidatorMessageReporter reporter) { pairs.getPairs().stream() @@ -487,9 +497,4 @@ public String toString() { } return this.name().toLowerCase().replaceAll("_", "-"); } - - /** Interface for dictionary elements. It associates an entry with a type. */ - public interface DictionaryElement { - TargetPropertyType getType(); - } } diff --git a/core/src/main/java/org/lflang/ast/ASTUtils.java b/core/src/main/java/org/lflang/ast/ASTUtils.java index 694cddfb00..132682a84a 100644 --- a/core/src/main/java/org/lflang/ast/ASTUtils.java +++ b/core/src/main/java/org/lflang/ast/ASTUtils.java @@ -61,7 +61,6 @@ import org.lflang.InferredType; import org.lflang.MessageReporter; import org.lflang.Target; -import org.lflang.target.TargetConfig; import org.lflang.TimeUnit; import org.lflang.TimeValue; import org.lflang.generator.CodeMap; @@ -102,6 +101,7 @@ import org.lflang.lf.Watchdog; import org.lflang.lf.WidthSpec; import org.lflang.lf.WidthTerm; +import org.lflang.target.TargetConfig; import org.lflang.util.StringUtil; /** 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 ad7b4f7137..9bad080b7a 100644 --- a/core/src/main/java/org/lflang/federated/generator/FedGenerator.java +++ b/core/src/main/java/org/lflang/federated/generator/FedGenerator.java @@ -31,7 +31,6 @@ import org.lflang.LFStandaloneSetup; import org.lflang.MessageReporter; import org.lflang.Target; -import org.lflang.target.TargetConfig; import org.lflang.ast.ASTUtils; import org.lflang.federated.launcher.FedLauncherGenerator; import org.lflang.federated.launcher.RtiConfig; @@ -58,6 +57,7 @@ import org.lflang.lf.Reactor; import org.lflang.lf.TargetDecl; import org.lflang.lf.VarRef; +import org.lflang.target.TargetConfig; import org.lflang.target.property.CoordinationProperty.CoordinationMode; import org.lflang.util.Averager; diff --git a/core/src/main/java/org/lflang/federated/generator/FedTargetConfig.java b/core/src/main/java/org/lflang/federated/generator/FedTargetConfig.java index 74e3893b02..aa0a054907 100644 --- a/core/src/main/java/org/lflang/federated/generator/FedTargetConfig.java +++ b/core/src/main/java/org/lflang/federated/generator/FedTargetConfig.java @@ -5,10 +5,10 @@ import java.nio.file.Path; import org.eclipse.emf.ecore.resource.Resource; import org.lflang.MessageReporter; -import org.lflang.target.TargetConfig; import org.lflang.TargetProperty; import org.lflang.generator.GeneratorUtils; import org.lflang.generator.LFGeneratorContext; +import org.lflang.target.TargetConfig; import org.lflang.util.FileUtil; /** diff --git a/core/src/main/java/org/lflang/federated/generator/FederateInstance.java b/core/src/main/java/org/lflang/federated/generator/FederateInstance.java index 9602f98047..799a403601 100644 --- a/core/src/main/java/org/lflang/federated/generator/FederateInstance.java +++ b/core/src/main/java/org/lflang/federated/generator/FederateInstance.java @@ -37,7 +37,6 @@ import java.util.stream.Collectors; import java.util.stream.Stream; import org.lflang.MessageReporter; -import org.lflang.target.TargetConfig; import org.lflang.TimeValue; import org.lflang.ast.ASTUtils; import org.lflang.federated.serialization.SupportedSerializers; @@ -64,6 +63,7 @@ import org.lflang.lf.TriggerRef; import org.lflang.lf.VarRef; import org.lflang.lf.Variable; +import org.lflang.target.TargetConfig; /** * Class that represents an instance of a federate, i.e., a reactor that is instantiated at the top diff --git a/core/src/main/java/org/lflang/federated/launcher/FedLauncherGenerator.java b/core/src/main/java/org/lflang/federated/launcher/FedLauncherGenerator.java index d9a7417964..bc4ec28087 100644 --- a/core/src/main/java/org/lflang/federated/launcher/FedLauncherGenerator.java +++ b/core/src/main/java/org/lflang/federated/launcher/FedLauncherGenerator.java @@ -34,9 +34,9 @@ import java.util.ArrayList; import java.util.List; import org.lflang.MessageReporter; -import org.lflang.target.TargetConfig; import org.lflang.federated.generator.FedFileConfig; import org.lflang.federated.generator.FederateInstance; +import org.lflang.target.TargetConfig; import org.lflang.target.property.ClockSyncModeProperty.ClockSyncMode; /** diff --git a/core/src/main/java/org/lflang/generator/GeneratorBase.java b/core/src/main/java/org/lflang/generator/GeneratorBase.java index 544a31cabd..31e3408266 100644 --- a/core/src/main/java/org/lflang/generator/GeneratorBase.java +++ b/core/src/main/java/org/lflang/generator/GeneratorBase.java @@ -43,12 +43,12 @@ import org.lflang.MainConflictChecker; import org.lflang.MessageReporter; import org.lflang.Target; -import org.lflang.target.TargetConfig; import org.lflang.analyses.uclid.UclidGenerator; import org.lflang.ast.ASTUtils; import org.lflang.ast.AstTransformation; import org.lflang.graph.InstantiationGraph; import org.lflang.lf.*; +import org.lflang.target.TargetConfig; import org.lflang.util.FileUtil; import org.lflang.validation.AbstractLFValidator; diff --git a/core/src/main/java/org/lflang/generator/GeneratorUtils.java b/core/src/main/java/org/lflang/generator/GeneratorUtils.java index deca5153ac..e7f1c6b89c 100644 --- a/core/src/main/java/org/lflang/generator/GeneratorUtils.java +++ b/core/src/main/java/org/lflang/generator/GeneratorUtils.java @@ -12,7 +12,7 @@ import org.eclipse.xtext.xbase.lib.IteratorExtensions; import org.lflang.FileConfig; import org.lflang.MessageReporter; -import org.lflang.target.TargetConfig; +import org.lflang.Target; import org.lflang.TargetProperty; import org.lflang.ast.ASTUtils; import org.lflang.generator.LFGeneratorContext.Mode; @@ -23,6 +23,7 @@ import org.lflang.lf.KeyValuePairs; import org.lflang.lf.Reactor; import org.lflang.lf.TargetDecl; +import org.lflang.target.TargetConfig; /** * A helper class with functions that may be useful for code generators. This is created to ease our @@ -118,7 +119,7 @@ public static LFResource getLFResource( MessageReporter messageReporter) { var target = ASTUtils.targetDecl(resource); KeyValuePairs config = target.getConfig(); - var targetConfig = new TargetConfig(target); + var targetConfig = new TargetConfig(Target.fromDecl(target)); if (config != null) { List pairs = config.getPairs(); TargetProperty.load(targetConfig, 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 cfd92cb527..dbe34946e3 100644 --- a/core/src/main/java/org/lflang/generator/MainContext.java +++ b/core/src/main/java/org/lflang/generator/MainContext.java @@ -11,8 +11,8 @@ import org.lflang.DefaultMessageReporter; import org.lflang.FileConfig; import org.lflang.MessageReporter; -import org.lflang.target.TargetConfig; import org.lflang.generator.IntegratedBuilder.ReportProgress; +import org.lflang.target.TargetConfig; /** * A {@code MainContext} is an {@code LFGeneratorContext} that is not nested in any other generator 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 8fd4ad0077..df6e6abb57 100644 --- a/core/src/main/java/org/lflang/generator/c/CCmakeGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CCmakeGenerator.java @@ -33,8 +33,8 @@ import java.util.stream.Stream; import org.lflang.FileConfig; import org.lflang.MessageReporter; -import org.lflang.target.TargetConfig; import org.lflang.generator.CodeBuilder; +import org.lflang.target.TargetConfig; import org.lflang.target.property.PlatformProperty.Platform; import org.lflang.util.FileUtil; diff --git a/core/src/main/java/org/lflang/generator/c/CCompiler.java b/core/src/main/java/org/lflang/generator/c/CCompiler.java index b917082431..55d5cb2b3b 100644 --- a/core/src/main/java/org/lflang/generator/c/CCompiler.java +++ b/core/src/main/java/org/lflang/generator/c/CCompiler.java @@ -35,11 +35,11 @@ import java.util.stream.Stream; import org.lflang.FileConfig; import org.lflang.MessageReporter; -import org.lflang.target.TargetConfig; import org.lflang.generator.GeneratorBase; import org.lflang.generator.GeneratorCommandFactory; import org.lflang.generator.GeneratorUtils; import org.lflang.generator.LFGeneratorContext; +import org.lflang.target.TargetConfig; import org.lflang.target.property.BuildTypeProperty; import org.lflang.target.property.PlatformProperty.Platform; import org.lflang.util.FileUtil; diff --git a/core/src/main/java/org/lflang/generator/c/CEnvironmentFunctionGenerator.java b/core/src/main/java/org/lflang/generator/c/CEnvironmentFunctionGenerator.java index a559d1188c..39569d0725 100644 --- a/core/src/main/java/org/lflang/generator/c/CEnvironmentFunctionGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CEnvironmentFunctionGenerator.java @@ -2,9 +2,9 @@ import java.util.ArrayList; import java.util.List; -import org.lflang.target.TargetConfig; import org.lflang.generator.CodeBuilder; import org.lflang.generator.ReactorInstance; +import org.lflang.target.TargetConfig; /** * This class is in charge of code generating functions and global variables related to the 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 ee04d6d795..90c9b41080 100644 --- a/core/src/main/java/org/lflang/generator/c/CGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CGenerator.java @@ -52,7 +52,6 @@ import org.eclipse.xtext.xbase.lib.StringExtensions; import org.lflang.FileConfig; import org.lflang.Target; -import org.lflang.target.TargetConfig; import org.lflang.ast.ASTUtils; import org.lflang.ast.DelayedConnectionTransformation; import org.lflang.federated.extensions.CExtensionUtils; @@ -86,6 +85,7 @@ import org.lflang.lf.ReactorDecl; import org.lflang.lf.StateVar; import org.lflang.lf.Variable; +import org.lflang.target.TargetConfig; import org.lflang.target.property.PlatformProperty.Platform; import org.lflang.target.property.PlatformProperty.PlatformOption; import org.lflang.target.property.SchedulerProperty.SchedulerOption; diff --git a/core/src/main/java/org/lflang/generator/c/CMainFunctionGenerator.java b/core/src/main/java/org/lflang/generator/c/CMainFunctionGenerator.java index 4b48277726..e8c58bd92f 100644 --- a/core/src/main/java/org/lflang/generator/c/CMainFunctionGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CMainFunctionGenerator.java @@ -2,8 +2,8 @@ import java.util.ArrayList; import java.util.List; -import org.lflang.target.TargetConfig; import org.lflang.generator.CodeBuilder; +import org.lflang.target.TargetConfig; import org.lflang.target.property.PlatformProperty.Platform; import org.lflang.util.StringUtil; 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 954102a9cf..c0cda07b3f 100644 --- a/core/src/main/java/org/lflang/generator/c/CPreambleGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CPreambleGenerator.java @@ -3,8 +3,8 @@ import static org.lflang.util.StringUtil.addDoubleQuotes; import java.nio.file.Path; -import org.lflang.target.TargetConfig; import org.lflang.generator.CodeBuilder; +import org.lflang.target.TargetConfig; import org.lflang.target.property.PlatformProperty.Platform; import org.lflang.util.StringUtil; diff --git a/core/src/main/java/org/lflang/generator/c/CReactionGenerator.java b/core/src/main/java/org/lflang/generator/c/CReactionGenerator.java index d55e74ab9a..b5db35ce92 100644 --- a/core/src/main/java/org/lflang/generator/c/CReactionGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CReactionGenerator.java @@ -11,7 +11,6 @@ import java.util.Set; import org.lflang.InferredType; import org.lflang.MessageReporter; -import org.lflang.target.TargetConfig; import org.lflang.ast.ASTUtils; import org.lflang.federated.extensions.CExtensionUtils; import org.lflang.generator.CodeBuilder; @@ -33,6 +32,7 @@ import org.lflang.lf.VarRef; import org.lflang.lf.Variable; import org.lflang.lf.Watchdog; +import org.lflang.target.TargetConfig; import org.lflang.util.StringUtil; public class CReactionGenerator { 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 43391623df..8cd050b8a0 100644 --- a/core/src/main/java/org/lflang/generator/c/CTriggerObjectsGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CTriggerObjectsGenerator.java @@ -14,7 +14,6 @@ import java.util.HashSet; import java.util.stream.Collectors; import org.lflang.AttributeUtils; -import org.lflang.target.TargetConfig; import org.lflang.ast.ASTUtils; import org.lflang.federated.extensions.CExtensionUtils; import org.lflang.generator.CodeBuilder; @@ -23,6 +22,7 @@ import org.lflang.generator.ReactorInstance; import org.lflang.generator.RuntimeRange; import org.lflang.generator.SendRange; +import org.lflang.target.TargetConfig; import org.lflang.target.property.LoggingProperty.LogLevel; /** diff --git a/core/src/main/java/org/lflang/generator/c/CUtil.java b/core/src/main/java/org/lflang/generator/c/CUtil.java index b3fa8ab04c..b3bd6d2c24 100644 --- a/core/src/main/java/org/lflang/generator/c/CUtil.java +++ b/core/src/main/java/org/lflang/generator/c/CUtil.java @@ -39,7 +39,6 @@ import org.lflang.FileConfig; import org.lflang.InferredType; import org.lflang.MessageReporter; -import org.lflang.target.TargetConfig; import org.lflang.ast.ASTUtils; import org.lflang.generator.ActionInstance; import org.lflang.generator.GeneratorCommandFactory; @@ -54,6 +53,7 @@ import org.lflang.lf.VarRef; import org.lflang.lf.Variable; import org.lflang.lf.WidthTerm; +import org.lflang.target.TargetConfig; import org.lflang.util.FileUtil; import org.lflang.util.LFCommand; diff --git a/core/src/main/java/org/lflang/generator/python/PythonPreambleGenerator.java b/core/src/main/java/org/lflang/generator/python/PythonPreambleGenerator.java index bf304c3106..305b2a78b7 100644 --- a/core/src/main/java/org/lflang/generator/python/PythonPreambleGenerator.java +++ b/core/src/main/java/org/lflang/generator/python/PythonPreambleGenerator.java @@ -3,11 +3,11 @@ import java.nio.file.Path; import java.util.ArrayList; import java.util.List; -import org.lflang.target.TargetConfig; import org.lflang.ast.ASTUtils; import org.lflang.generator.CodeBuilder; import org.lflang.generator.c.CPreambleGenerator; import org.lflang.lf.Preamble; +import org.lflang.target.TargetConfig; /** * Generates user-defined preambles and #define and #include directives for the Python target. diff --git a/core/src/main/java/org/lflang/target/TargetConfig.java b/core/src/main/java/org/lflang/target/TargetConfig.java index ba44b39b2b..2347ccba62 100644 --- a/core/src/main/java/org/lflang/target/TargetConfig.java +++ b/core/src/main/java/org/lflang/target/TargetConfig.java @@ -27,7 +27,6 @@ import java.util.ArrayList; import java.util.List; import java.util.Properties; - import org.lflang.MessageReporter; import org.lflang.Target; import org.lflang.TargetProperty; @@ -87,8 +86,8 @@ public class TargetConfig { * * @param target AST node of a target declaration. */ - public TargetConfig(TargetDecl target) { // FIXME: eliminate this constructor if we can - this.target = Target.fromDecl(target); + public TargetConfig(Target target) { + this.target = target; } /** @@ -100,7 +99,7 @@ public TargetConfig(TargetDecl target) { // FIXME: eliminate this constructor if * @param messageReporter An error reporter to report problems. */ public TargetConfig(Properties cliArgs, TargetDecl target, MessageReporter messageReporter) { - this(target); + this(Target.fromDecl(target)); if (target.getConfig() != null) { List pairs = target.getConfig().getPairs(); TargetProperty.load(this, pairs, messageReporter); 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 6428580624..e994ab1035 100644 --- a/core/src/main/java/org/lflang/target/property/ClockSyncOptionsProperty.java +++ b/core/src/main/java/org/lflang/target/property/ClockSyncOptionsProperty.java @@ -5,7 +5,6 @@ import org.lflang.AbstractTargetProperty; import org.lflang.MessageReporter; import org.lflang.Target; -import org.lflang.TargetProperty.DictionaryElement; import org.lflang.TimeUnit; import org.lflang.TimeValue; import org.lflang.ast.ASTUtils; @@ -15,6 +14,7 @@ import org.lflang.lf.LfFactory; import org.lflang.target.property.ClockSyncOptionsProperty.ClockSyncOptions; import org.lflang.target.property.type.DictionaryType; +import org.lflang.target.property.type.DictionaryType.DictionaryElement; import org.lflang.target.property.type.PrimitiveType; import org.lflang.target.property.type.TargetPropertyType; 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 7d01e5af7d..348b6f31b7 100644 --- a/core/src/main/java/org/lflang/target/property/CoordinationOptionsProperty.java +++ b/core/src/main/java/org/lflang/target/property/CoordinationOptionsProperty.java @@ -6,7 +6,6 @@ import org.lflang.AbstractTargetProperty; import org.lflang.MessageReporter; import org.lflang.Target; -import org.lflang.TargetProperty.DictionaryElement; import org.lflang.TimeValue; import org.lflang.ast.ASTUtils; import org.lflang.lf.Element; @@ -15,6 +14,7 @@ import org.lflang.lf.LfFactory; import org.lflang.target.property.CoordinationOptionsProperty.CoordinationOptions; import org.lflang.target.property.type.DictionaryType; +import org.lflang.target.property.type.DictionaryType.DictionaryElement; import org.lflang.target.property.type.PrimitiveType; import org.lflang.target.property.type.TargetPropertyType; 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 fb8b7d3920..ffd488f07a 100644 --- a/core/src/main/java/org/lflang/target/property/DockerProperty.java +++ b/core/src/main/java/org/lflang/target/property/DockerProperty.java @@ -6,7 +6,6 @@ import org.lflang.AbstractTargetProperty; import org.lflang.MessageReporter; import org.lflang.Target; -import org.lflang.TargetProperty.DictionaryElement; import org.lflang.ast.ASTUtils; import org.lflang.lf.Element; import org.lflang.lf.KeyValuePair; @@ -14,6 +13,7 @@ import org.lflang.lf.LfFactory; import org.lflang.target.property.DockerProperty.DockerOptions; import org.lflang.target.property.type.DictionaryType; +import org.lflang.target.property.type.DictionaryType.DictionaryElement; import org.lflang.target.property.type.PrimitiveType; import org.lflang.target.property.type.TargetPropertyType; import org.lflang.target.property.type.UnionType; 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 78ac245a61..3087a72c66 100644 --- a/core/src/main/java/org/lflang/target/property/PlatformProperty.java +++ b/core/src/main/java/org/lflang/target/property/PlatformProperty.java @@ -6,7 +6,6 @@ import org.lflang.MessageReporter; import org.lflang.Target; import org.lflang.TargetProperty; -import org.lflang.TargetProperty.DictionaryElement; import org.lflang.ast.ASTUtils; import org.lflang.lf.Element; import org.lflang.lf.KeyValuePair; @@ -16,6 +15,7 @@ import org.lflang.lf.Model; import org.lflang.target.property.PlatformProperty.PlatformOptions; import org.lflang.target.property.type.DictionaryType; +import org.lflang.target.property.type.DictionaryType.DictionaryElement; import org.lflang.target.property.type.PrimitiveType; import org.lflang.target.property.type.TargetPropertyType; import org.lflang.target.property.type.UnionType; 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 1505d14a59..314e989868 100644 --- a/core/src/main/java/org/lflang/target/property/TracingProperty.java +++ b/core/src/main/java/org/lflang/target/property/TracingProperty.java @@ -6,7 +6,6 @@ import org.lflang.MessageReporter; import org.lflang.Target; import org.lflang.TargetProperty; -import org.lflang.TargetProperty.DictionaryElement; import org.lflang.ast.ASTUtils; import org.lflang.lf.Element; import org.lflang.lf.KeyValuePair; @@ -16,6 +15,7 @@ import org.lflang.lf.Model; import org.lflang.target.property.TracingProperty.TracingOptions; import org.lflang.target.property.type.DictionaryType; +import org.lflang.target.property.type.DictionaryType.DictionaryElement; import org.lflang.target.property.type.PrimitiveType; import org.lflang.target.property.type.TargetPropertyType; import org.lflang.target.property.type.UnionType; diff --git a/core/src/main/java/org/lflang/target/property/type/DictionaryType.java b/core/src/main/java/org/lflang/target/property/type/DictionaryType.java index 63107eb98c..10522a09b1 100644 --- a/core/src/main/java/org/lflang/target/property/type/DictionaryType.java +++ b/core/src/main/java/org/lflang/target/property/type/DictionaryType.java @@ -6,7 +6,6 @@ import java.util.stream.Collectors; import org.lflang.MessageReporter; import org.lflang.Target; -import org.lflang.TargetProperty.DictionaryElement; import org.lflang.lf.Element; import org.lflang.lf.KeyValuePair; import org.lflang.lf.KeyValuePairs; @@ -91,4 +90,9 @@ public String toString() { return "a dictionary with one or more of the following keys: " + options.stream().map(option -> option.toString()).collect(Collectors.joining(", ")); } + + /** Interface for dictionary elements. It associates an entry with a type. */ + public interface DictionaryElement { + TargetPropertyType getType(); + } } diff --git a/core/src/main/java/org/lflang/util/ArduinoUtil.java b/core/src/main/java/org/lflang/util/ArduinoUtil.java index 04fd119131..3423e80ac7 100644 --- a/core/src/main/java/org/lflang/util/ArduinoUtil.java +++ b/core/src/main/java/org/lflang/util/ArduinoUtil.java @@ -8,9 +8,9 @@ import org.eclipse.xtext.xbase.lib.Exceptions; import org.lflang.FileConfig; import org.lflang.MessageReporter; -import org.lflang.target.TargetConfig; import org.lflang.generator.GeneratorCommandFactory; import org.lflang.generator.LFGeneratorContext; +import org.lflang.target.TargetConfig; /** * Utilities for Building using Arduino CLI. diff --git a/core/src/main/java/org/lflang/validation/LFValidator.java b/core/src/main/java/org/lflang/validation/LFValidator.java index 5c269ae310..2f0faf28a2 100644 --- a/core/src/main/java/org/lflang/validation/LFValidator.java +++ b/core/src/main/java/org/lflang/validation/LFValidator.java @@ -59,7 +59,6 @@ import org.lflang.InferredType; import org.lflang.ModelInfo; import org.lflang.Target; -import org.lflang.target.TargetConfig; import org.lflang.TargetProperty; import org.lflang.TimeValue; import org.lflang.ast.ASTUtils; @@ -115,6 +114,7 @@ import org.lflang.lf.Visibility; import org.lflang.lf.WidthSpec; import org.lflang.lf.WidthTerm; +import org.lflang.target.TargetConfig; import org.lflang.util.FileUtil; /** @@ -132,8 +132,6 @@ */ public class LFValidator extends BaseLFValidator { - private TargetConfig targetConfig; - // The methods annotated with @Check are automatically invoked on AST nodes matching the types of // their arguments. CheckType.FAST ensures that these checks run whenever a file is modified; // when CheckType.NORMAL is used, the check is run upon saving. @@ -1061,8 +1059,7 @@ public void checkTargetDecl(TargetDecl target) throws IOException { if (targetOpt.isEmpty()) { error("Unrecognized target: " + target.getName(), Literals.TARGET_DECL__NAME); } else { - this.target = targetOpt.get(); // FIXME: remove - this.targetConfig = new TargetConfig(target); + this.target = targetOpt.get(); } String lfFileName = FileUtil.nameWithoutExtension(target.eResource()); if (Character.isDigit(lfFileName.charAt(0))) { @@ -1078,7 +1075,7 @@ public void checkTargetDecl(TargetDecl target) throws IOException { @Check(CheckType.NORMAL) public void checkTargetProperties(KeyValuePairs targetProperties) { TargetProperty.validate( - targetProperties, this.info.model, this.targetConfig, getErrorReporter()); + targetProperties, this.info.model, new TargetConfig(this.target), getErrorReporter()); } @Check(CheckType.FAST) 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 43154df8b5..2762d360c9 100644 --- a/core/src/test/java/org/lflang/tests/compiler/LinguaFrancaValidationTest.java +++ b/core/src/test/java/org/lflang/tests/compiler/LinguaFrancaValidationTest.java @@ -46,13 +46,13 @@ import org.junit.jupiter.api.extension.ExtendWith; import org.lflang.Target; import org.lflang.TargetProperty; -import org.lflang.TargetProperty.DictionaryElement; import org.lflang.TimeValue; import org.lflang.lf.LfPackage; import org.lflang.lf.Model; import org.lflang.lf.Visibility; import org.lflang.target.property.type.ArrayType; import org.lflang.target.property.type.DictionaryType; +import org.lflang.target.property.type.DictionaryType.DictionaryElement; import org.lflang.target.property.type.PrimitiveType; import org.lflang.target.property.type.StringDictionaryType; import org.lflang.target.property.type.TargetPropertyType; diff --git a/core/src/testFixtures/java/org/lflang/tests/TestBase.java b/core/src/testFixtures/java/org/lflang/tests/TestBase.java index 23fdac9afa..64bcdbe42e 100644 --- a/core/src/testFixtures/java/org/lflang/tests/TestBase.java +++ b/core/src/testFixtures/java/org/lflang/tests/TestBase.java @@ -39,12 +39,12 @@ import org.lflang.LFRuntimeModule; import org.lflang.LFStandaloneSetup; import org.lflang.Target; -import org.lflang.target.TargetConfig; import org.lflang.generator.GeneratorResult; import org.lflang.generator.LFGenerator; import org.lflang.generator.LFGeneratorContext; import org.lflang.generator.LFGeneratorContext.BuildParm; import org.lflang.generator.MainContext; +import org.lflang.target.TargetConfig; import org.lflang.tests.Configurators.Configurator; import org.lflang.tests.LFTest.Result; import org.lflang.tests.TestRegistry.TestCategory; From f3aeb44b04baeaae7a12b4e0ee87a57fe3deaa13 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Sat, 30 Sep 2023 23:52:44 -0700 Subject: [PATCH 035/145] API rename --- .../main/java/org/lflang/ast/ASTUtils.java | 1 - .../federated/extensions/CExtensionUtils.java | 26 ++++++++----------- .../property/CompileDefinitionsProperty.java | 2 +- 3 files changed, 12 insertions(+), 17 deletions(-) diff --git a/core/src/main/java/org/lflang/ast/ASTUtils.java b/core/src/main/java/org/lflang/ast/ASTUtils.java index 132682a84a..623ec24e23 100644 --- a/core/src/main/java/org/lflang/ast/ASTUtils.java +++ b/core/src/main/java/org/lflang/ast/ASTUtils.java @@ -616,7 +616,6 @@ public static ReactorInstance createMainReactorInstance( } else { targetConfig .compileDefinitions - .get() .put("LF_REACTION_GRAPH_BREADTH", String.valueOf(reactionInstanceGraph.getBreadth())); } return main; diff --git a/core/src/main/java/org/lflang/federated/extensions/CExtensionUtils.java b/core/src/main/java/org/lflang/federated/extensions/CExtensionUtils.java index 7712093240..6ba7320b09 100644 --- a/core/src/main/java/org/lflang/federated/extensions/CExtensionUtils.java +++ b/core/src/main/java/org/lflang/federated/extensions/CExtensionUtils.java @@ -54,14 +54,14 @@ public static String initializeTriggersForNetworkActions( var trigger = CUtil.actionRef(actionInstance, null); code.pr( "_lf_action_table[" - + (actionTableCount++) + + actionTableCount++ + "] = (lf_action_base_t*)&" + trigger + "; \\"); if (federate.zeroDelayNetworkMessageActions.contains(action)) { code.pr( "_lf_zero_delay_action_table[" - + (zeroDelayActionTableCount++) + + zeroDelayActionTableCount++ + "] = (lf_action_base_t*)&" + trigger + "; \\"); @@ -114,7 +114,7 @@ public static String stpStructs(FederateInstance federate) { "staa_lst[" + i + "]->actions[" - + (tableCount++) + + tableCount++ + "] = _lf_action_table[" + federate.networkMessageActions.indexOf(action) + "];"); @@ -173,16 +173,16 @@ public static void handleCompileDefinitions( RtiConfig rtiConfig, MessageReporter messageReporter) { var definitions = federate.targetConfig.compileDefinitions; - definitions.add("FEDERATED", ""); - definitions.add( + definitions.put("FEDERATED", ""); + definitions.put( String.format( "FEDERATED_%s", federate.targetConfig.coordination.get().toString().toUpperCase()), ""); if (federate.targetConfig.auth.get()) { - definitions.add("FEDERATED_AUTHENTICATED", ""); + definitions.put("FEDERATED_AUTHENTICATED", ""); } - definitions.add("NUMBER_OF_FEDERATES", String.valueOf(numOfFederates)); - definitions.add("EXECUTABLE_PREAMBLE", ""); + definitions.put("NUMBER_OF_FEDERATES", String.valueOf(numOfFederates)); + definitions.put("EXECUTABLE_PREAMBLE", ""); handleAdvanceMessageInterval(federate); @@ -197,7 +197,6 @@ private static void handleAdvanceMessageInterval(FederateInstance federate) { federate .targetConfig .compileDefinitions - .get() .put("ADVANCE_MESSAGE_INTERVAL", String.valueOf(advanceMessageInterval.toNanoSeconds())); } } @@ -253,27 +252,24 @@ public static void addClockSyncCompileDefinitions(FederateInstance federate) { ClockSyncMode mode = federate.targetConfig.clockSync.get(); ClockSyncOptions options = federate.targetConfig.clockSyncOptions.get(); - federate.targetConfig.compileDefinitions.get().put("_LF_CLOCK_SYNC_INITIAL", ""); + federate.targetConfig.compileDefinitions.put("_LF_CLOCK_SYNC_INITIAL", ""); federate .targetConfig .compileDefinitions - .get() .put("_LF_CLOCK_SYNC_PERIOD_NS", String.valueOf(options.period.toNanoSeconds())); federate .targetConfig .compileDefinitions - .get() .put("_LF_CLOCK_SYNC_EXCHANGES_PER_INTERVAL", String.valueOf(options.trials)); federate .targetConfig .compileDefinitions - .get() .put("_LF_CLOCK_SYNC_ATTENUATION", String.valueOf(options.attenuation)); if (mode == ClockSyncMode.ON) { - federate.targetConfig.compileDefinitions.get().put("_LF_CLOCK_SYNC_ON", ""); + federate.targetConfig.compileDefinitions.put("_LF_CLOCK_SYNC_ON", ""); if (options.collectStats) { - federate.targetConfig.compileDefinitions.get().put("_LF_CLOCK_SYNC_COLLECT_STATS", ""); + federate.targetConfig.compileDefinitions.put("_LF_CLOCK_SYNC_COLLECT_STATS", ""); } } } diff --git a/core/src/main/java/org/lflang/target/property/CompileDefinitionsProperty.java b/core/src/main/java/org/lflang/target/property/CompileDefinitionsProperty.java index 584091d15c..a754b2ce4a 100644 --- a/core/src/main/java/org/lflang/target/property/CompileDefinitionsProperty.java +++ b/core/src/main/java/org/lflang/target/property/CompileDefinitionsProperty.java @@ -17,7 +17,7 @@ public CompileDefinitionsProperty() { super(StringDictionaryType.COMPILE_DEFINITION); } - public void add(String k, String v) { + public void put(String k, String v) { this.isSet = true; var value = this.get(); value.put(k, v); From 1ec7765f3e80e50e051a11b63a8167917b54daff Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Sun, 1 Oct 2023 00:00:11 -0700 Subject: [PATCH 036/145] Apply formatter --- .../main/java/org/lflang/ast/ASTUtils.java | 5 ++-- .../federated/extensions/CExtensionUtils.java | 24 +++++++------------ 2 files changed, 10 insertions(+), 19 deletions(-) diff --git a/core/src/main/java/org/lflang/ast/ASTUtils.java b/core/src/main/java/org/lflang/ast/ASTUtils.java index 623ec24e23..d30dae6189 100644 --- a/core/src/main/java/org/lflang/ast/ASTUtils.java +++ b/core/src/main/java/org/lflang/ast/ASTUtils.java @@ -614,9 +614,8 @@ public static ReactorInstance createMainReactorInstance( if (breadth == 0) { messageReporter.nowhere().warning("The program has no reactions"); } else { - targetConfig - .compileDefinitions - .put("LF_REACTION_GRAPH_BREADTH", String.valueOf(reactionInstanceGraph.getBreadth())); + targetConfig.compileDefinitions.put( + "LF_REACTION_GRAPH_BREADTH", String.valueOf(reactionInstanceGraph.getBreadth())); } return main; } diff --git a/core/src/main/java/org/lflang/federated/extensions/CExtensionUtils.java b/core/src/main/java/org/lflang/federated/extensions/CExtensionUtils.java index 6ba7320b09..db0cb2d0b4 100644 --- a/core/src/main/java/org/lflang/federated/extensions/CExtensionUtils.java +++ b/core/src/main/java/org/lflang/federated/extensions/CExtensionUtils.java @@ -194,10 +194,8 @@ private static void handleAdvanceMessageInterval(FederateInstance federate) { federate.targetConfig.coordinationOptions.get().advanceMessageInterval; federate.targetConfig.coordinationOptions.reset(); if (advanceMessageInterval != null) { - federate - .targetConfig - .compileDefinitions - .put("ADVANCE_MESSAGE_INTERVAL", String.valueOf(advanceMessageInterval.toNanoSeconds())); + federate.targetConfig.compileDefinitions.put( + "ADVANCE_MESSAGE_INTERVAL", String.valueOf(advanceMessageInterval.toNanoSeconds())); } } @@ -253,18 +251,12 @@ public static void addClockSyncCompileDefinitions(FederateInstance federate) { ClockSyncOptions options = federate.targetConfig.clockSyncOptions.get(); federate.targetConfig.compileDefinitions.put("_LF_CLOCK_SYNC_INITIAL", ""); - federate - .targetConfig - .compileDefinitions - .put("_LF_CLOCK_SYNC_PERIOD_NS", String.valueOf(options.period.toNanoSeconds())); - federate - .targetConfig - .compileDefinitions - .put("_LF_CLOCK_SYNC_EXCHANGES_PER_INTERVAL", String.valueOf(options.trials)); - federate - .targetConfig - .compileDefinitions - .put("_LF_CLOCK_SYNC_ATTENUATION", String.valueOf(options.attenuation)); + federate.targetConfig.compileDefinitions.put( + "_LF_CLOCK_SYNC_PERIOD_NS", String.valueOf(options.period.toNanoSeconds())); + federate.targetConfig.compileDefinitions.put( + "_LF_CLOCK_SYNC_EXCHANGES_PER_INTERVAL", String.valueOf(options.trials)); + federate.targetConfig.compileDefinitions.put( + "_LF_CLOCK_SYNC_ATTENUATION", String.valueOf(options.attenuation)); if (mode == ClockSyncMode.ON) { federate.targetConfig.compileDefinitions.put("_LF_CLOCK_SYNC_ON", ""); From 881b4d6e9c84bbd7b030ad85238a64391a4383fe Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Sun, 1 Oct 2023 01:10:23 -0700 Subject: [PATCH 037/145] Bugfix --- .../main/java/org/lflang/AbstractTargetProperty.java | 2 +- core/src/main/java/org/lflang/TargetProperty.java | 10 +++++++--- .../main/java/org/lflang/validation/LFValidator.java | 7 +++++-- .../tests/compiler/LinguaFrancaValidationTest.java | 4 ++-- 4 files changed, 15 insertions(+), 8 deletions(-) diff --git a/core/src/main/java/org/lflang/AbstractTargetProperty.java b/core/src/main/java/org/lflang/AbstractTargetProperty.java index 2ed2ebb752..03a7e7d305 100644 --- a/core/src/main/java/org/lflang/AbstractTargetProperty.java +++ b/core/src/main/java/org/lflang/AbstractTargetProperty.java @@ -52,7 +52,7 @@ public void checkSupport(KeyValuePair pair, Target target, MessageReporter repor .at(pair, Literals.KEY_VALUE_PAIR__NAME) .warning( String.format( - "The target parameter: %s is not supported by the %s target and will thus be" + "The target property: %s is not supported by the %s target and will thus be" + " ignored.", pair.getName(), target)); } diff --git a/core/src/main/java/org/lflang/TargetProperty.java b/core/src/main/java/org/lflang/TargetProperty.java index c2e948da6b..e3deb50a3f 100644 --- a/core/src/main/java/org/lflang/TargetProperty.java +++ b/core/src/main/java/org/lflang/TargetProperty.java @@ -395,7 +395,11 @@ public static KeyValuePair getKeyValuePair(Model ast, TargetProperty property) { /** Return a list containing the keys of all properties */ public static List getPropertyKeys() { - return Arrays.stream(TargetProperty.values()).map(TargetProperty::toString).toList(); + return Arrays.stream(TargetProperty.values()) + .map(TargetProperty::toString) + .filter(it -> !it.startsWith("_")) + .sorted() + .toList(); } /** @@ -424,9 +428,9 @@ public static void validate( reporter .at(pair, Literals.KEY_VALUE_PAIR__NAME) .warning( - "Unrecognized target parameter: " + "Unrecognized target property: " + pair.getName() - + ". Recognized parameters are: " + + ". Recognized properties are: " + getPropertyKeys()); } }); diff --git a/core/src/main/java/org/lflang/validation/LFValidator.java b/core/src/main/java/org/lflang/validation/LFValidator.java index 2f0faf28a2..51701ed7a0 100644 --- a/core/src/main/java/org/lflang/validation/LFValidator.java +++ b/core/src/main/java/org/lflang/validation/LFValidator.java @@ -1074,8 +1074,11 @@ public void checkTargetDecl(TargetDecl target) throws IOException { */ @Check(CheckType.NORMAL) public void checkTargetProperties(KeyValuePairs targetProperties) { - TargetProperty.validate( - targetProperties, this.info.model, new TargetConfig(this.target), getErrorReporter()); + if (targetProperties.eContainer() instanceof TargetDecl) { + // Only validate the target properties, not dictionaries that may be part of their values. + TargetProperty.validate( + targetProperties, this.info.model, new TargetConfig(this.target), getErrorReporter()); + } } @Check(CheckType.FAST) 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 2762d360c9..3240677a07 100644 --- a/core/src/test/java/org/lflang/tests/compiler/LinguaFrancaValidationTest.java +++ b/core/src/test/java/org/lflang/tests/compiler/LinguaFrancaValidationTest.java @@ -1810,7 +1810,7 @@ public void testInvalidTargetParam() throws Exception { List issues = validator.validate(parseWithoutError(testCase)); Assertions.assertTrue( issues.size() == 1 - && issues.get(0).getMessage().contains("Unrecognized target parameter: foobarbaz")); + && issues.get(0).getMessage().contains("Unrecognized target property: foobarbaz")); } @Test @@ -1827,7 +1827,7 @@ public void testTargetParamNotSupportedForTarget() throws Exception { .get(0) .getMessage() .contains( - "The target parameter: build" + "The target property: build" + " is not supported by the Python target and will thus be ignored.")); } From 5194bf1ed2b62cf3ad0d17e1ca5c4042de88033e Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Sun, 1 Oct 2023 16:36:04 -0700 Subject: [PATCH 038/145] Fix another mysterious federated execution bug --- .../java/org/lflang/federated/extensions/CExtension.java | 6 ++++-- .../org/lflang/federated/extensions/CExtensionUtils.java | 1 - 2 files changed, 4 insertions(+), 3 deletions(-) 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 f5de233de4..fcec922584 100644 --- a/core/src/main/java/org/lflang/federated/extensions/CExtension.java +++ b/core/src/main/java/org/lflang/federated/extensions/CExtension.java @@ -796,7 +796,9 @@ private String generateCodeToInitializeFederate(FederateInstance federate, RtiCo private String generateCodeForPhysicalActions( FederateInstance federate, MessageReporter messageReporter) { CodeBuilder code = new CodeBuilder(); - if (federate.targetConfig.coordination.equals(CoordinationMode.CENTRALIZED)) { + var coordinationMode = federate.targetConfig.coordination.get(); + var coordinationOptions = federate.targetConfig.coordinationOptions.get(); + if (coordinationMode.equals(CoordinationMode.CENTRALIZED)) { // If this program uses centralized coordination then check // for outputs that depend on physical actions so that null messages can be // sent to the RTI. @@ -819,7 +821,7 @@ private String generateCodeForPhysicalActions( } if (minDelay != TimeValue.MAX_VALUE) { // Unless silenced, issue a warning. - if (federate.targetConfig.coordinationOptions.get().advanceMessageInterval == null) { + if (coordinationOptions.advanceMessageInterval == null) { String message = String.join( "\n", diff --git a/core/src/main/java/org/lflang/federated/extensions/CExtensionUtils.java b/core/src/main/java/org/lflang/federated/extensions/CExtensionUtils.java index db0cb2d0b4..4cc93c2258 100644 --- a/core/src/main/java/org/lflang/federated/extensions/CExtensionUtils.java +++ b/core/src/main/java/org/lflang/federated/extensions/CExtensionUtils.java @@ -192,7 +192,6 @@ public static void handleCompileDefinitions( private static void handleAdvanceMessageInterval(FederateInstance federate) { var advanceMessageInterval = federate.targetConfig.coordinationOptions.get().advanceMessageInterval; - federate.targetConfig.coordinationOptions.reset(); if (advanceMessageInterval != null) { federate.targetConfig.compileDefinitions.put( "ADVANCE_MESSAGE_INTERVAL", String.valueOf(advanceMessageInterval.toNanoSeconds())); From ba8b4d4e688b5e2b79b45f15cc6897aec8801a91 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Sun, 1 Oct 2023 22:01:05 -0700 Subject: [PATCH 039/145] Typo fixes and address warning --- .../diagram/synthesis/styles/LinguaFrancaShapeExtensions.java | 2 +- .../diagram/synthesis/styles/LinguaFrancaStyleExtensions.java | 2 +- .../kotlin/org/lflang/generator/rust/RustMainFileEmitter.kt | 2 +- test/README.md | 2 +- test/Rust/src/concurrent/Workers.lf | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/core/src/main/java/org/lflang/diagram/synthesis/styles/LinguaFrancaShapeExtensions.java b/core/src/main/java/org/lflang/diagram/synthesis/styles/LinguaFrancaShapeExtensions.java index 37e82250ea..6fdd158890 100644 --- a/core/src/main/java/org/lflang/diagram/synthesis/styles/LinguaFrancaShapeExtensions.java +++ b/core/src/main/java/org/lflang/diagram/synthesis/styles/LinguaFrancaShapeExtensions.java @@ -85,7 +85,7 @@ import org.lflang.lf.StateVar; /** - * Extension class that provides shapes and figures for the Lingua France diagram synthesis. + * Extension class that provides shapes and figures for the Lingua Franca diagram synthesis. * * @author Alexander Schulz-Rosengarten */ diff --git a/core/src/main/java/org/lflang/diagram/synthesis/styles/LinguaFrancaStyleExtensions.java b/core/src/main/java/org/lflang/diagram/synthesis/styles/LinguaFrancaStyleExtensions.java index 6eb2cfd7f0..1973738d5a 100644 --- a/core/src/main/java/org/lflang/diagram/synthesis/styles/LinguaFrancaStyleExtensions.java +++ b/core/src/main/java/org/lflang/diagram/synthesis/styles/LinguaFrancaStyleExtensions.java @@ -59,7 +59,7 @@ import org.lflang.diagram.synthesis.AbstractSynthesisExtensions; /** - * Extension class that provides styles and coloring for the Lingua France diagram synthesis. + * Extension class that provides styles and coloring for the Lingua Franca diagram synthesis. * * @author Alexander Schulz-Rosengarten */ diff --git a/core/src/main/kotlin/org/lflang/generator/rust/RustMainFileEmitter.kt b/core/src/main/kotlin/org/lflang/generator/rust/RustMainFileEmitter.kt index fb54556a2c..69c6fd0ccb 100644 --- a/core/src/main/kotlin/org/lflang/generator/rust/RustMainFileEmitter.kt +++ b/core/src/main/kotlin/org/lflang/generator/rust/RustMainFileEmitter.kt @@ -81,7 +81,7 @@ ${" |"..gen.crate.modulesToIncludeInMain.joinWithLn { "mod ${it.fileName | if !cfg!(debug_assertions) && level < LevelFilter::Info { | warn!("Log level {} is not active because this application was built in release mode.", level); | warn!("Use a debug build to enable this level."); - | warn!("In Lingua France, use the target property `build-type: Debug` (the default)."); + | warn!("In Lingua Franca, use the target property `build-type: Debug` (the default)."); | } | | let mut builder = env_logger::Builder::from_env(env_logger::Env::default()); diff --git a/test/README.md b/test/README.md index 2292f25320..52e647c72a 100644 --- a/test/README.md +++ b/test/README.md @@ -1,6 +1,6 @@ # LF integration tests -**Integration tests** are complete Lingua France programs that are compiled and executed automatically. A test passes if it successfully compiles and runs to completion with normal termination (return code 0). These tests are located in a subdirectory corresponding to their target language. +**Integration tests** are complete Lingua Franca programs that are compiled and executed automatically. A test passes if it successfully compiles and runs to completion with normal termination (return code 0). These tests are located in a subdirectory corresponding to their target language. ### Running from the command line diff --git a/test/Rust/src/concurrent/Workers.lf b/test/Rust/src/concurrent/Workers.lf index 9f2afa1f43..69157f5927 100644 --- a/test/Rust/src/concurrent/Workers.lf +++ b/test/Rust/src/concurrent/Workers.lf @@ -4,7 +4,7 @@ target Rust { main reactor { reaction(startup) {= - if (ctx.num_workers() != 16) { + if ctx.num_workers() != 16 { panic!("Expected to have 16 workers."); } else { println!("Using 16 workers."); From 1dfa337520a242036a19b521c1bdad07d251b94f Mon Sep 17 00:00:00 2001 From: Shaokai Lin Date: Sun, 1 Oct 2023 22:47:25 -0700 Subject: [PATCH 040/145] Fix state space explorer --- .../analyses/statespace/StateSpaceExplorer.java | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/core/src/main/java/org/lflang/analyses/statespace/StateSpaceExplorer.java b/core/src/main/java/org/lflang/analyses/statespace/StateSpaceExplorer.java index 40f4a521ea..6b869e7ebd 100644 --- a/core/src/main/java/org/lflang/analyses/statespace/StateSpaceExplorer.java +++ b/core/src/main/java/org/lflang/analyses/statespace/StateSpaceExplorer.java @@ -4,7 +4,6 @@ import java.util.HashMap; import java.util.HashSet; import java.util.Set; -import java.util.stream.Collectors; import org.lflang.TimeUnit; import org.lflang.TimeValue; import org.lflang.generator.ActionInstance; @@ -101,12 +100,11 @@ public void explore(Tag horizon, boolean findLoop) { while (!stop) { // Pop the events from the earliest tag off the event queue. - - final var now = currentTag; - var currentEvents = - eventQ.stream() - .filter(e -> e.getTag().equals(now)) - .collect(Collectors.toCollection(ArrayList::new)); + ArrayList currentEvents = new ArrayList(); + while (eventQ.size() > 0 && eventQ.peek().getTag().compareTo(currentTag) == 0) { + Event e = eventQ.poll(); + currentEvents.add(e); + } // Collect all the reactions invoked in this current LOOP ITERATION // triggered by the earliest events. From 8e4feee8073cd924d52ae5e786fc9049ddc91446 Mon Sep 17 00:00:00 2001 From: Christian Menard Date: Mon, 2 Oct 2023 10:43:12 +0200 Subject: [PATCH 041/145] Fix rust tests --- .../main/kotlin/org/lflang/generator/rust/RustGenerator.kt | 2 +- .../src/main/kotlin/org/lflang/generator/rust/RustModel.kt | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/core/src/main/kotlin/org/lflang/generator/rust/RustGenerator.kt b/core/src/main/kotlin/org/lflang/generator/rust/RustGenerator.kt index 0c11c1538e..3ea93a72e1 100644 --- a/core/src/main/kotlin/org/lflang/generator/rust/RustGenerator.kt +++ b/core/src/main/kotlin/org/lflang/generator/rust/RustGenerator.kt @@ -127,7 +127,7 @@ class RustGenerator( // We still have to copy the compiled binary to the destination folder. val buildType = targetConfig.rust.getBuildType(context.targetConfig.buildType) val binaryPath = validator.metadata?.targetDirectory!! - .resolve(buildType.cargoProfileName) + .resolve(buildType.cargoTargetDirectory) .resolve(fileConfig.executable.fileName) val destPath = fileConfig.executable 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 f0fbf1ad10..6a2370d09b 100644 --- a/core/src/main/kotlin/org/lflang/generator/rust/RustModel.kt +++ b/core/src/main/kotlin/org/lflang/generator/rust/RustModel.kt @@ -721,6 +721,13 @@ val BuildType.cargoProfileName: String BuildType.MIN_SIZE_REL -> "release-with-min-size" } +/** Return the target directory in which cargo places the compiled binary. */ +val BuildType.cargoTargetDirectory: String + get() = when (this) { + BuildType.TEST -> "debug" + else -> cargoProfileName + } + /** Just the constructor of [CargoDependencySpec], but allows using named arguments. */ fun newCargoSpec( version: String? = null, From f0b81868cd6015eaee6e7ada9dec2883fda4def5 Mon Sep 17 00:00:00 2001 From: Christian Menard Date: Mon, 2 Oct 2023 11:33:49 +0200 Subject: [PATCH 042/145] fix Cpp build types --- .../org/lflang/generator/cpp/CppStandaloneGenerator.kt | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/core/src/main/kotlin/org/lflang/generator/cpp/CppStandaloneGenerator.kt b/core/src/main/kotlin/org/lflang/generator/cpp/CppStandaloneGenerator.kt index b7c9bd8982..6eda39d7b4 100644 --- a/core/src/main/kotlin/org/lflang/generator/cpp/CppStandaloneGenerator.kt +++ b/core/src/main/kotlin/org/lflang/generator/cpp/CppStandaloneGenerator.kt @@ -130,18 +130,12 @@ class CppStandaloneGenerator(generator: CppGenerator) : return 0 } - private fun buildTypeToCmakeConfig(type: BuildType?) = when (type) { - null -> "Release" - BuildType.TEST -> "Debug" - else -> type.toString() - } - private fun createMakeCommand(buildPath: Path, version: String, target: String): LFCommand { val makeArgs: List if (version.compareVersion("3.12.0") < 0) { messageReporter.nowhere().warning("CMAKE is older than version 3.12. Parallel building is not supported.") makeArgs = - listOf("--build", ".", "--target", target, "--config", targetConfig.buildType?.toString() ?: "Release") + listOf("--build", ".", "--target", target, "--config", targetConfig.buildType.toString()) } else { val cores = Runtime.getRuntime().availableProcessors() makeArgs = listOf( @@ -152,7 +146,7 @@ class CppStandaloneGenerator(generator: CppGenerator) : "--parallel", cores.toString(), "--config", - buildTypeToCmakeConfig(targetConfig.buildType.get()) + targetConfig.buildType.toString() ) } From 1a31e115a8df14b859d770d899469bccfc445dfc Mon Sep 17 00:00:00 2001 From: Christian Menard Date: Mon, 2 Oct 2023 11:34:02 +0200 Subject: [PATCH 043/145] fix test reports --- core/src/testFixtures/java/org/lflang/tests/LFTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/testFixtures/java/org/lflang/tests/LFTest.java b/core/src/testFixtures/java/org/lflang/tests/LFTest.java index 1fa4184237..cb92de3663 100644 --- a/core/src/testFixtures/java/org/lflang/tests/LFTest.java +++ b/core/src/testFixtures/java/org/lflang/tests/LFTest.java @@ -258,9 +258,9 @@ private Thread recordStream(StringBuffer builder, InputStream inputStream) { int len; char[] buf = new char[1024]; while ((len = reader.read(buf)) > 0) { - if (Runtime.getRuntime().freeMemory() < Runtime.getRuntime().totalMemory() / 2) { + if (Runtime.getRuntime().freeMemory() < Runtime.getRuntime().maxMemory() / 2) { builder.delete(0, builder.length() / 2); - builder.insert(0, "[earlier messages were removed to free up memory]%n"); + builder.insert(0, "[earlier messages were removed to free up memory]\n"); } builder.append(buf, 0, len); } From caa3bd87d38849ec34bb128f1234052881008ae4 Mon Sep 17 00:00:00 2001 From: Christian Menard Date: Mon, 2 Oct 2023 11:38:52 +0200 Subject: [PATCH 044/145] map the Test build type to the debug cargo profile --- .../kotlin/org/lflang/generator/rust/RustGenerator.kt | 2 +- .../main/kotlin/org/lflang/generator/rust/RustModel.kt | 9 +-------- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/core/src/main/kotlin/org/lflang/generator/rust/RustGenerator.kt b/core/src/main/kotlin/org/lflang/generator/rust/RustGenerator.kt index 3ea93a72e1..0c11c1538e 100644 --- a/core/src/main/kotlin/org/lflang/generator/rust/RustGenerator.kt +++ b/core/src/main/kotlin/org/lflang/generator/rust/RustGenerator.kt @@ -127,7 +127,7 @@ class RustGenerator( // We still have to copy the compiled binary to the destination folder. val buildType = targetConfig.rust.getBuildType(context.targetConfig.buildType) val binaryPath = validator.metadata?.targetDirectory!! - .resolve(buildType.cargoTargetDirectory) + .resolve(buildType.cargoProfileName) .resolve(fileConfig.executable.fileName) val destPath = fileConfig.executable 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 6a2370d09b..12a17e84c6 100644 --- a/core/src/main/kotlin/org/lflang/generator/rust/RustModel.kt +++ b/core/src/main/kotlin/org/lflang/generator/rust/RustModel.kt @@ -715,19 +715,12 @@ private val TypeParm.identifier: String val BuildType.cargoProfileName: String get() = when (this) { BuildType.DEBUG -> "debug" - BuildType.TEST -> "test" + BuildType.TEST -> "debug" // The LF build type "Test" requires a debug build BuildType.RELEASE -> "release" BuildType.REL_WITH_DEB_INFO -> "release-with-debug-info" BuildType.MIN_SIZE_REL -> "release-with-min-size" } -/** Return the target directory in which cargo places the compiled binary. */ -val BuildType.cargoTargetDirectory: String - get() = when (this) { - BuildType.TEST -> "debug" - else -> cargoProfileName - } - /** Just the constructor of [CargoDependencySpec], but allows using named arguments. */ fun newCargoSpec( version: String? = null, From 27a310b0529e745dbf06a946a5cbf1d6a2e72749 Mon Sep 17 00:00:00 2001 From: Christian Menard Date: Mon, 2 Oct 2023 11:48:18 +0200 Subject: [PATCH 045/145] move TargetProperty to org.lflang.target --- .../org/lflang/federated/generator/FedTargetConfig.java | 2 +- .../org/lflang/federated/generator/FedTargetEmitter.java | 2 +- .../lflang/federated/launcher/FedLauncherGenerator.java | 2 +- .../src/main/java/org/lflang/generator/GeneratorUtils.java | 2 +- .../org/lflang/generator/rust/CargoDependencySpec.java | 2 +- core/src/main/java/org/lflang/target/TargetConfig.java | 1 - .../main/java/org/lflang/{ => target}/TargetProperty.java | 7 +++++-- .../java/org/lflang/target/property/PlatformProperty.java | 2 +- .../lflang/target/property/Ros2DependenciesProperty.java | 2 +- .../java/org/lflang/target/property/TracingProperty.java | 2 +- core/src/main/java/org/lflang/validation/LFValidator.java | 2 +- .../lflang/tests/compiler/LinguaFrancaValidationTest.java | 2 +- 12 files changed, 15 insertions(+), 13 deletions(-) rename core/src/main/java/org/lflang/{ => target}/TargetProperty.java (99%) diff --git a/core/src/main/java/org/lflang/federated/generator/FedTargetConfig.java b/core/src/main/java/org/lflang/federated/generator/FedTargetConfig.java index aa0a054907..645a6ba4e8 100644 --- a/core/src/main/java/org/lflang/federated/generator/FedTargetConfig.java +++ b/core/src/main/java/org/lflang/federated/generator/FedTargetConfig.java @@ -5,7 +5,7 @@ import java.nio.file.Path; import org.eclipse.emf.ecore.resource.Resource; import org.lflang.MessageReporter; -import org.lflang.TargetProperty; +import org.lflang.target.TargetProperty; import org.lflang.generator.GeneratorUtils; import org.lflang.generator.LFGeneratorContext; import org.lflang.target.TargetConfig; diff --git a/core/src/main/java/org/lflang/federated/generator/FedTargetEmitter.java b/core/src/main/java/org/lflang/federated/generator/FedTargetEmitter.java index 2e9b26a7ff..c298f970f1 100644 --- a/core/src/main/java/org/lflang/federated/generator/FedTargetEmitter.java +++ b/core/src/main/java/org/lflang/federated/generator/FedTargetEmitter.java @@ -2,7 +2,7 @@ import java.io.IOException; import org.lflang.MessageReporter; -import org.lflang.TargetProperty; +import org.lflang.target.TargetProperty; import org.lflang.ast.FormattingUtil; import org.lflang.federated.extensions.FedTargetExtensionFactory; import org.lflang.federated.launcher.RtiConfig; diff --git a/core/src/main/java/org/lflang/federated/launcher/FedLauncherGenerator.java b/core/src/main/java/org/lflang/federated/launcher/FedLauncherGenerator.java index bc4ec28087..68517e3e98 100644 --- a/core/src/main/java/org/lflang/federated/launcher/FedLauncherGenerator.java +++ b/core/src/main/java/org/lflang/federated/launcher/FedLauncherGenerator.java @@ -7,7 +7,7 @@ * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * - * 2. Redistributions in binary formimport org.lflang.TargetProperty.ClockSyncMode; must reproduce the above copyright notice, + * 2. Redistributions in binary formimport org.lflang.target.TargetProperty.ClockSyncMode; must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * diff --git a/core/src/main/java/org/lflang/generator/GeneratorUtils.java b/core/src/main/java/org/lflang/generator/GeneratorUtils.java index e7f1c6b89c..08700ba9df 100644 --- a/core/src/main/java/org/lflang/generator/GeneratorUtils.java +++ b/core/src/main/java/org/lflang/generator/GeneratorUtils.java @@ -13,7 +13,7 @@ import org.lflang.FileConfig; import org.lflang.MessageReporter; import org.lflang.Target; -import org.lflang.TargetProperty; +import org.lflang.target.TargetProperty; import org.lflang.ast.ASTUtils; import org.lflang.generator.LFGeneratorContext.Mode; import org.lflang.lf.Action; diff --git a/core/src/main/java/org/lflang/generator/rust/CargoDependencySpec.java b/core/src/main/java/org/lflang/generator/rust/CargoDependencySpec.java index 50bf482024..82043e0c9d 100644 --- a/core/src/main/java/org/lflang/generator/rust/CargoDependencySpec.java +++ b/core/src/main/java/org/lflang/generator/rust/CargoDependencySpec.java @@ -33,7 +33,7 @@ import java.util.stream.Collectors; import org.eclipse.emf.ecore.EObject; import org.lflang.MessageReporter; -import org.lflang.TargetProperty; +import org.lflang.target.TargetProperty; import org.lflang.ast.ASTUtils; import org.lflang.generator.InvalidLfSourceException; import org.lflang.lf.Array; diff --git a/core/src/main/java/org/lflang/target/TargetConfig.java b/core/src/main/java/org/lflang/target/TargetConfig.java index 2347ccba62..31e46c0179 100644 --- a/core/src/main/java/org/lflang/target/TargetConfig.java +++ b/core/src/main/java/org/lflang/target/TargetConfig.java @@ -29,7 +29,6 @@ import java.util.Properties; import org.lflang.MessageReporter; import org.lflang.Target; -import org.lflang.TargetProperty; import org.lflang.generator.rust.RustTargetConfig; import org.lflang.lf.KeyValuePair; import org.lflang.lf.TargetDecl; diff --git a/core/src/main/java/org/lflang/TargetProperty.java b/core/src/main/java/org/lflang/target/TargetProperty.java similarity index 99% rename from core/src/main/java/org/lflang/TargetProperty.java rename to core/src/main/java/org/lflang/target/TargetProperty.java index e3deb50a3f..d398600f99 100644 --- a/core/src/main/java/org/lflang/TargetProperty.java +++ b/core/src/main/java/org/lflang/target/TargetProperty.java @@ -23,7 +23,7 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ***************/ -package org.lflang; +package org.lflang.target; import java.nio.file.Path; import java.util.Arrays; @@ -32,6 +32,10 @@ import java.util.Objects; import java.util.Properties; import java.util.stream.Collectors; + +import org.lflang.AbstractTargetProperty; +import org.lflang.MessageReporter; +import org.lflang.Target; import org.lflang.ast.ASTUtils; import org.lflang.generator.InvalidLfSourceException; import org.lflang.lf.KeyValuePair; @@ -40,7 +44,6 @@ import org.lflang.lf.LfPackage.Literals; import org.lflang.lf.Model; import org.lflang.lf.TargetDecl; -import org.lflang.target.TargetConfig; import org.lflang.target.property.AuthProperty; import org.lflang.target.property.BuildCommandsProperty; import org.lflang.target.property.BuildTypeProperty; 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 3087a72c66..22b6b1ddbd 100644 --- a/core/src/main/java/org/lflang/target/property/PlatformProperty.java +++ b/core/src/main/java/org/lflang/target/property/PlatformProperty.java @@ -5,7 +5,7 @@ import org.lflang.AbstractTargetProperty; import org.lflang.MessageReporter; import org.lflang.Target; -import org.lflang.TargetProperty; +import org.lflang.target.TargetProperty; import org.lflang.ast.ASTUtils; import org.lflang.lf.Element; import org.lflang.lf.KeyValuePair; 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 4545b64c5c..73e2d0ffd4 100644 --- a/core/src/main/java/org/lflang/target/property/Ros2DependenciesProperty.java +++ b/core/src/main/java/org/lflang/target/property/Ros2DependenciesProperty.java @@ -5,7 +5,7 @@ import org.lflang.AbstractTargetProperty; import org.lflang.MessageReporter; import org.lflang.Target; -import org.lflang.TargetProperty; +import org.lflang.target.TargetProperty; import org.lflang.ast.ASTUtils; import org.lflang.lf.Element; import org.lflang.lf.KeyValuePair; 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 314e989868..50fb92afc9 100644 --- a/core/src/main/java/org/lflang/target/property/TracingProperty.java +++ b/core/src/main/java/org/lflang/target/property/TracingProperty.java @@ -5,7 +5,7 @@ import org.lflang.AbstractTargetProperty; import org.lflang.MessageReporter; import org.lflang.Target; -import org.lflang.TargetProperty; +import org.lflang.target.TargetProperty; import org.lflang.ast.ASTUtils; import org.lflang.lf.Element; import org.lflang.lf.KeyValuePair; diff --git a/core/src/main/java/org/lflang/validation/LFValidator.java b/core/src/main/java/org/lflang/validation/LFValidator.java index 51701ed7a0..56609e18b0 100644 --- a/core/src/main/java/org/lflang/validation/LFValidator.java +++ b/core/src/main/java/org/lflang/validation/LFValidator.java @@ -59,7 +59,7 @@ import org.lflang.InferredType; import org.lflang.ModelInfo; import org.lflang.Target; -import org.lflang.TargetProperty; +import org.lflang.target.TargetProperty; import org.lflang.TimeValue; import org.lflang.ast.ASTUtils; import org.lflang.federated.serialization.SupportedSerializers; 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 3240677a07..a8a9a6eec2 100644 --- a/core/src/test/java/org/lflang/tests/compiler/LinguaFrancaValidationTest.java +++ b/core/src/test/java/org/lflang/tests/compiler/LinguaFrancaValidationTest.java @@ -45,7 +45,7 @@ import org.junit.jupiter.api.TestFactory; import org.junit.jupiter.api.extension.ExtendWith; import org.lflang.Target; -import org.lflang.TargetProperty; +import org.lflang.target.TargetProperty; import org.lflang.TimeValue; import org.lflang.lf.LfPackage; import org.lflang.lf.Model; From be85c7d8334c1d3d64695574d744b9ecedf3a542 Mon Sep 17 00:00:00 2001 From: Christian Menard Date: Mon, 2 Oct 2023 13:33:37 +0200 Subject: [PATCH 046/145] unify handling of C++ target properties --- .../kotlin/org/lflang/generator/cpp/CppRos2NodeGenerator.kt | 2 +- .../org/lflang/generator/cpp/CppStandaloneMainGenerator.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/main/kotlin/org/lflang/generator/cpp/CppRos2NodeGenerator.kt b/core/src/main/kotlin/org/lflang/generator/cpp/CppRos2NodeGenerator.kt index 15c523e4f8..e117a11b5a 100644 --- a/core/src/main/kotlin/org/lflang/generator/cpp/CppRos2NodeGenerator.kt +++ b/core/src/main/kotlin/org/lflang/generator/cpp/CppRos2NodeGenerator.kt @@ -59,7 +59,7 @@ class CppRos2NodeGenerator( | : Node("$nodeName", node_options) { | unsigned workers = ${if (targetConfig.workers.get() != 0) targetConfig.workers.get() else "std::thread::hardware_concurrency()"}; | bool fast{${targetConfig.fastMode}}; - | reactor::Duration lf_timeout{${targetConfig.timeout.get()?.toCppCode() ?: "reactor::Duration::max()"}}; + | reactor::Duration lf_timeout{${if (targetConfig.timeout.isSet) targetConfig.timeout.get().toCppCode() else "reactor::Duration::max()"}}; | | // provide a globally accessible reference to this node | // FIXME: this is pretty hacky... diff --git a/core/src/main/kotlin/org/lflang/generator/cpp/CppStandaloneMainGenerator.kt b/core/src/main/kotlin/org/lflang/generator/cpp/CppStandaloneMainGenerator.kt index 0504be555c..9fb16455fe 100644 --- a/core/src/main/kotlin/org/lflang/generator/cpp/CppStandaloneMainGenerator.kt +++ b/core/src/main/kotlin/org/lflang/generator/cpp/CppStandaloneMainGenerator.kt @@ -58,7 +58,7 @@ class CppStandaloneMainGenerator( |int main(int argc, char **argv) { | cxxopts::Options options("${fileConfig.name}", "Reactor Program"); | - | unsigned workers = ${if (targetConfig.workers.isSet) targetConfig.workers.get() else "std::thread::hardware_concurrency()"}; + | unsigned workers = ${if (targetConfig.workers.get() != 0) targetConfig.workers.get() else "std::thread::hardware_concurrency()"}; | bool fast{${targetConfig.fastMode.get()}}; | reactor::Duration timeout = ${if (targetConfig.timeout.isSet) targetConfig.timeout.get().toCppCode() else "reactor::Duration::max()"}; | From aefe79f09e6192eac830b17ef678faf5ca7e9c10 Mon Sep 17 00:00:00 2001 From: Christian Menard Date: Mon, 2 Oct 2023 13:34:10 +0200 Subject: [PATCH 047/145] fix test reporting --- core/src/testFixtures/java/org/lflang/tests/LFTest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/src/testFixtures/java/org/lflang/tests/LFTest.java b/core/src/testFixtures/java/org/lflang/tests/LFTest.java index cb92de3663..fabe1fd695 100644 --- a/core/src/testFixtures/java/org/lflang/tests/LFTest.java +++ b/core/src/testFixtures/java/org/lflang/tests/LFTest.java @@ -258,9 +258,10 @@ private Thread recordStream(StringBuffer builder, InputStream inputStream) { int len; char[] buf = new char[1024]; while ((len = reader.read(buf)) > 0) { - if (Runtime.getRuntime().freeMemory() < Runtime.getRuntime().maxMemory() / 2) { + if (builder.length() > Runtime.getRuntime().maxMemory() / 4) { builder.delete(0, builder.length() / 2); builder.insert(0, "[earlier messages were removed to free up memory]\n"); + builder.trimToSize(); } builder.append(buf, 0, len); } From ae16b457518318f759b1d771aa19634a471c5f85 Mon Sep 17 00:00:00 2001 From: Christian Menard Date: Mon, 2 Oct 2023 13:37:57 +0200 Subject: [PATCH 048/145] fix "Test" build type for C++ on Windows --- .../org/lflang/generator/cpp/CppStandaloneGenerator.kt | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/core/src/main/kotlin/org/lflang/generator/cpp/CppStandaloneGenerator.kt b/core/src/main/kotlin/org/lflang/generator/cpp/CppStandaloneGenerator.kt index 6eda39d7b4..a64b29b88c 100644 --- a/core/src/main/kotlin/org/lflang/generator/cpp/CppStandaloneGenerator.kt +++ b/core/src/main/kotlin/org/lflang/generator/cpp/CppStandaloneGenerator.kt @@ -3,6 +3,7 @@ package org.lflang.generator.cpp import org.lflang.target.property.BuildTypeProperty.BuildType import org.lflang.generator.CodeMap import org.lflang.generator.LFGeneratorContext +import org.lflang.target.TargetProperty import org.lflang.toUnixString import org.lflang.util.FileUtil import org.lflang.util.LFCommand @@ -130,12 +131,17 @@ class CppStandaloneGenerator(generator: CppGenerator) : return 0 } + private fun buildTypeToCmakeConfig(type: BuildType) = when (type) { + BuildType.TEST -> "Debug" + else -> type.toString() + } + private fun createMakeCommand(buildPath: Path, version: String, target: String): LFCommand { val makeArgs: List if (version.compareVersion("3.12.0") < 0) { messageReporter.nowhere().warning("CMAKE is older than version 3.12. Parallel building is not supported.") makeArgs = - listOf("--build", ".", "--target", target, "--config", targetConfig.buildType.toString()) + listOf("--build", ".", "--target", target, "--config", buildTypeToCmakeConfig(targetConfig.buildType.get())) } else { val cores = Runtime.getRuntime().availableProcessors() makeArgs = listOf( @@ -146,7 +152,7 @@ class CppStandaloneGenerator(generator: CppGenerator) : "--parallel", cores.toString(), "--config", - targetConfig.buildType.toString() + buildTypeToCmakeConfig(targetConfig.buildType.get()) ) } From 0dce26aae0145cbc9637167886b0517c80fb78a4 Mon Sep 17 00:00:00 2001 From: Christian Menard Date: Mon, 2 Oct 2023 14:36:13 +0200 Subject: [PATCH 049/145] create a cargo profile for LF tests --- .../kotlin/org/lflang/generator/rust/RustCargoTomlEmitter.kt | 4 ++++ core/src/main/kotlin/org/lflang/generator/rust/RustModel.kt | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/core/src/main/kotlin/org/lflang/generator/rust/RustCargoTomlEmitter.kt b/core/src/main/kotlin/org/lflang/generator/rust/RustCargoTomlEmitter.kt index e7690e78e5..00749e17e9 100644 --- a/core/src/main/kotlin/org/lflang/generator/rust/RustCargoTomlEmitter.kt +++ b/core/src/main/kotlin/org/lflang/generator/rust/RustCargoTomlEmitter.kt @@ -74,6 +74,10 @@ ${" |"..crate.dependencies.asIterable().joinWithLn { (name, spec) -> nam |inherits = "release" |debug = true | + |[profile.${TEST.cargoProfileName}] # use `build-type: $TEST` + |inherits = "dev" + |debug = true + | """.trimMargin() } 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 12a17e84c6..5be75ace24 100644 --- a/core/src/main/kotlin/org/lflang/generator/rust/RustModel.kt +++ b/core/src/main/kotlin/org/lflang/generator/rust/RustModel.kt @@ -715,7 +715,7 @@ private val TypeParm.identifier: String val BuildType.cargoProfileName: String get() = when (this) { BuildType.DEBUG -> "debug" - BuildType.TEST -> "debug" // The LF build type "Test" requires a debug build + BuildType.TEST -> "lf-test" BuildType.RELEASE -> "release" BuildType.REL_WITH_DEB_INFO -> "release-with-debug-info" BuildType.MIN_SIZE_REL -> "release-with-min-size" From 845d32d9427b72c5d3185d739d1a633a0160b7da Mon Sep 17 00:00:00 2001 From: Christian Menard Date: Mon, 2 Oct 2023 14:37:09 +0200 Subject: [PATCH 050/145] formatting --- .../java/org/lflang/federated/generator/FedTargetConfig.java | 2 +- .../java/org/lflang/federated/generator/FedTargetEmitter.java | 2 +- core/src/main/java/org/lflang/generator/GeneratorUtils.java | 2 +- .../java/org/lflang/generator/rust/CargoDependencySpec.java | 2 +- core/src/main/java/org/lflang/target/TargetProperty.java | 1 - .../main/java/org/lflang/target/property/PlatformProperty.java | 2 +- .../org/lflang/target/property/Ros2DependenciesProperty.java | 2 +- .../main/java/org/lflang/target/property/TracingProperty.java | 2 +- core/src/main/java/org/lflang/validation/LFValidator.java | 2 +- .../org/lflang/tests/compiler/LinguaFrancaValidationTest.java | 2 +- 10 files changed, 9 insertions(+), 10 deletions(-) diff --git a/core/src/main/java/org/lflang/federated/generator/FedTargetConfig.java b/core/src/main/java/org/lflang/federated/generator/FedTargetConfig.java index 645a6ba4e8..7b468013cc 100644 --- a/core/src/main/java/org/lflang/federated/generator/FedTargetConfig.java +++ b/core/src/main/java/org/lflang/federated/generator/FedTargetConfig.java @@ -5,10 +5,10 @@ import java.nio.file.Path; import org.eclipse.emf.ecore.resource.Resource; import org.lflang.MessageReporter; -import org.lflang.target.TargetProperty; import org.lflang.generator.GeneratorUtils; import org.lflang.generator.LFGeneratorContext; import org.lflang.target.TargetConfig; +import org.lflang.target.TargetProperty; import org.lflang.util.FileUtil; /** diff --git a/core/src/main/java/org/lflang/federated/generator/FedTargetEmitter.java b/core/src/main/java/org/lflang/federated/generator/FedTargetEmitter.java index c298f970f1..bbfc16bfd2 100644 --- a/core/src/main/java/org/lflang/federated/generator/FedTargetEmitter.java +++ b/core/src/main/java/org/lflang/federated/generator/FedTargetEmitter.java @@ -2,11 +2,11 @@ import java.io.IOException; import org.lflang.MessageReporter; -import org.lflang.target.TargetProperty; import org.lflang.ast.FormattingUtil; import org.lflang.federated.extensions.FedTargetExtensionFactory; import org.lflang.federated.launcher.RtiConfig; import org.lflang.generator.LFGeneratorContext; +import org.lflang.target.TargetProperty; public class FedTargetEmitter { diff --git a/core/src/main/java/org/lflang/generator/GeneratorUtils.java b/core/src/main/java/org/lflang/generator/GeneratorUtils.java index 08700ba9df..9c4c1f0270 100644 --- a/core/src/main/java/org/lflang/generator/GeneratorUtils.java +++ b/core/src/main/java/org/lflang/generator/GeneratorUtils.java @@ -13,7 +13,6 @@ import org.lflang.FileConfig; import org.lflang.MessageReporter; import org.lflang.Target; -import org.lflang.target.TargetProperty; import org.lflang.ast.ASTUtils; import org.lflang.generator.LFGeneratorContext.Mode; import org.lflang.lf.Action; @@ -24,6 +23,7 @@ import org.lflang.lf.Reactor; import org.lflang.lf.TargetDecl; import org.lflang.target.TargetConfig; +import org.lflang.target.TargetProperty; /** * A helper class with functions that may be useful for code generators. This is created to ease our diff --git a/core/src/main/java/org/lflang/generator/rust/CargoDependencySpec.java b/core/src/main/java/org/lflang/generator/rust/CargoDependencySpec.java index 82043e0c9d..f3620c0575 100644 --- a/core/src/main/java/org/lflang/generator/rust/CargoDependencySpec.java +++ b/core/src/main/java/org/lflang/generator/rust/CargoDependencySpec.java @@ -33,7 +33,6 @@ import java.util.stream.Collectors; import org.eclipse.emf.ecore.EObject; import org.lflang.MessageReporter; -import org.lflang.target.TargetProperty; import org.lflang.ast.ASTUtils; import org.lflang.generator.InvalidLfSourceException; import org.lflang.lf.Array; @@ -41,6 +40,7 @@ import org.lflang.lf.KeyValuePair; import org.lflang.lf.KeyValuePairs; import org.lflang.lf.LfFactory; +import org.lflang.target.TargetProperty; import org.lflang.target.property.type.TargetPropertyType; import org.lflang.util.StringUtil; diff --git a/core/src/main/java/org/lflang/target/TargetProperty.java b/core/src/main/java/org/lflang/target/TargetProperty.java index d398600f99..621623a813 100644 --- a/core/src/main/java/org/lflang/target/TargetProperty.java +++ b/core/src/main/java/org/lflang/target/TargetProperty.java @@ -32,7 +32,6 @@ import java.util.Objects; import java.util.Properties; import java.util.stream.Collectors; - import org.lflang.AbstractTargetProperty; import org.lflang.MessageReporter; import org.lflang.Target; 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 22b6b1ddbd..e670ad8305 100644 --- a/core/src/main/java/org/lflang/target/property/PlatformProperty.java +++ b/core/src/main/java/org/lflang/target/property/PlatformProperty.java @@ -5,7 +5,6 @@ import org.lflang.AbstractTargetProperty; import org.lflang.MessageReporter; import org.lflang.Target; -import org.lflang.target.TargetProperty; import org.lflang.ast.ASTUtils; import org.lflang.lf.Element; import org.lflang.lf.KeyValuePair; @@ -13,6 +12,7 @@ import org.lflang.lf.LfFactory; import org.lflang.lf.LfPackage.Literals; import org.lflang.lf.Model; +import org.lflang.target.TargetProperty; import org.lflang.target.property.PlatformProperty.PlatformOptions; import org.lflang.target.property.type.DictionaryType; import org.lflang.target.property.type.DictionaryType.DictionaryElement; 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 73e2d0ffd4..755911602b 100644 --- a/core/src/main/java/org/lflang/target/property/Ros2DependenciesProperty.java +++ b/core/src/main/java/org/lflang/target/property/Ros2DependenciesProperty.java @@ -5,12 +5,12 @@ import org.lflang.AbstractTargetProperty; import org.lflang.MessageReporter; import org.lflang.Target; -import org.lflang.target.TargetProperty; 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.TargetProperty; import org.lflang.target.property.type.ArrayType; public class Ros2DependenciesProperty extends AbstractTargetProperty> { 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 50fb92afc9..10dde00371 100644 --- a/core/src/main/java/org/lflang/target/property/TracingProperty.java +++ b/core/src/main/java/org/lflang/target/property/TracingProperty.java @@ -5,7 +5,6 @@ import org.lflang.AbstractTargetProperty; import org.lflang.MessageReporter; import org.lflang.Target; -import org.lflang.target.TargetProperty; import org.lflang.ast.ASTUtils; import org.lflang.lf.Element; import org.lflang.lf.KeyValuePair; @@ -13,6 +12,7 @@ import org.lflang.lf.LfFactory; import org.lflang.lf.LfPackage.Literals; import org.lflang.lf.Model; +import org.lflang.target.TargetProperty; import org.lflang.target.property.TracingProperty.TracingOptions; import org.lflang.target.property.type.DictionaryType; import org.lflang.target.property.type.DictionaryType.DictionaryElement; diff --git a/core/src/main/java/org/lflang/validation/LFValidator.java b/core/src/main/java/org/lflang/validation/LFValidator.java index 56609e18b0..7c961fc00c 100644 --- a/core/src/main/java/org/lflang/validation/LFValidator.java +++ b/core/src/main/java/org/lflang/validation/LFValidator.java @@ -59,7 +59,6 @@ import org.lflang.InferredType; import org.lflang.ModelInfo; import org.lflang.Target; -import org.lflang.target.TargetProperty; import org.lflang.TimeValue; import org.lflang.ast.ASTUtils; import org.lflang.federated.serialization.SupportedSerializers; @@ -115,6 +114,7 @@ import org.lflang.lf.WidthSpec; import org.lflang.lf.WidthTerm; import org.lflang.target.TargetConfig; +import org.lflang.target.TargetProperty; import org.lflang.util.FileUtil; /** 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 a8a9a6eec2..56aaa9636a 100644 --- a/core/src/test/java/org/lflang/tests/compiler/LinguaFrancaValidationTest.java +++ b/core/src/test/java/org/lflang/tests/compiler/LinguaFrancaValidationTest.java @@ -45,11 +45,11 @@ import org.junit.jupiter.api.TestFactory; import org.junit.jupiter.api.extension.ExtendWith; import org.lflang.Target; -import org.lflang.target.TargetProperty; import org.lflang.TimeValue; import org.lflang.lf.LfPackage; import org.lflang.lf.Model; import org.lflang.lf.Visibility; +import org.lflang.target.TargetProperty; import org.lflang.target.property.type.ArrayType; import org.lflang.target.property.type.DictionaryType; import org.lflang.target.property.type.DictionaryType.DictionaryElement; From f31c33132ddafab7bb53ee55f4862c2d27bba951 Mon Sep 17 00:00:00 2001 From: Christian Menard Date: Mon, 2 Oct 2023 14:59:28 +0200 Subject: [PATCH 051/145] add changes to checked in Cargo.toml --- test/Rust/src-gen/Cargo.toml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/Rust/src-gen/Cargo.toml b/test/Rust/src-gen/Cargo.toml index 171ccb64ee..ad2d186081 100644 --- a/test/Rust/src-gen/Cargo.toml +++ b/test/Rust/src-gen/Cargo.toml @@ -25,3 +25,8 @@ opt-level = "s" [profile.release-with-debug-info] # use `build-type: RelWithDebInfo` inherits = "release" debug = true + +[profile.lf-test] # use `build-type: Test` +inherits = "dev" +debug = true + From ce25d75f096783a1cc4f8621501b9982a25f2182 Mon Sep 17 00:00:00 2001 From: Christian Menard Date: Mon, 2 Oct 2023 15:18:43 +0200 Subject: [PATCH 052/145] compare the value of the property, not the property --- .../java/org/lflang/federated/extensions/TSExtension.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/core/src/main/java/org/lflang/federated/extensions/TSExtension.java b/core/src/main/java/org/lflang/federated/extensions/TSExtension.java index a2a2e54ebd..e3e0789d36 100644 --- a/core/src/main/java/org/lflang/federated/extensions/TSExtension.java +++ b/core/src/main/java/org/lflang/federated/extensions/TSExtension.java @@ -198,9 +198,8 @@ public String generatePreamble( upstreamConnectionDelays.stream().collect(Collectors.joining(","))); } - private TimeValue getMinOutputDelay( - FederateInstance federate, FedFileConfig fileConfig, MessageReporter messageReporter) { - if (federate.targetConfig.coordination.equals(CoordinationMode.CENTRALIZED)) { + private TimeValue getMinOutputDelay(FederateInstance federate, MessageReporter messageReporter) { + if (federate.targetConfig.coordination.get() == CoordinationMode.CENTRALIZED) { // If this program uses centralized coordination then check // for outputs that depend on physical actions so that null messages can be // sent to the RTI. From b23f028bea1a94f2ff928e4879bfc07837a810ce Mon Sep 17 00:00:00 2001 From: Christian Menard Date: Mon, 2 Oct 2023 15:19:03 +0200 Subject: [PATCH 053/145] cleanup --- .../federated/extensions/TSExtension.java | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/core/src/main/java/org/lflang/federated/extensions/TSExtension.java b/core/src/main/java/org/lflang/federated/extensions/TSExtension.java index e3e0789d36..7484adeb16 100644 --- a/core/src/main/java/org/lflang/federated/extensions/TSExtension.java +++ b/core/src/main/java/org/lflang/federated/extensions/TSExtension.java @@ -161,7 +161,7 @@ public String generatePreamble( FedFileConfig fileConfig, RtiConfig rtiConfig, MessageReporter messageReporter) { - var minOutputDelay = getMinOutputDelay(federate, fileConfig, messageReporter); + var minOutputDelay = getMinOutputDelay(federate, messageReporter); var upstreamConnectionDelays = getUpstreamConnectionDelays(federate); return """ const defaultFederateConfig: __FederateConfig = { @@ -195,7 +195,7 @@ public String generatePreamble( federate.sendsTo.keySet().stream() .map(e -> String.valueOf(e.id)) .collect(Collectors.joining(",")), - upstreamConnectionDelays.stream().collect(Collectors.joining(","))); + String.join(",", upstreamConnectionDelays)); } private TimeValue getMinOutputDelay(FederateInstance federate, MessageReporter messageReporter) { @@ -250,26 +250,26 @@ private List getUpstreamConnectionDelays(FederateInstance federate) { List candidates = new ArrayList<>(); if (!federate.dependsOn.keySet().isEmpty()) { for (FederateInstance upstreamFederate : federate.dependsOn.keySet()) { - String element = "["; + StringBuilder element = new StringBuilder("["); var delays = federate.dependsOn.get(upstreamFederate); int cnt = 0; if (delays != null) { for (Expression delay : delays) { if (delay == null) { - element += "TimeValue.never()"; + element.append("TimeValue.never()"); } else { - element += getNetworkDelayLiteral(delay); + element.append(getNetworkDelayLiteral(delay)); } cnt++; if (cnt != delays.size()) { - element += ", "; + element.append(", "); } } } else { - element += "TimeValue.never()"; + element.append("TimeValue.never()"); } - element += "]"; - candidates.add(element); + element.append("]"); + candidates.add(element.toString()); } } return candidates; From dbcc17f56c68351a71662271fbc2759a245f08d2 Mon Sep 17 00:00:00 2001 From: Christian Menard Date: Mon, 2 Oct 2023 15:20:29 +0200 Subject: [PATCH 054/145] build profile tests don't work, as we overwrite the profile to Test --- test/Rust/src/target/BuildProfileDefaultIsDev.lf | 10 ---------- test/Rust/src/target/BuildProfileRelease.lf | 12 ------------ 2 files changed, 22 deletions(-) delete mode 100644 test/Rust/src/target/BuildProfileDefaultIsDev.lf delete mode 100644 test/Rust/src/target/BuildProfileRelease.lf diff --git a/test/Rust/src/target/BuildProfileDefaultIsDev.lf b/test/Rust/src/target/BuildProfileDefaultIsDev.lf deleted file mode 100644 index 083794bdfc..0000000000 --- a/test/Rust/src/target/BuildProfileDefaultIsDev.lf +++ /dev/null @@ -1,10 +0,0 @@ -// Tests that the default build profile is dev. A proxy for checking this is to check that debug -// assertions are enabled. -target Rust - -main reactor { - reaction(startup) {= - assert!(cfg!(debug_assertions), "debug assertions should be enabled"); - println!("success"); - =} -} diff --git a/test/Rust/src/target/BuildProfileRelease.lf b/test/Rust/src/target/BuildProfileRelease.lf deleted file mode 100644 index da19c0bc79..0000000000 --- a/test/Rust/src/target/BuildProfileRelease.lf +++ /dev/null @@ -1,12 +0,0 @@ -// Tests that the we can enable the release profile A proxy for checking this is to check that debug -// assertions are disabled. -target Rust { - build-type: "Release" -} - -main reactor { - reaction(startup) {= - assert!(!cfg!(debug_assertions), "debug assertions should be disabled"); - println!("success"); - =} -} From df803f6382fbd30102f91d94e676fe2f911b375e Mon Sep 17 00:00:00 2001 From: Christian Menard Date: Mon, 2 Oct 2023 16:09:56 +0200 Subject: [PATCH 055/145] cleanup --- .../launcher/FedLauncherGenerator.java | 2 +- .../org/lflang/generator/GeneratorBase.java | 16 +++++++++++-- .../target/property/TracingProperty.java | 23 ++++++++----------- 3 files changed, 24 insertions(+), 17 deletions(-) diff --git a/core/src/main/java/org/lflang/federated/launcher/FedLauncherGenerator.java b/core/src/main/java/org/lflang/federated/launcher/FedLauncherGenerator.java index 68517e3e98..368d01311f 100644 --- a/core/src/main/java/org/lflang/federated/launcher/FedLauncherGenerator.java +++ b/core/src/main/java/org/lflang/federated/launcher/FedLauncherGenerator.java @@ -7,7 +7,7 @@ * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * - * 2. Redistributions in binary formimport org.lflang.target.TargetProperty.ClockSyncMode; must reproduce the above copyright notice, + * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * diff --git a/core/src/main/java/org/lflang/generator/GeneratorBase.java b/core/src/main/java/org/lflang/generator/GeneratorBase.java index 31e3408266..0ba80a494c 100644 --- a/core/src/main/java/org/lflang/generator/GeneratorBase.java +++ b/core/src/main/java/org/lflang/generator/GeneratorBase.java @@ -29,7 +29,13 @@ import java.io.IOException; import java.nio.file.Path; import java.nio.file.Paths; -import java.util.*; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; import java.util.stream.Collectors; import org.eclipse.core.resources.IMarker; import org.eclipse.emf.ecore.EObject; @@ -47,7 +53,13 @@ import org.lflang.ast.ASTUtils; import org.lflang.ast.AstTransformation; import org.lflang.graph.InstantiationGraph; -import org.lflang.lf.*; +import org.lflang.lf.Attribute; +import org.lflang.lf.Connection; +import org.lflang.lf.Instantiation; +import org.lflang.lf.LfFactory; +import org.lflang.lf.Mode; +import org.lflang.lf.Reaction; +import org.lflang.lf.Reactor; import org.lflang.target.TargetConfig; import org.lflang.util.FileUtil; import org.lflang.validation.AbstractLFValidator; 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 10dde00371..779ae9f68b 100644 --- a/core/src/main/java/org/lflang/target/property/TracingProperty.java +++ b/core/src/main/java/org/lflang/target/property/TracingProperty.java @@ -41,12 +41,8 @@ public TracingOptions fromAst(Element node, MessageReporter reporter) { } else { for (KeyValuePair entry : node.getKeyvalue().getPairs()) { TracingOption option = (TracingOption) DictionaryType.TRACING_DICT.forName(entry.getName()); - switch (option) { - case TRACE_FILE_NAME: - options.traceFileName = ASTUtils.elementToSingleString(entry.getValue()); - break; - default: - break; + if (Objects.requireNonNull(option) == TracingOption.TRACE_FILE_NAME) { + options.traceFileName = ASTUtils.elementToSingleString(entry.getValue()); } } } @@ -94,12 +90,11 @@ public Element toAstElement() { for (TracingOption opt : TracingOption.values()) { KeyValuePair pair = LfFactory.eINSTANCE.createKeyValuePair(); pair.setName(opt.toString()); - switch (opt) { - case TRACE_FILE_NAME: - if (this.get().traceFileName == null) { - continue; - } - pair.setValue(ASTUtils.toElement(this.get().traceFileName)); + if (opt == TracingOption.TRACE_FILE_NAME) { + if (this.get().traceFileName == null) { + continue; + } + pair.setValue(ASTUtils.toElement(this.get().traceFileName)); } kvp.getPairs().add(pair); } @@ -114,7 +109,7 @@ public Element toAstElement() { /** Settings related to tracing options. */ public static class TracingOptions { - protected boolean enabled = false; + protected boolean enabled; TracingOptions(boolean enabled) { this.enabled = enabled; @@ -155,7 +150,7 @@ public enum TracingOption implements DictionaryElement { private final String description; - private TracingOption(String alias, PrimitiveType type) { + TracingOption(String alias, PrimitiveType type) { this.description = alias; this.type = type; } From 2322dfdb9cd3c6218421ed229e39b06d2bf4f97a Mon Sep 17 00:00:00 2001 From: Christian Menard Date: Mon, 2 Oct 2023 16:10:35 +0200 Subject: [PATCH 056/145] keepalive is not supported in C++ anymore --- .../target/property/KeepaliveProperty.java | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/core/src/main/java/org/lflang/target/property/KeepaliveProperty.java b/core/src/main/java/org/lflang/target/property/KeepaliveProperty.java index 3c85a9c478..0e61ccbe68 100644 --- a/core/src/main/java/org/lflang/target/property/KeepaliveProperty.java +++ b/core/src/main/java/org/lflang/target/property/KeepaliveProperty.java @@ -1,28 +1,12 @@ package org.lflang.target.property; import java.util.List; -import org.lflang.MessageReporter; import org.lflang.Target; -import org.lflang.ast.ASTUtils; -import org.lflang.lf.KeyValuePair; -import org.lflang.lf.LfPackage.Literals; -import org.lflang.lf.Model; public class KeepaliveProperty extends AbstractBooleanProperty { @Override public List supportedTargets() { - return Target.ALL; - } - - @Override - public void validate(KeyValuePair pair, Model ast, MessageReporter reporter) { - if (pair != null && ASTUtils.getTarget(ast) == Target.CPP) { - reporter - .at(pair, Literals.KEY_VALUE_PAIR__NAME) - .warning( - "The keepalive property is inferred automatically by the C++ " - + "runtime and the value given here is ignored"); - } + return List.of(Target.C, Target.CCPP, Target.Python, Target.TS, Target.Rust); } } From 1370097a975858ade95ba7ece672b8a72aa7dd54 Mon Sep 17 00:00:00 2001 From: Christian Menard Date: Mon, 2 Oct 2023 16:16:55 +0200 Subject: [PATCH 057/145] fast works fine with physical actions in C++ --- .../lflang/target/property/FastProperty.java | 26 ++++++++++++------- 1 file changed, 17 insertions(+), 9 deletions(-) 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 941ae2ed04..80898e5417 100644 --- a/core/src/main/java/org/lflang/target/property/FastProperty.java +++ b/core/src/main/java/org/lflang/target/property/FastProperty.java @@ -3,6 +3,7 @@ import java.util.List; import org.lflang.MessageReporter; import org.lflang.Target; +import org.lflang.ast.ASTUtils; import org.lflang.lf.Action; import org.lflang.lf.ActionOrigin; import org.lflang.lf.KeyValuePair; @@ -31,15 +32,22 @@ public void validate(KeyValuePair pair, Model ast, MessageReporter reporter) { } } - // 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("The fast target property is incompatible with physical actions."); - break; + 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; + } } } } From 6961686fb4107d199c39278ef9f77b19cb7115d0 Mon Sep 17 00:00:00 2001 From: Christian Menard Date: Mon, 2 Oct 2023 16:25:03 +0200 Subject: [PATCH 058/145] rust also supports threading --- .../main/java/org/lflang/target/property/ThreadingProperty.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/org/lflang/target/property/ThreadingProperty.java b/core/src/main/java/org/lflang/target/property/ThreadingProperty.java index 483eb26603..bfc7881c25 100644 --- a/core/src/main/java/org/lflang/target/property/ThreadingProperty.java +++ b/core/src/main/java/org/lflang/target/property/ThreadingProperty.java @@ -7,7 +7,7 @@ public class ThreadingProperty extends AbstractBooleanProperty { @Override public List supportedTargets() { - return List.of(Target.C, Target.CCPP, Target.Python); + return List.of(Target.C, Target.CCPP, Target.Python, Target.Rust); } @Override From 9362bb8ceda65c178d7732d212ee4637d5c501ce Mon Sep 17 00:00:00 2001 From: Christian Menard Date: Mon, 2 Oct 2023 16:40:37 +0200 Subject: [PATCH 059/145] externa-runtime-path and runtime-version are supported by Rust --- .../org/lflang/target/property/ExternalRuntimePathProperty.java | 2 +- .../java/org/lflang/target/property/RuntimeVersionProperty.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/org/lflang/target/property/ExternalRuntimePathProperty.java b/core/src/main/java/org/lflang/target/property/ExternalRuntimePathProperty.java index fa418aa29b..8db19aee3c 100644 --- a/core/src/main/java/org/lflang/target/property/ExternalRuntimePathProperty.java +++ b/core/src/main/java/org/lflang/target/property/ExternalRuntimePathProperty.java @@ -7,6 +7,6 @@ public class ExternalRuntimePathProperty extends AbstractStringConfig { @Override public List supportedTargets() { - return List.of(Target.CPP); + return List.of(Target.CPP, Target.Rust); } } diff --git a/core/src/main/java/org/lflang/target/property/RuntimeVersionProperty.java b/core/src/main/java/org/lflang/target/property/RuntimeVersionProperty.java index c46a5db83e..19835dcbd8 100644 --- a/core/src/main/java/org/lflang/target/property/RuntimeVersionProperty.java +++ b/core/src/main/java/org/lflang/target/property/RuntimeVersionProperty.java @@ -7,6 +7,6 @@ public class RuntimeVersionProperty extends AbstractStringConfig { @Override public List supportedTargets() { - return List.of(Target.CPP); + return List.of(Target.CPP, Target.Rust); } } From 66933e4da39b6c87092ebc22f7b796a9f28c4aff Mon Sep 17 00:00:00 2001 From: Christian Menard Date: Mon, 2 Oct 2023 19:13:18 +0200 Subject: [PATCH 060/145] properly report unknown platforms Fixes https://github.com/lf-lang/lingua-franca/issues/1919 --- .../target/property/PlatformProperty.java | 75 ++++++++----------- .../compiler/LinguaFrancaValidationTest.java | 19 +++++ 2 files changed, 52 insertions(+), 42 deletions(-) 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 e670ad8305..054d2f7861 100644 --- a/core/src/main/java/org/lflang/target/property/PlatformProperty.java +++ b/core/src/main/java/org/lflang/target/property/PlatformProperty.java @@ -2,6 +2,7 @@ import java.util.Arrays; import java.util.List; +import java.util.Objects; import org.lflang.AbstractTargetProperty; import org.lflang.MessageReporter; import org.lflang.Target; @@ -22,6 +23,10 @@ public class PlatformProperty extends AbstractTargetProperty { + public static final String UNKNOW_PLATFORM = + "Unidentified Platform Type, LF supports the following platform types: " + + Arrays.asList(Platform.values()); + public PlatformProperty() { super(UnionType.PLATFORM_STRING_OR_DICTIONARY); } @@ -34,41 +39,25 @@ public PlatformOptions initialValue() { @Override public PlatformOptions fromAst(Element node, MessageReporter reporter) { var config = new PlatformOptions(); - if (node.getLiteral() != null) { + if (node.getLiteral() != null || node.getId() != null) { config.platform = (Platform) UnionType.PLATFORM_UNION.forName(ASTUtils.elementToSingleString(node)); - if (config.platform == null) { - String s = - "Unidentified Platform Type, LF supports the following platform types: " - + Arrays.asList(Platform.values()); - // err.at(value).error(s); - throw new AssertionError(s); - } } else { for (KeyValuePair entry : node.getKeyvalue().getPairs()) { PlatformOption option = (PlatformOption) DictionaryType.PLATFORM_DICT.forName(entry.getName()); switch (option) { case NAME -> { - Platform p = + config.platform = (Platform) UnionType.PLATFORM_UNION.forName( ASTUtils.elementToSingleString(entry.getValue())); - if (p == null) { - String s = - "Unidentified Platform Type, LF supports the following platform types: " - + Arrays.asList(Platform.values()); - reporter.at(entry).error(s); - throw new AssertionError(s); - } - config.platform = p; } case BAUDRATE -> config.baudRate = ASTUtils.toInteger(entry.getValue()); case BOARD -> config.board = ASTUtils.elementToSingleString(entry.getValue()); case FLASH -> config.flash = ASTUtils.toBoolean(entry.getValue()); case PORT -> config.port = ASTUtils.elementToSingleString(entry.getValue()); case USER_THREADS -> config.userThreads = ASTUtils.toInteger(entry.getValue()); - default -> {} } } } @@ -88,33 +77,35 @@ public List supportedTargets() { @Override public void validate(KeyValuePair pair, Model ast, MessageReporter reporter) { - var threading = TargetProperty.getKeyValuePair(ast, TargetProperty.THREADING); - if (threading != null) { - if (pair != null && ASTUtils.toBoolean(threading.getValue())) { - var lit = ASTUtils.elementToSingleString(pair.getValue()); - var dic = pair.getValue().getKeyvalue(); - if (lit != null && lit.equalsIgnoreCase(Platform.RP2040.toString())) { - reporter - .at(pair, Literals.KEY_VALUE_PAIR__VALUE) - .error("Platform " + Platform.RP2040 + " does not support threading"); - } - if (dic != null) { - var rp = - dic.getPairs().stream() - .filter( - kv -> - kv.getName().equalsIgnoreCase("name") - && ASTUtils.elementToSingleString(kv.getValue()) - .equalsIgnoreCase(Platform.RP2040.toString())) - .findFirst(); - rp.ifPresent( - keyValuePair -> - reporter - .at(keyValuePair, Literals.KEY_VALUE_PAIR__VALUE) - .error("Platform " + Platform.RP2040 + " does not support threading")); + final var node = pair.getValue(); + Platform platform = null; + if (node.getLiteral() != null || node.getId() != null) { + platform = (Platform) UnionType.PLATFORM_UNION.forName(ASTUtils.elementToSingleString(node)); + if (platform == null) { + reporter.at(pair, Literals.KEY_VALUE_PAIR__VALUE).error(UNKNOW_PLATFORM); + } + } else { + for (KeyValuePair entry : node.getKeyvalue().getPairs()) { + PlatformOption option = + (PlatformOption) DictionaryType.PLATFORM_DICT.forName(entry.getName()); + if (Objects.requireNonNull(option) == PlatformOption.NAME) { + platform = + (Platform) + UnionType.PLATFORM_UNION.forName( + ASTUtils.elementToSingleString(entry.getValue())); + if (platform == null) { + reporter.at(entry, Literals.KEY_VALUE_PAIR__VALUE).error(UNKNOW_PLATFORM); + } } } } + + var threading = TargetProperty.getKeyValuePair(ast, TargetProperty.THREADING); + if (threading != null && platform == Platform.RP2040) { + reporter + .at(pair, Literals.KEY_VALUE_PAIR__VALUE) + .error("Platform " + Platform.RP2040 + " does not support threading"); + } } @Override 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 56aaa9636a..073e7e1705 100644 --- a/core/src/test/java/org/lflang/tests/compiler/LinguaFrancaValidationTest.java +++ b/core/src/test/java/org/lflang/tests/compiler/LinguaFrancaValidationTest.java @@ -50,6 +50,8 @@ import org.lflang.lf.Model; import org.lflang.lf.Visibility; import org.lflang.target.TargetProperty; +import org.lflang.target.property.PlatformProperty; +import org.lflang.target.property.PlatformProperty.Platform; import org.lflang.target.property.type.ArrayType; import org.lflang.target.property.type.DictionaryType; import org.lflang.target.property.type.DictionaryType.DictionaryElement; @@ -1610,6 +1612,23 @@ public void checkCargoDependencyProperty() throws Exception { "Expected an array of strings for key 'features'"); } + @Test + public void checkPlatformProperty() throws Exception { + validator.assertNoErrors(createModel(TargetProperty.PLATFORM, Platform.ARDUINO.toString())); + validator.assertNoErrors( + createModel(TargetProperty.PLATFORM, String.format("{name: %s}", Platform.ZEPHYR))); + validator.assertError( + createModel(TargetProperty.PLATFORM, "foobar"), + LfPackage.eINSTANCE.getKeyValuePair(), + null, + PlatformProperty.UNKNOW_PLATFORM); + validator.assertError( + createModel(TargetProperty.PLATFORM, "{ name: foobar }"), + LfPackage.eINSTANCE.getKeyValuePair(), + null, + PlatformProperty.UNKNOW_PLATFORM); + } + @Test public void testImportedCyclicReactor() throws Exception { // File tempFile = File.createTempFile("lf-validation", ".lf"); From 6a85ee071d1765c7976a962efbe5a6cf770c5f3b Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Mon, 2 Oct 2023 11:55:14 -0700 Subject: [PATCH 061/145] Address review comment --- .../main/java/org/lflang/target/property/CompilerProperty.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/org/lflang/target/property/CompilerProperty.java b/core/src/main/java/org/lflang/target/property/CompilerProperty.java index 286938df10..85d3690fcf 100644 --- a/core/src/main/java/org/lflang/target/property/CompilerProperty.java +++ b/core/src/main/java/org/lflang/target/property/CompilerProperty.java @@ -7,6 +7,6 @@ public class CompilerProperty extends AbstractStringConfig { @Override public List supportedTargets() { - return Target.ALL; + return List.of(Target.C, Target.CCPP, Target.CPP); } } From 5d499c8bf15042d040ee12de7b117f976c989c59 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Mon, 2 Oct 2023 11:57:25 -0700 Subject: [PATCH 062/145] Address another review comment --- .../main/java/org/lflang/target/property/PlatformProperty.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 054d2f7861..70204cef25 100644 --- a/core/src/main/java/org/lflang/target/property/PlatformProperty.java +++ b/core/src/main/java/org/lflang/target/property/PlatformProperty.java @@ -72,7 +72,7 @@ protected PlatformOptions fromString(String string, MessageReporter reporter) { @Override public List supportedTargets() { - return Target.ALL; + return List.of(Target.C); } @Override From 876491c717789a5cc606f23d82e404f13f8f91a1 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Mon, 2 Oct 2023 11:58:30 -0700 Subject: [PATCH 063/145] Remove copypasta --- .../main/kotlin/org/lflang/generator/ts/TSGenerator.kt | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/core/src/main/kotlin/org/lflang/generator/ts/TSGenerator.kt b/core/src/main/kotlin/org/lflang/generator/ts/TSGenerator.kt index add6402ed3..38e601a8f7 100644 --- a/core/src/main/kotlin/org/lflang/generator/ts/TSGenerator.kt +++ b/core/src/main/kotlin/org/lflang/generator/ts/TSGenerator.kt @@ -91,13 +91,7 @@ class TSGenerator( = (IntegratedBuilder.GENERATED_PERCENT_PROGRESS + IntegratedBuilder.COMPILED_PERCENT_PROGRESS) / 2 } - - init { - // Set defaults for federate compilation. - targetConfig.compiler.override("gcc") - targetConfig.compilerFlags.get().add("-O2") - } - + /** Generate TypeScript code from the Lingua Franca model contained by the * specified resource. This is the main entry point for code * generation. From 2a046f1577815c42dde921ee6c9a7bbf5fcd0751 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Mon, 2 Oct 2023 12:20:45 -0700 Subject: [PATCH 064/145] Debugging --- .../org/lflang/generator/python/PythonGenerator.java | 10 +++++----- .../main/kotlin/org/lflang/generator/ts/TSGenerator.kt | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/core/src/main/java/org/lflang/generator/python/PythonGenerator.java b/core/src/main/java/org/lflang/generator/python/PythonGenerator.java index 92d0f8a840..19a2cedd08 100644 --- a/core/src/main/java/org/lflang/generator/python/PythonGenerator.java +++ b/core/src/main/java/org/lflang/generator/python/PythonGenerator.java @@ -363,11 +363,11 @@ public boolean isOSCompatible() { */ @Override public void doGenerate(Resource resource, LFGeneratorContext context) { - // Set the threading to false by default, unless the user has - // specifically asked for it. - if (!targetConfig.threading.isSet()) { - targetConfig.threading.override(false); - } +// // Set the threading to false by default, unless the user has +// // specifically asked for it. +// if (!targetConfig.threading.isSet()) { +// targetConfig.threading.override(false); +// } int cGeneratedPercentProgress = (IntegratedBuilder.VALIDATED_PERCENT_PROGRESS + 100) / 2; code.pr( PythonPreambleGenerator.generateCIncludeStatements( diff --git a/core/src/main/kotlin/org/lflang/generator/ts/TSGenerator.kt b/core/src/main/kotlin/org/lflang/generator/ts/TSGenerator.kt index 38e601a8f7..999b8fba54 100644 --- a/core/src/main/kotlin/org/lflang/generator/ts/TSGenerator.kt +++ b/core/src/main/kotlin/org/lflang/generator/ts/TSGenerator.kt @@ -91,7 +91,7 @@ class TSGenerator( = (IntegratedBuilder.GENERATED_PERCENT_PROGRESS + IntegratedBuilder.COMPILED_PERCENT_PROGRESS) / 2 } - + /** Generate TypeScript code from the Lingua Franca model contained by the * specified resource. This is the main entry point for code * generation. From 237b506e4977790bacd569735c0042fc2cad1d79 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Mon, 2 Oct 2023 14:42:12 -0700 Subject: [PATCH 065/145] Mostly formatting --- .../lflang/federated/generator/FedTargetConfig.java | 3 +-- .../org/lflang/generator/python/PythonGenerator.java | 11 +++-------- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/core/src/main/java/org/lflang/federated/generator/FedTargetConfig.java b/core/src/main/java/org/lflang/federated/generator/FedTargetConfig.java index 7b468013cc..705a2dbcec 100644 --- a/core/src/main/java/org/lflang/federated/generator/FedTargetConfig.java +++ b/core/src/main/java/org/lflang/federated/generator/FedTargetConfig.java @@ -36,8 +36,7 @@ public FedTargetConfig(LFGeneratorContext context, Resource federateResource) { mergeImportedConfig( federateResource, context.getFileConfig().resource, context.getErrorReporter()); - clearPropertiesToIgnore(); // FIXME: add boolean inherit() function to TargetPropertyConfig - // instead + clearPropertiesToIgnore(); ((FedFileConfig) context.getFileConfig()).relativizePaths(this); } diff --git a/core/src/main/java/org/lflang/generator/python/PythonGenerator.java b/core/src/main/java/org/lflang/generator/python/PythonGenerator.java index 19a2cedd08..ab9092575d 100644 --- a/core/src/main/java/org/lflang/generator/python/PythonGenerator.java +++ b/core/src/main/java/org/lflang/generator/python/PythonGenerator.java @@ -363,11 +363,6 @@ public boolean isOSCompatible() { */ @Override public void doGenerate(Resource resource, LFGeneratorContext context) { -// // Set the threading to false by default, unless the user has -// // specifically asked for it. -// if (!targetConfig.threading.isSet()) { -// targetConfig.threading.override(false); -// } int cGeneratedPercentProgress = (IntegratedBuilder.VALIDATED_PERCENT_PROGRESS + 100) / 2; code.pr( PythonPreambleGenerator.generateCIncludeStatements( @@ -443,7 +438,6 @@ protected void generateReaction( * left to Python code to allow for more liberal state variable assignments. * * @param instance The reactor class instance - * @return Initialization code fore state variables of instance */ @Override protected void generateStateVariableInitializations(ReactorInstance instance) { @@ -604,14 +598,15 @@ private static String generateCmakeInstall(FileConfig fileConfig) { return """ if(WIN32) file(GENERATE OUTPUT .bat CONTENT - "@echo off\n\ + "@echo off + \ ${Python_EXECUTABLE} %*" ) install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/.bat DESTINATION ${CMAKE_INSTALL_BINDIR}) else() file(GENERATE OUTPUT CONTENT "#!/bin/sh\\n\\ - ${Python_EXECUTABLE} \\\"$@\\\"" + ${Python_EXECUTABLE} \\"$@\\"" ) install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/ DESTINATION ${CMAKE_INSTALL_BINDIR}) endif() From f30a57f4e15958fef062d520120de5089bb6ea83 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Mon, 2 Oct 2023 16:19:47 -0700 Subject: [PATCH 066/145] Proof of concept of target properties without enum --- .../org/lflang/AbstractTargetProperty.java | 3 ++ .../java/org/lflang/target/TargetConfig.java | 28 +++++++++++++++++++ .../org/lflang/target/TargetProperty.java | 10 +++---- .../lflang/target/property/AuthProperty.java | 5 ++++ .../property/BuildCommandsProperty.java | 5 ++++ .../target/property/BuildTypeProperty.java | 5 ++++ .../property/CargoDependenciesProperty.java | 5 ++++ .../property/CargoFeaturesProperty.java | 5 ++++ .../property/ClockSyncModeProperty.java | 5 ++++ .../property/ClockSyncOptionsProperty.java | 5 ++++ .../target/property/CmakeIncludeProperty.java | 5 ++++ .../property/CompileDefinitionsProperty.java | 5 ++++ .../property/CompilerFlagsProperty.java | 5 ++++ .../target/property/CompilerProperty.java | 5 ++++ .../property/CoordinationOptionsProperty.java | 5 ++++ .../target/property/CoordinationProperty.java | 5 ++++ .../target/property/DockerProperty.java | 5 ++++ .../ExportDependencyGraphProperty.java | 5 ++++ .../target/property/ExportToYamlProperty.java | 5 ++++ .../property/ExternalRuntimePathProperty.java | 5 ++++ .../lflang/target/property/FastProperty.java | 5 ++++ .../target/property/FedSetupProperty.java | 5 ++++ .../lflang/target/property/FilesProperty.java | 5 ++++ .../target/property/KeepaliveProperty.java | 5 ++++ .../target/property/LoggingProperty.java | 5 ++++ .../target/property/NoCompileProperty.java | 5 ++++ .../property/NoRuntimeValidationProperty.java | 5 ++++ .../target/property/PlatformProperty.java | 5 ++++ .../property/PrintStatisticsProperty.java | 5 ++++ .../target/property/ProtobufsProperty.java | 5 ++++ .../property/Ros2DependenciesProperty.java | 5 ++++ .../lflang/target/property/Ros2Property.java | 5 ++++ .../property/RuntimeVersionProperty.java | 5 ++++ .../target/property/RustIncludeProperty.java | 5 ++++ .../target/property/SchedulerProperty.java | 5 ++++ .../property/SingleFileProjectProperty.java | 5 ++++ .../target/property/ThreadingProperty.java | 5 ++++ .../target/property/TimeOutProperty.java | 5 ++++ .../target/property/TracingProperty.java | 5 ++++ .../target/property/VerifyProperty.java | 5 ++++ .../target/property/WorkersProperty.java | 5 ++++ 41 files changed, 226 insertions(+), 5 deletions(-) diff --git a/core/src/main/java/org/lflang/AbstractTargetProperty.java b/core/src/main/java/org/lflang/AbstractTargetProperty.java index 03a7e7d305..1ec4d187f0 100644 --- a/core/src/main/java/org/lflang/AbstractTargetProperty.java +++ b/core/src/main/java/org/lflang/AbstractTargetProperty.java @@ -187,4 +187,7 @@ public T get() { * Return an AST node that represents this target property and the value currently assigned to it. */ public abstract Element toAstElement(); + + /** Return the name of this target property (in kebab case). */ + public abstract String name(); } diff --git a/core/src/main/java/org/lflang/target/TargetConfig.java b/core/src/main/java/org/lflang/target/TargetConfig.java index 31e46c0179..fe5430197b 100644 --- a/core/src/main/java/org/lflang/target/TargetConfig.java +++ b/core/src/main/java/org/lflang/target/TargetConfig.java @@ -25,8 +25,11 @@ package org.lflang.target; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.Properties; +import java.util.stream.Collectors; +import org.lflang.AbstractTargetProperty; import org.lflang.MessageReporter; import org.lflang.Target; import org.lflang.generator.rust.RustTargetConfig; @@ -263,4 +266,29 @@ public TargetConfig(Properties cliArgs, TargetDecl target, MessageReporter messa /** Path to a C file used by the Python target to setup federated execution. */ public final FedSetupProperty fedSetupPreamble = new FedSetupProperty(); + + public static List> getAllTargetProperties(Object object) { + var fields = object.getClass().getDeclaredFields(); + + List properties = + Arrays.stream(fields) + .filter(f -> AbstractTargetProperty.class.isAssignableFrom(f.getType())) + .map( + f -> { + try { + return (AbstractTargetProperty) f.get(object); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + }) + .collect(Collectors.toList()); + + return properties; + } + + public List> getAllTargetProperties() { + var properties = TargetConfig.getAllTargetProperties(this); + properties.addAll(TargetConfig.getAllTargetProperties(this.rust)); + return properties; + } } diff --git a/core/src/main/java/org/lflang/target/TargetProperty.java b/core/src/main/java/org/lflang/target/TargetProperty.java index 621623a813..50761efd1b 100644 --- a/core/src/main/java/org/lflang/target/TargetProperty.java +++ b/core/src/main/java/org/lflang/target/TargetProperty.java @@ -418,14 +418,14 @@ public static void validate( .forEach( pair -> { var match = - Arrays.stream(TargetProperty.values()) - .filter(prop -> prop.toString().equalsIgnoreCase(pair.getName())) + config.getAllTargetProperties().stream() + .filter(prop -> prop.name().equalsIgnoreCase(pair.getName())) .findAny(); if (match.isPresent()) { var p = match.get(); - p.property.of(config).checkSupport(pair, config.target, reporter); - p.property.of(config).checkType(pair, reporter); - p.property.of(config).validate(pair, ast, reporter); + p.checkSupport(pair, config.target, reporter); + p.checkType(pair, reporter); + p.validate(pair, ast, reporter); } else { reporter .at(pair, Literals.KEY_VALUE_PAIR__NAME) diff --git a/core/src/main/java/org/lflang/target/property/AuthProperty.java b/core/src/main/java/org/lflang/target/property/AuthProperty.java index f8132c116f..6540d0780f 100644 --- a/core/src/main/java/org/lflang/target/property/AuthProperty.java +++ b/core/src/main/java/org/lflang/target/property/AuthProperty.java @@ -10,4 +10,9 @@ public class AuthProperty extends AbstractBooleanProperty { public List supportedTargets() { return Arrays.asList(Target.C, Target.CCPP); } + + @Override + public String name() { + return "auth"; + } } diff --git a/core/src/main/java/org/lflang/target/property/BuildCommandsProperty.java b/core/src/main/java/org/lflang/target/property/BuildCommandsProperty.java index da459ab500..cb46e4864c 100644 --- a/core/src/main/java/org/lflang/target/property/BuildCommandsProperty.java +++ b/core/src/main/java/org/lflang/target/property/BuildCommandsProperty.java @@ -40,4 +40,9 @@ public List supportedTargets() { public Element toAstElement() { return ASTUtils.toElement(this.get().toString()); } + + @Override + public String name() { + return "build"; + } } diff --git a/core/src/main/java/org/lflang/target/property/BuildTypeProperty.java b/core/src/main/java/org/lflang/target/property/BuildTypeProperty.java index 86e79f4c99..f69f40e94a 100644 --- a/core/src/main/java/org/lflang/target/property/BuildTypeProperty.java +++ b/core/src/main/java/org/lflang/target/property/BuildTypeProperty.java @@ -36,6 +36,11 @@ protected BuildType fromString(String string, MessageReporter reporter) { return (BuildType) UnionType.BUILD_TYPE_UNION.forName(string); } + @Override + public String name() { + return "build-type"; + } + @Override public List supportedTargets() { return Arrays.asList(Target.C, Target.CCPP, Target.CPP, Target.Rust); 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 5761073267..b349541183 100644 --- a/core/src/main/java/org/lflang/target/property/CargoDependenciesProperty.java +++ b/core/src/main/java/org/lflang/target/property/CargoDependenciesProperty.java @@ -59,4 +59,9 @@ public Element toAstElement() { return e; } } + + @Override + public String name() { + return "cargo-dependencies"; + } } diff --git a/core/src/main/java/org/lflang/target/property/CargoFeaturesProperty.java b/core/src/main/java/org/lflang/target/property/CargoFeaturesProperty.java index 290b0961d3..ac1d299d08 100644 --- a/core/src/main/java/org/lflang/target/property/CargoFeaturesProperty.java +++ b/core/src/main/java/org/lflang/target/property/CargoFeaturesProperty.java @@ -10,4 +10,9 @@ public class CargoFeaturesProperty extends AbstractStringListProperty { public List supportedTargets() { return Arrays.asList(Target.Rust); } + + @Override + public String name() { + return "cargo-features"; + } } 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 1b18b20817..ce7bd3f6d8 100644 --- a/core/src/main/java/org/lflang/target/property/ClockSyncModeProperty.java +++ b/core/src/main/java/org/lflang/target/property/ClockSyncModeProperty.java @@ -65,6 +65,11 @@ public Element toAstElement() { return ASTUtils.toElement(this.get().toString()); } + @Override + public String name() { + return "clock-sync"; + } + /** * Enumeration of clock synchronization modes. * 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 e994ab1035..6227efe33f 100644 --- a/core/src/main/java/org/lflang/target/property/ClockSyncOptionsProperty.java +++ b/core/src/main/java/org/lflang/target/property/ClockSyncOptionsProperty.java @@ -90,6 +90,11 @@ public Element toAstElement() { return e; } + @Override + public String name() { + return "clock-sync-options"; + } + /** Settings related to clock synchronization. */ public static class ClockSyncOptions { diff --git a/core/src/main/java/org/lflang/target/property/CmakeIncludeProperty.java b/core/src/main/java/org/lflang/target/property/CmakeIncludeProperty.java index 179a80e7a6..90b1c5c297 100644 --- a/core/src/main/java/org/lflang/target/property/CmakeIncludeProperty.java +++ b/core/src/main/java/org/lflang/target/property/CmakeIncludeProperty.java @@ -59,4 +59,9 @@ public List supportedTargets() { public Element toAstElement() { return ASTUtils.toElement(this.get()); } + + @Override + public String name() { + return "cmake-include"; + } } diff --git a/core/src/main/java/org/lflang/target/property/CompileDefinitionsProperty.java b/core/src/main/java/org/lflang/target/property/CompileDefinitionsProperty.java index a754b2ce4a..6c3a826f30 100644 --- a/core/src/main/java/org/lflang/target/property/CompileDefinitionsProperty.java +++ b/core/src/main/java/org/lflang/target/property/CompileDefinitionsProperty.java @@ -47,4 +47,9 @@ public List supportedTargets() { public Element toAstElement() { return ASTUtils.toElement(this.get()); } + + @Override + public String name() { + return "compile-definitions"; + } } diff --git a/core/src/main/java/org/lflang/target/property/CompilerFlagsProperty.java b/core/src/main/java/org/lflang/target/property/CompilerFlagsProperty.java index 4ebd7a6131..acd12748ba 100644 --- a/core/src/main/java/org/lflang/target/property/CompilerFlagsProperty.java +++ b/core/src/main/java/org/lflang/target/property/CompilerFlagsProperty.java @@ -10,4 +10,9 @@ public class CompilerFlagsProperty extends AbstractStringListProperty { public List supportedTargets() { return Arrays.asList(Target.C, Target.CCPP); } + + @Override + public String name() { + return "compiler-flags"; + } } diff --git a/core/src/main/java/org/lflang/target/property/CompilerProperty.java b/core/src/main/java/org/lflang/target/property/CompilerProperty.java index 85d3690fcf..0be8df2f76 100644 --- a/core/src/main/java/org/lflang/target/property/CompilerProperty.java +++ b/core/src/main/java/org/lflang/target/property/CompilerProperty.java @@ -9,4 +9,9 @@ public class CompilerProperty extends AbstractStringConfig { public List supportedTargets() { return List.of(Target.C, Target.CCPP, Target.CPP); } + + @Override + public String name() { + return "compiler"; + } } 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 348b6f31b7..60575e3c01 100644 --- a/core/src/main/java/org/lflang/target/property/CoordinationOptionsProperty.java +++ b/core/src/main/java/org/lflang/target/property/CoordinationOptionsProperty.java @@ -74,6 +74,11 @@ public Element toAstElement() { return e; } + @Override + public String name() { + return "coordination-options"; + } + /** Settings related to coordination of federated execution. */ public static class CoordinationOptions { diff --git a/core/src/main/java/org/lflang/target/property/CoordinationProperty.java b/core/src/main/java/org/lflang/target/property/CoordinationProperty.java index d550fe5dc2..65b9f7fbb8 100644 --- a/core/src/main/java/org/lflang/target/property/CoordinationProperty.java +++ b/core/src/main/java/org/lflang/target/property/CoordinationProperty.java @@ -41,6 +41,11 @@ public Element toAstElement() { return ASTUtils.toElement(this.get().toString()); } + @Override + public String name() { + return "coordination"; + } + /** * Enumeration of coordination types. * 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 ffd488f07a..89ab7bef06 100644 --- a/core/src/main/java/org/lflang/target/property/DockerProperty.java +++ b/core/src/main/java/org/lflang/target/property/DockerProperty.java @@ -87,6 +87,11 @@ public Element toAstElement() { } } + @Override + public String name() { + return "docker"; + } + /** Settings related to Docker options. */ public static class DockerOptions { diff --git a/core/src/main/java/org/lflang/target/property/ExportDependencyGraphProperty.java b/core/src/main/java/org/lflang/target/property/ExportDependencyGraphProperty.java index 427f4eab17..761eded16c 100644 --- a/core/src/main/java/org/lflang/target/property/ExportDependencyGraphProperty.java +++ b/core/src/main/java/org/lflang/target/property/ExportDependencyGraphProperty.java @@ -9,4 +9,9 @@ public class ExportDependencyGraphProperty extends AbstractBooleanProperty { public List supportedTargets() { return List.of(Target.CPP, Target.Rust); } + + @Override + public String name() { + return "export-dependency-graph"; + } } diff --git a/core/src/main/java/org/lflang/target/property/ExportToYamlProperty.java b/core/src/main/java/org/lflang/target/property/ExportToYamlProperty.java index f9349afa6d..a4aebb4d16 100644 --- a/core/src/main/java/org/lflang/target/property/ExportToYamlProperty.java +++ b/core/src/main/java/org/lflang/target/property/ExportToYamlProperty.java @@ -9,4 +9,9 @@ public class ExportToYamlProperty extends AbstractBooleanProperty { public List supportedTargets() { return List.of(Target.CPP); } + + @Override + public String name() { + return "export-to-yaml"; + } } diff --git a/core/src/main/java/org/lflang/target/property/ExternalRuntimePathProperty.java b/core/src/main/java/org/lflang/target/property/ExternalRuntimePathProperty.java index 8db19aee3c..6c704974ac 100644 --- a/core/src/main/java/org/lflang/target/property/ExternalRuntimePathProperty.java +++ b/core/src/main/java/org/lflang/target/property/ExternalRuntimePathProperty.java @@ -9,4 +9,9 @@ public class ExternalRuntimePathProperty extends AbstractStringConfig { public List supportedTargets() { return List.of(Target.CPP, Target.Rust); } + + @Override + public String name() { + return "external-runtime-path"; + } } 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 80898e5417..9d019386b5 100644 --- a/core/src/main/java/org/lflang/target/property/FastProperty.java +++ b/core/src/main/java/org/lflang/target/property/FastProperty.java @@ -18,6 +18,11 @@ public List supportedTargets() { return Target.ALL; } + @Override + public String name() { + return "fast"; + } + @Override public void validate(KeyValuePair pair, Model ast, MessageReporter reporter) { if (pair != null) { diff --git a/core/src/main/java/org/lflang/target/property/FedSetupProperty.java b/core/src/main/java/org/lflang/target/property/FedSetupProperty.java index 3b2c539d47..83ede21100 100644 --- a/core/src/main/java/org/lflang/target/property/FedSetupProperty.java +++ b/core/src/main/java/org/lflang/target/property/FedSetupProperty.java @@ -39,4 +39,9 @@ public List supportedTargets() { public Element toAstElement() { return ASTUtils.toElement(get()); } + + @Override + public String name() { + return "_fed_setup"; // FIXME: follow kebab case convention + } } diff --git a/core/src/main/java/org/lflang/target/property/FilesProperty.java b/core/src/main/java/org/lflang/target/property/FilesProperty.java index d7d5578431..d0819fbac5 100644 --- a/core/src/main/java/org/lflang/target/property/FilesProperty.java +++ b/core/src/main/java/org/lflang/target/property/FilesProperty.java @@ -9,4 +9,9 @@ public class FilesProperty extends AbstractFileListProperty { public List supportedTargets() { return List.of(Target.C, Target.CCPP, Target.Python); } + + @Override + public String name() { + return "files"; + } } diff --git a/core/src/main/java/org/lflang/target/property/KeepaliveProperty.java b/core/src/main/java/org/lflang/target/property/KeepaliveProperty.java index 0e61ccbe68..d40c5ccccd 100644 --- a/core/src/main/java/org/lflang/target/property/KeepaliveProperty.java +++ b/core/src/main/java/org/lflang/target/property/KeepaliveProperty.java @@ -9,4 +9,9 @@ public class KeepaliveProperty extends AbstractBooleanProperty { public List supportedTargets() { return List.of(Target.C, Target.CCPP, Target.Python, Target.TS, Target.Rust); } + + @Override + public String name() { + return "keepalive"; + } } diff --git a/core/src/main/java/org/lflang/target/property/LoggingProperty.java b/core/src/main/java/org/lflang/target/property/LoggingProperty.java index 9c59b03f4d..554bfbebeb 100644 --- a/core/src/main/java/org/lflang/target/property/LoggingProperty.java +++ b/core/src/main/java/org/lflang/target/property/LoggingProperty.java @@ -39,6 +39,11 @@ public Element toAstElement() { return ASTUtils.toElement(get().toString()); } + @Override + public String name() { + return "logging"; + } + /** * Log levels in descending order of severity. * diff --git a/core/src/main/java/org/lflang/target/property/NoCompileProperty.java b/core/src/main/java/org/lflang/target/property/NoCompileProperty.java index fa8c949d6f..12728f02e9 100644 --- a/core/src/main/java/org/lflang/target/property/NoCompileProperty.java +++ b/core/src/main/java/org/lflang/target/property/NoCompileProperty.java @@ -10,4 +10,9 @@ public class NoCompileProperty extends AbstractBooleanProperty { public List supportedTargets() { return Arrays.asList(Target.C, Target.CPP, Target.CCPP, Target.Python); } + + @Override + public String name() { + return "no-compile"; + } } diff --git a/core/src/main/java/org/lflang/target/property/NoRuntimeValidationProperty.java b/core/src/main/java/org/lflang/target/property/NoRuntimeValidationProperty.java index dd0e91613c..e7fe466d29 100644 --- a/core/src/main/java/org/lflang/target/property/NoRuntimeValidationProperty.java +++ b/core/src/main/java/org/lflang/target/property/NoRuntimeValidationProperty.java @@ -9,4 +9,9 @@ public class NoRuntimeValidationProperty extends AbstractBooleanProperty { public List supportedTargets() { return List.of(Target.CPP); } + + @Override + public String name() { + return "no-runtime-validation"; + } } 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 70204cef25..310cedcd63 100644 --- a/core/src/main/java/org/lflang/target/property/PlatformProperty.java +++ b/core/src/main/java/org/lflang/target/property/PlatformProperty.java @@ -132,6 +132,11 @@ public Element toAstElement() { return e; } + @Override + public String name() { + return "platform"; + } + /** Settings related to Platform Options. */ public static class PlatformOptions { // FIXME: use a record for this diff --git a/core/src/main/java/org/lflang/target/property/PrintStatisticsProperty.java b/core/src/main/java/org/lflang/target/property/PrintStatisticsProperty.java index c100f3fc2c..928ca07dbc 100644 --- a/core/src/main/java/org/lflang/target/property/PrintStatisticsProperty.java +++ b/core/src/main/java/org/lflang/target/property/PrintStatisticsProperty.java @@ -9,4 +9,9 @@ public class PrintStatisticsProperty extends AbstractBooleanProperty { public List supportedTargets() { return List.of(Target.CPP); } + + @Override + public String name() { + return "print-statistics"; + } } diff --git a/core/src/main/java/org/lflang/target/property/ProtobufsProperty.java b/core/src/main/java/org/lflang/target/property/ProtobufsProperty.java index d8e0541bff..7fe1dcc94b 100644 --- a/core/src/main/java/org/lflang/target/property/ProtobufsProperty.java +++ b/core/src/main/java/org/lflang/target/property/ProtobufsProperty.java @@ -9,4 +9,9 @@ public class ProtobufsProperty extends AbstractFileListProperty { public List supportedTargets() { return List.of(Target.C, Target.CCPP, Target.TS, Target.Python); } + + @Override + public String name() { + return "protobufs"; + } } 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 755911602b..63db20f871 100644 --- a/core/src/main/java/org/lflang/target/property/Ros2DependenciesProperty.java +++ b/core/src/main/java/org/lflang/target/property/Ros2DependenciesProperty.java @@ -53,4 +53,9 @@ public void validate(KeyValuePair pair, Model ast, MessageReporter reporter) { public Element toAstElement() { return ASTUtils.toElement(get()); } + + @Override + public String name() { + return "ros2-dependencies"; + } } diff --git a/core/src/main/java/org/lflang/target/property/Ros2Property.java b/core/src/main/java/org/lflang/target/property/Ros2Property.java index b768f67d5d..51027779ea 100644 --- a/core/src/main/java/org/lflang/target/property/Ros2Property.java +++ b/core/src/main/java/org/lflang/target/property/Ros2Property.java @@ -9,4 +9,9 @@ public class Ros2Property extends AbstractBooleanProperty { public List supportedTargets() { return List.of(Target.CPP); } + + @Override + public String name() { + return "ros2"; + } } diff --git a/core/src/main/java/org/lflang/target/property/RuntimeVersionProperty.java b/core/src/main/java/org/lflang/target/property/RuntimeVersionProperty.java index 19835dcbd8..36758e8339 100644 --- a/core/src/main/java/org/lflang/target/property/RuntimeVersionProperty.java +++ b/core/src/main/java/org/lflang/target/property/RuntimeVersionProperty.java @@ -9,4 +9,9 @@ public class RuntimeVersionProperty extends AbstractStringConfig { public List supportedTargets() { return List.of(Target.CPP, Target.Rust); } + + @Override + public String name() { + return "runtime-version"; + } } diff --git a/core/src/main/java/org/lflang/target/property/RustIncludeProperty.java b/core/src/main/java/org/lflang/target/property/RustIncludeProperty.java index c448cba296..b375c68e82 100644 --- a/core/src/main/java/org/lflang/target/property/RustIncludeProperty.java +++ b/core/src/main/java/org/lflang/target/property/RustIncludeProperty.java @@ -87,6 +87,11 @@ public Element toAstElement() { } } + @Override + public String name() { + return "rust-include"; + } + private boolean checkTopLevelModule(Path path, EObject errorOwner, MessageReporter err) { String fileName = path.getFileName().toString(); if (!Files.exists(path)) { 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 55b574e4b0..e4613fa0a1 100644 --- a/core/src/main/java/org/lflang/target/property/SchedulerProperty.java +++ b/core/src/main/java/org/lflang/target/property/SchedulerProperty.java @@ -51,6 +51,11 @@ public Element toAstElement() { return ASTUtils.toElement(this.get().toString()); } + @Override + public String name() { + return "scheduler"; + } + @Override public void validate(KeyValuePair pair, Model ast, MessageReporter reporter) { if (pair != null) { diff --git a/core/src/main/java/org/lflang/target/property/SingleFileProjectProperty.java b/core/src/main/java/org/lflang/target/property/SingleFileProjectProperty.java index 651526a642..51d2f058b0 100644 --- a/core/src/main/java/org/lflang/target/property/SingleFileProjectProperty.java +++ b/core/src/main/java/org/lflang/target/property/SingleFileProjectProperty.java @@ -9,4 +9,9 @@ public class SingleFileProjectProperty extends AbstractBooleanProperty { public List supportedTargets() { return List.of(Target.Rust); } + + @Override + public String name() { + return "single-file-project"; + } } diff --git a/core/src/main/java/org/lflang/target/property/ThreadingProperty.java b/core/src/main/java/org/lflang/target/property/ThreadingProperty.java index bfc7881c25..bf5a39f36e 100644 --- a/core/src/main/java/org/lflang/target/property/ThreadingProperty.java +++ b/core/src/main/java/org/lflang/target/property/ThreadingProperty.java @@ -10,6 +10,11 @@ public List supportedTargets() { return List.of(Target.C, Target.CCPP, Target.Python, Target.Rust); } + @Override + public String name() { + return "threading"; + } + @Override public Boolean initialValue() { return true; diff --git a/core/src/main/java/org/lflang/target/property/TimeOutProperty.java b/core/src/main/java/org/lflang/target/property/TimeOutProperty.java index d5bd2310bf..faa6051320 100644 --- a/core/src/main/java/org/lflang/target/property/TimeOutProperty.java +++ b/core/src/main/java/org/lflang/target/property/TimeOutProperty.java @@ -39,4 +39,9 @@ public List supportedTargets() { public Element toAstElement() { return ASTUtils.toElement(get()); } + + @Override + public String name() { + return "timeout"; + } } 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 779ae9f68b..2eb2c1c7cd 100644 --- a/core/src/main/java/org/lflang/target/property/TracingProperty.java +++ b/core/src/main/java/org/lflang/target/property/TracingProperty.java @@ -106,6 +106,11 @@ public Element toAstElement() { } } + @Override + public String name() { + return "tracing"; + } + /** Settings related to tracing options. */ public static class TracingOptions { diff --git a/core/src/main/java/org/lflang/target/property/VerifyProperty.java b/core/src/main/java/org/lflang/target/property/VerifyProperty.java index 1065e4e147..5294c5cc80 100644 --- a/core/src/main/java/org/lflang/target/property/VerifyProperty.java +++ b/core/src/main/java/org/lflang/target/property/VerifyProperty.java @@ -10,4 +10,9 @@ public class VerifyProperty extends AbstractBooleanProperty { public List supportedTargets() { return List.of(Target.C); } + + @Override + public String name() { + return "verify"; + } } 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 823c6d8369..00812da4c1 100644 --- a/core/src/main/java/org/lflang/target/property/WorkersProperty.java +++ b/core/src/main/java/org/lflang/target/property/WorkersProperty.java @@ -38,4 +38,9 @@ public List supportedTargets() { public Element toAstElement() { return ASTUtils.toElement(get()); } + + @Override + public String name() { + return "workers"; + } } From ec56234220901a199e54519478e976b5963401b1 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Mon, 2 Oct 2023 17:56:02 -0700 Subject: [PATCH 067/145] Removal of enums --- .../org/lflang/AbstractTargetProperty.java | 21 ++ .../org/lflang/generator/GeneratorUtils.java | 2 +- .../java/org/lflang/target/TargetConfig.java | 48 +-- .../org/lflang/target/TargetProperty.java | 318 ++---------------- .../lflang/target/property/AuthProperty.java | 1 + .../property/BuildCommandsProperty.java | 1 + .../target/property/BuildTypeProperty.java | 4 + .../property/CargoDependenciesProperty.java | 25 ++ .../property/CargoFeaturesProperty.java | 1 + .../property/ClockSyncModeProperty.java | 1 + .../property/ClockSyncOptionsProperty.java | 1 + .../target/property/CmakeIncludeProperty.java | 6 + .../property/CompileDefinitionsProperty.java | 1 + .../property/CompilerFlagsProperty.java | 1 + .../target/property/CompilerProperty.java | 1 + .../property/CoordinationOptionsProperty.java | 1 + .../target/property/CoordinationProperty.java | 1 + .../target/property/DockerProperty.java | 4 + .../ExportDependencyGraphProperty.java | 5 + .../target/property/ExportToYamlProperty.java | 5 + .../property/ExternalRuntimePathProperty.java | 1 + .../lflang/target/property/FastProperty.java | 1 + .../target/property/FedSetupProperty.java | 4 + .../lflang/target/property/FilesProperty.java | 1 + .../target/property/KeepaliveProperty.java | 4 + .../target/property/LoggingProperty.java | 1 + .../target/property/NoCompileProperty.java | 1 + .../property/NoRuntimeValidationProperty.java | 1 + .../target/property/PlatformProperty.java | 6 +- .../property/PrintStatisticsProperty.java | 1 + .../target/property/ProtobufsProperty.java | 4 + .../property/Ros2DependenciesProperty.java | 3 +- .../lflang/target/property/Ros2Property.java | 1 + .../property/RuntimeVersionProperty.java | 1 + .../target/property/RustIncludeProperty.java | 6 + .../target/property/SchedulerProperty.java | 1 + .../property/SingleFileProjectProperty.java | 1 + .../target/property/ThreadingProperty.java | 1 + .../target/property/TimeOutProperty.java | 1 + .../target/property/TracingProperty.java | 3 +- .../target/property/VerifyProperty.java | 1 + .../target/property/WorkersProperty.java | 1 + .../compiler/LinguaFrancaValidationTest.java | 27 +- 43 files changed, 183 insertions(+), 337 deletions(-) diff --git a/core/src/main/java/org/lflang/AbstractTargetProperty.java b/core/src/main/java/org/lflang/AbstractTargetProperty.java index 1ec4d187f0..53d0ccd4bd 100644 --- a/core/src/main/java/org/lflang/AbstractTargetProperty.java +++ b/core/src/main/java/org/lflang/AbstractTargetProperty.java @@ -1,6 +1,8 @@ package org.lflang; +import java.util.Arrays; import java.util.List; +import java.util.stream.Collectors; import org.lflang.lf.Element; import org.lflang.lf.KeyValuePair; import org.lflang.lf.LfPackage.Literals; @@ -190,4 +192,23 @@ public T get() { /** Return the name of this target property (in kebab case). */ public abstract String name(); + + public static List getAllTargetProperties(Object object) { + var fields = object.getClass().getDeclaredFields(); + + List properties = + Arrays.stream(fields) + .filter(f -> AbstractTargetProperty.class.isAssignableFrom(f.getType())) + .map( + f -> { + try { + return (AbstractTargetProperty) f.get(object); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + }) + .collect(Collectors.toList()); + + return properties; + } } diff --git a/core/src/main/java/org/lflang/generator/GeneratorUtils.java b/core/src/main/java/org/lflang/generator/GeneratorUtils.java index 9c4c1f0270..e2a6e89928 100644 --- a/core/src/main/java/org/lflang/generator/GeneratorUtils.java +++ b/core/src/main/java/org/lflang/generator/GeneratorUtils.java @@ -63,7 +63,7 @@ public static void accommodatePhysicalActionsIfPresent( String message = String.format( "Setting %s to true because of the physical action %s.", - TargetProperty.KEEPALIVE, action.getName()); + targetConfig.keepalive.name(), action.getName()); messageReporter.at(action).warning(message); return; } diff --git a/core/src/main/java/org/lflang/target/TargetConfig.java b/core/src/main/java/org/lflang/target/TargetConfig.java index fe5430197b..23906a80ab 100644 --- a/core/src/main/java/org/lflang/target/TargetConfig.java +++ b/core/src/main/java/org/lflang/target/TargetConfig.java @@ -25,8 +25,8 @@ package org.lflang.target; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; +import java.util.Optional; import java.util.Properties; import java.util.stream.Collectors; import org.lflang.AbstractTargetProperty; @@ -83,6 +83,11 @@ public class TargetConfig { /** The target of this configuration (e.g., C, TypeScript, Python). */ public final Target target; + /** Private constructor used to create a target config that is not tied to a particular target. */ + private TargetConfig() { + this.target = null; + } + /** * Create a new target configuration based on the given target declaration AST node only. * @@ -267,28 +272,29 @@ public TargetConfig(Properties cliArgs, TargetDecl target, MessageReporter messa /** Path to a C file used by the Python target to setup federated execution. */ public final FedSetupProperty fedSetupPreamble = new FedSetupProperty(); - public static List> getAllTargetProperties(Object object) { - var fields = object.getClass().getDeclaredFields(); - - List properties = - Arrays.stream(fields) - .filter(f -> AbstractTargetProperty.class.isAssignableFrom(f.getType())) - .map( - f -> { - try { - return (AbstractTargetProperty) f.get(object); - } catch (IllegalAccessException e) { - throw new RuntimeException(e); - } - }) - .collect(Collectors.toList()); - + public List getAllTargetProperties() { + var properties = AbstractTargetProperty.getAllTargetProperties(this); + properties.addAll(AbstractTargetProperty.getAllTargetProperties(this.rust)); return properties; } - public List> getAllTargetProperties() { - var properties = TargetConfig.getAllTargetProperties(this); - properties.addAll(TargetConfig.getAllTargetProperties(this.rust)); - return properties; + public static List getUserTargetProperties() { + var config = new TargetConfig(); + var properties = AbstractTargetProperty.getAllTargetProperties(config); + properties.addAll(AbstractTargetProperty.getAllTargetProperties(config)); + return properties.stream() + .filter(it -> !it.name().startsWith("_")) + .collect(Collectors.toList()); + } + + /** + * Return the target property in this target config that matches the given string. + * + * @param name The string to match against. + */ + public Optional forName(String name) { + return this.getAllTargetProperties().stream() + .filter(c -> c.name().equalsIgnoreCase(name)) + .findFirst(); } } diff --git a/core/src/main/java/org/lflang/target/TargetProperty.java b/core/src/main/java/org/lflang/target/TargetProperty.java index 50761efd1b..fd85287440 100644 --- a/core/src/main/java/org/lflang/target/TargetProperty.java +++ b/core/src/main/java/org/lflang/target/TargetProperty.java @@ -26,7 +26,6 @@ package org.lflang.target; import java.nio.file.Path; -import java.util.Arrays; import java.util.LinkedList; import java.util.List; import java.util.Objects; @@ -43,44 +42,6 @@ import org.lflang.lf.LfPackage.Literals; import org.lflang.lf.Model; import org.lflang.lf.TargetDecl; -import org.lflang.target.property.AuthProperty; -import org.lflang.target.property.BuildCommandsProperty; -import org.lflang.target.property.BuildTypeProperty; -import org.lflang.target.property.CargoDependenciesProperty; -import org.lflang.target.property.CargoFeaturesProperty; -import org.lflang.target.property.ClockSyncModeProperty; -import org.lflang.target.property.ClockSyncOptionsProperty; -import org.lflang.target.property.CmakeIncludeProperty; -import org.lflang.target.property.CompileDefinitionsProperty; -import org.lflang.target.property.CompilerFlagsProperty; -import org.lflang.target.property.CompilerProperty; -import org.lflang.target.property.CoordinationOptionsProperty; -import org.lflang.target.property.CoordinationProperty; -import org.lflang.target.property.DockerProperty; -import org.lflang.target.property.ExportDependencyGraphProperty; -import org.lflang.target.property.ExportToYamlProperty; -import org.lflang.target.property.ExternalRuntimePathProperty; -import org.lflang.target.property.FastProperty; -import org.lflang.target.property.FedSetupProperty; -import org.lflang.target.property.FilesProperty; -import org.lflang.target.property.KeepaliveProperty; -import org.lflang.target.property.LoggingProperty; -import org.lflang.target.property.NoCompileProperty; -import org.lflang.target.property.NoRuntimeValidationProperty; -import org.lflang.target.property.PlatformProperty; -import org.lflang.target.property.PrintStatisticsProperty; -import org.lflang.target.property.ProtobufsProperty; -import org.lflang.target.property.Ros2DependenciesProperty; -import org.lflang.target.property.Ros2Property; -import org.lflang.target.property.RuntimeVersionProperty; -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.TimeOutProperty; -import org.lflang.target.property.TracingProperty; -import org.lflang.target.property.WorkersProperty; -import org.lflang.target.property.type.VerifyProperty; import org.lflang.validation.ValidatorMessageReporter; /** @@ -89,215 +50,14 @@ * * @author Marten Lohstroh */ -public enum TargetProperty { - - /** Directive to allow including OpenSSL libraries and process HMAC authentication. */ - AUTH(AuthProperty.class, config -> config.auth), - /** Directive to let the generator use the custom build command. */ - BUILD(BuildCommandsProperty.class, config -> config.buildCommands), - - /** - * Directive to specify the target build type such as 'Release' or 'Debug'. This is also used in - * the Rust target to select a Cargo profile. - */ - BUILD_TYPE(BuildTypeProperty.class, config -> config.buildType), - - /** Directive to let the federate execution handle clock synchronization in software. */ - CLOCK_SYNC(ClockSyncModeProperty.class, config -> config.clockSync), - /** Key-value pairs giving options for clock synchronization. */ - CLOCK_SYNC_OPTIONS(ClockSyncOptionsProperty.class, config -> config.clockSyncOptions), - - /** - * Directive to specify a cmake to be included by the generated build systems. - * - *

This gives full control over the C/C++ build as any cmake parameters can be adjusted in the - * included file. - */ - CMAKE_INCLUDE(CmakeIncludeProperty.class, config -> config.cmakeIncludes), - /** Directive to specify the target compiler. */ - COMPILER(CompilerProperty.class, config -> config.compiler), - /** Directive to specify compile-time definitions. */ - COMPILE_DEFINITIONS(CompileDefinitionsProperty.class, config -> config.compileDefinitions), - - /** Directive to specify the coordination mode */ - COORDINATION(CoordinationProperty.class, config -> config.coordination), - /** Key-value pairs giving options for clock synchronization. */ - COORDINATION_OPTIONS(CoordinationOptionsProperty.class, config -> config.coordinationOptions), - /** - * Directive to generate a Dockerfile. This is either a boolean, true or false, or a dictionary of - * options. - */ - DOCKER(DockerProperty.class, config -> config.dockerOptions), - /** Directive for specifying a path to an external runtime to be used for the compiled binary. */ - EXTERNAL_RUNTIME_PATH(ExternalRuntimePathProperty.class, config -> config.externalRuntimePath), - /** - * Directive to let the execution engine allow logical time to elapse faster than physical time. - */ - FAST(FastProperty.class, config -> config.fastMode), - /** - * Directive to stage particular files on the class path to be processed by the code generator. - */ - FILES(FilesProperty.class, config -> config.files), - - /** Flags to be passed on to the target compiler. */ - FLAGS(CompilerFlagsProperty.class, config -> config.compilerFlags), - - /** - * Directive to let the execution engine remain active also if there are no more events in the - * event queue. - */ - KEEPALIVE(KeepaliveProperty.class, config -> config.keepalive), - - /** Directive to specify the grain at which to report log messages during execution. */ - LOGGING(LoggingProperty.class, config -> config.logLevel), - - /** Directive to not invoke the target compiler. */ - NO_COMPILE(NoCompileProperty.class, config -> config.noCompile), - - /** Directive to disable validation of reactor rules at runtime. */ - NO_RUNTIME_VALIDATION(NoRuntimeValidationProperty.class, config -> config.noRuntimeValidation), - - /** - * Directive to specify the platform for cross code generation. This is either a string of the - * platform or a dictionary of options that includes the string name. - */ - PLATFORM(PlatformProperty.class, config -> config.platformOptions), - - /** Directive to instruct the runtime to collect and print execution statistics. */ - PRINT_STATISTICS(PrintStatisticsProperty.class, config -> config.printStatistics), - - /** - * Directive for specifying .proto files that need to be compiled and their code included in the - * sources. - */ - PROTOBUFS(ProtobufsProperty.class, config -> config.protoFiles), - - /** Directive to specify that ROS2 specific code is generated, */ - ROS2(Ros2Property.class, config -> config.ros2), - - /** Directive to specify additional ROS2 packages that this LF program depends on. */ - ROS2_DEPENDENCIES(Ros2DependenciesProperty.class, config -> config.ros2Dependencies), - - /** Directive for specifying a specific version of the reactor runtime library. */ - RUNTIME_VERSION(RuntimeVersionProperty.class, config -> config.runtimeVersion), - - /** Directive for specifying a specific runtime scheduler, if supported. */ - SCHEDULER(SchedulerProperty.class, config -> config.schedulerType), - /** Directive to specify that all code is generated in a single file. */ - SINGLE_FILE_PROJECT(SingleFileProjectProperty.class, config -> config.singleFileProject), - - /** Directive to indicate whether the runtime should use multi-threading. */ - THREADING(ThreadingProperty.class, config -> config.threading), - /** Directive to check the generated verification model. */ - VERIFY(VerifyProperty.class, config -> config.verify), - - /** Directive to specify the number of worker threads used by the runtime. */ - WORKERS(WorkersProperty.class, config -> config.workers), - - /** Directive to specify the execution timeout. */ - TIMEOUT(TimeOutProperty.class, config -> config.timeout), - - /** Directive to enable tracing. */ - TRACING(TracingProperty.class, config -> config.tracing), - - /** - * Directive to let the runtime export its internal dependency graph. - * - *

This is a debugging feature and currently only used for C++ and Rust programs. - */ - EXPORT_DEPENDENCY_GRAPH( - ExportDependencyGraphProperty.class, config -> config.exportDependencyGraph), - - /** - * Directive to let the runtime export the program structure to a yaml file. - * - *

This is a debugging feature and currently only used for C++ programs. - */ - EXPORT_TO_YAML(ExportToYamlProperty.class, config -> config.exportToYaml), - - /** - * List of module files to link into the crate as top-level. For instance, a {@code target Rust { - * rust-modules: [ "foo.rs" ] }} will cause the file to be copied into the generated project, and - * the generated {@code main.rs} will include it with a {@code mod foo;}. If one of the paths is a - * directory, it must contain a {@code mod.rs} file, and all its contents are copied. - */ - RUST_INCLUDE(RustIncludeProperty.class, config -> config.rust.rustTopLevelModules), - - /** Directive for specifying Cargo features of the generated program to enable. */ - CARGO_FEATURES(CargoFeaturesProperty.class, config -> config.rust.cargoFeatures), - - /** - * Dependency specifications for Cargo. This property looks like this: - * - *

{@code
-   * cargo-dependencies: {
-   *    // Name-of-the-crate: "version"
-   *    rand: "0.8",
-   *    // Equivalent to using an explicit map:
-   *    rand: {
-   *      version: "0.8"
-   *    },
-   *    // The map allows specifying more details
-   *    rand: {
-   *      // A path to a local unpublished crate.
-   *      // Note 'path' is mutually exclusive with 'version'.
-   *      path: "/home/me/Git/local-rand-clone"
-   *    },
-   *    rand: {
-   *      version: "0.8",
-   *      // you can specify cargo features
-   *      features: ["some-cargo-feature",]
-   *    }
-   * }
-   * }
- */ - CARGO_DEPENDENCIES(CargoDependenciesProperty.class, config -> config.rust.cargoDependencies), - - /** - * Directs the C or Python target to include the associated C file used for setting up federated - * execution before processing the first tag. - */ - FED_SETUP(FedSetupProperty.class, config -> config.fedSetupPreamble); - - public final ConfigLoader property; - - public final Class> propertyClass; - - @FunctionalInterface - private interface ConfigLoader { - AbstractTargetProperty of(TargetConfig config); - } - - TargetProperty(Class> cls, ConfigLoader property) { - this.propertyClass = cls; - this.property = property; - } - - /** - * Return key ot the property as it will be used in LF code. - * - *

Keys are of the form foo-bar. - * - * @return the property's key - */ - public String getKey() { - return name().toLowerCase().replace('_', '-'); - } - - public static AbstractTargetProperty getPropertyInstance(TargetProperty p) { - try { - return p.propertyClass.getDeclaredConstructor().newInstance(); - } catch (ReflectiveOperationException e) { - throw new RuntimeException(e); - } - } +public class TargetProperty { public static void load(TargetConfig config, Properties properties, MessageReporter err) { for (Object key : properties.keySet()) { - TargetProperty p = forName(key.toString()); - if (p != null) { + var p = config.forName(key.toString()); + if (p.isPresent()) { try { - p.property.of(config).set(properties.get(key).toString(), err); + p.get().set(properties.get(key).toString(), err); } catch (InvalidLfSourceException e) { err.at(e.getNode()).error(e.getProblem()); } @@ -318,10 +78,10 @@ public static void load(TargetConfig config, List properties, Mess } properties.forEach( property -> { - TargetProperty p = forName(property.getName()); - if (p != null) { + var p = config.forName(property.getName()); + if (p.isPresent()) { try { - p.property.of(config).set(property.getValue(), err); + p.get().set(property.getValue(), err); } catch (InvalidLfSourceException e) { err.at(e.getNode()).error(e.getProblem()); } @@ -338,10 +98,10 @@ public static void load(TargetConfig config, List properties, Mess */ public static List extractProperties(TargetConfig config) { var res = new LinkedList(); - for (TargetProperty p : TargetProperty.loaded(config)) { + for (AbstractTargetProperty p : TargetProperty.loaded(config)) { KeyValuePair kv = LfFactory.eINSTANCE.createKeyValuePair(); - kv.setName(p.toString()); - kv.setValue(p.property.of(config).toAstElement()); + kv.setName(p.name()); + kv.setValue(p.toAstElement()); if (kv.getValue() != null) { res.add(kv); } @@ -354,9 +114,9 @@ public static List extractProperties(TargetConfig config) { * * @param config The configuration to find the properties in. */ - public static List loaded(TargetConfig config) { - return Arrays.stream(TargetProperty.values()) - .filter(it -> it.property.of(config).isSet()) + public static List loaded(TargetConfig config) { + return config.getAllTargetProperties().stream() + .filter(p -> p.isSet()) .collect(Collectors.toList()); } @@ -385,25 +145,16 @@ public static TargetDecl extractTargetDecl(Target target, TargetConfig config) { * @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) { + public static KeyValuePair getKeyValuePair(Model ast, AbstractTargetProperty property) { var targetProperties = ast.getTarget().getConfig(); List properties = targetProperties.getPairs().stream() - .filter(pair -> pair.getName().equals(property.toString())) + .filter(pair -> pair.getName().equals(property.name())) .toList(); assert properties.size() <= 1; return properties.size() > 0 ? properties.get(0) : null; } - /** Return a list containing the keys of all properties */ - public static List getPropertyKeys() { - return Arrays.stream(TargetProperty.values()) - .map(TargetProperty::toString) - .filter(it -> !it.startsWith("_")) - .sorted() - .toList(); - } - /** * Validate the given key-value pairs and report issues via the given reporter. * @@ -433,7 +184,7 @@ public static void validate( "Unrecognized target property: " + pair.getName() + ". Recognized properties are: " - + getPropertyKeys()); + + TargetConfig.getUserTargetProperties()); } }); } @@ -450,8 +201,8 @@ public static void update( TargetConfig config, List properties, Path relativePath, MessageReporter err) { properties.forEach( property -> { - TargetProperty p = forName(property.getName()); - if (p != null) { + var p = config.forName(property.getName()); + if (p.isPresent()) { var value = property.getValue(); if (property.getName().equals("files")) { var array = LfFactory.eINSTANCE.createArray(); @@ -468,39 +219,8 @@ public static void update( value = LfFactory.eINSTANCE.createElement(); value.setArray(array); } - p.property.of(config).set(value, err); + p.get().set(value, err); } }); } - - /** - * Return the entry that matches the given string. - * - * @param name The string to match against. - */ - public static TargetProperty forName(String name) { - return Target.match(name, TargetProperty.values()); - } - - /** - * Return a list with all target properties. - * - * @return All existing target properties. - */ - public static List getOptions() { - return Arrays.asList(TargetProperty.values()); - } - - /** - * Return the name of the property in as it appears in the target declaration. It may be an - * invalid identifier in other languages (may contains dashes {@code -}). - */ - @Override - public String toString() { - // Workaround because this sole property does not follow the naming convention. - if (this.equals(FED_SETUP)) { - return "_fed_setup"; - } - return this.name().toLowerCase().replaceAll("_", "-"); - } } diff --git a/core/src/main/java/org/lflang/target/property/AuthProperty.java b/core/src/main/java/org/lflang/target/property/AuthProperty.java index 6540d0780f..a3e9ee6b1f 100644 --- a/core/src/main/java/org/lflang/target/property/AuthProperty.java +++ b/core/src/main/java/org/lflang/target/property/AuthProperty.java @@ -4,6 +4,7 @@ import java.util.List; import org.lflang.Target; +/** Directive to allow including OpenSSL libraries and process HMAC authentication. */ public class AuthProperty extends AbstractBooleanProperty { @Override diff --git a/core/src/main/java/org/lflang/target/property/BuildCommandsProperty.java b/core/src/main/java/org/lflang/target/property/BuildCommandsProperty.java index cb46e4864c..78c320d09f 100644 --- a/core/src/main/java/org/lflang/target/property/BuildCommandsProperty.java +++ b/core/src/main/java/org/lflang/target/property/BuildCommandsProperty.java @@ -10,6 +10,7 @@ import org.lflang.lf.Element; import org.lflang.target.property.type.UnionType; +/** Directive to let the generator use the custom build command. */ public class BuildCommandsProperty extends AbstractTargetProperty> { public BuildCommandsProperty() { diff --git a/core/src/main/java/org/lflang/target/property/BuildTypeProperty.java b/core/src/main/java/org/lflang/target/property/BuildTypeProperty.java index f69f40e94a..97ffcd560c 100644 --- a/core/src/main/java/org/lflang/target/property/BuildTypeProperty.java +++ b/core/src/main/java/org/lflang/target/property/BuildTypeProperty.java @@ -10,6 +10,10 @@ import org.lflang.target.property.BuildTypeProperty.BuildType; import org.lflang.target.property.type.UnionType; +/** + * Directive to specify the target build type such as 'Release' or 'Debug'. This is also used in the + * Rust target to select a Cargo profile. + */ public class BuildTypeProperty extends AbstractTargetProperty { public BuildTypeProperty() { 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 b349541183..bfc948cbd8 100644 --- a/core/src/main/java/org/lflang/target/property/CargoDependenciesProperty.java +++ b/core/src/main/java/org/lflang/target/property/CargoDependenciesProperty.java @@ -14,6 +14,31 @@ import org.lflang.lf.KeyValuePairs; import org.lflang.lf.LfFactory; +/** + * Dependency specifications for Cargo. This property looks like this: + * + *

{@code
+ * cargo-dependencies: {
+ *    // Name-of-the-crate: "version"
+ *    rand: "0.8",
+ *    // Equivalent to using an explicit map:
+ *    rand: {
+ *      version: "0.8"
+ *    },
+ *    // The map allows specifying more details
+ *    rand: {
+ *      // A path to a local unpublished crate.
+ *      // Note 'path' is mutually exclusive with 'version'.
+ *      path: "/home/me/Git/local-rand-clone"
+ *    },
+ *    rand: {
+ *      version: "0.8",
+ *      // you can specify cargo features
+ *      features: ["some-cargo-feature",]
+ *    }
+ * }
+ * }
+ */ public class CargoDependenciesProperty extends AbstractTargetProperty> { diff --git a/core/src/main/java/org/lflang/target/property/CargoFeaturesProperty.java b/core/src/main/java/org/lflang/target/property/CargoFeaturesProperty.java index ac1d299d08..afe9d7efc9 100644 --- a/core/src/main/java/org/lflang/target/property/CargoFeaturesProperty.java +++ b/core/src/main/java/org/lflang/target/property/CargoFeaturesProperty.java @@ -4,6 +4,7 @@ import java.util.List; import org.lflang.Target; +/** Directive for specifying Cargo features of the generated program to enable. */ public class CargoFeaturesProperty extends AbstractStringListProperty { @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 ce7bd3f6d8..224cbe1a2f 100644 --- a/core/src/main/java/org/lflang/target/property/ClockSyncModeProperty.java +++ b/core/src/main/java/org/lflang/target/property/ClockSyncModeProperty.java @@ -14,6 +14,7 @@ import org.lflang.target.property.ClockSyncModeProperty.ClockSyncMode; import org.lflang.target.property.type.UnionType; +/** Directive to let the federate execution handle clock synchronization in software. */ public class ClockSyncModeProperty extends AbstractTargetProperty { public ClockSyncModeProperty() { 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 6227efe33f..b0909c2689 100644 --- a/core/src/main/java/org/lflang/target/property/ClockSyncOptionsProperty.java +++ b/core/src/main/java/org/lflang/target/property/ClockSyncOptionsProperty.java @@ -18,6 +18,7 @@ import org.lflang.target.property.type.PrimitiveType; import org.lflang.target.property.type.TargetPropertyType; +/** Key-value pairs giving options for clock synchronization. */ public class ClockSyncOptionsProperty extends AbstractTargetProperty { public ClockSyncOptionsProperty() { diff --git a/core/src/main/java/org/lflang/target/property/CmakeIncludeProperty.java b/core/src/main/java/org/lflang/target/property/CmakeIncludeProperty.java index 90b1c5c297..7413bf8728 100644 --- a/core/src/main/java/org/lflang/target/property/CmakeIncludeProperty.java +++ b/core/src/main/java/org/lflang/target/property/CmakeIncludeProperty.java @@ -10,6 +10,12 @@ import org.lflang.lf.Element; import org.lflang.target.property.type.UnionType; +/** + * Directive to specify a cmake to be included by the generated build systems. + * + *

This gives full control over the C/C++ build as any cmake parameters can be adjusted in the + * included file. + */ public class CmakeIncludeProperty extends AbstractTargetProperty> { public CmakeIncludeProperty() { diff --git a/core/src/main/java/org/lflang/target/property/CompileDefinitionsProperty.java b/core/src/main/java/org/lflang/target/property/CompileDefinitionsProperty.java index 6c3a826f30..ff4aa30e11 100644 --- a/core/src/main/java/org/lflang/target/property/CompileDefinitionsProperty.java +++ b/core/src/main/java/org/lflang/target/property/CompileDefinitionsProperty.java @@ -11,6 +11,7 @@ import org.lflang.lf.Element; import org.lflang.target.property.type.StringDictionaryType; +/** Directive to specify compile-time definitions. */ public class CompileDefinitionsProperty extends AbstractTargetProperty> { public CompileDefinitionsProperty() { diff --git a/core/src/main/java/org/lflang/target/property/CompilerFlagsProperty.java b/core/src/main/java/org/lflang/target/property/CompilerFlagsProperty.java index acd12748ba..ebae420a1b 100644 --- a/core/src/main/java/org/lflang/target/property/CompilerFlagsProperty.java +++ b/core/src/main/java/org/lflang/target/property/CompilerFlagsProperty.java @@ -4,6 +4,7 @@ import java.util.List; import org.lflang.Target; +/** Flags to be passed on to the target compiler. */ public class CompilerFlagsProperty extends AbstractStringListProperty { @Override diff --git a/core/src/main/java/org/lflang/target/property/CompilerProperty.java b/core/src/main/java/org/lflang/target/property/CompilerProperty.java index 0be8df2f76..d9ce97ce50 100644 --- a/core/src/main/java/org/lflang/target/property/CompilerProperty.java +++ b/core/src/main/java/org/lflang/target/property/CompilerProperty.java @@ -3,6 +3,7 @@ import java.util.List; import org.lflang.Target; +/** Directive to specify the target compiler. */ public class CompilerProperty extends AbstractStringConfig { @Override 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 60575e3c01..c2d4e94b90 100644 --- a/core/src/main/java/org/lflang/target/property/CoordinationOptionsProperty.java +++ b/core/src/main/java/org/lflang/target/property/CoordinationOptionsProperty.java @@ -18,6 +18,7 @@ import org.lflang.target.property.type.PrimitiveType; import org.lflang.target.property.type.TargetPropertyType; +/** Key-value pairs giving options for clock synchronization. */ public class CoordinationOptionsProperty extends AbstractTargetProperty { public CoordinationOptionsProperty() { diff --git a/core/src/main/java/org/lflang/target/property/CoordinationProperty.java b/core/src/main/java/org/lflang/target/property/CoordinationProperty.java index 65b9f7fbb8..4837a68317 100644 --- a/core/src/main/java/org/lflang/target/property/CoordinationProperty.java +++ b/core/src/main/java/org/lflang/target/property/CoordinationProperty.java @@ -10,6 +10,7 @@ import org.lflang.target.property.CoordinationProperty.CoordinationMode; import org.lflang.target.property.type.UnionType; +/** Directive to specify the coordination mode */ public class CoordinationProperty extends AbstractTargetProperty { public CoordinationProperty() { 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 89ab7bef06..ea09ae836e 100644 --- a/core/src/main/java/org/lflang/target/property/DockerProperty.java +++ b/core/src/main/java/org/lflang/target/property/DockerProperty.java @@ -18,6 +18,10 @@ import org.lflang.target.property.type.TargetPropertyType; import org.lflang.target.property.type.UnionType; +/** + * Directive to generate a Dockerfile. This is either a boolean, true or false, or a dictionary of + * options. + */ public class DockerProperty extends AbstractTargetProperty { public DockerProperty() { diff --git a/core/src/main/java/org/lflang/target/property/ExportDependencyGraphProperty.java b/core/src/main/java/org/lflang/target/property/ExportDependencyGraphProperty.java index 761eded16c..ae79262988 100644 --- a/core/src/main/java/org/lflang/target/property/ExportDependencyGraphProperty.java +++ b/core/src/main/java/org/lflang/target/property/ExportDependencyGraphProperty.java @@ -3,6 +3,11 @@ import java.util.List; import org.lflang.Target; +/** + * Directive to let the runtime export its internal dependency graph. + * + *

This is a debugging feature and currently only used for C++ and Rust programs. + */ public class ExportDependencyGraphProperty extends AbstractBooleanProperty { @Override diff --git a/core/src/main/java/org/lflang/target/property/ExportToYamlProperty.java b/core/src/main/java/org/lflang/target/property/ExportToYamlProperty.java index a4aebb4d16..ed83f76787 100644 --- a/core/src/main/java/org/lflang/target/property/ExportToYamlProperty.java +++ b/core/src/main/java/org/lflang/target/property/ExportToYamlProperty.java @@ -3,6 +3,11 @@ import java.util.List; import org.lflang.Target; +/** + * Directive to let the runtime export the program structure to a yaml file. + * + *

This is a debugging feature and currently only used for C++ programs. + */ public class ExportToYamlProperty extends AbstractBooleanProperty { @Override diff --git a/core/src/main/java/org/lflang/target/property/ExternalRuntimePathProperty.java b/core/src/main/java/org/lflang/target/property/ExternalRuntimePathProperty.java index 6c704974ac..68540cc948 100644 --- a/core/src/main/java/org/lflang/target/property/ExternalRuntimePathProperty.java +++ b/core/src/main/java/org/lflang/target/property/ExternalRuntimePathProperty.java @@ -3,6 +3,7 @@ import java.util.List; import org.lflang.Target; +/** Directive for specifying a path to an external runtime to be used for the compiled binary. */ public class ExternalRuntimePathProperty extends AbstractStringConfig { @Override 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 9d019386b5..b24b032ce7 100644 --- a/core/src/main/java/org/lflang/target/property/FastProperty.java +++ b/core/src/main/java/org/lflang/target/property/FastProperty.java @@ -11,6 +11,7 @@ import org.lflang.lf.Model; import org.lflang.lf.Reactor; +/** Directive to let the execution engine allow logical time to elapse faster than physical time. */ public class FastProperty extends AbstractBooleanProperty { @Override diff --git a/core/src/main/java/org/lflang/target/property/FedSetupProperty.java b/core/src/main/java/org/lflang/target/property/FedSetupProperty.java index 83ede21100..1fde72bdc1 100644 --- a/core/src/main/java/org/lflang/target/property/FedSetupProperty.java +++ b/core/src/main/java/org/lflang/target/property/FedSetupProperty.java @@ -9,6 +9,10 @@ import org.lflang.target.property.type.PrimitiveType; import org.lflang.util.StringUtil; +/** + * Directs the C or Python target to include the associated C file used for setting up federated + * execution before processing the first tag. + */ public class FedSetupProperty extends AbstractTargetProperty { public FedSetupProperty() { diff --git a/core/src/main/java/org/lflang/target/property/FilesProperty.java b/core/src/main/java/org/lflang/target/property/FilesProperty.java index d0819fbac5..77159fcddb 100644 --- a/core/src/main/java/org/lflang/target/property/FilesProperty.java +++ b/core/src/main/java/org/lflang/target/property/FilesProperty.java @@ -3,6 +3,7 @@ import java.util.List; import org.lflang.Target; +/** Directive to stage particular files on the class path to be processed by the code generator. */ public class FilesProperty extends AbstractFileListProperty { @Override diff --git a/core/src/main/java/org/lflang/target/property/KeepaliveProperty.java b/core/src/main/java/org/lflang/target/property/KeepaliveProperty.java index d40c5ccccd..787c8967e2 100644 --- a/core/src/main/java/org/lflang/target/property/KeepaliveProperty.java +++ b/core/src/main/java/org/lflang/target/property/KeepaliveProperty.java @@ -3,6 +3,10 @@ import java.util.List; import org.lflang.Target; +/** + * Directive to let the execution engine remain active also if there are no more events in the event + * queue. + */ public class KeepaliveProperty extends AbstractBooleanProperty { @Override diff --git a/core/src/main/java/org/lflang/target/property/LoggingProperty.java b/core/src/main/java/org/lflang/target/property/LoggingProperty.java index 554bfbebeb..f90179d67d 100644 --- a/core/src/main/java/org/lflang/target/property/LoggingProperty.java +++ b/core/src/main/java/org/lflang/target/property/LoggingProperty.java @@ -9,6 +9,7 @@ import org.lflang.target.property.LoggingProperty.LogLevel; import org.lflang.target.property.type.UnionType; +/** Directive to specify the grain at which to report log messages during execution. */ public class LoggingProperty extends AbstractTargetProperty { public LoggingProperty() { diff --git a/core/src/main/java/org/lflang/target/property/NoCompileProperty.java b/core/src/main/java/org/lflang/target/property/NoCompileProperty.java index 12728f02e9..66d6e877a9 100644 --- a/core/src/main/java/org/lflang/target/property/NoCompileProperty.java +++ b/core/src/main/java/org/lflang/target/property/NoCompileProperty.java @@ -4,6 +4,7 @@ import java.util.List; import org.lflang.Target; +/** Directive to not invoke the target compiler. */ public class NoCompileProperty extends AbstractBooleanProperty { @Override diff --git a/core/src/main/java/org/lflang/target/property/NoRuntimeValidationProperty.java b/core/src/main/java/org/lflang/target/property/NoRuntimeValidationProperty.java index e7fe466d29..a3beacb951 100644 --- a/core/src/main/java/org/lflang/target/property/NoRuntimeValidationProperty.java +++ b/core/src/main/java/org/lflang/target/property/NoRuntimeValidationProperty.java @@ -3,6 +3,7 @@ import java.util.List; import org.lflang.Target; +/** Directive to disable validation of reactor rules at runtime. */ public class NoRuntimeValidationProperty extends AbstractBooleanProperty { @Override 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 310cedcd63..75aa611a4f 100644 --- a/core/src/main/java/org/lflang/target/property/PlatformProperty.java +++ b/core/src/main/java/org/lflang/target/property/PlatformProperty.java @@ -21,6 +21,10 @@ import org.lflang.target.property.type.TargetPropertyType; import org.lflang.target.property.type.UnionType; +/** + * Directive to specify the platform for cross code generation. This is either a string of the + * platform or a dictionary of options that includes the string name. + */ public class PlatformProperty extends AbstractTargetProperty { public static final String UNKNOW_PLATFORM = @@ -100,7 +104,7 @@ public void validate(KeyValuePair pair, Model ast, MessageReporter reporter) { } } - var threading = TargetProperty.getKeyValuePair(ast, TargetProperty.THREADING); + var threading = TargetProperty.getKeyValuePair(ast, new ThreadingProperty()); if (threading != null && platform == Platform.RP2040) { reporter .at(pair, Literals.KEY_VALUE_PAIR__VALUE) diff --git a/core/src/main/java/org/lflang/target/property/PrintStatisticsProperty.java b/core/src/main/java/org/lflang/target/property/PrintStatisticsProperty.java index 928ca07dbc..8f6fa48445 100644 --- a/core/src/main/java/org/lflang/target/property/PrintStatisticsProperty.java +++ b/core/src/main/java/org/lflang/target/property/PrintStatisticsProperty.java @@ -3,6 +3,7 @@ import java.util.List; import org.lflang.Target; +/** Directive to instruct the runtime to collect and print execution statistics. */ public class PrintStatisticsProperty extends AbstractBooleanProperty { @Override diff --git a/core/src/main/java/org/lflang/target/property/ProtobufsProperty.java b/core/src/main/java/org/lflang/target/property/ProtobufsProperty.java index 7fe1dcc94b..79bd510f21 100644 --- a/core/src/main/java/org/lflang/target/property/ProtobufsProperty.java +++ b/core/src/main/java/org/lflang/target/property/ProtobufsProperty.java @@ -3,6 +3,10 @@ import java.util.List; import org.lflang.Target; +/** + * Directive for specifying .proto files that need to be compiled and their code included in the + * sources. + */ public class ProtobufsProperty extends AbstractFileListProperty { @Override 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 63db20f871..ce766942dc 100644 --- a/core/src/main/java/org/lflang/target/property/Ros2DependenciesProperty.java +++ b/core/src/main/java/org/lflang/target/property/Ros2DependenciesProperty.java @@ -13,6 +13,7 @@ import org.lflang.target.TargetProperty; import org.lflang.target.property.type.ArrayType; +/** Directive to specify additional ROS2 packages that this LF program depends on. */ public class Ros2DependenciesProperty extends AbstractTargetProperty> { public Ros2DependenciesProperty() { @@ -41,7 +42,7 @@ public List supportedTargets() { @Override public void validate(KeyValuePair pair, Model ast, MessageReporter reporter) { - var ros2enabled = TargetProperty.getKeyValuePair(ast, TargetProperty.ROS2); + var ros2enabled = TargetProperty.getKeyValuePair(ast, new Ros2Property()); if (pair != null && (ros2enabled == null || !ASTUtils.toBoolean(ros2enabled.getValue()))) { reporter .at(pair, Literals.KEY_VALUE_PAIR__NAME) diff --git a/core/src/main/java/org/lflang/target/property/Ros2Property.java b/core/src/main/java/org/lflang/target/property/Ros2Property.java index 51027779ea..4b797e8fa7 100644 --- a/core/src/main/java/org/lflang/target/property/Ros2Property.java +++ b/core/src/main/java/org/lflang/target/property/Ros2Property.java @@ -3,6 +3,7 @@ import java.util.List; import org.lflang.Target; +/** Directive to specify that ROS2 specific code is generated. */ public class Ros2Property extends AbstractBooleanProperty { @Override diff --git a/core/src/main/java/org/lflang/target/property/RuntimeVersionProperty.java b/core/src/main/java/org/lflang/target/property/RuntimeVersionProperty.java index 36758e8339..68c41f8c81 100644 --- a/core/src/main/java/org/lflang/target/property/RuntimeVersionProperty.java +++ b/core/src/main/java/org/lflang/target/property/RuntimeVersionProperty.java @@ -3,6 +3,7 @@ import java.util.List; import org.lflang.Target; +/** Directive for specifying a specific version of the reactor runtime library. */ public class RuntimeVersionProperty extends AbstractStringConfig { @Override diff --git a/core/src/main/java/org/lflang/target/property/RustIncludeProperty.java b/core/src/main/java/org/lflang/target/property/RustIncludeProperty.java index b375c68e82..110b94d977 100644 --- a/core/src/main/java/org/lflang/target/property/RustIncludeProperty.java +++ b/core/src/main/java/org/lflang/target/property/RustIncludeProperty.java @@ -16,6 +16,12 @@ import org.lflang.util.FileUtil; import org.lflang.util.StringUtil; +/** + * List of module files to link into the crate as top-level. For instance, a {@code target Rust { + * rust-modules: [ "foo.rs" ] }} will cause the file to be copied into the generated project, and + * the generated {@code main.rs} will include it with a {@code mod foo;}. If one of the paths is a + * directory, it must contain a {@code mod.rs} file, and all its contents are copied. + */ public class RustIncludeProperty extends AbstractTargetProperty> { public RustIncludeProperty() { 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 e4613fa0a1..ff280fc18e 100644 --- a/core/src/main/java/org/lflang/target/property/SchedulerProperty.java +++ b/core/src/main/java/org/lflang/target/property/SchedulerProperty.java @@ -15,6 +15,7 @@ import org.lflang.target.property.SchedulerProperty.SchedulerOption; import org.lflang.target.property.type.UnionType; +/** Directive for specifying a specific runtime scheduler, if supported. */ public class SchedulerProperty extends AbstractTargetProperty { public SchedulerProperty() { diff --git a/core/src/main/java/org/lflang/target/property/SingleFileProjectProperty.java b/core/src/main/java/org/lflang/target/property/SingleFileProjectProperty.java index 51d2f058b0..7434907305 100644 --- a/core/src/main/java/org/lflang/target/property/SingleFileProjectProperty.java +++ b/core/src/main/java/org/lflang/target/property/SingleFileProjectProperty.java @@ -3,6 +3,7 @@ import java.util.List; import org.lflang.Target; +/** Directive to specify that all code is generated in a single file. */ public class SingleFileProjectProperty extends AbstractBooleanProperty { @Override diff --git a/core/src/main/java/org/lflang/target/property/ThreadingProperty.java b/core/src/main/java/org/lflang/target/property/ThreadingProperty.java index bf5a39f36e..4bbcf3aba6 100644 --- a/core/src/main/java/org/lflang/target/property/ThreadingProperty.java +++ b/core/src/main/java/org/lflang/target/property/ThreadingProperty.java @@ -3,6 +3,7 @@ import java.util.List; import org.lflang.Target; +/** Directive to indicate whether the runtime should use multi-threading. */ public class ThreadingProperty extends AbstractBooleanProperty { @Override diff --git a/core/src/main/java/org/lflang/target/property/TimeOutProperty.java b/core/src/main/java/org/lflang/target/property/TimeOutProperty.java index faa6051320..a43ef6c059 100644 --- a/core/src/main/java/org/lflang/target/property/TimeOutProperty.java +++ b/core/src/main/java/org/lflang/target/property/TimeOutProperty.java @@ -9,6 +9,7 @@ import org.lflang.lf.Element; import org.lflang.target.property.type.PrimitiveType; +/** Directive to specify the execution timeout. */ public class TimeOutProperty extends AbstractTargetProperty { public TimeOutProperty() { 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 2eb2c1c7cd..9f0835a9c6 100644 --- a/core/src/main/java/org/lflang/target/property/TracingProperty.java +++ b/core/src/main/java/org/lflang/target/property/TracingProperty.java @@ -20,6 +20,7 @@ import org.lflang.target.property.type.TargetPropertyType; import org.lflang.target.property.type.UnionType; +/** Directive to enable tracing. */ public class TracingProperty extends AbstractTargetProperty { public TracingProperty() { @@ -63,7 +64,7 @@ public List supportedTargets() { 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, TargetProperty.THREADING); + var threading = TargetProperty.getKeyValuePair(ast, new ThreadingProperty()); if (threading != null) { if (!ASTUtils.toBoolean(threading.getValue())) { reporter diff --git a/core/src/main/java/org/lflang/target/property/VerifyProperty.java b/core/src/main/java/org/lflang/target/property/VerifyProperty.java index 5294c5cc80..793ee4c280 100644 --- a/core/src/main/java/org/lflang/target/property/VerifyProperty.java +++ b/core/src/main/java/org/lflang/target/property/VerifyProperty.java @@ -4,6 +4,7 @@ import org.lflang.Target; import org.lflang.target.property.AbstractBooleanProperty; +/** Directive to check the generated verification model. */ public class VerifyProperty extends AbstractBooleanProperty { @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 00812da4c1..f0b8b9fcda 100644 --- a/core/src/main/java/org/lflang/target/property/WorkersProperty.java +++ b/core/src/main/java/org/lflang/target/property/WorkersProperty.java @@ -8,6 +8,7 @@ import org.lflang.lf.Element; import org.lflang.target.property.type.PrimitiveType; +/** Directive to specify the number of worker threads used by the runtime. */ public class WorkersProperty extends AbstractTargetProperty { public WorkersProperty() { 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 073e7e1705..2fd89a499e 100644 --- a/core/src/test/java/org/lflang/tests/compiler/LinguaFrancaValidationTest.java +++ b/core/src/test/java/org/lflang/tests/compiler/LinguaFrancaValidationTest.java @@ -44,12 +44,14 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestFactory; import org.junit.jupiter.api.extension.ExtendWith; +import org.lflang.AbstractTargetProperty; import org.lflang.Target; import org.lflang.TimeValue; import org.lflang.lf.LfPackage; import org.lflang.lf.Model; import org.lflang.lf.Visibility; -import org.lflang.target.TargetProperty; +import org.lflang.target.TargetConfig; +import org.lflang.target.property.CargoDependenciesProperty; import org.lflang.target.property.PlatformProperty; import org.lflang.target.property.PlatformProperty.Platform; import org.lflang.target.property.type.ArrayType; @@ -1477,9 +1479,8 @@ private List synthesizeExamples(TargetPropertyType type, boolean correct * Create an LF program with the given key and value as a target property, parse it, and return * the resulting model. */ - private Model createModel(TargetProperty key, String value) throws Exception { - var target = - TargetProperty.getPropertyInstance(key).supportedTargets().stream().findFirst().get(); + private Model createModel(AbstractTargetProperty property, String value) throws Exception { + var target = property.supportedTargets().stream().findFirst().get(); return parseWithoutError( """ target %s {%s: %s}; @@ -1488,7 +1489,7 @@ private Model createModel(TargetProperty key, String value) throws Exception { y = new Y() } """ - .formatted(target, key, value)); + .formatted(target, property.name(), value)); } /** Perform checks on target properties. */ @@ -1496,12 +1497,12 @@ private Model createModel(TargetProperty key, String value) throws Exception { public Collection checkTargetProperties() throws Exception { List result = new ArrayList<>(); - for (TargetProperty property : TargetProperty.getOptions()) { - if (property == TargetProperty.CARGO_DEPENDENCIES) { + for (AbstractTargetProperty property : TargetConfig.getUserTargetProperties()) { + if (property instanceof CargoDependenciesProperty) { // we test that separately as it has better error messages continue; } - var type = TargetProperty.getPropertyInstance(property).type; + var type = property.type; List knownCorrect = synthesizeExamples(type, true); for (String it : knownCorrect) { @@ -1579,7 +1580,7 @@ public Collection checkTargetProperties() throws Exception { @Test public void checkCargoDependencyProperty() throws Exception { - TargetProperty prop = TargetProperty.CARGO_DEPENDENCIES; + CargoDependenciesProperty prop = new CargoDependenciesProperty(); List knownCorrect = List.of( "{}", @@ -1614,16 +1615,16 @@ public void checkCargoDependencyProperty() throws Exception { @Test public void checkPlatformProperty() throws Exception { - validator.assertNoErrors(createModel(TargetProperty.PLATFORM, Platform.ARDUINO.toString())); + validator.assertNoErrors(createModel(new PlatformProperty(), Platform.ARDUINO.toString())); validator.assertNoErrors( - createModel(TargetProperty.PLATFORM, String.format("{name: %s}", Platform.ZEPHYR))); + createModel(new PlatformProperty(), String.format("{name: %s}", Platform.ZEPHYR))); validator.assertError( - createModel(TargetProperty.PLATFORM, "foobar"), + createModel(new PlatformProperty(), "foobar"), LfPackage.eINSTANCE.getKeyValuePair(), null, PlatformProperty.UNKNOW_PLATFORM); validator.assertError( - createModel(TargetProperty.PLATFORM, "{ name: foobar }"), + createModel(new PlatformProperty(), "{ name: foobar }"), LfPackage.eINSTANCE.getKeyValuePair(), null, PlatformProperty.UNKNOW_PLATFORM); From 45b31b833ed4cf0b0f7c1f42a243078dca10fd83 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Tue, 3 Oct 2023 23:57:47 -0700 Subject: [PATCH 068/145] Bugfixes and improvements in the handling of types --- cli/lfc/src/main/java/org/lflang/cli/Lfc.java | 10 ++- .../lflang/tests/runtime/CSchedulerTest.java | 12 ++- .../org/lflang/AbstractTargetProperty.java | 6 +- .../federated/extensions/CExtension.java | 2 +- .../federated/extensions/CExtensionUtils.java | 2 +- .../extensions/FedTargetExtension.java | 2 +- .../federated/extensions/PythonExtension.java | 2 +- .../federated/extensions/TSExtension.java | 2 +- .../federated/generator/FedASTUtils.java | 2 +- .../federated/generator/FedGenerator.java | 2 +- .../launcher/FedLauncherGenerator.java | 2 +- .../lflang/generator/c/CCmakeGenerator.java | 2 +- .../org/lflang/generator/c/CCompiler.java | 6 +- .../org/lflang/generator/c/CGenerator.java | 10 +-- .../generator/c/CMainFunctionGenerator.java | 2 +- .../generator/c/CPreambleGenerator.java | 5 +- .../generator/c/CTriggerObjectsGenerator.java | 2 +- .../python/PythonPreambleGenerator.java | 3 +- .../generator/rust/CargoDependencySpec.java | 2 +- .../generator/rust/RustTargetConfig.java | 5 +- .../java/org/lflang/target/TargetConfig.java | 5 +- .../property/AbstractBooleanProperty.java | 3 +- .../property/AbstractFileListProperty.java | 3 +- .../target/property/AbstractStringConfig.java | 2 +- .../property/AbstractStringListProperty.java | 3 +- .../property/BuildCommandsProperty.java | 2 +- .../target/property/BuildTypeProperty.java | 40 ++------- .../property/CargoDependenciesProperty.java | 7 +- .../property/ClockSyncModeProperty.java | 34 ++----- .../property/ClockSyncOptionsProperty.java | 3 +- .../target/property/CmakeIncludeProperty.java | 2 +- .../property/CompileDefinitionsProperty.java | 3 +- .../property/CoordinationOptionsProperty.java | 3 +- .../target/property/CoordinationProperty.java | 27 ++---- .../target/property/DockerProperty.java | 2 +- .../target/property/FedSetupProperty.java | 2 +- .../target/property/LoggingProperty.java | 29 ++---- .../target/property/PlatformProperty.java | 88 +++---------------- .../property/Ros2DependenciesProperty.java | 2 +- .../target/property/RustIncludeProperty.java | 2 +- .../target/property/SchedulerProperty.java | 72 +++------------ .../target/property/TimeOutProperty.java | 2 +- .../target/property/TracingProperty.java | 2 +- .../target/property/WorkersProperty.java | 2 +- .../target/property/type/DictionaryType.java | 14 ++- .../target/property/type/UnionType.java | 79 ++++------------- .../org/lflang/generator/cpp/CppExtensions.kt | 14 +-- .../generator/cpp/CppStandaloneGenerator.kt | 3 +- .../generator/rust/RustCargoTomlEmitter.kt | 10 +-- .../lflang/generator/rust/RustGenerator.kt | 6 +- .../org/lflang/generator/rust/RustModel.kt | 2 +- .../compiler/LinguaFrancaValidationTest.java | 29 +++--- .../java/org/lflang/tests/Configurators.java | 4 +- 53 files changed, 175 insertions(+), 407 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 6409b7c0ba..48cc85b7d0 100644 --- a/cli/lfc/src/main/java/org/lflang/cli/Lfc.java +++ b/cli/lfc/src/main/java/org/lflang/cli/Lfc.java @@ -14,7 +14,9 @@ import org.lflang.generator.LFGeneratorContext; import org.lflang.generator.LFGeneratorContext.BuildParm; import org.lflang.generator.MainContext; -import org.lflang.target.property.type.UnionType; +import org.lflang.target.property.type.BuildTypeType; +import org.lflang.target.property.type.LoggingType; +import org.lflang.target.property.type.SchedulerType; import picocli.CommandLine.Command; import picocli.CommandLine.Option; @@ -222,7 +224,7 @@ public Properties getGeneratorArgs() { if (buildType != null) { // Validate build type. - if (UnionType.BUILD_TYPE_UNION.forName(buildType) == null) { + if (new BuildTypeType().forName(buildType) == null) { reporter.printFatalErrorAndExit(buildType + ": Invalid build type."); } props.setProperty(BuildParm.BUILD_TYPE.getKey(), buildType); @@ -242,7 +244,7 @@ public Properties getGeneratorArgs() { if (logging != null) { // Validate log level. - if (UnionType.LOGGING_UNION.forName(logging) == null) { + if (new LoggingType().forName(logging) == null) { reporter.printFatalErrorAndExit(logging + ": Invalid log level."); } props.setProperty(BuildParm.LOGGING.getKey(), logging); @@ -282,7 +284,7 @@ public Properties getGeneratorArgs() { if (scheduler != null) { // Validate scheduler. - if (UnionType.SCHEDULER_UNION.forName(scheduler) == null) { + if (new SchedulerType().forName(scheduler) == null) { reporter.printFatalErrorAndExit(scheduler + ": Invalid scheduler."); } props.setProperty(BuildParm.SCHEDULER.getKey(), scheduler); diff --git a/core/src/integrationTest/java/org/lflang/tests/runtime/CSchedulerTest.java b/core/src/integrationTest/java/org/lflang/tests/runtime/CSchedulerTest.java index 09a11faa6f..e8c13d73b0 100644 --- a/core/src/integrationTest/java/org/lflang/tests/runtime/CSchedulerTest.java +++ b/core/src/integrationTest/java/org/lflang/tests/runtime/CSchedulerTest.java @@ -3,7 +3,7 @@ import java.util.EnumSet; import org.junit.jupiter.api.Test; import org.lflang.Target; -import org.lflang.target.property.SchedulerProperty.SchedulerOption; +import org.lflang.target.property.type.SchedulerType.Scheduler; import org.lflang.tests.Configurators; import org.lflang.tests.TestBase; import org.lflang.tests.TestRegistry.TestCategory; @@ -35,23 +35,21 @@ public void runWithNonDefaultSchedulers() { if (name != null) { var option = - EnumSet.allOf(SchedulerOption.class).stream() - .filter(it -> it.name().equals(name)) - .findFirst(); + EnumSet.allOf(Scheduler.class).stream().filter(it -> it.name().equals(name)).findFirst(); if (option.isPresent()) { this.runTest(option.get(), categories); } else { throw new RuntimeException("Cannot find runtime scheduler called " + name); } } else { - for (SchedulerOption scheduler : EnumSet.allOf(SchedulerOption.class)) { - if (scheduler == SchedulerOption.getDefault()) continue; + for (Scheduler scheduler : EnumSet.allOf(Scheduler.class)) { + if (scheduler == Scheduler.getDefault()) continue; this.runTest(scheduler, categories); } } } - private void runTest(SchedulerOption scheduler, EnumSet categories) { + private void runTest(Scheduler scheduler, EnumSet categories) { this.runTestsForTargets( Message.DESC_SCHED_SWAPPING + scheduler.toString() + ".", categories::contains, diff --git a/core/src/main/java/org/lflang/AbstractTargetProperty.java b/core/src/main/java/org/lflang/AbstractTargetProperty.java index 53d0ccd4bd..cdef9ddce6 100644 --- a/core/src/main/java/org/lflang/AbstractTargetProperty.java +++ b/core/src/main/java/org/lflang/AbstractTargetProperty.java @@ -17,10 +17,10 @@ * * @param The data type of the value assigned to the target property. */ -public abstract class AbstractTargetProperty { +public abstract class AbstractTargetProperty { /** The type of values that can be assigned to this property. */ - public final TargetPropertyType type; + public final S type; /** Whether (after initialization) this property has been set. */ protected boolean isSet; @@ -35,7 +35,7 @@ public abstract class AbstractTargetProperty { * * @param type The type of the value that can be assigned to the property. */ - public AbstractTargetProperty(TargetPropertyType type) { + public AbstractTargetProperty(S type) { this.type = type; } 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 fcec922584..eafc0ae68b 100644 --- a/core/src/main/java/org/lflang/federated/extensions/CExtension.java +++ b/core/src/main/java/org/lflang/federated/extensions/CExtension.java @@ -56,7 +56,7 @@ import org.lflang.lf.Port; import org.lflang.lf.Reactor; import org.lflang.lf.VarRef; -import org.lflang.target.property.CoordinationProperty.CoordinationMode; +import org.lflang.target.property.type.CoordinationModeType.CoordinationMode; /** * An extension class to the CGenerator that enables certain federated functionalities. diff --git a/core/src/main/java/org/lflang/federated/extensions/CExtensionUtils.java b/core/src/main/java/org/lflang/federated/extensions/CExtensionUtils.java index 4cc93c2258..2903977c1e 100644 --- a/core/src/main/java/org/lflang/federated/extensions/CExtensionUtils.java +++ b/core/src/main/java/org/lflang/federated/extensions/CExtensionUtils.java @@ -22,8 +22,8 @@ import org.lflang.lf.Expression; import org.lflang.lf.Input; import org.lflang.lf.ParameterReference; -import org.lflang.target.property.ClockSyncModeProperty.ClockSyncMode; import org.lflang.target.property.ClockSyncOptionsProperty.ClockSyncOptions; +import org.lflang.target.property.type.ClockSyncModeType.ClockSyncMode; public class CExtensionUtils { diff --git a/core/src/main/java/org/lflang/federated/extensions/FedTargetExtension.java b/core/src/main/java/org/lflang/federated/extensions/FedTargetExtension.java index a580ec693a..7afafa105c 100644 --- a/core/src/main/java/org/lflang/federated/extensions/FedTargetExtension.java +++ b/core/src/main/java/org/lflang/federated/extensions/FedTargetExtension.java @@ -13,7 +13,7 @@ import org.lflang.lf.Reaction; import org.lflang.lf.Reactor; import org.lflang.lf.VarRef; -import org.lflang.target.property.CoordinationProperty.CoordinationMode; +import org.lflang.target.property.type.CoordinationModeType.CoordinationMode; public interface FedTargetExtension { diff --git a/core/src/main/java/org/lflang/federated/extensions/PythonExtension.java b/core/src/main/java/org/lflang/federated/extensions/PythonExtension.java index c0fae10f32..25c7198fe9 100644 --- a/core/src/main/java/org/lflang/federated/extensions/PythonExtension.java +++ b/core/src/main/java/org/lflang/federated/extensions/PythonExtension.java @@ -42,7 +42,7 @@ import org.lflang.lf.Action; import org.lflang.lf.Reaction; import org.lflang.lf.VarRef; -import org.lflang.target.property.CoordinationProperty.CoordinationMode; +import org.lflang.target.property.type.CoordinationModeType.CoordinationMode; /** * An extension class to the PythonGenerator that enables certain federated functionalities. diff --git a/core/src/main/java/org/lflang/federated/extensions/TSExtension.java b/core/src/main/java/org/lflang/federated/extensions/TSExtension.java index 7484adeb16..e1b79de941 100644 --- a/core/src/main/java/org/lflang/federated/extensions/TSExtension.java +++ b/core/src/main/java/org/lflang/federated/extensions/TSExtension.java @@ -25,7 +25,7 @@ import org.lflang.lf.Reactor; import org.lflang.lf.VarRef; import org.lflang.lf.Variable; -import org.lflang.target.property.CoordinationProperty.CoordinationMode; +import org.lflang.target.property.type.CoordinationModeType.CoordinationMode; public class TSExtension implements FedTargetExtension { @Override diff --git a/core/src/main/java/org/lflang/federated/generator/FedASTUtils.java b/core/src/main/java/org/lflang/federated/generator/FedASTUtils.java index 28290a1a6d..9d4dad046d 100644 --- a/core/src/main/java/org/lflang/federated/generator/FedASTUtils.java +++ b/core/src/main/java/org/lflang/federated/generator/FedASTUtils.java @@ -70,7 +70,7 @@ import org.lflang.lf.Type; import org.lflang.lf.VarRef; import org.lflang.lf.Variable; -import org.lflang.target.property.CoordinationProperty.CoordinationMode; +import org.lflang.target.property.type.CoordinationModeType.CoordinationMode; /** * A helper class for AST transformations needed for federated execution. 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 9bad080b7a..168bb0a8fd 100644 --- a/core/src/main/java/org/lflang/federated/generator/FedGenerator.java +++ b/core/src/main/java/org/lflang/federated/generator/FedGenerator.java @@ -58,7 +58,7 @@ import org.lflang.lf.TargetDecl; import org.lflang.lf.VarRef; import org.lflang.target.TargetConfig; -import org.lflang.target.property.CoordinationProperty.CoordinationMode; +import org.lflang.target.property.type.CoordinationModeType.CoordinationMode; import org.lflang.util.Averager; public class FedGenerator { diff --git a/core/src/main/java/org/lflang/federated/launcher/FedLauncherGenerator.java b/core/src/main/java/org/lflang/federated/launcher/FedLauncherGenerator.java index 368d01311f..99e942a45c 100644 --- a/core/src/main/java/org/lflang/federated/launcher/FedLauncherGenerator.java +++ b/core/src/main/java/org/lflang/federated/launcher/FedLauncherGenerator.java @@ -37,7 +37,7 @@ import org.lflang.federated.generator.FedFileConfig; import org.lflang.federated.generator.FederateInstance; import org.lflang.target.TargetConfig; -import org.lflang.target.property.ClockSyncModeProperty.ClockSyncMode; +import org.lflang.target.property.type.ClockSyncModeType.ClockSyncMode; /** * Utility class that can be used to create a launcher for federated LF programs. 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 df6e6abb57..e760e7ff7a 100644 --- a/core/src/main/java/org/lflang/generator/c/CCmakeGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CCmakeGenerator.java @@ -35,7 +35,7 @@ import org.lflang.MessageReporter; import org.lflang.generator.CodeBuilder; import org.lflang.target.TargetConfig; -import org.lflang.target.property.PlatformProperty.Platform; +import org.lflang.target.property.type.PlatformType.Platform; import org.lflang.util.FileUtil; /** diff --git a/core/src/main/java/org/lflang/generator/c/CCompiler.java b/core/src/main/java/org/lflang/generator/c/CCompiler.java index 55d5cb2b3b..6466f3f26e 100644 --- a/core/src/main/java/org/lflang/generator/c/CCompiler.java +++ b/core/src/main/java/org/lflang/generator/c/CCompiler.java @@ -40,8 +40,8 @@ import org.lflang.generator.GeneratorUtils; import org.lflang.generator.LFGeneratorContext; import org.lflang.target.TargetConfig; -import org.lflang.target.property.BuildTypeProperty; -import org.lflang.target.property.PlatformProperty.Platform; +import org.lflang.target.property.type.BuildTypeType.BuildType; +import org.lflang.target.property.type.PlatformType.Platform; import org.lflang.util.FileUtil; import org.lflang.util.LFCommand; @@ -261,7 +261,7 @@ private static List cmakeOptions(TargetConfig targetConfig, FileConfig f } /** Return the cmake config name corresponding to a given build type. */ - private String buildTypeToCmakeConfig(BuildTypeProperty.BuildType type) { + private String buildTypeToCmakeConfig(BuildType type) { if (type == null) { return "Release"; } 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 90c9b41080..7a10616c7b 100644 --- a/core/src/main/java/org/lflang/generator/c/CGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CGenerator.java @@ -86,9 +86,9 @@ import org.lflang.lf.StateVar; import org.lflang.lf.Variable; import org.lflang.target.TargetConfig; -import org.lflang.target.property.PlatformProperty.Platform; import org.lflang.target.property.PlatformProperty.PlatformOption; -import org.lflang.target.property.SchedulerProperty.SchedulerOption; +import org.lflang.target.property.type.PlatformType.Platform; +import org.lflang.target.property.type.SchedulerType.Scheduler; import org.lflang.util.ArduinoUtil; import org.lflang.util.FileUtil; @@ -698,7 +698,7 @@ private void pickScheduler() { // Check if a deadline is assigned to any reaction if (hasDeadlines(reactors)) { if (!targetConfig.schedulerType.isSet()) { - targetConfig.schedulerType.override(SchedulerOption.GEDF_NP); + targetConfig.schedulerType.override(Scheduler.GEDF_NP); } } } @@ -2042,9 +2042,7 @@ public String generateDirectives() { CodeBuilder code = new CodeBuilder(); code.prComment("Code generated by the Lingua Franca compiler from:"); code.prComment("file:/" + FileUtil.toUnixString(fileConfig.srcFile)); - code.pr( - CPreambleGenerator.generateDefineDirectives( - targetConfig, fileConfig.getSrcGenPath(), hasModalReactors)); + code.pr(CPreambleGenerator.generateDefineDirectives(targetConfig, fileConfig.getSrcGenPath())); code.pr(CPreambleGenerator.generateIncludeStatements(targetConfig, CCppMode)); return code.toString(); } diff --git a/core/src/main/java/org/lflang/generator/c/CMainFunctionGenerator.java b/core/src/main/java/org/lflang/generator/c/CMainFunctionGenerator.java index e8c58bd92f..1ef7280834 100644 --- a/core/src/main/java/org/lflang/generator/c/CMainFunctionGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CMainFunctionGenerator.java @@ -4,7 +4,7 @@ import java.util.List; import org.lflang.generator.CodeBuilder; import org.lflang.target.TargetConfig; -import org.lflang.target.property.PlatformProperty.Platform; +import org.lflang.target.property.type.PlatformType.Platform; import org.lflang.util.StringUtil; public class CMainFunctionGenerator { 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 c0cda07b3f..df26dbb943 100644 --- a/core/src/main/java/org/lflang/generator/c/CPreambleGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CPreambleGenerator.java @@ -5,7 +5,7 @@ import java.nio.file.Path; import org.lflang.generator.CodeBuilder; import org.lflang.target.TargetConfig; -import org.lflang.target.property.PlatformProperty.Platform; +import org.lflang.target.property.type.PlatformType.Platform; import org.lflang.util.StringUtil; /** @@ -59,8 +59,7 @@ public static String generateIncludeStatements(TargetConfig targetConfig, boolea return code.toString(); } - public static String generateDefineDirectives( - TargetConfig targetConfig, Path srcGenPath, boolean hasModalReactors) { + public static String generateDefineDirectives(TargetConfig targetConfig, Path srcGenPath) { int logLevel = targetConfig.logLevel.get().ordinal(); var tracing = targetConfig.tracing.get(); CodeBuilder code = new CodeBuilder(); 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 8cd050b8a0..29cf3a682d 100644 --- a/core/src/main/java/org/lflang/generator/c/CTriggerObjectsGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CTriggerObjectsGenerator.java @@ -23,7 +23,7 @@ import org.lflang.generator.RuntimeRange; import org.lflang.generator.SendRange; import org.lflang.target.TargetConfig; -import org.lflang.target.property.LoggingProperty.LogLevel; +import org.lflang.target.property.type.LoggingType.LogLevel; /** * Generate code for the "_lf_initialize_trigger_objects" function diff --git a/core/src/main/java/org/lflang/generator/python/PythonPreambleGenerator.java b/core/src/main/java/org/lflang/generator/python/PythonPreambleGenerator.java index 305b2a78b7..8194f78c63 100644 --- a/core/src/main/java/org/lflang/generator/python/PythonPreambleGenerator.java +++ b/core/src/main/java/org/lflang/generator/python/PythonPreambleGenerator.java @@ -37,8 +37,7 @@ public static String generateCDefineDirectives( TargetConfig targetConfig, Path srcGenPath, boolean hasModalReactors) { // TODO: Delete all of this. It is not used. CodeBuilder code = new CodeBuilder(); - code.pr( - CPreambleGenerator.generateDefineDirectives(targetConfig, srcGenPath, hasModalReactors)); + code.pr(CPreambleGenerator.generateDefineDirectives(targetConfig, srcGenPath)); return code.toString(); } diff --git a/core/src/main/java/org/lflang/generator/rust/CargoDependencySpec.java b/core/src/main/java/org/lflang/generator/rust/CargoDependencySpec.java index f3620c0575..d30ae87255 100644 --- a/core/src/main/java/org/lflang/generator/rust/CargoDependencySpec.java +++ b/core/src/main/java/org/lflang/generator/rust/CargoDependencySpec.java @@ -269,7 +269,7 @@ public static final class CargoDependenciesPropertyType implements TargetPropert public static final TargetPropertyType INSTANCE = new CargoDependenciesPropertyType(); - private CargoDependenciesPropertyType() {} + public CargoDependenciesPropertyType() {} @Override public boolean validate(Element e) { diff --git a/core/src/main/java/org/lflang/generator/rust/RustTargetConfig.java b/core/src/main/java/org/lflang/generator/rust/RustTargetConfig.java index 9ad8b08716..3bced7afa2 100644 --- a/core/src/main/java/org/lflang/generator/rust/RustTargetConfig.java +++ b/core/src/main/java/org/lflang/generator/rust/RustTargetConfig.java @@ -26,10 +26,11 @@ import org.lflang.target.TargetConfig; import org.lflang.target.property.BuildTypeProperty; -import org.lflang.target.property.BuildTypeProperty.BuildType; import org.lflang.target.property.CargoDependenciesProperty; import org.lflang.target.property.CargoFeaturesProperty; import org.lflang.target.property.RustIncludeProperty; +import org.lflang.target.property.type.BuildTypeType; +import org.lflang.target.property.type.BuildTypeType.BuildType; /** * Rust-specific part of a {@link TargetConfig}. @@ -48,7 +49,7 @@ public final class RustTargetConfig { public final RustIncludeProperty rustTopLevelModules = new RustIncludeProperty(); /** Cargo profile, default is debug (corresponds to cargo dev profile). */ - private BuildType profile = BuildTypeProperty.BuildType.DEBUG; + private BuildType profile = BuildTypeType.BuildType.DEBUG; /** The build type to use. Corresponds to a Cargo profile. */ public BuildType getBuildType(BuildTypeProperty cmakeBuildType) { diff --git a/core/src/main/java/org/lflang/target/TargetConfig.java b/core/src/main/java/org/lflang/target/TargetConfig.java index 23906a80ab..8067161b0c 100644 --- a/core/src/main/java/org/lflang/target/TargetConfig.java +++ b/core/src/main/java/org/lflang/target/TargetConfig.java @@ -275,13 +275,14 @@ public TargetConfig(Properties cliArgs, TargetDecl target, MessageReporter messa public List getAllTargetProperties() { var properties = AbstractTargetProperty.getAllTargetProperties(this); properties.addAll(AbstractTargetProperty.getAllTargetProperties(this.rust)); - return properties; + return properties.stream() + .sorted((p1, p2) -> p1.name().compareTo(p2.name())) + .collect(Collectors.toList()); } public static List getUserTargetProperties() { var config = new TargetConfig(); var properties = AbstractTargetProperty.getAllTargetProperties(config); - properties.addAll(AbstractTargetProperty.getAllTargetProperties(config)); return properties.stream() .filter(it -> !it.name().startsWith("_")) .collect(Collectors.toList()); diff --git a/core/src/main/java/org/lflang/target/property/AbstractBooleanProperty.java b/core/src/main/java/org/lflang/target/property/AbstractBooleanProperty.java index 8d65a0674b..91530c9db7 100644 --- a/core/src/main/java/org/lflang/target/property/AbstractBooleanProperty.java +++ b/core/src/main/java/org/lflang/target/property/AbstractBooleanProperty.java @@ -6,7 +6,8 @@ import org.lflang.lf.Element; import org.lflang.target.property.type.PrimitiveType; -public abstract class AbstractBooleanProperty extends AbstractTargetProperty { +public abstract class AbstractBooleanProperty + extends AbstractTargetProperty { public AbstractBooleanProperty() { super(PrimitiveType.BOOLEAN); diff --git a/core/src/main/java/org/lflang/target/property/AbstractFileListProperty.java b/core/src/main/java/org/lflang/target/property/AbstractFileListProperty.java index cd462ab2ec..3d866c62fe 100644 --- a/core/src/main/java/org/lflang/target/property/AbstractFileListProperty.java +++ b/core/src/main/java/org/lflang/target/property/AbstractFileListProperty.java @@ -8,7 +8,8 @@ import org.lflang.lf.Element; import org.lflang.target.property.type.UnionType; -public abstract class AbstractFileListProperty extends AbstractTargetProperty> { +public abstract class AbstractFileListProperty + extends AbstractTargetProperty, UnionType> { public AbstractFileListProperty() { super(UnionType.FILE_OR_FILE_ARRAY); diff --git a/core/src/main/java/org/lflang/target/property/AbstractStringConfig.java b/core/src/main/java/org/lflang/target/property/AbstractStringConfig.java index 619a7f135d..d4dcb9a3d3 100644 --- a/core/src/main/java/org/lflang/target/property/AbstractStringConfig.java +++ b/core/src/main/java/org/lflang/target/property/AbstractStringConfig.java @@ -6,7 +6,7 @@ import org.lflang.lf.Element; import org.lflang.target.property.type.PrimitiveType; -public abstract class AbstractStringConfig extends AbstractTargetProperty { +public abstract class AbstractStringConfig extends AbstractTargetProperty { public AbstractStringConfig() { super(PrimitiveType.STRING); diff --git a/core/src/main/java/org/lflang/target/property/AbstractStringListProperty.java b/core/src/main/java/org/lflang/target/property/AbstractStringListProperty.java index 43afc06e91..71ffbe500b 100644 --- a/core/src/main/java/org/lflang/target/property/AbstractStringListProperty.java +++ b/core/src/main/java/org/lflang/target/property/AbstractStringListProperty.java @@ -9,7 +9,8 @@ import org.lflang.target.property.type.UnionType; /** Note: {@code set} implements an "append" semantics. */ -public abstract class AbstractStringListProperty extends AbstractTargetProperty> { +public abstract class AbstractStringListProperty + extends AbstractTargetProperty, UnionType> { public AbstractStringListProperty() { super(UnionType.STRING_OR_STRING_ARRAY); diff --git a/core/src/main/java/org/lflang/target/property/BuildCommandsProperty.java b/core/src/main/java/org/lflang/target/property/BuildCommandsProperty.java index 78c320d09f..8010b2869a 100644 --- a/core/src/main/java/org/lflang/target/property/BuildCommandsProperty.java +++ b/core/src/main/java/org/lflang/target/property/BuildCommandsProperty.java @@ -11,7 +11,7 @@ import org.lflang.target.property.type.UnionType; /** Directive to let the generator use the custom build command. */ -public class BuildCommandsProperty extends AbstractTargetProperty> { +public class BuildCommandsProperty extends AbstractTargetProperty, UnionType> { public BuildCommandsProperty() { super(UnionType.STRING_OR_STRING_ARRAY); diff --git a/core/src/main/java/org/lflang/target/property/BuildTypeProperty.java b/core/src/main/java/org/lflang/target/property/BuildTypeProperty.java index 97ffcd560c..c613ac5c42 100644 --- a/core/src/main/java/org/lflang/target/property/BuildTypeProperty.java +++ b/core/src/main/java/org/lflang/target/property/BuildTypeProperty.java @@ -7,17 +7,17 @@ import org.lflang.Target; import org.lflang.ast.ASTUtils; import org.lflang.lf.Element; -import org.lflang.target.property.BuildTypeProperty.BuildType; -import org.lflang.target.property.type.UnionType; +import org.lflang.target.property.type.BuildTypeType; +import org.lflang.target.property.type.BuildTypeType.BuildType; /** * Directive to specify the target build type such as 'Release' or 'Debug'. This is also used in the * Rust target to select a Cargo profile. */ -public class BuildTypeProperty extends AbstractTargetProperty { +public class BuildTypeProperty extends AbstractTargetProperty { public BuildTypeProperty() { - super(UnionType.BUILD_TYPE_UNION); + super(new BuildTypeType()); } @Override @@ -27,7 +27,7 @@ public Element toAstElement() { @Override public BuildType initialValue() { - return BuildType.RELEASE; + return BuildTypeType.BuildType.RELEASE; } @Override @@ -37,7 +37,7 @@ public BuildType fromAst(Element node, MessageReporter reporter) { @Override protected BuildType fromString(String string, MessageReporter reporter) { - return (BuildType) UnionType.BUILD_TYPE_UNION.forName(string); + return ((BuildTypeType) this.type).forName(string); } @Override @@ -49,32 +49,4 @@ public String name() { public List supportedTargets() { return Arrays.asList(Target.C, Target.CCPP, Target.CPP, Target.Rust); } - - /** - * Enumeration of Cmake build types. These are also mapped to Cargo profiles for the Rust target - * (see {@link org.lflang.generator.rust.RustTargetConfig}) - * - * @author Christian Menard - */ - public enum BuildType { - RELEASE("Release"), - DEBUG("Debug"), - TEST("Test"), - REL_WITH_DEB_INFO("RelWithDebInfo"), - MIN_SIZE_REL("MinSizeRel"); - - /** Alias used in toString method. */ - private final String alias; - - /** Private constructor for Cmake build types. */ - BuildType(String alias) { - this.alias = alias; - } - - /** Return the alias. */ - @Override - public String toString() { - return this.alias; - } - } } 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 bfc948cbd8..859b697a13 100644 --- a/core/src/main/java/org/lflang/target/property/CargoDependenciesProperty.java +++ b/core/src/main/java/org/lflang/target/property/CargoDependenciesProperty.java @@ -40,11 +40,12 @@ * } */ public class CargoDependenciesProperty - extends AbstractTargetProperty> { + extends AbstractTargetProperty< + Map, CargoDependenciesPropertyType> { public CargoDependenciesProperty() { - super(CargoDependenciesPropertyType.INSTANCE); - } + super(new CargoDependenciesPropertyType()); + } // FIXME @Override public Map initialValue() { 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 224cbe1a2f..cfed672d81 100644 --- a/core/src/main/java/org/lflang/target/property/ClockSyncModeProperty.java +++ b/core/src/main/java/org/lflang/target/property/ClockSyncModeProperty.java @@ -11,14 +11,15 @@ import org.lflang.lf.LfPackage.Literals; import org.lflang.lf.Model; import org.lflang.lf.Reactor; -import org.lflang.target.property.ClockSyncModeProperty.ClockSyncMode; -import org.lflang.target.property.type.UnionType; +import org.lflang.target.property.type.ClockSyncModeType; +import org.lflang.target.property.type.ClockSyncModeType.ClockSyncMode; /** Directive to let the federate execution handle clock synchronization in software. */ -public class ClockSyncModeProperty extends AbstractTargetProperty { +public class ClockSyncModeProperty + extends AbstractTargetProperty { public ClockSyncModeProperty() { - super(UnionType.CLOCK_SYNC_UNION); + super(new ClockSyncModeType()); } @Override @@ -28,14 +29,13 @@ public ClockSyncMode initialValue() { @Override public ClockSyncMode fromAst(Element node, MessageReporter reporter) { - UnionType.CLOCK_SYNC_UNION.validate(node); var mode = fromString(ASTUtils.elementToSingleString(node), reporter); return Objects.requireNonNullElse(mode, ClockSyncMode.INIT); } @Override protected ClockSyncMode fromString(String string, MessageReporter reporter) { - return (ClockSyncMode) UnionType.CLOCK_SYNC_UNION.forName(string); + return this.type.forName(string); } @Override @@ -70,26 +70,4 @@ public Element toAstElement() { public String name() { return "clock-sync"; } - - /** - * Enumeration of clock synchronization modes. - * - *

    - *
  • OFF: The clock synchronization is universally off. - *
  • STARTUP: Clock synchronization occurs at startup only. - *
  • ON: Clock synchronization occurs at startup and at runtime. - *
- * - * @author Edward A. Lee - */ - public enum ClockSyncMode { - OFF, - INIT, - ON; - /** Return the name in lower case. */ - @Override - public String toString() { - return this.name().toLowerCase(); - } - } } 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 b0909c2689..6cb0d76d8a 100644 --- a/core/src/main/java/org/lflang/target/property/ClockSyncOptionsProperty.java +++ b/core/src/main/java/org/lflang/target/property/ClockSyncOptionsProperty.java @@ -19,7 +19,8 @@ import org.lflang.target.property.type.TargetPropertyType; /** Key-value pairs giving options for clock synchronization. */ -public class ClockSyncOptionsProperty extends AbstractTargetProperty { +public class ClockSyncOptionsProperty + extends AbstractTargetProperty { public ClockSyncOptionsProperty() { super(DictionaryType.CLOCK_SYNC_OPTION_DICT); diff --git a/core/src/main/java/org/lflang/target/property/CmakeIncludeProperty.java b/core/src/main/java/org/lflang/target/property/CmakeIncludeProperty.java index 7413bf8728..4c4a8fa108 100644 --- a/core/src/main/java/org/lflang/target/property/CmakeIncludeProperty.java +++ b/core/src/main/java/org/lflang/target/property/CmakeIncludeProperty.java @@ -16,7 +16,7 @@ *

This gives full control over the C/C++ build as any cmake parameters can be adjusted in the * included file. */ -public class CmakeIncludeProperty extends AbstractTargetProperty> { +public class CmakeIncludeProperty extends AbstractTargetProperty, UnionType> { public CmakeIncludeProperty() { super(UnionType.FILE_OR_FILE_ARRAY); diff --git a/core/src/main/java/org/lflang/target/property/CompileDefinitionsProperty.java b/core/src/main/java/org/lflang/target/property/CompileDefinitionsProperty.java index ff4aa30e11..88eb50fd0c 100644 --- a/core/src/main/java/org/lflang/target/property/CompileDefinitionsProperty.java +++ b/core/src/main/java/org/lflang/target/property/CompileDefinitionsProperty.java @@ -12,7 +12,8 @@ import org.lflang.target.property.type.StringDictionaryType; /** Directive to specify compile-time definitions. */ -public class CompileDefinitionsProperty extends AbstractTargetProperty> { +public class CompileDefinitionsProperty + extends AbstractTargetProperty, StringDictionaryType> { public CompileDefinitionsProperty() { super(StringDictionaryType.COMPILE_DEFINITION); 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 c2d4e94b90..a84506eedf 100644 --- a/core/src/main/java/org/lflang/target/property/CoordinationOptionsProperty.java +++ b/core/src/main/java/org/lflang/target/property/CoordinationOptionsProperty.java @@ -19,7 +19,8 @@ import org.lflang.target.property.type.TargetPropertyType; /** Key-value pairs giving options for clock synchronization. */ -public class CoordinationOptionsProperty extends AbstractTargetProperty { +public class CoordinationOptionsProperty + extends AbstractTargetProperty { public CoordinationOptionsProperty() { super(DictionaryType.COORDINATION_OPTION_DICT); diff --git a/core/src/main/java/org/lflang/target/property/CoordinationProperty.java b/core/src/main/java/org/lflang/target/property/CoordinationProperty.java index 4837a68317..c751b5e802 100644 --- a/core/src/main/java/org/lflang/target/property/CoordinationProperty.java +++ b/core/src/main/java/org/lflang/target/property/CoordinationProperty.java @@ -7,14 +7,15 @@ import org.lflang.Target; import org.lflang.ast.ASTUtils; import org.lflang.lf.Element; -import org.lflang.target.property.CoordinationProperty.CoordinationMode; -import org.lflang.target.property.type.UnionType; +import org.lflang.target.property.type.CoordinationModeType; +import org.lflang.target.property.type.CoordinationModeType.CoordinationMode; /** Directive to specify the coordination mode */ -public class CoordinationProperty extends AbstractTargetProperty { +public class CoordinationProperty + extends AbstractTargetProperty { public CoordinationProperty() { - super(UnionType.COORDINATION_UNION); + super(new CoordinationModeType()); } @Override @@ -29,7 +30,7 @@ public CoordinationMode fromAst(Element node, MessageReporter reporter) { @Override protected CoordinationMode fromString(String string, MessageReporter reporter) { - return (CoordinationMode) UnionType.COORDINATION_UNION.forName(string); + return ((CoordinationModeType) this.type).forName(string); } @Override @@ -46,20 +47,4 @@ public Element toAstElement() { public String name() { return "coordination"; } - - /** - * Enumeration of coordination types. - * - * @author Marten Lohstroh - */ - public enum CoordinationMode { - CENTRALIZED, - DECENTRALIZED; - - /** Return the name in lower case. */ - @Override - public String toString() { - return this.name().toLowerCase(); - } - } } 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 ea09ae836e..998c38d082 100644 --- a/core/src/main/java/org/lflang/target/property/DockerProperty.java +++ b/core/src/main/java/org/lflang/target/property/DockerProperty.java @@ -22,7 +22,7 @@ * Directive to generate a Dockerfile. This is either a boolean, true or false, or a dictionary of * options. */ -public class DockerProperty extends AbstractTargetProperty { +public class DockerProperty extends AbstractTargetProperty { public DockerProperty() { super(UnionType.DOCKER_UNION); diff --git a/core/src/main/java/org/lflang/target/property/FedSetupProperty.java b/core/src/main/java/org/lflang/target/property/FedSetupProperty.java index 1fde72bdc1..5334e1c9be 100644 --- a/core/src/main/java/org/lflang/target/property/FedSetupProperty.java +++ b/core/src/main/java/org/lflang/target/property/FedSetupProperty.java @@ -13,7 +13,7 @@ * Directs the C or Python target to include the associated C file used for setting up federated * execution before processing the first tag. */ -public class FedSetupProperty extends AbstractTargetProperty { +public class FedSetupProperty extends AbstractTargetProperty { public FedSetupProperty() { super(PrimitiveType.FILE); diff --git a/core/src/main/java/org/lflang/target/property/LoggingProperty.java b/core/src/main/java/org/lflang/target/property/LoggingProperty.java index f90179d67d..2cddd285ca 100644 --- a/core/src/main/java/org/lflang/target/property/LoggingProperty.java +++ b/core/src/main/java/org/lflang/target/property/LoggingProperty.java @@ -6,19 +6,19 @@ import org.lflang.Target; import org.lflang.ast.ASTUtils; import org.lflang.lf.Element; -import org.lflang.target.property.LoggingProperty.LogLevel; -import org.lflang.target.property.type.UnionType; +import org.lflang.target.property.type.LoggingType; +import org.lflang.target.property.type.LoggingType.LogLevel; /** Directive to specify the grain at which to report log messages during execution. */ -public class LoggingProperty extends AbstractTargetProperty { +public class LoggingProperty extends AbstractTargetProperty { public LoggingProperty() { - super(UnionType.LOGGING_UNION); + super(new LoggingType()); } @Override public LogLevel initialValue() { - return LogLevel.INFO; + return LogLevel.getDefault(); } @Override @@ -44,23 +44,4 @@ public Element toAstElement() { public String name() { return "logging"; } - - /** - * Log levels in descending order of severity. - * - * @author Marten Lohstroh - */ - public enum LogLevel { - ERROR, - WARN, - INFO, - LOG, - DEBUG; - - /** Return the name in lower case. */ - @Override - public String toString() { - return this.name().toLowerCase(); - } - } } 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 75aa611a4f..4eb7f780c2 100644 --- a/core/src/main/java/org/lflang/target/property/PlatformProperty.java +++ b/core/src/main/java/org/lflang/target/property/PlatformProperty.java @@ -1,8 +1,6 @@ package org.lflang.target.property; -import java.util.Arrays; import java.util.List; -import java.util.Objects; import org.lflang.AbstractTargetProperty; import org.lflang.MessageReporter; import org.lflang.Target; @@ -17,6 +15,8 @@ import org.lflang.target.property.PlatformProperty.PlatformOptions; import org.lflang.target.property.type.DictionaryType; import org.lflang.target.property.type.DictionaryType.DictionaryElement; +import org.lflang.target.property.type.PlatformType; +import org.lflang.target.property.type.PlatformType.Platform; import org.lflang.target.property.type.PrimitiveType; import org.lflang.target.property.type.TargetPropertyType; import org.lflang.target.property.type.UnionType; @@ -25,11 +25,11 @@ * Directive to specify the platform for cross code generation. This is either a string of the * platform or a dictionary of options that includes the string name. */ -public class PlatformProperty extends AbstractTargetProperty { +public class PlatformProperty extends AbstractTargetProperty { - public static final String UNKNOW_PLATFORM = + public static final String UNKNOWN_PLATFORM = "Unidentified Platform Type, LF supports the following platform types: " - + Arrays.asList(Platform.values()); + + new PlatformType().optionsList(); public PlatformProperty() { super(UnionType.PLATFORM_STRING_OR_DICTIONARY); @@ -44,18 +44,18 @@ public PlatformOptions initialValue() { public PlatformOptions fromAst(Element node, MessageReporter reporter) { var config = new PlatformOptions(); if (node.getLiteral() != null || node.getId() != null) { - config.platform = - (Platform) UnionType.PLATFORM_UNION.forName(ASTUtils.elementToSingleString(node)); + config.platform = new PlatformType().forName(ASTUtils.elementToSingleString(node)); } else { 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 -> { config.platform = - (Platform) - UnionType.PLATFORM_UNION.forName( - ASTUtils.elementToSingleString(entry.getValue())); + new PlatformType().forName(ASTUtils.elementToSingleString(entry.getValue())); } case BAUDRATE -> config.baudRate = ASTUtils.toInteger(entry.getValue()); case BOARD -> config.board = ASTUtils.elementToSingleString(entry.getValue()); @@ -81,31 +81,9 @@ public List supportedTargets() { @Override public void validate(KeyValuePair pair, Model ast, MessageReporter reporter) { - final var node = pair.getValue(); - Platform platform = null; - if (node.getLiteral() != null || node.getId() != null) { - platform = (Platform) UnionType.PLATFORM_UNION.forName(ASTUtils.elementToSingleString(node)); - if (platform == null) { - reporter.at(pair, Literals.KEY_VALUE_PAIR__VALUE).error(UNKNOW_PLATFORM); - } - } else { - for (KeyValuePair entry : node.getKeyvalue().getPairs()) { - PlatformOption option = - (PlatformOption) DictionaryType.PLATFORM_DICT.forName(entry.getName()); - if (Objects.requireNonNull(option) == PlatformOption.NAME) { - platform = - (Platform) - UnionType.PLATFORM_UNION.forName( - ASTUtils.elementToSingleString(entry.getValue())); - if (platform == null) { - reporter.at(entry, Literals.KEY_VALUE_PAIR__VALUE).error(UNKNOW_PLATFORM); - } - } - } - } - + var config = fromAst(pair.getValue(), reporter); var threading = TargetProperty.getKeyValuePair(ast, new ThreadingProperty()); - if (threading != null && platform == Platform.RP2040) { + if (threading != null && config.platform == Platform.RP2040) { reporter .at(pair, Literals.KEY_VALUE_PAIR__VALUE) .error("Platform " + Platform.RP2040 + " does not support threading"); @@ -184,48 +162,6 @@ public static class PlatformOptions { // FIXME: use a record for this public int userThreads = 0; } - /** Enumeration of supported platforms */ - public enum Platform { - AUTO, - ARDUINO, - NRF52("Nrf52", true), - RP2040("Rp2040", false), - LINUX("Linux", true), - MAC("Darwin", true), - ZEPHYR("Zephyr", true), - WINDOWS("Windows", true); - - final String cMakeName; - - private boolean multiThreaded = - true; // FIXME: this is never read. If we set it, we can simplify the validator method in - // the encapsulating class. - - Platform() { - this.cMakeName = this.toString(); - } - - Platform(String cMakeName, boolean isMultiThreaded) { - this.cMakeName = cMakeName; - this.multiThreaded = isMultiThreaded; - } - - /** Return the name in lower case. */ - @Override - public String toString() { - return this.name().toLowerCase(); - } - - /** Get the CMake name for the platform. */ - public String getcMakeName() { - return this.cMakeName; - } - - public boolean isMultiThreaded() { - return this.multiThreaded; - } - } - /** * Platform options. * 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 ce766942dc..5f55913bca 100644 --- a/core/src/main/java/org/lflang/target/property/Ros2DependenciesProperty.java +++ b/core/src/main/java/org/lflang/target/property/Ros2DependenciesProperty.java @@ -14,7 +14,7 @@ import org.lflang.target.property.type.ArrayType; /** Directive to specify additional ROS2 packages that this LF program depends on. */ -public class Ros2DependenciesProperty extends AbstractTargetProperty> { +public class Ros2DependenciesProperty extends AbstractTargetProperty, ArrayType> { public Ros2DependenciesProperty() { super(ArrayType.STRING_ARRAY); diff --git a/core/src/main/java/org/lflang/target/property/RustIncludeProperty.java b/core/src/main/java/org/lflang/target/property/RustIncludeProperty.java index 110b94d977..478cc7e5e7 100644 --- a/core/src/main/java/org/lflang/target/property/RustIncludeProperty.java +++ b/core/src/main/java/org/lflang/target/property/RustIncludeProperty.java @@ -22,7 +22,7 @@ * the generated {@code main.rs} will include it with a {@code mod foo;}. If one of the paths is a * directory, it must contain a {@code mod.rs} file, and all its contents are copied. */ -public class RustIncludeProperty extends AbstractTargetProperty> { +public class RustIncludeProperty extends AbstractTargetProperty, UnionType> { public RustIncludeProperty() { super(UnionType.FILE_OR_FILE_ARRAY); 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 ff280fc18e..813504f880 100644 --- a/core/src/main/java/org/lflang/target/property/SchedulerProperty.java +++ b/core/src/main/java/org/lflang/target/property/SchedulerProperty.java @@ -1,7 +1,5 @@ package org.lflang.target.property; -import com.google.common.collect.ImmutableList; -import java.nio.file.Path; import java.util.Arrays; import java.util.List; import org.lflang.AbstractTargetProperty; @@ -12,34 +10,34 @@ import org.lflang.lf.KeyValuePair; import org.lflang.lf.LfPackage.Literals; import org.lflang.lf.Model; -import org.lflang.target.property.SchedulerProperty.SchedulerOption; -import org.lflang.target.property.type.UnionType; +import org.lflang.target.property.type.SchedulerType; +import org.lflang.target.property.type.SchedulerType.Scheduler; /** Directive for specifying a specific runtime scheduler, if supported. */ -public class SchedulerProperty extends AbstractTargetProperty { +public class SchedulerProperty extends AbstractTargetProperty { public SchedulerProperty() { - super(UnionType.SCHEDULER_UNION); + super(new SchedulerType()); } @Override - public SchedulerOption initialValue() { - return SchedulerOption.getDefault(); + public Scheduler initialValue() { + return Scheduler.getDefault(); } @Override - public SchedulerOption fromAst(Element node, MessageReporter reporter) { + public Scheduler fromAst(Element node, MessageReporter reporter) { var scheduler = fromString(ASTUtils.elementToSingleString(node), reporter); if (scheduler != null) { return scheduler; } else { - return SchedulerOption.getDefault(); + return Scheduler.getDefault(); } } @Override - protected SchedulerOption fromString(String string, MessageReporter reporter) { - return (SchedulerOption) UnionType.SCHEDULER_UNION.forName(string); + protected Scheduler fromString(String string, MessageReporter reporter) { + return this.type.forName(string); } @Override @@ -62,7 +60,7 @@ public void validate(KeyValuePair pair, Model ast, MessageReporter reporter) { if (pair != null) { String schedulerName = ASTUtils.elementToSingleString(pair.getValue()); try { - if (!SchedulerOption.valueOf(schedulerName).prioritizesDeadline()) { + 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. @@ -89,52 +87,4 @@ public void validate(KeyValuePair pair, Model ast, MessageReporter reporter) { } } } - - /** - * Supported schedulers. - * - * @author Soroush Bateni - */ - public enum SchedulerOption { - NP(false), // Non-preemptive - ADAPTIVE( - false, - List.of( - Path.of("scheduler_adaptive.c"), - Path.of("worker_assignments.h"), - Path.of("worker_states.h"), - Path.of("data_collection.h"))), - GEDF_NP(true), // Global EDF non-preemptive - GEDF_NP_CI(true); // Global EDF non-preemptive with chain ID - - /** Indicate whether the scheduler prioritizes reactions by deadline. */ - private final boolean prioritizesDeadline; - - /** Relative paths to files required by this scheduler. */ - private final List relativePaths; - - SchedulerOption(boolean prioritizesDeadline) { - this(prioritizesDeadline, null); - } - - SchedulerOption(boolean prioritizesDeadline, List relativePaths) { - this.prioritizesDeadline = prioritizesDeadline; - this.relativePaths = relativePaths; - } - - /** Return true if the scheduler prioritizes reactions by deadline. */ - public boolean prioritizesDeadline() { - return this.prioritizesDeadline; - } - - public List getRelativePaths() { - return relativePaths != null - ? ImmutableList.copyOf(relativePaths) - : List.of(Path.of("scheduler_" + this + ".c")); - } - - public static SchedulerOption getDefault() { - return NP; - } - } } diff --git a/core/src/main/java/org/lflang/target/property/TimeOutProperty.java b/core/src/main/java/org/lflang/target/property/TimeOutProperty.java index a43ef6c059..bef95c7ff6 100644 --- a/core/src/main/java/org/lflang/target/property/TimeOutProperty.java +++ b/core/src/main/java/org/lflang/target/property/TimeOutProperty.java @@ -10,7 +10,7 @@ import org.lflang.target.property.type.PrimitiveType; /** Directive to specify the execution timeout. */ -public class TimeOutProperty extends AbstractTargetProperty { +public class TimeOutProperty extends AbstractTargetProperty { public TimeOutProperty() { super(PrimitiveType.TIME_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 9f0835a9c6..114f6deebf 100644 --- a/core/src/main/java/org/lflang/target/property/TracingProperty.java +++ b/core/src/main/java/org/lflang/target/property/TracingProperty.java @@ -21,7 +21,7 @@ import org.lflang.target.property.type.UnionType; /** Directive to enable tracing. */ -public class TracingProperty extends AbstractTargetProperty { +public class TracingProperty extends AbstractTargetProperty { public TracingProperty() { super(UnionType.TRACING_UNION); 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 f0b8b9fcda..057be50e56 100644 --- a/core/src/main/java/org/lflang/target/property/WorkersProperty.java +++ b/core/src/main/java/org/lflang/target/property/WorkersProperty.java @@ -9,7 +9,7 @@ import org.lflang.target.property.type.PrimitiveType; /** Directive to specify the number of worker threads used by the runtime. */ -public class WorkersProperty extends AbstractTargetProperty { +public class WorkersProperty extends AbstractTargetProperty { public WorkersProperty() { super(PrimitiveType.NON_NEGATIVE_INTEGER); diff --git a/core/src/main/java/org/lflang/target/property/type/DictionaryType.java b/core/src/main/java/org/lflang/target/property/type/DictionaryType.java index 10522a09b1..00aae0a870 100644 --- a/core/src/main/java/org/lflang/target/property/type/DictionaryType.java +++ b/core/src/main/java/org/lflang/target/property/type/DictionaryType.java @@ -9,6 +9,7 @@ import org.lflang.lf.Element; import org.lflang.lf.KeyValuePair; import org.lflang.lf.KeyValuePairs; +import org.lflang.lf.LfPackage.Literals; import org.lflang.target.property.ClockSyncOptionsProperty.ClockSyncOption; import org.lflang.target.property.CoordinationOptionsProperty.CoordinationOption; import org.lflang.target.property.DockerProperty.DockerOption; @@ -67,6 +68,12 @@ public boolean check(Element e, String name, MessageReporter v) { TargetPropertyType type = match.get().getType(); valid &= type.check(val, "Entry", v); } else { + v.at(pair, Literals.KEY_VALUE_PAIR__NAME) + .error( + "Unrecognized key: " + + pair.getName() + + ". Recognized properties are: " + + keysList()); valid = false; } return valid; @@ -87,8 +94,11 @@ public boolean validate(Element e) { /** Return a human-readable description of this type. */ @Override public String toString() { - return "a dictionary with one or more of the following keys: " - + options.stream().map(option -> option.toString()).collect(Collectors.joining(", ")); + return "a dictionary with one or more of the following keys: " + keysList(); + } + + public String keysList() { + return options.stream().map(option -> option.toString()).collect(Collectors.joining(", ")); } /** Interface for dictionary elements. It associates an entry with a type. */ diff --git a/core/src/main/java/org/lflang/target/property/type/UnionType.java b/core/src/main/java/org/lflang/target/property/type/UnionType.java index b044455115..66abb1d1ef 100644 --- a/core/src/main/java/org/lflang/target/property/type/UnionType.java +++ b/core/src/main/java/org/lflang/target/property/type/UnionType.java @@ -6,14 +6,7 @@ import java.util.stream.Collectors; import org.lflang.MessageReporter; import org.lflang.Target; -import org.lflang.ast.ASTUtils; import org.lflang.lf.Element; -import org.lflang.target.property.BuildTypeProperty; -import org.lflang.target.property.ClockSyncModeProperty.ClockSyncMode; -import org.lflang.target.property.CoordinationProperty.CoordinationMode; -import org.lflang.target.property.LoggingProperty.LogLevel; -import org.lflang.target.property.PlatformProperty.Platform; -import org.lflang.target.property.SchedulerProperty.SchedulerOption; /** * A type that can assume one of several types. @@ -21,34 +14,22 @@ * @author Marten Lohstroh */ public enum UnionType implements TargetPropertyType { - STRING_OR_STRING_ARRAY(Arrays.asList(PrimitiveType.STRING, ArrayType.STRING_ARRAY), null), - PLATFORM_STRING_OR_DICTIONARY( - Arrays.asList(PrimitiveType.STRING, DictionaryType.PLATFORM_DICT), null), - FILE_OR_FILE_ARRAY(Arrays.asList(PrimitiveType.FILE, ArrayType.FILE_ARRAY), null), - BUILD_TYPE_UNION(Arrays.asList(BuildTypeProperty.BuildType.values()), null), - COORDINATION_UNION(Arrays.asList(CoordinationMode.values()), CoordinationMode.CENTRALIZED), - SCHEDULER_UNION(Arrays.asList(SchedulerOption.values()), SchedulerOption.getDefault()), - LOGGING_UNION(Arrays.asList(LogLevel.values()), LogLevel.INFO), - PLATFORM_UNION(Arrays.asList(Platform.values()), Platform.AUTO), - CLOCK_SYNC_UNION(Arrays.asList(ClockSyncMode.values()), ClockSyncMode.INIT), - DOCKER_UNION(Arrays.asList(PrimitiveType.BOOLEAN, DictionaryType.DOCKER_DICT), null), - TRACING_UNION(Arrays.asList(PrimitiveType.BOOLEAN, DictionaryType.TRACING_DICT), null); + STRING_OR_STRING_ARRAY(Arrays.asList(PrimitiveType.STRING, ArrayType.STRING_ARRAY)), + PLATFORM_STRING_OR_DICTIONARY(List.of(new PlatformType(), DictionaryType.PLATFORM_DICT)), + FILE_OR_FILE_ARRAY(Arrays.asList(PrimitiveType.FILE, ArrayType.FILE_ARRAY)), + DOCKER_UNION(Arrays.asList(PrimitiveType.BOOLEAN, DictionaryType.DOCKER_DICT)), + TRACING_UNION(Arrays.asList(PrimitiveType.BOOLEAN, DictionaryType.TRACING_DICT)); /** The constituents of this type union. */ - public final List> options; - - /** The default type, if there is one. */ - private final Enum defaultOption; + public final List options; /** * Private constructor for creating unions types. * - * @param options The types that that are part of the union. - * @param defaultOption The default type. + * @param options The types that are part of the union. */ - UnionType(List> options, Enum defaultOption) { + UnionType(List options) { this.options = options; - this.defaultOption = defaultOption; } /** @@ -57,30 +38,18 @@ public enum UnionType implements TargetPropertyType { * @param name The string to match against. * @return The matching dictionary element (or null if there is none). */ - public Enum forName(String name) { + public TargetPropertyType forName(String name) { return Target.match(name, options); } /** Recursively check that the passed in element conforms to the rules of this union. */ @Override public boolean check(Element e, String name, MessageReporter r) { - Optional> match = this.match(e); - var found = false; + var match = this.match(e); if (match.isPresent()) { - found = true; - // Go deeper if the element is an array or dictionary. - Enum type = match.get(); - if (type instanceof DictionaryType) { - found = ((DictionaryType) type).check(e, name, r); - } else if (type instanceof ArrayType) { - found = ((ArrayType) type).check(e, name, r); - } else if (type instanceof PrimitiveType) { - found = ((PrimitiveType) type).check(e, name, r); - } else if (!(type instanceof Enum)) { - throw new RuntimeException("Encountered an unknown type."); - } + return match.get().check(e, name, r); } - return found; + return false; } /** @@ -89,17 +58,8 @@ public boolean check(Element e, String name, MessageReporter r) { * @param e AST node that represents the value of a target property. * @return The matching type wrapped in an Optional object. */ - private Optional> match(Element e) { - return this.options.stream() - .filter( - option -> { - if (option instanceof TargetPropertyType) { - return ((TargetPropertyType) option).validate(e); - } else { - return ASTUtils.elementToSingleString(e).equalsIgnoreCase(option.toString()); - } - }) - .findAny(); + private Optional match(Element e) { + return this.options.stream().filter(option -> option.validate(e)).findAny(); } /** @@ -122,15 +82,6 @@ public boolean validate(Element e) { @Override public String toString() { return "one of the following: " - + options.stream() - .map( - option -> { - if (option == this.defaultOption) { - return option.toString() + " (default)"; - } else { - return option.toString(); - } - }) - .collect(Collectors.joining(", ")); + + options.stream().map(option -> option.toString()).collect(Collectors.joining(", ")); } } diff --git a/core/src/main/kotlin/org/lflang/generator/cpp/CppExtensions.kt b/core/src/main/kotlin/org/lflang/generator/cpp/CppExtensions.kt index b525c8e481..d444b3083e 100644 --- a/core/src/main/kotlin/org/lflang/generator/cpp/CppExtensions.kt +++ b/core/src/main/kotlin/org/lflang/generator/cpp/CppExtensions.kt @@ -13,7 +13,7 @@ import org.lflang.lf.TriggerRef import org.lflang.lf.VarRef import org.lflang.lf.Visibility import org.lflang.lf.WidthSpec -import org.lflang.target.property.LoggingProperty +import org.lflang.target.property.type.LoggingType.LogLevel /************* * Copyright (c) 2019-2021, TU Dresden. @@ -139,13 +139,13 @@ val InferredType.cppType: String /** Convert a log level to a severity number understood by the reactor-cpp runtime. */ -val LoggingProperty.LogLevel.severity +val LogLevel.severity get() = when (this) { - LoggingProperty.LogLevel.ERROR -> 1 - LoggingProperty.LogLevel.WARN -> 2 - LoggingProperty.LogLevel.INFO -> 3 - LoggingProperty.LogLevel.LOG -> 4 - LoggingProperty.LogLevel.DEBUG -> 4 + LogLevel.ERROR -> 1 + LogLevel.WARN -> 2 + LogLevel.INFO -> 3 + LogLevel.LOG -> 4 + LogLevel.DEBUG -> 4 } fun Reactor.hasBankIndexParameter() = parameters.firstOrNull { it.name == "bank_index" } != null diff --git a/core/src/main/kotlin/org/lflang/generator/cpp/CppStandaloneGenerator.kt b/core/src/main/kotlin/org/lflang/generator/cpp/CppStandaloneGenerator.kt index a64b29b88c..8d21e05282 100644 --- a/core/src/main/kotlin/org/lflang/generator/cpp/CppStandaloneGenerator.kt +++ b/core/src/main/kotlin/org/lflang/generator/cpp/CppStandaloneGenerator.kt @@ -1,9 +1,8 @@ package org.lflang.generator.cpp -import org.lflang.target.property.BuildTypeProperty.BuildType import org.lflang.generator.CodeMap import org.lflang.generator.LFGeneratorContext -import org.lflang.target.TargetProperty +import org.lflang.target.property.type.BuildTypeType.BuildType import org.lflang.toUnixString import org.lflang.util.FileUtil import org.lflang.util.LFCommand diff --git a/core/src/main/kotlin/org/lflang/generator/rust/RustCargoTomlEmitter.kt b/core/src/main/kotlin/org/lflang/generator/rust/RustCargoTomlEmitter.kt index 00749e17e9..c1a016af74 100644 --- a/core/src/main/kotlin/org/lflang/generator/rust/RustCargoTomlEmitter.kt +++ b/core/src/main/kotlin/org/lflang/generator/rust/RustCargoTomlEmitter.kt @@ -24,7 +24,7 @@ package org.lflang.generator.rust -import org.lflang.target.property.BuildTypeProperty.BuildType.* +import org.lflang.target.property.type.BuildTypeType.BuildType import org.lflang.escapeStringLiteral import org.lflang.generator.PrependOperator.rangeTo import org.lflang.joinWithCommas @@ -62,19 +62,19 @@ ${" |"..crate.dependencies.asIterable().joinWithLn { (name, spec) -> nam |[features] |cli=["clap"] | - |[profile.${RELEASE.cargoProfileName}] # use `build-type: $RELEASE` + |[profile.${BuildType.RELEASE.cargoProfileName}] # use `build-type: ${BuildType.RELEASE}` |lto = "thin" |codegen-units = 1 | - |[profile.${MIN_SIZE_REL.cargoProfileName}] # use `build-type: $MIN_SIZE_REL` + |[profile.${BuildType.MIN_SIZE_REL.cargoProfileName}] # use `build-type: ${BuildType.MIN_SIZE_REL}` |inherits = "release" |opt-level = "s" | - |[profile.${REL_WITH_DEB_INFO.cargoProfileName}] # use `build-type: $REL_WITH_DEB_INFO` + |[profile.${BuildType.REL_WITH_DEB_INFO.cargoProfileName}] # use `build-type: ${BuildType.REL_WITH_DEB_INFO}` |inherits = "release" |debug = true | - |[profile.${TEST.cargoProfileName}] # use `build-type: $TEST` + |[profile.${BuildType.TEST.cargoProfileName}] # use `build-type: ${BuildType.TEST}` |inherits = "dev" |debug = true | diff --git a/core/src/main/kotlin/org/lflang/generator/rust/RustGenerator.kt b/core/src/main/kotlin/org/lflang/generator/rust/RustGenerator.kt index 0c11c1538e..b7d438d0dc 100644 --- a/core/src/main/kotlin/org/lflang/generator/rust/RustGenerator.kt +++ b/core/src/main/kotlin/org/lflang/generator/rust/RustGenerator.kt @@ -26,7 +26,6 @@ package org.lflang.generator.rust import org.eclipse.emf.ecore.resource.Resource import org.lflang.Target -import org.lflang.target.property.BuildTypeProperty.BuildType import org.lflang.generator.GeneratorUtils.canGenerate import org.lflang.generator.CodeMap import org.lflang.generator.GeneratorBase @@ -37,6 +36,7 @@ import org.lflang.generator.TargetTypes import org.lflang.joinWithCommas import org.lflang.scoping.LFGlobalScopeProvider +import org.lflang.target.property.type.BuildTypeType import org.lflang.util.FileUtil import java.nio.file.Files import java.nio.file.Path @@ -97,9 +97,9 @@ class RustGenerator( this += "build" val buildType = targetConfig.rust.getBuildType(context.targetConfig.buildType) - if (buildType == BuildType.RELEASE) { + if (buildType == BuildTypeType.BuildType.RELEASE) { this += "--release" - } else if (buildType != BuildType.DEBUG) { + } else if (buildType != BuildTypeType.BuildType.DEBUG) { this += "--profile" this += buildType.cargoProfileName } 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 5be75ace24..52f0e19608 100644 --- a/core/src/main/kotlin/org/lflang/generator/rust/RustModel.kt +++ b/core/src/main/kotlin/org/lflang/generator/rust/RustModel.kt @@ -26,7 +26,7 @@ package org.lflang.generator.rust import org.lflang.* -import org.lflang.target.property.BuildTypeProperty.BuildType +import org.lflang.target.property.type.BuildTypeType.BuildType import org.lflang.ast.ASTUtils import org.lflang.generator.* import org.lflang.lf.* 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 2fd89a499e..5d9267ddfb 100644 --- a/core/src/test/java/org/lflang/tests/compiler/LinguaFrancaValidationTest.java +++ b/core/src/test/java/org/lflang/tests/compiler/LinguaFrancaValidationTest.java @@ -53,10 +53,10 @@ import org.lflang.target.TargetConfig; import org.lflang.target.property.CargoDependenciesProperty; import org.lflang.target.property.PlatformProperty; -import org.lflang.target.property.PlatformProperty.Platform; import org.lflang.target.property.type.ArrayType; import org.lflang.target.property.type.DictionaryType; import org.lflang.target.property.type.DictionaryType.DictionaryElement; +import org.lflang.target.property.type.PlatformType.Platform; import org.lflang.target.property.type.PrimitiveType; import org.lflang.target.property.type.StringDictionaryType; import org.lflang.target.property.type.TargetPropertyType; @@ -1384,12 +1384,8 @@ private List synthesizeExamples(ArrayType type, boolean correct) { private List synthesizeExamples(UnionType type, boolean correct) { List examples = new LinkedList<>(); if (correct) { - for (Enum it : type.options) { - if (it instanceof TargetPropertyType) { - examples.addAll(synthesizeExamples((TargetPropertyType) it, correct)); - } else { - examples.add(it.toString()); - } + for (var it : type.options) { + examples.addAll(synthesizeExamples(it, correct)); } } else { // Return some obviously bad examples for the common @@ -1469,7 +1465,7 @@ private List synthesizeExamples(TargetPropertyType type, boolean correct } else if (type instanceof StringDictionaryType) { return synthesizeExamples((StringDictionaryType) type, correct); } else { - Assertions.fail("Encountered an unknown type: " + type); + // Assertions.fail("Encountered an unknown type: " + type); } } return new LinkedList<>(); @@ -1511,6 +1507,8 @@ public Collection checkTargetProperties() throws Exception { "Property %s (%s) - known good assignment: %s".formatted(property, type, it), () -> { Model model = createModel(property, it); + System.out.println(property.name()); + System.out.println(it.toString()); validator.assertNoErrors(model); // Also make sure warnings are produced when files are not present. if (type == PrimitiveType.FILE) { @@ -1529,14 +1527,15 @@ public Collection checkTargetProperties() throws Exception { for (String it : knownIncorrect) { var test = DynamicTest.dynamicTest( - "Property %s (%s) - known bad assignment: %s".formatted(property, type, it), + "Property %s (%s) - known bad assignment: %s" + .formatted(property.name(), type, it), () -> { validator.assertError( createModel(property, it), LfPackage.eINSTANCE.getKeyValuePair(), null, String.format( - "Target property '%s' is required to be %s.", property, type)); + "Target property '%s' is required to be %s.", property.name(), type)); }); result.add(test); } @@ -1547,7 +1546,8 @@ public Collection checkTargetProperties() throws Exception { for (List it : list) { var test = DynamicTest.dynamicTest( - "Property %s (%s) - known bad assignment: %s".formatted(property, type, it), + "Property %s (%s) - known bad assignment: %s" + .formatted(property.name(), type, it), () -> { System.out.println(it); // var issues = validator.validate(createModel(property, @@ -1564,7 +1564,8 @@ public Collection checkTargetProperties() throws Exception { LfPackage.eINSTANCE.getKeyValuePair(), null, String.format( - "Target property '%s' is required to be %s.", property, type)); + "Target property '%s' is required to be %s.", + property.name(), type)); } }); // String.format( @@ -1622,12 +1623,12 @@ public void checkPlatformProperty() throws Exception { createModel(new PlatformProperty(), "foobar"), LfPackage.eINSTANCE.getKeyValuePair(), null, - PlatformProperty.UNKNOW_PLATFORM); + PlatformProperty.UNKNOWN_PLATFORM); validator.assertError( createModel(new PlatformProperty(), "{ name: foobar }"), LfPackage.eINSTANCE.getKeyValuePair(), null, - PlatformProperty.UNKNOW_PLATFORM); + PlatformProperty.UNKNOWN_PLATFORM); } @Test diff --git a/core/src/testFixtures/java/org/lflang/tests/Configurators.java b/core/src/testFixtures/java/org/lflang/tests/Configurators.java index 93b0743e2b..7191efe494 100644 --- a/core/src/testFixtures/java/org/lflang/tests/Configurators.java +++ b/core/src/testFixtures/java/org/lflang/tests/Configurators.java @@ -24,8 +24,8 @@ package org.lflang.tests; -import org.lflang.target.property.LoggingProperty.LogLevel; -import org.lflang.target.property.PlatformProperty.Platform; +import org.lflang.target.property.type.LoggingType.LogLevel; +import org.lflang.target.property.type.PlatformType.Platform; import org.lflang.tests.TestRegistry.TestCategory; /** From 2d47aebd4fe15444510d3561338fd0938113b88a Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Tue, 3 Oct 2023 23:58:58 -0700 Subject: [PATCH 069/145] Custom types for composite target properties --- .../target/property/type/BuildTypeType.java | 51 +++++++++++++++ .../property/type/ClockSyncModeType.java | 33 ++++++++++ .../property/type/CoordinationModeType.java | 32 ++++++++++ .../target/property/type/LoggingType.java | 34 ++++++++++ .../target/property/type/OptionsType.java | 60 ++++++++++++++++++ .../target/property/type/PlatformType.java | 56 +++++++++++++++++ .../target/property/type/SchedulerType.java | 62 +++++++++++++++++++ 7 files changed, 328 insertions(+) create mode 100644 core/src/main/java/org/lflang/target/property/type/BuildTypeType.java create mode 100644 core/src/main/java/org/lflang/target/property/type/ClockSyncModeType.java create mode 100644 core/src/main/java/org/lflang/target/property/type/CoordinationModeType.java create mode 100644 core/src/main/java/org/lflang/target/property/type/LoggingType.java create mode 100644 core/src/main/java/org/lflang/target/property/type/OptionsType.java create mode 100644 core/src/main/java/org/lflang/target/property/type/PlatformType.java create mode 100644 core/src/main/java/org/lflang/target/property/type/SchedulerType.java diff --git a/core/src/main/java/org/lflang/target/property/type/BuildTypeType.java b/core/src/main/java/org/lflang/target/property/type/BuildTypeType.java new file mode 100644 index 0000000000..8045eb9229 --- /dev/null +++ b/core/src/main/java/org/lflang/target/property/type/BuildTypeType.java @@ -0,0 +1,51 @@ +package org.lflang.target.property.type; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; +import org.lflang.target.property.type.BuildTypeType.BuildType; + +/** Enumeration of supported platforms */ +public class BuildTypeType extends OptionsType { + + @Override + protected Class enumClass() { + return BuildType.class; + } + + /** + * Enumeration of Cmake build types. These are also mapped to Cargo profiles for the Rust target + * (see {@link org.lflang.generator.rust.RustTargetConfig}) + * + * @author Christian Menard + */ + public enum BuildType { + RELEASE("Release"), + DEBUG("Debug"), + TEST("Test"), + REL_WITH_DEB_INFO("RelWithDebInfo"), + MIN_SIZE_REL("MinSizeRel"); + + /** Alias used in toString method. */ + private final String alias; + + /** Private constructor for Cmake build types. */ + BuildType(String alias) { + this.alias = alias; + } + + /** Return the alias. */ + @Override + public String toString() { + return this.alias; + } + + public static List optionsList() { + return Arrays.stream(BuildType.values()).collect(Collectors.toList()); + } + + public static BuildType getDefault() { + return BuildType.DEBUG; + } + } +} diff --git a/core/src/main/java/org/lflang/target/property/type/ClockSyncModeType.java b/core/src/main/java/org/lflang/target/property/type/ClockSyncModeType.java new file mode 100644 index 0000000000..72ec1f8d1a --- /dev/null +++ b/core/src/main/java/org/lflang/target/property/type/ClockSyncModeType.java @@ -0,0 +1,33 @@ +package org.lflang.target.property.type; + +import org.lflang.target.property.type.ClockSyncModeType.ClockSyncMode; + +public class ClockSyncModeType extends OptionsType { + + @Override + protected Class enumClass() { + return ClockSyncMode.class; + } + + /** + * Enumeration of clock synchronization modes. + * + *
    + *
  • OFF: The clock synchronization is universally off. + *
  • STARTUP: Clock synchronization occurs at startup only. + *
  • ON: Clock synchronization occurs at startup and at runtime. + *
+ * + * @author Edward A. Lee + */ + public enum ClockSyncMode { + OFF, + INIT, + ON; + /** Return the name in lower case. */ + @Override + public String toString() { + return this.name().toLowerCase(); + } + } +} diff --git a/core/src/main/java/org/lflang/target/property/type/CoordinationModeType.java b/core/src/main/java/org/lflang/target/property/type/CoordinationModeType.java new file mode 100644 index 0000000000..67e0f9b433 --- /dev/null +++ b/core/src/main/java/org/lflang/target/property/type/CoordinationModeType.java @@ -0,0 +1,32 @@ +package org.lflang.target.property.type; + +import org.lflang.target.property.type.CoordinationModeType.CoordinationMode; + +/** Enumeration of supported platforms */ +public class CoordinationModeType extends OptionsType { + + @Override + protected Class enumClass() { + return CoordinationMode.class; + } + + /** + * Enumeration of coordination types. + * + * @author Marten Lohstroh + */ + public enum CoordinationMode { + CENTRALIZED, + DECENTRALIZED; + + /** Return the name in lower case. */ + @Override + public String toString() { + return this.name().toLowerCase(); + } + + public static CoordinationMode getDefault() { + return CoordinationMode.CENTRALIZED; + } + } +} diff --git a/core/src/main/java/org/lflang/target/property/type/LoggingType.java b/core/src/main/java/org/lflang/target/property/type/LoggingType.java new file mode 100644 index 0000000000..aad6e2627d --- /dev/null +++ b/core/src/main/java/org/lflang/target/property/type/LoggingType.java @@ -0,0 +1,34 @@ +package org.lflang.target.property.type; + +import org.lflang.target.property.type.LoggingType.LogLevel; + +public class LoggingType extends OptionsType { + + @Override + protected Class enumClass() { + return LogLevel.class; + } + + /** + * Log levels in descending order of severity. + * + * @author Marten Lohstroh + */ + public enum LogLevel { + ERROR, + WARN, + INFO, + LOG, + DEBUG; + + /** Return the name in lower case. */ + @Override + public String toString() { + return this.name().toLowerCase(); + } + + public static LogLevel getDefault() { + return LogLevel.INFO; + } + } +} diff --git a/core/src/main/java/org/lflang/target/property/type/OptionsType.java b/core/src/main/java/org/lflang/target/property/type/OptionsType.java new file mode 100644 index 0000000000..0fac71696f --- /dev/null +++ b/core/src/main/java/org/lflang/target/property/type/OptionsType.java @@ -0,0 +1,60 @@ +package org.lflang.target.property.type; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; +import org.lflang.MessageReporter; +import org.lflang.ast.ASTUtils; +import org.lflang.lf.Element; + +public abstract class OptionsType> implements TargetPropertyType { + + public final List optionsList() { + return Arrays.stream(enumClass().getEnumConstants()).collect(Collectors.toList()); + } + + protected abstract Class enumClass(); + + @Override + public boolean validate(Element e) { + if (e.getKeyvalue() != null) { + return false; // Not a literal. + } + return optionsList().stream() + .anyMatch(v -> v.toString().equalsIgnoreCase(ASTUtils.elementToSingleString(e))); + } + + public String optionsString() { + return optionsList().stream().map(v -> v.toString()).collect(Collectors.joining(", ")); + } + + @Override + public boolean check(Element e, String name, MessageReporter r) { + var valid = this.validate(e); + if (!valid) { + r.at(e).error(String.format("%s is required to be %s.", name, this)); + return false; + } else { + return true; + } + } + + @Override + public String toString() { + return "a choice of " + this.optionsString(); + } + + /** + * Return option among those listed that matches the given name. + * + * @param name The string to match against. + * @return The matching option (or null if there is none). + */ + public T forName(String name) { + var match = optionsList().stream().filter(o -> o.toString().equalsIgnoreCase(name)).findFirst(); + if (match.isPresent()) { + return match.get(); + } + return null; + } +} diff --git a/core/src/main/java/org/lflang/target/property/type/PlatformType.java b/core/src/main/java/org/lflang/target/property/type/PlatformType.java new file mode 100644 index 0000000000..6382291c61 --- /dev/null +++ b/core/src/main/java/org/lflang/target/property/type/PlatformType.java @@ -0,0 +1,56 @@ +package org.lflang.target.property.type; + +import org.lflang.target.property.type.PlatformType.Platform; + +/** Enumeration of supported platforms */ +public class PlatformType extends OptionsType { + + @Override + protected Class enumClass() { + return Platform.class; + } + + public enum Platform { + AUTO, + ARDUINO, // FIXME: not multithreaded + NRF52("Nrf52", true), + RP2040("Rp2040", false), + LINUX("Linux", true), + MAC("Darwin", true), + ZEPHYR("Zephyr", true), + WINDOWS("Windows", true); + + final String cMakeName; + + private final boolean multiThreaded; + + Platform() { + this.cMakeName = this.toString(); + this.multiThreaded = true; + } + + Platform(String cMakeName, boolean isMultiThreaded) { + this.cMakeName = cMakeName; + this.multiThreaded = isMultiThreaded; + } + + /** Return the name in lower case. */ + @Override + public String toString() { + return this.name().toLowerCase(); + } + + /** Get the CMake name for the platform. */ + public String getcMakeName() { + return this.cMakeName; + } + + public boolean isMultiThreaded() { + return this.multiThreaded; + } + + public Platform getDefault() { + return Platform.AUTO; + } + } +} diff --git a/core/src/main/java/org/lflang/target/property/type/SchedulerType.java b/core/src/main/java/org/lflang/target/property/type/SchedulerType.java new file mode 100644 index 0000000000..4edc45d515 --- /dev/null +++ b/core/src/main/java/org/lflang/target/property/type/SchedulerType.java @@ -0,0 +1,62 @@ +package org.lflang.target.property.type; + +import com.google.common.collect.ImmutableList; +import java.nio.file.Path; +import java.util.List; +import org.lflang.target.property.type.SchedulerType.Scheduler; + +public class SchedulerType extends OptionsType { + + @Override + protected Class enumClass() { + return Scheduler.class; + } + + /** + * Supported schedulers. + * + * @author Soroush Bateni + */ + public enum Scheduler { + NP(false), // Non-preemptive + ADAPTIVE( + false, + List.of( + Path.of("scheduler_adaptive.c"), + Path.of("worker_assignments.h"), + Path.of("worker_states.h"), + Path.of("data_collection.h"))), + GEDF_NP(true), // Global EDF non-preemptive + GEDF_NP_CI(true); // Global EDF non-preemptive with chain ID + + /** Indicate whether the scheduler prioritizes reactions by deadline. */ + private final boolean prioritizesDeadline; + + /** Relative paths to files required by this scheduler. */ + private final List relativePaths; + + Scheduler(boolean prioritizesDeadline) { + this(prioritizesDeadline, null); + } + + Scheduler(boolean prioritizesDeadline, List relativePaths) { + this.prioritizesDeadline = prioritizesDeadline; + this.relativePaths = relativePaths; + } + + /** Return true if the scheduler prioritizes reactions by deadline. */ + public boolean prioritizesDeadline() { + return this.prioritizesDeadline; + } + + public List getRelativePaths() { + return relativePaths != null + ? ImmutableList.copyOf(relativePaths) + : List.of(Path.of("scheduler_" + this + ".c")); + } + + public static Scheduler getDefault() { + return Scheduler.NP; + } + } +} From 769afbd8c46e88c128e93151d5d338e566682dea Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Wed, 4 Oct 2023 00:48:31 -0700 Subject: [PATCH 070/145] More bugfixes --- .../org/lflang/target/property/PlatformProperty.java | 10 +++------- .../tests/compiler/LinguaFrancaValidationTest.java | 7 ++++--- 2 files changed, 7 insertions(+), 10 deletions(-) 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 4eb7f780c2..f81062115d 100644 --- a/core/src/main/java/org/lflang/target/property/PlatformProperty.java +++ b/core/src/main/java/org/lflang/target/property/PlatformProperty.java @@ -27,10 +27,6 @@ */ public class PlatformProperty extends AbstractTargetProperty { - public static final String UNKNOWN_PLATFORM = - "Unidentified Platform Type, LF supports the following platform types: " - + new PlatformType().optionsList(); - public PlatformProperty() { super(UnionType.PLATFORM_STRING_OR_DICTIONARY); } @@ -168,18 +164,18 @@ public static class PlatformOptions { // FIXME: use a record for this * @author Anirudh Rengarajan */ public enum PlatformOption implements DictionaryElement { - NAME("name", PrimitiveType.STRING), + NAME("name", new PlatformType()), BAUDRATE("baud-rate", PrimitiveType.NON_NEGATIVE_INTEGER), BOARD("board", PrimitiveType.STRING), FLASH("flash", PrimitiveType.BOOLEAN), PORT("port", PrimitiveType.STRING), USER_THREADS("user-threads", PrimitiveType.NON_NEGATIVE_INTEGER); - public final PrimitiveType type; + public final TargetPropertyType type; private final String description; - PlatformOption(String alias, PrimitiveType type) { + PlatformOption(String alias, TargetPropertyType type) { this.description = alias; this.type = type; } 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 5d9267ddfb..da67f16812 100644 --- a/core/src/test/java/org/lflang/tests/compiler/LinguaFrancaValidationTest.java +++ b/core/src/test/java/org/lflang/tests/compiler/LinguaFrancaValidationTest.java @@ -56,6 +56,7 @@ import org.lflang.target.property.type.ArrayType; import org.lflang.target.property.type.DictionaryType; import org.lflang.target.property.type.DictionaryType.DictionaryElement; +import org.lflang.target.property.type.PlatformType; import org.lflang.target.property.type.PlatformType.Platform; import org.lflang.target.property.type.PrimitiveType; import org.lflang.target.property.type.StringDictionaryType; @@ -1623,12 +1624,12 @@ public void checkPlatformProperty() throws Exception { createModel(new PlatformProperty(), "foobar"), LfPackage.eINSTANCE.getKeyValuePair(), null, - PlatformProperty.UNKNOWN_PLATFORM); + new PlatformType().toString()); validator.assertError( createModel(new PlatformProperty(), "{ name: foobar }"), - LfPackage.eINSTANCE.getKeyValuePair(), + LfPackage.eINSTANCE.getElement(), null, - PlatformProperty.UNKNOWN_PLATFORM); + new PlatformType().toString()); } @Test From 8da314784109c5b731d3a468b72eb98ba5ae3702 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Wed, 4 Oct 2023 14:29:06 -0700 Subject: [PATCH 071/145] Fix unit tests --- core/src/main/java/org/lflang/AbstractTargetProperty.java | 2 +- .../org/lflang/tests/compiler/LinguaFrancaValidationTest.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/core/src/main/java/org/lflang/AbstractTargetProperty.java b/core/src/main/java/org/lflang/AbstractTargetProperty.java index cdef9ddce6..5a64918e3d 100644 --- a/core/src/main/java/org/lflang/AbstractTargetProperty.java +++ b/core/src/main/java/org/lflang/AbstractTargetProperty.java @@ -195,7 +195,7 @@ public T get() { public static List getAllTargetProperties(Object object) { var fields = object.getClass().getDeclaredFields(); - + // FIXME: also collect inherited properties. List properties = Arrays.stream(fields) .filter(f -> AbstractTargetProperty.class.isAssignableFrom(f.getType())) 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 da67f16812..695be5abee 100644 --- a/core/src/test/java/org/lflang/tests/compiler/LinguaFrancaValidationTest.java +++ b/core/src/test/java/org/lflang/tests/compiler/LinguaFrancaValidationTest.java @@ -1311,9 +1311,9 @@ public void recognizeHostNames() throws Exception { LfPackage.eINSTANCE.getKeyValuePair(), UnionType.PLATFORM_STRING_OR_DICTIONARY), List.of( - "{name: [1, 2, 3]}", LfPackage.eINSTANCE.getElement(), PrimitiveType.STRING), + "{name: [1, 2, 3]}", LfPackage.eINSTANCE.getElement(), new PlatformType()), List.of( - "{name: {bar: baz}}", LfPackage.eINSTANCE.getElement(), PrimitiveType.STRING), + "{name: {bar: baz}}", LfPackage.eINSTANCE.getElement(), new PlatformType()), List.of( "{board: [1, 2, 3]}", LfPackage.eINSTANCE.getElement(), PrimitiveType.STRING), List.of( From 902aa010fa10b8ea35c04b5621f8d08255346ee2 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Wed, 4 Oct 2023 21:10:22 -0700 Subject: [PATCH 072/145] Redesign based on feedback from @oowekyala --- .../lflang/tests/runtime/CVerifierTest.java | 3 +- .../org/lflang/tests/runtime/CppRos2Test.java | 3 +- .../org/lflang/AbstractTargetProperty.java | 21 -- .../main/java/org/lflang/ast/ASTUtils.java | 7 +- .../federated/extensions/CExtension.java | 22 +- .../federated/extensions/CExtensionUtils.java | 63 +++-- .../federated/extensions/TSExtension.java | 7 +- .../federated/generator/FedFileConfig.java | 9 +- .../federated/generator/FedGenerator.java | 25 +- .../federated/generator/FedTargetConfig.java | 6 +- .../launcher/FedLauncherGenerator.java | 28 ++- .../FedROS2CPPSerialization.java | 3 +- .../org/lflang/generator/GeneratorBase.java | 9 +- .../org/lflang/generator/GeneratorUtils.java | 9 +- .../lflang/generator/c/CCmakeGenerator.java | 64 ++--- .../org/lflang/generator/c/CCompiler.java | 46 ++-- .../lflang/generator/c/CDockerGenerator.java | 11 +- .../c/CEnvironmentFunctionGenerator.java | 3 +- .../org/lflang/generator/c/CGenerator.java | 165 +++++++----- .../generator/c/CMainFunctionGenerator.java | 22 +- .../generator/c/CPreambleGenerator.java | 37 +-- .../generator/c/CTriggerObjectsGenerator.java | 6 +- .../java/org/lflang/generator/c/CUtil.java | 6 +- .../generator/python/PythonGenerator.java | 9 +- .../generator/rust/RustTargetConfig.java | 30 +-- .../java/org/lflang/target/TargetConfig.java | 235 ++++++------------ .../org/lflang/target/TargetProperty.java | 8 +- .../property/BuildCommandsProperty.java | 6 +- .../property/ClockSyncModeProperty.java | 2 +- .../property/CompileDefinitionsProperty.java | 7 +- .../property/CompilerFlagsProperty.java | 2 +- .../target/property/CompilerProperty.java | 2 +- .../target/property/CoordinationProperty.java | 5 +- .../ExportDependencyGraphProperty.java | 5 +- .../target/property/ExportToYamlProperty.java | 6 +- .../property/ExternalRuntimePathProperty.java | 5 +- .../lflang/target/property/FastProperty.java | 5 +- .../target/property/KeepaliveProperty.java | 4 +- .../target/property/LoggingProperty.java | 5 +- .../target/property/NoCompileProperty.java | 2 +- .../property/NoRuntimeValidationProperty.java | 2 +- .../property/PrintStatisticsProperty.java | 2 +- .../lflang/target/property/Ros2Property.java | 2 +- .../target/property/SchedulerProperty.java | 2 +- .../target/property/TimeOutProperty.java | 2 +- .../target/property/TracingProperty.java | 2 +- .../target/property/VerifyProperty.java | 2 +- .../target/property/WorkersProperty.java | 5 +- .../java/org/lflang/util/ArduinoUtil.java | 15 +- .../org/lflang/generator/cpp/CppGenerator.kt | 21 +- .../generator/cpp/CppPlatformGenerator.kt | 15 +- .../generator/cpp/CppRos2NodeGenerator.kt | 9 +- .../generator/cpp/CppRos2PackageGenerator.kt | 12 +- .../cpp/CppStandaloneCmakeGenerator.kt | 14 +- .../generator/cpp/CppStandaloneGenerator.kt | 10 +- .../cpp/CppStandaloneMainGenerator.kt | 17 +- .../lflang/generator/rust/RustGenerator.kt | 16 +- .../org/lflang/generator/rust/RustModel.kt | 47 ++-- .../generator/ts/TSConstructorGenerator.kt | 3 +- .../org/lflang/generator/ts/TSGenerator.kt | 15 +- .../ts/TSParameterPreambleGenerator.kt | 12 +- .../compiler/LinguaFrancaValidationTest.java | 2 +- .../java/org/lflang/tests/Configurators.java | 21 +- .../java/org/lflang/tests/TestBase.java | 3 +- 64 files changed, 618 insertions(+), 546 deletions(-) diff --git a/core/src/integrationTest/java/org/lflang/tests/runtime/CVerifierTest.java b/core/src/integrationTest/java/org/lflang/tests/runtime/CVerifierTest.java index 4ac734d314..7140eca72f 100644 --- a/core/src/integrationTest/java/org/lflang/tests/runtime/CVerifierTest.java +++ b/core/src/integrationTest/java/org/lflang/tests/runtime/CVerifierTest.java @@ -4,6 +4,7 @@ import org.junit.jupiter.api.Assumptions; import org.junit.jupiter.api.Test; import org.lflang.Target; +import org.lflang.target.property.type.VerifyProperty; import org.lflang.tests.TestBase; import org.lflang.tests.TestRegistry; @@ -21,7 +22,7 @@ public void runVerifierTests() { Message.DESC_VERIFIER, TestRegistry.TestCategory.VERIFIER::equals, test -> { - test.getContext().getTargetConfig().verify.override(true); + test.getContext().getTargetConfig().override(new VerifyProperty(), true); return true; }, TestLevel.BUILD, diff --git a/core/src/integrationTest/java/org/lflang/tests/runtime/CppRos2Test.java b/core/src/integrationTest/java/org/lflang/tests/runtime/CppRos2Test.java index a0ad550577..427eb07650 100644 --- a/core/src/integrationTest/java/org/lflang/tests/runtime/CppRos2Test.java +++ b/core/src/integrationTest/java/org/lflang/tests/runtime/CppRos2Test.java @@ -5,6 +5,7 @@ import org.lflang.Target; import org.lflang.lf.Element; import org.lflang.lf.LfFactory; +import org.lflang.target.property.Ros2Property; import org.lflang.tests.TestBase; /** @@ -30,7 +31,7 @@ public void runWithRos2() { Message.DESC_ROS2, it -> true, it -> { - it.getContext().getTargetConfig().ros2.override(true); + it.getContext().getTargetConfig().override(new Ros2Property(), true); return true; }, TestLevel.EXECUTION, diff --git a/core/src/main/java/org/lflang/AbstractTargetProperty.java b/core/src/main/java/org/lflang/AbstractTargetProperty.java index 5a64918e3d..9b854a660e 100644 --- a/core/src/main/java/org/lflang/AbstractTargetProperty.java +++ b/core/src/main/java/org/lflang/AbstractTargetProperty.java @@ -1,8 +1,6 @@ package org.lflang; -import java.util.Arrays; import java.util.List; -import java.util.stream.Collectors; import org.lflang.lf.Element; import org.lflang.lf.KeyValuePair; import org.lflang.lf.LfPackage.Literals; @@ -192,23 +190,4 @@ public T get() { /** Return the name of this target property (in kebab case). */ public abstract String name(); - - public static List getAllTargetProperties(Object object) { - var fields = object.getClass().getDeclaredFields(); - // FIXME: also collect inherited properties. - List properties = - Arrays.stream(fields) - .filter(f -> AbstractTargetProperty.class.isAssignableFrom(f.getType())) - .map( - f -> { - try { - return (AbstractTargetProperty) f.get(object); - } catch (IllegalAccessException e) { - throw new RuntimeException(e); - } - }) - .collect(Collectors.toList()); - - return properties; - } } diff --git a/core/src/main/java/org/lflang/ast/ASTUtils.java b/core/src/main/java/org/lflang/ast/ASTUtils.java index d30dae6189..59189f1d24 100644 --- a/core/src/main/java/org/lflang/ast/ASTUtils.java +++ b/core/src/main/java/org/lflang/ast/ASTUtils.java @@ -102,6 +102,7 @@ import org.lflang.lf.WidthSpec; import org.lflang.lf.WidthTerm; import org.lflang.target.TargetConfig; +import org.lflang.target.property.CompileDefinitionsProperty; import org.lflang.util.StringUtil; /** @@ -614,8 +615,10 @@ public static ReactorInstance createMainReactorInstance( if (breadth == 0) { messageReporter.nowhere().warning("The program has no reactions"); } else { - targetConfig.compileDefinitions.put( - "LF_REACTION_GRAPH_BREADTH", String.valueOf(reactionInstanceGraph.getBreadth())); + // FIXME: not marking the property as set! + targetConfig + .get(new CompileDefinitionsProperty()) + .put("LF_REACTION_GRAPH_BREADTH", String.valueOf(reactionInstanceGraph.getBreadth())); } return main; } 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 eafc0ae68b..955b561071 100644 --- a/core/src/main/java/org/lflang/federated/extensions/CExtension.java +++ b/core/src/main/java/org/lflang/federated/extensions/CExtension.java @@ -56,6 +56,12 @@ import org.lflang.lf.Port; import org.lflang.lf.Reactor; import org.lflang.lf.VarRef; +import org.lflang.target.property.ClockSyncOptionsProperty; +import org.lflang.target.property.CoordinationOptionsProperty; +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.type.CoordinationModeType.CoordinationMode; /** @@ -81,16 +87,16 @@ public void initializeTargetConfig( generateCMakeInclude(federate, fileConfig); - federate.targetConfig.keepalive.override(true); + federate.targetConfig.override(new KeepaliveProperty(), true); // If there are federates, copy the required files for that. // Also, create the RTI C file and the launcher script. // Handle target parameters. // If the program is federated, then ensure that threading is enabled. - federate.targetConfig.threading.override(true); + federate.targetConfig.override(new ThreadingProperty(), true); // Include the fed setup file for this federate in the target property - federate.targetConfig.fedSetupPreamble.override(getPreamblePath(federate)); + federate.targetConfig.override(new FedSetupProperty(), getPreamblePath(federate)); } /** Generate a cmake-include file for {@code federate} if needed. */ @@ -676,7 +682,7 @@ private String generateCodeToInitializeFederate(FederateInstance federate, RtiCo "lf_cond_init(&logical_time_changed, &env->mutex);"))); // Find the STA (A.K.A. the global STP offset) for this federate. - if (federate.targetConfig.coordination.get() == CoordinationMode.DECENTRALIZED) { + if (federate.targetConfig.get(new CoordinationProperty()) == CoordinationMode.DECENTRALIZED) { var reactor = ASTUtils.toDefinition(federate.instantiation.getReactorClass()); var stpParam = reactor.getParameters().stream() @@ -736,12 +742,12 @@ private String generateCodeToInitializeFederate(FederateInstance federate, RtiCo } // If a test clock offset has been specified, insert code to set it here. - if (federate.targetConfig.clockSyncOptions.get().testOffset != null) { + if (federate.targetConfig.get(new ClockSyncOptionsProperty()).testOffset != null) { code.pr( "lf_set_physical_clock_offset((1 + " + federate.id + ") * " - + federate.targetConfig.clockSyncOptions.get().testOffset.toNanoSeconds() + + federate.targetConfig.get(new ClockSyncOptionsProperty()).testOffset.toNanoSeconds() + "LL);"); } @@ -796,8 +802,8 @@ private String generateCodeToInitializeFederate(FederateInstance federate, RtiCo private String generateCodeForPhysicalActions( FederateInstance federate, MessageReporter messageReporter) { CodeBuilder code = new CodeBuilder(); - var coordinationMode = federate.targetConfig.coordination.get(); - var coordinationOptions = federate.targetConfig.coordinationOptions.get(); + var coordinationMode = federate.targetConfig.get(new CoordinationProperty()); + var coordinationOptions = federate.targetConfig.get(new CoordinationOptionsProperty()); if (coordinationMode.equals(CoordinationMode.CENTRALIZED)) { // If this program uses centralized coordination then check // for outputs that depend on physical actions so that null messages can be diff --git a/core/src/main/java/org/lflang/federated/extensions/CExtensionUtils.java b/core/src/main/java/org/lflang/federated/extensions/CExtensionUtils.java index 2903977c1e..7f17673d28 100644 --- a/core/src/main/java/org/lflang/federated/extensions/CExtensionUtils.java +++ b/core/src/main/java/org/lflang/federated/extensions/CExtensionUtils.java @@ -22,7 +22,15 @@ import org.lflang.lf.Expression; import org.lflang.lf.Input; import org.lflang.lf.ParameterReference; +import org.lflang.target.property.AuthProperty; +import org.lflang.target.property.ClockSyncModeProperty; +import org.lflang.target.property.ClockSyncOptionsProperty; import org.lflang.target.property.ClockSyncOptionsProperty.ClockSyncOptions; +import org.lflang.target.property.CmakeIncludeProperty; +import org.lflang.target.property.CompileDefinitionsProperty; +import org.lflang.target.property.CompilerFlagsProperty; +import org.lflang.target.property.CoordinationOptionsProperty; +import org.lflang.target.property.CoordinationProperty; import org.lflang.target.property.type.ClockSyncModeType.ClockSyncMode; public class CExtensionUtils { @@ -172,13 +180,14 @@ public static void handleCompileDefinitions( int numOfFederates, RtiConfig rtiConfig, MessageReporter messageReporter) { - var definitions = federate.targetConfig.compileDefinitions; + var definitions = federate.targetConfig.get(new CompileDefinitionsProperty()); definitions.put("FEDERATED", ""); definitions.put( String.format( - "FEDERATED_%s", federate.targetConfig.coordination.get().toString().toUpperCase()), + "FEDERATED_%s", + federate.targetConfig.get(new CoordinationProperty()).toString().toUpperCase()), ""); - if (federate.targetConfig.auth.get()) { + if (federate.targetConfig.get(new AuthProperty())) { definitions.put("FEDERATED_AUTHENTICATED", ""); } definitions.put("NUMBER_OF_FEDERATES", String.valueOf(numOfFederates)); @@ -191,17 +200,19 @@ public static void handleCompileDefinitions( private static void handleAdvanceMessageInterval(FederateInstance federate) { var advanceMessageInterval = - federate.targetConfig.coordinationOptions.get().advanceMessageInterval; + federate.targetConfig.get(new CoordinationOptionsProperty()).advanceMessageInterval; if (advanceMessageInterval != null) { - federate.targetConfig.compileDefinitions.put( - "ADVANCE_MESSAGE_INTERVAL", String.valueOf(advanceMessageInterval.toNanoSeconds())); + federate + .targetConfig + .get(new CompileDefinitionsProperty()) + .put("ADVANCE_MESSAGE_INTERVAL", String.valueOf(advanceMessageInterval.toNanoSeconds())); } } static boolean clockSyncIsOn(FederateInstance federate, RtiConfig rtiConfig) { - return federate.targetConfig.clockSync.get() != ClockSyncMode.OFF + return federate.targetConfig.get(new ClockSyncModeProperty()) != ClockSyncMode.OFF && (!rtiConfig.getHost().equals(federate.host) - || federate.targetConfig.clockSyncOptions.get().localFederatesOn); + || federate.targetConfig.get(new ClockSyncOptionsProperty()).localFederatesOn); } /** @@ -219,13 +230,16 @@ public static void initializeClockSynchronization( messageReporter .nowhere() .info("Initial clock synchronization is enabled for federate " + federate.id); - if (federate.targetConfig.clockSync.get() == ClockSyncMode.ON) { - if (federate.targetConfig.clockSyncOptions.get().collectStats) { + if (federate.targetConfig.get(new ClockSyncModeProperty()) == ClockSyncMode.ON) { + if (federate.targetConfig.get(new ClockSyncOptionsProperty()).collectStats) { messageReporter .nowhere() .info("Will collect clock sync statistics for federate " + federate.id); // Add libm to the compiler flags - federate.targetConfig.compilerFlags.add("-lm"); + federate + .targetConfig + .get(new CompilerFlagsProperty()) + .add("-lm"); // FIXME: add without marking as set } messageReporter .nowhere() @@ -246,21 +260,18 @@ public static void initializeClockSynchronization( */ public static void addClockSyncCompileDefinitions(FederateInstance federate) { - ClockSyncMode mode = federate.targetConfig.clockSync.get(); - ClockSyncOptions options = federate.targetConfig.clockSyncOptions.get(); - - federate.targetConfig.compileDefinitions.put("_LF_CLOCK_SYNC_INITIAL", ""); - federate.targetConfig.compileDefinitions.put( - "_LF_CLOCK_SYNC_PERIOD_NS", String.valueOf(options.period.toNanoSeconds())); - federate.targetConfig.compileDefinitions.put( - "_LF_CLOCK_SYNC_EXCHANGES_PER_INTERVAL", String.valueOf(options.trials)); - federate.targetConfig.compileDefinitions.put( - "_LF_CLOCK_SYNC_ATTENUATION", String.valueOf(options.attenuation)); + ClockSyncMode mode = federate.targetConfig.get(new ClockSyncModeProperty()); + ClockSyncOptions options = federate.targetConfig.get(new ClockSyncOptionsProperty()); + final var defs = federate.targetConfig.get(new CompileDefinitionsProperty()); + defs.put("_LF_CLOCK_SYNC_INITIAL", ""); + defs.put("_LF_CLOCK_SYNC_PERIOD_NS", String.valueOf(options.period.toNanoSeconds())); + defs.put("_LF_CLOCK_SYNC_EXCHANGES_PER_INTERVAL", String.valueOf(options.trials)); + defs.put("_LF_CLOCK_SYNC_ATTENUATION", String.valueOf(options.attenuation)); if (mode == ClockSyncMode.ON) { - federate.targetConfig.compileDefinitions.put("_LF_CLOCK_SYNC_ON", ""); + defs.put("_LF_CLOCK_SYNC_ON", ""); if (options.collectStats) { - federate.targetConfig.compileDefinitions.put("_LF_CLOCK_SYNC_COLLECT_STATS", ""); + defs.put("_LF_CLOCK_SYNC_COLLECT_STATS", ""); // FIXME: more puts } } } @@ -287,8 +298,10 @@ public static void generateCMakeInclude(FederateInstance federate, FedFileConfig srcWriter.write(cmakeIncludeCode.getCode()); } - federate.targetConfig.cmakeIncludes.add( - fileConfig.getSrcPath().relativize(cmakeIncludePath).toString()); + federate + .targetConfig + .get(new CmakeIncludeProperty()) + .add(fileConfig.getSrcPath().relativize(cmakeIncludePath).toString()); } /** diff --git a/core/src/main/java/org/lflang/federated/extensions/TSExtension.java b/core/src/main/java/org/lflang/federated/extensions/TSExtension.java index e1b79de941..bf3337d913 100644 --- a/core/src/main/java/org/lflang/federated/extensions/TSExtension.java +++ b/core/src/main/java/org/lflang/federated/extensions/TSExtension.java @@ -25,6 +25,8 @@ import org.lflang.lf.Reactor; import org.lflang.lf.VarRef; import org.lflang.lf.Variable; +import org.lflang.target.property.CoordinationOptionsProperty; +import org.lflang.target.property.CoordinationProperty; import org.lflang.target.property.type.CoordinationModeType.CoordinationMode; public class TSExtension implements FedTargetExtension { @@ -199,7 +201,7 @@ public String generatePreamble( } private TimeValue getMinOutputDelay(FederateInstance federate, MessageReporter messageReporter) { - if (federate.targetConfig.coordination.get() == CoordinationMode.CENTRALIZED) { + if (federate.targetConfig.get(new CoordinationProperty()) == CoordinationMode.CENTRALIZED) { // If this program uses centralized coordination then check // for outputs that depend on physical actions so that null messages can be // sent to the RTI. @@ -222,7 +224,8 @@ private TimeValue getMinOutputDelay(FederateInstance federate, MessageReporter m } if (minOutputDelay != TimeValue.MAX_VALUE) { // Unless silenced, issue a warning. - if (federate.targetConfig.coordinationOptions.get().advanceMessageInterval == null) { + if (federate.targetConfig.get(new CoordinationOptionsProperty()).advanceMessageInterval + == null) { String message = String.join( "\n", diff --git a/core/src/main/java/org/lflang/federated/generator/FedFileConfig.java b/core/src/main/java/org/lflang/federated/generator/FedFileConfig.java index 00e49baa7d..f23d0c7a81 100644 --- a/core/src/main/java/org/lflang/federated/generator/FedFileConfig.java +++ b/core/src/main/java/org/lflang/federated/generator/FedFileConfig.java @@ -32,6 +32,9 @@ import java.util.List; import org.eclipse.emf.ecore.resource.Resource; import org.lflang.FileConfig; +import org.lflang.target.property.CmakeIncludeProperty; +import org.lflang.target.property.FilesProperty; +import org.lflang.target.property.ProtobufsProperty; import org.lflang.util.FileUtil; /** @@ -100,9 +103,9 @@ public void doClean() throws IOException { * the generated .lf file for the federate. */ public void relativizePaths(FedTargetConfig targetConfig) { - relativizePathList(targetConfig.protoFiles.get()); - relativizePathList(targetConfig.files.get()); - relativizePathList(targetConfig.cmakeIncludes.get()); + relativizePathList(targetConfig.get(new ProtobufsProperty())); + relativizePathList(targetConfig.get(new FilesProperty())); + relativizePathList(targetConfig.get(new CmakeIncludeProperty())); } /** 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 168bb0a8fd..afa7e30627 100644 --- a/core/src/main/java/org/lflang/federated/generator/FedGenerator.java +++ b/core/src/main/java/org/lflang/federated/generator/FedGenerator.java @@ -58,6 +58,10 @@ import org.lflang.lf.TargetDecl; import org.lflang.lf.VarRef; import org.lflang.target.TargetConfig; +import org.lflang.target.property.CoordinationProperty; +import org.lflang.target.property.DockerProperty; +import org.lflang.target.property.KeepaliveProperty; +import org.lflang.target.property.NoCompileProperty; import org.lflang.target.property.type.CoordinationModeType.CoordinationMode; import org.lflang.util.Averager; @@ -121,7 +125,7 @@ public boolean doGenerate(Resource resource, LFGeneratorContext context) throws // In a federated execution, we need keepalive to be true, // otherwise a federate could exit simply because it hasn't received // any messages. - targetConfig.keepalive.override(true); + targetConfig.override(new KeepaliveProperty(), true); // Process command-line arguments processCLIArguments(context); @@ -153,7 +157,7 @@ public boolean doGenerate(Resource resource, LFGeneratorContext context) throws } // Do not invoke target code generators if --no-compile flag is used. - if (context.getTargetConfig().noCompile.get()) { + if (context.getTargetConfig().get(new NoCompileProperty())) { context.finish(Status.GENERATED, lf2lfCodeMapMap); return false; } @@ -193,14 +197,13 @@ private void generateLaunchScript() { * @param subContexts The subcontexts in which the federates have been compiled. */ private void createDockerFiles(LFGeneratorContext context, List subContexts) { - if (!context.getTargetConfig().dockerOptions.get().enabled) return; + if (!context.getTargetConfig().get(new DockerProperty()).enabled) return; final List services = new ArrayList<>(); // 1. create a Dockerfile for each federate for (SubContext subContext : subContexts) { // Inherit Docker options from main context subContext .getTargetConfig() - .dockerOptions - .override(context.getTargetConfig().dockerOptions.get()); + .override(new DockerProperty(), context.getTargetConfig().get(new DockerProperty())); var dockerGenerator = dockerGeneratorFactory(subContext); var dockerData = dockerGenerator.generateDockerData(); try { @@ -298,11 +301,11 @@ private Map compileFederates( new Properties(), GeneratorUtils.findTargetDecl(subFileConfig.resource), subContextMessageReporter); - if (targetConfig.dockerOptions.get().enabled + if (targetConfig.get(new DockerProperty()).enabled && targetConfig.target.buildsUsingDocker()) { - subConfig.noCompile.override(true); + subConfig.override(new NoCompileProperty(), true); } - subConfig.dockerOptions.get().enabled = false; + subConfig.get(new DockerProperty()).enabled = false; SubContext subContext = new SubContext(context, IntegratedBuilder.VALIDATED_PERCENT_PROGRESS, 100) { @@ -420,7 +423,7 @@ private void analyzeFederates(Reactor federation, LFGeneratorContext context) { rtiConfig.setHost(federation.getHost().getAddr()); } // If the federation is dockerized, use "rti" as the hostname. - if (rtiConfig.getHost().equals("localhost") && targetConfig.dockerOptions.get().enabled) { + if (rtiConfig.getHost().equals("localhost") && targetConfig.get(new DockerProperty()).enabled) { rtiConfig.setHost("rti"); } @@ -676,7 +679,7 @@ private void replaceOneToManyConnection( */ private void replaceFedConnection(FedConnectionInstance connection, Resource resource) { if (!connection.getDefinition().isPhysical() - && targetConfig.coordination.get() != CoordinationMode.DECENTRALIZED) { + && targetConfig.get(new CoordinationProperty()) != CoordinationMode.DECENTRALIZED) { // Map the delays on connections between federates. Set dependsOnDelays = connection.dstFederate.dependsOn.computeIfAbsent( @@ -701,6 +704,6 @@ private void replaceFedConnection(FedConnectionInstance connection, Resource res } FedASTUtils.makeCommunication( - connection, resource, targetConfig.coordination.get(), messageReporter); + connection, resource, targetConfig.get(new CoordinationProperty()), messageReporter); } } diff --git a/core/src/main/java/org/lflang/federated/generator/FedTargetConfig.java b/core/src/main/java/org/lflang/federated/generator/FedTargetConfig.java index 705a2dbcec..008ee3f85c 100644 --- a/core/src/main/java/org/lflang/federated/generator/FedTargetConfig.java +++ b/core/src/main/java/org/lflang/federated/generator/FedTargetConfig.java @@ -9,6 +9,8 @@ import org.lflang.generator.LFGeneratorContext; import org.lflang.target.TargetConfig; import org.lflang.target.TargetProperty; +import org.lflang.target.property.ClockSyncModeProperty; +import org.lflang.target.property.ClockSyncOptionsProperty; import org.lflang.util.FileUtil; /** @@ -75,7 +77,7 @@ private Path getRelativePath(Resource source, Resource target) { /** Method for the removal of things that should not appear in the target config of a federate. */ private void clearPropertiesToIgnore() { - this.clockSync.reset(); - this.clockSyncOptions.reset(); + this.reset(new ClockSyncModeProperty()); + this.reset(new ClockSyncOptionsProperty()); } } diff --git a/core/src/main/java/org/lflang/federated/launcher/FedLauncherGenerator.java b/core/src/main/java/org/lflang/federated/launcher/FedLauncherGenerator.java index 99e942a45c..8a8efbf0aa 100644 --- a/core/src/main/java/org/lflang/federated/launcher/FedLauncherGenerator.java +++ b/core/src/main/java/org/lflang/federated/launcher/FedLauncherGenerator.java @@ -37,6 +37,10 @@ import org.lflang.federated.generator.FedFileConfig; import org.lflang.federated.generator.FederateInstance; import org.lflang.target.TargetConfig; +import org.lflang.target.property.AuthProperty; +import org.lflang.target.property.ClockSyncModeProperty; +import org.lflang.target.property.ClockSyncOptionsProperty; +import org.lflang.target.property.TracingProperty; import org.lflang.target.property.type.ClockSyncModeType.ClockSyncMode; /** @@ -334,22 +338,30 @@ private String getRtiCommand(List federates, boolean isRemote) } else { commands.add("RTI -i ${FEDERATION_ID} \\"); } - if (targetConfig.auth.get()) { + if (targetConfig.get(new AuthProperty())) { commands.add(" -a \\"); } - if (targetConfig.tracing.get().isEnabled()) { + if (targetConfig.get(new TracingProperty()).isEnabled()) { commands.add(" -t \\"); } commands.addAll( List.of( " -n " + federates.size() + " \\", - " -c " + targetConfig.clockSync.get().toString() + " \\")); - if (targetConfig.clockSync.get().equals(ClockSyncMode.ON)) { - commands.add("period " + targetConfig.clockSyncOptions.get().period.toNanoSeconds() + " \\"); + " -c " + + targetConfig.get(new ClockSyncModeProperty()).toString() + + " \\")); + if (targetConfig.get(new ClockSyncModeProperty()).equals(ClockSyncMode.ON)) { + commands.add( + "period " + + targetConfig.get(new ClockSyncOptionsProperty()).period.toNanoSeconds() + + " \\"); } - if (targetConfig.clockSync.get().equals(ClockSyncMode.ON) - || targetConfig.clockSync.get().equals(ClockSyncMode.INIT)) { - commands.add("exchanges-per-interval " + targetConfig.clockSyncOptions.get().trials + " \\"); + if (targetConfig.get(new ClockSyncModeProperty()).equals(ClockSyncMode.ON) + || targetConfig.get(new ClockSyncModeProperty()).equals(ClockSyncMode.INIT)) { + commands.add( + "exchanges-per-interval " + + targetConfig.get(new ClockSyncOptionsProperty()).trials + + " \\"); } commands.add("&"); return String.join("\n", commands); diff --git a/core/src/main/java/org/lflang/federated/serialization/FedROS2CPPSerialization.java b/core/src/main/java/org/lflang/federated/serialization/FedROS2CPPSerialization.java index 48e9e2ec92..2dc54a235a 100644 --- a/core/src/main/java/org/lflang/federated/serialization/FedROS2CPPSerialization.java +++ b/core/src/main/java/org/lflang/federated/serialization/FedROS2CPPSerialization.java @@ -29,6 +29,7 @@ import org.lflang.Target; import org.lflang.generator.GeneratorBase; +import org.lflang.target.property.CompilerProperty; /** * Enables support for ROS 2 serialization in C/C++ code. @@ -52,7 +53,7 @@ public boolean isCompatible(GeneratorBase generator) { .nowhere() .error("ROS serialization is currently only supported for the C target."); return false; - } else if (!generator.getTargetConfig().compiler.get().equalsIgnoreCase("g++")) { + } else if (!generator.getTargetConfig().get(new CompilerProperty()).equalsIgnoreCase("g++")) { generator .messageReporter .nowhere() diff --git a/core/src/main/java/org/lflang/generator/GeneratorBase.java b/core/src/main/java/org/lflang/generator/GeneratorBase.java index 0ba80a494c..64e6e6aec6 100644 --- a/core/src/main/java/org/lflang/generator/GeneratorBase.java +++ b/core/src/main/java/org/lflang/generator/GeneratorBase.java @@ -61,6 +61,9 @@ import org.lflang.lf.Reaction; import org.lflang.lf.Reactor; import org.lflang.target.TargetConfig; +import org.lflang.target.property.FilesProperty; +import org.lflang.target.property.ThreadingProperty; +import org.lflang.target.property.type.VerifyProperty; import org.lflang.util.FileUtil; import org.lflang.validation.AbstractLFValidator; @@ -264,7 +267,7 @@ public void doGenerate(Resource resource, LFGeneratorContext context) { // Check for the existence and support of watchdogs hasWatchdogs = IterableExtensions.exists(reactors, it -> !it.getWatchdogs().isEmpty()); - checkWatchdogSupport(targetConfig.threading.get() && getTarget() == Target.C); + checkWatchdogSupport(targetConfig.get(new ThreadingProperty()) && getTarget() == Target.C); additionalPostProcessingForModes(); } @@ -331,7 +334,7 @@ protected void setReactorsAndInstantiationGraph(LFGeneratorContext.Mode mode) { protected void copyUserFiles(TargetConfig targetConfig, FileConfig fileConfig) { var dst = this.context.getFileConfig().getSrcGenPath(); FileUtil.copyFilesOrDirectories( - targetConfig.files.get(), dst, fileConfig, messageReporter, false); + targetConfig.get(new FilesProperty()), dst, fileConfig, messageReporter, false); } /** @@ -648,7 +651,7 @@ private void runVerifierIfPropertiesDetected(Resource resource, LFGeneratorConte uclidGenerator.doGenerate(resource, lfContext); // Check the generated uclid files. - if (uclidGenerator.targetConfig.verify.get()) { + if (uclidGenerator.targetConfig.get(new VerifyProperty())) { // Check if Uclid5 and Z3 are installed. if (commandFactory.createCommand("uclid", List.of()) == null diff --git a/core/src/main/java/org/lflang/generator/GeneratorUtils.java b/core/src/main/java/org/lflang/generator/GeneratorUtils.java index e2a6e89928..4ee4f070b2 100644 --- a/core/src/main/java/org/lflang/generator/GeneratorUtils.java +++ b/core/src/main/java/org/lflang/generator/GeneratorUtils.java @@ -24,6 +24,7 @@ import org.lflang.lf.TargetDecl; import org.lflang.target.TargetConfig; import org.lflang.target.TargetProperty; +import org.lflang.target.property.KeepaliveProperty; /** * A helper class with functions that may be useful for code generators. This is created to ease our @@ -56,14 +57,14 @@ public static void accommodatePhysicalActionsIfPresent( for (Resource resource : resources) { for (Action action : findAll(resource, Action.class)) { if (action.getOrigin() == ActionOrigin.PHYSICAL - && !targetConfig.keepalive.isSet() - && !targetConfig.keepalive.get()) { + && !targetConfig.isSet(new KeepaliveProperty()) + && !targetConfig.get(new KeepaliveProperty())) { // Keepalive was explicitly set to false; set it to true. - targetConfig.keepalive.override(true); + targetConfig.override(new KeepaliveProperty(), true); String message = String.format( "Setting %s to true because of the physical action %s.", - targetConfig.keepalive.name(), action.getName()); + new KeepaliveProperty().name(), action.getName()); messageReporter.at(action).warning(message); return; } 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 e760e7ff7a..1eff36adb5 100644 --- a/core/src/main/java/org/lflang/generator/c/CCmakeGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CCmakeGenerator.java @@ -35,6 +35,15 @@ import org.lflang.MessageReporter; import org.lflang.generator.CodeBuilder; import org.lflang.target.TargetConfig; +import org.lflang.target.property.AuthProperty; +import org.lflang.target.property.BuildCommandsProperty; +import org.lflang.target.property.CmakeIncludeProperty; +import org.lflang.target.property.CompilerFlagsProperty; +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.WorkersProperty; import org.lflang.target.property.type.PlatformType.Platform; import org.lflang.util.FileUtil; @@ -118,8 +127,9 @@ CodeBuilder generateCMakeCode( // rp2040 : // arduino String[] boardProperties = {}; - if (targetConfig.platformOptions.get().board != null) { - boardProperties = targetConfig.platformOptions.get().board.trim().split(":"); + var platformOptions = targetConfig.get(new PlatformProperty()); + if (platformOptions.board != null) { + boardProperties = platformOptions.board.trim().split(":"); // Ignore whitespace for (int i = 0; i < boardProperties.length; i++) { boardProperties[i] = boardProperties[i].trim(); @@ -132,14 +142,14 @@ CodeBuilder generateCMakeCode( cMakeCode.pr("cmake_minimum_required(VERSION " + MIN_CMAKE_VERSION + ")"); // Setup the project header for different platforms - switch (targetConfig.platformOptions.get().platform) { + switch (platformOptions.platform) { case ZEPHYR: cMakeCode.pr("# Set default configuration file. To add custom configurations,"); cMakeCode.pr("# pass -- -DOVERLAY_CONFIG=my_config.prj to either cmake or west"); cMakeCode.pr("set(CONF_FILE prj_lf.conf)"); - if (targetConfig.platformOptions.get().board != null) { + if (platformOptions.board != null) { cMakeCode.pr("# Selecting board specified in target property"); - cMakeCode.pr("set(BOARD " + targetConfig.platformOptions.get().board + ")"); + cMakeCode.pr("set(BOARD " + platformOptions.board + ")"); } else { cMakeCode.pr("# Selecting default board"); cMakeCode.pr("set(BOARD qemu_cortex_m3)"); @@ -175,7 +185,7 @@ CodeBuilder generateCMakeCode( cMakeCode.pr("project(" + executableName + " LANGUAGES C CXX ASM)"); cMakeCode.newLine(); // board type for rp2040 based boards - if (targetConfig.platformOptions.get().board != null) { + if (platformOptions.board != null) { if (boardProperties.length < 1 || boardProperties[0].equals("")) { cMakeCode.pr("set(PICO_BOARD pico)"); } else { @@ -218,7 +228,7 @@ CodeBuilder generateCMakeCode( cMakeCode.pr("set(CMAKE_CXX_STANDARD 17)"); cMakeCode.pr("set(CMAKE_CXX_STANDARD_REQUIRED ON)"); cMakeCode.newLine(); - if (!targetConfig.cmakeIncludes.get().isEmpty()) { + if (!targetConfig.get(new CmakeIncludeProperty()).isEmpty()) { // The user might be using the non-keyword form of // target_link_libraries. Ideally we would detect whether they are // doing that, but it is easier to just always have a deprecation @@ -231,7 +241,7 @@ CodeBuilder generateCMakeCode( } // Set the build type - cMakeCode.pr("set(DEFAULT_BUILD_TYPE " + targetConfig.buildType + ")\n"); + cMakeCode.pr("set(DEFAULT_BUILD_TYPE " + targetConfig.get(new BuildCommandsProperty()) + ")\n"); cMakeCode.pr("if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)\n"); cMakeCode.pr( " set(CMAKE_BUILD_TYPE ${DEFAULT_BUILD_TYPE} CACHE STRING \"Choose the type of build.\"" @@ -249,16 +259,13 @@ CodeBuilder generateCMakeCode( cMakeCode.newLine(); } - if (targetConfig.platformOptions.get().platform != Platform.AUTO) { - cMakeCode.pr( - "set(CMAKE_SYSTEM_NAME " - + targetConfig.platformOptions.get().platform.getcMakeName() - + ")"); + if (platformOptions.platform != Platform.AUTO) { + cMakeCode.pr("set(CMAKE_SYSTEM_NAME " + platformOptions.platform.getcMakeName() + ")"); } cMakeCode.newLine(); // Setup main target for different platforms - switch (targetConfig.platformOptions.get().platform) { + switch (platformOptions.platform) { case ZEPHYR: cMakeCode.pr( setUpMainTargetZephyr( @@ -298,12 +305,12 @@ CodeBuilder generateCMakeCode( cMakeCode.pr("target_include_directories(${LF_MAIN_TARGET} PUBLIC include/core/utils)"); // post target definition board configurations - switch (targetConfig.platformOptions.get().platform) { + switch (platformOptions.platform) { case RP2040: // set stdio output boolean usb = true; boolean uart = true; - if (targetConfig.platformOptions.get().board != null && boardProperties.length > 1) { + if (platformOptions.board != null && boardProperties.length > 1) { uart = !boardProperties[1].equals("usb"); usb = !boardProperties[1].equals("uart"); } @@ -312,12 +319,12 @@ CodeBuilder generateCMakeCode( break; } - if (targetConfig.auth.get()) { + if (targetConfig.get(new AuthProperty())) { // If security is requested, add the auth option. var osName = System.getProperty("os.name").toLowerCase(); // if platform target was set, use given platform instead - if (targetConfig.platformOptions.get().platform != Platform.AUTO) { - osName = targetConfig.platformOptions.get().platform.toString(); + if (platformOptions.platform != Platform.AUTO) { + osName = platformOptions.platform.toString(); } if (osName.contains("mac")) { cMakeCode.pr("set(OPENSSL_ROOT_DIR /usr/local/opt/openssl)"); @@ -328,8 +335,7 @@ CodeBuilder generateCMakeCode( cMakeCode.newLine(); } - if (targetConfig.threading.get() - && targetConfig.platformOptions.get().platform != Platform.ZEPHYR) { + if (targetConfig.get(new ThreadingProperty()) && 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)"); @@ -339,11 +345,11 @@ CodeBuilder generateCMakeCode( // Add additional flags so runtime can distinguish between multi-threaded and single-threaded // mode - if (targetConfig.threading.get()) { + if (targetConfig.get(new ThreadingProperty())) { cMakeCode.pr("# Set the number of workers to enable threading/tracing"); cMakeCode.pr( "target_compile_definitions(${LF_MAIN_TARGET} PUBLIC NUMBER_OF_WORKERS=" - + targetConfig.workers + + targetConfig.get(new WorkersProperty()) + ")"); cMakeCode.newLine(); cMakeCode.pr("# Set flag to indicate a multi-threaded runtime"); @@ -356,18 +362,18 @@ CodeBuilder generateCMakeCode( if (CppMode) cMakeCode.pr("enable_language(CXX)"); - if (!targetConfig.compiler.isSet()) { + if (!targetConfig.isSet(new CompilerProperty())) { if (CppMode) { // Set the CXX compiler to what the user has requested. - cMakeCode.pr("set(CMAKE_CXX_COMPILER " + targetConfig.compiler + ")"); + cMakeCode.pr("set(CMAKE_CXX_COMPILER " + targetConfig.get(new CompilerProperty()) + ")"); } else { - cMakeCode.pr("set(CMAKE_C_COMPILER " + targetConfig.compiler + ")"); + cMakeCode.pr("set(CMAKE_C_COMPILER " + targetConfig.get(new CompilerProperty()) + ")"); } cMakeCode.newLine(); } // link protobuf - if (!targetConfig.protoFiles.get().isEmpty()) { + if (!targetConfig.get(new ProtobufsProperty()).isEmpty()) { cMakeCode.pr("include(FindPackageHandleStandardArgs)"); cMakeCode.pr("FIND_PATH( PROTOBUF_INCLUDE_DIR protobuf-c/protobuf-c.h)"); cMakeCode.pr( @@ -386,7 +392,7 @@ CodeBuilder generateCMakeCode( // Set the compiler flags // We can detect a few common libraries and use the proper target_link_libraries to find them - for (String compilerFlag : targetConfig.compilerFlags.get()) { + for (String compilerFlag : targetConfig.get(new CompilerFlagsProperty())) { messageReporter .nowhere() .warning( @@ -402,7 +408,7 @@ CodeBuilder generateCMakeCode( cMakeCode.newLine(); // Add the include file - for (String includeFile : targetConfig.cmakeIncludes.get()) { + for (String includeFile : targetConfig.get(new CmakeIncludeProperty())) { cMakeCode.pr("include(\"" + Path.of(includeFile).getFileName() + "\")"); } cMakeCode.newLine(); diff --git a/core/src/main/java/org/lflang/generator/c/CCompiler.java b/core/src/main/java/org/lflang/generator/c/CCompiler.java index 6466f3f26e..8336a83ebe 100644 --- a/core/src/main/java/org/lflang/generator/c/CCompiler.java +++ b/core/src/main/java/org/lflang/generator/c/CCompiler.java @@ -40,6 +40,11 @@ import org.lflang.generator.GeneratorUtils; import org.lflang.generator.LFGeneratorContext; import org.lflang.target.TargetConfig; +import org.lflang.target.property.BuildTypeProperty; +import org.lflang.target.property.CompileDefinitionsProperty; +import org.lflang.target.property.CompilerFlagsProperty; +import org.lflang.target.property.CompilerProperty; +import org.lflang.target.property.PlatformProperty; import org.lflang.target.property.type.BuildTypeType.BuildType; import org.lflang.target.property.type.PlatformType.Platform; import org.lflang.util.FileUtil; @@ -119,13 +124,13 @@ public boolean runCCompiler(GeneratorBase generator, LFGeneratorContext context) } // Use the user-specified compiler if any - if (targetConfig.compiler != null) { + if (targetConfig.get(new CompilerProperty()) != null) { if (cppMode) { // Set the CXX environment variable to change the C++ compiler. - compile.replaceEnvironmentVariable("CXX", targetConfig.compiler.get()); + compile.replaceEnvironmentVariable("CXX", targetConfig.get(new CompilerProperty())); } else { // Set the CC environment variable to change the C compiler. - compile.replaceEnvironmentVariable("CC", targetConfig.compiler.get()); + compile.replaceEnvironmentVariable("CC", targetConfig.get(new CompilerProperty())); } } @@ -136,7 +141,10 @@ public boolean runCCompiler(GeneratorBase generator, LFGeneratorContext context) && !outputContainsKnownCMakeErrors(compile.getErrors())) { messageReporter .nowhere() - .error(targetConfig.compiler + " failed with error code " + cMakeReturnCode); + .error( + targetConfig.get(new CompilerProperty()) + + " failed with error code " + + cMakeReturnCode); } // For warnings (vs. errors), the return code is 0. @@ -159,7 +167,10 @@ public boolean runCCompiler(GeneratorBase generator, LFGeneratorContext context) && !outputContainsKnownCMakeErrors(build.getErrors())) { messageReporter .nowhere() - .error(targetConfig.compiler + " failed with error code " + makeReturnCode); + .error( + targetConfig.get(new CompilerProperty()) + + " failed with error code " + + makeReturnCode); } // For warnings (vs. errors), the return code is 0. @@ -179,8 +190,8 @@ public boolean runCCompiler(GeneratorBase generator, LFGeneratorContext context) + " finished with no errors."); } - if (targetConfig.platformOptions.get().platform == Platform.ZEPHYR - && targetConfig.platformOptions.get().flash) { + if (targetConfig.get(new PlatformProperty()).platform == Platform.ZEPHYR + && targetConfig.get(new PlatformProperty()).flash) { messageReporter.nowhere().info("Invoking flash command for Zephyr"); LFCommand flash = buildWestFlashCommand(); int flashRet = flash.run(); @@ -217,7 +228,7 @@ public LFCommand compileCmakeCommand() { } static Stream cmakeCompileDefinitions(TargetConfig targetConfig) { - return targetConfig.compileDefinitions.get().entrySet().stream() + return targetConfig.get(new CompileDefinitionsProperty()).entrySet().stream() .map(entry -> "-D" + entry.getKey() + "=" + entry.getValue()); } @@ -237,8 +248,8 @@ private static List cmakeOptions(TargetConfig targetConfig, FileConfig f arguments.addAll( List.of( "-DCMAKE_BUILD_TYPE=" - + ((targetConfig.buildType != null) - ? targetConfig.buildType.toString() + + ((targetConfig.get(new BuildTypeProperty()) != null) + ? targetConfig.get(new BuildTypeProperty()).toString() : "Release"), "-DCMAKE_INSTALL_PREFIX=" + FileUtil.toUnixString(fileConfig.getOutPath()), "-DCMAKE_INSTALL_BINDIR=" @@ -295,7 +306,7 @@ public LFCommand buildCmakeCommand() { "--parallel", cores, "--config", - buildTypeToCmakeConfig(targetConfig.buildType.get())), + buildTypeToCmakeConfig(targetConfig.get(new BuildTypeProperty()))), buildPath); if (command == null) { messageReporter @@ -316,7 +327,7 @@ public LFCommand buildCmakeCommand() { public LFCommand buildWestFlashCommand() { // Set the build directory to be "build" Path buildPath = fileConfig.getSrcGenPath().resolve("build"); - String board = targetConfig.platformOptions.get().board; + String board = targetConfig.get(new PlatformProperty()).board; LFCommand cmd; if (board == null || board.startsWith("qemu") || board.equals("native_posix")) { cmd = commandFactory.createCommand("west", List.of("build", "-t", "run"), buildPath); @@ -349,7 +360,7 @@ private boolean outputContainsKnownCMakeErrors(String CMakeOutput) { // Check if the error thrown is due to the wrong compiler if (CMakeOutput.contains("The CMAKE_C_COMPILER is set to a C++ compiler")) { // If so, print an appropriate error message - if (targetConfig.compiler != null) { + if (targetConfig.get(new CompilerProperty()) != null) { messageReporter .nowhere() .error( @@ -405,12 +416,11 @@ public LFCommand compileCCommand(String fileToCompile, boolean noBinary) { // Add compile definitions targetConfig - .compileDefinitions - .get() + .get(new CompileDefinitionsProperty()) .forEach((key, value) -> compileArgs.add("-D" + key + "=" + value)); // Finally, add the compiler flags in target parameters (if any) - compileArgs.addAll(targetConfig.compilerFlags.get()); + compileArgs.addAll(targetConfig.get(new CompilerFlagsProperty())); // Only set the output file name if it hasn't already been set // using a target property or Args line flag. @@ -429,7 +439,7 @@ public LFCommand compileCCommand(String fileToCompile, boolean noBinary) { LFCommand command = commandFactory.createCommand( - targetConfig.compiler.get(), compileArgs, fileConfig.getOutPath()); + targetConfig.get(new CompilerProperty()), compileArgs, fileConfig.getOutPath()); if (command == null) { messageReporter .nowhere() @@ -448,7 +458,7 @@ public LFCommand compileCCommand(String fileToCompile, boolean noBinary) { * .cpp files instead of .c files and uses a C++ compiler to compiler the code. */ static String getTargetFileName(String fileName, boolean cppMode, TargetConfig targetConfig) { - if (targetConfig.platformOptions.get().platform == Platform.ARDUINO) { + if (targetConfig.get(new PlatformProperty()).platform == Platform.ARDUINO) { return fileName + ".ino"; } if (cppMode) { diff --git a/core/src/main/java/org/lflang/generator/c/CDockerGenerator.java b/core/src/main/java/org/lflang/generator/c/CDockerGenerator.java index 0474b06ea9..fb040d7dc0 100644 --- a/core/src/main/java/org/lflang/generator/c/CDockerGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CDockerGenerator.java @@ -5,6 +5,8 @@ import org.lflang.Target; import org.lflang.generator.DockerGenerator; import org.lflang.generator.LFGeneratorContext; +import org.lflang.target.property.BuildCommandsProperty; +import org.lflang.target.property.DockerProperty; import org.lflang.util.StringUtil; /** @@ -30,13 +32,14 @@ protected String generateDockerFileContent() { var lfModuleName = context.getFileConfig().name; var config = context.getTargetConfig(); var compileCommand = - IterableExtensions.isNullOrEmpty(config.buildCommands.get()) + IterableExtensions.isNullOrEmpty(config.get(new BuildCommandsProperty())) ? generateDefaultCompileCommand() - : StringUtil.joinObjects(config.buildCommands.get(), " "); + : StringUtil.joinObjects(config.get(new BuildCommandsProperty()), " "); var compiler = config.target == Target.CCPP ? "g++" : "gcc"; var baseImage = DEFAULT_BASE_IMAGE; - if (config.dockerOptions.get().enabled && config.dockerOptions.get().from != null) { - baseImage = config.dockerOptions.get().from; + var dockerConf = config.get(new DockerProperty()); + if (dockerConf.enabled && dockerConf.from != null) { + baseImage = dockerConf.from; } return String.join( "\n", diff --git a/core/src/main/java/org/lflang/generator/c/CEnvironmentFunctionGenerator.java b/core/src/main/java/org/lflang/generator/c/CEnvironmentFunctionGenerator.java index 39569d0725..b09d29c330 100644 --- a/core/src/main/java/org/lflang/generator/c/CEnvironmentFunctionGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CEnvironmentFunctionGenerator.java @@ -5,6 +5,7 @@ import org.lflang.generator.CodeBuilder; import org.lflang.generator.ReactorInstance; import org.lflang.target.TargetConfig; +import org.lflang.target.property.TracingProperty; /** * This class is in charge of code generating functions and global variables related to the @@ -89,7 +90,7 @@ private String generateCreateEnvironments() { // Figure out the name of the trace file String traceFileName = "NULL"; - var tracing = targetConfig.tracing.get(); + var tracing = targetConfig.get(new TracingProperty()); if (tracing.isEnabled()) { if (tracing.traceFileName != null) { if (enclave.isMainOrFederated()) { 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 7a10616c7b..46e584656f 100644 --- a/core/src/main/java/org/lflang/generator/c/CGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CGenerator.java @@ -86,7 +86,20 @@ import org.lflang.lf.StateVar; import org.lflang.lf.Variable; import org.lflang.target.TargetConfig; +import org.lflang.target.property.BuildCommandsProperty; +import org.lflang.target.property.CmakeIncludeProperty; +import org.lflang.target.property.CompileDefinitionsProperty; +import org.lflang.target.property.DockerProperty; +import org.lflang.target.property.FedSetupProperty; +import org.lflang.target.property.LoggingProperty; +import org.lflang.target.property.NoCompileProperty; +import org.lflang.target.property.PlatformProperty; 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.TracingProperty; +import org.lflang.target.property.WorkersProperty; import org.lflang.target.property.type.PlatformType.Platform; import org.lflang.target.property.type.SchedulerType.Scheduler; import org.lflang.util.ArduinoUtil; @@ -346,8 +359,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. - if (!targetConfig.threading.get() && !targetConfig.threading.isSet()) { - targetConfig.threading.override(true); + var threading = new ThreadingProperty(); + if (!targetConfig.get(threading) && !targetConfig.isSet(threading)) { + targetConfig.override(threading, true); String message = "Using the threaded C runtime to allow for asynchronous handling of physical action" + " " @@ -419,7 +433,7 @@ public void doGenerate(Resource resource, LFGeneratorContext context) { } // Create docker file. - if (targetConfig.dockerOptions.get().enabled && mainDef != null) { + if (targetConfig.get(new DockerProperty()).enabled && mainDef != null) { try { var dockerData = getDockerGenerator(context).generateDockerData(); dockerData.writeDockerFile(); @@ -430,7 +444,7 @@ public void doGenerate(Resource resource, LFGeneratorContext context) { } // If cmake is requested, generate the CMakeLists.txt - if (targetConfig.platformOptions.get().platform != Platform.ARDUINO) { + if (targetConfig.get(new PlatformProperty()).platform != Platform.ARDUINO) { var cmakeFile = fileConfig.getSrcGenPath() + File.separator + "CMakeLists.txt"; var sources = allTypeParameterizedReactors() @@ -457,14 +471,14 @@ public void doGenerate(Resource resource, LFGeneratorContext context) { try { Path include = fileConfig.getSrcGenPath().resolve("include/"); Path src = fileConfig.getSrcGenPath().resolve("src/"); - FileUtil.arduinoDeleteHelper(src, targetConfig.threading.get()); + FileUtil.arduinoDeleteHelper(src, targetConfig.get(new ThreadingProperty())); FileUtil.relativeIncludeHelper(src, include, messageReporter); FileUtil.relativeIncludeHelper(include, include, messageReporter); } catch (IOException e) { //noinspection ThrowableNotThrown,ResultOfMethodCallIgnored Exceptions.sneakyThrow(e); } - if (!targetConfig.noCompile.get()) { + if (!targetConfig.get(new NoCompileProperty())) { ArduinoUtil arduinoUtil = new ArduinoUtil(context, commandFactory, messageReporter); arduinoUtil.buildArduino(fileConfig, targetConfig); context.finish(GeneratorResult.Status.COMPILED, null); @@ -499,9 +513,10 @@ public void doGenerate(Resource resource, LFGeneratorContext context) { // self-contained. In this way, third-party build tools like PlatformIO, west, arduino-cli can // take over and do the rest of compilation. try { + var defs = targetConfig.get(new CompileDefinitionsProperty()); String compileDefs = - targetConfig.compileDefinitions.get().keySet().stream() - .map(key -> key + "=" + targetConfig.compileDefinitions.get().get(key)) + defs.keySet().stream() + .map(key -> key + "=" + defs.get(key)) .collect(Collectors.joining("\n")) + "\n"; FileUtil.writeToFile( @@ -514,10 +529,10 @@ public void doGenerate(Resource resource, LFGeneratorContext context) { // Create a .vscode/settings.json file in the target directory so that VSCode can // immediately compile the generated code. try { + var defs = targetConfig.get(new CompileDefinitionsProperty()); String compileDefs = - targetConfig.compileDefinitions.get().keySet().stream() - .map( - key -> "\"-D" + key + "=" + targetConfig.compileDefinitions.get().get(key) + "\"") + defs.keySet().stream() + .map(key -> "\"-D" + key + "=" + defs.get(key) + "\"") .collect(Collectors.joining(",\n")); String settings = "{\n" + "\"cmake.configureArgs\": [\n" + compileDefs + "\n]\n}\n"; Path vscodePath = fileConfig.getSrcGenPath().resolve(".vscode"); @@ -536,9 +551,9 @@ public void doGenerate(Resource resource, LFGeneratorContext context) { // If this code generator is directly compiling the code, compile it now so that we // clean it up after, removing the #line directives after errors have been reported. - if (!targetConfig.noCompile.get() - && !targetConfig.dockerOptions.get().enabled - && IterableExtensions.isNullOrEmpty(targetConfig.buildCommands.get()) + if (!targetConfig.get(new NoCompileProperty()) + && !targetConfig.get(new DockerProperty()).enabled + && IterableExtensions.isNullOrEmpty(targetConfig.get(new BuildCommandsProperty())) // This code is unreachable in LSP_FAST mode, so that check is omitted. && context.getMode() != LFGeneratorContext.Mode.LSP_MEDIUM) { // FIXME: Currently, a lack of main is treated as a request to not produce @@ -580,8 +595,8 @@ public void doGenerate(Resource resource, LFGeneratorContext context) { // If a build directive has been given, invoke it now. // Note that the code does not get cleaned in this case. - if (!targetConfig.noCompile.get()) { - if (!IterableExtensions.isNullOrEmpty(targetConfig.buildCommands.get())) { + if (!targetConfig.get(new NoCompileProperty())) { + if (!IterableExtensions.isNullOrEmpty(targetConfig.get(new BuildCommandsProperty()))) { CUtil.runBuildCommand( fileConfig, targetConfig, @@ -634,9 +649,9 @@ private void generateCodeFor(String lfModuleName) throws IOException { code.pr(envFuncGen.generateDefinitions()); - if (targetConfig.fedSetupPreamble.isSet()) { + if (targetConfig.isSet(new FedSetupProperty())) { if (targetLanguageIsCpp()) code.pr("extern \"C\" {"); - code.pr("#include \"" + targetConfig.fedSetupPreamble + "\""); + code.pr("#include \"" + targetConfig.get(new FedSetupProperty()) + "\""); if (targetLanguageIsCpp()) code.pr("}"); } @@ -653,7 +668,7 @@ private void generateCodeFor(String lfModuleName) throws IOException { // is set to decentralized) or, if there are // downstream federates, will notify the RTI // that the specified logical time is complete. - if (CCppMode || targetConfig.platformOptions.get().platform == Platform.ARDUINO) + if (CCppMode || targetConfig.get(new PlatformProperty()).platform == Platform.ARDUINO) code.pr("extern \"C\""); code.pr( String.join( @@ -694,11 +709,11 @@ protected String getConflictingConnectionsInModalReactorsBody(String source, Str private void pickScheduler() { // Don't use a scheduler that does not prioritize reactions based on deadlines // if the program contains a deadline (handler). Use the GEDF_NP scheduler instead. - if (!targetConfig.schedulerType.get().prioritizesDeadline()) { + if (!targetConfig.get(new SchedulerProperty()).prioritizesDeadline()) { // Check if a deadline is assigned to any reaction if (hasDeadlines(reactors)) { - if (!targetConfig.schedulerType.isSet()) { - targetConfig.schedulerType.override(Scheduler.GEDF_NP); + if (!targetConfig.isSet(new SchedulerProperty())) { + targetConfig.override(new SchedulerProperty(), Scheduler.GEDF_NP); } } } @@ -742,14 +757,14 @@ private void inspectReactorEResource(ReactorDecl reactor) { // Copy the user files and cmake-includes to the src-gen path of the main .lf file copyUserFiles(lfResource.getTargetConfig(), lfResource.getFileConfig()); // Merge the CMake includes from the imported file into the target config + final var cmakeIncludes = this.targetConfig.get(new CmakeIncludeProperty()); lfResource .getTargetConfig() - .cmakeIncludes - .get() + .get(new CmakeIncludeProperty()) .forEach( incl -> { - if (!this.targetConfig.cmakeIncludes.get().contains(incl)) { - this.targetConfig.cmakeIncludes.get().add(incl); + if (!cmakeIncludes.contains(incl)) { + cmakeIncludes.add(incl); } }); } @@ -770,16 +785,20 @@ protected void copyUserFiles(TargetConfig targetConfig, FileConfig fileConfig) { var destination = this.fileConfig.getSrcGenPath(); FileUtil.copyFilesOrDirectories( - targetConfig.cmakeIncludes.get(), destination, fileConfig, messageReporter, true); + targetConfig.get(new CmakeIncludeProperty()), + destination, + fileConfig, + messageReporter, + true); - if (!StringExtensions.isNullOrEmpty(targetConfig.fedSetupPreamble.get())) { + if (!StringExtensions.isNullOrEmpty(targetConfig.get(new FedSetupProperty()))) { try { - var file = targetConfig.fedSetupPreamble.get(); + var file = targetConfig.get(new FedSetupProperty()); FileUtil.copyFile(fileConfig.srcFile.getParent().resolve(file), destination.resolve(file)); } catch (IOException e) { messageReporter .nowhere() - .error("Failed to find _fed_setup file " + targetConfig.fedSetupPreamble); + .error("Failed to find _fed_setup file " + targetConfig.get(new FedSetupProperty())); } } } @@ -897,8 +916,8 @@ private void generateReactorChildren( private void pickCompilePlatform() { var osName = System.getProperty("os.name").toLowerCase(); // if platform target was set, use given platform instead - if (targetConfig.platformOptions.get().platform != Platform.AUTO) { - osName = targetConfig.platformOptions.get().platform.toString(); + if (targetConfig.get(new PlatformProperty()).platform != Platform.AUTO) { + osName = targetConfig.get(new PlatformProperty()).platform.toString(); } else if (Stream.of("mac", "darwin", "win", "nux").noneMatch(osName::contains)) { messageReporter.nowhere().error("Platform " + osName + " is not supported"); } @@ -909,7 +928,7 @@ protected void copyTargetFiles() throws IOException { // Copy the core lib String coreLib = LFGeneratorContext.BuildParm.EXTERNAL_RUNTIME_PATH.getValue(context); Path dest = fileConfig.getSrcGenPath(); - if (targetConfig.platformOptions.get().platform == Platform.ARDUINO) { + if (targetConfig.get(new PlatformProperty()).platform == Platform.ARDUINO) { dest = dest.resolve("src"); } if (coreLib != null) { @@ -920,7 +939,7 @@ protected void copyTargetFiles() throws IOException { } // For the Zephyr target, copy default config and board files. - if (targetConfig.platformOptions.get().platform == Platform.ZEPHYR) { + if (targetConfig.get(new PlatformProperty()).platform == Platform.ZEPHYR) { FileUtil.copyFromClassPath( "/lib/platform/zephyr/boards", fileConfig.getSrcGenPath(), false, false); FileUtil.copyFileFromClassPath( @@ -931,7 +950,7 @@ protected void copyTargetFiles() throws IOException { } // For the pico src-gen, copy over vscode configurations for debugging - if (targetConfig.platformOptions.get().platform == Platform.RP2040) { + if (targetConfig.get(new PlatformProperty()).platform == Platform.RP2040) { Path vscodePath = fileConfig.getSrcGenPath().resolve(".vscode"); // If pico-sdk-path not defined, this can be used to pull the sdk into src-gen FileUtil.copyFileFromClassPath( @@ -978,7 +997,7 @@ private void generateReactorClass(TypeParameterizedReactor tpr) throws IOExcepti fileConfig.getSrcGenPath().resolve(headerName), true); var extension = - targetConfig.platformOptions.get().platform == Platform.ARDUINO + targetConfig.get(new PlatformProperty()).platform == Platform.ARDUINO ? ".ino" : CCppMode ? ".cpp" : ".c"; FileUtil.writeToFile( @@ -1404,7 +1423,7 @@ private void recordBuiltinTriggers(ReactorInstance instance) { foundOne = true; enclaveInfo.numShutdownReactions += reactor.getTotalWidth(); - if (targetConfig.tracing.get().isEnabled()) { + if (targetConfig.get(new TracingProperty()).isEnabled()) { var description = CUtil.getShortenedName(reactor); var reactorRef = CUtil.reactorRef(reactor); var envTraceRef = CUtil.getEnvironmentStruct(reactor) + ".trace"; @@ -1687,7 +1706,7 @@ public static String variableStructType(TriggerInstance portOrAction) { * @param instance The reactor instance. */ private void generateTraceTableEntries(ReactorInstance instance) { - if (targetConfig.tracing.get().isEnabled()) { + if (targetConfig.get(new TracingProperty()).isEnabled()) { initializeTriggerObjects.pr(CTracingGenerator.generateTraceTableEntries(instance)); } } @@ -1958,33 +1977,39 @@ protected DockerGenerator getDockerGenerator(LFGeneratorContext context) { protected void setUpGeneralParameters() { accommodatePhysicalActionsIfPresent(); targetConfig - .compileDefinitions - .get() - .put("LOG_LEVEL", String.valueOf(targetConfig.logLevel.get().ordinal())); + .get(new CompileDefinitionsProperty()) + .put( + "LOG_LEVEL", + String.valueOf( + targetConfig + .get(new LoggingProperty()) + .ordinal())); // FIXME: put without marking as set targetConfig.compileAdditionalSources.addAll(CCoreFilesUtils.getCTargetSrc()); // Create the main reactor instance if there is a main reactor. this.main = ASTUtils.createMainReactorInstance(mainDef, reactors, messageReporter, targetConfig); if (hasModalReactors) { // So that each separate compile knows about modal reactors, do this: - targetConfig.compileDefinitions.get().put("MODAL_REACTORS", "TRUE"); + targetConfig + .get(new CompileDefinitionsProperty()) + .put("MODAL_REACTORS", "TRUE"); // FIXME: put without marking as set } - if (targetConfig.threading.get() - && targetConfig.platformOptions.get().platform == Platform.ARDUINO - && (targetConfig.platformOptions.get().board == null - || !targetConfig.platformOptions.get().board.contains("mbed"))) { + final var platformOptions = targetConfig.get(new PlatformProperty()); + if (targetConfig.get(new ThreadingProperty()) + && platformOptions.platform == Platform.ARDUINO + && (platformOptions.board == null || !platformOptions.board.contains("mbed"))) { // non-MBED boards should not use threading messageReporter .nowhere() .info( "Threading is incompatible on your current Arduino flavor. Setting threading to" + " false."); - targetConfig.threading.override(false); + targetConfig.override(new ThreadingProperty(), false); } - if (targetConfig.platformOptions.get().platform == Platform.ARDUINO - && !targetConfig.noCompile.get() - && targetConfig.platformOptions.get().board == null) { + if (platformOptions.platform == Platform.ARDUINO + && !targetConfig.get(new NoCompileProperty()) + && platformOptions.board == null) { messageReporter .nowhere() .info( @@ -1992,19 +2017,16 @@ protected void setUpGeneralParameters() { + " board name (FQBN) in the target property. For example, platform: {name:" + " arduino, board: arduino:avr:leonardo}. Entering \"no-compile\" mode and" + " generating target code only."); - targetConfig.noCompile.override(true); + targetConfig.override(new NoCompileProperty(), true); } - if (targetConfig.platformOptions.get().platform == Platform.ZEPHYR - && targetConfig.threading.get() - && targetConfig.platformOptions.get().userThreads >= 0) { + if (platformOptions.platform == Platform.ZEPHYR + && targetConfig.get(new ThreadingProperty()) + && platformOptions.userThreads >= 0) { targetConfig - .compileDefinitions - .get() - .put( - PlatformOption.USER_THREADS.name(), - String.valueOf(targetConfig.platformOptions.get().userThreads)); - } else if (targetConfig.platformOptions.get().userThreads > 0) { + .get(new CompileDefinitionsProperty()) + .put(PlatformOption.USER_THREADS.name(), String.valueOf(platformOptions.userThreads)); + } else if (platformOptions.userThreads > 0) { messageReporter .nowhere() .warning( @@ -2012,24 +2034,29 @@ protected void setUpGeneralParameters() { + " This option will be ignored."); } - if (targetConfig.threading.get()) { // FIXME: This logic is duplicated in CMake + if (targetConfig.get(new ThreadingProperty())) { // FIXME: This logic is duplicated in CMake pickScheduler(); // FIXME: this and pickScheduler should be combined. targetConfig - .compileDefinitions - .get() - .put("SCHEDULER", targetConfig.schedulerType.get().name()); + .get(new CompileDefinitionsProperty()) + .put( + "SCHEDULER", + targetConfig + .get(new SchedulerProperty()) + .name()); // FIXME: put without marking as set targetConfig - .compileDefinitions - .get() - .put("NUMBER_OF_WORKERS", String.valueOf(targetConfig.workers)); + .get(new CompileDefinitionsProperty()) + .put( + "NUMBER_OF_WORKERS", + String.valueOf( + targetConfig.get(new WorkersProperty()))); // FIXME: put without marking as set } pickCompilePlatform(); } protected void handleProtoFiles() { // Handle .proto files. - for (String file : targetConfig.protoFiles.get()) { + for (String file : targetConfig.get(new ProtobufsProperty())) { this.processProtoFile(file); } } @@ -2060,7 +2087,7 @@ protected String generateTopLevelPreambles(Reactor reactor) { .flatMap(it -> ASTUtils.allFileLevelPreambles(it).stream()) .collect(Collectors.toSet()) .forEach(it -> builder.pr(toText(it.getCode()))); - for (String file : targetConfig.protoFiles.get()) { + for (String file : targetConfig.get(new ProtobufsProperty())) { var dotIndex = file.lastIndexOf("."); var rootFilename = file; if (dotIndex > 0) { diff --git a/core/src/main/java/org/lflang/generator/c/CMainFunctionGenerator.java b/core/src/main/java/org/lflang/generator/c/CMainFunctionGenerator.java index 1ef7280834..65168e078a 100644 --- a/core/src/main/java/org/lflang/generator/c/CMainFunctionGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CMainFunctionGenerator.java @@ -4,6 +4,10 @@ import java.util.List; import org.lflang.generator.CodeBuilder; import org.lflang.target.TargetConfig; +import org.lflang.target.property.FastProperty; +import org.lflang.target.property.KeepaliveProperty; +import org.lflang.target.property.PlatformProperty; +import org.lflang.target.property.TimeOutProperty; import org.lflang.target.property.type.PlatformType.Platform; import org.lflang.util.StringUtil; @@ -33,7 +37,7 @@ public String generateCode() { /** Generate the {@code main} function. */ private String generateMainFunction() { - if (targetConfig.platformOptions.get().platform == Platform.ARDUINO) { + if (targetConfig.get(new PlatformProperty()).platform == Platform.ARDUINO) { /** * By default, we must have a serial begin line prior to calling lf_reactor_c_main due to * internal debugging messages requiring a print buffer. For the future, we can check whether @@ -48,12 +52,12 @@ private String generateMainFunction() { "}\n", "// Arduino setup() and loop() functions", "void setup() {", - "\tSerial.begin(" + targetConfig.platformOptions.get().baudRate + ");", + "\tSerial.begin(" + targetConfig.get(new PlatformProperty()).baudRate + ");", "\tlf_register_print_function(&_lf_arduino_print_message_function, LOG_LEVEL);", "\tlf_reactor_c_main(0, NULL);", "}\n", "void loop() {}"); - } else if (targetConfig.platformOptions.get().platform == Platform.ZEPHYR) { + } else if (targetConfig.get(new PlatformProperty()).platform == Platform.ZEPHYR) { // The Zephyr "runtime" does not terminate when main returns. // Rather, {@code exit} should be called explicitly. return String.join( @@ -62,7 +66,7 @@ private String generateMainFunction() { " int res = lf_reactor_c_main(0, NULL);", " exit(res);", "}"); - } else if (targetConfig.platformOptions.get().platform == Platform.RP2040) { + } else if (targetConfig.get(new PlatformProperty()).platform == Platform.RP2040) { // Pico platform cannot use command line args. return String.join("\n", "int main(void) {", " return lf_reactor_c_main(0, NULL);", "}"); } else { @@ -97,18 +101,18 @@ private String generateSetDefaultCliOption() { /** Parse the target parameters and set flags to the runCommand accordingly. */ private void parseTargetParameters() { - if (targetConfig.fastMode.get()) { + if (targetConfig.get(new FastProperty())) { runCommand.add("-f"); runCommand.add("true"); } - if (targetConfig.keepalive.get()) { + if (targetConfig.get(new KeepaliveProperty())) { runCommand.add("-k"); runCommand.add("true"); } - if (targetConfig.timeout.get() != null) { + if (targetConfig.get(new TimeOutProperty()) != null) { runCommand.add("-o"); - runCommand.add(targetConfig.timeout.get().getMagnitude() + ""); - runCommand.add(targetConfig.timeout.get().unit.getCanonicalName()); + runCommand.add(targetConfig.get(new TimeOutProperty()).getMagnitude() + ""); + runCommand.add(targetConfig.get(new TimeOutProperty()).unit.getCanonicalName()); } // The runCommand has a first entry that is ignored but needed. if (runCommand.size() > 0) { 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 df26dbb943..18c783a4f5 100644 --- a/core/src/main/java/org/lflang/generator/c/CPreambleGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CPreambleGenerator.java @@ -5,6 +5,12 @@ import java.nio.file.Path; import org.lflang.generator.CodeBuilder; import org.lflang.target.TargetConfig; +import org.lflang.target.property.CompileDefinitionsProperty; +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.TracingProperty; import org.lflang.target.property.type.PlatformType.Platform; import org.lflang.util.StringUtil; @@ -28,7 +34,7 @@ public class CPreambleGenerator { public static String generateIncludeStatements(TargetConfig targetConfig, boolean cppMode) { CodeBuilder code = new CodeBuilder(); - if (cppMode || targetConfig.platformOptions.get().platform == Platform.ARDUINO) { + if (cppMode || targetConfig.get(new PlatformProperty()).platform == Platform.ARDUINO) { code.pr("extern \"C\" {"); } code.pr("#include "); @@ -37,11 +43,11 @@ 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.threading.get()) { + if (targetConfig.get(new ThreadingProperty())) { code.pr("#include \"include/core/threaded/scheduler.h\""); } - if (targetConfig.tracing.get().isEnabled()) { + if (targetConfig.get(new TracingProperty()).isEnabled()) { code.pr("#include \"include/core/trace.h\""); } code.pr("#include \"include/core/mixed_radix.h\""); @@ -49,26 +55,28 @@ public static String generateIncludeStatements(TargetConfig targetConfig, boolea code.pr("#include \"include/core/environment.h\""); code.pr("int lf_reactor_c_main(int argc, const char* argv[]);"); - if (targetConfig.fedSetupPreamble.isSet()) { + if (targetConfig.isSet(new FedSetupProperty())) { code.pr("#include \"include/core/federated/federate.h\""); code.pr("#include \"include/core/federated/net_common.h\""); } - if (cppMode || targetConfig.platformOptions.get().platform == Platform.ARDUINO) { + if (cppMode || targetConfig.get(new PlatformProperty()).platform == Platform.ARDUINO) { code.pr("}"); } return code.toString(); } public static String generateDefineDirectives(TargetConfig targetConfig, Path srcGenPath) { - int logLevel = targetConfig.logLevel.get().ordinal(); - var tracing = targetConfig.tracing.get(); + int logLevel = targetConfig.get(new LoggingProperty()).ordinal(); + var tracing = targetConfig.get(new TracingProperty()); CodeBuilder code = new CodeBuilder(); // TODO: Get rid of all of these code.pr("#define LOG_LEVEL " + logLevel); code.pr("#define TARGET_FILES_DIRECTORY " + addDoubleQuotes(srcGenPath.toString())); if (tracing.isEnabled()) { - targetConfig.compileDefinitions.get().put("LF_TRACE", tracing.traceFileName); + targetConfig + .get(new CompileDefinitionsProperty()) + .put("LF_TRACE", tracing.traceFileName); // FIXME: put without marking as set } // if (clockSyncIsOn) { // code.pr(generateClockSyncDefineDirective( @@ -76,15 +84,16 @@ public static String generateDefineDirectives(TargetConfig targetConfig, Path sr // targetConfig.clockSyncOptions // )); // } - if (targetConfig.threading.get()) { - targetConfig.compileDefinitions.get().put("LF_THREADED", "1"); + final var defs = targetConfig.get(new CompileDefinitionsProperty()); + if (targetConfig.get(new ThreadingProperty())) { + defs.put("LF_THREADED", "1"); } else { - targetConfig.compileDefinitions.get().put("LF_UNTHREADED", "1"); + defs.put("LF_UNTHREADED", "1"); } - if (targetConfig.threading.get()) { - targetConfig.compileDefinitions.get().put("LF_THREADED", "1"); + if (targetConfig.get(new ThreadingProperty())) { + defs.put("LF_THREADED", "1"); } else { - targetConfig.compileDefinitions.get().put("LF_UNTHREADED", "1"); + defs.put("LF_UNTHREADED", "1"); } code.newLine(); return code.toString(); 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 29cf3a682d..9b52667b58 100644 --- a/core/src/main/java/org/lflang/generator/c/CTriggerObjectsGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CTriggerObjectsGenerator.java @@ -23,6 +23,8 @@ import org.lflang.generator.RuntimeRange; 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.type.LoggingType.LogLevel; /** @@ -100,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.threading.get()) { + if (!targetConfig.get(new ThreadingProperty())) { return ""; } var code = new CodeBuilder(); @@ -883,7 +885,7 @@ private static String deferredReactionOutputs( // val selfRef = CUtil.reactorRef(reaction.getParent()); var name = reaction.getParent().getFullName(); // Insert a string name to facilitate debugging. - if (targetConfig.logLevel.get().compareTo(LogLevel.LOG) >= 0) { + if (targetConfig.get(new LoggingProperty()).compareTo(LogLevel.LOG) >= 0) { code.pr( CUtil.reactionRef(reaction) + ".name = " diff --git a/core/src/main/java/org/lflang/generator/c/CUtil.java b/core/src/main/java/org/lflang/generator/c/CUtil.java index b3bd6d2c24..8ed5f41671 100644 --- a/core/src/main/java/org/lflang/generator/c/CUtil.java +++ b/core/src/main/java/org/lflang/generator/c/CUtil.java @@ -54,6 +54,7 @@ import org.lflang.lf.Variable; import org.lflang.lf.WidthTerm; import org.lflang.target.TargetConfig; +import org.lflang.target.property.BuildCommandsProperty; import org.lflang.util.FileUtil; import org.lflang.util.LFCommand; @@ -614,7 +615,8 @@ public static void runBuildCommand( ReportCommandErrors reportCommandErrors, LFGeneratorContext.Mode mode) { List commands = - getCommands(targetConfig.buildCommands.get(), commandFactory, fileConfig.srcPath); + getCommands( + targetConfig.get(new BuildCommandsProperty()), commandFactory, fileConfig.srcPath); // If the build command could not be found, abort. // An error has already been reported in createCommand. if (commands.stream().anyMatch(Objects::isNull)) return; @@ -631,7 +633,7 @@ public static void runBuildCommand( // FIXME: Why is the content of stderr not provided to the user in this error // message? "Build command \"%s\" failed with error code %d.", - targetConfig.buildCommands, returnCode)); + targetConfig.get(new BuildCommandsProperty()), returnCode)); return; } // For warnings (vs. errors), the return code is 0. diff --git a/core/src/main/java/org/lflang/generator/python/PythonGenerator.java b/core/src/main/java/org/lflang/generator/python/PythonGenerator.java index ab9092575d..ca291f1d3e 100644 --- a/core/src/main/java/org/lflang/generator/python/PythonGenerator.java +++ b/core/src/main/java/org/lflang/generator/python/PythonGenerator.java @@ -59,6 +59,9 @@ import org.lflang.lf.Port; import org.lflang.lf.Reaction; import org.lflang.lf.Reactor; +import org.lflang.target.property.CompilerFlagsProperty; +import org.lflang.target.property.CompilerProperty; +import org.lflang.target.property.ProtobufsProperty; import org.lflang.util.FileUtil; import org.lflang.util.LFCommand; import org.lflang.util.StringUtil; @@ -106,8 +109,8 @@ public PythonGenerator(LFGeneratorContext context) { private PythonGenerator( LFGeneratorContext context, PythonTypes types, CCmakeGenerator cmakeGenerator) { super(context, false, types, cmakeGenerator, new PythonDelayBodyGenerator(types)); - this.targetConfig.compiler.override("gcc"); // FIXME: why? - this.targetConfig.compilerFlags.get().clear(); + this.targetConfig.override(new CompilerProperty(), "gcc"); // FIXME: why? + this.targetConfig.get(new CompilerFlagsProperty()).clear(); this.targetConfig.linkerFlags = ""; // FIXME: why? this.types = types; } @@ -276,7 +279,7 @@ protected String generateTopLevelPreambles(Reactor ignored) { @Override protected void handleProtoFiles() { - for (String name : targetConfig.protoFiles.get()) { + for (String name : targetConfig.get(new ProtobufsProperty())) { this.processProtoFile(name); int dotIndex = name.lastIndexOf("."); String rootFilename = dotIndex > 0 ? name.substring(0, dotIndex) : name; diff --git a/core/src/main/java/org/lflang/generator/rust/RustTargetConfig.java b/core/src/main/java/org/lflang/generator/rust/RustTargetConfig.java index 3bced7afa2..76dba1f2c9 100644 --- a/core/src/main/java/org/lflang/generator/rust/RustTargetConfig.java +++ b/core/src/main/java/org/lflang/generator/rust/RustTargetConfig.java @@ -24,40 +24,22 @@ package org.lflang.generator.rust; +import org.lflang.Target; import org.lflang.target.TargetConfig; -import org.lflang.target.property.BuildTypeProperty; import org.lflang.target.property.CargoDependenciesProperty; import org.lflang.target.property.CargoFeaturesProperty; import org.lflang.target.property.RustIncludeProperty; -import org.lflang.target.property.type.BuildTypeType; -import org.lflang.target.property.type.BuildTypeType.BuildType; /** * Rust-specific part of a {@link TargetConfig}. * * @author Clément Fournier - TU Dresden, INSA Rennes */ -public final class RustTargetConfig { +public final class RustTargetConfig extends TargetConfig { - /** List of Cargo features of the generated crate to enable. */ - public final CargoFeaturesProperty cargoFeatures = new CargoFeaturesProperty(); - - /** Map of Cargo dependency to dependency properties. */ - public final CargoDependenciesProperty cargoDependencies = new CargoDependenciesProperty(); - - /** List of top-level modules, those are absolute paths. */ - public final RustIncludeProperty rustTopLevelModules = new RustIncludeProperty(); - - /** Cargo profile, default is debug (corresponds to cargo dev profile). */ - private BuildType profile = BuildTypeType.BuildType.DEBUG; - - /** The build type to use. Corresponds to a Cargo profile. */ - public BuildType getBuildType(BuildTypeProperty cmakeBuildType) { - // FIXME: this is because Rust uses a different default. - // Can we just use the same? - if (cmakeBuildType.isSet()) { - return cmakeBuildType.get(); - } - return profile; + public RustTargetConfig() { + super(Target.Rust); + register( + new CargoFeaturesProperty(), new CargoDependenciesProperty(), new RustIncludeProperty()); } } diff --git a/core/src/main/java/org/lflang/target/TargetConfig.java b/core/src/main/java/org/lflang/target/TargetConfig.java index 8067161b0c..868a5f3f9b 100644 --- a/core/src/main/java/org/lflang/target/TargetConfig.java +++ b/core/src/main/java/org/lflang/target/TargetConfig.java @@ -25,14 +25,18 @@ package org.lflang.target; import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Optional; import java.util.Properties; +import java.util.Set; import java.util.stream.Collectors; import org.lflang.AbstractTargetProperty; import org.lflang.MessageReporter; import org.lflang.Target; -import org.lflang.generator.rust.RustTargetConfig; import org.lflang.lf.KeyValuePair; import org.lflang.lf.TargetDecl; import org.lflang.target.property.AuthProperty; @@ -69,6 +73,7 @@ import org.lflang.target.property.TimeOutProperty; import org.lflang.target.property.TracingProperty; import org.lflang.target.property.WorkersProperty; +import org.lflang.target.property.type.TargetPropertyType; import org.lflang.target.property.type.VerifyProperty; /** @@ -83,11 +88,6 @@ public class TargetConfig { /** The target of this configuration (e.g., C, TypeScript, Python). */ public final Target target; - /** Private constructor used to create a target config that is not tied to a particular target. */ - private TargetConfig() { - this.target = null; - } - /** * Create a new target configuration based on the given target declaration AST node only. * @@ -95,6 +95,44 @@ private TargetConfig() { */ public TargetConfig(Target target) { this.target = target; + + this.register( + new AuthProperty(), + new BuildCommandsProperty(), + new BuildTypeProperty(), + new ClockSyncModeProperty(), + new ClockSyncOptionsProperty(), + new CmakeIncludeProperty(), + new CompileDefinitionsProperty(), + new CompilerFlagsProperty(), + new CompilerProperty(), + new CoordinationOptionsProperty(), + new CoordinationProperty(), + new DockerProperty(), + new ExportDependencyGraphProperty(), + new ExportToYamlProperty(), + new ExternalRuntimePathProperty(), + new FastProperty(), + new FilesProperty(), + new KeepaliveProperty(), + new LoggingProperty(), + new NoCompileProperty(), + new NoRuntimeValidationProperty(), + new PlatformProperty(), + new PrintStatisticsProperty(), + new ProtobufsProperty(), + new Ros2DependenciesProperty(), + new Ros2Property(), + new RuntimeVersionProperty(), + new SchedulerProperty(), + new SingleFileProjectProperty(), + new ThreadingProperty(), + new TimeOutProperty(), + new TracingProperty(), + new VerifyProperty(), + new WorkersProperty()); + + this.register(new FedSetupProperty()); } /** @@ -117,174 +155,51 @@ public TargetConfig(Properties cliArgs, TargetDecl target, MessageReporter messa } } - /** - * A list of custom build commands that replace the default build process of directly invoking a - * designated compiler. A common usage of this target property is to set the command to build on - * the basis of a Makefile. - */ - public final BuildCommandsProperty buildCommands = new BuildCommandsProperty(); - - /** - * The mode of clock synchronization to be used in federated programs. The default is 'initial'. - */ - public final ClockSyncModeProperty clockSync = new ClockSyncModeProperty(); - - /** Clock sync options. */ - public final ClockSyncOptionsProperty clockSyncOptions = new ClockSyncOptionsProperty(); - - /** Parameter passed to cmake. The default is 'Release'. */ - public final BuildTypeProperty buildType = new BuildTypeProperty(); - - /** Optional additional extensions to include in the generated CMakeLists.txt. */ - public final CmakeIncludeProperty cmakeIncludes = new CmakeIncludeProperty(); - - /** The compiler to invoke, unless a build command has been specified. */ - public final CompilerProperty compiler = new CompilerProperty(); - /** Additional sources to add to the compile command if appropriate. */ public final List compileAdditionalSources = new ArrayList<>(); - /** - * Additional (preprocessor) definitions to add to the compile command if appropriate. - * - *

The first string is the definition itself, and the second string is the value to attribute - * to that definition, if any. The second value could be left empty. - */ - public final CompileDefinitionsProperty compileDefinitions = new CompileDefinitionsProperty(); - - /** Flags to pass to the compiler, unless a build command has been specified. */ - public final CompilerFlagsProperty compilerFlags = new CompilerFlagsProperty(); - - /** - * The type of coordination used during the execution of a federated program. The default is - * 'centralized'. - */ - public final CoordinationProperty coordination = new CoordinationProperty(); - - /** Docker options. */ - public final DockerProperty dockerOptions = new DockerProperty(); - - /** Coordination options. */ - public final CoordinationOptionsProperty coordinationOptions = new CoordinationOptionsProperty(); - - /** Link to an external runtime library instead of the default one. */ - public final ExternalRuntimePathProperty externalRuntimePath = new ExternalRuntimePathProperty(); - - /** - * If true, configure the execution environment such that it does not wait for physical time to - * match logical time. The default is false. - */ - public final FastProperty fastMode = new FastProperty(); - - /** List of files to be copied to src-gen. */ - public final FilesProperty files = new FilesProperty(); - - /** - * If true, configure the execution environment to keep executing if there are no more events on - * the event queue. The default is false. - */ - public final KeepaliveProperty keepalive = new KeepaliveProperty(); - - /** The level of logging during execution. The default is INFO. */ - public final LoggingProperty logLevel = new LoggingProperty(); - /** Flags to pass to the linker, unless a build command has been specified. */ public String linkerFlags = ""; - /** If true, do not invoke the target compiler or build command. The default is false. */ - public final NoCompileProperty noCompile = new NoCompileProperty(); - - /** If true, do not perform runtime validation. The default is false. */ - public final NoRuntimeValidationProperty noRuntimeValidation = new NoRuntimeValidationProperty(); - - /** If true, check the generated verification model. The default is false. */ - public final VerifyProperty verify = new VerifyProperty(); - - /** - * Set the target platform config. This tells the build system what platform-specific support - * files it needs to incorporate at compile time. - * - *

This is now a wrapped class to account for overloaded definitions of defining platform - * (either a string or dictionary of values) - */ - public final PlatformProperty platformOptions = new PlatformProperty(); - - /** If true, instruct the runtime to collect and print execution statistics. */ - public final PrintStatisticsProperty printStatistics = new PrintStatisticsProperty(); + private final Map, Object> properties = new HashMap<>(); - /** List of proto files to be processed by the code generator. */ - public final ProtobufsProperty protoFiles = new ProtobufsProperty(); - - /** If true, generate ROS2 specific code. */ - public final Ros2Property ros2 = new Ros2Property(); - - /** Additional ROS2 packages that the LF program depends on. */ - public final Ros2DependenciesProperty ros2Dependencies = new Ros2DependenciesProperty(); - - /** The version of the runtime library to be used in the generated target. */ - public final RuntimeVersionProperty runtimeVersion = new RuntimeVersionProperty(); - - /** Whether all reactors are to be generated into a single target language file. */ - public final SingleFileProjectProperty singleFileProject = new SingleFileProjectProperty(); - - /** What runtime scheduler to use. */ - public final SchedulerProperty schedulerType = new SchedulerProperty(); - - /** - * The number of worker threads to deploy. The default is zero, which indicates that the runtime - * is allowed to freely choose the number of workers. - */ - public final WorkersProperty workers = new WorkersProperty(); + private final Set> setProperties = new HashSet<>(); - /** Indicate whether HMAC authentication is used. */ - public final AuthProperty auth = new AuthProperty(); - - /** Indicate whether the runtime should use multithreaded execution. */ - public final ThreadingProperty threading = new ThreadingProperty(); - - /** The timeout to be observed during execution of the program. */ - public final TimeOutProperty timeout = new TimeOutProperty(); - - /** If non-null, configure the runtime environment to perform tracing. The default is null. */ - public final TracingProperty tracing = new TracingProperty(); + public void register(AbstractTargetProperty... properties) { + Arrays.stream(properties) + .forEach(property -> this.properties.put(property, property.initialValue())); + } - /** - * If true, the resulting binary will output a graph visualizing all reaction dependencies. - * - *

This option is currently only used for C++ and Rust. This export function is a valuable tool - * for debugging LF programs and helps to understand the dependencies inferred by the runtime. - */ - public final ExportDependencyGraphProperty exportDependencyGraph = - new ExportDependencyGraphProperty(); + public void override( + AbstractTargetProperty property, T value) { + this.setProperties.add(property); + this.properties.put(property, value); + } - /** - * If true, the resulting binary will output a yaml file describing the whole reactor structure of - * the program. - * - *

This option is currently only used for C++. This export function is a valuable tool for - * debugging LF programs and performing external analysis. - */ - public final ExportToYamlProperty exportToYaml = new ExportToYamlProperty(); + public void reset(AbstractTargetProperty property) { + this.properties.remove(property); + this.setProperties.remove(property); + } - /** Rust-specific configuration. */ - public final RustTargetConfig rust = new RustTargetConfig(); + @SuppressWarnings("unchecked") + public T get(AbstractTargetProperty property) { + return (T) properties.get(property); + } - /** Path to a C file used by the Python target to setup federated execution. */ - public final FedSetupProperty fedSetupPreamble = new FedSetupProperty(); + public boolean isSet(AbstractTargetProperty property) { + return this.setProperties.contains(property); + } - public List getAllTargetProperties() { - var properties = AbstractTargetProperty.getAllTargetProperties(this); - properties.addAll(AbstractTargetProperty.getAllTargetProperties(this.rust)); - return properties.stream() - .sorted((p1, p2) -> p1.name().compareTo(p2.name())) - .collect(Collectors.toList()); + public String listOfRegisteredProperties() { + return getRegisteredProperties().stream() + .map(p -> p.toString()) + .filter(s -> !s.startsWith("_")) + .collect(Collectors.joining(", ")); } - public static List getUserTargetProperties() { - var config = new TargetConfig(); - var properties = AbstractTargetProperty.getAllTargetProperties(config); - return properties.stream() - .filter(it -> !it.name().startsWith("_")) + public List getRegisteredProperties() { + return this.properties.keySet().stream() + .sorted((p1, p2) -> p1.getClass().getName().compareTo(p2.getClass().getName())) .collect(Collectors.toList()); } @@ -294,7 +209,7 @@ public static List getUserTargetProperties() { * @param name The string to match against. */ public Optional forName(String name) { - return this.getAllTargetProperties().stream() + return this.getRegisteredProperties().stream() .filter(c -> c.name().equalsIgnoreCase(name)) .findFirst(); } diff --git a/core/src/main/java/org/lflang/target/TargetProperty.java b/core/src/main/java/org/lflang/target/TargetProperty.java index fd85287440..c47386981d 100644 --- a/core/src/main/java/org/lflang/target/TargetProperty.java +++ b/core/src/main/java/org/lflang/target/TargetProperty.java @@ -115,8 +115,8 @@ public static List extractProperties(TargetConfig config) { * @param config The configuration to find the properties in. */ public static List loaded(TargetConfig config) { - return config.getAllTargetProperties().stream() - .filter(p -> p.isSet()) + return config.getRegisteredProperties().stream() + .filter(p -> config.isSet(p)) .collect(Collectors.toList()); } @@ -169,7 +169,7 @@ public static void validate( .forEach( pair -> { var match = - config.getAllTargetProperties().stream() + config.getRegisteredProperties().stream() .filter(prop -> prop.name().equalsIgnoreCase(pair.getName())) .findAny(); if (match.isPresent()) { @@ -184,7 +184,7 @@ public static void validate( "Unrecognized target property: " + pair.getName() + ". Recognized properties are: " - + TargetConfig.getUserTargetProperties()); + + config.listOfRegisteredProperties()); } }); } diff --git a/core/src/main/java/org/lflang/target/property/BuildCommandsProperty.java b/core/src/main/java/org/lflang/target/property/BuildCommandsProperty.java index 8010b2869a..29a35fb2b9 100644 --- a/core/src/main/java/org/lflang/target/property/BuildCommandsProperty.java +++ b/core/src/main/java/org/lflang/target/property/BuildCommandsProperty.java @@ -10,7 +10,11 @@ import org.lflang.lf.Element; import org.lflang.target.property.type.UnionType; -/** Directive to let the generator use the custom build command. */ +/** + * A list of custom build commands that replace the default build process of directly invoking a + * designated compiler. A common usage of this target property is to set the command to build on the + * basis of a Makefile. + */ public class BuildCommandsProperty extends AbstractTargetProperty, UnionType> { public BuildCommandsProperty() { 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 cfed672d81..bc7fa61f09 100644 --- a/core/src/main/java/org/lflang/target/property/ClockSyncModeProperty.java +++ b/core/src/main/java/org/lflang/target/property/ClockSyncModeProperty.java @@ -14,7 +14,7 @@ import org.lflang.target.property.type.ClockSyncModeType; import org.lflang.target.property.type.ClockSyncModeType.ClockSyncMode; -/** Directive to let the federate execution handle clock synchronization in software. */ +/** The mode of clock synchronization to be used in federated programs. The default is 'initial'. */ public class ClockSyncModeProperty extends AbstractTargetProperty { diff --git a/core/src/main/java/org/lflang/target/property/CompileDefinitionsProperty.java b/core/src/main/java/org/lflang/target/property/CompileDefinitionsProperty.java index 88eb50fd0c..ab7a7772d9 100644 --- a/core/src/main/java/org/lflang/target/property/CompileDefinitionsProperty.java +++ b/core/src/main/java/org/lflang/target/property/CompileDefinitionsProperty.java @@ -11,7 +11,12 @@ import org.lflang.lf.Element; import org.lflang.target.property.type.StringDictionaryType; -/** Directive to specify compile-time definitions. */ +/** + * Additional (preprocessor) definitions to add to the compile command if appropriate. + * + *

The first string is the definition itself, and the second string is the value to attribute to + * that definition, if any. The second value could be left empty. + */ public class CompileDefinitionsProperty extends AbstractTargetProperty, StringDictionaryType> { diff --git a/core/src/main/java/org/lflang/target/property/CompilerFlagsProperty.java b/core/src/main/java/org/lflang/target/property/CompilerFlagsProperty.java index ebae420a1b..8f9aee85ca 100644 --- a/core/src/main/java/org/lflang/target/property/CompilerFlagsProperty.java +++ b/core/src/main/java/org/lflang/target/property/CompilerFlagsProperty.java @@ -4,7 +4,7 @@ import java.util.List; import org.lflang.Target; -/** Flags to be passed on to the target compiler. */ +/** Flags to pass to the compiler, unless a build command has been specified. */ public class CompilerFlagsProperty extends AbstractStringListProperty { @Override diff --git a/core/src/main/java/org/lflang/target/property/CompilerProperty.java b/core/src/main/java/org/lflang/target/property/CompilerProperty.java index d9ce97ce50..635a66e421 100644 --- a/core/src/main/java/org/lflang/target/property/CompilerProperty.java +++ b/core/src/main/java/org/lflang/target/property/CompilerProperty.java @@ -3,7 +3,7 @@ import java.util.List; import org.lflang.Target; -/** Directive to specify the target compiler. */ +/** The compiler to invoke, unless a build command has been specified. */ public class CompilerProperty extends AbstractStringConfig { @Override diff --git a/core/src/main/java/org/lflang/target/property/CoordinationProperty.java b/core/src/main/java/org/lflang/target/property/CoordinationProperty.java index c751b5e802..3163154a91 100644 --- a/core/src/main/java/org/lflang/target/property/CoordinationProperty.java +++ b/core/src/main/java/org/lflang/target/property/CoordinationProperty.java @@ -10,7 +10,10 @@ import org.lflang.target.property.type.CoordinationModeType; import org.lflang.target.property.type.CoordinationModeType.CoordinationMode; -/** Directive to specify the coordination mode */ +/** + * The type of coordination used during the execution of a federated program. The default is + * 'centralized'. + */ public class CoordinationProperty extends AbstractTargetProperty { diff --git a/core/src/main/java/org/lflang/target/property/ExportDependencyGraphProperty.java b/core/src/main/java/org/lflang/target/property/ExportDependencyGraphProperty.java index ae79262988..0f8c80ae6d 100644 --- a/core/src/main/java/org/lflang/target/property/ExportDependencyGraphProperty.java +++ b/core/src/main/java/org/lflang/target/property/ExportDependencyGraphProperty.java @@ -4,9 +4,10 @@ import org.lflang.Target; /** - * Directive to let the runtime export its internal dependency graph. + * If true, the resulting binary will output a graph visualizing all reaction dependencies. * - *

This is a debugging feature and currently only used for C++ and Rust programs. + *

This option is currently only used for C++ and Rust. This export function is a valuable tool + * for debugging LF programs and helps to understand the dependencies inferred by the runtime. */ public class ExportDependencyGraphProperty extends AbstractBooleanProperty { diff --git a/core/src/main/java/org/lflang/target/property/ExportToYamlProperty.java b/core/src/main/java/org/lflang/target/property/ExportToYamlProperty.java index ed83f76787..437b6d333f 100644 --- a/core/src/main/java/org/lflang/target/property/ExportToYamlProperty.java +++ b/core/src/main/java/org/lflang/target/property/ExportToYamlProperty.java @@ -4,9 +4,11 @@ import org.lflang.Target; /** - * Directive to let the runtime export the program structure to a yaml file. + * If true, the resulting binary will output a yaml file describing the whole reactor structure of + * the program. * - *

This is a debugging feature and currently only used for C++ programs. + *

This option is currently only used for C++. This export function is a valuable tool for + * debugging LF programs and performing external analysis. */ public class ExportToYamlProperty extends AbstractBooleanProperty { diff --git a/core/src/main/java/org/lflang/target/property/ExternalRuntimePathProperty.java b/core/src/main/java/org/lflang/target/property/ExternalRuntimePathProperty.java index 68540cc948..615e7c9e55 100644 --- a/core/src/main/java/org/lflang/target/property/ExternalRuntimePathProperty.java +++ b/core/src/main/java/org/lflang/target/property/ExternalRuntimePathProperty.java @@ -3,7 +3,10 @@ import java.util.List; import org.lflang.Target; -/** Directive for specifying a path to an external runtime to be used for the compiled binary. */ +/** + * Directive for specifying a path to an external runtime libray to link to instead of the default + * one. + */ public class ExternalRuntimePathProperty extends AbstractStringConfig { @Override 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 b24b032ce7..e57a13e46d 100644 --- a/core/src/main/java/org/lflang/target/property/FastProperty.java +++ b/core/src/main/java/org/lflang/target/property/FastProperty.java @@ -11,7 +11,10 @@ import org.lflang.lf.Model; import org.lflang.lf.Reactor; -/** Directive to let the execution engine allow logical time to elapse faster than physical time. */ +/** + * If true, configure the execution environment such that it does not wait for physical time to + * match logical time. The default is false. + */ public class FastProperty extends AbstractBooleanProperty { @Override diff --git a/core/src/main/java/org/lflang/target/property/KeepaliveProperty.java b/core/src/main/java/org/lflang/target/property/KeepaliveProperty.java index 787c8967e2..da6d994c1d 100644 --- a/core/src/main/java/org/lflang/target/property/KeepaliveProperty.java +++ b/core/src/main/java/org/lflang/target/property/KeepaliveProperty.java @@ -4,8 +4,8 @@ import org.lflang.Target; /** - * Directive to let the execution engine remain active also if there are no more events in the event - * queue. + * If true, configure the execution environment to keep executing if there are no more events on the + * event queue. The default is false. */ public class KeepaliveProperty extends AbstractBooleanProperty { diff --git a/core/src/main/java/org/lflang/target/property/LoggingProperty.java b/core/src/main/java/org/lflang/target/property/LoggingProperty.java index 2cddd285ca..0784166762 100644 --- a/core/src/main/java/org/lflang/target/property/LoggingProperty.java +++ b/core/src/main/java/org/lflang/target/property/LoggingProperty.java @@ -9,7 +9,10 @@ import org.lflang.target.property.type.LoggingType; import org.lflang.target.property.type.LoggingType.LogLevel; -/** Directive to specify the grain at which to report log messages during execution. */ +/** + * Directive to specify the grain at which to report log messages during execution. The default is + * INFO. + */ public class LoggingProperty extends AbstractTargetProperty { public LoggingProperty() { diff --git a/core/src/main/java/org/lflang/target/property/NoCompileProperty.java b/core/src/main/java/org/lflang/target/property/NoCompileProperty.java index 66d6e877a9..b1a6a375b0 100644 --- a/core/src/main/java/org/lflang/target/property/NoCompileProperty.java +++ b/core/src/main/java/org/lflang/target/property/NoCompileProperty.java @@ -4,7 +4,7 @@ import java.util.List; import org.lflang.Target; -/** Directive to not invoke the target compiler. */ +/** If true, do not invoke the target compiler or build command. The default is false. */ public class NoCompileProperty extends AbstractBooleanProperty { @Override diff --git a/core/src/main/java/org/lflang/target/property/NoRuntimeValidationProperty.java b/core/src/main/java/org/lflang/target/property/NoRuntimeValidationProperty.java index a3beacb951..e9176d6680 100644 --- a/core/src/main/java/org/lflang/target/property/NoRuntimeValidationProperty.java +++ b/core/src/main/java/org/lflang/target/property/NoRuntimeValidationProperty.java @@ -3,7 +3,7 @@ import java.util.List; import org.lflang.Target; -/** Directive to disable validation of reactor rules at runtime. */ +/** If true, do not perform runtime validation. The default is false. */ public class NoRuntimeValidationProperty extends AbstractBooleanProperty { @Override diff --git a/core/src/main/java/org/lflang/target/property/PrintStatisticsProperty.java b/core/src/main/java/org/lflang/target/property/PrintStatisticsProperty.java index 8f6fa48445..c722a8530d 100644 --- a/core/src/main/java/org/lflang/target/property/PrintStatisticsProperty.java +++ b/core/src/main/java/org/lflang/target/property/PrintStatisticsProperty.java @@ -3,7 +3,7 @@ import java.util.List; import org.lflang.Target; -/** Directive to instruct the runtime to collect and print execution statistics. */ +/** If true, instruct the runtime to collect and print execution statistics. */ public class PrintStatisticsProperty extends AbstractBooleanProperty { @Override diff --git a/core/src/main/java/org/lflang/target/property/Ros2Property.java b/core/src/main/java/org/lflang/target/property/Ros2Property.java index 4b797e8fa7..c4fd562ac6 100644 --- a/core/src/main/java/org/lflang/target/property/Ros2Property.java +++ b/core/src/main/java/org/lflang/target/property/Ros2Property.java @@ -3,7 +3,7 @@ import java.util.List; import org.lflang.Target; -/** Directive to specify that ROS2 specific code is generated. */ +/** If true, generate ROS2 specific code. */ public class Ros2Property extends AbstractBooleanProperty { @Override 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 813504f880..c3438d44e6 100644 --- a/core/src/main/java/org/lflang/target/property/SchedulerProperty.java +++ b/core/src/main/java/org/lflang/target/property/SchedulerProperty.java @@ -13,7 +13,7 @@ import org.lflang.target.property.type.SchedulerType; import org.lflang.target.property.type.SchedulerType.Scheduler; -/** Directive for specifying a specific runtime scheduler, if supported. */ +/** Directive for specifying the use of a specific runtime scheduler. */ public class SchedulerProperty extends AbstractTargetProperty { public SchedulerProperty() { diff --git a/core/src/main/java/org/lflang/target/property/TimeOutProperty.java b/core/src/main/java/org/lflang/target/property/TimeOutProperty.java index bef95c7ff6..d2575ae561 100644 --- a/core/src/main/java/org/lflang/target/property/TimeOutProperty.java +++ b/core/src/main/java/org/lflang/target/property/TimeOutProperty.java @@ -9,7 +9,7 @@ import org.lflang.lf.Element; import org.lflang.target.property.type.PrimitiveType; -/** Directive to specify the execution timeout. */ +/** The timeout to be observed during execution of the program. */ public class TimeOutProperty extends AbstractTargetProperty { public TimeOutProperty() { 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 114f6deebf..0c69a7fd5e 100644 --- a/core/src/main/java/org/lflang/target/property/TracingProperty.java +++ b/core/src/main/java/org/lflang/target/property/TracingProperty.java @@ -20,7 +20,7 @@ import org.lflang.target.property.type.TargetPropertyType; import org.lflang.target.property.type.UnionType; -/** Directive to enable tracing. */ +/** Directive to configure the runtime environment to perform tracing. */ public class TracingProperty extends AbstractTargetProperty { public TracingProperty() { diff --git a/core/src/main/java/org/lflang/target/property/VerifyProperty.java b/core/src/main/java/org/lflang/target/property/VerifyProperty.java index 793ee4c280..c26421dc03 100644 --- a/core/src/main/java/org/lflang/target/property/VerifyProperty.java +++ b/core/src/main/java/org/lflang/target/property/VerifyProperty.java @@ -4,7 +4,7 @@ import org.lflang.Target; import org.lflang.target.property.AbstractBooleanProperty; -/** Directive to check the generated verification model. */ +/** If true, check the generated verification model. The default is false. */ public class VerifyProperty extends AbstractBooleanProperty { @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 057be50e56..19a433e8db 100644 --- a/core/src/main/java/org/lflang/target/property/WorkersProperty.java +++ b/core/src/main/java/org/lflang/target/property/WorkersProperty.java @@ -8,7 +8,10 @@ import org.lflang.lf.Element; import org.lflang.target.property.type.PrimitiveType; -/** Directive to specify the number of worker threads used by the runtime. */ +/** + * The number of worker threads to deploy. The default is zero, which indicates that the runtime is + * allowed to freely choose the number of workers. + */ public class WorkersProperty extends AbstractTargetProperty { public WorkersProperty() { diff --git a/core/src/main/java/org/lflang/util/ArduinoUtil.java b/core/src/main/java/org/lflang/util/ArduinoUtil.java index 3423e80ac7..a94097ee54 100644 --- a/core/src/main/java/org/lflang/util/ArduinoUtil.java +++ b/core/src/main/java/org/lflang/util/ArduinoUtil.java @@ -11,6 +11,7 @@ import org.lflang.generator.GeneratorCommandFactory; import org.lflang.generator.LFGeneratorContext; import org.lflang.target.TargetConfig; +import org.lflang.target.property.PlatformProperty; /** * Utilities for Building using Arduino CLI. @@ -68,11 +69,11 @@ private LFCommand arduinoCompileCommand(FileConfig fileConfig, TargetConfig targ var fileWriter = new FileWriter(testScript.getAbsoluteFile(), true); BufferedWriter bufferedWriter = new BufferedWriter(fileWriter); String board = - targetConfig.platformOptions.get().board != null - ? targetConfig.platformOptions.get().board + targetConfig.get(new PlatformProperty()).board != null + ? targetConfig.get(new PlatformProperty()).board : "arduino:avr:leonardo"; String isThreaded = - targetConfig.platformOptions.get().board.contains("mbed") + targetConfig.get(new PlatformProperty()).board.contains("mbed") ? "-DLF_THREADED" : "-DLF_UNTHREADED"; bufferedWriter.write( @@ -122,8 +123,8 @@ public void buildArduino(FileConfig fileConfig, TargetConfig targetConfig) { "SUCCESS: Compiling generated code for " + fileConfig.name + " finished with no errors."); - if (targetConfig.platformOptions.get().flash) { - if (targetConfig.platformOptions.get().port != null) { + if (targetConfig.get(new PlatformProperty()).flash) { + if (targetConfig.get(new PlatformProperty()).port != null) { messageReporter.nowhere().info("Invoking flash command for Arduino"); LFCommand flash = commandFactory.createCommand( @@ -131,9 +132,9 @@ public void buildArduino(FileConfig fileConfig, TargetConfig targetConfig) { List.of( "upload", "-b", - targetConfig.platformOptions.get().board, + targetConfig.get(new PlatformProperty()).board, "-p", - targetConfig.platformOptions.get().port), + targetConfig.get(new PlatformProperty()).port), fileConfig.getSrcGenPath()); if (flash == null) { messageReporter.nowhere().error("Could not create arduino-cli flash command."); diff --git a/core/src/main/kotlin/org/lflang/generator/cpp/CppGenerator.kt b/core/src/main/kotlin/org/lflang/generator/cpp/CppGenerator.kt index b98dc1d79c..e2796c337b 100644 --- a/core/src/main/kotlin/org/lflang/generator/cpp/CppGenerator.kt +++ b/core/src/main/kotlin/org/lflang/generator/cpp/CppGenerator.kt @@ -28,16 +28,15 @@ package org.lflang.generator.cpp import org.eclipse.emf.ecore.resource.Resource import org.lflang.Target -import org.lflang.generator.CodeMap -import org.lflang.generator.GeneratorBase -import org.lflang.generator.GeneratorResult +import org.lflang.generator.* import org.lflang.generator.GeneratorUtils.canGenerate -import org.lflang.generator.IntegratedBuilder -import org.lflang.generator.LFGeneratorContext import org.lflang.generator.LFGeneratorContext.Mode -import org.lflang.generator.TargetTypes import org.lflang.isGeneric import org.lflang.scoping.LFGlobalScopeProvider +import org.lflang.target.property.ExternalRuntimePathProperty +import org.lflang.target.property.NoCompileProperty +import org.lflang.target.property.Ros2Property +import org.lflang.target.property.RuntimeVersionProperty import org.lflang.util.FileUtil import java.nio.file.Files import java.nio.file.Path @@ -71,7 +70,7 @@ class CppGenerator( // create a platform-specific generator val platformGenerator: CppPlatformGenerator = - if (targetConfig.ros2.get()) CppRos2Generator(this) else CppStandaloneGenerator(this) + if (targetConfig.get(Ros2Property())) CppRos2Generator(this) else CppStandaloneGenerator(this) // generate all core files generateFiles(platformGenerator.srcGenPath) @@ -79,7 +78,7 @@ class CppGenerator( // generate platform specific files platformGenerator.generatePlatformFiles() - if (targetConfig.noCompile.get() || errorsOccurred()) { + if (targetConfig.get(NoCompileProperty()) || errorsOccurred()) { println("Exiting before invoking target compiler.") context.finish(GeneratorResult.GENERATED_NO_EXECUTABLE.apply(context, codeMaps)) } else if (context.mode == Mode.LSP_MEDIUM) { @@ -133,9 +132,9 @@ class CppGenerator( true) // copy or download reactor-cpp - if (!targetConfig.externalRuntimePath.isSet) { - if (targetConfig.runtimeVersion.isSet) { - fetchReactorCpp(targetConfig.runtimeVersion.get()) + if (!targetConfig.isSet(ExternalRuntimePathProperty())) { + if (targetConfig.isSet(RuntimeVersionProperty())) { + fetchReactorCpp(targetConfig.get(RuntimeVersionProperty())) } else { FileUtil.copyFromClassPath( "$libDir/reactor-cpp", diff --git a/core/src/main/kotlin/org/lflang/generator/cpp/CppPlatformGenerator.kt b/core/src/main/kotlin/org/lflang/generator/cpp/CppPlatformGenerator.kt index 82b881ea25..1c11055573 100644 --- a/core/src/main/kotlin/org/lflang/generator/cpp/CppPlatformGenerator.kt +++ b/core/src/main/kotlin/org/lflang/generator/cpp/CppPlatformGenerator.kt @@ -4,6 +4,11 @@ import org.lflang.MessageReporter import org.lflang.target.TargetConfig import org.lflang.generator.GeneratorCommandFactory import org.lflang.generator.LFGeneratorContext +import org.lflang.target.property.BuildTypeProperty +import org.lflang.target.property.LoggingProperty +import org.lflang.target.property.NoRuntimeValidationProperty +import org.lflang.target.property.PrintStatisticsProperty +import org.lflang.target.property.TracingProperty import org.lflang.toDefinition import java.nio.file.Path @@ -25,11 +30,11 @@ abstract class CppPlatformGenerator(protected val generator: CppGenerator) { protected val cmakeArgs: List get() = listOf( - "-DCMAKE_BUILD_TYPE=${targetConfig.buildType}", - "-DREACTOR_CPP_VALIDATE=${if (targetConfig.noRuntimeValidation.get()) "OFF" else "ON"}", - "-DREACTOR_CPP_PRINT_STATISTICS=${if (targetConfig.printStatistics.get()) "ON" else "OFF"}", - "-DREACTOR_CPP_TRACE=${if (targetConfig.tracing.get().isEnabled) "ON" else "OFF"}", - "-DREACTOR_CPP_LOG_LEVEL=${targetConfig.logLevel.get().severity}", + "-DCMAKE_BUILD_TYPE=${targetConfig.get(BuildTypeProperty())}", + "-DREACTOR_CPP_VALIDATE=${if (targetConfig.get(NoRuntimeValidationProperty())) "OFF" else "ON"}", + "-DREACTOR_CPP_PRINT_STATISTICS=${if (targetConfig.get(PrintStatisticsProperty())) "ON" else "OFF"}", + "-DREACTOR_CPP_TRACE=${if (targetConfig.get(TracingProperty()).isEnabled) "ON" else "OFF"}", + "-DREACTOR_CPP_LOG_LEVEL=${targetConfig.get(LoggingProperty()).severity}", "-DLF_SRC_PKG_PATH=${fileConfig.srcPkgPath}", ) } diff --git a/core/src/main/kotlin/org/lflang/generator/cpp/CppRos2NodeGenerator.kt b/core/src/main/kotlin/org/lflang/generator/cpp/CppRos2NodeGenerator.kt index e117a11b5a..f3078bc5b3 100644 --- a/core/src/main/kotlin/org/lflang/generator/cpp/CppRos2NodeGenerator.kt +++ b/core/src/main/kotlin/org/lflang/generator/cpp/CppRos2NodeGenerator.kt @@ -2,6 +2,9 @@ package org.lflang.generator.cpp import org.lflang.target.TargetConfig import org.lflang.lf.Reactor +import org.lflang.target.property.FastProperty +import org.lflang.target.property.TimeOutProperty +import org.lflang.target.property.WorkersProperty import org.lflang.toUnixString /** A C++ code generator for creating a ROS2 node from a main reactor definition */ @@ -57,9 +60,9 @@ class CppRos2NodeGenerator( | |$nodeName::$nodeName(const rclcpp::NodeOptions& node_options) | : Node("$nodeName", node_options) { - | unsigned workers = ${if (targetConfig.workers.get() != 0) targetConfig.workers.get() else "std::thread::hardware_concurrency()"}; - | bool fast{${targetConfig.fastMode}}; - | reactor::Duration lf_timeout{${if (targetConfig.timeout.isSet) targetConfig.timeout.get().toCppCode() else "reactor::Duration::max()"}}; + | unsigned workers = ${if (targetConfig.get(WorkersProperty()) != 0) targetConfig.get(WorkersProperty()) else "std::thread::hardware_concurrency()"}; + | bool fast{${targetConfig.get(FastProperty())}}; + | reactor::Duration lf_timeout{${if (targetConfig.isSet(TimeOutProperty())) targetConfig.get(TimeOutProperty()).toCppCode() else "reactor::Duration::max()"}}; | | // provide a globally accessible reference to this node | // FIXME: this is pretty hacky... diff --git a/core/src/main/kotlin/org/lflang/generator/cpp/CppRos2PackageGenerator.kt b/core/src/main/kotlin/org/lflang/generator/cpp/CppRos2PackageGenerator.kt index 49311d121a..83f1d0d57a 100644 --- a/core/src/main/kotlin/org/lflang/generator/cpp/CppRos2PackageGenerator.kt +++ b/core/src/main/kotlin/org/lflang/generator/cpp/CppRos2PackageGenerator.kt @@ -2,6 +2,10 @@ package org.lflang.generator.cpp import org.lflang.generator.PrependOperator import org.lflang.joinWithLn +import org.lflang.target.property.BuildTypeProperty +import org.lflang.target.property.CmakeIncludeProperty +import org.lflang.target.property.Ros2DependenciesProperty +import org.lflang.target.property.RuntimeVersionProperty import org.lflang.toUnixString import java.nio.file.Path @@ -9,11 +13,11 @@ import java.nio.file.Path class CppRos2PackageGenerator(generator: CppGenerator, private val nodeName: String) { private val fileConfig = generator.fileConfig private val targetConfig = generator.targetConfig - val reactorCppSuffix: String = if (targetConfig.runtimeVersion.isSet) targetConfig.runtimeVersion.get() else "default" + val reactorCppSuffix: String = if (targetConfig.isSet(RuntimeVersionProperty())) targetConfig.get(RuntimeVersionProperty()) else "default" val reactorCppName = "reactor-cpp-$reactorCppSuffix" private val dependencies = listOf("rclcpp", "rclcpp_components", reactorCppName) + ( - if (targetConfig.ros2Dependencies.isSet) targetConfig.ros2Dependencies.get() else listOf()) + if (targetConfig.isSet(Ros2DependenciesProperty())) targetConfig.get(Ros2DependenciesProperty()) else listOf()) @Suppress("PrivatePropertyName") // allows us to use capital S as variable name below private val S = '$' // a little trick to escape the dollar sign with $S @@ -48,7 +52,7 @@ class CppRos2PackageGenerator(generator: CppGenerator, private val nodeName: Str fun generatePackageCmake(sources: List): String { // Resolve path to the cmake include files if any was provided - val includeFiles = targetConfig.cmakeIncludes.get()?.map { fileConfig.srcPath.resolve(it).toUnixString() } + val includeFiles = targetConfig.get(CmakeIncludeProperty())?.map { fileConfig.srcPath.resolve(it).toUnixString() } return with(PrependOperator) { with(CppGenerator) { @@ -61,7 +65,7 @@ class CppRos2PackageGenerator(generator: CppGenerator, private val nodeName: Str |set(CMAKE_CXX_STANDARD_REQUIRED ON) |set(CMAKE_CXX_EXTENSIONS OFF) | - |set(DEFAULT_BUILD_TYPE "${targetConfig.buildType}") + |set(DEFAULT_BUILD_TYPE "${targetConfig.get(BuildTypeProperty())}") |if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) |set (CMAKE_BUILD_TYPE "$S{DEFAULT_BUILD_TYPE}" CACHE STRING "Choose the type of build." FORCE) |endif() diff --git a/core/src/main/kotlin/org/lflang/generator/cpp/CppStandaloneCmakeGenerator.kt b/core/src/main/kotlin/org/lflang/generator/cpp/CppStandaloneCmakeGenerator.kt index b456145342..22ea6e19c0 100644 --- a/core/src/main/kotlin/org/lflang/generator/cpp/CppStandaloneCmakeGenerator.kt +++ b/core/src/main/kotlin/org/lflang/generator/cpp/CppStandaloneCmakeGenerator.kt @@ -28,6 +28,10 @@ import org.lflang.FileConfig import org.lflang.target.TargetConfig import org.lflang.generator.PrependOperator import org.lflang.joinWithLn +import org.lflang.target.property.BuildTypeProperty +import org.lflang.target.property.CmakeIncludeProperty +import org.lflang.target.property.ExternalRuntimePathProperty +import org.lflang.target.property.RuntimeVersionProperty import org.lflang.toUnixString import java.nio.file.Path @@ -79,7 +83,7 @@ class CppStandaloneCmakeGenerator(private val targetConfig: TargetConfig, privat |include($S{CMAKE_ROOT}/Modules/ExternalProject.cmake) |include(GNUInstallDirs) | - |set(DEFAULT_BUILD_TYPE "${targetConfig.buildType}") + |set(DEFAULT_BUILD_TYPE "${targetConfig.get(BuildTypeProperty())}") |if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) |set (CMAKE_BUILD_TYPE "$S{DEFAULT_BUILD_TYPE}" CACHE STRING "Choose the type of build." FORCE) |endif() @@ -133,11 +137,11 @@ class CppStandaloneCmakeGenerator(private val targetConfig: TargetConfig, privat fun generateCmake(sources: List): String { // Resolve path to the cmake include files if any was provided - val includeFiles = targetConfig.cmakeIncludes.get()?.map { fileConfig.srcPath.resolve(it).toUnixString() } + val includeFiles = targetConfig.get(CmakeIncludeProperty())?.map { fileConfig.srcPath.resolve(it).toUnixString() } val reactorCppTarget = when { - targetConfig.externalRuntimePath.isSet -> "reactor-cpp" - targetConfig.runtimeVersion.isSet -> "reactor-cpp-${targetConfig.runtimeVersion}" + targetConfig.isSet(ExternalRuntimePathProperty()) -> "reactor-cpp" + targetConfig.isSet(RuntimeVersionProperty()) -> "reactor-cpp-${targetConfig.get(RuntimeVersionProperty())}" else -> "reactor-cpp-default" } @@ -146,7 +150,7 @@ class CppStandaloneCmakeGenerator(private val targetConfig: TargetConfig, privat |cmake_minimum_required(VERSION 3.5) |project(${fileConfig.name} VERSION 0.0.0 LANGUAGES CXX) | - |${if (targetConfig.externalRuntimePath != null) "find_package(reactor-cpp PATHS ${targetConfig.externalRuntimePath})" else ""} + |${if (targetConfig.get(ExternalRuntimePathProperty()) != null) "find_package(reactor-cpp PATHS ${targetConfig.get(ExternalRuntimePathProperty())})" else ""} | |set(LF_MAIN_TARGET ${fileConfig.name}) | diff --git a/core/src/main/kotlin/org/lflang/generator/cpp/CppStandaloneGenerator.kt b/core/src/main/kotlin/org/lflang/generator/cpp/CppStandaloneGenerator.kt index 8d21e05282..5f7adb4ae5 100644 --- a/core/src/main/kotlin/org/lflang/generator/cpp/CppStandaloneGenerator.kt +++ b/core/src/main/kotlin/org/lflang/generator/cpp/CppStandaloneGenerator.kt @@ -2,6 +2,8 @@ package org.lflang.generator.cpp import org.lflang.generator.CodeMap import org.lflang.generator.LFGeneratorContext +import org.lflang.target.property.BuildTypeProperty +import org.lflang.target.property.CompilerProperty import org.lflang.target.property.type.BuildTypeType.BuildType import org.lflang.toUnixString import org.lflang.util.FileUtil @@ -140,7 +142,7 @@ class CppStandaloneGenerator(generator: CppGenerator) : if (version.compareVersion("3.12.0") < 0) { messageReporter.nowhere().warning("CMAKE is older than version 3.12. Parallel building is not supported.") makeArgs = - listOf("--build", ".", "--target", target, "--config", buildTypeToCmakeConfig(targetConfig.buildType.get())) + listOf("--build", ".", "--target", target, "--config", buildTypeToCmakeConfig(targetConfig.get(BuildTypeProperty()))) } else { val cores = Runtime.getRuntime().availableProcessors() makeArgs = listOf( @@ -151,7 +153,7 @@ class CppStandaloneGenerator(generator: CppGenerator) : "--parallel", cores.toString(), "--config", - buildTypeToCmakeConfig(targetConfig.buildType.get()) + buildTypeToCmakeConfig(targetConfig.get(BuildTypeProperty())) ) } @@ -170,8 +172,8 @@ class CppStandaloneGenerator(generator: CppGenerator) : ) // prepare cmake - if (targetConfig.compiler != null) { - cmd.setEnvironmentVariable("CXX", targetConfig.compiler.get()) + if (targetConfig.get(CompilerProperty()) != null) { + cmd.setEnvironmentVariable("CXX", targetConfig.get(CompilerProperty())) } return cmd } diff --git a/core/src/main/kotlin/org/lflang/generator/cpp/CppStandaloneMainGenerator.kt b/core/src/main/kotlin/org/lflang/generator/cpp/CppStandaloneMainGenerator.kt index 9fb16455fe..c288222e25 100644 --- a/core/src/main/kotlin/org/lflang/generator/cpp/CppStandaloneMainGenerator.kt +++ b/core/src/main/kotlin/org/lflang/generator/cpp/CppStandaloneMainGenerator.kt @@ -5,6 +5,11 @@ import org.lflang.generator.PrependOperator import org.lflang.inferredType import org.lflang.lf.Parameter import org.lflang.lf.Reactor +import org.lflang.target.property.ExportDependencyGraphProperty +import org.lflang.target.property.ExportToYamlProperty +import org.lflang.target.property.FastProperty +import org.lflang.target.property.TimeOutProperty +import org.lflang.target.property.WorkersProperty import org.lflang.toUnixString /** C++ code generator responsible for generating the main file including the main() function */ @@ -58,9 +63,9 @@ class CppStandaloneMainGenerator( |int main(int argc, char **argv) { | cxxopts::Options options("${fileConfig.name}", "Reactor Program"); | - | unsigned workers = ${if (targetConfig.workers.get() != 0) targetConfig.workers.get() else "std::thread::hardware_concurrency()"}; - | bool fast{${targetConfig.fastMode.get()}}; - | reactor::Duration timeout = ${if (targetConfig.timeout.isSet) targetConfig.timeout.get().toCppCode() else "reactor::Duration::max()"}; + | unsigned workers = ${if (targetConfig.get(WorkersProperty()) != 0) targetConfig.get(WorkersProperty()) else "std::thread::hardware_concurrency()"}; + | bool fast{${targetConfig.get(FastProperty())}}; + | reactor::Duration timeout = ${if (targetConfig.isSet(TimeOutProperty())) targetConfig.get(TimeOutProperty()).toCppCode() else "reactor::Duration::max()"}; | | // the timeout variable needs to be tested beyond fitting the Duration-type | options @@ -68,7 +73,7 @@ class CppStandaloneMainGenerator( | .add_options() | ("w,workers", "the number of worker threads used by the scheduler", cxxopts::value(workers)->default_value(std::to_string(workers)), "'unsigned'") | ("o,timeout", "Time after which the execution is aborted.", cxxopts::value(timeout)->default_value(time_to_string(timeout)), "'FLOAT UNIT'") - | ("f,fast", "Allow logical time to run faster than physical time.", cxxopts::value(fast)->default_value("${targetConfig.fastMode}")) + | ("f,fast", "Allow logical time to run faster than physical time.", cxxopts::value(fast)->default_value("${targetConfig.get(FastProperty())}")) | ("help", "Print help"); | ${" |"..main.parameters.joinToString("\n\n") { generateParameterParser(it) }} @@ -96,8 +101,8 @@ class CppStandaloneMainGenerator( | | // assemble reactor program | e.assemble(); - ${" |".. if (targetConfig.exportDependencyGraph.get()) "e.export_dependency_graph(\"${main.name}.dot\");" else ""} - ${" |".. if (targetConfig.exportToYaml.get()) "e.dump_to_yaml(\"${main.name}.yaml\");" else ""} + ${" |".. if (targetConfig.get(ExportDependencyGraphProperty())) "e.export_dependency_graph(\"${main.name}.dot\");" else ""} + ${" |".. if (targetConfig.get(ExportToYamlProperty())) "e.dump_to_yaml(\"${main.name}.yaml\");" else ""} | | // start execution | auto thread = e.startup(); diff --git a/core/src/main/kotlin/org/lflang/generator/rust/RustGenerator.kt b/core/src/main/kotlin/org/lflang/generator/rust/RustGenerator.kt index b7d438d0dc..b9fc1a58db 100644 --- a/core/src/main/kotlin/org/lflang/generator/rust/RustGenerator.kt +++ b/core/src/main/kotlin/org/lflang/generator/rust/RustGenerator.kt @@ -36,6 +36,10 @@ import org.lflang.generator.TargetTypes import org.lflang.joinWithCommas import org.lflang.scoping.LFGlobalScopeProvider +import org.lflang.target.property.BuildTypeProperty +import org.lflang.target.property.CargoFeaturesProperty +import org.lflang.target.property.CompilerFlagsProperty +import org.lflang.target.property.NoCompileProperty import org.lflang.target.property.type.BuildTypeType import org.lflang.util.FileUtil import java.nio.file.Files @@ -78,7 +82,7 @@ class RustGenerator( val gen = RustModelBuilder.makeGenerationInfo(targetConfig, reactors, messageReporter) val codeMaps: Map = RustEmitter.generateRustProject(fileConfig, gen) - if (targetConfig.noCompile.get() || errorsOccurred()) { + if (targetConfig.get(NoCompileProperty()) || errorsOccurred()) { context.finish(GeneratorResult.GENERATED_NO_EXECUTABLE.apply(context, codeMaps)) println("Exiting before invoking target compiler.") } else { @@ -96,7 +100,7 @@ class RustGenerator( val args = mutableListOf().apply { this += "build" - val buildType = targetConfig.rust.getBuildType(context.targetConfig.buildType) + val buildType = targetConfig.get(BuildTypeProperty()) if (buildType == BuildTypeType.BuildType.RELEASE) { this += "--release" } else if (buildType != BuildTypeType.BuildType.DEBUG) { @@ -104,12 +108,12 @@ class RustGenerator( this += buildType.cargoProfileName } - if (targetConfig.rust.cargoFeatures.get().isNotEmpty()) { + if (targetConfig.get(CargoFeaturesProperty()).isNotEmpty()) { this += "--features" - this += targetConfig.rust.cargoFeatures.get().joinWithCommas() + this += targetConfig.get(CargoFeaturesProperty()).joinWithCommas() } - this += targetConfig.compilerFlags.get() + this += targetConfig.get(CompilerFlagsProperty()) this += listOf("--message-format", "json-diagnostic-rendered-ansi") } @@ -125,7 +129,7 @@ class RustGenerator( if (cargoReturnCode == 0) { // We still have to copy the compiled binary to the destination folder. - val buildType = targetConfig.rust.getBuildType(context.targetConfig.buildType) + val buildType = targetConfig.get(BuildTypeProperty()) val binaryPath = validator.metadata?.targetDirectory!! .resolve(buildType.cargoProfileName) .resolve(fileConfig.executable.fileName) 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 52f0e19608..82e0fc842c 100644 --- a/core/src/main/kotlin/org/lflang/generator/rust/RustModel.kt +++ b/core/src/main/kotlin/org/lflang/generator/rust/RustModel.kt @@ -32,6 +32,17 @@ import org.lflang.generator.* import org.lflang.lf.* import org.lflang.lf.Timer import org.lflang.target.TargetConfig +import org.lflang.target.property.CargoDependenciesProperty +import org.lflang.target.property.CargoFeaturesProperty +import org.lflang.target.property.ExportDependencyGraphProperty +import org.lflang.target.property.ExternalRuntimePathProperty +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.TimeOutProperty +import org.lflang.target.property.WorkersProperty import java.nio.file.Path import java.util.* @@ -429,7 +440,7 @@ object RustModelBuilder { val mainReactor = reactorsInfos.lastOrNull { it.isMain } ?: reactorsInfos.last() - val dependencies = targetConfig.rust.cargoDependencies.get().toMutableMap() + val dependencies = targetConfig.get(CargoDependenciesProperty()).toMutableMap() dependencies.compute(RustEmitterBase.runtimeCrateFullName) { _, spec -> computeDefaultRuntimeConfiguration(spec, targetConfig, messageReporter) } @@ -440,8 +451,8 @@ object RustModelBuilder { version = "1.0.0", authors = listOf(System.getProperty("user.name")), dependencies = dependencies, - modulesToIncludeInMain = targetConfig.rust.rustTopLevelModules.get(), - enabledCargoFeatures = targetConfig.rust.cargoFeatures.get().toSet() + modulesToIncludeInMain = targetConfig.get(RustIncludeProperty()), + enabledCargoFeatures = targetConfig.get(CargoFeaturesProperty()).toSet() ), reactors = reactorsInfos, mainReactor = mainReactor, @@ -479,25 +490,25 @@ object RustModelBuilder { // default configuration for the runtime crate // enable parallel feature if asked - val parallelFeature = listOf(PARALLEL_RT_FEATURE).takeIf { targetConfig.threading.get() } + val parallelFeature = listOf(PARALLEL_RT_FEATURE).takeIf { targetConfig.get(ThreadingProperty()) } val spec = newCargoSpec( features = parallelFeature, ) - if (targetConfig.externalRuntimePath.isSet) { - spec.localPath = targetConfig.externalRuntimePath.get() - } else if (targetConfig.runtimeVersion.isSet) { + if (targetConfig.isSet(ExternalRuntimePathProperty())) { + spec.localPath = targetConfig.get(ExternalRuntimePathProperty()) + } else if (targetConfig.isSet(RuntimeVersionProperty())) { spec.gitRepo = RustEmitterBase.runtimeGitUrl - spec.rev = targetConfig.runtimeVersion.get() + spec.rev = targetConfig.get(RuntimeVersionProperty()) } else { spec.useDefaultRuntimePath() } return spec } else { - if (targetConfig.externalRuntimePath.isSet) { - userSpec.localPath = targetConfig.externalRuntimePath.get() + if (targetConfig.isSet(ExternalRuntimePathProperty())) { + userSpec.localPath = targetConfig.get(ExternalRuntimePathProperty()) } if (userSpec.localPath == null && userSpec.gitRepo == null) { @@ -505,11 +516,11 @@ object RustModelBuilder { } // enable parallel feature if asked - if (targetConfig.threading.get()) { + if (targetConfig.get(ThreadingProperty())) { userSpec.features += PARALLEL_RT_FEATURE } - if (!targetConfig.threading.get() && PARALLEL_RT_FEATURE in userSpec.features) { + if (!targetConfig.get(ThreadingProperty()) && PARALLEL_RT_FEATURE in userSpec.features) { messageReporter.nowhere().warning("Threading cannot be disabled as it was enabled manually as a runtime feature.") } @@ -519,12 +530,12 @@ object RustModelBuilder { private fun TargetConfig.toRustProperties(): RustTargetProperties = RustTargetProperties( - keepAlive = this.keepalive.get(), - timeout = this.timeout.get()?.toRustTimeExpr(), - timeoutLf = this.timeout.get(), - singleFile = this.singleFileProject.get(), - workers = this.workers.get(), - dumpDependencyGraph = this.exportDependencyGraph.get(), + keepAlive = this.get(KeepaliveProperty()), + timeout = this.get(TimeOutProperty())?.toRustTimeExpr(), + timeoutLf = this.get(TimeOutProperty()), + singleFile = this.get(SingleFileProjectProperty()), + workers = this.get(WorkersProperty()), + dumpDependencyGraph = this.get(ExportDependencyGraphProperty()), ) private fun makeReactorInfos(reactors: List): List = diff --git a/core/src/main/kotlin/org/lflang/generator/ts/TSConstructorGenerator.kt b/core/src/main/kotlin/org/lflang/generator/ts/TSConstructorGenerator.kt index fe25d3207b..af945f1d88 100644 --- a/core/src/main/kotlin/org/lflang/generator/ts/TSConstructorGenerator.kt +++ b/core/src/main/kotlin/org/lflang/generator/ts/TSConstructorGenerator.kt @@ -6,6 +6,7 @@ import org.lflang.generator.PrependOperator import org.lflang.generator.getTargetInitializer import org.lflang.lf.Parameter import org.lflang.lf.Reactor +import org.lflang.target.property.CoordinationOptionsProperty import java.util.* /** @@ -77,7 +78,7 @@ class TSConstructorGenerator( // Generate code for setting target configurations. private fun generateTargetConfigurations(targetConfig: TargetConfig): String { - val interval = targetConfig.coordinationOptions.get().advanceMessageInterval + val interval = targetConfig.get(CoordinationOptionsProperty()).advanceMessageInterval return if ((reactor.isMain) && interval != null) { "this.setAdvanceMessageInterval(${interval.toTsTime()})" } else "" diff --git a/core/src/main/kotlin/org/lflang/generator/ts/TSGenerator.kt b/core/src/main/kotlin/org/lflang/generator/ts/TSGenerator.kt index 999b8fba54..7aafa6ad5a 100644 --- a/core/src/main/kotlin/org/lflang/generator/ts/TSGenerator.kt +++ b/core/src/main/kotlin/org/lflang/generator/ts/TSGenerator.kt @@ -35,6 +35,9 @@ import org.lflang.generator.GeneratorUtils.canGenerate import org.lflang.lf.Preamble import org.lflang.model import org.lflang.scoping.LFGlobalScopeProvider +import org.lflang.target.property.DockerProperty +import org.lflang.target.property.NoCompileProperty +import org.lflang.target.property.ProtobufsProperty import org.lflang.util.FileUtil import java.nio.file.Files import java.nio.file.Path @@ -117,7 +120,7 @@ class TSGenerator( val codeMaps = HashMap() generateCode(codeMaps, resource.model.preambles) - if (targetConfig.dockerOptions.get().enabled) { + if (targetConfig.get(DockerProperty()).enabled) { val dockerData = TSDockerGenerator(context).generateDockerData(); dockerData.writeDockerFile() DockerComposeGenerator(context).writeDockerComposeFile(listOf(dockerData)) @@ -125,7 +128,7 @@ class TSGenerator( // For small programs, everything up until this point is virtually instantaneous. This is the point where cancellation, // progress reporting, and IDE responsiveness become real considerations. - if (context.mode != LFGeneratorContext.Mode.LSP_MEDIUM && targetConfig.noCompile.get()) { + if (context.mode != LFGeneratorContext.Mode.LSP_MEDIUM && targetConfig.get(NoCompileProperty())) { context.finish(GeneratorResult.GENERATED_NO_EXECUTABLE.apply(context, null)) } else { context.reportProgress( @@ -136,7 +139,7 @@ class TSGenerator( context.unsuccessfulFinish() return } - if (targetConfig.protoFiles.get().size != 0) { + if (targetConfig.get(ProtobufsProperty()).size != 0) { protoc() } else { println("No .proto files have been imported. Skipping protocol buffer compilation.") @@ -240,7 +243,7 @@ class TSGenerator( val tsCode = StringBuilder() val preambleGenerator = TSImportPreambleGenerator(fileConfig.srcFile, - targetConfig.protoFiles.get(), preambles) + targetConfig.get(ProtobufsProperty()), preambles) tsCode.append(preambleGenerator.generatePreamble()) val parameterGenerator = TSParameterPreambleGenerator(fileConfig, targetConfig, reactors) @@ -342,7 +345,7 @@ class TSGenerator( } private fun installProtoBufsIfNeeded(pnpmIsAvailable: Boolean, cwd: Path, cancelIndicator: CancelIndicator) { - if (targetConfig.protoFiles.get().size != 0) { + if (targetConfig.get(ProtobufsProperty()).size != 0) { commandFactory.createCommand( if (pnpmIsAvailable) "pnpm" else "npm", listOf("install", "google-protobuf"), @@ -369,7 +372,7 @@ class TSGenerator( "--ts_out=$tsOutPath" ) ) - protocArgs.addAll(targetConfig.protoFiles.get()) + protocArgs.addAll(targetConfig.get(ProtobufsProperty())) val protoc = commandFactory.createCommand("protoc", protocArgs, fileConfig.srcPath) if (protoc == null) { diff --git a/core/src/main/kotlin/org/lflang/generator/ts/TSParameterPreambleGenerator.kt b/core/src/main/kotlin/org/lflang/generator/ts/TSParameterPreambleGenerator.kt index 4efc48d045..e4e59ffc40 100644 --- a/core/src/main/kotlin/org/lflang/generator/ts/TSParameterPreambleGenerator.kt +++ b/core/src/main/kotlin/org/lflang/generator/ts/TSParameterPreambleGenerator.kt @@ -30,6 +30,10 @@ import org.lflang.target.TargetConfig import org.lflang.joinWithLn import org.lflang.lf.Parameter import org.lflang.lf.Reactor +import org.lflang.target.property.FastProperty +import org.lflang.target.property.KeepaliveProperty +import org.lflang.target.property.LoggingProperty +import org.lflang.target.property.TimeOutProperty import java.util.StringJoiner /** @@ -49,7 +53,7 @@ class TSParameterPreambleGenerator( ) { private fun getTimeoutTimeValue(): String = - targetConfig.timeout.get()?.toTsTime() ?: "undefined" + targetConfig.get(TimeOutProperty())?.toTsTime() ?: "undefined" private fun getParameters(): List { var mainReactor: Reactor? = null @@ -162,8 +166,8 @@ class TSParameterPreambleGenerator( val codeText = """ |// ************* App Parameters |let __timeout: TimeValue | undefined = ${getTimeoutTimeValue()}; - |let __keepAlive: boolean = ${targetConfig.keepalive}; - |let __fast: boolean = ${targetConfig.fastMode}; + |let __keepAlive: boolean = ${targetConfig.get(KeepaliveProperty())}; + |let __fast: boolean = ${targetConfig.get(FastProperty())}; |let __federationID: string = 'Unidentified Federation' | |let __noStart = false; // If set to true, don't start the app. @@ -235,7 +239,7 @@ class TSParameterPreambleGenerator( | throw new Error("'logging' command line argument is malformed."); | } |} else { - | Log.global.level = Log.levels.${targetConfig.logLevel.get().name}; // Default from target property. + | Log.global.level = Log.levels.${targetConfig.get(LoggingProperty()).name}; // Default from target property. |} | |// Help parameter (not a constructor parameter, but a command line option) 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 695be5abee..8123bff865 100644 --- a/core/src/test/java/org/lflang/tests/compiler/LinguaFrancaValidationTest.java +++ b/core/src/test/java/org/lflang/tests/compiler/LinguaFrancaValidationTest.java @@ -1494,7 +1494,7 @@ private Model createModel(AbstractTargetProperty property, String value) throws public Collection checkTargetProperties() throws Exception { List result = new ArrayList<>(); - for (AbstractTargetProperty property : TargetConfig.getUserTargetProperties()) { + for (AbstractTargetProperty property : (new TargetConfig(Target.C)).getRegisteredProperties()) { if (property instanceof CargoDependenciesProperty) { // we test that separately as it has better error messages continue; diff --git a/core/src/testFixtures/java/org/lflang/tests/Configurators.java b/core/src/testFixtures/java/org/lflang/tests/Configurators.java index 7191efe494..7febf6cefc 100644 --- a/core/src/testFixtures/java/org/lflang/tests/Configurators.java +++ b/core/src/testFixtures/java/org/lflang/tests/Configurators.java @@ -24,6 +24,9 @@ package org.lflang.tests; +import org.lflang.target.property.LoggingProperty; +import org.lflang.target.property.PlatformProperty; +import org.lflang.target.property.ThreadingProperty; import org.lflang.target.property.type.LoggingType.LogLevel; import org.lflang.target.property.type.PlatformType.Platform; import org.lflang.tests.TestRegistry.TestCategory; @@ -65,26 +68,26 @@ public static boolean disableThreading(LFTest test) { public static boolean makeZephyrCompatibleUnthreaded(LFTest test) { test.getContext().getArgs().setProperty("tracing", "false"); - test.getContext().getTargetConfig().threading.override(false); + test.getContext().getTargetConfig().override(new ThreadingProperty(), false); // FIXME: use a record and override. - test.getContext().getTargetConfig().platformOptions.get().platform = Platform.ZEPHYR; - test.getContext().getTargetConfig().platformOptions.get().flash = false; - test.getContext().getTargetConfig().platformOptions.get().board = "qemu_cortex_m3"; + test.getContext().getTargetConfig().get(new PlatformProperty()).platform = Platform.ZEPHYR; + test.getContext().getTargetConfig().get(new PlatformProperty()).flash = false; + test.getContext().getTargetConfig().get(new PlatformProperty()).board = "qemu_cortex_m3"; // FIXME: Zephyr emulations fails with debug log-levels. - test.getContext().getTargetConfig().logLevel.override(LogLevel.WARN); + test.getContext().getTargetConfig().override(new LoggingProperty(), LogLevel.WARN); test.getContext().getArgs().setProperty("logging", "warning"); return true; } public static boolean makeZephyrCompatible(LFTest test) { test.getContext().getArgs().setProperty("tracing", "false"); - test.getContext().getTargetConfig().platformOptions.get().platform = Platform.ZEPHYR; - test.getContext().getTargetConfig().platformOptions.get().flash = false; - test.getContext().getTargetConfig().platformOptions.get().board = "qemu_cortex_m3"; + test.getContext().getTargetConfig().get(new PlatformProperty()).platform = Platform.ZEPHYR; + test.getContext().getTargetConfig().get(new PlatformProperty()).flash = false; + test.getContext().getTargetConfig().get(new PlatformProperty()).board = "qemu_cortex_m3"; // FIXME: Zephyr emulations fails with debug log-levels. - test.getContext().getTargetConfig().logLevel.override(LogLevel.WARN); + test.getContext().getTargetConfig().override(new LoggingProperty(), LogLevel.WARN); test.getContext().getArgs().setProperty("logging", "warning"); return true; diff --git a/core/src/testFixtures/java/org/lflang/tests/TestBase.java b/core/src/testFixtures/java/org/lflang/tests/TestBase.java index 64bcdbe42e..2e125ffaa2 100644 --- a/core/src/testFixtures/java/org/lflang/tests/TestBase.java +++ b/core/src/testFixtures/java/org/lflang/tests/TestBase.java @@ -45,6 +45,7 @@ import org.lflang.generator.LFGeneratorContext.BuildParm; import org.lflang.generator.MainContext; import org.lflang.target.TargetConfig; +import org.lflang.target.property.LoggingProperty; import org.lflang.tests.Configurators.Configurator; import org.lflang.tests.LFTest.Result; import org.lflang.tests.TestRegistry.TestCategory; @@ -438,7 +439,7 @@ private void validate(LFTest test) throws TestError { /** Override to add some LFC arguments to all runs of this test class. */ protected void addExtraLfcArgs(Properties args, TargetConfig targetConfig) { args.setProperty("build-type", "Test"); - if (!targetConfig.logLevel.isSet()) args.setProperty("logging", "Debug"); + if (!targetConfig.isSet(new LoggingProperty())) args.setProperty("logging", "Debug"); } /** From 9aec15284fbee14aa82771bddb6f9e74edfa5490 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Thu, 5 Oct 2023 00:29:38 -0700 Subject: [PATCH 073/145] Further refactoring. Next: fixes and cleanup. --- .../org/lflang/AbstractTargetProperty.java | 109 +++++++----------- .../federated/generator/FedTargetConfig.java | 43 ++++++- .../org/lflang/generator/GeneratorUtils.java | 3 +- .../java/org/lflang/target/TargetConfig.java | 65 ++++++++++- .../org/lflang/target/TargetProperty.java | 86 +------------- .../property/AbstractBooleanProperty.java | 4 +- .../property/AbstractFileListProperty.java | 13 +-- .../target/property/AbstractStringConfig.java | 4 +- .../property/AbstractStringListProperty.java | 31 ++--- .../property/BuildCommandsProperty.java | 4 +- .../target/property/BuildTypeProperty.java | 4 +- .../property/CargoDependenciesProperty.java | 7 +- .../property/ClockSyncModeProperty.java | 4 +- .../property/ClockSyncOptionsProperty.java | 18 +-- .../target/property/CmakeIncludeProperty.java | 24 ++-- .../property/CompileDefinitionsProperty.java | 12 +- .../property/CoordinationOptionsProperty.java | 6 +- .../target/property/CoordinationProperty.java | 4 +- .../target/property/DockerProperty.java | 10 +- .../target/property/FedSetupProperty.java | 4 +- .../target/property/LoggingProperty.java | 4 +- .../target/property/PlatformProperty.java | 14 +-- .../property/Ros2DependenciesProperty.java | 4 +- .../target/property/RustIncludeProperty.java | 11 +- .../target/property/SchedulerProperty.java | 4 +- .../target/property/TimeOutProperty.java | 4 +- .../target/property/TracingProperty.java | 10 +- .../target/property/WorkersProperty.java | 4 +- 28 files changed, 241 insertions(+), 269 deletions(-) diff --git a/core/src/main/java/org/lflang/AbstractTargetProperty.java b/core/src/main/java/org/lflang/AbstractTargetProperty.java index 9b854a660e..19745ba27f 100644 --- a/core/src/main/java/org/lflang/AbstractTargetProperty.java +++ b/core/src/main/java/org/lflang/AbstractTargetProperty.java @@ -5,6 +5,7 @@ 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; /** @@ -17,17 +18,9 @@ */ public abstract class AbstractTargetProperty { - /** The type of values that can be assigned to this property. */ + /** The type of values assignable to this target property. */ public final S type; - /** Whether (after initialization) this property has been set. */ - protected boolean isSet; - - /** - * The value assigned to the target property, initialized using the {@code initialValue()} method. - */ - private T value = initialValue(); - /** * Construct a new target property. * @@ -74,14 +67,6 @@ public void checkType(KeyValuePair pair, MessageReporter reporter) { } } - /** - * Return {@code true} if this target property has been set (past initialization), {@code false} - * otherwise. - */ - public boolean isSet() { - return isSet; - } - /** * Return {@code true} if this target property is supported by the given target, {@code false} * otherwise. @@ -92,52 +77,37 @@ public final boolean isSupported(Target target) { return supportedTargets().contains(target); } - /** - * Manually override the value of this target property. - * - * @param value The value to assign to this target property. - */ - public void override(T value) { - this.isSet = true; - this.value = value; - } - - /** Reset this target property to its initial value. */ - public void reset() { - this.value = initialValue(); - this.isSet = false; - } - - /** - * Parse the given AST node into the given target config. Encountered errors are reported via the - * given reporter. - * - * @param node The AST node to derive a newly assigned value from. - * @param reporter A reporter for reporting errors. - */ - public void set(Element node, MessageReporter reporter) { - var parsed = this.fromAst(node, reporter); - if (parsed != null) { - this.isSet = true; - this.value = parsed; - } - } - - /** - * Parse the given element into the given target config. May use the error reporter to report - * format errors. - */ - public void set(String value, MessageReporter err) { - var parsed = this.fromString(value, err); - if (parsed != null) { - this.isSet = true; - this.value = parsed; - } - } + // /** + // * Parse the given AST node into the given target config. Encountered errors are reported via + // the + // * given reporter. + // * + // * @param node The AST node to derive a newly assigned value from. + // * @param reporter A reporter for reporting errors. + // */ + // public void set(Element node, MessageReporter reporter) { + // var parsed = this.fromAst(node, reporter); + // if (parsed != null) { + // this.isSet = true; + // this.value = parsed; + // } + // } + + // /** + // * Parse the given element into the given target config. May use the error reporter to report + // * format errors. + // */ + // public void set(String value, MessageReporter err) { + // var parsed = this.fromString(value, err); + // if (parsed != null) { + // this.isSet = true; + // this.value = parsed; + // } + // } @Override public String toString() { - return value == null ? "" : value.toString(); + return this.name(); } /** @@ -155,11 +125,6 @@ public void validate(KeyValuePair pair, Model ast, MessageReporter reporter) {} /** Return the initial value to assign to this target property. */ public abstract T initialValue(); - /** Return the value currently assigned to this target property. */ - public T get() { - return value; - } - /** * Given an AST node, produce a corresponding value that is assignable to this target property, or * report an error via the given reporter in case any problems are encountered. @@ -186,8 +151,20 @@ public T get() { /** * Return an AST node that represents this target property and the value currently assigned to it. */ - public abstract Element toAstElement(); + public abstract Element toAstElement(T value); /** Return the name of this target property (in kebab case). */ public abstract String name(); + + protected void update(TargetConfig config, T value) { + config.set(this, value); + } + + public void update(TargetConfig config, Element node, MessageReporter reporter) { + this.update(config, fromAst(node, reporter)); + } + + public void update(TargetConfig config, String value, MessageReporter reporter) { + this.update(config, fromString(value, reporter)); + } } diff --git a/core/src/main/java/org/lflang/federated/generator/FedTargetConfig.java b/core/src/main/java/org/lflang/federated/generator/FedTargetConfig.java index 008ee3f85c..7283ae5261 100644 --- a/core/src/main/java/org/lflang/federated/generator/FedTargetConfig.java +++ b/core/src/main/java/org/lflang/federated/generator/FedTargetConfig.java @@ -3,12 +3,16 @@ import static org.lflang.ast.ASTUtils.convertToEmptyListIfNull; import java.nio.file.Path; +import java.util.List; +import java.util.Objects; import org.eclipse.emf.ecore.resource.Resource; import org.lflang.MessageReporter; +import org.lflang.ast.ASTUtils; import org.lflang.generator.GeneratorUtils; import org.lflang.generator.LFGeneratorContext; +import org.lflang.lf.KeyValuePair; +import org.lflang.lf.LfFactory; import org.lflang.target.TargetConfig; -import org.lflang.target.TargetProperty; import org.lflang.target.property.ClockSyncModeProperty; import org.lflang.target.property.ClockSyncOptionsProperty; import org.lflang.util.FileUtil; @@ -60,7 +64,7 @@ private void mergeImportedConfig( var targetProperties = importedTargetDecl.getConfig(); if (targetProperties != null) { // Merge properties - TargetProperty.update( + update( this, convertToEmptyListIfNull(targetProperties.getPairs()), getRelativePath(mainResource, federateResource), @@ -80,4 +84,39 @@ private void clearPropertiesToIgnore() { this.reset(new ClockSyncModeProperty()); this.reset(new ClockSyncOptionsProperty()); } + + /** + * Update the given configuration using the given target properties. + * + * @param config The configuration object to update. + * @param pairs AST node that holds all the target properties. + * @param relativePath The path from the main resource to the resource from which the new + * properties originate. + */ + public void update( + TargetConfig config, List pairs, Path relativePath, MessageReporter err) { + pairs.forEach( + pair -> { + var p = config.forName(pair.getName()); + if (p.isPresent()) { + var value = pair.getValue(); + 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); + } + p.get().update(this, value, err); + } + }); + } } diff --git a/core/src/main/java/org/lflang/generator/GeneratorUtils.java b/core/src/main/java/org/lflang/generator/GeneratorUtils.java index 4ee4f070b2..e846bb03dc 100644 --- a/core/src/main/java/org/lflang/generator/GeneratorUtils.java +++ b/core/src/main/java/org/lflang/generator/GeneratorUtils.java @@ -23,7 +23,6 @@ import org.lflang.lf.Reactor; import org.lflang.lf.TargetDecl; import org.lflang.target.TargetConfig; -import org.lflang.target.TargetProperty; import org.lflang.target.property.KeepaliveProperty; /** @@ -123,7 +122,7 @@ public static LFResource getLFResource( var targetConfig = new TargetConfig(Target.fromDecl(target)); if (config != null) { List pairs = config.getPairs(); - TargetProperty.load(targetConfig, pairs != null ? pairs : List.of(), messageReporter); + targetConfig.load(pairs != null ? pairs : List.of(), messageReporter); } FileConfig fc = LFGenerator.createFileConfig( diff --git a/core/src/main/java/org/lflang/target/TargetConfig.java b/core/src/main/java/org/lflang/target/TargetConfig.java index 868a5f3f9b..f58a3e1ed3 100644 --- a/core/src/main/java/org/lflang/target/TargetConfig.java +++ b/core/src/main/java/org/lflang/target/TargetConfig.java @@ -147,11 +147,11 @@ public TargetConfig(Properties cliArgs, TargetDecl target, MessageReporter messa this(Target.fromDecl(target)); if (target.getConfig() != null) { List pairs = target.getConfig().getPairs(); - TargetProperty.load(this, pairs, messageReporter); + this.load(pairs, messageReporter); } if (cliArgs != null) { - TargetProperty.load(this, cliArgs, messageReporter); + this.load(cliArgs, messageReporter); } } @@ -161,7 +161,7 @@ public TargetConfig(Properties cliArgs, TargetDecl target, MessageReporter messa /** Flags to pass to the linker, unless a build command has been specified. */ public String linkerFlags = ""; - private final Map, Object> properties = new HashMap<>(); + protected final Map, Object> properties = new HashMap<>(); private final Set> setProperties = new HashSet<>(); @@ -170,22 +170,33 @@ public void register(AbstractTargetProperty... properties) { .forEach(property -> this.properties.put(property, property.initialValue())); } + /** + * Manually override the value of this target property. + * + * @param value The value to assign to this target property. + */ public void override( AbstractTargetProperty property, T value) { this.setProperties.add(property); this.properties.put(property, value); } - public void reset(AbstractTargetProperty property) { + /** Reset this target property to its initial value (and mark it as unset). */ + public void reset(AbstractTargetProperty property) { this.properties.remove(property); this.setProperties.remove(property); } + /** Return the value currently assigned to the given target property. */ @SuppressWarnings("unchecked") public T get(AbstractTargetProperty property) { return (T) properties.get(property); } + /** + * Return {@code true} if this target property has been set (past initialization), {@code false} + * otherwise. + */ public boolean isSet(AbstractTargetProperty property) { return this.setProperties.contains(property); } @@ -197,7 +208,7 @@ public String listOfRegisteredProperties() { .collect(Collectors.joining(", ")); } - public List getRegisteredProperties() { + public List> getRegisteredProperties() { return this.properties.keySet().stream() .sorted((p1, p2) -> p1.getClass().getName().compareTo(p2.getClass().getName())) .collect(Collectors.toList()); @@ -208,9 +219,51 @@ public List getRegisteredProperties() { * * @param name The string to match against. */ - public Optional forName(String name) { + public Optional> forName(String name) { return this.getRegisteredProperties().stream() .filter(c -> c.name().equalsIgnoreCase(name)) .findFirst(); } + + public void load(Properties properties, MessageReporter err) { + for (Object key : properties.keySet()) { + var p = this.forName(key.toString()); + if (p.isPresent()) { + var property = p.get(); + property.update(this, (String) properties.get(key), err); + } else { + throw new RuntimeException("Attempting to load unrecognized target property"); + } + } + } + + /** + * Set the configuration using the given pairs from the AST. + * + * @param pairs AST node that holds all the target properties. + * @param err Error reporter on which property format errors will be reported + */ + public void load(List pairs, MessageReporter err) { + if (pairs == null) { + return; + } + pairs.forEach( + pair -> { + var p = forName(pair.getName()); + if (p.isPresent()) { + var property = p.get(); + property.update(this, pair.getValue(), err); + } + }); + } + + public void set( + AbstractTargetProperty property, T value) { + this.setProperties.add(property); + this.properties.put(property, value); + } + + public void markSet(AbstractTargetProperty property) { + this.setProperties.add(property); + } } diff --git a/core/src/main/java/org/lflang/target/TargetProperty.java b/core/src/main/java/org/lflang/target/TargetProperty.java index c47386981d..7f24e131f5 100644 --- a/core/src/main/java/org/lflang/target/TargetProperty.java +++ b/core/src/main/java/org/lflang/target/TargetProperty.java @@ -25,17 +25,11 @@ package org.lflang.target; -import java.nio.file.Path; import java.util.LinkedList; import java.util.List; -import java.util.Objects; -import java.util.Properties; import java.util.stream.Collectors; import org.lflang.AbstractTargetProperty; -import org.lflang.MessageReporter; import org.lflang.Target; -import org.lflang.ast.ASTUtils; -import org.lflang.generator.InvalidLfSourceException; import org.lflang.lf.KeyValuePair; import org.lflang.lf.KeyValuePairs; import org.lflang.lf.LfFactory; @@ -52,43 +46,6 @@ */ public class TargetProperty { - public static void load(TargetConfig config, Properties properties, MessageReporter err) { - for (Object key : properties.keySet()) { - var p = config.forName(key.toString()); - if (p.isPresent()) { - try { - p.get().set(properties.get(key).toString(), err); - } catch (InvalidLfSourceException e) { - err.at(e.getNode()).error(e.getProblem()); - } - } - } - } - - /** - * Set the given configuration using the given target properties. - * - * @param config The configuration object to update. - * @param properties AST node that holds all the target properties. - * @param err Error reporter on which property format errors will be reported - */ - public static void load(TargetConfig config, List properties, MessageReporter err) { - if (properties == null) { - return; - } - properties.forEach( - property -> { - var p = config.forName(property.getName()); - if (p.isPresent()) { - try { - p.get().set(property.getValue(), err); - } catch (InvalidLfSourceException e) { - err.at(e.getNode()).error(e.getProblem()); - } - } - }); - } - /** * Extracts all properties as a list of key-value pairs from a TargetConfig. Only extracts * properties explicitly set by user. @@ -96,12 +53,13 @@ public static void load(TargetConfig config, List properties, Mess * @param config The TargetConfig to extract from. * @return The extracted properties. */ - public static List extractProperties(TargetConfig config) { + public static List extractProperties( + TargetConfig config) { // FIXME: move to TargetConfig var res = new LinkedList(); for (AbstractTargetProperty p : TargetProperty.loaded(config)) { KeyValuePair kv = LfFactory.eINSTANCE.createKeyValuePair(); kv.setName(p.name()); - kv.setValue(p.toAstElement()); + kv.setValue(p.toAstElement(config.get(p))); if (kv.getValue() != null) { res.add(kv); } @@ -114,7 +72,8 @@ public static List extractProperties(TargetConfig config) { * * @param config The configuration to find the properties in. */ - public static List loaded(TargetConfig config) { + public static List loaded( + TargetConfig config) { // FIXME: move to target config return config.getRegisteredProperties().stream() .filter(p -> config.isSet(p)) .collect(Collectors.toList()); @@ -188,39 +147,4 @@ public static void validate( } }); } - - /** - * Update the given configuration using the given target properties. - * - * @param config The configuration object to update. - * @param properties AST node that holds all the target properties. - * @param relativePath The path from the main resource to the resource from which the new - * properties originate. - */ - public static void update( - TargetConfig config, List properties, Path relativePath, MessageReporter err) { - properties.forEach( - property -> { - var p = config.forName(property.getName()); - if (p.isPresent()) { - var value = property.getValue(); - if (property.getName().equals("files")) { - var array = LfFactory.eINSTANCE.createArray(); - ASTUtils.elementToListOfStrings(property.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); - } - p.get().set(value, err); - } - }); - } } diff --git a/core/src/main/java/org/lflang/target/property/AbstractBooleanProperty.java b/core/src/main/java/org/lflang/target/property/AbstractBooleanProperty.java index 91530c9db7..9e6c2bc56c 100644 --- a/core/src/main/java/org/lflang/target/property/AbstractBooleanProperty.java +++ b/core/src/main/java/org/lflang/target/property/AbstractBooleanProperty.java @@ -29,7 +29,7 @@ protected Boolean fromString(String string, MessageReporter reporter) { } @Override - public Element toAstElement() { - return ASTUtils.toElement(get()); + public Element toAstElement(Boolean value) { + return ASTUtils.toElement(value); } } diff --git a/core/src/main/java/org/lflang/target/property/AbstractFileListProperty.java b/core/src/main/java/org/lflang/target/property/AbstractFileListProperty.java index 3d866c62fe..bcdab64c96 100644 --- a/core/src/main/java/org/lflang/target/property/AbstractFileListProperty.java +++ b/core/src/main/java/org/lflang/target/property/AbstractFileListProperty.java @@ -6,6 +6,7 @@ import org.lflang.MessageReporter; import org.lflang.ast.ASTUtils; import org.lflang.lf.Element; +import org.lflang.target.TargetConfig; import org.lflang.target.property.type.UnionType; public abstract class AbstractFileListProperty @@ -21,11 +22,9 @@ public List initialValue() { } @Override - public void set(Element node, MessageReporter reporter) { - if (!this.isSet) { - super.set(node, reporter); - } else { - this.get().addAll(fromAst(node, reporter)); + public void update(TargetConfig config, Element node, MessageReporter reporter) { + if (config.isSet(this)) { + config.get(this).addAll(fromAst(node, reporter)); } } @@ -40,7 +39,7 @@ protected List fromString(String string, MessageReporter reporter) { } @Override - public Element toAstElement() { - return ASTUtils.toElement(get()); + public Element toAstElement(List value) { + return ASTUtils.toElement(value); } } diff --git a/core/src/main/java/org/lflang/target/property/AbstractStringConfig.java b/core/src/main/java/org/lflang/target/property/AbstractStringConfig.java index d4dcb9a3d3..a82bbd0e26 100644 --- a/core/src/main/java/org/lflang/target/property/AbstractStringConfig.java +++ b/core/src/main/java/org/lflang/target/property/AbstractStringConfig.java @@ -28,7 +28,7 @@ protected String fromString(String string, MessageReporter reporter) { } @Override - public Element toAstElement() { - return ASTUtils.toElement(this.get()); + public Element toAstElement(String value) { + return ASTUtils.toElement(value); } } diff --git a/core/src/main/java/org/lflang/target/property/AbstractStringListProperty.java b/core/src/main/java/org/lflang/target/property/AbstractStringListProperty.java index 71ffbe500b..b0f78109ed 100644 --- a/core/src/main/java/org/lflang/target/property/AbstractStringListProperty.java +++ b/core/src/main/java/org/lflang/target/property/AbstractStringListProperty.java @@ -6,6 +6,7 @@ import org.lflang.MessageReporter; import org.lflang.ast.ASTUtils; import org.lflang.lf.Element; +import org.lflang.target.TargetConfig; import org.lflang.target.property.type.UnionType; /** Note: {@code set} implements an "append" semantics. */ @@ -16,10 +17,9 @@ public AbstractStringListProperty() { super(UnionType.STRING_OR_STRING_ARRAY); } - public void add(String entry) { - this.isSet = true; - var value = this.get(); - value.add(entry); + public void add(TargetConfig config, String entry) { + config.markSet(this); + config.get(this).add(entry); } @Override @@ -28,20 +28,9 @@ public List initialValue() { } @Override - public void set(Element node, MessageReporter reporter) { - if (!this.isSet) { - super.set(node, reporter); - } else { - this.get().addAll(this.fromAst(node, reporter)); - } - } - - @Override - public void set(String string, MessageReporter err) { - if (!this.isSet) { - super.set(string, err); - } else { - this.get().addAll(this.fromString(string, err)); + public void update(TargetConfig config, Element node, MessageReporter reporter) { + if (config.isSet(this)) { + config.get(this).addAll(fromAst(node, reporter)); } } @@ -52,11 +41,11 @@ public List fromAst(Element node, MessageReporter reporter) { @Override protected List fromString(String string, MessageReporter reporter) { - return List.of(string.split(" ")); + return List.of(string.split(" ")); // FIXME: this does not look right } @Override - public Element toAstElement() { - return ASTUtils.toElement(get()); + public Element toAstElement(List value) { + return ASTUtils.toElement(value); } } diff --git a/core/src/main/java/org/lflang/target/property/BuildCommandsProperty.java b/core/src/main/java/org/lflang/target/property/BuildCommandsProperty.java index 29a35fb2b9..19ccaba064 100644 --- a/core/src/main/java/org/lflang/target/property/BuildCommandsProperty.java +++ b/core/src/main/java/org/lflang/target/property/BuildCommandsProperty.java @@ -42,8 +42,8 @@ public List supportedTargets() { } @Override - public Element toAstElement() { - return ASTUtils.toElement(this.get().toString()); + public Element toAstElement(List value) { + return ASTUtils.toElement(value); } @Override diff --git a/core/src/main/java/org/lflang/target/property/BuildTypeProperty.java b/core/src/main/java/org/lflang/target/property/BuildTypeProperty.java index c613ac5c42..48def1278c 100644 --- a/core/src/main/java/org/lflang/target/property/BuildTypeProperty.java +++ b/core/src/main/java/org/lflang/target/property/BuildTypeProperty.java @@ -21,8 +21,8 @@ public BuildTypeProperty() { } @Override - public Element toAstElement() { - return ASTUtils.toElement(this.get().toString()); + public Element toAstElement(BuildType value) { + return ASTUtils.toElement(value.toString()); } @Override 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 859b697a13..95a95790c1 100644 --- a/core/src/main/java/org/lflang/target/property/CargoDependenciesProperty.java +++ b/core/src/main/java/org/lflang/target/property/CargoDependenciesProperty.java @@ -68,14 +68,13 @@ public List supportedTargets() { } @Override - public Element toAstElement() { - var deps = this.get(); - if (deps.size() == 0) { + public Element toAstElement(Map value) { + if (value.size() == 0) { return null; } else { Element e = LfFactory.eINSTANCE.createElement(); KeyValuePairs kvp = LfFactory.eINSTANCE.createKeyValuePairs(); - for (var ent : deps.entrySet()) { + for (var ent : value.entrySet()) { KeyValuePair pair = LfFactory.eINSTANCE.createKeyValuePair(); pair.setName(ent.getKey()); pair.setValue(CargoDependencySpec.extractSpec(ent.getValue())); 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 bc7fa61f09..06863f3a01 100644 --- a/core/src/main/java/org/lflang/target/property/ClockSyncModeProperty.java +++ b/core/src/main/java/org/lflang/target/property/ClockSyncModeProperty.java @@ -62,8 +62,8 @@ public void validate(KeyValuePair pair, Model ast, MessageReporter reporter) { } @Override - public Element toAstElement() { - return ASTUtils.toElement(this.get().toString()); + public Element toAstElement(ClockSyncMode value) { + return ASTUtils.toElement(value.toString()); } @Override 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 6cb0d76d8a..d84fefe76c 100644 --- a/core/src/main/java/org/lflang/target/property/ClockSyncOptionsProperty.java +++ b/core/src/main/java/org/lflang/target/property/ClockSyncOptionsProperty.java @@ -61,29 +61,29 @@ public List supportedTargets() { } @Override - public Element toAstElement() { + public Element toAstElement(ClockSyncOptions value) { Element e = LfFactory.eINSTANCE.createElement(); KeyValuePairs kvp = LfFactory.eINSTANCE.createKeyValuePairs(); for (ClockSyncOption opt : ClockSyncOption.values()) { KeyValuePair pair = LfFactory.eINSTANCE.createKeyValuePair(); pair.setName(opt.toString()); switch (opt) { - case ATTENUATION -> pair.setValue(ASTUtils.toElement(get().attenuation)); - case COLLECT_STATS -> pair.setValue(ASTUtils.toElement(get().collectStats)); - case LOCAL_FEDERATES_ON -> pair.setValue(ASTUtils.toElement(get().localFederatesOn)); + case ATTENUATION -> pair.setValue(ASTUtils.toElement(value.attenuation)); + case COLLECT_STATS -> pair.setValue(ASTUtils.toElement(value.collectStats)); + case LOCAL_FEDERATES_ON -> pair.setValue(ASTUtils.toElement(value.localFederatesOn)); case PERIOD -> { - if (get().period == null) { + if (value.period == null) { continue; // don't set if null } - pair.setValue(ASTUtils.toElement(get().period)); + pair.setValue(ASTUtils.toElement(value.period)); } case TEST_OFFSET -> { - if (get().testOffset == null) { + if (value.testOffset == null) { continue; // don't set if null } - pair.setValue(ASTUtils.toElement(get().testOffset)); + pair.setValue(ASTUtils.toElement(value.testOffset)); } - case TRIALS -> pair.setValue(ASTUtils.toElement(get().trials)); + case TRIALS -> pair.setValue(ASTUtils.toElement(value.trials)); } kvp.getPairs().add(pair); } diff --git a/core/src/main/java/org/lflang/target/property/CmakeIncludeProperty.java b/core/src/main/java/org/lflang/target/property/CmakeIncludeProperty.java index 4c4a8fa108..5ab3133599 100644 --- a/core/src/main/java/org/lflang/target/property/CmakeIncludeProperty.java +++ b/core/src/main/java/org/lflang/target/property/CmakeIncludeProperty.java @@ -8,6 +8,7 @@ import org.lflang.Target; import org.lflang.ast.ASTUtils; import org.lflang.lf.Element; +import org.lflang.target.TargetConfig; import org.lflang.target.property.type.UnionType; /** @@ -22,10 +23,9 @@ public CmakeIncludeProperty() { super(UnionType.FILE_OR_FILE_ARRAY); } - public void add(String entry) { - this.isSet = true; - var value = this.get(); - value.add(entry); + public void add(TargetConfig config, String entry) { + config.markSet(this); + config.get(this).add(entry); } @Override @@ -34,15 +34,9 @@ public List initialValue() { } @Override - public void set(Element node, MessageReporter reporter) { - if (!this.isSet) { - super.set(node, reporter); - } else { - // NOTE: This merging of lists is potentially dangerous since - // the incoming list of cmake-includes can belong to a .lf file that is - // located in a different location, and keeping just filename - // strings like this without absolute paths is incorrect. - this.get().addAll(ASTUtils.elementToListOfStrings(node)); + public void update(TargetConfig config, Element node, MessageReporter reporter) { + if (config.isSet(this)) { + config.get(this).addAll(fromAst(node, reporter)); } } @@ -62,8 +56,8 @@ public List supportedTargets() { } @Override - public Element toAstElement() { - return ASTUtils.toElement(this.get()); + public Element toAstElement(List value) { + return ASTUtils.toElement(value); } @Override diff --git a/core/src/main/java/org/lflang/target/property/CompileDefinitionsProperty.java b/core/src/main/java/org/lflang/target/property/CompileDefinitionsProperty.java index ab7a7772d9..5ee2642393 100644 --- a/core/src/main/java/org/lflang/target/property/CompileDefinitionsProperty.java +++ b/core/src/main/java/org/lflang/target/property/CompileDefinitionsProperty.java @@ -9,6 +9,7 @@ import org.lflang.Target; import org.lflang.ast.ASTUtils; import org.lflang.lf.Element; +import org.lflang.target.TargetConfig; import org.lflang.target.property.type.StringDictionaryType; /** @@ -24,10 +25,9 @@ public CompileDefinitionsProperty() { super(StringDictionaryType.COMPILE_DEFINITION); } - public void put(String k, String v) { - this.isSet = true; - var value = this.get(); - value.put(k, v); + public void put(TargetConfig config, String k, String v) { + config.markSet(this); + config.get(this).put(k, v); } @Override @@ -51,8 +51,8 @@ public List supportedTargets() { } @Override - public Element toAstElement() { - return ASTUtils.toElement(this.get()); + public Element toAstElement(Map value) { + return ASTUtils.toElement(value); } @Override 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 a84506eedf..c7247627e0 100644 --- a/core/src/main/java/org/lflang/target/property/CoordinationOptionsProperty.java +++ b/core/src/main/java/org/lflang/target/property/CoordinationOptionsProperty.java @@ -55,17 +55,17 @@ public List supportedTargets() { } @Override - public Element toAstElement() { + public Element toAstElement(CoordinationOptions value) { Element e = LfFactory.eINSTANCE.createElement(); KeyValuePairs kvp = LfFactory.eINSTANCE.createKeyValuePairs(); for (CoordinationOption opt : CoordinationOption.values()) { KeyValuePair pair = LfFactory.eINSTANCE.createKeyValuePair(); pair.setName(opt.toString()); if (opt == CoordinationOption.ADVANCE_MESSAGE_INTERVAL) { - if (this.get().advanceMessageInterval == null) { + if (value.advanceMessageInterval == null) { continue; } - pair.setValue(ASTUtils.toElement(get().advanceMessageInterval)); + pair.setValue(ASTUtils.toElement(value.advanceMessageInterval)); } kvp.getPairs().add(pair); } diff --git a/core/src/main/java/org/lflang/target/property/CoordinationProperty.java b/core/src/main/java/org/lflang/target/property/CoordinationProperty.java index 3163154a91..361960f934 100644 --- a/core/src/main/java/org/lflang/target/property/CoordinationProperty.java +++ b/core/src/main/java/org/lflang/target/property/CoordinationProperty.java @@ -42,8 +42,8 @@ public List supportedTargets() { } @Override - public Element toAstElement() { - return ASTUtils.toElement(this.get().toString()); + public Element toAstElement(CoordinationMode value) { + return ASTUtils.toElement(value.toString()); } @Override 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 998c38d082..67a454528d 100644 --- a/core/src/main/java/org/lflang/target/property/DockerProperty.java +++ b/core/src/main/java/org/lflang/target/property/DockerProperty.java @@ -63,10 +63,10 @@ public List supportedTargets() { } @Override - public Element toAstElement() { - if (!this.get().enabled) { + public Element toAstElement(DockerOptions value) { + if (!value.enabled) { return null; - } else if (this.get().equals(new DockerOptions(true))) { + } else if (value.equals(new DockerOptions(true))) { // default configuration return ASTUtils.toElement(true); } else { @@ -76,10 +76,10 @@ public Element toAstElement() { KeyValuePair pair = LfFactory.eINSTANCE.createKeyValuePair(); pair.setName(opt.toString()); if (opt == DockerOption.FROM) { - if (this.get().from == null) { + if (value.from == null) { continue; } - pair.setValue(ASTUtils.toElement(this.get().from)); + pair.setValue(ASTUtils.toElement(value.from)); } kvp.getPairs().add(pair); } diff --git a/core/src/main/java/org/lflang/target/property/FedSetupProperty.java b/core/src/main/java/org/lflang/target/property/FedSetupProperty.java index 5334e1c9be..e49d2b535e 100644 --- a/core/src/main/java/org/lflang/target/property/FedSetupProperty.java +++ b/core/src/main/java/org/lflang/target/property/FedSetupProperty.java @@ -40,8 +40,8 @@ public List supportedTargets() { } @Override - public Element toAstElement() { - return ASTUtils.toElement(get()); + public Element toAstElement(String value) { + return ASTUtils.toElement(value); } @Override diff --git a/core/src/main/java/org/lflang/target/property/LoggingProperty.java b/core/src/main/java/org/lflang/target/property/LoggingProperty.java index 0784166762..e7d40d49a5 100644 --- a/core/src/main/java/org/lflang/target/property/LoggingProperty.java +++ b/core/src/main/java/org/lflang/target/property/LoggingProperty.java @@ -39,8 +39,8 @@ public List supportedTargets() { } @Override - public Element toAstElement() { - return ASTUtils.toElement(get().toString()); + public Element toAstElement(LogLevel value) { + return ASTUtils.toElement(value.toString()); } @Override 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 f81062115d..02d37b6ca0 100644 --- a/core/src/main/java/org/lflang/target/property/PlatformProperty.java +++ b/core/src/main/java/org/lflang/target/property/PlatformProperty.java @@ -87,19 +87,19 @@ public void validate(KeyValuePair pair, Model ast, MessageReporter reporter) { } @Override - public Element toAstElement() { + public Element toAstElement(PlatformOptions value) { Element e = LfFactory.eINSTANCE.createElement(); KeyValuePairs kvp = LfFactory.eINSTANCE.createKeyValuePairs(); for (PlatformOption opt : PlatformOption.values()) { KeyValuePair pair = LfFactory.eINSTANCE.createKeyValuePair(); pair.setName(opt.toString()); switch (opt) { - case NAME -> pair.setValue(ASTUtils.toElement(get().platform.toString())); - case BAUDRATE -> pair.setValue(ASTUtils.toElement(get().baudRate)); - case BOARD -> pair.setValue(ASTUtils.toElement(get().board)); - case FLASH -> pair.setValue(ASTUtils.toElement(get().flash)); - case PORT -> pair.setValue(ASTUtils.toElement(get().port)); - case USER_THREADS -> pair.setValue(ASTUtils.toElement(get().userThreads)); + case NAME -> pair.setValue(ASTUtils.toElement(value.platform.toString())); + case BAUDRATE -> pair.setValue(ASTUtils.toElement(value.baudRate)); + case BOARD -> pair.setValue(ASTUtils.toElement(value.board)); + case FLASH -> pair.setValue(ASTUtils.toElement(value.flash)); + case PORT -> pair.setValue(ASTUtils.toElement(value.port)); + case USER_THREADS -> pair.setValue(ASTUtils.toElement(value.userThreads)); } kvp.getPairs().add(pair); } 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 5f55913bca..d64df016a6 100644 --- a/core/src/main/java/org/lflang/target/property/Ros2DependenciesProperty.java +++ b/core/src/main/java/org/lflang/target/property/Ros2DependenciesProperty.java @@ -51,8 +51,8 @@ public void validate(KeyValuePair pair, Model ast, MessageReporter reporter) { } @Override - public Element toAstElement() { - return ASTUtils.toElement(get()); + public Element toAstElement(List value) { + return ASTUtils.toElement(value); } @Override diff --git a/core/src/main/java/org/lflang/target/property/RustIncludeProperty.java b/core/src/main/java/org/lflang/target/property/RustIncludeProperty.java index 478cc7e5e7..851bf7030f 100644 --- a/core/src/main/java/org/lflang/target/property/RustIncludeProperty.java +++ b/core/src/main/java/org/lflang/target/property/RustIncludeProperty.java @@ -75,17 +75,16 @@ protected List fromString(String string, MessageReporter reporter) { } @Override - public Element toAstElement() { + public Element toAstElement(List value) { // do not check paths here, and simply copy the absolute path over - List paths = this.get(); - if (paths.isEmpty()) { + if (value.isEmpty()) { return null; - } else if (paths.size() == 1) { - return ASTUtils.toElement(paths.get(0).toString()); + } else if (value.size() == 1) { + return ASTUtils.toElement(value.get(0).toString()); } else { Element e = LfFactory.eINSTANCE.createElement(); Array arr = LfFactory.eINSTANCE.createArray(); - for (Path p : paths) { + for (Path p : value) { arr.getElements().add(ASTUtils.toElement(p.toString())); } e.setArray(arr); 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 c3438d44e6..14de36e2da 100644 --- a/core/src/main/java/org/lflang/target/property/SchedulerProperty.java +++ b/core/src/main/java/org/lflang/target/property/SchedulerProperty.java @@ -46,8 +46,8 @@ public List supportedTargets() { } @Override - public Element toAstElement() { - return ASTUtils.toElement(this.get().toString()); + public Element toAstElement(Scheduler value) { + return ASTUtils.toElement(value.toString()); } @Override diff --git a/core/src/main/java/org/lflang/target/property/TimeOutProperty.java b/core/src/main/java/org/lflang/target/property/TimeOutProperty.java index d2575ae561..2a118a3851 100644 --- a/core/src/main/java/org/lflang/target/property/TimeOutProperty.java +++ b/core/src/main/java/org/lflang/target/property/TimeOutProperty.java @@ -37,8 +37,8 @@ public List supportedTargets() { } @Override - public Element toAstElement() { - return ASTUtils.toElement(get()); + public Element toAstElement(TimeValue value) { + return ASTUtils.toElement(value); } @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 0c69a7fd5e..ce8470a512 100644 --- a/core/src/main/java/org/lflang/target/property/TracingProperty.java +++ b/core/src/main/java/org/lflang/target/property/TracingProperty.java @@ -79,10 +79,10 @@ public void validate(KeyValuePair pair, Model ast, MessageReporter reporter) { } @Override - public Element toAstElement() { - if (!this.get().isEnabled()) { + public Element toAstElement(TracingOptions value) { + if (!value.isEnabled()) { return null; - } else if (this.get().equals(new TracingOptions(true))) { + } else if (value.equals(new TracingOptions(true))) { // default values return ASTUtils.toElement(true); } else { @@ -92,10 +92,10 @@ public Element toAstElement() { KeyValuePair pair = LfFactory.eINSTANCE.createKeyValuePair(); pair.setName(opt.toString()); if (opt == TracingOption.TRACE_FILE_NAME) { - if (this.get().traceFileName == null) { + if (value.traceFileName == null) { continue; } - pair.setValue(ASTUtils.toElement(this.get().traceFileName)); + pair.setValue(ASTUtils.toElement(value.traceFileName)); } kvp.getPairs().add(pair); } 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 19a433e8db..88e9292322 100644 --- a/core/src/main/java/org/lflang/target/property/WorkersProperty.java +++ b/core/src/main/java/org/lflang/target/property/WorkersProperty.java @@ -39,8 +39,8 @@ public List supportedTargets() { } @Override - public Element toAstElement() { - return ASTUtils.toElement(get()); + public Element toAstElement(Integer value) { + return ASTUtils.toElement(value); } @Override From 2c98113f3ad8677d49ceb9f0a2905596bc536d14 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Thu, 5 Oct 2023 23:27:49 -0700 Subject: [PATCH 074/145] Move Rust target properties --- .../generator/rust/RustTargetConfig.java | 8 ++--- .../java/org/lflang/target/TargetConfig.java | 6 ++++ .../compiler/LinguaFrancaValidationTest.java | 30 ++++++++++--------- 3 files changed, 25 insertions(+), 19 deletions(-) diff --git a/core/src/main/java/org/lflang/generator/rust/RustTargetConfig.java b/core/src/main/java/org/lflang/generator/rust/RustTargetConfig.java index 76dba1f2c9..7a13216046 100644 --- a/core/src/main/java/org/lflang/generator/rust/RustTargetConfig.java +++ b/core/src/main/java/org/lflang/generator/rust/RustTargetConfig.java @@ -24,7 +24,6 @@ package org.lflang.generator.rust; -import org.lflang.Target; import org.lflang.target.TargetConfig; import org.lflang.target.property.CargoDependenciesProperty; import org.lflang.target.property.CargoFeaturesProperty; @@ -35,11 +34,10 @@ * * @author Clément Fournier - TU Dresden, INSA Rennes */ -public final class RustTargetConfig extends TargetConfig { +public final class RustTargetConfig { - public RustTargetConfig() { - super(Target.Rust); - register( + public RustTargetConfig(TargetConfig parent) { + parent.register( new CargoFeaturesProperty(), new CargoDependenciesProperty(), new RustIncludeProperty()); } } diff --git a/core/src/main/java/org/lflang/target/TargetConfig.java b/core/src/main/java/org/lflang/target/TargetConfig.java index f58a3e1ed3..524266f802 100644 --- a/core/src/main/java/org/lflang/target/TargetConfig.java +++ b/core/src/main/java/org/lflang/target/TargetConfig.java @@ -42,6 +42,8 @@ import org.lflang.target.property.AuthProperty; import org.lflang.target.property.BuildCommandsProperty; import org.lflang.target.property.BuildTypeProperty; +import org.lflang.target.property.CargoDependenciesProperty; +import org.lflang.target.property.CargoFeaturesProperty; import org.lflang.target.property.ClockSyncModeProperty; import org.lflang.target.property.ClockSyncOptionsProperty; import org.lflang.target.property.CmakeIncludeProperty; @@ -67,6 +69,7 @@ import org.lflang.target.property.Ros2DependenciesProperty; import org.lflang.target.property.Ros2Property; import org.lflang.target.property.RuntimeVersionProperty; +import org.lflang.target.property.RustIncludeProperty; import org.lflang.target.property.SchedulerProperty; import org.lflang.target.property.SingleFileProjectProperty; import org.lflang.target.property.ThreadingProperty; @@ -133,6 +136,9 @@ public TargetConfig(Target target) { new WorkersProperty()); this.register(new FedSetupProperty()); + + this.register( + new CargoFeaturesProperty(), new CargoDependenciesProperty(), new RustIncludeProperty()); } /** 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 8123bff865..f015b017b9 100644 --- a/core/src/test/java/org/lflang/tests/compiler/LinguaFrancaValidationTest.java +++ b/core/src/test/java/org/lflang/tests/compiler/LinguaFrancaValidationTest.java @@ -1476,8 +1476,8 @@ private List synthesizeExamples(TargetPropertyType type, boolean correct * Create an LF program with the given key and value as a target property, parse it, and return * the resulting model. */ - private Model createModel(AbstractTargetProperty property, String value) throws Exception { - var target = property.supportedTargets().stream().findFirst().get(); + private Model createModel(Target target, AbstractTargetProperty property, String value) + throws Exception { return parseWithoutError( """ target %s {%s: %s}; @@ -1507,7 +1507,7 @@ public Collection checkTargetProperties() throws Exception { DynamicTest.dynamicTest( "Property %s (%s) - known good assignment: %s".formatted(property, type, it), () -> { - Model model = createModel(property, it); + Model model = createModel(Target.C, property, it); System.out.println(property.name()); System.out.println(it.toString()); validator.assertNoErrors(model); @@ -1532,7 +1532,7 @@ public Collection checkTargetProperties() throws Exception { .formatted(property.name(), type, it), () -> { validator.assertError( - createModel(property, it), + createModel(Target.C, property, it), LfPackage.eINSTANCE.getKeyValuePair(), null, String.format( @@ -1555,13 +1555,13 @@ public Collection checkTargetProperties() throws Exception { // it.get(0).toString())); if (it.get(1).equals(LfPackage.eINSTANCE.getElement())) { validator.assertError( - createModel(property, it.get(0).toString()), + createModel(Target.C, property, it.get(0).toString()), LfPackage.eINSTANCE.getElement(), null, String.format("Entry is required to be %s.", it.get(2))); } else { validator.assertError( - createModel(property, it.get(0).toString()), + createModel(Target.C, property, it.get(0).toString()), LfPackage.eINSTANCE.getKeyValuePair(), null, String.format( @@ -1590,26 +1590,26 @@ public void checkCargoDependencyProperty() throws Exception { "{ dep: { version: \"8.2\"} }", "{ dep: { version: \"8.2\", features: [\"foo\"]} }"); for (String it : knownCorrect) { - validator.assertNoErrors(createModel(prop, it)); + validator.assertNoErrors(createModel(Target.Rust, prop, it)); } // vvvvvvvvvvv validator.assertError( - createModel(prop, "{ dep: {/*empty*/} }"), + createModel(Target.C, prop, "{ dep: {/*empty*/} }"), LfPackage.eINSTANCE.getKeyValuePairs(), null, "Must specify one of 'version', 'path', or 'git'"); // vvvvvvvvvvv validator.assertError( - createModel(prop, "{ dep: { unknown_key: \"\"} }"), + createModel(Target.C, prop, "{ dep: { unknown_key: \"\"} }"), LfPackage.eINSTANCE.getKeyValuePair(), null, "Unknown key: 'unknown_key'"); // vvvv validator.assertError( - createModel(prop, "{ dep: { features: \"\" } }"), + createModel(Target.C, prop, "{ dep: { features: \"\" } }"), LfPackage.eINSTANCE.getElement(), null, "Expected an array of strings for key 'features'"); @@ -1617,16 +1617,18 @@ public void checkCargoDependencyProperty() throws Exception { @Test public void checkPlatformProperty() throws Exception { - validator.assertNoErrors(createModel(new PlatformProperty(), Platform.ARDUINO.toString())); validator.assertNoErrors( - createModel(new PlatformProperty(), String.format("{name: %s}", Platform.ZEPHYR))); + createModel(Target.C, new PlatformProperty(), Platform.ARDUINO.toString())); + validator.assertNoErrors( + createModel( + Target.C, new PlatformProperty(), String.format("{name: %s}", Platform.ZEPHYR))); validator.assertError( - createModel(new PlatformProperty(), "foobar"), + createModel(Target.C, new PlatformProperty(), "foobar"), LfPackage.eINSTANCE.getKeyValuePair(), null, new PlatformType().toString()); validator.assertError( - createModel(new PlatformProperty(), "{ name: foobar }"), + createModel(Target.C, new PlatformProperty(), "{ name: foobar }"), LfPackage.eINSTANCE.getElement(), null, new PlatformType().toString()); From 23d65a53dc1a1b6ae6188cae4ff38d7f1c0d8e57 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Thu, 12 Oct 2023 23:31:52 -0700 Subject: [PATCH 075/145] Fix more failing unit tests --- .../main/java/org/lflang/AbstractTargetProperty.java | 10 ++++++++++ .../org/lflang/federated/generator/FedGenerator.java | 5 ++++- core/src/main/java/org/lflang/target/TargetConfig.java | 2 +- 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/org/lflang/AbstractTargetProperty.java b/core/src/main/java/org/lflang/AbstractTargetProperty.java index 19745ba27f..7723beafab 100644 --- a/core/src/main/java/org/lflang/AbstractTargetProperty.java +++ b/core/src/main/java/org/lflang/AbstractTargetProperty.java @@ -167,4 +167,14 @@ public void update(TargetConfig config, Element node, MessageReporter reporter) public void update(TargetConfig config, String value, MessageReporter reporter) { this.update(config, fromString(value, reporter)); } + + @Override + public boolean equals(Object obj) { + return obj.getClass().getName().equals(this.getClass().getName()); + } + + @Override + public int hashCode() { + return this.getClass().getName().hashCode(); + } } 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 afa7e30627..6eee6656ee 100644 --- a/core/src/main/java/org/lflang/federated/generator/FedGenerator.java +++ b/core/src/main/java/org/lflang/federated/generator/FedGenerator.java @@ -422,8 +422,11 @@ private void analyzeFederates(Reactor federation, LFGeneratorContext context) { && !federation.getHost().getAddr().equals("localhost")) { rtiConfig.setHost(federation.getHost().getAddr()); } + + var d = new DockerProperty(); + var x = targetConfig.get(d); // If the federation is dockerized, use "rti" as the hostname. - if (rtiConfig.getHost().equals("localhost") && targetConfig.get(new DockerProperty()).enabled) { + if (rtiConfig.getHost().equals("localhost") && x.enabled) { rtiConfig.setHost("rti"); } diff --git a/core/src/main/java/org/lflang/target/TargetConfig.java b/core/src/main/java/org/lflang/target/TargetConfig.java index 524266f802..7c416eb376 100644 --- a/core/src/main/java/org/lflang/target/TargetConfig.java +++ b/core/src/main/java/org/lflang/target/TargetConfig.java @@ -189,7 +189,7 @@ public void override( /** Reset this target property to its initial value (and mark it as unset). */ public void reset(AbstractTargetProperty property) { - this.properties.remove(property); + this.properties.put(property, property.initialValue()); this.setProperties.remove(property); } From a3effa11b611b82b2a93788ae95511b9a41fd330 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Fri, 13 Oct 2023 11:44:29 -0700 Subject: [PATCH 076/145] Add missing hierarhical-bin target property --- .../org/lflang/generator/MainContext.java | 6 +++--- .../java/org/lflang/target/TargetConfig.java | 4 +++- .../property/HierarchicalBinProperty.java | 21 +++++++++++++++++++ 3 files changed, 27 insertions(+), 4 deletions(-) create mode 100644 core/src/main/java/org/lflang/target/property/HierarchicalBinProperty.java diff --git a/core/src/main/java/org/lflang/generator/MainContext.java b/core/src/main/java/org/lflang/generator/MainContext.java index dbe34946e3..ebd4d2552e 100644 --- a/core/src/main/java/org/lflang/generator/MainContext.java +++ b/core/src/main/java/org/lflang/generator/MainContext.java @@ -13,6 +13,7 @@ import org.lflang.MessageReporter; import org.lflang.generator.IntegratedBuilder.ReportProgress; import org.lflang.target.TargetConfig; +import org.lflang.target.property.HierarchicalBinProperty; /** * A {@code MainContext} is an {@code LFGeneratorContext} that is not nested in any other generator @@ -93,9 +94,8 @@ public MainContext( this.args = args; try { - var useHierarchicalBin = - args.containsKey("hierarchical-bin") - && Boolean.parseBoolean(args.getProperty("hierarchical-bin")); + var key = new HierarchicalBinProperty().name(); + var useHierarchicalBin = args.contains(key) && Boolean.parseBoolean(args.getProperty(key)); fileConfig = Objects.requireNonNull( LFGenerator.createFileConfig( diff --git a/core/src/main/java/org/lflang/target/TargetConfig.java b/core/src/main/java/org/lflang/target/TargetConfig.java index 7c416eb376..f89bc98809 100644 --- a/core/src/main/java/org/lflang/target/TargetConfig.java +++ b/core/src/main/java/org/lflang/target/TargetConfig.java @@ -59,6 +59,7 @@ import org.lflang.target.property.FastProperty; import org.lflang.target.property.FedSetupProperty; import org.lflang.target.property.FilesProperty; +import org.lflang.target.property.HierarchicalBinProperty; import org.lflang.target.property.KeepaliveProperty; import org.lflang.target.property.LoggingProperty; import org.lflang.target.property.NoCompileProperty; @@ -117,6 +118,7 @@ public TargetConfig(Target target) { new ExternalRuntimePathProperty(), new FastProperty(), new FilesProperty(), + new HierarchicalBinProperty(), new KeepaliveProperty(), new LoggingProperty(), new NoCompileProperty(), @@ -238,7 +240,7 @@ public void load(Properties properties, MessageReporter err) { var property = p.get(); property.update(this, (String) properties.get(key), err); } else { - throw new RuntimeException("Attempting to load unrecognized target property"); + throw new RuntimeException("Attempting to load unrecognized target property: " + key); } } } diff --git a/core/src/main/java/org/lflang/target/property/HierarchicalBinProperty.java b/core/src/main/java/org/lflang/target/property/HierarchicalBinProperty.java new file mode 100644 index 0000000000..8dfa87bdc7 --- /dev/null +++ b/core/src/main/java/org/lflang/target/property/HierarchicalBinProperty.java @@ -0,0 +1,21 @@ +package org.lflang.target.property; + +import java.util.Arrays; +import java.util.List; +import org.lflang.Target; + +/** + * Whether the bin directory should have a flat or hierarchical organization. It is flat by default. + */ +public class HierarchicalBinProperty extends AbstractBooleanProperty { + + @Override + public List supportedTargets() { + return Arrays.asList(Target.C, Target.CCPP); + } + + @Override + public String name() { + return "hierarchical-bin"; + } +} From 062f31d8fa8bc864593b0881caeb74839443de67 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Fri, 13 Oct 2023 22:46:38 -0700 Subject: [PATCH 077/145] More fixes --- .../org/lflang/AbstractTargetProperty.java | 33 +++---------------- .../property/AbstractFileListProperty.java | 14 +++++++- .../target/property/CmakeIncludeProperty.java | 14 +++++++- 3 files changed, 31 insertions(+), 30 deletions(-) diff --git a/core/src/main/java/org/lflang/AbstractTargetProperty.java b/core/src/main/java/org/lflang/AbstractTargetProperty.java index 7723beafab..861753d6a5 100644 --- a/core/src/main/java/org/lflang/AbstractTargetProperty.java +++ b/core/src/main/java/org/lflang/AbstractTargetProperty.java @@ -77,34 +77,6 @@ public final boolean isSupported(Target target) { return supportedTargets().contains(target); } - // /** - // * Parse the given AST node into the given target config. Encountered errors are reported via - // the - // * given reporter. - // * - // * @param node The AST node to derive a newly assigned value from. - // * @param reporter A reporter for reporting errors. - // */ - // public void set(Element node, MessageReporter reporter) { - // var parsed = this.fromAst(node, reporter); - // if (parsed != null) { - // this.isSet = true; - // this.value = parsed; - // } - // } - - // /** - // * Parse the given element into the given target config. May use the error reporter to report - // * format errors. - // */ - // public void set(String value, MessageReporter err) { - // var parsed = this.fromString(value, err); - // if (parsed != null) { - // this.isSet = true; - // this.value = parsed; - // } - // } - @Override public String toString() { return this.name(); @@ -168,6 +140,11 @@ public 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. + * + * @param obj The object to compare this instance to. + */ @Override public boolean equals(Object obj) { return obj.getClass().getName().equals(this.getClass().getName()); diff --git a/core/src/main/java/org/lflang/target/property/AbstractFileListProperty.java b/core/src/main/java/org/lflang/target/property/AbstractFileListProperty.java index bcdab64c96..d7bf5a4748 100644 --- a/core/src/main/java/org/lflang/target/property/AbstractFileListProperty.java +++ b/core/src/main/java/org/lflang/target/property/AbstractFileListProperty.java @@ -23,8 +23,20 @@ public List initialValue() { @Override public void update(TargetConfig config, Element node, MessageReporter reporter) { + var files = fromAst(node, reporter); + var existing = config.get(this); if (config.isSet(this)) { - config.get(this).addAll(fromAst(node, reporter)); + files.stream() + .forEach( + f -> { + if (!existing.contains(f)) { + existing.add(f); + } + }); + + } else { + config.get(this).addAll(files); + config.markSet(this); } } diff --git a/core/src/main/java/org/lflang/target/property/CmakeIncludeProperty.java b/core/src/main/java/org/lflang/target/property/CmakeIncludeProperty.java index 5ab3133599..c6f441255e 100644 --- a/core/src/main/java/org/lflang/target/property/CmakeIncludeProperty.java +++ b/core/src/main/java/org/lflang/target/property/CmakeIncludeProperty.java @@ -35,8 +35,20 @@ public List initialValue() { @Override public void update(TargetConfig config, Element node, MessageReporter reporter) { + var files = fromAst(node, reporter); + var existing = config.get(this); if (config.isSet(this)) { - config.get(this).addAll(fromAst(node, reporter)); + files.stream() + .forEach( + f -> { + if (!existing.contains(f)) { + existing.add(f); + } + }); + + } else { + config.get(this).addAll(files); + config.markSet(this); } } From de53b8f9007f88ac5410c7025aef39799d2260b4 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Sun, 15 Oct 2023 00:12:13 -0700 Subject: [PATCH 078/145] Fixes that illustrate the trouble with modifiable target properties. Better fix needed. --- .../org/lflang/federated/extensions/CExtensionUtils.java | 8 ++++---- .../main/java/org/lflang/generator/c/CCmakeGenerator.java | 6 +++--- core/src/main/java/org/lflang/generator/c/CCompiler.java | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/core/src/main/java/org/lflang/federated/extensions/CExtensionUtils.java b/core/src/main/java/org/lflang/federated/extensions/CExtensionUtils.java index 7f17673d28..77678e64f4 100644 --- a/core/src/main/java/org/lflang/federated/extensions/CExtensionUtils.java +++ b/core/src/main/java/org/lflang/federated/extensions/CExtensionUtils.java @@ -192,6 +192,7 @@ public static void handleCompileDefinitions( } definitions.put("NUMBER_OF_FEDERATES", String.valueOf(numOfFederates)); definitions.put("EXECUTABLE_PREAMBLE", ""); + federate.targetConfig.markSet(new CompileDefinitionsProperty()); handleAdvanceMessageInterval(federate); @@ -298,10 +299,9 @@ public static void generateCMakeInclude(FederateInstance federate, FedFileConfig srcWriter.write(cmakeIncludeCode.getCode()); } - federate - .targetConfig - .get(new CmakeIncludeProperty()) - .add(fileConfig.getSrcPath().relativize(cmakeIncludePath).toString()); + new CmakeIncludeProperty() + .add( + federate.targetConfig, fileConfig.getSrcPath().relativize(cmakeIncludePath).toString()); } /** 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 1eff36adb5..ad90148bec 100644 --- a/core/src/main/java/org/lflang/generator/c/CCmakeGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CCmakeGenerator.java @@ -36,7 +36,7 @@ import org.lflang.generator.CodeBuilder; import org.lflang.target.TargetConfig; import org.lflang.target.property.AuthProperty; -import org.lflang.target.property.BuildCommandsProperty; +import org.lflang.target.property.BuildTypeProperty; import org.lflang.target.property.CmakeIncludeProperty; import org.lflang.target.property.CompilerFlagsProperty; import org.lflang.target.property.CompilerProperty; @@ -241,7 +241,7 @@ CodeBuilder generateCMakeCode( } // Set the build type - cMakeCode.pr("set(DEFAULT_BUILD_TYPE " + targetConfig.get(new BuildCommandsProperty()) + ")\n"); + cMakeCode.pr("set(DEFAULT_BUILD_TYPE " + targetConfig.get(new BuildTypeProperty()) + ")\n"); cMakeCode.pr("if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)\n"); cMakeCode.pr( " set(CMAKE_BUILD_TYPE ${DEFAULT_BUILD_TYPE} CACHE STRING \"Choose the type of build.\"" @@ -362,7 +362,7 @@ CodeBuilder generateCMakeCode( if (CppMode) cMakeCode.pr("enable_language(CXX)"); - if (!targetConfig.isSet(new CompilerProperty())) { + if (targetConfig.isSet(new CompilerProperty())) { if (CppMode) { // Set the CXX compiler to what the user has requested. cMakeCode.pr("set(CMAKE_CXX_COMPILER " + targetConfig.get(new CompilerProperty()) + ")"); diff --git a/core/src/main/java/org/lflang/generator/c/CCompiler.java b/core/src/main/java/org/lflang/generator/c/CCompiler.java index 8336a83ebe..d108ae3fec 100644 --- a/core/src/main/java/org/lflang/generator/c/CCompiler.java +++ b/core/src/main/java/org/lflang/generator/c/CCompiler.java @@ -248,7 +248,7 @@ private static List cmakeOptions(TargetConfig targetConfig, FileConfig f arguments.addAll( List.of( "-DCMAKE_BUILD_TYPE=" - + ((targetConfig.get(new BuildTypeProperty()) != null) + + (targetConfig.isSet(new BuildTypeProperty()) ? targetConfig.get(new BuildTypeProperty()).toString() : "Release"), "-DCMAKE_INSTALL_PREFIX=" + FileUtil.toUnixString(fileConfig.getOutPath()), From f1f1735577ac6353219b7c1678509dfe672a3bc9 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Sun, 15 Oct 2023 13:09:59 -0700 Subject: [PATCH 079/145] API improvements --- .../org/lflang/AbstractTargetProperty.java | 8 ++-- .../federated/extensions/CExtensionUtils.java | 12 ++++-- .../federated/generator/FedTargetConfig.java | 2 + .../property/AbstractFileListProperty.java | 24 +++++------- .../property/AbstractStringListProperty.java | 17 ++++---- .../target/property/CmakeIncludeProperty.java | 39 +------------------ .../property/CompileDefinitionsProperty.java | 9 ++--- 7 files changed, 39 insertions(+), 72 deletions(-) diff --git a/core/src/main/java/org/lflang/AbstractTargetProperty.java b/core/src/main/java/org/lflang/AbstractTargetProperty.java index 861753d6a5..2f88198a32 100644 --- a/core/src/main/java/org/lflang/AbstractTargetProperty.java +++ b/core/src/main/java/org/lflang/AbstractTargetProperty.java @@ -132,16 +132,18 @@ protected void update(TargetConfig config, T value) { config.set(this, value); } - public void update(TargetConfig config, Element node, MessageReporter reporter) { + public final void update(TargetConfig config, Element node, MessageReporter reporter) { this.update(config, fromAst(node, reporter)); } - public void update(TargetConfig config, String value, MessageReporter reporter) { + 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. + * Return true if the given object is an instance of a class with the same name. FIXME: make this + * a singleton class and remove this override https://www.baeldung.com/kotlin/singleton-classes + * https://stackoverflow.com/questions/24214148/java-getinstance-vs-static * * @param obj The object to compare this instance to. */ diff --git a/core/src/main/java/org/lflang/federated/extensions/CExtensionUtils.java b/core/src/main/java/org/lflang/federated/extensions/CExtensionUtils.java index 77678e64f4..25d02824f4 100644 --- a/core/src/main/java/org/lflang/federated/extensions/CExtensionUtils.java +++ b/core/src/main/java/org/lflang/federated/extensions/CExtensionUtils.java @@ -4,6 +4,7 @@ import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; +import java.util.HashMap; import java.util.List; import java.util.regex.Pattern; import org.lflang.InferredType; @@ -180,7 +181,8 @@ public static void handleCompileDefinitions( int numOfFederates, RtiConfig rtiConfig, MessageReporter messageReporter) { - var definitions = federate.targetConfig.get(new CompileDefinitionsProperty()); + + var definitions = new HashMap(); definitions.put("FEDERATED", ""); definitions.put( String.format( @@ -192,7 +194,8 @@ public static void handleCompileDefinitions( } definitions.put("NUMBER_OF_FEDERATES", String.valueOf(numOfFederates)); definitions.put("EXECUTABLE_PREAMBLE", ""); - federate.targetConfig.markSet(new CompileDefinitionsProperty()); + + new CompileDefinitionsProperty().update(federate.targetConfig, definitions); handleAdvanceMessageInterval(federate); @@ -300,8 +303,9 @@ public static void generateCMakeInclude(FederateInstance federate, FedFileConfig } new CmakeIncludeProperty() - .add( - federate.targetConfig, fileConfig.getSrcPath().relativize(cmakeIncludePath).toString()); + .update( + federate.targetConfig, + List.of(fileConfig.getSrcPath().relativize(cmakeIncludePath).toString())); } /** diff --git a/core/src/main/java/org/lflang/federated/generator/FedTargetConfig.java b/core/src/main/java/org/lflang/federated/generator/FedTargetConfig.java index 7283ae5261..fc4df6e121 100644 --- a/core/src/main/java/org/lflang/federated/generator/FedTargetConfig.java +++ b/core/src/main/java/org/lflang/federated/generator/FedTargetConfig.java @@ -101,6 +101,8 @@ public void update( if (p.isPresent()) { var value = pair.getValue(); if (pair.getName().equals("files")) { + // FIXME: this logic doesn't really belong here. + // Also: what about other target properties that have paths? var array = LfFactory.eINSTANCE.createArray(); ASTUtils.elementToListOfStrings(pair.getValue()).stream() .map(relativePath::resolve) // assume all paths are relative diff --git a/core/src/main/java/org/lflang/target/property/AbstractFileListProperty.java b/core/src/main/java/org/lflang/target/property/AbstractFileListProperty.java index d7bf5a4748..0fd7087136 100644 --- a/core/src/main/java/org/lflang/target/property/AbstractFileListProperty.java +++ b/core/src/main/java/org/lflang/target/property/AbstractFileListProperty.java @@ -22,26 +22,22 @@ public List initialValue() { } @Override - public void update(TargetConfig config, Element node, MessageReporter reporter) { - var files = fromAst(node, reporter); + public void update(TargetConfig config, List value) { + var files = new ArrayList<>(value); var existing = config.get(this); if (config.isSet(this)) { - files.stream() - .forEach( - f -> { - if (!existing.contains(f)) { - existing.add(f); - } - }); - - } else { - config.get(this).addAll(files); - config.markSet(this); + existing.forEach( + f -> { + if (!files.contains(f)) { + files.add(f); + } + }); } + config.set(this, files.stream().sorted(String::compareTo).toList()); } @Override - public List fromAst(Element node, MessageReporter reporter) { + protected List fromAst(Element node, MessageReporter reporter) { return ASTUtils.elementToListOfStrings(node); } diff --git a/core/src/main/java/org/lflang/target/property/AbstractStringListProperty.java b/core/src/main/java/org/lflang/target/property/AbstractStringListProperty.java index b0f78109ed..ba5e99c22e 100644 --- a/core/src/main/java/org/lflang/target/property/AbstractStringListProperty.java +++ b/core/src/main/java/org/lflang/target/property/AbstractStringListProperty.java @@ -17,21 +17,24 @@ public AbstractStringListProperty() { super(UnionType.STRING_OR_STRING_ARRAY); } - public void add(TargetConfig config, String entry) { - config.markSet(this); - config.get(this).add(entry); - } - @Override public List initialValue() { return new ArrayList<>(); } @Override - public void update(TargetConfig config, Element node, MessageReporter reporter) { + public void update(TargetConfig config, List value) { + var files = new ArrayList<>(value); + var existing = config.get(this); if (config.isSet(this)) { - config.get(this).addAll(fromAst(node, reporter)); + existing.forEach( + f -> { + if (!files.contains(f)) { + files.add(f); + } + }); } + config.set(this, files.stream().sorted(String::compareTo).toList()); } @Override diff --git a/core/src/main/java/org/lflang/target/property/CmakeIncludeProperty.java b/core/src/main/java/org/lflang/target/property/CmakeIncludeProperty.java index c6f441255e..07937a632e 100644 --- a/core/src/main/java/org/lflang/target/property/CmakeIncludeProperty.java +++ b/core/src/main/java/org/lflang/target/property/CmakeIncludeProperty.java @@ -1,15 +1,11 @@ package org.lflang.target.property; -import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import org.lflang.AbstractTargetProperty; import org.lflang.MessageReporter; import org.lflang.Target; import org.lflang.ast.ASTUtils; import org.lflang.lf.Element; -import org.lflang.target.TargetConfig; -import org.lflang.target.property.type.UnionType; /** * Directive to specify a cmake to be included by the generated build systems. @@ -17,40 +13,7 @@ *

This gives full control over the C/C++ build as any cmake parameters can be adjusted in the * included file. */ -public class CmakeIncludeProperty extends AbstractTargetProperty, UnionType> { - - public CmakeIncludeProperty() { - super(UnionType.FILE_OR_FILE_ARRAY); - } - - public void add(TargetConfig config, String entry) { - config.markSet(this); - config.get(this).add(entry); - } - - @Override - public List initialValue() { - return new ArrayList<>(); - } - - @Override - public void update(TargetConfig config, Element node, MessageReporter reporter) { - var files = fromAst(node, reporter); - var existing = config.get(this); - if (config.isSet(this)) { - files.stream() - .forEach( - f -> { - if (!existing.contains(f)) { - existing.add(f); - } - }); - - } else { - config.get(this).addAll(files); - config.markSet(this); - } - } +public class CmakeIncludeProperty extends AbstractFileListProperty { @Override protected List fromAst(Element node, MessageReporter reporter) { diff --git a/core/src/main/java/org/lflang/target/property/CompileDefinitionsProperty.java b/core/src/main/java/org/lflang/target/property/CompileDefinitionsProperty.java index 5ee2642393..fd439b7519 100644 --- a/core/src/main/java/org/lflang/target/property/CompileDefinitionsProperty.java +++ b/core/src/main/java/org/lflang/target/property/CompileDefinitionsProperty.java @@ -1,7 +1,6 @@ package org.lflang.target.property; import java.util.Arrays; -import java.util.HashMap; import java.util.List; import java.util.Map; import org.lflang.AbstractTargetProperty; @@ -25,14 +24,12 @@ public CompileDefinitionsProperty() { super(StringDictionaryType.COMPILE_DEFINITION); } - public void put(TargetConfig config, String k, String v) { - config.markSet(this); - config.get(this).put(k, v); - } + @Override + public void update(TargetConfig config, Map value) {} @Override public Map initialValue() { - return new HashMap<>(); + return Map.of(); } @Override From f02ff3f47143a8135f859017b3285ab551558924 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Sun, 15 Oct 2023 15:07:20 -0700 Subject: [PATCH 080/145] Address immutability exceptions --- .../org/lflang/cli/LfcIssueReportingTest.kt | 17 +-------- .../main/java/org/lflang/ast/ASTUtils.java | 10 +++--- .../org/lflang/generator/c/CGenerator.java | 36 +++++++------------ .../generator/c/CPreambleGenerator.java | 18 +++++----- 4 files changed, 28 insertions(+), 53 deletions(-) diff --git a/cli/lfc/src/test/kotlin/org/lflang/cli/LfcIssueReportingTest.kt b/cli/lfc/src/test/kotlin/org/lflang/cli/LfcIssueReportingTest.kt index 21cdaf3043..8589cddc8a 100644 --- a/cli/lfc/src/test/kotlin/org/lflang/cli/LfcIssueReportingTest.kt +++ b/cli/lfc/src/test/kotlin/org/lflang/cli/LfcIssueReportingTest.kt @@ -47,22 +47,7 @@ class SpyPrintStream { class LfcIssueReportingTest { - /* - Note: when executing these tests in Intellij, I get the following error: - - java.lang.SecurityException: class "org.eclipse.core.runtime.IPath"'s - signer information does not match signer information of other classes - in the same package - - To fix this: - - Go into File > Project Structure (CTRL+MAJ+S) - - Open the "Modules" tab - - Select the module org.lflang/lfc/test in the tree view - - Open the "Dependencies" tab - - Remove the dependency org.eclipse.platform:org.eclipse.equinox.common (it will have Provided scope) - */ - - + @Test fun testSimpleWarning() { doTest(fileBaseName = "simpleWarning") diff --git a/core/src/main/java/org/lflang/ast/ASTUtils.java b/core/src/main/java/org/lflang/ast/ASTUtils.java index 59189f1d24..472ce87d88 100644 --- a/core/src/main/java/org/lflang/ast/ASTUtils.java +++ b/core/src/main/java/org/lflang/ast/ASTUtils.java @@ -615,10 +615,12 @@ public static ReactorInstance createMainReactorInstance( if (breadth == 0) { messageReporter.nowhere().warning("The program has no reactions"); } else { - // FIXME: not marking the property as set! - targetConfig - .get(new CompileDefinitionsProperty()) - .put("LF_REACTION_GRAPH_BREADTH", String.valueOf(reactionInstanceGraph.getBreadth())); + new CompileDefinitionsProperty() + .update( + targetConfig, + Map.of( + "LF_REACTION_GRAPH_BREADTH", + String.valueOf(reactionInstanceGraph.getBreadth()))); } return main; } 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 46e584656f..93925abc8b 100644 --- a/core/src/main/java/org/lflang/generator/c/CGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CGenerator.java @@ -41,8 +41,10 @@ import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; +import java.util.HashMap; import java.util.LinkedHashSet; import java.util.List; +import java.util.Map; import java.util.regex.Pattern; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -1976,23 +1978,18 @@ protected DockerGenerator getDockerGenerator(LFGeneratorContext context) { // Perform set up that does not generate code protected void setUpGeneralParameters() { accommodatePhysicalActionsIfPresent(); - targetConfig - .get(new CompileDefinitionsProperty()) - .put( - "LOG_LEVEL", - String.valueOf( - targetConfig - .get(new LoggingProperty()) - .ordinal())); // FIXME: put without marking as set + new CompileDefinitionsProperty() + .update( + targetConfig, + Map.of("LOG_LEVEL", String.valueOf(targetConfig.get(new LoggingProperty()).ordinal()))); + targetConfig.compileAdditionalSources.addAll(CCoreFilesUtils.getCTargetSrc()); // Create the main reactor instance if there is a main reactor. this.main = ASTUtils.createMainReactorInstance(mainDef, reactors, messageReporter, targetConfig); if (hasModalReactors) { // So that each separate compile knows about modal reactors, do this: - targetConfig - .get(new CompileDefinitionsProperty()) - .put("MODAL_REACTORS", "TRUE"); // FIXME: put without marking as set + new CompileDefinitionsProperty().update(targetConfig, Map.of("MODAL_REACTORS", "TRUE")); } final var platformOptions = targetConfig.get(new PlatformProperty()); if (targetConfig.get(new ThreadingProperty()) @@ -2037,19 +2034,10 @@ protected void setUpGeneralParameters() { if (targetConfig.get(new ThreadingProperty())) { // FIXME: This logic is duplicated in CMake pickScheduler(); // FIXME: this and pickScheduler should be combined. - targetConfig - .get(new CompileDefinitionsProperty()) - .put( - "SCHEDULER", - targetConfig - .get(new SchedulerProperty()) - .name()); // FIXME: put without marking as set - targetConfig - .get(new CompileDefinitionsProperty()) - .put( - "NUMBER_OF_WORKERS", - String.valueOf( - targetConfig.get(new WorkersProperty()))); // FIXME: put without marking as set + var map = new HashMap(); + map.put("SCHEDULER", targetConfig.get(new SchedulerProperty()).name()); + map.put("NUMBER_OF_WORKERS", String.valueOf(targetConfig.get(new WorkersProperty()))); + new CompileDefinitionsProperty().update(targetConfig, map); } pickCompilePlatform(); } 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 18c783a4f5..d4b084d6bb 100644 --- a/core/src/main/java/org/lflang/generator/c/CPreambleGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CPreambleGenerator.java @@ -3,6 +3,7 @@ import static org.lflang.util.StringUtil.addDoubleQuotes; import java.nio.file.Path; +import java.util.HashMap; import org.lflang.generator.CodeBuilder; import org.lflang.target.TargetConfig; import org.lflang.target.property.CompileDefinitionsProperty; @@ -72,11 +73,9 @@ public static String generateDefineDirectives(TargetConfig targetConfig, Path sr // TODO: Get rid of all of these code.pr("#define LOG_LEVEL " + logLevel); code.pr("#define TARGET_FILES_DIRECTORY " + addDoubleQuotes(srcGenPath.toString())); - + final var definitions = new HashMap(); if (tracing.isEnabled()) { - targetConfig - .get(new CompileDefinitionsProperty()) - .put("LF_TRACE", tracing.traceFileName); // FIXME: put without marking as set + definitions.put("LF_TRACE", tracing.traceFileName); } // if (clockSyncIsOn) { // code.pr(generateClockSyncDefineDirective( @@ -84,17 +83,18 @@ public static String generateDefineDirectives(TargetConfig targetConfig, Path sr // targetConfig.clockSyncOptions // )); // } - final var defs = targetConfig.get(new CompileDefinitionsProperty()); + if (targetConfig.get(new ThreadingProperty())) { - defs.put("LF_THREADED", "1"); + definitions.put("LF_THREADED", "1"); } else { - defs.put("LF_UNTHREADED", "1"); + definitions.put("LF_UNTHREADED", "1"); } if (targetConfig.get(new ThreadingProperty())) { - defs.put("LF_THREADED", "1"); + definitions.put("LF_THREADED", "1"); } else { - defs.put("LF_UNTHREADED", "1"); + definitions.put("LF_UNTHREADED", "1"); } + new CompileDefinitionsProperty().update(targetConfig, definitions); code.newLine(); return code.toString(); } From 32101a3cbafedcbfce8cce8fa179f02c70b145d4 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Sun, 15 Oct 2023 16:17:29 -0700 Subject: [PATCH 081/145] More immutability exceptions --- .../org/lflang/federated/extensions/CExtensionUtils.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/org/lflang/federated/extensions/CExtensionUtils.java b/core/src/main/java/org/lflang/federated/extensions/CExtensionUtils.java index 25d02824f4..e61f230a78 100644 --- a/core/src/main/java/org/lflang/federated/extensions/CExtensionUtils.java +++ b/core/src/main/java/org/lflang/federated/extensions/CExtensionUtils.java @@ -266,7 +266,8 @@ public static void addClockSyncCompileDefinitions(FederateInstance federate) { ClockSyncMode mode = federate.targetConfig.get(new ClockSyncModeProperty()); ClockSyncOptions options = federate.targetConfig.get(new ClockSyncOptionsProperty()); - final var defs = federate.targetConfig.get(new CompileDefinitionsProperty()); + final var defs = new HashMap(); + defs.put("_LF_CLOCK_SYNC_INITIAL", ""); defs.put("_LF_CLOCK_SYNC_PERIOD_NS", String.valueOf(options.period.toNanoSeconds())); defs.put("_LF_CLOCK_SYNC_EXCHANGES_PER_INTERVAL", String.valueOf(options.trials)); @@ -275,9 +276,10 @@ public static void addClockSyncCompileDefinitions(FederateInstance federate) { if (mode == ClockSyncMode.ON) { defs.put("_LF_CLOCK_SYNC_ON", ""); if (options.collectStats) { - defs.put("_LF_CLOCK_SYNC_COLLECT_STATS", ""); // FIXME: more puts + defs.put("_LF_CLOCK_SYNC_COLLECT_STATS", ""); } } + new CompileDefinitionsProperty().update(federate.targetConfig, defs); } /** Generate a file to be included by CMake. */ From e4c3e068bf64dec7e34b57b60df88028e8ae013b Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Sun, 15 Oct 2023 17:53:57 -0700 Subject: [PATCH 082/145] More fixes --- .../lflang/tests/runtime/CVerifierTest.java | 2 +- .../org/lflang/tests/runtime/CppRos2Test.java | 2 +- .../org/lflang/AbstractTargetProperty.java | 6 +++++- .../federated/extensions/CExtension.java | 6 +++--- .../federated/generator/FedFileConfig.java | 13 ++++++------ .../federated/generator/FedGenerator.java | 11 +++++----- .../org/lflang/generator/GeneratorUtils.java | 3 ++- .../org/lflang/generator/c/CGenerator.java | 8 ++++---- .../generator/python/PythonGenerator.java | 4 ++-- .../java/org/lflang/target/TargetConfig.java | 20 +++---------------- .../java/org/lflang/tests/Configurators.java | 6 +++--- 11 files changed, 37 insertions(+), 44 deletions(-) diff --git a/core/src/integrationTest/java/org/lflang/tests/runtime/CVerifierTest.java b/core/src/integrationTest/java/org/lflang/tests/runtime/CVerifierTest.java index 7140eca72f..86d61464b0 100644 --- a/core/src/integrationTest/java/org/lflang/tests/runtime/CVerifierTest.java +++ b/core/src/integrationTest/java/org/lflang/tests/runtime/CVerifierTest.java @@ -22,7 +22,7 @@ public void runVerifierTests() { Message.DESC_VERIFIER, TestRegistry.TestCategory.VERIFIER::equals, test -> { - test.getContext().getTargetConfig().override(new VerifyProperty(), true); + new VerifyProperty().override(test.getContext().getTargetConfig(), true); return true; }, TestLevel.BUILD, diff --git a/core/src/integrationTest/java/org/lflang/tests/runtime/CppRos2Test.java b/core/src/integrationTest/java/org/lflang/tests/runtime/CppRos2Test.java index 427eb07650..efb051944b 100644 --- a/core/src/integrationTest/java/org/lflang/tests/runtime/CppRos2Test.java +++ b/core/src/integrationTest/java/org/lflang/tests/runtime/CppRos2Test.java @@ -31,7 +31,7 @@ public void runWithRos2() { Message.DESC_ROS2, it -> true, it -> { - it.getContext().getTargetConfig().override(new Ros2Property(), true); + new Ros2Property().override(it.getContext().getTargetConfig(), true); return true; }, TestLevel.EXECUTION, diff --git a/core/src/main/java/org/lflang/AbstractTargetProperty.java b/core/src/main/java/org/lflang/AbstractTargetProperty.java index 2f88198a32..f2575f6cf9 100644 --- a/core/src/main/java/org/lflang/AbstractTargetProperty.java +++ b/core/src/main/java/org/lflang/AbstractTargetProperty.java @@ -128,10 +128,14 @@ public void validate(KeyValuePair pair, Model ast, MessageReporter reporter) {} /** Return the name of this target property (in kebab case). */ public abstract String name(); - protected void update(TargetConfig config, T value) { + public final void override(TargetConfig config, T value) { config.set(this, value); } + protected void update(TargetConfig config, T value) { + override(config, value); + } + public final void update(TargetConfig config, Element node, MessageReporter reporter) { this.update(config, fromAst(node, reporter)); } 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 955b561071..ba5f67f76c 100644 --- a/core/src/main/java/org/lflang/federated/extensions/CExtension.java +++ b/core/src/main/java/org/lflang/federated/extensions/CExtension.java @@ -87,16 +87,16 @@ public void initializeTargetConfig( generateCMakeInclude(federate, fileConfig); - federate.targetConfig.override(new KeepaliveProperty(), true); + new KeepaliveProperty().override(federate.targetConfig, true); // If there are federates, copy the required files for that. // Also, create the RTI C file and the launcher script. // Handle target parameters. // If the program is federated, then ensure that threading is enabled. - federate.targetConfig.override(new ThreadingProperty(), true); + new ThreadingProperty().override(federate.targetConfig, true); // Include the fed setup file for this federate in the target property - federate.targetConfig.override(new FedSetupProperty(), getPreamblePath(federate)); + new FedSetupProperty().override(federate.targetConfig, getPreamblePath(federate)); } /** Generate a cmake-include file for {@code federate} if needed. */ diff --git a/core/src/main/java/org/lflang/federated/generator/FedFileConfig.java b/core/src/main/java/org/lflang/federated/generator/FedFileConfig.java index f23d0c7a81..9e5e103c8f 100644 --- a/core/src/main/java/org/lflang/federated/generator/FedFileConfig.java +++ b/core/src/main/java/org/lflang/federated/generator/FedFileConfig.java @@ -103,9 +103,11 @@ public void doClean() throws IOException { * the generated .lf file for the federate. */ public void relativizePaths(FedTargetConfig targetConfig) { - relativizePathList(targetConfig.get(new ProtobufsProperty())); - relativizePathList(targetConfig.get(new FilesProperty())); - relativizePathList(targetConfig.get(new CmakeIncludeProperty())); + List.of(new ProtobufsProperty(), new FilesProperty(), new CmakeIncludeProperty()) + .forEach( + p -> { + p.override(targetConfig, relativizePathList(targetConfig.get(p))); + }); } /** @@ -113,11 +115,10 @@ public void relativizePaths(FedTargetConfig targetConfig) { * * @param paths The paths to relativize. */ - private void relativizePathList(List paths) { + private List relativizePathList(List paths) { List tempList = new ArrayList<>(); paths.forEach(f -> tempList.add(relativizePath(Paths.get(f)))); - paths.clear(); - paths.addAll(tempList); + return tempList; } /** 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 6eee6656ee..aa645a932f 100644 --- a/core/src/main/java/org/lflang/federated/generator/FedGenerator.java +++ b/core/src/main/java/org/lflang/federated/generator/FedGenerator.java @@ -125,7 +125,7 @@ public boolean doGenerate(Resource resource, LFGeneratorContext context) throws // In a federated execution, we need keepalive to be true, // otherwise a federate could exit simply because it hasn't received // any messages. - targetConfig.override(new KeepaliveProperty(), true); + new KeepaliveProperty().override(targetConfig, true); // Process command-line arguments processCLIArguments(context); @@ -201,9 +201,10 @@ private void createDockerFiles(LFGeneratorContext context, List subC final List services = new ArrayList<>(); // 1. create a Dockerfile for each federate for (SubContext subContext : subContexts) { // Inherit Docker options from main context - subContext - .getTargetConfig() - .override(new DockerProperty(), context.getTargetConfig().get(new DockerProperty())); + + new DockerProperty() + .override( + subContext.getTargetConfig(), context.getTargetConfig().get(new DockerProperty())); var dockerGenerator = dockerGeneratorFactory(subContext); var dockerData = dockerGenerator.generateDockerData(); try { @@ -303,7 +304,7 @@ private Map compileFederates( subContextMessageReporter); if (targetConfig.get(new DockerProperty()).enabled && targetConfig.target.buildsUsingDocker()) { - subConfig.override(new NoCompileProperty(), true); + new NoCompileProperty().override(subConfig, true); } subConfig.get(new DockerProperty()).enabled = false; diff --git a/core/src/main/java/org/lflang/generator/GeneratorUtils.java b/core/src/main/java/org/lflang/generator/GeneratorUtils.java index e846bb03dc..1b4c0f9fa2 100644 --- a/core/src/main/java/org/lflang/generator/GeneratorUtils.java +++ b/core/src/main/java/org/lflang/generator/GeneratorUtils.java @@ -59,7 +59,8 @@ public static void accommodatePhysicalActionsIfPresent( && !targetConfig.isSet(new KeepaliveProperty()) && !targetConfig.get(new KeepaliveProperty())) { // Keepalive was explicitly set to false; set it to true. - targetConfig.override(new KeepaliveProperty(), true); + + new KeepaliveProperty().override(targetConfig, true); String message = String.format( "Setting %s to true because of the physical action %s.", 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 93925abc8b..a39281b790 100644 --- a/core/src/main/java/org/lflang/generator/c/CGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CGenerator.java @@ -363,7 +363,7 @@ public void accommodatePhysicalActionsIfPresent() { // because it is the only one currently capable of handling asynchronous events. var threading = new ThreadingProperty(); if (!targetConfig.get(threading) && !targetConfig.isSet(threading)) { - targetConfig.override(threading, true); + threading.override(targetConfig, true); String message = "Using the threaded C runtime to allow for asynchronous handling of physical action" + " " @@ -715,7 +715,7 @@ private void pickScheduler() { // Check if a deadline is assigned to any reaction if (hasDeadlines(reactors)) { if (!targetConfig.isSet(new SchedulerProperty())) { - targetConfig.override(new SchedulerProperty(), Scheduler.GEDF_NP); + new SchedulerProperty().override(targetConfig, Scheduler.GEDF_NP); } } } @@ -2001,7 +2001,7 @@ protected void setUpGeneralParameters() { .info( "Threading is incompatible on your current Arduino flavor. Setting threading to" + " false."); - targetConfig.override(new ThreadingProperty(), false); + new ThreadingProperty().override(targetConfig, false); } if (platformOptions.platform == Platform.ARDUINO @@ -2014,7 +2014,7 @@ protected void setUpGeneralParameters() { + " board name (FQBN) in the target property. For example, platform: {name:" + " arduino, board: arduino:avr:leonardo}. Entering \"no-compile\" mode and" + " generating target code only."); - targetConfig.override(new NoCompileProperty(), true); + new NoCompileProperty().override(targetConfig, true); } if (platformOptions.platform == Platform.ZEPHYR diff --git a/core/src/main/java/org/lflang/generator/python/PythonGenerator.java b/core/src/main/java/org/lflang/generator/python/PythonGenerator.java index ca291f1d3e..72b3d59e5e 100644 --- a/core/src/main/java/org/lflang/generator/python/PythonGenerator.java +++ b/core/src/main/java/org/lflang/generator/python/PythonGenerator.java @@ -109,8 +109,8 @@ public PythonGenerator(LFGeneratorContext context) { private PythonGenerator( LFGeneratorContext context, PythonTypes types, CCmakeGenerator cmakeGenerator) { super(context, false, types, cmakeGenerator, new PythonDelayBodyGenerator(types)); - this.targetConfig.override(new CompilerProperty(), "gcc"); // FIXME: why? - this.targetConfig.get(new CompilerFlagsProperty()).clear(); + new CompilerProperty().override(this.targetConfig, "gcc"); // FIXME: why? + this.targetConfig.reset(new CompilerFlagsProperty()); this.targetConfig.linkerFlags = ""; // FIXME: why? this.types = types; } diff --git a/core/src/main/java/org/lflang/target/TargetConfig.java b/core/src/main/java/org/lflang/target/TargetConfig.java index f89bc98809..085b3ca06c 100644 --- a/core/src/main/java/org/lflang/target/TargetConfig.java +++ b/core/src/main/java/org/lflang/target/TargetConfig.java @@ -26,6 +26,7 @@ import java.util.ArrayList; import java.util.Arrays; +import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -178,17 +179,6 @@ public void register(AbstractTargetProperty... properties) { .forEach(property -> this.properties.put(property, property.initialValue())); } - /** - * Manually override the value of this target property. - * - * @param value The value to assign to this target property. - */ - public void override( - AbstractTargetProperty property, T value) { - this.setProperties.add(property); - this.properties.put(property, value); - } - /** Reset this target property to its initial value (and mark it as unset). */ public void reset(AbstractTargetProperty property) { this.properties.put(property, property.initialValue()); @@ -211,14 +201,14 @@ public boolean isSet(AbstractTargetProperty property) { public String listOfRegisteredProperties() { return getRegisteredProperties().stream() - .map(p -> p.toString()) + .map(AbstractTargetProperty::toString) .filter(s -> !s.startsWith("_")) .collect(Collectors.joining(", ")); } public List> getRegisteredProperties() { return this.properties.keySet().stream() - .sorted((p1, p2) -> p1.getClass().getName().compareTo(p2.getClass().getName())) + .sorted(Comparator.comparing(p -> p.getClass().getName())) .collect(Collectors.toList()); } @@ -270,8 +260,4 @@ public void set( this.setProperties.add(property); this.properties.put(property, value); } - - public void markSet(AbstractTargetProperty property) { - this.setProperties.add(property); - } } diff --git a/core/src/testFixtures/java/org/lflang/tests/Configurators.java b/core/src/testFixtures/java/org/lflang/tests/Configurators.java index 7febf6cefc..397904fc9d 100644 --- a/core/src/testFixtures/java/org/lflang/tests/Configurators.java +++ b/core/src/testFixtures/java/org/lflang/tests/Configurators.java @@ -68,14 +68,14 @@ public static boolean disableThreading(LFTest test) { public static boolean makeZephyrCompatibleUnthreaded(LFTest test) { test.getContext().getArgs().setProperty("tracing", "false"); - test.getContext().getTargetConfig().override(new ThreadingProperty(), false); + new ThreadingProperty().override(test.getContext().getTargetConfig(), false); // FIXME: use a record and override. test.getContext().getTargetConfig().get(new PlatformProperty()).platform = Platform.ZEPHYR; test.getContext().getTargetConfig().get(new PlatformProperty()).flash = false; test.getContext().getTargetConfig().get(new PlatformProperty()).board = "qemu_cortex_m3"; // FIXME: Zephyr emulations fails with debug log-levels. - test.getContext().getTargetConfig().override(new LoggingProperty(), LogLevel.WARN); + new LoggingProperty().override(test.getContext().getTargetConfig(), LogLevel.WARN); test.getContext().getArgs().setProperty("logging", "warning"); return true; } @@ -87,7 +87,7 @@ public static boolean makeZephyrCompatible(LFTest test) { test.getContext().getTargetConfig().get(new PlatformProperty()).board = "qemu_cortex_m3"; // FIXME: Zephyr emulations fails with debug log-levels. - test.getContext().getTargetConfig().override(new LoggingProperty(), LogLevel.WARN); + new LoggingProperty().override(test.getContext().getTargetConfig(), LogLevel.WARN); test.getContext().getArgs().setProperty("logging", "warning"); return true; From 1fc2af574d3c7b6dfa24f299ba3142099858e370 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Sun, 15 Oct 2023 18:29:54 -0700 Subject: [PATCH 083/145] Fix compile definitions --- .../property/CompileDefinitionsProperty.java | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/org/lflang/target/property/CompileDefinitionsProperty.java b/core/src/main/java/org/lflang/target/property/CompileDefinitionsProperty.java index fd439b7519..d65b608940 100644 --- a/core/src/main/java/org/lflang/target/property/CompileDefinitionsProperty.java +++ b/core/src/main/java/org/lflang/target/property/CompileDefinitionsProperty.java @@ -1,6 +1,7 @@ package org.lflang.target.property; import java.util.Arrays; +import java.util.HashMap; import java.util.List; import java.util.Map; import org.lflang.AbstractTargetProperty; @@ -25,7 +26,19 @@ public CompileDefinitionsProperty() { } @Override - public void update(TargetConfig config, Map value) {} + public void update(TargetConfig config, Map value) { + var pairs = new HashMap<>(value); + var existing = config.get(this); + if (config.isSet(this)) { + existing.forEach( + (k, v) -> { + if (!pairs.containsKey(k)) { + pairs.put(k, v); + } + }); + } + config.set(this, pairs); + } @Override public Map initialValue() { From 75e0c7ffa83c8c8a9ac67782aca00ab29ab247fc Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Sun, 15 Oct 2023 21:20:14 -0700 Subject: [PATCH 084/145] Fixed CmakeInclude handling --- .../org/lflang/AbstractTargetProperty.java | 27 ++++++++++++ .../org/lflang/generator/c/CGenerator.java | 13 ++---- .../java/org/lflang/target/TargetConfig.java | 23 ++++++++++ .../org/lflang/target/TargetProperty.java | 43 +------------------ .../target/property/PlatformProperty.java | 3 +- .../property/Ros2DependenciesProperty.java | 3 +- .../target/property/TracingProperty.java | 3 +- 7 files changed, 58 insertions(+), 57 deletions(-) diff --git a/core/src/main/java/org/lflang/AbstractTargetProperty.java b/core/src/main/java/org/lflang/AbstractTargetProperty.java index f2575f6cf9..f8ff90e78a 100644 --- a/core/src/main/java/org/lflang/AbstractTargetProperty.java +++ b/core/src/main/java/org/lflang/AbstractTargetProperty.java @@ -1,6 +1,7 @@ package org.lflang; import java.util.List; +import java.util.Optional; import org.lflang.lf.Element; import org.lflang.lf.KeyValuePair; import org.lflang.lf.LfPackage.Literals; @@ -125,6 +126,15 @@ public void validate(KeyValuePair pair, Model ast, MessageReporter reporter) {} */ public abstract Element toAstElement(T value); + public Optional astElementFromConfig(TargetConfig config) { + var value = toAstElement(config.get(this)); + if (value != null) { + return Optional.of(value); + } else { + return Optional.empty(); + } + } + /** Return the name of this target property (in kebab case). */ public abstract String name(); @@ -160,4 +170,21 @@ public boolean equals(Object obj) { public int hashCode() { return this.getClass().getName().hashCode(); } + + /** + * 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, AbstractTargetProperty 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/generator/c/CGenerator.java b/core/src/main/java/org/lflang/generator/c/CGenerator.java index a39281b790..5258008b3b 100644 --- a/core/src/main/java/org/lflang/generator/c/CGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CGenerator.java @@ -759,16 +759,9 @@ private void inspectReactorEResource(ReactorDecl reactor) { // Copy the user files and cmake-includes to the src-gen path of the main .lf file copyUserFiles(lfResource.getTargetConfig(), lfResource.getFileConfig()); // Merge the CMake includes from the imported file into the target config - final var cmakeIncludes = this.targetConfig.get(new CmakeIncludeProperty()); - lfResource - .getTargetConfig() - .get(new CmakeIncludeProperty()) - .forEach( - incl -> { - if (!cmakeIncludes.contains(incl)) { - cmakeIncludes.add(incl); - } - }); + new CmakeIncludeProperty() + .update( + this.targetConfig, lfResource.getTargetConfig().get(new CmakeIncludeProperty())); } } } diff --git a/core/src/main/java/org/lflang/target/TargetConfig.java b/core/src/main/java/org/lflang/target/TargetConfig.java index 085b3ca06c..1331005760 100644 --- a/core/src/main/java/org/lflang/target/TargetConfig.java +++ b/core/src/main/java/org/lflang/target/TargetConfig.java @@ -29,6 +29,7 @@ import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; +import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Optional; @@ -39,6 +40,7 @@ import org.lflang.MessageReporter; import org.lflang.Target; import org.lflang.lf.KeyValuePair; +import org.lflang.lf.LfFactory; import org.lflang.lf.TargetDecl; import org.lflang.target.property.AuthProperty; import org.lflang.target.property.BuildCommandsProperty; @@ -260,4 +262,25 @@ public void set( this.setProperties.add(property); this.properties.put(property, value); } + + /** + * Extracts all properties as a list of key-value pairs from a TargetConfig. Only extracts + * properties explicitly set by user. + * + * @param config The TargetConfig to extract from. + * @return The extracted properties. + */ + public static List extractProperties(TargetConfig config) { + var res = new LinkedList(); + for (AbstractTargetProperty p : TargetProperty.loaded(config)) { + KeyValuePair kv = LfFactory.eINSTANCE.createKeyValuePair(); + var element = p.astElementFromConfig(config); + if (element.isPresent()) { + kv.setName(p.name()); + kv.setValue(element.get()); + res.add(kv); + } + } + return res; + } } diff --git a/core/src/main/java/org/lflang/target/TargetProperty.java b/core/src/main/java/org/lflang/target/TargetProperty.java index 7f24e131f5..5caf4db8b2 100644 --- a/core/src/main/java/org/lflang/target/TargetProperty.java +++ b/core/src/main/java/org/lflang/target/TargetProperty.java @@ -25,7 +25,6 @@ package org.lflang.target; -import java.util.LinkedList; import java.util.List; import java.util.stream.Collectors; import org.lflang.AbstractTargetProperty; @@ -46,33 +45,12 @@ */ public class TargetProperty { - /** - * Extracts all properties as a list of key-value pairs from a TargetConfig. Only extracts - * properties explicitly set by user. - * - * @param config The TargetConfig to extract from. - * @return The extracted properties. - */ - public static List extractProperties( - TargetConfig config) { // FIXME: move to TargetConfig - var res = new LinkedList(); - for (AbstractTargetProperty p : TargetProperty.loaded(config)) { - KeyValuePair kv = LfFactory.eINSTANCE.createKeyValuePair(); - kv.setName(p.name()); - kv.setValue(p.toAstElement(config.get(p))); - if (kv.getValue() != null) { - res.add(kv); - } - } - return res; - } - /** * Return all the target properties that have been set. * * @param config The configuration to find the properties in. */ - public static List loaded( + public static List> loaded( TargetConfig config) { // FIXME: move to target config return config.getRegisteredProperties().stream() .filter(p -> config.isSet(p)) @@ -89,7 +67,7 @@ public static List loaded( public static TargetDecl extractTargetDecl(Target target, TargetConfig config) { TargetDecl decl = LfFactory.eINSTANCE.createTargetDecl(); KeyValuePairs kvp = LfFactory.eINSTANCE.createKeyValuePairs(); - for (KeyValuePair p : extractProperties(config)) { + for (KeyValuePair p : TargetConfig.extractProperties(config)) { kvp.getPairs().add(p); } decl.setName(target.toString()); @@ -97,23 +75,6 @@ public static TargetDecl extractTargetDecl(Target target, TargetConfig config) { return decl; } - /** - * 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, AbstractTargetProperty 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; - } - /** * Validate the given key-value pairs and report issues via the given reporter. * 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 02d37b6ca0..55c8110dec 100644 --- a/core/src/main/java/org/lflang/target/property/PlatformProperty.java +++ b/core/src/main/java/org/lflang/target/property/PlatformProperty.java @@ -11,7 +11,6 @@ import org.lflang.lf.LfFactory; import org.lflang.lf.LfPackage.Literals; import org.lflang.lf.Model; -import org.lflang.target.TargetProperty; import org.lflang.target.property.PlatformProperty.PlatformOptions; import org.lflang.target.property.type.DictionaryType; import org.lflang.target.property.type.DictionaryType.DictionaryElement; @@ -78,7 +77,7 @@ public List supportedTargets() { @Override public void validate(KeyValuePair pair, Model ast, MessageReporter reporter) { var config = fromAst(pair.getValue(), reporter); - var threading = TargetProperty.getKeyValuePair(ast, new ThreadingProperty()); + var threading = AbstractTargetProperty.getKeyValuePair(ast, new ThreadingProperty()); if (threading != null && config.platform == Platform.RP2040) { reporter .at(pair, Literals.KEY_VALUE_PAIR__VALUE) 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 d64df016a6..426d8c02a0 100644 --- a/core/src/main/java/org/lflang/target/property/Ros2DependenciesProperty.java +++ b/core/src/main/java/org/lflang/target/property/Ros2DependenciesProperty.java @@ -10,7 +10,6 @@ import org.lflang.lf.KeyValuePair; import org.lflang.lf.LfPackage.Literals; import org.lflang.lf.Model; -import org.lflang.target.TargetProperty; import org.lflang.target.property.type.ArrayType; /** Directive to specify additional ROS2 packages that this LF program depends on. */ @@ -42,7 +41,7 @@ public List supportedTargets() { @Override public void validate(KeyValuePair pair, Model ast, MessageReporter reporter) { - var ros2enabled = TargetProperty.getKeyValuePair(ast, new Ros2Property()); + var ros2enabled = AbstractTargetProperty.getKeyValuePair(ast, new Ros2Property()); if (pair != null && (ros2enabled == null || !ASTUtils.toBoolean(ros2enabled.getValue()))) { reporter .at(pair, Literals.KEY_VALUE_PAIR__NAME) 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 ce8470a512..b6ac6b4325 100644 --- a/core/src/main/java/org/lflang/target/property/TracingProperty.java +++ b/core/src/main/java/org/lflang/target/property/TracingProperty.java @@ -12,7 +12,6 @@ import org.lflang.lf.LfFactory; import org.lflang.lf.LfPackage.Literals; import org.lflang.lf.Model; -import org.lflang.target.TargetProperty; import org.lflang.target.property.TracingProperty.TracingOptions; import org.lflang.target.property.type.DictionaryType; import org.lflang.target.property.type.DictionaryType.DictionaryElement; @@ -64,7 +63,7 @@ public List supportedTargets() { 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, new ThreadingProperty()); + var threading = AbstractTargetProperty.getKeyValuePair(ast, new ThreadingProperty()); if (threading != null) { if (!ASTUtils.toBoolean(threading.getValue())) { reporter From 499e158f04696ec177b365bd9349102e67c615b8 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Sun, 15 Oct 2023 21:52:11 -0700 Subject: [PATCH 085/145] Address another FIXME --- .../org/lflang/AbstractTargetProperty.java | 21 +++++++++++++++++++ .../federated/extensions/CExtensionUtils.java | 5 +---- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/core/src/main/java/org/lflang/AbstractTargetProperty.java b/core/src/main/java/org/lflang/AbstractTargetProperty.java index f8ff90e78a..5034c2819e 100644 --- a/core/src/main/java/org/lflang/AbstractTargetProperty.java +++ b/core/src/main/java/org/lflang/AbstractTargetProperty.java @@ -142,14 +142,35 @@ public final void override(TargetConfig config, T value) { config.set(this, value); } + /** + * Update the given configuration using the given value. The default implementation simply assigns + * the given value, overriding whatever value might have been assigned before. + * + * @param config The configuration to update. + * @param value The value to perform the update with. + */ protected void update(TargetConfig config, T value) { override(config, 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 reporter A reporter to report issues. + */ public final void update(TargetConfig config, Element node, MessageReporter reporter) { this.update(config, fromAst(node, 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)); } diff --git a/core/src/main/java/org/lflang/federated/extensions/CExtensionUtils.java b/core/src/main/java/org/lflang/federated/extensions/CExtensionUtils.java index e61f230a78..f18e73ae8c 100644 --- a/core/src/main/java/org/lflang/federated/extensions/CExtensionUtils.java +++ b/core/src/main/java/org/lflang/federated/extensions/CExtensionUtils.java @@ -240,10 +240,7 @@ public static void initializeClockSynchronization( .nowhere() .info("Will collect clock sync statistics for federate " + federate.id); // Add libm to the compiler flags - federate - .targetConfig - .get(new CompilerFlagsProperty()) - .add("-lm"); // FIXME: add without marking as set + new CompilerFlagsProperty().update(federate.targetConfig, List.of("-lm")); } messageReporter .nowhere() From a90f44e2fb6e1ee86d36d8a3be54aef837f5f5fb Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Sun, 15 Oct 2023 22:32:17 -0700 Subject: [PATCH 086/145] Further refactoring --- ...argetProperty.java => TargetProperty.java} | 12 +- .../federated/generator/FedTargetEmitter.java | 4 +- .../generator/python/PythonGenerator.java | 1 - .../generator/rust/CargoDependencySpec.java | 3 +- .../java/org/lflang/target/TargetConfig.java | 94 ++++++++++++--- .../org/lflang/target/TargetProperty.java | 111 ------------------ .../lflang/target/property/AuthProperty.java | 2 +- ...leanProperty.java => BooleanProperty.java} | 7 +- .../property/BuildCommandsProperty.java | 4 +- .../target/property/BuildTypeProperty.java | 4 +- .../property/CargoDependenciesProperty.java | 5 +- .../property/CargoFeaturesProperty.java | 2 +- .../property/ClockSyncModeProperty.java | 5 +- .../property/ClockSyncOptionsProperty.java | 5 +- .../target/property/CmakeIncludeProperty.java | 2 +- .../property/CompileDefinitionsProperty.java | 4 +- .../property/CompilerFlagsProperty.java | 2 +- .../target/property/CompilerProperty.java | 2 +- .../property/CoordinationOptionsProperty.java | 4 +- .../target/property/CoordinationProperty.java | 5 +- .../target/property/DockerProperty.java | 4 +- .../ExportDependencyGraphProperty.java | 2 +- .../target/property/ExportToYamlProperty.java | 2 +- .../property/ExternalRuntimePathProperty.java | 2 +- .../lflang/target/property/FastProperty.java | 2 +- .../target/property/FedSetupProperty.java | 4 +- ...istProperty.java => FileListProperty.java} | 7 +- .../lflang/target/property/FilesProperty.java | 2 +- .../property/HierarchicalBinProperty.java | 2 +- .../target/property/KeepaliveProperty.java | 2 +- .../target/property/LoggingProperty.java | 4 +- .../target/property/NoCompileProperty.java | 2 +- .../property/NoRuntimeValidationProperty.java | 2 +- .../target/property/PlatformProperty.java | 6 +- .../property/PrintStatisticsProperty.java | 2 +- .../target/property/ProtobufsProperty.java | 2 +- .../property/Ros2DependenciesProperty.java | 6 +- .../lflang/target/property/Ros2Property.java | 2 +- .../property/RuntimeVersionProperty.java | 2 +- .../target/property/RustIncludeProperty.java | 4 +- .../target/property/SchedulerProperty.java | 4 +- .../property/SingleFileProjectProperty.java | 2 +- ...tProperty.java => StringListProperty.java} | 7 +- ...tStringConfig.java => StringProperty.java} | 6 +- .../target/property/ThreadingProperty.java | 2 +- .../target/property/TimeOutProperty.java | 4 +- .../target/property/TracingProperty.java | 6 +- .../target/property/VerifyProperty.java | 4 +- .../target/property/WorkersProperty.java | 4 +- .../org/lflang/validation/LFValidator.java | 3 +- .../compiler/LinguaFrancaValidationTest.java | 7 +- 51 files changed, 162 insertions(+), 226 deletions(-) rename core/src/main/java/org/lflang/{AbstractTargetProperty.java => TargetProperty.java} (94%) delete mode 100644 core/src/main/java/org/lflang/target/TargetProperty.java rename core/src/main/java/org/lflang/target/property/{AbstractBooleanProperty.java => BooleanProperty.java} (77%) rename core/src/main/java/org/lflang/target/property/{AbstractFileListProperty.java => FileListProperty.java} (86%) rename core/src/main/java/org/lflang/target/property/{AbstractStringListProperty.java => StringListProperty.java} (86%) rename core/src/main/java/org/lflang/target/property/{AbstractStringConfig.java => StringProperty.java} (78%) diff --git a/core/src/main/java/org/lflang/AbstractTargetProperty.java b/core/src/main/java/org/lflang/TargetProperty.java similarity index 94% rename from core/src/main/java/org/lflang/AbstractTargetProperty.java rename to core/src/main/java/org/lflang/TargetProperty.java index 5034c2819e..7c47afde72 100644 --- a/core/src/main/java/org/lflang/AbstractTargetProperty.java +++ b/core/src/main/java/org/lflang/TargetProperty.java @@ -10,14 +10,12 @@ import org.lflang.target.property.type.TargetPropertyType; /** - * A base class for target properties. - * - *

After implementing this class to create a new target property, add a corresponding entry to - * {@code TargetConfig} and hook it into the {@code TargetProperty} enum. + * A abstract base class for target properties. * * @param The data type of the value assigned to the target property. + * @author Marten Lohstroh */ -public abstract class AbstractTargetProperty { +public abstract class TargetProperty { /** The type of values assignable to this target property. */ public final S type; @@ -27,7 +25,7 @@ public abstract class AbstractTargetProperty { * * @param type The type of the value that can be assigned to the property. */ - public AbstractTargetProperty(S type) { + public TargetProperty(S type) { this.type = type; } @@ -199,7 +197,7 @@ public int hashCode() { * @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, AbstractTargetProperty property) { + public static KeyValuePair getKeyValuePair(Model ast, TargetProperty property) { var targetProperties = ast.getTarget().getConfig(); List properties = targetProperties.getPairs().stream() diff --git a/core/src/main/java/org/lflang/federated/generator/FedTargetEmitter.java b/core/src/main/java/org/lflang/federated/generator/FedTargetEmitter.java index bbfc16bfd2..ff273e7ead 100644 --- a/core/src/main/java/org/lflang/federated/generator/FedTargetEmitter.java +++ b/core/src/main/java/org/lflang/federated/generator/FedTargetEmitter.java @@ -6,7 +6,6 @@ import org.lflang.federated.extensions.FedTargetExtensionFactory; import org.lflang.federated.launcher.RtiConfig; import org.lflang.generator.LFGeneratorContext; -import org.lflang.target.TargetProperty; public class FedTargetEmitter { @@ -28,7 +27,6 @@ String generateTarget( context, numOfFederates, federate, fileConfig, messageReporter, rtiConfig); return FormattingUtil.renderer(federate.targetConfig.target) - .apply( - TargetProperty.extractTargetDecl(federate.targetConfig.target, federate.targetConfig)); + .apply(federate.targetConfig.extractTargetDecl()); } } diff --git a/core/src/main/java/org/lflang/generator/python/PythonGenerator.java b/core/src/main/java/org/lflang/generator/python/PythonGenerator.java index 72b3d59e5e..c9b82b9e5b 100644 --- a/core/src/main/java/org/lflang/generator/python/PythonGenerator.java +++ b/core/src/main/java/org/lflang/generator/python/PythonGenerator.java @@ -111,7 +111,6 @@ private PythonGenerator( super(context, false, types, cmakeGenerator, new PythonDelayBodyGenerator(types)); new CompilerProperty().override(this.targetConfig, "gcc"); // FIXME: why? this.targetConfig.reset(new CompilerFlagsProperty()); - this.targetConfig.linkerFlags = ""; // FIXME: why? this.types = types; } diff --git a/core/src/main/java/org/lflang/generator/rust/CargoDependencySpec.java b/core/src/main/java/org/lflang/generator/rust/CargoDependencySpec.java index d30ae87255..4b5f3f5565 100644 --- a/core/src/main/java/org/lflang/generator/rust/CargoDependencySpec.java +++ b/core/src/main/java/org/lflang/generator/rust/CargoDependencySpec.java @@ -40,12 +40,11 @@ import org.lflang.lf.KeyValuePair; import org.lflang.lf.KeyValuePairs; import org.lflang.lf.LfFactory; -import org.lflang.target.TargetProperty; import org.lflang.target.property.type.TargetPropertyType; import org.lflang.util.StringUtil; /** - * Info about a cargo dependency. See {@link TargetProperty#CARGO_DEPENDENCIES}. + * Info about a cargo dependency. See {@link org.lflang.target.property.CargoDependenciesProperty}. * * @author Clément Fournier - TU Dresden, INSA Rennes */ diff --git a/core/src/main/java/org/lflang/target/TargetConfig.java b/core/src/main/java/org/lflang/target/TargetConfig.java index 1331005760..93c8111c6b 100644 --- a/core/src/main/java/org/lflang/target/TargetConfig.java +++ b/core/src/main/java/org/lflang/target/TargetConfig.java @@ -36,11 +36,14 @@ import java.util.Properties; import java.util.Set; import java.util.stream.Collectors; -import org.lflang.AbstractTargetProperty; import org.lflang.MessageReporter; import org.lflang.Target; +import org.lflang.TargetProperty; 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.AuthProperty; import org.lflang.target.property.BuildCommandsProperty; @@ -82,6 +85,7 @@ import org.lflang.target.property.WorkersProperty; import org.lflang.target.property.type.TargetPropertyType; import org.lflang.target.property.type.VerifyProperty; +import org.lflang.validation.ValidatorMessageReporter; /** * A class for keeping the current target configuration. @@ -169,27 +173,24 @@ public TargetConfig(Properties cliArgs, TargetDecl target, MessageReporter messa /** Additional sources to add to the compile command if appropriate. */ public final List compileAdditionalSources = new ArrayList<>(); - /** Flags to pass to the linker, unless a build command has been specified. */ - public String linkerFlags = ""; + protected final Map, Object> properties = new HashMap<>(); - protected final Map, Object> properties = new HashMap<>(); + private final Set> setProperties = new HashSet<>(); - private final Set> setProperties = new HashSet<>(); - - public void register(AbstractTargetProperty... properties) { + public void register(TargetProperty... properties) { Arrays.stream(properties) .forEach(property -> this.properties.put(property, property.initialValue())); } /** Reset this target property to its initial value (and mark it as unset). */ - public void reset(AbstractTargetProperty property) { + public void reset(TargetProperty property) { this.properties.put(property, property.initialValue()); this.setProperties.remove(property); } /** Return the value currently assigned to the given target property. */ @SuppressWarnings("unchecked") - public T get(AbstractTargetProperty property) { + public T get(TargetProperty property) { return (T) properties.get(property); } @@ -197,18 +198,18 @@ public T get(AbstractTargetProperty prop * Return {@code true} if this target property has been set (past initialization), {@code false} * otherwise. */ - public boolean isSet(AbstractTargetProperty property) { + public boolean isSet(TargetProperty property) { return this.setProperties.contains(property); } public String listOfRegisteredProperties() { return getRegisteredProperties().stream() - .map(AbstractTargetProperty::toString) + .map(TargetProperty::toString) .filter(s -> !s.startsWith("_")) .collect(Collectors.joining(", ")); } - public List> getRegisteredProperties() { + public List> getRegisteredProperties() { return this.properties.keySet().stream() .sorted(Comparator.comparing(p -> p.getClass().getName())) .collect(Collectors.toList()); @@ -219,7 +220,7 @@ public String listOfRegisteredProperties() { * * @param name The string to match against. */ - public Optional> forName(String name) { + public Optional> forName(String name) { return this.getRegisteredProperties().stream() .filter(c -> c.name().equalsIgnoreCase(name)) .findFirst(); @@ -257,8 +258,7 @@ public void load(List pairs, MessageReporter err) { }); } - public void set( - AbstractTargetProperty property, T value) { + public void set(TargetProperty property, T value) { this.setProperties.add(property); this.properties.put(property, value); } @@ -272,7 +272,7 @@ public void set( */ public static List extractProperties(TargetConfig config) { var res = new LinkedList(); - for (AbstractTargetProperty p : TargetProperty.loaded(config)) { + for (TargetProperty p : loaded(config)) { KeyValuePair kv = LfFactory.eINSTANCE.createKeyValuePair(); var element = p.astElementFromConfig(config); if (element.isPresent()) { @@ -283,4 +283,66 @@ public static List extractProperties(TargetConfig config) { } return res; } + + /** + * Return all the target properties that have been set. + * + * @param config The configuration to find the properties in. + */ + public static List> loaded( + TargetConfig config) { // FIXME: move to target config + return config.getRegisteredProperties().stream() + .filter(p -> config.isSet(p)) + .collect(Collectors.toList()); + } + + /** + * Construct a {@code TargetDecl} by extracting the fields of the given {@code TargetConfig}. + * + * @return A generated TargetDecl. + */ + public TargetDecl extractTargetDecl() { + TargetDecl decl = LfFactory.eINSTANCE.createTargetDecl(); + KeyValuePairs kvp = LfFactory.eINSTANCE.createKeyValuePairs(); + for (KeyValuePair p : extractProperties(this)) { + kvp.getPairs().add(p); + } + decl.setName(target.toString()); + decl.setConfig(kvp); + return decl; + } + + /** + * Validate the given key-value pairs 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 config A target configuration used to retrieve the corresponding target properties. + * @param reporter A reporter to report errors and warnings through. + */ + public static void validate( + KeyValuePairs pairs, Model ast, TargetConfig config, ValidatorMessageReporter reporter) { + pairs.getPairs().stream() + .forEach( + pair -> { + var match = + config.getRegisteredProperties().stream() + .filter(prop -> prop.name().equalsIgnoreCase(pair.getName())) + .findAny(); + if (match.isPresent()) { + var p = match.get(); + p.checkSupport(pair, config.target, reporter); + p.checkType(pair, reporter); + p.validate(pair, ast, reporter); + } else { + reporter + .at(pair, Literals.KEY_VALUE_PAIR__NAME) + .warning( + "Unrecognized target property: " + + pair.getName() + + ". Recognized properties are: " + + config.listOfRegisteredProperties()); + } + }); + } } diff --git a/core/src/main/java/org/lflang/target/TargetProperty.java b/core/src/main/java/org/lflang/target/TargetProperty.java deleted file mode 100644 index 5caf4db8b2..0000000000 --- a/core/src/main/java/org/lflang/target/TargetProperty.java +++ /dev/null @@ -1,111 +0,0 @@ -/************* - * Copyright (c) 2019, The University of California at Berkeley. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ***************/ - -package org.lflang.target; - -import java.util.List; -import java.util.stream.Collectors; -import org.lflang.AbstractTargetProperty; -import org.lflang.Target; -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.validation.ValidatorMessageReporter; - -/** - * A target properties along with a type and a list of supporting targets that supports it, as well - * as a function for configuration updates. - * - * @author Marten Lohstroh - */ -public class TargetProperty { - - /** - * Return all the target properties that have been set. - * - * @param config The configuration to find the properties in. - */ - public static List> loaded( - TargetConfig config) { // FIXME: move to target config - return config.getRegisteredProperties().stream() - .filter(p -> config.isSet(p)) - .collect(Collectors.toList()); - } - - /** - * Constructs a {@code TargetDecl} by extracting the fields of the given {@code TargetConfig}. - * - * @param target The target to generate for. - * @param config The TargetConfig to extract from. - * @return A generated TargetDecl. - */ - public static TargetDecl extractTargetDecl(Target target, TargetConfig config) { - TargetDecl decl = LfFactory.eINSTANCE.createTargetDecl(); - KeyValuePairs kvp = LfFactory.eINSTANCE.createKeyValuePairs(); - for (KeyValuePair p : TargetConfig.extractProperties(config)) { - kvp.getPairs().add(p); - } - decl.setName(target.toString()); - decl.setConfig(kvp); - return decl; - } - - /** - * Validate the given key-value pairs 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 config A target configuration used to retrieve the corresponding target properties. - * @param reporter A reporter to report errors and warnings through. - */ - public static void validate( - KeyValuePairs pairs, Model ast, TargetConfig config, ValidatorMessageReporter reporter) { - pairs.getPairs().stream() - .forEach( - pair -> { - var match = - config.getRegisteredProperties().stream() - .filter(prop -> prop.name().equalsIgnoreCase(pair.getName())) - .findAny(); - if (match.isPresent()) { - var p = match.get(); - p.checkSupport(pair, config.target, reporter); - p.checkType(pair, reporter); - p.validate(pair, ast, reporter); - } else { - reporter - .at(pair, Literals.KEY_VALUE_PAIR__NAME) - .warning( - "Unrecognized target property: " - + pair.getName() - + ". Recognized properties are: " - + config.listOfRegisteredProperties()); - } - }); - } -} diff --git a/core/src/main/java/org/lflang/target/property/AuthProperty.java b/core/src/main/java/org/lflang/target/property/AuthProperty.java index a3e9ee6b1f..26088b1d97 100644 --- a/core/src/main/java/org/lflang/target/property/AuthProperty.java +++ b/core/src/main/java/org/lflang/target/property/AuthProperty.java @@ -5,7 +5,7 @@ import org.lflang.Target; /** Directive to allow including OpenSSL libraries and process HMAC authentication. */ -public class AuthProperty extends AbstractBooleanProperty { +public class AuthProperty extends BooleanProperty { @Override public List supportedTargets() { diff --git a/core/src/main/java/org/lflang/target/property/AbstractBooleanProperty.java b/core/src/main/java/org/lflang/target/property/BooleanProperty.java similarity index 77% rename from core/src/main/java/org/lflang/target/property/AbstractBooleanProperty.java rename to core/src/main/java/org/lflang/target/property/BooleanProperty.java index 9e6c2bc56c..b8ab9f7cb9 100644 --- a/core/src/main/java/org/lflang/target/property/AbstractBooleanProperty.java +++ b/core/src/main/java/org/lflang/target/property/BooleanProperty.java @@ -1,15 +1,14 @@ package org.lflang.target.property; -import org.lflang.AbstractTargetProperty; import org.lflang.MessageReporter; +import org.lflang.TargetProperty; import org.lflang.ast.ASTUtils; import org.lflang.lf.Element; import org.lflang.target.property.type.PrimitiveType; -public abstract class AbstractBooleanProperty - extends AbstractTargetProperty { +public abstract class BooleanProperty extends TargetProperty { - public AbstractBooleanProperty() { + public BooleanProperty() { super(PrimitiveType.BOOLEAN); } diff --git a/core/src/main/java/org/lflang/target/property/BuildCommandsProperty.java b/core/src/main/java/org/lflang/target/property/BuildCommandsProperty.java index 19ccaba064..8049f02668 100644 --- a/core/src/main/java/org/lflang/target/property/BuildCommandsProperty.java +++ b/core/src/main/java/org/lflang/target/property/BuildCommandsProperty.java @@ -3,9 +3,9 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import org.lflang.AbstractTargetProperty; import org.lflang.MessageReporter; import org.lflang.Target; +import org.lflang.TargetProperty; import org.lflang.ast.ASTUtils; import org.lflang.lf.Element; import org.lflang.target.property.type.UnionType; @@ -15,7 +15,7 @@ * designated compiler. A common usage of this target property is to set the command to build on the * basis of a Makefile. */ -public class BuildCommandsProperty extends AbstractTargetProperty, UnionType> { +public class BuildCommandsProperty extends TargetProperty, UnionType> { public BuildCommandsProperty() { super(UnionType.STRING_OR_STRING_ARRAY); diff --git a/core/src/main/java/org/lflang/target/property/BuildTypeProperty.java b/core/src/main/java/org/lflang/target/property/BuildTypeProperty.java index 48def1278c..66ac8273b1 100644 --- a/core/src/main/java/org/lflang/target/property/BuildTypeProperty.java +++ b/core/src/main/java/org/lflang/target/property/BuildTypeProperty.java @@ -2,9 +2,9 @@ import java.util.Arrays; import java.util.List; -import org.lflang.AbstractTargetProperty; import org.lflang.MessageReporter; import org.lflang.Target; +import org.lflang.TargetProperty; import org.lflang.ast.ASTUtils; import org.lflang.lf.Element; import org.lflang.target.property.type.BuildTypeType; @@ -14,7 +14,7 @@ * Directive to specify the target build type such as 'Release' or 'Debug'. This is also used in the * Rust target to select a Cargo profile. */ -public class BuildTypeProperty extends AbstractTargetProperty { +public class BuildTypeProperty extends TargetProperty { public BuildTypeProperty() { super(new BuildTypeType()); 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 95a95790c1..17bbadd732 100644 --- a/core/src/main/java/org/lflang/target/property/CargoDependenciesProperty.java +++ b/core/src/main/java/org/lflang/target/property/CargoDependenciesProperty.java @@ -4,9 +4,9 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import org.lflang.AbstractTargetProperty; import org.lflang.MessageReporter; import org.lflang.Target; +import org.lflang.TargetProperty; import org.lflang.generator.rust.CargoDependencySpec; import org.lflang.generator.rust.CargoDependencySpec.CargoDependenciesPropertyType; import org.lflang.lf.Element; @@ -40,8 +40,7 @@ * } */ public class CargoDependenciesProperty - extends AbstractTargetProperty< - Map, CargoDependenciesPropertyType> { + extends TargetProperty, CargoDependenciesPropertyType> { public CargoDependenciesProperty() { super(new CargoDependenciesPropertyType()); diff --git a/core/src/main/java/org/lflang/target/property/CargoFeaturesProperty.java b/core/src/main/java/org/lflang/target/property/CargoFeaturesProperty.java index afe9d7efc9..d9c050dec9 100644 --- a/core/src/main/java/org/lflang/target/property/CargoFeaturesProperty.java +++ b/core/src/main/java/org/lflang/target/property/CargoFeaturesProperty.java @@ -5,7 +5,7 @@ import org.lflang.Target; /** Directive for specifying Cargo features of the generated program to enable. */ -public class CargoFeaturesProperty extends AbstractStringListProperty { +public class CargoFeaturesProperty extends StringListProperty { @Override public List supportedTargets() { 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 06863f3a01..584ddc4856 100644 --- a/core/src/main/java/org/lflang/target/property/ClockSyncModeProperty.java +++ b/core/src/main/java/org/lflang/target/property/ClockSyncModeProperty.java @@ -2,9 +2,9 @@ import java.util.List; import java.util.Objects; -import org.lflang.AbstractTargetProperty; import org.lflang.MessageReporter; import org.lflang.Target; +import org.lflang.TargetProperty; import org.lflang.ast.ASTUtils; import org.lflang.lf.Element; import org.lflang.lf.KeyValuePair; @@ -15,8 +15,7 @@ import org.lflang.target.property.type.ClockSyncModeType.ClockSyncMode; /** The mode of clock synchronization to be used in federated programs. The default is 'initial'. */ -public class ClockSyncModeProperty - extends AbstractTargetProperty { +public class ClockSyncModeProperty extends TargetProperty { public ClockSyncModeProperty() { super(new ClockSyncModeType()); 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 d84fefe76c..92ef3fdafd 100644 --- a/core/src/main/java/org/lflang/target/property/ClockSyncOptionsProperty.java +++ b/core/src/main/java/org/lflang/target/property/ClockSyncOptionsProperty.java @@ -2,9 +2,9 @@ import java.util.Arrays; import java.util.List; -import org.lflang.AbstractTargetProperty; import org.lflang.MessageReporter; import org.lflang.Target; +import org.lflang.TargetProperty; import org.lflang.TimeUnit; import org.lflang.TimeValue; import org.lflang.ast.ASTUtils; @@ -19,8 +19,7 @@ import org.lflang.target.property.type.TargetPropertyType; /** Key-value pairs giving options for clock synchronization. */ -public class ClockSyncOptionsProperty - extends AbstractTargetProperty { +public class ClockSyncOptionsProperty extends TargetProperty { public ClockSyncOptionsProperty() { super(DictionaryType.CLOCK_SYNC_OPTION_DICT); diff --git a/core/src/main/java/org/lflang/target/property/CmakeIncludeProperty.java b/core/src/main/java/org/lflang/target/property/CmakeIncludeProperty.java index 07937a632e..b5ca6a6970 100644 --- a/core/src/main/java/org/lflang/target/property/CmakeIncludeProperty.java +++ b/core/src/main/java/org/lflang/target/property/CmakeIncludeProperty.java @@ -13,7 +13,7 @@ *

This gives full control over the C/C++ build as any cmake parameters can be adjusted in the * included file. */ -public class CmakeIncludeProperty extends AbstractFileListProperty { +public class CmakeIncludeProperty extends FileListProperty { @Override protected List fromAst(Element node, MessageReporter reporter) { diff --git a/core/src/main/java/org/lflang/target/property/CompileDefinitionsProperty.java b/core/src/main/java/org/lflang/target/property/CompileDefinitionsProperty.java index d65b608940..51e9ed34ae 100644 --- a/core/src/main/java/org/lflang/target/property/CompileDefinitionsProperty.java +++ b/core/src/main/java/org/lflang/target/property/CompileDefinitionsProperty.java @@ -4,9 +4,9 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import org.lflang.AbstractTargetProperty; import org.lflang.MessageReporter; import org.lflang.Target; +import org.lflang.TargetProperty; import org.lflang.ast.ASTUtils; import org.lflang.lf.Element; import org.lflang.target.TargetConfig; @@ -19,7 +19,7 @@ * that definition, if any. The second value could be left empty. */ public class CompileDefinitionsProperty - extends AbstractTargetProperty, StringDictionaryType> { + extends TargetProperty, StringDictionaryType> { public CompileDefinitionsProperty() { super(StringDictionaryType.COMPILE_DEFINITION); diff --git a/core/src/main/java/org/lflang/target/property/CompilerFlagsProperty.java b/core/src/main/java/org/lflang/target/property/CompilerFlagsProperty.java index 8f9aee85ca..8902f605f2 100644 --- a/core/src/main/java/org/lflang/target/property/CompilerFlagsProperty.java +++ b/core/src/main/java/org/lflang/target/property/CompilerFlagsProperty.java @@ -5,7 +5,7 @@ import org.lflang.Target; /** Flags to pass to the compiler, unless a build command has been specified. */ -public class CompilerFlagsProperty extends AbstractStringListProperty { +public class CompilerFlagsProperty extends StringListProperty { @Override public List supportedTargets() { diff --git a/core/src/main/java/org/lflang/target/property/CompilerProperty.java b/core/src/main/java/org/lflang/target/property/CompilerProperty.java index 635a66e421..daa9b50b28 100644 --- a/core/src/main/java/org/lflang/target/property/CompilerProperty.java +++ b/core/src/main/java/org/lflang/target/property/CompilerProperty.java @@ -4,7 +4,7 @@ import org.lflang.Target; /** The compiler to invoke, unless a build command has been specified. */ -public class CompilerProperty extends AbstractStringConfig { +public class CompilerProperty extends StringProperty { @Override public List supportedTargets() { 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 c7247627e0..e82b43ffc6 100644 --- a/core/src/main/java/org/lflang/target/property/CoordinationOptionsProperty.java +++ b/core/src/main/java/org/lflang/target/property/CoordinationOptionsProperty.java @@ -3,9 +3,9 @@ import java.util.Arrays; import java.util.List; import java.util.Objects; -import org.lflang.AbstractTargetProperty; import org.lflang.MessageReporter; import org.lflang.Target; +import org.lflang.TargetProperty; import org.lflang.TimeValue; import org.lflang.ast.ASTUtils; import org.lflang.lf.Element; @@ -20,7 +20,7 @@ /** Key-value pairs giving options for clock synchronization. */ public class CoordinationOptionsProperty - extends AbstractTargetProperty { + extends TargetProperty { public CoordinationOptionsProperty() { super(DictionaryType.COORDINATION_OPTION_DICT); diff --git a/core/src/main/java/org/lflang/target/property/CoordinationProperty.java b/core/src/main/java/org/lflang/target/property/CoordinationProperty.java index 361960f934..83068bbe19 100644 --- a/core/src/main/java/org/lflang/target/property/CoordinationProperty.java +++ b/core/src/main/java/org/lflang/target/property/CoordinationProperty.java @@ -2,9 +2,9 @@ import java.util.Arrays; import java.util.List; -import org.lflang.AbstractTargetProperty; import org.lflang.MessageReporter; import org.lflang.Target; +import org.lflang.TargetProperty; import org.lflang.ast.ASTUtils; import org.lflang.lf.Element; import org.lflang.target.property.type.CoordinationModeType; @@ -14,8 +14,7 @@ * The type of coordination used during the execution of a federated program. The default is * 'centralized'. */ -public class CoordinationProperty - extends AbstractTargetProperty { +public class CoordinationProperty extends TargetProperty { public CoordinationProperty() { super(new CoordinationModeType()); 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 67a454528d..e3b0e0bbd4 100644 --- a/core/src/main/java/org/lflang/target/property/DockerProperty.java +++ b/core/src/main/java/org/lflang/target/property/DockerProperty.java @@ -3,9 +3,9 @@ import java.util.Arrays; import java.util.List; import java.util.Objects; -import org.lflang.AbstractTargetProperty; import org.lflang.MessageReporter; import org.lflang.Target; +import org.lflang.TargetProperty; import org.lflang.ast.ASTUtils; import org.lflang.lf.Element; import org.lflang.lf.KeyValuePair; @@ -22,7 +22,7 @@ * Directive to generate a Dockerfile. This is either a boolean, true or false, or a dictionary of * options. */ -public class DockerProperty extends AbstractTargetProperty { +public class DockerProperty extends TargetProperty { public DockerProperty() { super(UnionType.DOCKER_UNION); diff --git a/core/src/main/java/org/lflang/target/property/ExportDependencyGraphProperty.java b/core/src/main/java/org/lflang/target/property/ExportDependencyGraphProperty.java index 0f8c80ae6d..87628d2a9c 100644 --- a/core/src/main/java/org/lflang/target/property/ExportDependencyGraphProperty.java +++ b/core/src/main/java/org/lflang/target/property/ExportDependencyGraphProperty.java @@ -9,7 +9,7 @@ *

This option is currently only used for C++ and Rust. This export function is a valuable tool * for debugging LF programs and helps to understand the dependencies inferred by the runtime. */ -public class ExportDependencyGraphProperty extends AbstractBooleanProperty { +public class ExportDependencyGraphProperty extends BooleanProperty { @Override public List supportedTargets() { diff --git a/core/src/main/java/org/lflang/target/property/ExportToYamlProperty.java b/core/src/main/java/org/lflang/target/property/ExportToYamlProperty.java index 437b6d333f..bd6d975ed7 100644 --- a/core/src/main/java/org/lflang/target/property/ExportToYamlProperty.java +++ b/core/src/main/java/org/lflang/target/property/ExportToYamlProperty.java @@ -10,7 +10,7 @@ *

This option is currently only used for C++. This export function is a valuable tool for * debugging LF programs and performing external analysis. */ -public class ExportToYamlProperty extends AbstractBooleanProperty { +public class ExportToYamlProperty extends BooleanProperty { @Override public List supportedTargets() { diff --git a/core/src/main/java/org/lflang/target/property/ExternalRuntimePathProperty.java b/core/src/main/java/org/lflang/target/property/ExternalRuntimePathProperty.java index 615e7c9e55..36bace7002 100644 --- a/core/src/main/java/org/lflang/target/property/ExternalRuntimePathProperty.java +++ b/core/src/main/java/org/lflang/target/property/ExternalRuntimePathProperty.java @@ -7,7 +7,7 @@ * Directive for specifying a path to an external runtime libray to link to instead of the default * one. */ -public class ExternalRuntimePathProperty extends AbstractStringConfig { +public class ExternalRuntimePathProperty extends StringProperty { @Override public List supportedTargets() { 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 e57a13e46d..c4106f525e 100644 --- a/core/src/main/java/org/lflang/target/property/FastProperty.java +++ b/core/src/main/java/org/lflang/target/property/FastProperty.java @@ -15,7 +15,7 @@ * If true, configure the execution environment such that it does not wait for physical time to * match logical time. The default is false. */ -public class FastProperty extends AbstractBooleanProperty { +public class FastProperty extends BooleanProperty { @Override public List supportedTargets() { diff --git a/core/src/main/java/org/lflang/target/property/FedSetupProperty.java b/core/src/main/java/org/lflang/target/property/FedSetupProperty.java index e49d2b535e..b532448bfd 100644 --- a/core/src/main/java/org/lflang/target/property/FedSetupProperty.java +++ b/core/src/main/java/org/lflang/target/property/FedSetupProperty.java @@ -1,9 +1,9 @@ package org.lflang.target.property; import java.util.List; -import org.lflang.AbstractTargetProperty; import org.lflang.MessageReporter; import org.lflang.Target; +import org.lflang.TargetProperty; import org.lflang.ast.ASTUtils; import org.lflang.lf.Element; import org.lflang.target.property.type.PrimitiveType; @@ -13,7 +13,7 @@ * Directs the C or Python target to include the associated C file used for setting up federated * execution before processing the first tag. */ -public class FedSetupProperty extends AbstractTargetProperty { +public class FedSetupProperty extends TargetProperty { public FedSetupProperty() { super(PrimitiveType.FILE); diff --git a/core/src/main/java/org/lflang/target/property/AbstractFileListProperty.java b/core/src/main/java/org/lflang/target/property/FileListProperty.java similarity index 86% rename from core/src/main/java/org/lflang/target/property/AbstractFileListProperty.java rename to core/src/main/java/org/lflang/target/property/FileListProperty.java index 0fd7087136..0baaadec0c 100644 --- a/core/src/main/java/org/lflang/target/property/AbstractFileListProperty.java +++ b/core/src/main/java/org/lflang/target/property/FileListProperty.java @@ -2,17 +2,16 @@ import java.util.ArrayList; import java.util.List; -import org.lflang.AbstractTargetProperty; import org.lflang.MessageReporter; +import org.lflang.TargetProperty; import org.lflang.ast.ASTUtils; import org.lflang.lf.Element; import org.lflang.target.TargetConfig; import org.lflang.target.property.type.UnionType; -public abstract class AbstractFileListProperty - extends AbstractTargetProperty, UnionType> { +public abstract class FileListProperty extends TargetProperty, UnionType> { - public AbstractFileListProperty() { + public FileListProperty() { super(UnionType.FILE_OR_FILE_ARRAY); } diff --git a/core/src/main/java/org/lflang/target/property/FilesProperty.java b/core/src/main/java/org/lflang/target/property/FilesProperty.java index 77159fcddb..cb56324958 100644 --- a/core/src/main/java/org/lflang/target/property/FilesProperty.java +++ b/core/src/main/java/org/lflang/target/property/FilesProperty.java @@ -4,7 +4,7 @@ import org.lflang.Target; /** Directive to stage particular files on the class path to be processed by the code generator. */ -public class FilesProperty extends AbstractFileListProperty { +public class FilesProperty extends FileListProperty { @Override public List supportedTargets() { diff --git a/core/src/main/java/org/lflang/target/property/HierarchicalBinProperty.java b/core/src/main/java/org/lflang/target/property/HierarchicalBinProperty.java index 8dfa87bdc7..5fc3a856e8 100644 --- a/core/src/main/java/org/lflang/target/property/HierarchicalBinProperty.java +++ b/core/src/main/java/org/lflang/target/property/HierarchicalBinProperty.java @@ -7,7 +7,7 @@ /** * Whether the bin directory should have a flat or hierarchical organization. It is flat by default. */ -public class HierarchicalBinProperty extends AbstractBooleanProperty { +public class HierarchicalBinProperty extends BooleanProperty { @Override public List supportedTargets() { diff --git a/core/src/main/java/org/lflang/target/property/KeepaliveProperty.java b/core/src/main/java/org/lflang/target/property/KeepaliveProperty.java index da6d994c1d..76a1515632 100644 --- a/core/src/main/java/org/lflang/target/property/KeepaliveProperty.java +++ b/core/src/main/java/org/lflang/target/property/KeepaliveProperty.java @@ -7,7 +7,7 @@ * If true, configure the execution environment to keep executing if there are no more events on the * event queue. The default is false. */ -public class KeepaliveProperty extends AbstractBooleanProperty { +public class KeepaliveProperty extends BooleanProperty { @Override public List supportedTargets() { diff --git a/core/src/main/java/org/lflang/target/property/LoggingProperty.java b/core/src/main/java/org/lflang/target/property/LoggingProperty.java index e7d40d49a5..080697ffee 100644 --- a/core/src/main/java/org/lflang/target/property/LoggingProperty.java +++ b/core/src/main/java/org/lflang/target/property/LoggingProperty.java @@ -1,9 +1,9 @@ package org.lflang.target.property; import java.util.List; -import org.lflang.AbstractTargetProperty; import org.lflang.MessageReporter; import org.lflang.Target; +import org.lflang.TargetProperty; import org.lflang.ast.ASTUtils; import org.lflang.lf.Element; import org.lflang.target.property.type.LoggingType; @@ -13,7 +13,7 @@ * Directive to specify the grain at which to report log messages during execution. The default is * INFO. */ -public class LoggingProperty extends AbstractTargetProperty { +public class LoggingProperty extends TargetProperty { public LoggingProperty() { super(new LoggingType()); diff --git a/core/src/main/java/org/lflang/target/property/NoCompileProperty.java b/core/src/main/java/org/lflang/target/property/NoCompileProperty.java index b1a6a375b0..b0b7513c21 100644 --- a/core/src/main/java/org/lflang/target/property/NoCompileProperty.java +++ b/core/src/main/java/org/lflang/target/property/NoCompileProperty.java @@ -5,7 +5,7 @@ import org.lflang.Target; /** If true, do not invoke the target compiler or build command. The default is false. */ -public class NoCompileProperty extends AbstractBooleanProperty { +public class NoCompileProperty extends BooleanProperty { @Override public List supportedTargets() { diff --git a/core/src/main/java/org/lflang/target/property/NoRuntimeValidationProperty.java b/core/src/main/java/org/lflang/target/property/NoRuntimeValidationProperty.java index e9176d6680..216bfe8491 100644 --- a/core/src/main/java/org/lflang/target/property/NoRuntimeValidationProperty.java +++ b/core/src/main/java/org/lflang/target/property/NoRuntimeValidationProperty.java @@ -4,7 +4,7 @@ import org.lflang.Target; /** If true, do not perform runtime validation. The default is false. */ -public class NoRuntimeValidationProperty extends AbstractBooleanProperty { +public class NoRuntimeValidationProperty extends BooleanProperty { @Override public List supportedTargets() { 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 55c8110dec..73287acd83 100644 --- a/core/src/main/java/org/lflang/target/property/PlatformProperty.java +++ b/core/src/main/java/org/lflang/target/property/PlatformProperty.java @@ -1,9 +1,9 @@ package org.lflang.target.property; import java.util.List; -import org.lflang.AbstractTargetProperty; import org.lflang.MessageReporter; import org.lflang.Target; +import org.lflang.TargetProperty; import org.lflang.ast.ASTUtils; import org.lflang.lf.Element; import org.lflang.lf.KeyValuePair; @@ -24,7 +24,7 @@ * Directive to specify the platform for cross code generation. This is either a string of the * platform or a dictionary of options that includes the string name. */ -public class PlatformProperty extends AbstractTargetProperty { +public class PlatformProperty extends TargetProperty { public PlatformProperty() { super(UnionType.PLATFORM_STRING_OR_DICTIONARY); @@ -77,7 +77,7 @@ public List supportedTargets() { @Override public void validate(KeyValuePair pair, Model ast, MessageReporter reporter) { var config = fromAst(pair.getValue(), reporter); - var threading = AbstractTargetProperty.getKeyValuePair(ast, new ThreadingProperty()); + var threading = TargetProperty.getKeyValuePair(ast, new ThreadingProperty()); if (threading != null && config.platform == Platform.RP2040) { reporter .at(pair, Literals.KEY_VALUE_PAIR__VALUE) diff --git a/core/src/main/java/org/lflang/target/property/PrintStatisticsProperty.java b/core/src/main/java/org/lflang/target/property/PrintStatisticsProperty.java index c722a8530d..d682f40a6a 100644 --- a/core/src/main/java/org/lflang/target/property/PrintStatisticsProperty.java +++ b/core/src/main/java/org/lflang/target/property/PrintStatisticsProperty.java @@ -4,7 +4,7 @@ import org.lflang.Target; /** If true, instruct the runtime to collect and print execution statistics. */ -public class PrintStatisticsProperty extends AbstractBooleanProperty { +public class PrintStatisticsProperty extends BooleanProperty { @Override public List supportedTargets() { diff --git a/core/src/main/java/org/lflang/target/property/ProtobufsProperty.java b/core/src/main/java/org/lflang/target/property/ProtobufsProperty.java index 79bd510f21..426723a93a 100644 --- a/core/src/main/java/org/lflang/target/property/ProtobufsProperty.java +++ b/core/src/main/java/org/lflang/target/property/ProtobufsProperty.java @@ -7,7 +7,7 @@ * Directive for specifying .proto files that need to be compiled and their code included in the * sources. */ -public class ProtobufsProperty extends AbstractFileListProperty { +public class ProtobufsProperty extends FileListProperty { @Override public List supportedTargets() { 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 426d8c02a0..ca5bfc1ffd 100644 --- a/core/src/main/java/org/lflang/target/property/Ros2DependenciesProperty.java +++ b/core/src/main/java/org/lflang/target/property/Ros2DependenciesProperty.java @@ -2,9 +2,9 @@ import java.util.ArrayList; import java.util.List; -import org.lflang.AbstractTargetProperty; import org.lflang.MessageReporter; import org.lflang.Target; +import org.lflang.TargetProperty; import org.lflang.ast.ASTUtils; import org.lflang.lf.Element; import org.lflang.lf.KeyValuePair; @@ -13,7 +13,7 @@ import org.lflang.target.property.type.ArrayType; /** Directive to specify additional ROS2 packages that this LF program depends on. */ -public class Ros2DependenciesProperty extends AbstractTargetProperty, ArrayType> { +public class Ros2DependenciesProperty extends TargetProperty, ArrayType> { public Ros2DependenciesProperty() { super(ArrayType.STRING_ARRAY); @@ -41,7 +41,7 @@ public List supportedTargets() { @Override public void validate(KeyValuePair pair, Model ast, MessageReporter reporter) { - var ros2enabled = AbstractTargetProperty.getKeyValuePair(ast, new Ros2Property()); + var ros2enabled = TargetProperty.getKeyValuePair(ast, new Ros2Property()); if (pair != null && (ros2enabled == null || !ASTUtils.toBoolean(ros2enabled.getValue()))) { reporter .at(pair, Literals.KEY_VALUE_PAIR__NAME) diff --git a/core/src/main/java/org/lflang/target/property/Ros2Property.java b/core/src/main/java/org/lflang/target/property/Ros2Property.java index c4fd562ac6..a9c0b02431 100644 --- a/core/src/main/java/org/lflang/target/property/Ros2Property.java +++ b/core/src/main/java/org/lflang/target/property/Ros2Property.java @@ -4,7 +4,7 @@ import org.lflang.Target; /** If true, generate ROS2 specific code. */ -public class Ros2Property extends AbstractBooleanProperty { +public class Ros2Property extends BooleanProperty { @Override public List supportedTargets() { diff --git a/core/src/main/java/org/lflang/target/property/RuntimeVersionProperty.java b/core/src/main/java/org/lflang/target/property/RuntimeVersionProperty.java index 68c41f8c81..ceb93cfc52 100644 --- a/core/src/main/java/org/lflang/target/property/RuntimeVersionProperty.java +++ b/core/src/main/java/org/lflang/target/property/RuntimeVersionProperty.java @@ -4,7 +4,7 @@ import org.lflang.Target; /** Directive for specifying a specific version of the reactor runtime library. */ -public class RuntimeVersionProperty extends AbstractStringConfig { +public class RuntimeVersionProperty extends StringProperty { @Override public List supportedTargets() { diff --git a/core/src/main/java/org/lflang/target/property/RustIncludeProperty.java b/core/src/main/java/org/lflang/target/property/RustIncludeProperty.java index 851bf7030f..62dcb6a49d 100644 --- a/core/src/main/java/org/lflang/target/property/RustIncludeProperty.java +++ b/core/src/main/java/org/lflang/target/property/RustIncludeProperty.java @@ -5,9 +5,9 @@ import java.util.ArrayList; import java.util.List; import org.eclipse.emf.ecore.EObject; -import org.lflang.AbstractTargetProperty; import org.lflang.MessageReporter; import org.lflang.Target; +import org.lflang.TargetProperty; import org.lflang.ast.ASTUtils; import org.lflang.lf.Array; import org.lflang.lf.Element; @@ -22,7 +22,7 @@ * the generated {@code main.rs} will include it with a {@code mod foo;}. If one of the paths is a * directory, it must contain a {@code mod.rs} file, and all its contents are copied. */ -public class RustIncludeProperty extends AbstractTargetProperty, UnionType> { +public class RustIncludeProperty extends TargetProperty, UnionType> { public RustIncludeProperty() { super(UnionType.FILE_OR_FILE_ARRAY); 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 14de36e2da..d981009f58 100644 --- a/core/src/main/java/org/lflang/target/property/SchedulerProperty.java +++ b/core/src/main/java/org/lflang/target/property/SchedulerProperty.java @@ -2,9 +2,9 @@ import java.util.Arrays; import java.util.List; -import org.lflang.AbstractTargetProperty; import org.lflang.MessageReporter; import org.lflang.Target; +import org.lflang.TargetProperty; import org.lflang.ast.ASTUtils; import org.lflang.lf.Element; import org.lflang.lf.KeyValuePair; @@ -14,7 +14,7 @@ import org.lflang.target.property.type.SchedulerType.Scheduler; /** Directive for specifying the use of a specific runtime scheduler. */ -public class SchedulerProperty extends AbstractTargetProperty { +public class SchedulerProperty extends TargetProperty { public SchedulerProperty() { super(new SchedulerType()); diff --git a/core/src/main/java/org/lflang/target/property/SingleFileProjectProperty.java b/core/src/main/java/org/lflang/target/property/SingleFileProjectProperty.java index 7434907305..952c0c9f01 100644 --- a/core/src/main/java/org/lflang/target/property/SingleFileProjectProperty.java +++ b/core/src/main/java/org/lflang/target/property/SingleFileProjectProperty.java @@ -4,7 +4,7 @@ import org.lflang.Target; /** Directive to specify that all code is generated in a single file. */ -public class SingleFileProjectProperty extends AbstractBooleanProperty { +public class SingleFileProjectProperty extends BooleanProperty { @Override public List supportedTargets() { diff --git a/core/src/main/java/org/lflang/target/property/AbstractStringListProperty.java b/core/src/main/java/org/lflang/target/property/StringListProperty.java similarity index 86% rename from core/src/main/java/org/lflang/target/property/AbstractStringListProperty.java rename to core/src/main/java/org/lflang/target/property/StringListProperty.java index ba5e99c22e..1a010e0ea8 100644 --- a/core/src/main/java/org/lflang/target/property/AbstractStringListProperty.java +++ b/core/src/main/java/org/lflang/target/property/StringListProperty.java @@ -2,18 +2,17 @@ import java.util.ArrayList; import java.util.List; -import org.lflang.AbstractTargetProperty; import org.lflang.MessageReporter; +import org.lflang.TargetProperty; import org.lflang.ast.ASTUtils; import org.lflang.lf.Element; import org.lflang.target.TargetConfig; import org.lflang.target.property.type.UnionType; /** Note: {@code set} implements an "append" semantics. */ -public abstract class AbstractStringListProperty - extends AbstractTargetProperty, UnionType> { +public abstract class StringListProperty extends TargetProperty, UnionType> { - public AbstractStringListProperty() { + public StringListProperty() { super(UnionType.STRING_OR_STRING_ARRAY); } diff --git a/core/src/main/java/org/lflang/target/property/AbstractStringConfig.java b/core/src/main/java/org/lflang/target/property/StringProperty.java similarity index 78% rename from core/src/main/java/org/lflang/target/property/AbstractStringConfig.java rename to core/src/main/java/org/lflang/target/property/StringProperty.java index a82bbd0e26..a3536ffff4 100644 --- a/core/src/main/java/org/lflang/target/property/AbstractStringConfig.java +++ b/core/src/main/java/org/lflang/target/property/StringProperty.java @@ -1,14 +1,14 @@ package org.lflang.target.property; -import org.lflang.AbstractTargetProperty; import org.lflang.MessageReporter; +import org.lflang.TargetProperty; import org.lflang.ast.ASTUtils; import org.lflang.lf.Element; import org.lflang.target.property.type.PrimitiveType; -public abstract class AbstractStringConfig extends AbstractTargetProperty { +public abstract class StringProperty extends TargetProperty { - public AbstractStringConfig() { + public StringProperty() { super(PrimitiveType.STRING); } diff --git a/core/src/main/java/org/lflang/target/property/ThreadingProperty.java b/core/src/main/java/org/lflang/target/property/ThreadingProperty.java index 4bbcf3aba6..0071899c81 100644 --- a/core/src/main/java/org/lflang/target/property/ThreadingProperty.java +++ b/core/src/main/java/org/lflang/target/property/ThreadingProperty.java @@ -4,7 +4,7 @@ import org.lflang.Target; /** Directive to indicate whether the runtime should use multi-threading. */ -public class ThreadingProperty extends AbstractBooleanProperty { +public class ThreadingProperty extends BooleanProperty { @Override public List supportedTargets() { diff --git a/core/src/main/java/org/lflang/target/property/TimeOutProperty.java b/core/src/main/java/org/lflang/target/property/TimeOutProperty.java index 2a118a3851..b853822e12 100644 --- a/core/src/main/java/org/lflang/target/property/TimeOutProperty.java +++ b/core/src/main/java/org/lflang/target/property/TimeOutProperty.java @@ -1,16 +1,16 @@ package org.lflang.target.property; import java.util.List; -import org.lflang.AbstractTargetProperty; import org.lflang.MessageReporter; import org.lflang.Target; +import org.lflang.TargetProperty; import org.lflang.TimeValue; import org.lflang.ast.ASTUtils; import org.lflang.lf.Element; import org.lflang.target.property.type.PrimitiveType; /** The timeout to be observed during execution of the program. */ -public class TimeOutProperty extends AbstractTargetProperty { +public class TimeOutProperty extends TargetProperty { public TimeOutProperty() { super(PrimitiveType.TIME_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 b6ac6b4325..b0298a500f 100644 --- a/core/src/main/java/org/lflang/target/property/TracingProperty.java +++ b/core/src/main/java/org/lflang/target/property/TracingProperty.java @@ -2,9 +2,9 @@ import java.util.List; import java.util.Objects; -import org.lflang.AbstractTargetProperty; import org.lflang.MessageReporter; import org.lflang.Target; +import org.lflang.TargetProperty; import org.lflang.ast.ASTUtils; import org.lflang.lf.Element; import org.lflang.lf.KeyValuePair; @@ -20,7 +20,7 @@ import org.lflang.target.property.type.UnionType; /** Directive to configure the runtime environment to perform tracing. */ -public class TracingProperty extends AbstractTargetProperty { +public class TracingProperty extends TargetProperty { public TracingProperty() { super(UnionType.TRACING_UNION); @@ -63,7 +63,7 @@ public List supportedTargets() { 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 = AbstractTargetProperty.getKeyValuePair(ast, new ThreadingProperty()); + var threading = TargetProperty.getKeyValuePair(ast, new ThreadingProperty()); if (threading != null) { if (!ASTUtils.toBoolean(threading.getValue())) { reporter diff --git a/core/src/main/java/org/lflang/target/property/VerifyProperty.java b/core/src/main/java/org/lflang/target/property/VerifyProperty.java index c26421dc03..99317847f7 100644 --- a/core/src/main/java/org/lflang/target/property/VerifyProperty.java +++ b/core/src/main/java/org/lflang/target/property/VerifyProperty.java @@ -2,10 +2,10 @@ import java.util.List; import org.lflang.Target; -import org.lflang.target.property.AbstractBooleanProperty; +import org.lflang.target.property.BooleanProperty; /** If true, check the generated verification model. The default is false. */ -public class VerifyProperty extends AbstractBooleanProperty { +public class VerifyProperty extends BooleanProperty { @Override public List supportedTargets() { 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 88e9292322..fab1b4bb82 100644 --- a/core/src/main/java/org/lflang/target/property/WorkersProperty.java +++ b/core/src/main/java/org/lflang/target/property/WorkersProperty.java @@ -1,9 +1,9 @@ package org.lflang.target.property; import java.util.List; -import org.lflang.AbstractTargetProperty; import org.lflang.MessageReporter; import org.lflang.Target; +import org.lflang.TargetProperty; import org.lflang.ast.ASTUtils; import org.lflang.lf.Element; import org.lflang.target.property.type.PrimitiveType; @@ -12,7 +12,7 @@ * The number of worker threads to deploy. The default is zero, which indicates that the runtime is * allowed to freely choose the number of workers. */ -public class WorkersProperty extends AbstractTargetProperty { +public class WorkersProperty extends TargetProperty { public WorkersProperty() { super(PrimitiveType.NON_NEGATIVE_INTEGER); diff --git a/core/src/main/java/org/lflang/validation/LFValidator.java b/core/src/main/java/org/lflang/validation/LFValidator.java index 7c961fc00c..218d5e1d4d 100644 --- a/core/src/main/java/org/lflang/validation/LFValidator.java +++ b/core/src/main/java/org/lflang/validation/LFValidator.java @@ -114,7 +114,6 @@ import org.lflang.lf.WidthSpec; import org.lflang.lf.WidthTerm; import org.lflang.target.TargetConfig; -import org.lflang.target.TargetProperty; import org.lflang.util.FileUtil; /** @@ -1076,7 +1075,7 @@ public void checkTargetDecl(TargetDecl target) throws IOException { public void checkTargetProperties(KeyValuePairs targetProperties) { if (targetProperties.eContainer() instanceof TargetDecl) { // Only validate the target properties, not dictionaries that may be part of their values. - TargetProperty.validate( + TargetConfig.validate( targetProperties, this.info.model, new TargetConfig(this.target), 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 f015b017b9..3b434ebb4e 100644 --- a/core/src/test/java/org/lflang/tests/compiler/LinguaFrancaValidationTest.java +++ b/core/src/test/java/org/lflang/tests/compiler/LinguaFrancaValidationTest.java @@ -44,8 +44,8 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestFactory; import org.junit.jupiter.api.extension.ExtendWith; -import org.lflang.AbstractTargetProperty; import org.lflang.Target; +import org.lflang.TargetProperty; import org.lflang.TimeValue; import org.lflang.lf.LfPackage; import org.lflang.lf.Model; @@ -1476,8 +1476,7 @@ private List synthesizeExamples(TargetPropertyType type, boolean correct * Create an LF program with the given key and value as a target property, parse it, and return * the resulting model. */ - private Model createModel(Target target, AbstractTargetProperty property, String value) - throws Exception { + private Model createModel(Target target, TargetProperty property, String value) throws Exception { return parseWithoutError( """ target %s {%s: %s}; @@ -1494,7 +1493,7 @@ private Model createModel(Target target, AbstractTargetProperty property, String public Collection checkTargetProperties() throws Exception { List result = new ArrayList<>(); - for (AbstractTargetProperty property : (new TargetConfig(Target.C)).getRegisteredProperties()) { + for (TargetProperty property : (new TargetConfig(Target.C)).getRegisteredProperties()) { if (property instanceof CargoDependenciesProperty) { // we test that separately as it has better error messages continue; From 7a63360ccf75c58da1db512d1c2119999348c5cc Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Sun, 15 Oct 2023 22:36:11 -0700 Subject: [PATCH 087/145] Address FIXME --- .../src/main/java/org/lflang/target/TargetConfig.java | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/core/src/main/java/org/lflang/target/TargetConfig.java b/core/src/main/java/org/lflang/target/TargetConfig.java index 93c8111c6b..9ba312b2e8 100644 --- a/core/src/main/java/org/lflang/target/TargetConfig.java +++ b/core/src/main/java/org/lflang/target/TargetConfig.java @@ -272,7 +272,7 @@ public void set(TargetProperty property, */ public static List extractProperties(TargetConfig config) { var res = new LinkedList(); - for (TargetProperty p : loaded(config)) { + for (TargetProperty p : config.loaded()) { KeyValuePair kv = LfFactory.eINSTANCE.createKeyValuePair(); var element = p.astElementFromConfig(config); if (element.isPresent()) { @@ -286,13 +286,10 @@ public static List extractProperties(TargetConfig config) { /** * Return all the target properties that have been set. - * - * @param config The configuration to find the properties in. */ - public static List> loaded( - TargetConfig config) { // FIXME: move to target config - return config.getRegisteredProperties().stream() - .filter(p -> config.isSet(p)) + public List> loaded() { + return getRegisteredProperties().stream() + .filter(this::isSet) .collect(Collectors.toList()); } From 99c4cd1617d23c9bb3f73fe7b6aa522bf99b6d47 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Sun, 15 Oct 2023 22:44:41 -0700 Subject: [PATCH 088/145] Apply formatter --- core/src/main/java/org/lflang/target/TargetConfig.java | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/core/src/main/java/org/lflang/target/TargetConfig.java b/core/src/main/java/org/lflang/target/TargetConfig.java index 9ba312b2e8..e5a95352de 100644 --- a/core/src/main/java/org/lflang/target/TargetConfig.java +++ b/core/src/main/java/org/lflang/target/TargetConfig.java @@ -284,13 +284,9 @@ public static List extractProperties(TargetConfig config) { return res; } - /** - * Return all the target properties that have been set. - */ + /** Return all the target properties that have been set. */ public List> loaded() { - return getRegisteredProperties().stream() - .filter(this::isSet) - .collect(Collectors.toList()); + return getRegisteredProperties().stream().filter(this::isSet).collect(Collectors.toList()); } /** From 5134a47081aa4bce344ad9d37c2a39fce50b31f2 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Mon, 16 Oct 2023 12:29:14 -0700 Subject: [PATCH 089/145] Fix merge artifacts --- .../lflang/generator/c/CCmakeGenerator.java | 35 ++++++++++--------- .../org/lflang/generator/c/CCompiler.java | 1 - .../target/property/type/SchedulerType.java | 4 +++ 3 files changed, 23 insertions(+), 17 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 5b0cec4964..7456327e33 100644 --- a/core/src/main/java/org/lflang/generator/c/CCmakeGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CCmakeGenerator.java @@ -38,6 +38,7 @@ import org.lflang.target.property.AuthProperty; import org.lflang.target.property.BuildTypeProperty; import org.lflang.target.property.CmakeIncludeProperty; +import org.lflang.target.property.CompileDefinitionsProperty; import org.lflang.target.property.CompilerFlagsProperty; import org.lflang.target.property.CompilerProperty; import org.lflang.target.property.PlatformProperty; @@ -264,22 +265,24 @@ CodeBuilder generateCMakeCode( } cMakeCode.newLine(); cMakeCode.pr("# Set default values for build parameters\n"); - targetConfig.compileDefinitions.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.indent(); - var v = "TRUE"; - if (value != null && !value.isEmpty()) { - v = value; - } - cMakeCode.pr("set(" + key + " " + v + ")\n"); - cMakeCode.unindent(); - cMakeCode.pr("endif()\n"); - }); + targetConfig + .get(new CompileDefinitionsProperty()) + .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.indent(); + var v = "TRUE"; + if (value != null && !value.isEmpty()) { + v = value; + } + cMakeCode.pr("set(" + key + " " + v + ")\n"); + cMakeCode.unindent(); + cMakeCode.pr("endif()\n"); + }); // Setup main target for different platforms switch (platformOptions.platform) { diff --git a/core/src/main/java/org/lflang/generator/c/CCompiler.java b/core/src/main/java/org/lflang/generator/c/CCompiler.java index db8434ed57..7317f06fdb 100644 --- a/core/src/main/java/org/lflang/generator/c/CCompiler.java +++ b/core/src/main/java/org/lflang/generator/c/CCompiler.java @@ -40,7 +40,6 @@ import org.lflang.generator.LFGeneratorContext; import org.lflang.target.TargetConfig; import org.lflang.target.property.BuildTypeProperty; -import org.lflang.target.property.CompileDefinitionsProperty; import org.lflang.target.property.CompilerFlagsProperty; import org.lflang.target.property.CompilerProperty; import org.lflang.target.property.PlatformProperty; diff --git a/core/src/main/java/org/lflang/target/property/type/SchedulerType.java b/core/src/main/java/org/lflang/target/property/type/SchedulerType.java index 4edc45d515..d6b9816ad3 100644 --- a/core/src/main/java/org/lflang/target/property/type/SchedulerType.java +++ b/core/src/main/java/org/lflang/target/property/type/SchedulerType.java @@ -58,5 +58,9 @@ public List getRelativePaths() { public static Scheduler getDefault() { return Scheduler.NP; } + + public String getSchedulerCompileDef() { + return "SCHED_" + this.name(); + } } } From b802c78a1094ecdbb6530f79343c7d47aa20e7d3 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Mon, 16 Oct 2023 14:27:36 -0700 Subject: [PATCH 090/145] Start registering target properties in code generator --- core/src/main/java/org/lflang/TargetProperty.java | 10 +++++++--- .../lflang/federated/extensions/CExtensionUtils.java | 2 +- .../federated/launcher/FedLauncherGenerator.java | 2 +- .../java/org/lflang/generator/c/CCmakeGenerator.java | 2 +- .../java/org/lflang/generator/c/CDockerGenerator.java | 4 ++-- .../main/java/org/lflang/generator/c/CGenerator.java | 10 ++++++++-- core/src/main/java/org/lflang/generator/c/CUtil.java | 4 ++-- .../src/main/java/org/lflang/target/TargetConfig.java | 2 -- .../java/org/lflang/target/property/AuthProperty.java | 11 ++++++++++- .../org/lflang/target/property/BooleanProperty.java | 2 +- .../lflang/target/property/BuildCommandsProperty.java | 9 +++++++-- 11 files changed, 40 insertions(+), 18 deletions(-) diff --git a/core/src/main/java/org/lflang/TargetProperty.java b/core/src/main/java/org/lflang/TargetProperty.java index 7c47afde72..a59b3fb9f2 100644 --- a/core/src/main/java/org/lflang/TargetProperty.java +++ b/core/src/main/java/org/lflang/TargetProperty.java @@ -136,6 +136,12 @@ public Optional astElementFromConfig(TargetConfig config) { /** Return the name of this target property (in kebab case). */ public abstract String name(); + /** + * Replace the value assigned to this target property in the given config with the given value. + * + * @param config The configuration to change. + * @param value The new value to assign. + */ public final void override(TargetConfig config, T value) { config.set(this, value); } @@ -174,9 +180,7 @@ public final void update(TargetConfig config, String value, MessageReporter repo } /** - * Return true if the given object is an instance of a class with the same name. FIXME: make this - * a singleton class and remove this override https://www.baeldung.com/kotlin/singleton-classes - * https://stackoverflow.com/questions/24214148/java-getinstance-vs-static + * Return true if the given object is an instance of a class with the same name. * * @param obj The object to compare this instance to. */ diff --git a/core/src/main/java/org/lflang/federated/extensions/CExtensionUtils.java b/core/src/main/java/org/lflang/federated/extensions/CExtensionUtils.java index f18e73ae8c..3b670a4295 100644 --- a/core/src/main/java/org/lflang/federated/extensions/CExtensionUtils.java +++ b/core/src/main/java/org/lflang/federated/extensions/CExtensionUtils.java @@ -189,7 +189,7 @@ public static void handleCompileDefinitions( "FEDERATED_%s", federate.targetConfig.get(new CoordinationProperty()).toString().toUpperCase()), ""); - if (federate.targetConfig.get(new AuthProperty())) { + if (federate.targetConfig.get(AuthProperty.INSTANCE)) { definitions.put("FEDERATED_AUTHENTICATED", ""); } definitions.put("NUMBER_OF_FEDERATES", String.valueOf(numOfFederates)); diff --git a/core/src/main/java/org/lflang/federated/launcher/FedLauncherGenerator.java b/core/src/main/java/org/lflang/federated/launcher/FedLauncherGenerator.java index 8a8efbf0aa..5b17cb5f52 100644 --- a/core/src/main/java/org/lflang/federated/launcher/FedLauncherGenerator.java +++ b/core/src/main/java/org/lflang/federated/launcher/FedLauncherGenerator.java @@ -338,7 +338,7 @@ private String getRtiCommand(List federates, boolean isRemote) } else { commands.add("RTI -i ${FEDERATION_ID} \\"); } - if (targetConfig.get(new AuthProperty())) { + if (targetConfig.get(AuthProperty.INSTANCE)) { commands.add(" -a \\"); } if (targetConfig.get(new TracingProperty()).isEnabled()) { 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 7456327e33..de79c06b37 100644 --- a/core/src/main/java/org/lflang/generator/c/CCmakeGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CCmakeGenerator.java @@ -339,7 +339,7 @@ CodeBuilder generateCMakeCode( break; } - if (targetConfig.get(new AuthProperty())) { + if (targetConfig.get(AuthProperty.INSTANCE)) { // If security is requested, add the auth option. var osName = System.getProperty("os.name").toLowerCase(); // if platform target was set, use given platform instead diff --git a/core/src/main/java/org/lflang/generator/c/CDockerGenerator.java b/core/src/main/java/org/lflang/generator/c/CDockerGenerator.java index b626cc24fd..8b3adf0dfa 100644 --- a/core/src/main/java/org/lflang/generator/c/CDockerGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CDockerGenerator.java @@ -31,9 +31,9 @@ protected String generateDockerFileContent() { var lfModuleName = context.getFileConfig().name; var config = context.getTargetConfig(); var compileCommand = - IterableExtensions.isNullOrEmpty(config.get(new BuildCommandsProperty())) + IterableExtensions.isNullOrEmpty(config.get(BuildCommandsProperty.INSTANCE)) ? generateDefaultCompileCommand() - : StringUtil.joinObjects(config.get(new BuildCommandsProperty()), " "); + : StringUtil.joinObjects(config.get(BuildCommandsProperty.INSTANCE), " "); var compiler = config.target == Target.CCPP ? "g++" : "gcc"; var baseImage = DEFAULT_BASE_IMAGE; var dockerConf = config.get(new DockerProperty()); 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 fd5be6fabe..8bfd3fa840 100644 --- a/core/src/main/java/org/lflang/generator/c/CGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CGenerator.java @@ -87,6 +87,7 @@ import org.lflang.lf.StateVar; import org.lflang.lf.Variable; import org.lflang.target.TargetConfig; +import org.lflang.target.property.AuthProperty; import org.lflang.target.property.BuildCommandsProperty; import org.lflang.target.property.CmakeIncludeProperty; import org.lflang.target.property.CompileDefinitionsProperty; @@ -404,6 +405,7 @@ protected boolean isOSCompatible() { @Override public void doGenerate(Resource resource, LFGeneratorContext context) { super.doGenerate(resource, context); + registerTargetProperties(); if (!GeneratorUtils.canGenerate(errorsOccurred(), mainDef, messageReporter, context)) return; if (!isOSCompatible()) return; // Incompatible OS and configuration @@ -514,7 +516,7 @@ public void doGenerate(Resource resource, LFGeneratorContext context) { // clean it up after, removing the #line directives after errors have been reported. if (!targetConfig.get(new NoCompileProperty()) && !targetConfig.get(new DockerProperty()).enabled - && IterableExtensions.isNullOrEmpty(targetConfig.get(new BuildCommandsProperty())) + && IterableExtensions.isNullOrEmpty(targetConfig.get(BuildCommandsProperty.INSTANCE)) // This code is unreachable in LSP_FAST mode, so that check is omitted. && context.getMode() != LFGeneratorContext.Mode.LSP_MEDIUM) { // FIXME: Currently, a lack of main is treated as a request to not produce @@ -557,7 +559,7 @@ public void doGenerate(Resource resource, LFGeneratorContext context) { // If a build directive has been given, invoke it now. // Note that the code does not get cleaned in this case. if (!targetConfig.get(new NoCompileProperty())) { - if (!IterableExtensions.isNullOrEmpty(targetConfig.get(new BuildCommandsProperty()))) { + if (!IterableExtensions.isNullOrEmpty(targetConfig.get(BuildCommandsProperty.INSTANCE))) { CUtil.runBuildCommand( fileConfig, targetConfig, @@ -578,6 +580,10 @@ public void doGenerate(Resource resource, LFGeneratorContext context) { GeneratorUtils.refreshProject(resource, context.getMode()); } + private void registerTargetProperties() { + context.getTargetConfig().register(AuthProperty.INSTANCE, BuildCommandsProperty.INSTANCE); + } + private void generateCodeFor(String lfModuleName) throws IOException { code.pr(generateDirectives()); code.pr(new CMainFunctionGenerator(targetConfig).generateCode()); diff --git a/core/src/main/java/org/lflang/generator/c/CUtil.java b/core/src/main/java/org/lflang/generator/c/CUtil.java index 8ed5f41671..37d088c044 100644 --- a/core/src/main/java/org/lflang/generator/c/CUtil.java +++ b/core/src/main/java/org/lflang/generator/c/CUtil.java @@ -616,7 +616,7 @@ public static void runBuildCommand( LFGeneratorContext.Mode mode) { List commands = getCommands( - targetConfig.get(new BuildCommandsProperty()), commandFactory, fileConfig.srcPath); + targetConfig.get(BuildCommandsProperty.INSTANCE), commandFactory, fileConfig.srcPath); // If the build command could not be found, abort. // An error has already been reported in createCommand. if (commands.stream().anyMatch(Objects::isNull)) return; @@ -633,7 +633,7 @@ public static void runBuildCommand( // FIXME: Why is the content of stderr not provided to the user in this error // message? "Build command \"%s\" failed with error code %d.", - targetConfig.get(new BuildCommandsProperty()), returnCode)); + targetConfig.get(BuildCommandsProperty.INSTANCE), returnCode)); return; } // For warnings (vs. errors), the return code is 0. diff --git a/core/src/main/java/org/lflang/target/TargetConfig.java b/core/src/main/java/org/lflang/target/TargetConfig.java index e5a95352de..23f7df9591 100644 --- a/core/src/main/java/org/lflang/target/TargetConfig.java +++ b/core/src/main/java/org/lflang/target/TargetConfig.java @@ -108,8 +108,6 @@ public TargetConfig(Target target) { this.target = target; this.register( - new AuthProperty(), - new BuildCommandsProperty(), new BuildTypeProperty(), new ClockSyncModeProperty(), new ClockSyncOptionsProperty(), diff --git a/core/src/main/java/org/lflang/target/property/AuthProperty.java b/core/src/main/java/org/lflang/target/property/AuthProperty.java index 26088b1d97..662049ebc5 100644 --- a/core/src/main/java/org/lflang/target/property/AuthProperty.java +++ b/core/src/main/java/org/lflang/target/property/AuthProperty.java @@ -5,7 +5,16 @@ import org.lflang.Target; /** Directive to allow including OpenSSL libraries and process HMAC authentication. */ -public class AuthProperty extends BooleanProperty { +public final class AuthProperty extends BooleanProperty { + + /** + * Singleton target property instance. + */ + public static final AuthProperty INSTANCE = new AuthProperty(); + + private AuthProperty() { + super(); + } @Override public List supportedTargets() { diff --git a/core/src/main/java/org/lflang/target/property/BooleanProperty.java b/core/src/main/java/org/lflang/target/property/BooleanProperty.java index b8ab9f7cb9..adf1314480 100644 --- a/core/src/main/java/org/lflang/target/property/BooleanProperty.java +++ b/core/src/main/java/org/lflang/target/property/BooleanProperty.java @@ -8,7 +8,7 @@ public abstract class BooleanProperty extends TargetProperty { - public BooleanProperty() { + protected BooleanProperty() { super(PrimitiveType.BOOLEAN); } diff --git a/core/src/main/java/org/lflang/target/property/BuildCommandsProperty.java b/core/src/main/java/org/lflang/target/property/BuildCommandsProperty.java index 8049f02668..728b446e55 100644 --- a/core/src/main/java/org/lflang/target/property/BuildCommandsProperty.java +++ b/core/src/main/java/org/lflang/target/property/BuildCommandsProperty.java @@ -15,9 +15,14 @@ * designated compiler. A common usage of this target property is to set the command to build on the * basis of a Makefile. */ -public class BuildCommandsProperty extends TargetProperty, UnionType> { +public final class BuildCommandsProperty extends TargetProperty, UnionType> { - public BuildCommandsProperty() { + /** + * Singleton target property instance. + */ + public static final BuildCommandsProperty INSTANCE = new BuildCommandsProperty(); + + private BuildCommandsProperty() { super(UnionType.STRING_OR_STRING_ARRAY); } From 3e061d3d6309387ac66d32e9b78bc01548e3151e Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Mon, 16 Oct 2023 14:28:48 -0700 Subject: [PATCH 091/145] Apply formatter --- core/src/main/java/org/lflang/target/TargetConfig.java | 2 -- .../main/java/org/lflang/target/property/AuthProperty.java | 4 +--- .../org/lflang/target/property/BuildCommandsProperty.java | 4 +--- 3 files changed, 2 insertions(+), 8 deletions(-) diff --git a/core/src/main/java/org/lflang/target/TargetConfig.java b/core/src/main/java/org/lflang/target/TargetConfig.java index 23f7df9591..1581e8191b 100644 --- a/core/src/main/java/org/lflang/target/TargetConfig.java +++ b/core/src/main/java/org/lflang/target/TargetConfig.java @@ -45,8 +45,6 @@ import org.lflang.lf.LfPackage.Literals; import org.lflang.lf.Model; import org.lflang.lf.TargetDecl; -import org.lflang.target.property.AuthProperty; -import org.lflang.target.property.BuildCommandsProperty; import org.lflang.target.property.BuildTypeProperty; import org.lflang.target.property.CargoDependenciesProperty; import org.lflang.target.property.CargoFeaturesProperty; diff --git a/core/src/main/java/org/lflang/target/property/AuthProperty.java b/core/src/main/java/org/lflang/target/property/AuthProperty.java index 662049ebc5..fd760153b5 100644 --- a/core/src/main/java/org/lflang/target/property/AuthProperty.java +++ b/core/src/main/java/org/lflang/target/property/AuthProperty.java @@ -7,9 +7,7 @@ /** Directive to allow including OpenSSL libraries and process HMAC authentication. */ public final class AuthProperty extends BooleanProperty { - /** - * Singleton target property instance. - */ + /** Singleton target property instance. */ public static final AuthProperty INSTANCE = new AuthProperty(); private AuthProperty() { diff --git a/core/src/main/java/org/lflang/target/property/BuildCommandsProperty.java b/core/src/main/java/org/lflang/target/property/BuildCommandsProperty.java index 728b446e55..e5a31daf65 100644 --- a/core/src/main/java/org/lflang/target/property/BuildCommandsProperty.java +++ b/core/src/main/java/org/lflang/target/property/BuildCommandsProperty.java @@ -17,9 +17,7 @@ */ public final class BuildCommandsProperty extends TargetProperty, UnionType> { - /** - * Singleton target property instance. - */ + /** Singleton target property instance. */ public static final BuildCommandsProperty INSTANCE = new BuildCommandsProperty(); private BuildCommandsProperty() { From ea73eba55b7d4f17c7f94414fda991aa965af395 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Mon, 16 Oct 2023 16:54:58 -0700 Subject: [PATCH 092/145] Adjustments to ensure proper initialization of the target config --- core/src/main/java/org/lflang/Target.java | 38 ++++++++++++++++ .../main/java/org/lflang/TargetProperty.java | 2 +- .../main/java/org/lflang/ast/ASTUtils.java | 10 ++--- .../federated/extensions/CExtension.java | 8 +++- .../federated/extensions/CExtensionUtils.java | 27 ++++++------ .../federated/generator/FedFileConfig.java | 2 +- .../federated/generator/FedGenerator.java | 6 ++- .../federated/generator/FedTargetConfig.java | 14 ++++-- .../launcher/FedLauncherGenerator.java | 12 +++--- .../org/lflang/generator/MainContext.java | 2 +- .../lflang/generator/c/CCmakeGenerator.java | 10 ++--- .../org/lflang/generator/c/CCompiler.java | 8 ++-- .../org/lflang/generator/c/CGenerator.java | 27 +++++------- .../generator/c/CPreambleGenerator.java | 2 +- .../generator/python/PythonGenerator.java | 2 +- .../generator/rust/RustTargetConfig.java | 43 ------------------- .../java/org/lflang/target/TargetConfig.java | 42 ++++++++---------- .../target/property/BuildTypeProperty.java | 5 ++- .../property/CargoDependenciesProperty.java | 7 ++- .../property/CargoFeaturesProperty.java | 7 +++ .../property/ClockSyncModeProperty.java | 5 ++- .../property/ClockSyncOptionsProperty.java | 5 ++- .../target/property/CmakeIncludeProperty.java | 7 +++ .../property/CompileDefinitionsProperty.java | 5 ++- .../property/CompilerFlagsProperty.java | 7 +++ .../org/lflang/generator/cpp/CppGenerator.kt | 5 +-- .../generator/cpp/CppPlatformGenerator.kt | 2 +- .../generator/cpp/CppRos2PackageGenerator.kt | 4 +- .../cpp/CppStandaloneCmakeGenerator.kt | 4 +- .../generator/cpp/CppStandaloneGenerator.kt | 4 +- .../lflang/generator/rust/RustGenerator.kt | 23 +++------- .../org/lflang/generator/rust/RustModel.kt | 4 +- .../compiler/LinguaFrancaValidationTest.java | 6 +-- 33 files changed, 184 insertions(+), 171 deletions(-) delete mode 100644 core/src/main/java/org/lflang/generator/rust/RustTargetConfig.java diff --git a/core/src/main/java/org/lflang/Target.java b/core/src/main/java/org/lflang/Target.java index dc1a78d65f..0d73df15a1 100644 --- a/core/src/main/java/org/lflang/Target.java +++ b/core/src/main/java/org/lflang/Target.java @@ -26,6 +26,18 @@ import java.util.Set; import net.jcip.annotations.Immutable; import org.lflang.lf.TargetDecl; +import org.lflang.target.TargetConfig; +import org.lflang.target.property.AuthProperty; +import org.lflang.target.property.BuildCommandsProperty; +import org.lflang.target.property.BuildTypeProperty; +import org.lflang.target.property.CargoDependenciesProperty; +import org.lflang.target.property.CargoFeaturesProperty; +import org.lflang.target.property.ClockSyncModeProperty; +import org.lflang.target.property.ClockSyncOptionsProperty; +import org.lflang.target.property.CmakeIncludeProperty; +import org.lflang.target.property.CompileDefinitionsProperty; +import org.lflang.target.property.CompilerFlagsProperty; +import org.lflang.target.property.RustIncludeProperty; /** * Enumeration of targets and their associated properties. @@ -546,4 +558,30 @@ public static Target fromDecl(TargetDecl targetDecl) { return Target.forName(name) .orElseThrow(() -> new RuntimeException("Invalid target name '" + name + "'")); } + + public void initialize(TargetConfig config) { + switch (this) { + case C, CCPP -> config.register( + AuthProperty.INSTANCE, + BuildCommandsProperty.INSTANCE, + BuildTypeProperty.INSTANCE, + ClockSyncModeProperty.INSTANCE, + ClockSyncOptionsProperty.INSTANCE, + CmakeIncludeProperty.INSTANCE, + CompileDefinitionsProperty.INSTANCE, + CompilerFlagsProperty.INSTANCE); + case CPP -> config.register(BuildTypeProperty.INSTANCE, CmakeIncludeProperty.INSTANCE); + case Python -> config.register( + ClockSyncModeProperty.INSTANCE, + ClockSyncOptionsProperty.INSTANCE, + CompileDefinitionsProperty.INSTANCE); + case Rust -> config.register( + BuildTypeProperty.INSTANCE, + CargoDependenciesProperty.INSTANCE, + CargoFeaturesProperty.INSTANCE, + CmakeIncludeProperty.INSTANCE, + CompileDefinitionsProperty.INSTANCE, + new RustIncludeProperty()); + } + } } diff --git a/core/src/main/java/org/lflang/TargetProperty.java b/core/src/main/java/org/lflang/TargetProperty.java index a59b3fb9f2..4de4ecc5cb 100644 --- a/core/src/main/java/org/lflang/TargetProperty.java +++ b/core/src/main/java/org/lflang/TargetProperty.java @@ -25,7 +25,7 @@ public abstract class TargetProperty { * * @param type The type of the value that can be assigned to the property. */ - public TargetProperty(S type) { + protected TargetProperty(S type) { this.type = type; } diff --git a/core/src/main/java/org/lflang/ast/ASTUtils.java b/core/src/main/java/org/lflang/ast/ASTUtils.java index 472ce87d88..ed2141dbe2 100644 --- a/core/src/main/java/org/lflang/ast/ASTUtils.java +++ b/core/src/main/java/org/lflang/ast/ASTUtils.java @@ -615,12 +615,10 @@ public static ReactorInstance createMainReactorInstance( if (breadth == 0) { messageReporter.nowhere().warning("The program has no reactions"); } else { - new CompileDefinitionsProperty() - .update( - targetConfig, - Map.of( - "LF_REACTION_GRAPH_BREADTH", - String.valueOf(reactionInstanceGraph.getBreadth()))); + CompileDefinitionsProperty.INSTANCE.update( + targetConfig, + Map.of( + "LF_REACTION_GRAPH_BREADTH", String.valueOf(reactionInstanceGraph.getBreadth()))); } return main; } 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 ba5f67f76c..21b44588ce 100644 --- a/core/src/main/java/org/lflang/federated/extensions/CExtension.java +++ b/core/src/main/java/org/lflang/federated/extensions/CExtension.java @@ -742,12 +742,16 @@ private String generateCodeToInitializeFederate(FederateInstance federate, RtiCo } // If a test clock offset has been specified, insert code to set it here. - if (federate.targetConfig.get(new ClockSyncOptionsProperty()).testOffset != null) { + if (federate.targetConfig.get(ClockSyncOptionsProperty.INSTANCE).testOffset != null) { code.pr( "lf_set_physical_clock_offset((1 + " + federate.id + ") * " - + federate.targetConfig.get(new ClockSyncOptionsProperty()).testOffset.toNanoSeconds() + + federate + .targetConfig + .get(ClockSyncOptionsProperty.INSTANCE) + .testOffset + .toNanoSeconds() + "LL);"); } diff --git a/core/src/main/java/org/lflang/federated/extensions/CExtensionUtils.java b/core/src/main/java/org/lflang/federated/extensions/CExtensionUtils.java index 3b670a4295..59f2d59a65 100644 --- a/core/src/main/java/org/lflang/federated/extensions/CExtensionUtils.java +++ b/core/src/main/java/org/lflang/federated/extensions/CExtensionUtils.java @@ -195,7 +195,7 @@ public static void handleCompileDefinitions( definitions.put("NUMBER_OF_FEDERATES", String.valueOf(numOfFederates)); definitions.put("EXECUTABLE_PREAMBLE", ""); - new CompileDefinitionsProperty().update(federate.targetConfig, definitions); + CompileDefinitionsProperty.INSTANCE.update(federate.targetConfig, definitions); handleAdvanceMessageInterval(federate); @@ -208,15 +208,15 @@ private static void handleAdvanceMessageInterval(FederateInstance federate) { if (advanceMessageInterval != null) { federate .targetConfig - .get(new CompileDefinitionsProperty()) + .get(CompileDefinitionsProperty.INSTANCE) .put("ADVANCE_MESSAGE_INTERVAL", String.valueOf(advanceMessageInterval.toNanoSeconds())); } } static boolean clockSyncIsOn(FederateInstance federate, RtiConfig rtiConfig) { - return federate.targetConfig.get(new ClockSyncModeProperty()) != ClockSyncMode.OFF + return federate.targetConfig.get(ClockSyncModeProperty.INSTANCE) != ClockSyncMode.OFF && (!rtiConfig.getHost().equals(federate.host) - || federate.targetConfig.get(new ClockSyncOptionsProperty()).localFederatesOn); + || federate.targetConfig.get(ClockSyncOptionsProperty.INSTANCE).localFederatesOn); } /** @@ -234,13 +234,13 @@ public static void initializeClockSynchronization( messageReporter .nowhere() .info("Initial clock synchronization is enabled for federate " + federate.id); - if (federate.targetConfig.get(new ClockSyncModeProperty()) == ClockSyncMode.ON) { - if (federate.targetConfig.get(new ClockSyncOptionsProperty()).collectStats) { + if (federate.targetConfig.get(ClockSyncModeProperty.INSTANCE) == ClockSyncMode.ON) { + if (federate.targetConfig.get(ClockSyncOptionsProperty.INSTANCE).collectStats) { messageReporter .nowhere() .info("Will collect clock sync statistics for federate " + federate.id); // Add libm to the compiler flags - new CompilerFlagsProperty().update(federate.targetConfig, List.of("-lm")); + CompilerFlagsProperty.INSTANCE.update(federate.targetConfig, List.of("-lm")); } messageReporter .nowhere() @@ -261,8 +261,8 @@ public static void initializeClockSynchronization( */ public static void addClockSyncCompileDefinitions(FederateInstance federate) { - ClockSyncMode mode = federate.targetConfig.get(new ClockSyncModeProperty()); - ClockSyncOptions options = federate.targetConfig.get(new ClockSyncOptionsProperty()); + ClockSyncMode mode = federate.targetConfig.get(ClockSyncModeProperty.INSTANCE); + ClockSyncOptions options = federate.targetConfig.get(ClockSyncOptionsProperty.INSTANCE); final var defs = new HashMap(); defs.put("_LF_CLOCK_SYNC_INITIAL", ""); @@ -276,7 +276,7 @@ public static void addClockSyncCompileDefinitions(FederateInstance federate) { defs.put("_LF_CLOCK_SYNC_COLLECT_STATS", ""); } } - new CompileDefinitionsProperty().update(federate.targetConfig, defs); + CompileDefinitionsProperty.INSTANCE.update(federate.targetConfig, defs); } /** Generate a file to be included by CMake. */ @@ -301,10 +301,9 @@ public static void generateCMakeInclude(FederateInstance federate, FedFileConfig srcWriter.write(cmakeIncludeCode.getCode()); } - new CmakeIncludeProperty() - .update( - federate.targetConfig, - List.of(fileConfig.getSrcPath().relativize(cmakeIncludePath).toString())); + CmakeIncludeProperty.INSTANCE.update( + federate.targetConfig, + List.of(fileConfig.getSrcPath().relativize(cmakeIncludePath).toString())); } /** diff --git a/core/src/main/java/org/lflang/federated/generator/FedFileConfig.java b/core/src/main/java/org/lflang/federated/generator/FedFileConfig.java index 9e5e103c8f..a8e5c3a4ff 100644 --- a/core/src/main/java/org/lflang/federated/generator/FedFileConfig.java +++ b/core/src/main/java/org/lflang/federated/generator/FedFileConfig.java @@ -103,7 +103,7 @@ public void doClean() throws IOException { * the generated .lf file for the federate. */ public void relativizePaths(FedTargetConfig targetConfig) { - List.of(new ProtobufsProperty(), new FilesProperty(), new CmakeIncludeProperty()) + List.of(new ProtobufsProperty(), new FilesProperty(), CmakeIncludeProperty.INSTANCE) .forEach( p -> { p.override(targetConfig, relativizePathList(targetConfig.get(p))); 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 aa645a932f..cb89639f57 100644 --- a/core/src/main/java/org/lflang/federated/generator/FedGenerator.java +++ b/core/src/main/java/org/lflang/federated/generator/FedGenerator.java @@ -299,8 +299,8 @@ private Map compileFederates( TargetConfig subConfig = new TargetConfig( - new Properties(), GeneratorUtils.findTargetDecl(subFileConfig.resource), + new Properties(), subContextMessageReporter); if (targetConfig.get(new DockerProperty()).enabled && targetConfig.target.buildsUsingDocker()) { @@ -473,7 +473,9 @@ private List getFederateInstances( // Assign an integer ID to the federate. int federateID = federates.size(); var resource = instantiation.getReactorClass().eResource(); - var federateTargetConfig = new FedTargetConfig(context, resource); + var federateTargetConfig = + new FedTargetConfig( + context, resource); // FIXME: Based on the target, need to load properties. FederateInstance federateInstance = new FederateInstance( instantiation, federateID, i, bankWidth, federateTargetConfig, messageReporter); diff --git a/core/src/main/java/org/lflang/federated/generator/FedTargetConfig.java b/core/src/main/java/org/lflang/federated/generator/FedTargetConfig.java index fc4df6e121..1a9d8188d9 100644 --- a/core/src/main/java/org/lflang/federated/generator/FedTargetConfig.java +++ b/core/src/main/java/org/lflang/federated/generator/FedTargetConfig.java @@ -7,6 +7,7 @@ import java.util.Objects; import org.eclipse.emf.ecore.resource.Resource; import org.lflang.MessageReporter; +import org.lflang.Target; import org.lflang.ast.ASTUtils; import org.lflang.generator.GeneratorUtils; import org.lflang.generator.LFGeneratorContext; @@ -15,6 +16,7 @@ import org.lflang.target.TargetConfig; import org.lflang.target.property.ClockSyncModeProperty; import org.lflang.target.property.ClockSyncOptionsProperty; +import org.lflang.target.property.FedSetupProperty; import org.lflang.util.FileUtil; /** @@ -33,12 +35,16 @@ public class FedTargetConfig extends TargetConfig { * @param federateResource The resource in which to find the reactor class of the federate. */ public FedTargetConfig(LFGeneratorContext context, Resource federateResource) { - // Create target config based on the main .lf file + // 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(), - GeneratorUtils.findTargetDecl(context.getFileConfig().resource), context.getErrorReporter()); + this.register(new FedSetupProperty()); + mergeImportedConfig( federateResource, context.getFileConfig().resource, context.getErrorReporter()); @@ -81,8 +87,8 @@ private Path getRelativePath(Resource source, Resource target) { /** Method for the removal of things that should not appear in the target config of a federate. */ private void clearPropertiesToIgnore() { - this.reset(new ClockSyncModeProperty()); - this.reset(new ClockSyncOptionsProperty()); + this.reset(ClockSyncModeProperty.INSTANCE); + this.reset(ClockSyncOptionsProperty.INSTANCE); } /** diff --git a/core/src/main/java/org/lflang/federated/launcher/FedLauncherGenerator.java b/core/src/main/java/org/lflang/federated/launcher/FedLauncherGenerator.java index 5b17cb5f52..f289918b7d 100644 --- a/core/src/main/java/org/lflang/federated/launcher/FedLauncherGenerator.java +++ b/core/src/main/java/org/lflang/federated/launcher/FedLauncherGenerator.java @@ -348,19 +348,19 @@ private String getRtiCommand(List federates, boolean isRemote) List.of( " -n " + federates.size() + " \\", " -c " - + targetConfig.get(new ClockSyncModeProperty()).toString() + + targetConfig.get(ClockSyncModeProperty.INSTANCE).toString() + " \\")); - if (targetConfig.get(new ClockSyncModeProperty()).equals(ClockSyncMode.ON)) { + if (targetConfig.get(ClockSyncModeProperty.INSTANCE).equals(ClockSyncMode.ON)) { commands.add( "period " - + targetConfig.get(new ClockSyncOptionsProperty()).period.toNanoSeconds() + + targetConfig.get(ClockSyncOptionsProperty.INSTANCE).period.toNanoSeconds() + " \\"); } - if (targetConfig.get(new ClockSyncModeProperty()).equals(ClockSyncMode.ON) - || targetConfig.get(new ClockSyncModeProperty()).equals(ClockSyncMode.INIT)) { + if (targetConfig.get(ClockSyncModeProperty.INSTANCE).equals(ClockSyncMode.ON) + || targetConfig.get(ClockSyncModeProperty.INSTANCE).equals(ClockSyncMode.INIT)) { commands.add( "exchanges-per-interval " - + targetConfig.get(new ClockSyncOptionsProperty()).trials + + targetConfig.get(ClockSyncOptionsProperty.INSTANCE).trials + " \\"); } commands.add("&"); diff --git a/core/src/main/java/org/lflang/generator/MainContext.java b/core/src/main/java/org/lflang/generator/MainContext.java index ebd4d2552e..cf4add1d37 100644 --- a/core/src/main/java/org/lflang/generator/MainContext.java +++ b/core/src/main/java/org/lflang/generator/MainContext.java @@ -165,6 +165,6 @@ public void reportProgress(String message, int percentage) { */ public void loadTargetConfig() { this.targetConfig = - new TargetConfig(args, GeneratorUtils.findTargetDecl(fileConfig.resource), messageReporter); + new TargetConfig(GeneratorUtils.findTargetDecl(fileConfig.resource), args, messageReporter); } } 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 de79c06b37..3c35d078bc 100644 --- a/core/src/main/java/org/lflang/generator/c/CCmakeGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CCmakeGenerator.java @@ -229,7 +229,7 @@ CodeBuilder generateCMakeCode( cMakeCode.pr("set(CMAKE_CXX_STANDARD 17)"); cMakeCode.pr("set(CMAKE_CXX_STANDARD_REQUIRED ON)"); cMakeCode.newLine(); - if (!targetConfig.get(new CmakeIncludeProperty()).isEmpty()) { + if (!targetConfig.get(CmakeIncludeProperty.INSTANCE).isEmpty()) { // The user might be using the non-keyword form of // target_link_libraries. Ideally we would detect whether they are // doing that, but it is easier to just always have a deprecation @@ -242,7 +242,7 @@ CodeBuilder generateCMakeCode( } // Set the build type - cMakeCode.pr("set(DEFAULT_BUILD_TYPE " + targetConfig.get(new BuildTypeProperty()) + ")\n"); + cMakeCode.pr("set(DEFAULT_BUILD_TYPE " + targetConfig.get(BuildTypeProperty.INSTANCE) + ")\n"); cMakeCode.pr("if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)\n"); cMakeCode.pr( " set(CMAKE_BUILD_TYPE ${DEFAULT_BUILD_TYPE} CACHE STRING \"Choose the type of build.\"" @@ -266,7 +266,7 @@ CodeBuilder generateCMakeCode( cMakeCode.newLine(); cMakeCode.pr("# Set default values for build parameters\n"); targetConfig - .get(new CompileDefinitionsProperty()) + .get(CompileDefinitionsProperty.INSTANCE) .forEach( (key, value) -> { if (key.equals("LF_THREADED") || key.equals("LF_UNTHREADED")) { @@ -412,7 +412,7 @@ CodeBuilder generateCMakeCode( // Set the compiler flags // We can detect a few common libraries and use the proper target_link_libraries to find them - for (String compilerFlag : targetConfig.get(new CompilerFlagsProperty())) { + for (String compilerFlag : targetConfig.get(CompilerFlagsProperty.INSTANCE)) { messageReporter .nowhere() .warning( @@ -428,7 +428,7 @@ CodeBuilder generateCMakeCode( cMakeCode.newLine(); // Add the include file - for (String includeFile : targetConfig.get(new CmakeIncludeProperty())) { + for (String includeFile : targetConfig.get(CmakeIncludeProperty.INSTANCE)) { cMakeCode.pr("include(\"" + Path.of(includeFile).getFileName() + "\")"); } cMakeCode.newLine(); diff --git a/core/src/main/java/org/lflang/generator/c/CCompiler.java b/core/src/main/java/org/lflang/generator/c/CCompiler.java index 7317f06fdb..d0f175dafc 100644 --- a/core/src/main/java/org/lflang/generator/c/CCompiler.java +++ b/core/src/main/java/org/lflang/generator/c/CCompiler.java @@ -240,8 +240,8 @@ private static List cmakeOptions(TargetConfig targetConfig, FileConfig f arguments.addAll( List.of( "-DCMAKE_BUILD_TYPE=" - + (targetConfig.isSet(new BuildTypeProperty()) - ? targetConfig.get(new BuildTypeProperty()).toString() + + (targetConfig.isSet(BuildTypeProperty.INSTANCE) + ? targetConfig.get(BuildTypeProperty.INSTANCE).toString() : "Release"), "-DCMAKE_INSTALL_PREFIX=" + FileUtil.toUnixString(fileConfig.getOutPath()), "-DCMAKE_INSTALL_BINDIR=" @@ -298,7 +298,7 @@ public LFCommand buildCmakeCommand() { "--parallel", cores, "--config", - buildTypeToCmakeConfig(targetConfig.get(new BuildTypeProperty()))), + buildTypeToCmakeConfig(targetConfig.get(BuildTypeProperty.INSTANCE))), buildPath); if (command == null) { messageReporter @@ -407,7 +407,7 @@ public LFCommand compileCCommand(String fileToCompile, boolean noBinary) { } // Finally, add the compiler flags in target parameters (if any) - compileArgs.addAll(targetConfig.get(new CompilerFlagsProperty())); + compileArgs.addAll(targetConfig.get(CompilerFlagsProperty.INSTANCE)); // Only set the output file name if it hasn't already been set // using a target property or Args line flag. 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 8bfd3fa840..077fecdb9e 100644 --- a/core/src/main/java/org/lflang/generator/c/CGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CGenerator.java @@ -87,7 +87,6 @@ import org.lflang.lf.StateVar; import org.lflang.lf.Variable; import org.lflang.target.TargetConfig; -import org.lflang.target.property.AuthProperty; import org.lflang.target.property.BuildCommandsProperty; import org.lflang.target.property.CmakeIncludeProperty; import org.lflang.target.property.CompileDefinitionsProperty; @@ -405,7 +404,7 @@ protected boolean isOSCompatible() { @Override public void doGenerate(Resource resource, LFGeneratorContext context) { super.doGenerate(resource, context); - registerTargetProperties(); + if (!GeneratorUtils.canGenerate(errorsOccurred(), mainDef, messageReporter, context)) return; if (!isOSCompatible()) return; // Incompatible OS and configuration @@ -580,10 +579,6 @@ public void doGenerate(Resource resource, LFGeneratorContext context) { GeneratorUtils.refreshProject(resource, context.getMode()); } - private void registerTargetProperties() { - context.getTargetConfig().register(AuthProperty.INSTANCE, BuildCommandsProperty.INSTANCE); - } - private void generateCodeFor(String lfModuleName) throws IOException { code.pr(generateDirectives()); code.pr(new CMainFunctionGenerator(targetConfig).generateCode()); @@ -724,9 +719,8 @@ private void inspectReactorEResource(ReactorDecl reactor) { // Copy the user files and cmake-includes to the src-gen path of the main .lf file copyUserFiles(lfResource.getTargetConfig(), lfResource.getFileConfig()); // Merge the CMake includes from the imported file into the target config - new CmakeIncludeProperty() - .update( - this.targetConfig, lfResource.getTargetConfig().get(new CmakeIncludeProperty())); + CmakeIncludeProperty.INSTANCE.update( + this.targetConfig, lfResource.getTargetConfig().get(CmakeIncludeProperty.INSTANCE)); } } } @@ -745,7 +739,7 @@ protected void copyUserFiles(TargetConfig targetConfig, FileConfig fileConfig) { var destination = this.fileConfig.getSrcGenPath(); FileUtil.copyFilesOrDirectories( - targetConfig.get(new CmakeIncludeProperty()), + targetConfig.get(CmakeIncludeProperty.INSTANCE), destination, fileConfig, messageReporter, @@ -1936,10 +1930,9 @@ protected DockerGenerator getDockerGenerator(LFGeneratorContext context) { // Perform set up that does not generate code protected void setUpGeneralParameters() { accommodatePhysicalActionsIfPresent(); - new CompileDefinitionsProperty() - .update( - targetConfig, - Map.of("LOG_LEVEL", String.valueOf(targetConfig.get(new LoggingProperty()).ordinal()))); + CompileDefinitionsProperty.INSTANCE.update( + targetConfig, + Map.of("LOG_LEVEL", String.valueOf(targetConfig.get(new LoggingProperty()).ordinal()))); targetConfig.compileAdditionalSources.addAll(CCoreFilesUtils.getCTargetSrc()); // Create the main reactor instance if there is a main reactor. @@ -1947,7 +1940,7 @@ protected void setUpGeneralParameters() { ASTUtils.createMainReactorInstance(mainDef, reactors, messageReporter, targetConfig); if (hasModalReactors) { // So that each separate compile knows about modal reactors, do this: - new CompileDefinitionsProperty().update(targetConfig, Map.of("MODAL_REACTORS", "TRUE")); + CompileDefinitionsProperty.INSTANCE.update(targetConfig, Map.of("MODAL_REACTORS", "TRUE")); } final var platformOptions = targetConfig.get(new PlatformProperty()); if (targetConfig.get(new ThreadingProperty()) @@ -1979,7 +1972,7 @@ protected void setUpGeneralParameters() { && targetConfig.get(new ThreadingProperty()) && platformOptions.userThreads >= 0) { targetConfig - .get(new CompileDefinitionsProperty()) + .get(CompileDefinitionsProperty.INSTANCE) .put(PlatformOption.USER_THREADS.name(), String.valueOf(platformOptions.userThreads)); } else if (platformOptions.userThreads > 0) { messageReporter @@ -1995,7 +1988,7 @@ protected void setUpGeneralParameters() { var map = new HashMap(); map.put("SCHEDULER", targetConfig.get(new SchedulerProperty()).getSchedulerCompileDef()); map.put("NUMBER_OF_WORKERS", String.valueOf(targetConfig.get(new WorkersProperty()))); - new CompileDefinitionsProperty().update(targetConfig, map); + CompileDefinitionsProperty.INSTANCE.update(targetConfig, map); } pickCompilePlatform(); } 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 d4b084d6bb..187c90e651 100644 --- a/core/src/main/java/org/lflang/generator/c/CPreambleGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CPreambleGenerator.java @@ -94,7 +94,7 @@ public static String generateDefineDirectives(TargetConfig targetConfig, Path sr } else { definitions.put("LF_UNTHREADED", "1"); } - new CompileDefinitionsProperty().update(targetConfig, definitions); + CompileDefinitionsProperty.INSTANCE.update(targetConfig, definitions); code.newLine(); return code.toString(); } diff --git a/core/src/main/java/org/lflang/generator/python/PythonGenerator.java b/core/src/main/java/org/lflang/generator/python/PythonGenerator.java index c9b82b9e5b..4321b4c4e2 100644 --- a/core/src/main/java/org/lflang/generator/python/PythonGenerator.java +++ b/core/src/main/java/org/lflang/generator/python/PythonGenerator.java @@ -110,7 +110,7 @@ private PythonGenerator( LFGeneratorContext context, PythonTypes types, CCmakeGenerator cmakeGenerator) { super(context, false, types, cmakeGenerator, new PythonDelayBodyGenerator(types)); new CompilerProperty().override(this.targetConfig, "gcc"); // FIXME: why? - this.targetConfig.reset(new CompilerFlagsProperty()); + this.targetConfig.reset(CompilerFlagsProperty.INSTANCE); this.types = types; } diff --git a/core/src/main/java/org/lflang/generator/rust/RustTargetConfig.java b/core/src/main/java/org/lflang/generator/rust/RustTargetConfig.java deleted file mode 100644 index 7a13216046..0000000000 --- a/core/src/main/java/org/lflang/generator/rust/RustTargetConfig.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (c) 2021, TU Dresden. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF - * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package org.lflang.generator.rust; - -import org.lflang.target.TargetConfig; -import org.lflang.target.property.CargoDependenciesProperty; -import org.lflang.target.property.CargoFeaturesProperty; -import org.lflang.target.property.RustIncludeProperty; - -/** - * Rust-specific part of a {@link TargetConfig}. - * - * @author Clément Fournier - TU Dresden, INSA Rennes - */ -public final class RustTargetConfig { - - public RustTargetConfig(TargetConfig parent) { - parent.register( - new CargoFeaturesProperty(), new CargoDependenciesProperty(), new RustIncludeProperty()); - } -} diff --git a/core/src/main/java/org/lflang/target/TargetConfig.java b/core/src/main/java/org/lflang/target/TargetConfig.java index 1581e8191b..5ad61e20e2 100644 --- a/core/src/main/java/org/lflang/target/TargetConfig.java +++ b/core/src/main/java/org/lflang/target/TargetConfig.java @@ -45,14 +45,6 @@ import org.lflang.lf.LfPackage.Literals; import org.lflang.lf.Model; import org.lflang.lf.TargetDecl; -import org.lflang.target.property.BuildTypeProperty; -import org.lflang.target.property.CargoDependenciesProperty; -import org.lflang.target.property.CargoFeaturesProperty; -import org.lflang.target.property.ClockSyncModeProperty; -import org.lflang.target.property.ClockSyncOptionsProperty; -import org.lflang.target.property.CmakeIncludeProperty; -import org.lflang.target.property.CompileDefinitionsProperty; -import org.lflang.target.property.CompilerFlagsProperty; import org.lflang.target.property.CompilerProperty; import org.lflang.target.property.CoordinationOptionsProperty; import org.lflang.target.property.CoordinationProperty; @@ -61,7 +53,6 @@ import org.lflang.target.property.ExportToYamlProperty; import org.lflang.target.property.ExternalRuntimePathProperty; import org.lflang.target.property.FastProperty; -import org.lflang.target.property.FedSetupProperty; import org.lflang.target.property.FilesProperty; import org.lflang.target.property.HierarchicalBinProperty; import org.lflang.target.property.KeepaliveProperty; @@ -74,7 +65,6 @@ import org.lflang.target.property.Ros2DependenciesProperty; import org.lflang.target.property.Ros2Property; import org.lflang.target.property.RuntimeVersionProperty; -import org.lflang.target.property.RustIncludeProperty; import org.lflang.target.property.SchedulerProperty; import org.lflang.target.property.SingleFileProjectProperty; import org.lflang.target.property.ThreadingProperty; @@ -105,13 +95,11 @@ public class TargetConfig { public TargetConfig(Target target) { this.target = target; + // Register target-specific properties + target.initialize(this); + + // Register general-purpose properties this.register( - new BuildTypeProperty(), - new ClockSyncModeProperty(), - new ClockSyncOptionsProperty(), - new CmakeIncludeProperty(), - new CompileDefinitionsProperty(), - new CompilerFlagsProperty(), new CompilerProperty(), new CoordinationOptionsProperty(), new CoordinationProperty(), @@ -139,25 +127,29 @@ public TargetConfig(Target target) { new TracingProperty(), new VerifyProperty(), new WorkersProperty()); + } - this.register(new FedSetupProperty()); - - this.register( - new CargoFeaturesProperty(), new CargoDependenciesProperty(), new RustIncludeProperty()); + public TargetConfig(TargetDecl target, Properties cliArgs, MessageReporter messageReporter) { + this(Target.fromDecl(target), target.getConfig(), cliArgs, 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 cliArgs Arguments passed on the commandline. - * @param target AST node of a target declaration. * @param messageReporter An error reporter to report problems. */ - public TargetConfig(Properties cliArgs, TargetDecl target, MessageReporter messageReporter) { - this(Target.fromDecl(target)); - if (target.getConfig() != null) { - List pairs = target.getConfig().getPairs(); + public TargetConfig( + Target target, + KeyValuePairs properties, + Properties cliArgs, + MessageReporter messageReporter) { + this(target); + if (properties != null) { + List pairs = properties.getPairs(); this.load(pairs, messageReporter); } diff --git a/core/src/main/java/org/lflang/target/property/BuildTypeProperty.java b/core/src/main/java/org/lflang/target/property/BuildTypeProperty.java index 66ac8273b1..5ed41eb99d 100644 --- a/core/src/main/java/org/lflang/target/property/BuildTypeProperty.java +++ b/core/src/main/java/org/lflang/target/property/BuildTypeProperty.java @@ -16,7 +16,10 @@ */ public class BuildTypeProperty extends TargetProperty { - public BuildTypeProperty() { + /** Singleton target property instance. */ + public static final BuildTypeProperty INSTANCE = new BuildTypeProperty(); + + private BuildTypeProperty() { super(new BuildTypeType()); } 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 17bbadd732..a719d7dbd0 100644 --- a/core/src/main/java/org/lflang/target/property/CargoDependenciesProperty.java +++ b/core/src/main/java/org/lflang/target/property/CargoDependenciesProperty.java @@ -42,9 +42,12 @@ public class CargoDependenciesProperty extends TargetProperty, CargoDependenciesPropertyType> { - public CargoDependenciesProperty() { + /** Singleton target property instance. */ + public static final CargoDependenciesProperty INSTANCE = new CargoDependenciesProperty(); + + private CargoDependenciesProperty() { super(new CargoDependenciesPropertyType()); - } // FIXME + } @Override public Map initialValue() { diff --git a/core/src/main/java/org/lflang/target/property/CargoFeaturesProperty.java b/core/src/main/java/org/lflang/target/property/CargoFeaturesProperty.java index d9c050dec9..0d17ef360d 100644 --- a/core/src/main/java/org/lflang/target/property/CargoFeaturesProperty.java +++ b/core/src/main/java/org/lflang/target/property/CargoFeaturesProperty.java @@ -7,6 +7,13 @@ /** Directive for specifying Cargo features of the generated program to enable. */ public class CargoFeaturesProperty extends StringListProperty { + /** Singleton target property instance. */ + public static final CargoFeaturesProperty INSTANCE = new CargoFeaturesProperty(); + + private CargoFeaturesProperty() { + super(); + } + @Override public List supportedTargets() { return Arrays.asList(Target.Rust); 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 584ddc4856..89562e10cb 100644 --- a/core/src/main/java/org/lflang/target/property/ClockSyncModeProperty.java +++ b/core/src/main/java/org/lflang/target/property/ClockSyncModeProperty.java @@ -17,7 +17,10 @@ /** The mode of clock synchronization to be used in federated programs. The default is 'initial'. */ public class ClockSyncModeProperty extends TargetProperty { - public ClockSyncModeProperty() { + /** Singleton target property instance. */ + public static final ClockSyncModeProperty INSTANCE = new ClockSyncModeProperty(); + + private ClockSyncModeProperty() { super(new ClockSyncModeType()); } 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 92ef3fdafd..4d65c58ccb 100644 --- a/core/src/main/java/org/lflang/target/property/ClockSyncOptionsProperty.java +++ b/core/src/main/java/org/lflang/target/property/ClockSyncOptionsProperty.java @@ -21,7 +21,10 @@ /** Key-value pairs giving options for clock synchronization. */ public class ClockSyncOptionsProperty extends TargetProperty { - public ClockSyncOptionsProperty() { + /** Singleton target property instance. */ + public static final ClockSyncOptionsProperty INSTANCE = new ClockSyncOptionsProperty(); + + private ClockSyncOptionsProperty() { super(DictionaryType.CLOCK_SYNC_OPTION_DICT); } diff --git a/core/src/main/java/org/lflang/target/property/CmakeIncludeProperty.java b/core/src/main/java/org/lflang/target/property/CmakeIncludeProperty.java index b5ca6a6970..b7006b7f37 100644 --- a/core/src/main/java/org/lflang/target/property/CmakeIncludeProperty.java +++ b/core/src/main/java/org/lflang/target/property/CmakeIncludeProperty.java @@ -15,6 +15,13 @@ */ public class CmakeIncludeProperty extends FileListProperty { + /** Singleton target property instance. */ + public static final CmakeIncludeProperty INSTANCE = new CmakeIncludeProperty(); + + private CmakeIncludeProperty() { + super(); + } + @Override protected List fromAst(Element node, MessageReporter reporter) { return ASTUtils.elementToListOfStrings(node); diff --git a/core/src/main/java/org/lflang/target/property/CompileDefinitionsProperty.java b/core/src/main/java/org/lflang/target/property/CompileDefinitionsProperty.java index 51e9ed34ae..831f25682c 100644 --- a/core/src/main/java/org/lflang/target/property/CompileDefinitionsProperty.java +++ b/core/src/main/java/org/lflang/target/property/CompileDefinitionsProperty.java @@ -21,7 +21,10 @@ public class CompileDefinitionsProperty extends TargetProperty, StringDictionaryType> { - public CompileDefinitionsProperty() { + /** Singleton target property instance. */ + public static final CompileDefinitionsProperty INSTANCE = new CompileDefinitionsProperty(); + + private CompileDefinitionsProperty() { super(StringDictionaryType.COMPILE_DEFINITION); } diff --git a/core/src/main/java/org/lflang/target/property/CompilerFlagsProperty.java b/core/src/main/java/org/lflang/target/property/CompilerFlagsProperty.java index 8902f605f2..e5d061a436 100644 --- a/core/src/main/java/org/lflang/target/property/CompilerFlagsProperty.java +++ b/core/src/main/java/org/lflang/target/property/CompilerFlagsProperty.java @@ -7,6 +7,13 @@ /** Flags to pass to the compiler, unless a build command has been specified. */ public class CompilerFlagsProperty extends StringListProperty { + /** Singleton target property instance. */ + public static final CompilerFlagsProperty INSTANCE = new CompilerFlagsProperty(); + + private CompilerFlagsProperty() { + super(); + } + @Override public List supportedTargets() { return Arrays.asList(Target.C, Target.CCPP); diff --git a/core/src/main/kotlin/org/lflang/generator/cpp/CppGenerator.kt b/core/src/main/kotlin/org/lflang/generator/cpp/CppGenerator.kt index e2796c337b..ce338a8f40 100644 --- a/core/src/main/kotlin/org/lflang/generator/cpp/CppGenerator.kt +++ b/core/src/main/kotlin/org/lflang/generator/cpp/CppGenerator.kt @@ -33,10 +33,7 @@ import org.lflang.generator.GeneratorUtils.canGenerate import org.lflang.generator.LFGeneratorContext.Mode import org.lflang.isGeneric import org.lflang.scoping.LFGlobalScopeProvider -import org.lflang.target.property.ExternalRuntimePathProperty -import org.lflang.target.property.NoCompileProperty -import org.lflang.target.property.Ros2Property -import org.lflang.target.property.RuntimeVersionProperty +import org.lflang.target.property.* import org.lflang.util.FileUtil import java.nio.file.Files import java.nio.file.Path diff --git a/core/src/main/kotlin/org/lflang/generator/cpp/CppPlatformGenerator.kt b/core/src/main/kotlin/org/lflang/generator/cpp/CppPlatformGenerator.kt index 1c11055573..92278526a6 100644 --- a/core/src/main/kotlin/org/lflang/generator/cpp/CppPlatformGenerator.kt +++ b/core/src/main/kotlin/org/lflang/generator/cpp/CppPlatformGenerator.kt @@ -30,7 +30,7 @@ abstract class CppPlatformGenerator(protected val generator: CppGenerator) { protected val cmakeArgs: List get() = listOf( - "-DCMAKE_BUILD_TYPE=${targetConfig.get(BuildTypeProperty())}", + "-DCMAKE_BUILD_TYPE=${targetConfig.get(BuildTypeProperty.INSTANCE)}", "-DREACTOR_CPP_VALIDATE=${if (targetConfig.get(NoRuntimeValidationProperty())) "OFF" else "ON"}", "-DREACTOR_CPP_PRINT_STATISTICS=${if (targetConfig.get(PrintStatisticsProperty())) "ON" else "OFF"}", "-DREACTOR_CPP_TRACE=${if (targetConfig.get(TracingProperty()).isEnabled) "ON" else "OFF"}", diff --git a/core/src/main/kotlin/org/lflang/generator/cpp/CppRos2PackageGenerator.kt b/core/src/main/kotlin/org/lflang/generator/cpp/CppRos2PackageGenerator.kt index 83f1d0d57a..5f3aac1a84 100644 --- a/core/src/main/kotlin/org/lflang/generator/cpp/CppRos2PackageGenerator.kt +++ b/core/src/main/kotlin/org/lflang/generator/cpp/CppRos2PackageGenerator.kt @@ -52,7 +52,7 @@ class CppRos2PackageGenerator(generator: CppGenerator, private val nodeName: Str fun generatePackageCmake(sources: List): String { // Resolve path to the cmake include files if any was provided - val includeFiles = targetConfig.get(CmakeIncludeProperty())?.map { fileConfig.srcPath.resolve(it).toUnixString() } + val includeFiles = targetConfig.get(CmakeIncludeProperty.INSTANCE)?.map { fileConfig.srcPath.resolve(it).toUnixString() } return with(PrependOperator) { with(CppGenerator) { @@ -65,7 +65,7 @@ class CppRos2PackageGenerator(generator: CppGenerator, private val nodeName: Str |set(CMAKE_CXX_STANDARD_REQUIRED ON) |set(CMAKE_CXX_EXTENSIONS OFF) | - |set(DEFAULT_BUILD_TYPE "${targetConfig.get(BuildTypeProperty())}") + |set(DEFAULT_BUILD_TYPE "${targetConfig.get(BuildTypeProperty.INSTANCE)}") |if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) |set (CMAKE_BUILD_TYPE "$S{DEFAULT_BUILD_TYPE}" CACHE STRING "Choose the type of build." FORCE) |endif() diff --git a/core/src/main/kotlin/org/lflang/generator/cpp/CppStandaloneCmakeGenerator.kt b/core/src/main/kotlin/org/lflang/generator/cpp/CppStandaloneCmakeGenerator.kt index 22ea6e19c0..3048ccd5a0 100644 --- a/core/src/main/kotlin/org/lflang/generator/cpp/CppStandaloneCmakeGenerator.kt +++ b/core/src/main/kotlin/org/lflang/generator/cpp/CppStandaloneCmakeGenerator.kt @@ -83,7 +83,7 @@ class CppStandaloneCmakeGenerator(private val targetConfig: TargetConfig, privat |include($S{CMAKE_ROOT}/Modules/ExternalProject.cmake) |include(GNUInstallDirs) | - |set(DEFAULT_BUILD_TYPE "${targetConfig.get(BuildTypeProperty())}") + |set(DEFAULT_BUILD_TYPE "${targetConfig.get(BuildTypeProperty.INSTANCE)}") |if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) |set (CMAKE_BUILD_TYPE "$S{DEFAULT_BUILD_TYPE}" CACHE STRING "Choose the type of build." FORCE) |endif() @@ -137,7 +137,7 @@ class CppStandaloneCmakeGenerator(private val targetConfig: TargetConfig, privat fun generateCmake(sources: List): String { // Resolve path to the cmake include files if any was provided - val includeFiles = targetConfig.get(CmakeIncludeProperty())?.map { fileConfig.srcPath.resolve(it).toUnixString() } + val includeFiles = targetConfig.get(CmakeIncludeProperty.INSTANCE)?.map { fileConfig.srcPath.resolve(it).toUnixString() } val reactorCppTarget = when { targetConfig.isSet(ExternalRuntimePathProperty()) -> "reactor-cpp" diff --git a/core/src/main/kotlin/org/lflang/generator/cpp/CppStandaloneGenerator.kt b/core/src/main/kotlin/org/lflang/generator/cpp/CppStandaloneGenerator.kt index 5f7adb4ae5..a4f689dc97 100644 --- a/core/src/main/kotlin/org/lflang/generator/cpp/CppStandaloneGenerator.kt +++ b/core/src/main/kotlin/org/lflang/generator/cpp/CppStandaloneGenerator.kt @@ -142,7 +142,7 @@ class CppStandaloneGenerator(generator: CppGenerator) : if (version.compareVersion("3.12.0") < 0) { messageReporter.nowhere().warning("CMAKE is older than version 3.12. Parallel building is not supported.") makeArgs = - listOf("--build", ".", "--target", target, "--config", buildTypeToCmakeConfig(targetConfig.get(BuildTypeProperty()))) + listOf("--build", ".", "--target", target, "--config", buildTypeToCmakeConfig(targetConfig.get(BuildTypeProperty.INSTANCE))) } else { val cores = Runtime.getRuntime().availableProcessors() makeArgs = listOf( @@ -153,7 +153,7 @@ class CppStandaloneGenerator(generator: CppGenerator) : "--parallel", cores.toString(), "--config", - buildTypeToCmakeConfig(targetConfig.get(BuildTypeProperty())) + buildTypeToCmakeConfig(targetConfig.get(BuildTypeProperty.INSTANCE)) ) } diff --git a/core/src/main/kotlin/org/lflang/generator/rust/RustGenerator.kt b/core/src/main/kotlin/org/lflang/generator/rust/RustGenerator.kt index b9fc1a58db..c664c5308f 100644 --- a/core/src/main/kotlin/org/lflang/generator/rust/RustGenerator.kt +++ b/core/src/main/kotlin/org/lflang/generator/rust/RustGenerator.kt @@ -26,20 +26,11 @@ package org.lflang.generator.rust import org.eclipse.emf.ecore.resource.Resource import org.lflang.Target +import org.lflang.generator.* import org.lflang.generator.GeneratorUtils.canGenerate -import org.lflang.generator.CodeMap -import org.lflang.generator.GeneratorBase -import org.lflang.generator.GeneratorResult -import org.lflang.generator.IntegratedBuilder -import org.lflang.generator.LFGeneratorContext -import org.lflang.generator.TargetTypes - import org.lflang.joinWithCommas import org.lflang.scoping.LFGlobalScopeProvider -import org.lflang.target.property.BuildTypeProperty -import org.lflang.target.property.CargoFeaturesProperty -import org.lflang.target.property.CompilerFlagsProperty -import org.lflang.target.property.NoCompileProperty +import org.lflang.target.property.* import org.lflang.target.property.type.BuildTypeType import org.lflang.util.FileUtil import java.nio.file.Files @@ -100,7 +91,7 @@ class RustGenerator( val args = mutableListOf().apply { this += "build" - val buildType = targetConfig.get(BuildTypeProperty()) + val buildType = targetConfig.get(BuildTypeProperty.INSTANCE) if (buildType == BuildTypeType.BuildType.RELEASE) { this += "--release" } else if (buildType != BuildTypeType.BuildType.DEBUG) { @@ -108,12 +99,12 @@ class RustGenerator( this += buildType.cargoProfileName } - if (targetConfig.get(CargoFeaturesProperty()).isNotEmpty()) { + if (targetConfig.get(CargoFeaturesProperty.INSTANCE).isNotEmpty()) { this += "--features" - this += targetConfig.get(CargoFeaturesProperty()).joinWithCommas() + this += targetConfig.get(CargoFeaturesProperty.INSTANCE).joinWithCommas() } - this += targetConfig.get(CompilerFlagsProperty()) + this += targetConfig.get(CompilerFlagsProperty.INSTANCE) this += listOf("--message-format", "json-diagnostic-rendered-ansi") } @@ -129,7 +120,7 @@ class RustGenerator( if (cargoReturnCode == 0) { // We still have to copy the compiled binary to the destination folder. - val buildType = targetConfig.get(BuildTypeProperty()) + val buildType = targetConfig.get(BuildTypeProperty.INSTANCE) val binaryPath = validator.metadata?.targetDirectory!! .resolve(buildType.cargoProfileName) .resolve(fileConfig.executable.fileName) 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 82e0fc842c..d65b816d2f 100644 --- a/core/src/main/kotlin/org/lflang/generator/rust/RustModel.kt +++ b/core/src/main/kotlin/org/lflang/generator/rust/RustModel.kt @@ -440,7 +440,7 @@ object RustModelBuilder { val mainReactor = reactorsInfos.lastOrNull { it.isMain } ?: reactorsInfos.last() - val dependencies = targetConfig.get(CargoDependenciesProperty()).toMutableMap() + val dependencies = targetConfig.get(CargoDependenciesProperty.INSTANCE).toMutableMap() dependencies.compute(RustEmitterBase.runtimeCrateFullName) { _, spec -> computeDefaultRuntimeConfiguration(spec, targetConfig, messageReporter) } @@ -452,7 +452,7 @@ object RustModelBuilder { authors = listOf(System.getProperty("user.name")), dependencies = dependencies, modulesToIncludeInMain = targetConfig.get(RustIncludeProperty()), - enabledCargoFeatures = targetConfig.get(CargoFeaturesProperty()).toSet() + enabledCargoFeatures = targetConfig.get(CargoFeaturesProperty.INSTANCE).toSet() ), reactors = reactorsInfos, mainReactor = mainReactor, 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 3b434ebb4e..88b2633943 100644 --- a/core/src/test/java/org/lflang/tests/compiler/LinguaFrancaValidationTest.java +++ b/core/src/test/java/org/lflang/tests/compiler/LinguaFrancaValidationTest.java @@ -1581,7 +1581,7 @@ public Collection checkTargetProperties() throws Exception { @Test public void checkCargoDependencyProperty() throws Exception { - CargoDependenciesProperty prop = new CargoDependenciesProperty(); + CargoDependenciesProperty prop = CargoDependenciesProperty.INSTANCE; List knownCorrect = List.of( "{}", @@ -1840,7 +1840,7 @@ public void testInvalidTargetParam() throws Exception { public void testTargetParamNotSupportedForTarget() throws Exception { String testCase = """ - target Python { build: "" } + target Python { cargo-features: "" } main reactor {} """; List issues = validator.validate(parseWithoutError(testCase)); @@ -1850,7 +1850,7 @@ public void testTargetParamNotSupportedForTarget() throws Exception { .get(0) .getMessage() .contains( - "The target property: build" + "The target property: cargo-features" + " is not supported by the Python target and will thus be ignored.")); } From 46eb4f9a3d9b147362a37d3fd3501ecfd709fb24 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Mon, 16 Oct 2023 18:05:26 -0700 Subject: [PATCH 093/145] Moved more property initializations --- core/src/main/java/org/lflang/Target.java | 46 +++++++++++++++++-- .../federated/extensions/CExtension.java | 9 ++-- .../federated/extensions/CExtensionUtils.java | 4 +- .../federated/extensions/TSExtension.java | 4 +- .../federated/generator/FedFileConfig.java | 2 +- .../federated/generator/FedGenerator.java | 23 +++++----- .../FedROS2CPPSerialization.java | 5 +- .../org/lflang/generator/GeneratorBase.java | 2 +- .../org/lflang/generator/GeneratorUtils.java | 8 ++-- .../org/lflang/generator/MainContext.java | 2 +- .../lflang/generator/c/CCmakeGenerator.java | 6 +-- .../org/lflang/generator/c/CCompiler.java | 14 +++--- .../lflang/generator/c/CDockerGenerator.java | 2 +- .../org/lflang/generator/c/CGenerator.java | 16 +++---- .../generator/c/CMainFunctionGenerator.java | 4 +- .../generator/c/CPreambleGenerator.java | 2 +- .../generator/c/CTriggerObjectsGenerator.java | 2 +- .../generator/python/PythonGenerator.java | 2 +- .../java/org/lflang/target/TargetConfig.java | 26 ++--------- .../target/property/BuildTypeProperty.java | 4 +- .../property/CargoDependenciesProperty.java | 2 +- .../property/CargoFeaturesProperty.java | 2 +- .../property/ClockSyncModeProperty.java | 2 +- .../property/ClockSyncOptionsProperty.java | 3 +- .../target/property/CmakeIncludeProperty.java | 2 +- .../property/CompileDefinitionsProperty.java | 2 +- .../property/CompilerFlagsProperty.java | 2 +- .../target/property/CompilerProperty.java | 9 +++- .../property/CoordinationOptionsProperty.java | 7 ++- .../target/property/CoordinationProperty.java | 8 +++- .../target/property/DockerProperty.java | 7 ++- .../ExportDependencyGraphProperty.java | 9 +++- .../target/property/ExportToYamlProperty.java | 9 +++- .../property/ExternalRuntimePathProperty.java | 9 +++- .../lflang/target/property/FastProperty.java | 9 +++- .../lflang/target/property/FilesProperty.java | 9 +++- .../property/HierarchicalBinProperty.java | 9 +++- .../target/property/KeepaliveProperty.java | 9 +++- .../target/property/LoggingProperty.java | 7 ++- .../target/property/NoCompileProperty.java | 9 +++- .../target/property/RustIncludeProperty.java | 7 ++- .../org/lflang/generator/cpp/CppGenerator.kt | 4 +- .../generator/cpp/CppPlatformGenerator.kt | 2 +- .../generator/cpp/CppRos2NodeGenerator.kt | 2 +- .../cpp/CppStandaloneCmakeGenerator.kt | 4 +- .../generator/cpp/CppStandaloneGenerator.kt | 4 +- .../cpp/CppStandaloneMainGenerator.kt | 8 ++-- .../lflang/generator/rust/RustGenerator.kt | 2 +- .../org/lflang/generator/rust/RustModel.kt | 14 +++--- .../org/lflang/generator/ts/TSGenerator.kt | 11 +++-- .../ts/TSParameterPreambleGenerator.kt | 6 +-- .../java/org/lflang/tests/Configurators.java | 4 +- .../java/org/lflang/tests/TestBase.java | 2 +- 53 files changed, 241 insertions(+), 137 deletions(-) diff --git a/core/src/main/java/org/lflang/Target.java b/core/src/main/java/org/lflang/Target.java index 0d73df15a1..edfd0bda2d 100644 --- a/core/src/main/java/org/lflang/Target.java +++ b/core/src/main/java/org/lflang/Target.java @@ -37,6 +37,16 @@ import org.lflang.target.property.CmakeIncludeProperty; import org.lflang.target.property.CompileDefinitionsProperty; import org.lflang.target.property.CompilerFlagsProperty; +import org.lflang.target.property.CompilerProperty; +import org.lflang.target.property.CoordinationOptionsProperty; +import org.lflang.target.property.CoordinationProperty; +import org.lflang.target.property.DockerProperty; +import org.lflang.target.property.ExportDependencyGraphProperty; +import org.lflang.target.property.ExportToYamlProperty; +import org.lflang.target.property.ExternalRuntimePathProperty; +import org.lflang.target.property.FilesProperty; +import org.lflang.target.property.HierarchicalBinProperty; +import org.lflang.target.property.KeepaliveProperty; import org.lflang.target.property.RustIncludeProperty; /** @@ -569,19 +579,47 @@ public void initialize(TargetConfig config) { ClockSyncOptionsProperty.INSTANCE, CmakeIncludeProperty.INSTANCE, CompileDefinitionsProperty.INSTANCE, - CompilerFlagsProperty.INSTANCE); - case CPP -> config.register(BuildTypeProperty.INSTANCE, CmakeIncludeProperty.INSTANCE); + CompilerFlagsProperty.INSTANCE, + CompilerProperty.INSTANCE, + CoordinationOptionsProperty.INSTANCE, + CoordinationProperty.INSTANCE, + DockerProperty.INSTANCE, + FilesProperty.INSTANCE, + HierarchicalBinProperty.INSTANCE, + KeepaliveProperty.INSTANCE); + case CPP -> config.register( + BuildTypeProperty.INSTANCE, + CmakeIncludeProperty.INSTANCE, + CompilerProperty.INSTANCE, + ExportDependencyGraphProperty.INSTANCE, + ExportToYamlProperty.INSTANCE, + ExternalRuntimePathProperty.INSTANCE); case Python -> config.register( + BuildTypeProperty.INSTANCE, ClockSyncModeProperty.INSTANCE, ClockSyncOptionsProperty.INSTANCE, - CompileDefinitionsProperty.INSTANCE); + CompileDefinitionsProperty.INSTANCE, + CoordinationOptionsProperty.INSTANCE, + CoordinationProperty.INSTANCE, + DockerProperty.INSTANCE, + FilesProperty.INSTANCE, + KeepaliveProperty.INSTANCE); case Rust -> config.register( BuildTypeProperty.INSTANCE, CargoDependenciesProperty.INSTANCE, CargoFeaturesProperty.INSTANCE, CmakeIncludeProperty.INSTANCE, CompileDefinitionsProperty.INSTANCE, - new RustIncludeProperty()); + CompilerFlagsProperty.INSTANCE, + ExportDependencyGraphProperty.INSTANCE, + ExternalRuntimePathProperty.INSTANCE, + RustIncludeProperty.INSTANCE, + KeepaliveProperty.INSTANCE); + case TS -> config.register( + CoordinationOptionsProperty.INSTANCE, + CoordinationProperty.INSTANCE, + DockerProperty.INSTANCE, + KeepaliveProperty.INSTANCE); } } } 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 21b44588ce..ca0552b85e 100644 --- a/core/src/main/java/org/lflang/federated/extensions/CExtension.java +++ b/core/src/main/java/org/lflang/federated/extensions/CExtension.java @@ -87,7 +87,7 @@ public void initializeTargetConfig( generateCMakeInclude(federate, fileConfig); - new KeepaliveProperty().override(federate.targetConfig, true); + KeepaliveProperty.INSTANCE.override(federate.targetConfig, true); // If there are federates, copy the required files for that. // Also, create the RTI C file and the launcher script. @@ -682,7 +682,8 @@ private String generateCodeToInitializeFederate(FederateInstance federate, RtiCo "lf_cond_init(&logical_time_changed, &env->mutex);"))); // Find the STA (A.K.A. the global STP offset) for this federate. - if (federate.targetConfig.get(new CoordinationProperty()) == CoordinationMode.DECENTRALIZED) { + if (federate.targetConfig.get(CoordinationProperty.INSTANCE) + == CoordinationMode.DECENTRALIZED) { var reactor = ASTUtils.toDefinition(federate.instantiation.getReactorClass()); var stpParam = reactor.getParameters().stream() @@ -806,8 +807,8 @@ private String generateCodeToInitializeFederate(FederateInstance federate, RtiCo private String generateCodeForPhysicalActions( FederateInstance federate, MessageReporter messageReporter) { CodeBuilder code = new CodeBuilder(); - var coordinationMode = federate.targetConfig.get(new CoordinationProperty()); - var coordinationOptions = federate.targetConfig.get(new CoordinationOptionsProperty()); + var coordinationMode = federate.targetConfig.get(CoordinationProperty.INSTANCE); + var coordinationOptions = federate.targetConfig.get(CoordinationOptionsProperty.INSTANCE); if (coordinationMode.equals(CoordinationMode.CENTRALIZED)) { // If this program uses centralized coordination then check // for outputs that depend on physical actions so that null messages can be diff --git a/core/src/main/java/org/lflang/federated/extensions/CExtensionUtils.java b/core/src/main/java/org/lflang/federated/extensions/CExtensionUtils.java index 59f2d59a65..6f535da595 100644 --- a/core/src/main/java/org/lflang/federated/extensions/CExtensionUtils.java +++ b/core/src/main/java/org/lflang/federated/extensions/CExtensionUtils.java @@ -187,7 +187,7 @@ public static void handleCompileDefinitions( definitions.put( String.format( "FEDERATED_%s", - federate.targetConfig.get(new CoordinationProperty()).toString().toUpperCase()), + federate.targetConfig.get(CoordinationProperty.INSTANCE).toString().toUpperCase()), ""); if (federate.targetConfig.get(AuthProperty.INSTANCE)) { definitions.put("FEDERATED_AUTHENTICATED", ""); @@ -204,7 +204,7 @@ public static void handleCompileDefinitions( private static void handleAdvanceMessageInterval(FederateInstance federate) { var advanceMessageInterval = - federate.targetConfig.get(new CoordinationOptionsProperty()).advanceMessageInterval; + federate.targetConfig.get(CoordinationOptionsProperty.INSTANCE).advanceMessageInterval; if (advanceMessageInterval != null) { federate .targetConfig diff --git a/core/src/main/java/org/lflang/federated/extensions/TSExtension.java b/core/src/main/java/org/lflang/federated/extensions/TSExtension.java index bf3337d913..88579137d3 100644 --- a/core/src/main/java/org/lflang/federated/extensions/TSExtension.java +++ b/core/src/main/java/org/lflang/federated/extensions/TSExtension.java @@ -201,7 +201,7 @@ public String generatePreamble( } private TimeValue getMinOutputDelay(FederateInstance federate, MessageReporter messageReporter) { - if (federate.targetConfig.get(new CoordinationProperty()) == CoordinationMode.CENTRALIZED) { + if (federate.targetConfig.get(CoordinationProperty.INSTANCE) == CoordinationMode.CENTRALIZED) { // If this program uses centralized coordination then check // for outputs that depend on physical actions so that null messages can be // sent to the RTI. @@ -224,7 +224,7 @@ private TimeValue getMinOutputDelay(FederateInstance federate, MessageReporter m } if (minOutputDelay != TimeValue.MAX_VALUE) { // Unless silenced, issue a warning. - if (federate.targetConfig.get(new CoordinationOptionsProperty()).advanceMessageInterval + if (federate.targetConfig.get(CoordinationOptionsProperty.INSTANCE).advanceMessageInterval == null) { String message = String.join( diff --git a/core/src/main/java/org/lflang/federated/generator/FedFileConfig.java b/core/src/main/java/org/lflang/federated/generator/FedFileConfig.java index a8e5c3a4ff..f3db2573c7 100644 --- a/core/src/main/java/org/lflang/federated/generator/FedFileConfig.java +++ b/core/src/main/java/org/lflang/federated/generator/FedFileConfig.java @@ -103,7 +103,7 @@ public void doClean() throws IOException { * the generated .lf file for the federate. */ public void relativizePaths(FedTargetConfig targetConfig) { - List.of(new ProtobufsProperty(), new FilesProperty(), CmakeIncludeProperty.INSTANCE) + List.of(new ProtobufsProperty(), FilesProperty.INSTANCE, CmakeIncludeProperty.INSTANCE) .forEach( p -> { p.override(targetConfig, relativizePathList(targetConfig.get(p))); 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 cb89639f57..682d12d1eb 100644 --- a/core/src/main/java/org/lflang/federated/generator/FedGenerator.java +++ b/core/src/main/java/org/lflang/federated/generator/FedGenerator.java @@ -125,7 +125,7 @@ public boolean doGenerate(Resource resource, LFGeneratorContext context) throws // In a federated execution, we need keepalive to be true, // otherwise a federate could exit simply because it hasn't received // any messages. - new KeepaliveProperty().override(targetConfig, true); + KeepaliveProperty.INSTANCE.override(targetConfig, true); // Process command-line arguments processCLIArguments(context); @@ -157,7 +157,7 @@ public boolean doGenerate(Resource resource, LFGeneratorContext context) throws } // Do not invoke target code generators if --no-compile flag is used. - if (context.getTargetConfig().get(new NoCompileProperty())) { + if (context.getTargetConfig().get(NoCompileProperty.INSTANCE)) { context.finish(Status.GENERATED, lf2lfCodeMapMap); return false; } @@ -197,14 +197,13 @@ private void generateLaunchScript() { * @param subContexts The subcontexts in which the federates have been compiled. */ private void createDockerFiles(LFGeneratorContext context, List subContexts) { - if (!context.getTargetConfig().get(new DockerProperty()).enabled) return; + if (!context.getTargetConfig().get(DockerProperty.INSTANCE).enabled) return; final List services = new ArrayList<>(); // 1. create a Dockerfile for each federate for (SubContext subContext : subContexts) { // Inherit Docker options from main context - new DockerProperty() - .override( - subContext.getTargetConfig(), context.getTargetConfig().get(new DockerProperty())); + DockerProperty.INSTANCE.override( + subContext.getTargetConfig(), context.getTargetConfig().get(DockerProperty.INSTANCE)); var dockerGenerator = dockerGeneratorFactory(subContext); var dockerData = dockerGenerator.generateDockerData(); try { @@ -302,11 +301,11 @@ private Map compileFederates( GeneratorUtils.findTargetDecl(subFileConfig.resource), new Properties(), subContextMessageReporter); - if (targetConfig.get(new DockerProperty()).enabled + if (targetConfig.get(DockerProperty.INSTANCE).enabled && targetConfig.target.buildsUsingDocker()) { - new NoCompileProperty().override(subConfig, true); + NoCompileProperty.INSTANCE.override(subConfig, true); } - subConfig.get(new DockerProperty()).enabled = false; + subConfig.get(DockerProperty.INSTANCE).enabled = false; SubContext subContext = new SubContext(context, IntegratedBuilder.VALIDATED_PERCENT_PROGRESS, 100) { @@ -424,7 +423,7 @@ private void analyzeFederates(Reactor federation, LFGeneratorContext context) { rtiConfig.setHost(federation.getHost().getAddr()); } - var d = new DockerProperty(); + var d = DockerProperty.INSTANCE; var x = targetConfig.get(d); // If the federation is dockerized, use "rti" as the hostname. if (rtiConfig.getHost().equals("localhost") && x.enabled) { @@ -685,7 +684,7 @@ private void replaceOneToManyConnection( */ private void replaceFedConnection(FedConnectionInstance connection, Resource resource) { if (!connection.getDefinition().isPhysical() - && targetConfig.get(new CoordinationProperty()) != CoordinationMode.DECENTRALIZED) { + && targetConfig.get(CoordinationProperty.INSTANCE) != CoordinationMode.DECENTRALIZED) { // Map the delays on connections between federates. Set dependsOnDelays = connection.dstFederate.dependsOn.computeIfAbsent( @@ -710,6 +709,6 @@ private void replaceFedConnection(FedConnectionInstance connection, Resource res } FedASTUtils.makeCommunication( - connection, resource, targetConfig.get(new CoordinationProperty()), messageReporter); + connection, resource, targetConfig.get(CoordinationProperty.INSTANCE), messageReporter); } } diff --git a/core/src/main/java/org/lflang/federated/serialization/FedROS2CPPSerialization.java b/core/src/main/java/org/lflang/federated/serialization/FedROS2CPPSerialization.java index 2dc54a235a..225d519d77 100644 --- a/core/src/main/java/org/lflang/federated/serialization/FedROS2CPPSerialization.java +++ b/core/src/main/java/org/lflang/federated/serialization/FedROS2CPPSerialization.java @@ -53,7 +53,10 @@ public boolean isCompatible(GeneratorBase generator) { .nowhere() .error("ROS serialization is currently only supported for the C target."); return false; - } else if (!generator.getTargetConfig().get(new CompilerProperty()).equalsIgnoreCase("g++")) { + } else if (!generator + .getTargetConfig() + .get(CompilerProperty.INSTANCE) + .equalsIgnoreCase("g++")) { generator .messageReporter .nowhere() diff --git a/core/src/main/java/org/lflang/generator/GeneratorBase.java b/core/src/main/java/org/lflang/generator/GeneratorBase.java index 64e6e6aec6..50cad851d5 100644 --- a/core/src/main/java/org/lflang/generator/GeneratorBase.java +++ b/core/src/main/java/org/lflang/generator/GeneratorBase.java @@ -334,7 +334,7 @@ protected void setReactorsAndInstantiationGraph(LFGeneratorContext.Mode mode) { protected void copyUserFiles(TargetConfig targetConfig, FileConfig fileConfig) { var dst = this.context.getFileConfig().getSrcGenPath(); FileUtil.copyFilesOrDirectories( - targetConfig.get(new FilesProperty()), dst, fileConfig, messageReporter, false); + targetConfig.get(FilesProperty.INSTANCE), dst, fileConfig, messageReporter, false); } /** diff --git a/core/src/main/java/org/lflang/generator/GeneratorUtils.java b/core/src/main/java/org/lflang/generator/GeneratorUtils.java index 1b4c0f9fa2..1ce0cac900 100644 --- a/core/src/main/java/org/lflang/generator/GeneratorUtils.java +++ b/core/src/main/java/org/lflang/generator/GeneratorUtils.java @@ -56,15 +56,15 @@ public static void accommodatePhysicalActionsIfPresent( for (Resource resource : resources) { for (Action action : findAll(resource, Action.class)) { if (action.getOrigin() == ActionOrigin.PHYSICAL - && !targetConfig.isSet(new KeepaliveProperty()) - && !targetConfig.get(new KeepaliveProperty())) { + && !targetConfig.isSet(KeepaliveProperty.INSTANCE) + && !targetConfig.get(KeepaliveProperty.INSTANCE)) { // Keepalive was explicitly set to false; set it to true. - new KeepaliveProperty().override(targetConfig, true); + KeepaliveProperty.INSTANCE.override(targetConfig, true); String message = String.format( "Setting %s to true because of the physical action %s.", - new KeepaliveProperty().name(), action.getName()); + KeepaliveProperty.INSTANCE.name(), action.getName()); messageReporter.at(action).warning(message); return; } diff --git a/core/src/main/java/org/lflang/generator/MainContext.java b/core/src/main/java/org/lflang/generator/MainContext.java index cf4add1d37..4e9dad4765 100644 --- a/core/src/main/java/org/lflang/generator/MainContext.java +++ b/core/src/main/java/org/lflang/generator/MainContext.java @@ -94,7 +94,7 @@ public MainContext( this.args = args; try { - var key = new HierarchicalBinProperty().name(); + var key = HierarchicalBinProperty.INSTANCE.name(); var useHierarchicalBin = args.contains(key) && Boolean.parseBoolean(args.getProperty(key)); fileConfig = Objects.requireNonNull( 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 3c35d078bc..af98735fe5 100644 --- a/core/src/main/java/org/lflang/generator/c/CCmakeGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CCmakeGenerator.java @@ -382,12 +382,12 @@ CodeBuilder generateCMakeCode( if (CppMode) cMakeCode.pr("enable_language(CXX)"); - if (targetConfig.isSet(new CompilerProperty())) { + if (targetConfig.isSet(CompilerProperty.INSTANCE)) { if (CppMode) { // Set the CXX compiler to what the user has requested. - cMakeCode.pr("set(CMAKE_CXX_COMPILER " + targetConfig.get(new CompilerProperty()) + ")"); + cMakeCode.pr("set(CMAKE_CXX_COMPILER " + targetConfig.get(CompilerProperty.INSTANCE) + ")"); } else { - cMakeCode.pr("set(CMAKE_C_COMPILER " + targetConfig.get(new CompilerProperty()) + ")"); + cMakeCode.pr("set(CMAKE_C_COMPILER " + targetConfig.get(CompilerProperty.INSTANCE) + ")"); } cMakeCode.newLine(); } diff --git a/core/src/main/java/org/lflang/generator/c/CCompiler.java b/core/src/main/java/org/lflang/generator/c/CCompiler.java index d0f175dafc..ba84d74af8 100644 --- a/core/src/main/java/org/lflang/generator/c/CCompiler.java +++ b/core/src/main/java/org/lflang/generator/c/CCompiler.java @@ -122,13 +122,13 @@ public boolean runCCompiler(GeneratorBase generator, LFGeneratorContext context) } // Use the user-specified compiler if any - if (targetConfig.get(new CompilerProperty()) != null) { + if (targetConfig.isSet(CompilerProperty.INSTANCE)) { if (cppMode) { // Set the CXX environment variable to change the C++ compiler. - compile.replaceEnvironmentVariable("CXX", targetConfig.get(new CompilerProperty())); + compile.replaceEnvironmentVariable("CXX", targetConfig.get(CompilerProperty.INSTANCE)); } else { // Set the CC environment variable to change the C compiler. - compile.replaceEnvironmentVariable("CC", targetConfig.get(new CompilerProperty())); + compile.replaceEnvironmentVariable("CC", targetConfig.get(CompilerProperty.INSTANCE)); } } @@ -140,7 +140,7 @@ public boolean runCCompiler(GeneratorBase generator, LFGeneratorContext context) messageReporter .nowhere() .error( - targetConfig.get(new CompilerProperty()) + targetConfig.get(CompilerProperty.INSTANCE) + " failed with error code " + cMakeReturnCode); } @@ -166,7 +166,7 @@ public boolean runCCompiler(GeneratorBase generator, LFGeneratorContext context) messageReporter .nowhere() .error( - targetConfig.get(new CompilerProperty()) + targetConfig.get(CompilerProperty.INSTANCE) + " failed with error code " + makeReturnCode); } @@ -352,7 +352,7 @@ private boolean outputContainsKnownCMakeErrors(String CMakeOutput) { // Check if the error thrown is due to the wrong compiler if (CMakeOutput.contains("The CMAKE_C_COMPILER is set to a C++ compiler")) { // If so, print an appropriate error message - if (targetConfig.get(new CompilerProperty()) != null) { + if (targetConfig.get(CompilerProperty.INSTANCE) != null) { messageReporter .nowhere() .error( @@ -426,7 +426,7 @@ public LFCommand compileCCommand(String fileToCompile, boolean noBinary) { LFCommand command = commandFactory.createCommand( - targetConfig.get(new CompilerProperty()), compileArgs, fileConfig.getOutPath()); + targetConfig.get(CompilerProperty.INSTANCE), compileArgs, fileConfig.getOutPath()); if (command == null) { messageReporter .nowhere() diff --git a/core/src/main/java/org/lflang/generator/c/CDockerGenerator.java b/core/src/main/java/org/lflang/generator/c/CDockerGenerator.java index 8b3adf0dfa..4f2cb10f1d 100644 --- a/core/src/main/java/org/lflang/generator/c/CDockerGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CDockerGenerator.java @@ -36,7 +36,7 @@ protected String generateDockerFileContent() { : StringUtil.joinObjects(config.get(BuildCommandsProperty.INSTANCE), " "); var compiler = config.target == Target.CCPP ? "g++" : "gcc"; var baseImage = DEFAULT_BASE_IMAGE; - var dockerConf = config.get(new DockerProperty()); + var dockerConf = config.get(DockerProperty.INSTANCE); if (dockerConf.enabled && dockerConf.from != null) { baseImage = dockerConf.from; } 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 077fecdb9e..20a49452c3 100644 --- a/core/src/main/java/org/lflang/generator/c/CGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CGenerator.java @@ -435,7 +435,7 @@ public void doGenerate(Resource resource, LFGeneratorContext context) { } // Create docker file. - if (targetConfig.get(new DockerProperty()).enabled && mainDef != null) { + if (targetConfig.get(DockerProperty.INSTANCE).enabled && mainDef != null) { try { var dockerData = getDockerGenerator(context).generateDockerData(); dockerData.writeDockerFile(); @@ -480,7 +480,7 @@ public void doGenerate(Resource resource, LFGeneratorContext context) { //noinspection ThrowableNotThrown,ResultOfMethodCallIgnored Exceptions.sneakyThrow(e); } - if (!targetConfig.get(new NoCompileProperty())) { + if (!targetConfig.get(NoCompileProperty.INSTANCE)) { ArduinoUtil arduinoUtil = new ArduinoUtil(context, commandFactory, messageReporter); arduinoUtil.buildArduino(fileConfig, targetConfig); context.finish(GeneratorResult.Status.COMPILED, null); @@ -513,8 +513,8 @@ public void doGenerate(Resource resource, LFGeneratorContext context) { // If this code generator is directly compiling the code, compile it now so that we // clean it up after, removing the #line directives after errors have been reported. - if (!targetConfig.get(new NoCompileProperty()) - && !targetConfig.get(new DockerProperty()).enabled + if (!targetConfig.get(NoCompileProperty.INSTANCE) + && !targetConfig.get(DockerProperty.INSTANCE).enabled && IterableExtensions.isNullOrEmpty(targetConfig.get(BuildCommandsProperty.INSTANCE)) // This code is unreachable in LSP_FAST mode, so that check is omitted. && context.getMode() != LFGeneratorContext.Mode.LSP_MEDIUM) { @@ -557,7 +557,7 @@ public void doGenerate(Resource resource, LFGeneratorContext context) { // If a build directive has been given, invoke it now. // Note that the code does not get cleaned in this case. - if (!targetConfig.get(new NoCompileProperty())) { + if (!targetConfig.get(NoCompileProperty.INSTANCE)) { if (!IterableExtensions.isNullOrEmpty(targetConfig.get(BuildCommandsProperty.INSTANCE))) { CUtil.runBuildCommand( fileConfig, @@ -1932,7 +1932,7 @@ protected void setUpGeneralParameters() { accommodatePhysicalActionsIfPresent(); CompileDefinitionsProperty.INSTANCE.update( targetConfig, - Map.of("LOG_LEVEL", String.valueOf(targetConfig.get(new LoggingProperty()).ordinal()))); + Map.of("LOG_LEVEL", String.valueOf(targetConfig.get(LoggingProperty.INSTANCE).ordinal()))); targetConfig.compileAdditionalSources.addAll(CCoreFilesUtils.getCTargetSrc()); // Create the main reactor instance if there is a main reactor. @@ -1956,7 +1956,7 @@ protected void setUpGeneralParameters() { } if (platformOptions.platform == Platform.ARDUINO - && !targetConfig.get(new NoCompileProperty()) + && !targetConfig.get(NoCompileProperty.INSTANCE) && platformOptions.board == null) { messageReporter .nowhere() @@ -1965,7 +1965,7 @@ protected void setUpGeneralParameters() { + " board name (FQBN) in the target property. For example, platform: {name:" + " arduino, board: arduino:avr:leonardo}. Entering \"no-compile\" mode and" + " generating target code only."); - new NoCompileProperty().override(targetConfig, true); + NoCompileProperty.INSTANCE.override(targetConfig, true); } if (platformOptions.platform == Platform.ZEPHYR diff --git a/core/src/main/java/org/lflang/generator/c/CMainFunctionGenerator.java b/core/src/main/java/org/lflang/generator/c/CMainFunctionGenerator.java index 65168e078a..0cac08f682 100644 --- a/core/src/main/java/org/lflang/generator/c/CMainFunctionGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CMainFunctionGenerator.java @@ -101,11 +101,11 @@ private String generateSetDefaultCliOption() { /** Parse the target parameters and set flags to the runCommand accordingly. */ private void parseTargetParameters() { - if (targetConfig.get(new FastProperty())) { + if (targetConfig.get(FastProperty.INSTANCE)) { runCommand.add("-f"); runCommand.add("true"); } - if (targetConfig.get(new KeepaliveProperty())) { + if (targetConfig.get(KeepaliveProperty.INSTANCE)) { runCommand.add("-k"); runCommand.add("true"); } 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 187c90e651..14de2ae16d 100644 --- a/core/src/main/java/org/lflang/generator/c/CPreambleGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CPreambleGenerator.java @@ -67,7 +67,7 @@ public static String generateIncludeStatements(TargetConfig targetConfig, boolea } public static String generateDefineDirectives(TargetConfig targetConfig, Path srcGenPath) { - int logLevel = targetConfig.get(new LoggingProperty()).ordinal(); + int logLevel = targetConfig.get(LoggingProperty.INSTANCE).ordinal(); var tracing = targetConfig.get(new TracingProperty()); CodeBuilder code = new CodeBuilder(); // TODO: Get rid of all of these 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 9b52667b58..16130a3152 100644 --- a/core/src/main/java/org/lflang/generator/c/CTriggerObjectsGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CTriggerObjectsGenerator.java @@ -885,7 +885,7 @@ private static String deferredReactionOutputs( // val selfRef = CUtil.reactorRef(reaction.getParent()); var name = reaction.getParent().getFullName(); // Insert a string name to facilitate debugging. - if (targetConfig.get(new LoggingProperty()).compareTo(LogLevel.LOG) >= 0) { + if (targetConfig.get(LoggingProperty.INSTANCE).compareTo(LogLevel.LOG) >= 0) { code.pr( CUtil.reactionRef(reaction) + ".name = " diff --git a/core/src/main/java/org/lflang/generator/python/PythonGenerator.java b/core/src/main/java/org/lflang/generator/python/PythonGenerator.java index 4321b4c4e2..c2b8421bb9 100644 --- a/core/src/main/java/org/lflang/generator/python/PythonGenerator.java +++ b/core/src/main/java/org/lflang/generator/python/PythonGenerator.java @@ -109,7 +109,7 @@ public PythonGenerator(LFGeneratorContext context) { private PythonGenerator( LFGeneratorContext context, PythonTypes types, CCmakeGenerator cmakeGenerator) { super(context, false, types, cmakeGenerator, new PythonDelayBodyGenerator(types)); - new CompilerProperty().override(this.targetConfig, "gcc"); // FIXME: why? + CompilerProperty.INSTANCE.override(this.targetConfig, "gcc"); // FIXME: why? this.targetConfig.reset(CompilerFlagsProperty.INSTANCE); this.types = types; } diff --git a/core/src/main/java/org/lflang/target/TargetConfig.java b/core/src/main/java/org/lflang/target/TargetConfig.java index 5ad61e20e2..32d06ff5fb 100644 --- a/core/src/main/java/org/lflang/target/TargetConfig.java +++ b/core/src/main/java/org/lflang/target/TargetConfig.java @@ -45,17 +45,7 @@ import org.lflang.lf.LfPackage.Literals; import org.lflang.lf.Model; import org.lflang.lf.TargetDecl; -import org.lflang.target.property.CompilerProperty; -import org.lflang.target.property.CoordinationOptionsProperty; -import org.lflang.target.property.CoordinationProperty; -import org.lflang.target.property.DockerProperty; -import org.lflang.target.property.ExportDependencyGraphProperty; -import org.lflang.target.property.ExportToYamlProperty; -import org.lflang.target.property.ExternalRuntimePathProperty; import org.lflang.target.property.FastProperty; -import org.lflang.target.property.FilesProperty; -import org.lflang.target.property.HierarchicalBinProperty; -import org.lflang.target.property.KeepaliveProperty; import org.lflang.target.property.LoggingProperty; import org.lflang.target.property.NoCompileProperty; import org.lflang.target.property.NoRuntimeValidationProperty; @@ -100,19 +90,9 @@ public TargetConfig(Target target) { // Register general-purpose properties this.register( - new CompilerProperty(), - new CoordinationOptionsProperty(), - new CoordinationProperty(), - new DockerProperty(), - new ExportDependencyGraphProperty(), - new ExportToYamlProperty(), - new ExternalRuntimePathProperty(), - new FastProperty(), - new FilesProperty(), - new HierarchicalBinProperty(), - new KeepaliveProperty(), - new LoggingProperty(), - new NoCompileProperty(), + FastProperty.INSTANCE, + LoggingProperty.INSTANCE, + NoCompileProperty.INSTANCE, new NoRuntimeValidationProperty(), new PlatformProperty(), new PrintStatisticsProperty(), diff --git a/core/src/main/java/org/lflang/target/property/BuildTypeProperty.java b/core/src/main/java/org/lflang/target/property/BuildTypeProperty.java index 5ed41eb99d..93e44d2715 100644 --- a/core/src/main/java/org/lflang/target/property/BuildTypeProperty.java +++ b/core/src/main/java/org/lflang/target/property/BuildTypeProperty.java @@ -14,7 +14,7 @@ * Directive to specify the target build type such as 'Release' or 'Debug'. This is also used in the * Rust target to select a Cargo profile. */ -public class BuildTypeProperty extends TargetProperty { +public final class BuildTypeProperty extends TargetProperty { /** Singleton target property instance. */ public static final BuildTypeProperty INSTANCE = new BuildTypeProperty(); @@ -30,7 +30,7 @@ public Element toAstElement(BuildType value) { @Override public BuildType initialValue() { - return BuildTypeType.BuildType.RELEASE; + return BuildType.DEBUG; } @Override 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 a719d7dbd0..16c4fac5ce 100644 --- a/core/src/main/java/org/lflang/target/property/CargoDependenciesProperty.java +++ b/core/src/main/java/org/lflang/target/property/CargoDependenciesProperty.java @@ -39,7 +39,7 @@ * } * } */ -public class CargoDependenciesProperty +public final class CargoDependenciesProperty extends TargetProperty, CargoDependenciesPropertyType> { /** Singleton target property instance. */ diff --git a/core/src/main/java/org/lflang/target/property/CargoFeaturesProperty.java b/core/src/main/java/org/lflang/target/property/CargoFeaturesProperty.java index 0d17ef360d..02308b9bc4 100644 --- a/core/src/main/java/org/lflang/target/property/CargoFeaturesProperty.java +++ b/core/src/main/java/org/lflang/target/property/CargoFeaturesProperty.java @@ -5,7 +5,7 @@ import org.lflang.Target; /** Directive for specifying Cargo features of the generated program to enable. */ -public class CargoFeaturesProperty extends StringListProperty { +public final class CargoFeaturesProperty extends StringListProperty { /** Singleton target property instance. */ public static final CargoFeaturesProperty INSTANCE = new CargoFeaturesProperty(); 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 89562e10cb..70195d9de6 100644 --- a/core/src/main/java/org/lflang/target/property/ClockSyncModeProperty.java +++ b/core/src/main/java/org/lflang/target/property/ClockSyncModeProperty.java @@ -15,7 +15,7 @@ import org.lflang.target.property.type.ClockSyncModeType.ClockSyncMode; /** The mode of clock synchronization to be used in federated programs. The default is 'initial'. */ -public class ClockSyncModeProperty extends TargetProperty { +public final class ClockSyncModeProperty extends TargetProperty { /** Singleton target property instance. */ public static final ClockSyncModeProperty INSTANCE = new ClockSyncModeProperty(); 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 4d65c58ccb..b962f45d8e 100644 --- a/core/src/main/java/org/lflang/target/property/ClockSyncOptionsProperty.java +++ b/core/src/main/java/org/lflang/target/property/ClockSyncOptionsProperty.java @@ -19,7 +19,8 @@ import org.lflang.target.property.type.TargetPropertyType; /** Key-value pairs giving options for clock synchronization. */ -public class ClockSyncOptionsProperty extends TargetProperty { +public final class ClockSyncOptionsProperty + extends TargetProperty { /** Singleton target property instance. */ public static final ClockSyncOptionsProperty INSTANCE = new ClockSyncOptionsProperty(); diff --git a/core/src/main/java/org/lflang/target/property/CmakeIncludeProperty.java b/core/src/main/java/org/lflang/target/property/CmakeIncludeProperty.java index b7006b7f37..a8e4cc0527 100644 --- a/core/src/main/java/org/lflang/target/property/CmakeIncludeProperty.java +++ b/core/src/main/java/org/lflang/target/property/CmakeIncludeProperty.java @@ -13,7 +13,7 @@ *

This gives full control over the C/C++ build as any cmake parameters can be adjusted in the * included file. */ -public class CmakeIncludeProperty extends FileListProperty { +public final class CmakeIncludeProperty extends FileListProperty { /** Singleton target property instance. */ public static final CmakeIncludeProperty INSTANCE = new CmakeIncludeProperty(); diff --git a/core/src/main/java/org/lflang/target/property/CompileDefinitionsProperty.java b/core/src/main/java/org/lflang/target/property/CompileDefinitionsProperty.java index 831f25682c..2bab9c7722 100644 --- a/core/src/main/java/org/lflang/target/property/CompileDefinitionsProperty.java +++ b/core/src/main/java/org/lflang/target/property/CompileDefinitionsProperty.java @@ -18,7 +18,7 @@ *

The first string is the definition itself, and the second string is the value to attribute to * that definition, if any. The second value could be left empty. */ -public class CompileDefinitionsProperty +public final class CompileDefinitionsProperty extends TargetProperty, StringDictionaryType> { /** Singleton target property instance. */ diff --git a/core/src/main/java/org/lflang/target/property/CompilerFlagsProperty.java b/core/src/main/java/org/lflang/target/property/CompilerFlagsProperty.java index e5d061a436..b5f4e24a28 100644 --- a/core/src/main/java/org/lflang/target/property/CompilerFlagsProperty.java +++ b/core/src/main/java/org/lflang/target/property/CompilerFlagsProperty.java @@ -5,7 +5,7 @@ import org.lflang.Target; /** Flags to pass to the compiler, unless a build command has been specified. */ -public class CompilerFlagsProperty extends StringListProperty { +public final class CompilerFlagsProperty extends StringListProperty { /** Singleton target property instance. */ public static final CompilerFlagsProperty INSTANCE = new CompilerFlagsProperty(); diff --git a/core/src/main/java/org/lflang/target/property/CompilerProperty.java b/core/src/main/java/org/lflang/target/property/CompilerProperty.java index daa9b50b28..5701155fb0 100644 --- a/core/src/main/java/org/lflang/target/property/CompilerProperty.java +++ b/core/src/main/java/org/lflang/target/property/CompilerProperty.java @@ -4,7 +4,14 @@ import org.lflang.Target; /** The compiler to invoke, unless a build command has been specified. */ -public class CompilerProperty extends StringProperty { +public final class CompilerProperty extends StringProperty { + + /** Singleton target property instance. */ + public static final CompilerProperty INSTANCE = new CompilerProperty(); + + private CompilerProperty() { + super(); + } @Override public List supportedTargets() { 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 e82b43ffc6..129c710b37 100644 --- a/core/src/main/java/org/lflang/target/property/CoordinationOptionsProperty.java +++ b/core/src/main/java/org/lflang/target/property/CoordinationOptionsProperty.java @@ -19,10 +19,13 @@ import org.lflang.target.property.type.TargetPropertyType; /** Key-value pairs giving options for clock synchronization. */ -public class CoordinationOptionsProperty +public final class CoordinationOptionsProperty extends TargetProperty { - public CoordinationOptionsProperty() { + /** Singleton target property instance. */ + public static final CoordinationOptionsProperty INSTANCE = new CoordinationOptionsProperty(); + + private CoordinationOptionsProperty() { super(DictionaryType.COORDINATION_OPTION_DICT); } diff --git a/core/src/main/java/org/lflang/target/property/CoordinationProperty.java b/core/src/main/java/org/lflang/target/property/CoordinationProperty.java index 83068bbe19..abe044e943 100644 --- a/core/src/main/java/org/lflang/target/property/CoordinationProperty.java +++ b/core/src/main/java/org/lflang/target/property/CoordinationProperty.java @@ -14,9 +14,13 @@ * The type of coordination used during the execution of a federated program. The default is * 'centralized'. */ -public class CoordinationProperty extends TargetProperty { +public final class CoordinationProperty + extends TargetProperty { - public CoordinationProperty() { + /** Singleton target property instance. */ + public static final CoordinationProperty INSTANCE = new CoordinationProperty(); + + private CoordinationProperty() { super(new CoordinationModeType()); } 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 e3b0e0bbd4..2132c6cd78 100644 --- a/core/src/main/java/org/lflang/target/property/DockerProperty.java +++ b/core/src/main/java/org/lflang/target/property/DockerProperty.java @@ -22,9 +22,12 @@ * Directive to generate a Dockerfile. This is either a boolean, true or false, or a dictionary of * options. */ -public class DockerProperty extends TargetProperty { +public final class DockerProperty extends TargetProperty { - public DockerProperty() { + /** Singleton target property instance. */ + public static final DockerProperty INSTANCE = new DockerProperty(); + + private DockerProperty() { super(UnionType.DOCKER_UNION); } diff --git a/core/src/main/java/org/lflang/target/property/ExportDependencyGraphProperty.java b/core/src/main/java/org/lflang/target/property/ExportDependencyGraphProperty.java index 87628d2a9c..e06295cbb9 100644 --- a/core/src/main/java/org/lflang/target/property/ExportDependencyGraphProperty.java +++ b/core/src/main/java/org/lflang/target/property/ExportDependencyGraphProperty.java @@ -9,7 +9,14 @@ *

This option is currently only used for C++ and Rust. This export function is a valuable tool * for debugging LF programs and helps to understand the dependencies inferred by the runtime. */ -public class ExportDependencyGraphProperty extends BooleanProperty { +public final class ExportDependencyGraphProperty extends BooleanProperty { + + /** Singleton target property instance. */ + public static final ExportDependencyGraphProperty INSTANCE = new ExportDependencyGraphProperty(); + + private ExportDependencyGraphProperty() { + super(); + } @Override public List supportedTargets() { diff --git a/core/src/main/java/org/lflang/target/property/ExportToYamlProperty.java b/core/src/main/java/org/lflang/target/property/ExportToYamlProperty.java index bd6d975ed7..5abe77895d 100644 --- a/core/src/main/java/org/lflang/target/property/ExportToYamlProperty.java +++ b/core/src/main/java/org/lflang/target/property/ExportToYamlProperty.java @@ -10,7 +10,14 @@ *

This option is currently only used for C++. This export function is a valuable tool for * debugging LF programs and performing external analysis. */ -public class ExportToYamlProperty extends BooleanProperty { +public final class ExportToYamlProperty extends BooleanProperty { + + /** Singleton target property instance. */ + public static final ExportToYamlProperty INSTANCE = new ExportToYamlProperty(); + + private ExportToYamlProperty() { + super(); + } @Override public List supportedTargets() { diff --git a/core/src/main/java/org/lflang/target/property/ExternalRuntimePathProperty.java b/core/src/main/java/org/lflang/target/property/ExternalRuntimePathProperty.java index 36bace7002..ff6ae354c5 100644 --- a/core/src/main/java/org/lflang/target/property/ExternalRuntimePathProperty.java +++ b/core/src/main/java/org/lflang/target/property/ExternalRuntimePathProperty.java @@ -7,7 +7,14 @@ * Directive for specifying a path to an external runtime libray to link to instead of the default * one. */ -public class ExternalRuntimePathProperty extends StringProperty { +public final class ExternalRuntimePathProperty extends StringProperty { + + /** Singleton target property instance. */ + public static final ExternalRuntimePathProperty INSTANCE = new ExternalRuntimePathProperty(); + + private ExternalRuntimePathProperty() { + super(); + } @Override public List supportedTargets() { 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 c4106f525e..fee019c94e 100644 --- a/core/src/main/java/org/lflang/target/property/FastProperty.java +++ b/core/src/main/java/org/lflang/target/property/FastProperty.java @@ -15,7 +15,14 @@ * If true, configure the execution environment such that it does not wait for physical time to * match logical time. The default is false. */ -public class FastProperty extends BooleanProperty { +public final class FastProperty extends BooleanProperty { + + /** Singleton target property instance. */ + public static final FastProperty INSTANCE = new FastProperty(); + + private FastProperty() { + super(); + } @Override public List supportedTargets() { diff --git a/core/src/main/java/org/lflang/target/property/FilesProperty.java b/core/src/main/java/org/lflang/target/property/FilesProperty.java index cb56324958..c3dff093fc 100644 --- a/core/src/main/java/org/lflang/target/property/FilesProperty.java +++ b/core/src/main/java/org/lflang/target/property/FilesProperty.java @@ -4,7 +4,14 @@ import org.lflang.Target; /** Directive to stage particular files on the class path to be processed by the code generator. */ -public class FilesProperty extends FileListProperty { +public final class FilesProperty extends FileListProperty { + + /** Singleton target property instance. */ + public static final FilesProperty INSTANCE = new FilesProperty(); + + private FilesProperty() { + super(); + } @Override public List supportedTargets() { diff --git a/core/src/main/java/org/lflang/target/property/HierarchicalBinProperty.java b/core/src/main/java/org/lflang/target/property/HierarchicalBinProperty.java index 5fc3a856e8..5fa11e7f37 100644 --- a/core/src/main/java/org/lflang/target/property/HierarchicalBinProperty.java +++ b/core/src/main/java/org/lflang/target/property/HierarchicalBinProperty.java @@ -7,7 +7,14 @@ /** * Whether the bin directory should have a flat or hierarchical organization. It is flat by default. */ -public class HierarchicalBinProperty extends BooleanProperty { +public final class HierarchicalBinProperty extends BooleanProperty { + + /** Singleton target property instance. */ + public static final HierarchicalBinProperty INSTANCE = new HierarchicalBinProperty(); + + private HierarchicalBinProperty() { + super(); + } @Override public List supportedTargets() { diff --git a/core/src/main/java/org/lflang/target/property/KeepaliveProperty.java b/core/src/main/java/org/lflang/target/property/KeepaliveProperty.java index 76a1515632..8b639179c8 100644 --- a/core/src/main/java/org/lflang/target/property/KeepaliveProperty.java +++ b/core/src/main/java/org/lflang/target/property/KeepaliveProperty.java @@ -7,7 +7,14 @@ * If true, configure the execution environment to keep executing if there are no more events on the * event queue. The default is false. */ -public class KeepaliveProperty extends BooleanProperty { +public final class KeepaliveProperty extends BooleanProperty { + + /** Singleton target property instance. */ + public static final KeepaliveProperty INSTANCE = new KeepaliveProperty(); + + private KeepaliveProperty() { + super(); + } @Override public List supportedTargets() { diff --git a/core/src/main/java/org/lflang/target/property/LoggingProperty.java b/core/src/main/java/org/lflang/target/property/LoggingProperty.java index 080697ffee..051b17c5de 100644 --- a/core/src/main/java/org/lflang/target/property/LoggingProperty.java +++ b/core/src/main/java/org/lflang/target/property/LoggingProperty.java @@ -13,9 +13,12 @@ * Directive to specify the grain at which to report log messages during execution. The default is * INFO. */ -public class LoggingProperty extends TargetProperty { +public final class LoggingProperty extends TargetProperty { - public LoggingProperty() { + /** Singleton target property instance. */ + public static final LoggingProperty INSTANCE = new LoggingProperty(); + + private LoggingProperty() { super(new LoggingType()); } diff --git a/core/src/main/java/org/lflang/target/property/NoCompileProperty.java b/core/src/main/java/org/lflang/target/property/NoCompileProperty.java index b0b7513c21..6e06552c8f 100644 --- a/core/src/main/java/org/lflang/target/property/NoCompileProperty.java +++ b/core/src/main/java/org/lflang/target/property/NoCompileProperty.java @@ -5,7 +5,14 @@ import org.lflang.Target; /** If true, do not invoke the target compiler or build command. The default is false. */ -public class NoCompileProperty extends BooleanProperty { +public final class NoCompileProperty extends BooleanProperty { + + /** Singleton target property instance. */ + public static final NoCompileProperty INSTANCE = new NoCompileProperty(); + + private NoCompileProperty() { + super(); + } @Override public List supportedTargets() { diff --git a/core/src/main/java/org/lflang/target/property/RustIncludeProperty.java b/core/src/main/java/org/lflang/target/property/RustIncludeProperty.java index 62dcb6a49d..a5ba132010 100644 --- a/core/src/main/java/org/lflang/target/property/RustIncludeProperty.java +++ b/core/src/main/java/org/lflang/target/property/RustIncludeProperty.java @@ -22,9 +22,12 @@ * the generated {@code main.rs} will include it with a {@code mod foo;}. If one of the paths is a * directory, it must contain a {@code mod.rs} file, and all its contents are copied. */ -public class RustIncludeProperty extends TargetProperty, UnionType> { +public final class RustIncludeProperty extends TargetProperty, UnionType> { - public RustIncludeProperty() { + /** Singleton target property instance. */ + public static final RustIncludeProperty INSTANCE = new RustIncludeProperty(); + + private RustIncludeProperty() { super(UnionType.FILE_OR_FILE_ARRAY); } diff --git a/core/src/main/kotlin/org/lflang/generator/cpp/CppGenerator.kt b/core/src/main/kotlin/org/lflang/generator/cpp/CppGenerator.kt index ce338a8f40..119fa5e449 100644 --- a/core/src/main/kotlin/org/lflang/generator/cpp/CppGenerator.kt +++ b/core/src/main/kotlin/org/lflang/generator/cpp/CppGenerator.kt @@ -75,7 +75,7 @@ class CppGenerator( // generate platform specific files platformGenerator.generatePlatformFiles() - if (targetConfig.get(NoCompileProperty()) || errorsOccurred()) { + if (targetConfig.get(NoCompileProperty.INSTANCE) || errorsOccurred()) { println("Exiting before invoking target compiler.") context.finish(GeneratorResult.GENERATED_NO_EXECUTABLE.apply(context, codeMaps)) } else if (context.mode == Mode.LSP_MEDIUM) { @@ -129,7 +129,7 @@ class CppGenerator( true) // copy or download reactor-cpp - if (!targetConfig.isSet(ExternalRuntimePathProperty())) { + if (!targetConfig.isSet(ExternalRuntimePathProperty.INSTANCE)) { if (targetConfig.isSet(RuntimeVersionProperty())) { fetchReactorCpp(targetConfig.get(RuntimeVersionProperty())) } else { diff --git a/core/src/main/kotlin/org/lflang/generator/cpp/CppPlatformGenerator.kt b/core/src/main/kotlin/org/lflang/generator/cpp/CppPlatformGenerator.kt index 92278526a6..735d94a130 100644 --- a/core/src/main/kotlin/org/lflang/generator/cpp/CppPlatformGenerator.kt +++ b/core/src/main/kotlin/org/lflang/generator/cpp/CppPlatformGenerator.kt @@ -34,7 +34,7 @@ abstract class CppPlatformGenerator(protected val generator: CppGenerator) { "-DREACTOR_CPP_VALIDATE=${if (targetConfig.get(NoRuntimeValidationProperty())) "OFF" else "ON"}", "-DREACTOR_CPP_PRINT_STATISTICS=${if (targetConfig.get(PrintStatisticsProperty())) "ON" else "OFF"}", "-DREACTOR_CPP_TRACE=${if (targetConfig.get(TracingProperty()).isEnabled) "ON" else "OFF"}", - "-DREACTOR_CPP_LOG_LEVEL=${targetConfig.get(LoggingProperty()).severity}", + "-DREACTOR_CPP_LOG_LEVEL=${targetConfig.get(LoggingProperty.INSTANCE).severity}", "-DLF_SRC_PKG_PATH=${fileConfig.srcPkgPath}", ) } diff --git a/core/src/main/kotlin/org/lflang/generator/cpp/CppRos2NodeGenerator.kt b/core/src/main/kotlin/org/lflang/generator/cpp/CppRos2NodeGenerator.kt index f3078bc5b3..e9f042d93d 100644 --- a/core/src/main/kotlin/org/lflang/generator/cpp/CppRos2NodeGenerator.kt +++ b/core/src/main/kotlin/org/lflang/generator/cpp/CppRos2NodeGenerator.kt @@ -61,7 +61,7 @@ class CppRos2NodeGenerator( |$nodeName::$nodeName(const rclcpp::NodeOptions& node_options) | : Node("$nodeName", node_options) { | unsigned workers = ${if (targetConfig.get(WorkersProperty()) != 0) targetConfig.get(WorkersProperty()) else "std::thread::hardware_concurrency()"}; - | bool fast{${targetConfig.get(FastProperty())}}; + | bool fast{${targetConfig.get(FastProperty.INSTANCE)}}; | reactor::Duration lf_timeout{${if (targetConfig.isSet(TimeOutProperty())) targetConfig.get(TimeOutProperty()).toCppCode() else "reactor::Duration::max()"}}; | | // provide a globally accessible reference to this node diff --git a/core/src/main/kotlin/org/lflang/generator/cpp/CppStandaloneCmakeGenerator.kt b/core/src/main/kotlin/org/lflang/generator/cpp/CppStandaloneCmakeGenerator.kt index 3048ccd5a0..c767aa892b 100644 --- a/core/src/main/kotlin/org/lflang/generator/cpp/CppStandaloneCmakeGenerator.kt +++ b/core/src/main/kotlin/org/lflang/generator/cpp/CppStandaloneCmakeGenerator.kt @@ -140,7 +140,7 @@ class CppStandaloneCmakeGenerator(private val targetConfig: TargetConfig, privat val includeFiles = targetConfig.get(CmakeIncludeProperty.INSTANCE)?.map { fileConfig.srcPath.resolve(it).toUnixString() } val reactorCppTarget = when { - targetConfig.isSet(ExternalRuntimePathProperty()) -> "reactor-cpp" + targetConfig.isSet(ExternalRuntimePathProperty.INSTANCE) -> "reactor-cpp" targetConfig.isSet(RuntimeVersionProperty()) -> "reactor-cpp-${targetConfig.get(RuntimeVersionProperty())}" else -> "reactor-cpp-default" } @@ -150,7 +150,7 @@ class CppStandaloneCmakeGenerator(private val targetConfig: TargetConfig, privat |cmake_minimum_required(VERSION 3.5) |project(${fileConfig.name} VERSION 0.0.0 LANGUAGES CXX) | - |${if (targetConfig.get(ExternalRuntimePathProperty()) != null) "find_package(reactor-cpp PATHS ${targetConfig.get(ExternalRuntimePathProperty())})" else ""} + |${if (targetConfig.get(ExternalRuntimePathProperty.INSTANCE) != null) "find_package(reactor-cpp PATHS ${targetConfig.get(ExternalRuntimePathProperty.INSTANCE)})" else ""} | |set(LF_MAIN_TARGET ${fileConfig.name}) | diff --git a/core/src/main/kotlin/org/lflang/generator/cpp/CppStandaloneGenerator.kt b/core/src/main/kotlin/org/lflang/generator/cpp/CppStandaloneGenerator.kt index a4f689dc97..dd03db376d 100644 --- a/core/src/main/kotlin/org/lflang/generator/cpp/CppStandaloneGenerator.kt +++ b/core/src/main/kotlin/org/lflang/generator/cpp/CppStandaloneGenerator.kt @@ -172,8 +172,8 @@ class CppStandaloneGenerator(generator: CppGenerator) : ) // prepare cmake - if (targetConfig.get(CompilerProperty()) != null) { - cmd.setEnvironmentVariable("CXX", targetConfig.get(CompilerProperty())) + if (targetConfig.isSet(CompilerProperty.INSTANCE)) { + cmd.setEnvironmentVariable("CXX", targetConfig.get(CompilerProperty.INSTANCE)) } return cmd } diff --git a/core/src/main/kotlin/org/lflang/generator/cpp/CppStandaloneMainGenerator.kt b/core/src/main/kotlin/org/lflang/generator/cpp/CppStandaloneMainGenerator.kt index c288222e25..e0ee61a755 100644 --- a/core/src/main/kotlin/org/lflang/generator/cpp/CppStandaloneMainGenerator.kt +++ b/core/src/main/kotlin/org/lflang/generator/cpp/CppStandaloneMainGenerator.kt @@ -64,7 +64,7 @@ class CppStandaloneMainGenerator( | cxxopts::Options options("${fileConfig.name}", "Reactor Program"); | | unsigned workers = ${if (targetConfig.get(WorkersProperty()) != 0) targetConfig.get(WorkersProperty()) else "std::thread::hardware_concurrency()"}; - | bool fast{${targetConfig.get(FastProperty())}}; + | bool fast{${targetConfig.get(FastProperty.INSTANCE)}}; | reactor::Duration timeout = ${if (targetConfig.isSet(TimeOutProperty())) targetConfig.get(TimeOutProperty()).toCppCode() else "reactor::Duration::max()"}; | | // the timeout variable needs to be tested beyond fitting the Duration-type @@ -73,7 +73,7 @@ class CppStandaloneMainGenerator( | .add_options() | ("w,workers", "the number of worker threads used by the scheduler", cxxopts::value(workers)->default_value(std::to_string(workers)), "'unsigned'") | ("o,timeout", "Time after which the execution is aborted.", cxxopts::value(timeout)->default_value(time_to_string(timeout)), "'FLOAT UNIT'") - | ("f,fast", "Allow logical time to run faster than physical time.", cxxopts::value(fast)->default_value("${targetConfig.get(FastProperty())}")) + | ("f,fast", "Allow logical time to run faster than physical time.", cxxopts::value(fast)->default_value("${targetConfig.get(FastProperty.INSTANCE)}")) | ("help", "Print help"); | ${" |"..main.parameters.joinToString("\n\n") { generateParameterParser(it) }} @@ -101,8 +101,8 @@ class CppStandaloneMainGenerator( | | // assemble reactor program | e.assemble(); - ${" |".. if (targetConfig.get(ExportDependencyGraphProperty())) "e.export_dependency_graph(\"${main.name}.dot\");" else ""} - ${" |".. if (targetConfig.get(ExportToYamlProperty())) "e.dump_to_yaml(\"${main.name}.yaml\");" else ""} + ${" |".. if (targetConfig.get(ExportDependencyGraphProperty.INSTANCE)) "e.export_dependency_graph(\"${main.name}.dot\");" else ""} + ${" |".. if (targetConfig.get(ExportToYamlProperty.INSTANCE)) "e.dump_to_yaml(\"${main.name}.yaml\");" else ""} | | // start execution | auto thread = e.startup(); diff --git a/core/src/main/kotlin/org/lflang/generator/rust/RustGenerator.kt b/core/src/main/kotlin/org/lflang/generator/rust/RustGenerator.kt index c664c5308f..a3ae57ba21 100644 --- a/core/src/main/kotlin/org/lflang/generator/rust/RustGenerator.kt +++ b/core/src/main/kotlin/org/lflang/generator/rust/RustGenerator.kt @@ -73,7 +73,7 @@ class RustGenerator( val gen = RustModelBuilder.makeGenerationInfo(targetConfig, reactors, messageReporter) val codeMaps: Map = RustEmitter.generateRustProject(fileConfig, gen) - if (targetConfig.get(NoCompileProperty()) || errorsOccurred()) { + if (targetConfig.get(NoCompileProperty.INSTANCE) || errorsOccurred()) { context.finish(GeneratorResult.GENERATED_NO_EXECUTABLE.apply(context, codeMaps)) println("Exiting before invoking target compiler.") } else { 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 d65b816d2f..7b3e6637a3 100644 --- a/core/src/main/kotlin/org/lflang/generator/rust/RustModel.kt +++ b/core/src/main/kotlin/org/lflang/generator/rust/RustModel.kt @@ -451,7 +451,7 @@ object RustModelBuilder { version = "1.0.0", authors = listOf(System.getProperty("user.name")), dependencies = dependencies, - modulesToIncludeInMain = targetConfig.get(RustIncludeProperty()), + modulesToIncludeInMain = targetConfig.get(RustIncludeProperty.INSTANCE), enabledCargoFeatures = targetConfig.get(CargoFeaturesProperty.INSTANCE).toSet() ), reactors = reactorsInfos, @@ -496,8 +496,8 @@ object RustModelBuilder { features = parallelFeature, ) - if (targetConfig.isSet(ExternalRuntimePathProperty())) { - spec.localPath = targetConfig.get(ExternalRuntimePathProperty()) + if (targetConfig.isSet(ExternalRuntimePathProperty.INSTANCE)) { + spec.localPath = targetConfig.get(ExternalRuntimePathProperty.INSTANCE) } else if (targetConfig.isSet(RuntimeVersionProperty())) { spec.gitRepo = RustEmitterBase.runtimeGitUrl spec.rev = targetConfig.get(RuntimeVersionProperty()) @@ -507,8 +507,8 @@ object RustModelBuilder { return spec } else { - if (targetConfig.isSet(ExternalRuntimePathProperty())) { - userSpec.localPath = targetConfig.get(ExternalRuntimePathProperty()) + if (targetConfig.isSet(ExternalRuntimePathProperty.INSTANCE)) { + userSpec.localPath = targetConfig.get(ExternalRuntimePathProperty.INSTANCE) } if (userSpec.localPath == null && userSpec.gitRepo == null) { @@ -530,12 +530,12 @@ object RustModelBuilder { private fun TargetConfig.toRustProperties(): RustTargetProperties = RustTargetProperties( - keepAlive = this.get(KeepaliveProperty()), + keepAlive = this.get(KeepaliveProperty.INSTANCE), timeout = this.get(TimeOutProperty())?.toRustTimeExpr(), timeoutLf = this.get(TimeOutProperty()), singleFile = this.get(SingleFileProjectProperty()), workers = this.get(WorkersProperty()), - dumpDependencyGraph = this.get(ExportDependencyGraphProperty()), + dumpDependencyGraph = this.get(ExportDependencyGraphProperty.INSTANCE), ) private fun makeReactorInfos(reactors: List): List = diff --git a/core/src/main/kotlin/org/lflang/generator/ts/TSGenerator.kt b/core/src/main/kotlin/org/lflang/generator/ts/TSGenerator.kt index 7aafa6ad5a..759aa559cd 100644 --- a/core/src/main/kotlin/org/lflang/generator/ts/TSGenerator.kt +++ b/core/src/main/kotlin/org/lflang/generator/ts/TSGenerator.kt @@ -38,6 +38,7 @@ import org.lflang.scoping.LFGlobalScopeProvider import org.lflang.target.property.DockerProperty import org.lflang.target.property.NoCompileProperty import org.lflang.target.property.ProtobufsProperty +import org.lflang.target.property.type.PrimitiveType import org.lflang.util.FileUtil import java.nio.file.Files import java.nio.file.Path @@ -120,7 +121,7 @@ class TSGenerator( val codeMaps = HashMap() generateCode(codeMaps, resource.model.preambles) - if (targetConfig.get(DockerProperty()).enabled) { + if (targetConfig.get(DockerProperty.INSTANCE).enabled) { val dockerData = TSDockerGenerator(context).generateDockerData(); dockerData.writeDockerFile() DockerComposeGenerator(context).writeDockerComposeFile(listOf(dockerData)) @@ -128,7 +129,7 @@ class TSGenerator( // For small programs, everything up until this point is virtually instantaneous. This is the point where cancellation, // progress reporting, and IDE responsiveness become real considerations. - if (context.mode != LFGeneratorContext.Mode.LSP_MEDIUM && targetConfig.get(NoCompileProperty())) { + if (context.mode != LFGeneratorContext.Mode.LSP_MEDIUM && targetConfig.get(NoCompileProperty.INSTANCE)) { context.finish(GeneratorResult.GENERATED_NO_EXECUTABLE.apply(context, null)) } else { context.reportProgress( @@ -147,7 +148,7 @@ class TSGenerator( val parsingContext = SubContext(context, COLLECTED_DEPENDENCIES_PERCENT_PROGRESS, 100) val validator = TSValidator(fileConfig, messageReporter, codeMaps) if (!context.cancelIndicator.isCanceled) { - if (context.mode == LFGeneratorContext.Mode.LSP_MEDIUM) { + if (context.mode == LFGeneratorContext.Mode.LSP_MEDIUM || targetConfig.get(NoCompileProperty.INSTANCE)) { if (!passesChecks(validator, parsingContext)) { context.unsuccessfulFinish(); return; @@ -278,7 +279,9 @@ class TSGenerator( * Return whether it is advisable to install dependencies. */ private fun shouldCollectDependencies(context: LFGeneratorContext): Boolean = - context.mode != LFGeneratorContext.Mode.LSP_MEDIUM || !fileConfig.srcGenPkgPath.resolve("node_modules").toFile().exists() + (context.mode != LFGeneratorContext.Mode.LSP_MEDIUM + && !targetConfig.get(NoCompileProperty.INSTANCE)) + || !fileConfig.srcGenPkgPath.resolve("node_modules").toFile().exists() /** * Collect the dependencies in package.json and their diff --git a/core/src/main/kotlin/org/lflang/generator/ts/TSParameterPreambleGenerator.kt b/core/src/main/kotlin/org/lflang/generator/ts/TSParameterPreambleGenerator.kt index e4e59ffc40..bbb6611805 100644 --- a/core/src/main/kotlin/org/lflang/generator/ts/TSParameterPreambleGenerator.kt +++ b/core/src/main/kotlin/org/lflang/generator/ts/TSParameterPreambleGenerator.kt @@ -166,8 +166,8 @@ class TSParameterPreambleGenerator( val codeText = """ |// ************* App Parameters |let __timeout: TimeValue | undefined = ${getTimeoutTimeValue()}; - |let __keepAlive: boolean = ${targetConfig.get(KeepaliveProperty())}; - |let __fast: boolean = ${targetConfig.get(FastProperty())}; + |let __keepAlive: boolean = ${targetConfig.get(KeepaliveProperty.INSTANCE)}; + |let __fast: boolean = ${targetConfig.get(FastProperty.INSTANCE)}; |let __federationID: string = 'Unidentified Federation' | |let __noStart = false; // If set to true, don't start the app. @@ -239,7 +239,7 @@ class TSParameterPreambleGenerator( | throw new Error("'logging' command line argument is malformed."); | } |} else { - | Log.global.level = Log.levels.${targetConfig.get(LoggingProperty()).name}; // Default from target property. + | Log.global.level = Log.levels.${targetConfig.get(LoggingProperty.INSTANCE).name}; // Default from target property. |} | |// Help parameter (not a constructor parameter, but a command line option) diff --git a/core/src/testFixtures/java/org/lflang/tests/Configurators.java b/core/src/testFixtures/java/org/lflang/tests/Configurators.java index 397904fc9d..65fb9b9975 100644 --- a/core/src/testFixtures/java/org/lflang/tests/Configurators.java +++ b/core/src/testFixtures/java/org/lflang/tests/Configurators.java @@ -75,7 +75,7 @@ public static boolean makeZephyrCompatibleUnthreaded(LFTest test) { test.getContext().getTargetConfig().get(new PlatformProperty()).board = "qemu_cortex_m3"; // FIXME: Zephyr emulations fails with debug log-levels. - new LoggingProperty().override(test.getContext().getTargetConfig(), LogLevel.WARN); + LoggingProperty.INSTANCE.override(test.getContext().getTargetConfig(), LogLevel.WARN); test.getContext().getArgs().setProperty("logging", "warning"); return true; } @@ -87,7 +87,7 @@ public static boolean makeZephyrCompatible(LFTest test) { test.getContext().getTargetConfig().get(new PlatformProperty()).board = "qemu_cortex_m3"; // FIXME: Zephyr emulations fails with debug log-levels. - new LoggingProperty().override(test.getContext().getTargetConfig(), LogLevel.WARN); + LoggingProperty.INSTANCE.override(test.getContext().getTargetConfig(), LogLevel.WARN); test.getContext().getArgs().setProperty("logging", "warning"); return true; diff --git a/core/src/testFixtures/java/org/lflang/tests/TestBase.java b/core/src/testFixtures/java/org/lflang/tests/TestBase.java index 2e125ffaa2..d9d36b2ea7 100644 --- a/core/src/testFixtures/java/org/lflang/tests/TestBase.java +++ b/core/src/testFixtures/java/org/lflang/tests/TestBase.java @@ -439,7 +439,7 @@ private void validate(LFTest test) throws TestError { /** Override to add some LFC arguments to all runs of this test class. */ protected void addExtraLfcArgs(Properties args, TargetConfig targetConfig) { args.setProperty("build-type", "Test"); - if (!targetConfig.isSet(new LoggingProperty())) args.setProperty("logging", "Debug"); + if (!targetConfig.isSet(LoggingProperty.INSTANCE)) args.setProperty("logging", "Debug"); } /** From f3115342cca8a6dc242ccfaf768474e9fb8dfc14 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Mon, 16 Oct 2023 18:10:50 -0700 Subject: [PATCH 094/145] Fix build problem --- core/src/main/java/org/lflang/Target.java | 4 +++- core/src/main/java/org/lflang/target/TargetConfig.java | 2 -- .../org/lflang/target/property/BuildTypeProperty.java | 2 +- .../target/property/NoRuntimeValidationProperty.java | 9 ++++++++- .../org/lflang/generator/cpp/CppPlatformGenerator.kt | 2 +- .../org/lflang/generator/ts/TSConstructorGenerator.kt | 2 +- 6 files changed, 14 insertions(+), 7 deletions(-) diff --git a/core/src/main/java/org/lflang/Target.java b/core/src/main/java/org/lflang/Target.java index edfd0bda2d..3dcaa4c804 100644 --- a/core/src/main/java/org/lflang/Target.java +++ b/core/src/main/java/org/lflang/Target.java @@ -47,6 +47,7 @@ import org.lflang.target.property.FilesProperty; import org.lflang.target.property.HierarchicalBinProperty; import org.lflang.target.property.KeepaliveProperty; +import org.lflang.target.property.NoRuntimeValidationProperty; import org.lflang.target.property.RustIncludeProperty; /** @@ -586,7 +587,8 @@ public void initialize(TargetConfig config) { DockerProperty.INSTANCE, FilesProperty.INSTANCE, HierarchicalBinProperty.INSTANCE, - KeepaliveProperty.INSTANCE); + KeepaliveProperty.INSTANCE, + NoRuntimeValidationProperty.INSTANCE); case CPP -> config.register( BuildTypeProperty.INSTANCE, CmakeIncludeProperty.INSTANCE, diff --git a/core/src/main/java/org/lflang/target/TargetConfig.java b/core/src/main/java/org/lflang/target/TargetConfig.java index 32d06ff5fb..efbf3eb6a4 100644 --- a/core/src/main/java/org/lflang/target/TargetConfig.java +++ b/core/src/main/java/org/lflang/target/TargetConfig.java @@ -48,7 +48,6 @@ import org.lflang.target.property.FastProperty; import org.lflang.target.property.LoggingProperty; import org.lflang.target.property.NoCompileProperty; -import org.lflang.target.property.NoRuntimeValidationProperty; import org.lflang.target.property.PlatformProperty; import org.lflang.target.property.PrintStatisticsProperty; import org.lflang.target.property.ProtobufsProperty; @@ -93,7 +92,6 @@ public TargetConfig(Target target) { FastProperty.INSTANCE, LoggingProperty.INSTANCE, NoCompileProperty.INSTANCE, - new NoRuntimeValidationProperty(), new PlatformProperty(), new PrintStatisticsProperty(), new ProtobufsProperty(), diff --git a/core/src/main/java/org/lflang/target/property/BuildTypeProperty.java b/core/src/main/java/org/lflang/target/property/BuildTypeProperty.java index 93e44d2715..94559a490a 100644 --- a/core/src/main/java/org/lflang/target/property/BuildTypeProperty.java +++ b/core/src/main/java/org/lflang/target/property/BuildTypeProperty.java @@ -40,7 +40,7 @@ public BuildType fromAst(Element node, MessageReporter reporter) { @Override protected BuildType fromString(String string, MessageReporter reporter) { - return ((BuildTypeType) this.type).forName(string); + return this.type.forName(string); } @Override diff --git a/core/src/main/java/org/lflang/target/property/NoRuntimeValidationProperty.java b/core/src/main/java/org/lflang/target/property/NoRuntimeValidationProperty.java index 216bfe8491..a6eb771d2f 100644 --- a/core/src/main/java/org/lflang/target/property/NoRuntimeValidationProperty.java +++ b/core/src/main/java/org/lflang/target/property/NoRuntimeValidationProperty.java @@ -4,7 +4,14 @@ import org.lflang.Target; /** If true, do not perform runtime validation. The default is false. */ -public class NoRuntimeValidationProperty extends BooleanProperty { +public final class NoRuntimeValidationProperty extends BooleanProperty { + + /** Singleton target property instance. */ + public static final NoRuntimeValidationProperty INSTANCE = new NoRuntimeValidationProperty(); + + private NoRuntimeValidationProperty() { + super(); + } @Override public List supportedTargets() { diff --git a/core/src/main/kotlin/org/lflang/generator/cpp/CppPlatformGenerator.kt b/core/src/main/kotlin/org/lflang/generator/cpp/CppPlatformGenerator.kt index 735d94a130..a9afc8a376 100644 --- a/core/src/main/kotlin/org/lflang/generator/cpp/CppPlatformGenerator.kt +++ b/core/src/main/kotlin/org/lflang/generator/cpp/CppPlatformGenerator.kt @@ -31,7 +31,7 @@ abstract class CppPlatformGenerator(protected val generator: CppGenerator) { protected val cmakeArgs: List get() = listOf( "-DCMAKE_BUILD_TYPE=${targetConfig.get(BuildTypeProperty.INSTANCE)}", - "-DREACTOR_CPP_VALIDATE=${if (targetConfig.get(NoRuntimeValidationProperty())) "OFF" else "ON"}", + "-DREACTOR_CPP_VALIDATE=${if (targetConfig.get(NoRuntimeValidationProperty.INSTANCE)) "OFF" else "ON"}", "-DREACTOR_CPP_PRINT_STATISTICS=${if (targetConfig.get(PrintStatisticsProperty())) "ON" else "OFF"}", "-DREACTOR_CPP_TRACE=${if (targetConfig.get(TracingProperty()).isEnabled) "ON" else "OFF"}", "-DREACTOR_CPP_LOG_LEVEL=${targetConfig.get(LoggingProperty.INSTANCE).severity}", diff --git a/core/src/main/kotlin/org/lflang/generator/ts/TSConstructorGenerator.kt b/core/src/main/kotlin/org/lflang/generator/ts/TSConstructorGenerator.kt index af945f1d88..1be7a51e30 100644 --- a/core/src/main/kotlin/org/lflang/generator/ts/TSConstructorGenerator.kt +++ b/core/src/main/kotlin/org/lflang/generator/ts/TSConstructorGenerator.kt @@ -78,7 +78,7 @@ class TSConstructorGenerator( // Generate code for setting target configurations. private fun generateTargetConfigurations(targetConfig: TargetConfig): String { - val interval = targetConfig.get(CoordinationOptionsProperty()).advanceMessageInterval + val interval = targetConfig.get(CoordinationOptionsProperty.INSTANCE).advanceMessageInterval return if ((reactor.isMain) && interval != null) { "this.setAdvanceMessageInterval(${interval.toTsTime()})" } else "" From 2159a1e874e6d316dfd85729969d3be3d774f071 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Mon, 16 Oct 2023 18:21:04 -0700 Subject: [PATCH 095/145] Fix broken unit test --- core/src/main/java/org/lflang/Target.java | 4 +++- .../lflang/generator/c/CCmakeGenerator.java | 2 +- .../java/org/lflang/generator/c/CCompiler.java | 8 ++++---- .../org/lflang/generator/c/CGenerator.java | 18 +++++++++--------- .../generator/c/CMainFunctionGenerator.java | 8 ++++---- .../lflang/generator/c/CPreambleGenerator.java | 4 ++-- .../java/org/lflang/target/TargetConfig.java | 2 -- .../target/property/PlatformProperty.java | 7 +++++-- .../main/java/org/lflang/util/ArduinoUtil.java | 14 +++++++------- .../compiler/LinguaFrancaValidationTest.java | 14 +++++++------- .../java/org/lflang/tests/Configurators.java | 12 ++++++------ 11 files changed, 48 insertions(+), 45 deletions(-) diff --git a/core/src/main/java/org/lflang/Target.java b/core/src/main/java/org/lflang/Target.java index 3dcaa4c804..9ec0998bd3 100644 --- a/core/src/main/java/org/lflang/Target.java +++ b/core/src/main/java/org/lflang/Target.java @@ -48,6 +48,7 @@ import org.lflang.target.property.HierarchicalBinProperty; import org.lflang.target.property.KeepaliveProperty; import org.lflang.target.property.NoRuntimeValidationProperty; +import org.lflang.target.property.PlatformProperty; import org.lflang.target.property.RustIncludeProperty; /** @@ -588,7 +589,8 @@ public void initialize(TargetConfig config) { FilesProperty.INSTANCE, HierarchicalBinProperty.INSTANCE, KeepaliveProperty.INSTANCE, - NoRuntimeValidationProperty.INSTANCE); + NoRuntimeValidationProperty.INSTANCE, + PlatformProperty.INSTANCE); case CPP -> config.register( BuildTypeProperty.INSTANCE, CmakeIncludeProperty.INSTANCE, 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 af98735fe5..0eeb27dd34 100644 --- a/core/src/main/java/org/lflang/generator/c/CCmakeGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CCmakeGenerator.java @@ -128,7 +128,7 @@ CodeBuilder generateCMakeCode( // rp2040 : // arduino String[] boardProperties = {}; - var platformOptions = targetConfig.get(new PlatformProperty()); + var platformOptions = targetConfig.get(PlatformProperty.INSTANCE); if (platformOptions.board != null) { boardProperties = platformOptions.board.trim().split(":"); // Ignore whitespace diff --git a/core/src/main/java/org/lflang/generator/c/CCompiler.java b/core/src/main/java/org/lflang/generator/c/CCompiler.java index ba84d74af8..c46230caa2 100644 --- a/core/src/main/java/org/lflang/generator/c/CCompiler.java +++ b/core/src/main/java/org/lflang/generator/c/CCompiler.java @@ -188,8 +188,8 @@ public boolean runCCompiler(GeneratorBase generator, LFGeneratorContext context) + " finished with no errors."); } - if (targetConfig.get(new PlatformProperty()).platform == Platform.ZEPHYR - && targetConfig.get(new PlatformProperty()).flash) { + if (targetConfig.get(PlatformProperty.INSTANCE).platform == Platform.ZEPHYR + && targetConfig.get(PlatformProperty.INSTANCE).flash) { messageReporter.nowhere().info("Invoking flash command for Zephyr"); LFCommand flash = buildWestFlashCommand(); int flashRet = flash.run(); @@ -319,7 +319,7 @@ public LFCommand buildCmakeCommand() { public LFCommand buildWestFlashCommand() { // Set the build directory to be "build" Path buildPath = fileConfig.getSrcGenPath().resolve("build"); - String board = targetConfig.get(new PlatformProperty()).board; + String board = targetConfig.get(PlatformProperty.INSTANCE).board; LFCommand cmd; if (board == null || board.startsWith("qemu") || board.equals("native_posix")) { cmd = commandFactory.createCommand("west", List.of("build", "-t", "run"), buildPath); @@ -445,7 +445,7 @@ public LFCommand compileCCommand(String fileToCompile, boolean noBinary) { * .cpp files instead of .c files and uses a C++ compiler to compiler the code. */ static String getTargetFileName(String fileName, boolean cppMode, TargetConfig targetConfig) { - if (targetConfig.get(new PlatformProperty()).platform == Platform.ARDUINO) { + if (targetConfig.get(PlatformProperty.INSTANCE).platform == Platform.ARDUINO) { return fileName + ".ino"; } if (cppMode) { 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 20a49452c3..fd93686166 100644 --- a/core/src/main/java/org/lflang/generator/c/CGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CGenerator.java @@ -446,7 +446,7 @@ public void doGenerate(Resource resource, LFGeneratorContext context) { } // If cmake is requested, generate the CMakeLists.txt - if (targetConfig.get(new PlatformProperty()).platform != Platform.ARDUINO) { + if (targetConfig.get(PlatformProperty.INSTANCE).platform != Platform.ARDUINO) { var cmakeFile = fileConfig.getSrcGenPath() + File.separator + "CMakeLists.txt"; var sources = allTypeParameterizedReactors() @@ -630,7 +630,7 @@ private void generateCodeFor(String lfModuleName) throws IOException { // is set to decentralized) or, if there are // downstream federates, will notify the RTI // that the specified logical time is complete. - if (CCppMode || targetConfig.get(new PlatformProperty()).platform == Platform.ARDUINO) + if (CCppMode || targetConfig.get(PlatformProperty.INSTANCE).platform == Platform.ARDUINO) code.pr("extern \"C\""); code.pr( String.join( @@ -870,8 +870,8 @@ private void generateReactorChildren( private void pickCompilePlatform() { var osName = System.getProperty("os.name").toLowerCase(); // if platform target was set, use given platform instead - if (targetConfig.get(new PlatformProperty()).platform != Platform.AUTO) { - osName = targetConfig.get(new PlatformProperty()).platform.toString(); + if (targetConfig.get(PlatformProperty.INSTANCE).platform != Platform.AUTO) { + osName = targetConfig.get(PlatformProperty.INSTANCE).platform.toString(); } else if (Stream.of("mac", "darwin", "win", "nux").noneMatch(osName::contains)) { messageReporter.nowhere().error("Platform " + osName + " is not supported"); } @@ -882,7 +882,7 @@ protected void copyTargetFiles() throws IOException { // Copy the core lib String coreLib = LFGeneratorContext.BuildParm.EXTERNAL_RUNTIME_PATH.getValue(context); Path dest = fileConfig.getSrcGenPath(); - if (targetConfig.get(new PlatformProperty()).platform == Platform.ARDUINO) { + if (targetConfig.get(PlatformProperty.INSTANCE).platform == Platform.ARDUINO) { dest = dest.resolve("src"); } if (coreLib != null) { @@ -893,7 +893,7 @@ protected void copyTargetFiles() throws IOException { } // For the Zephyr target, copy default config and board files. - if (targetConfig.get(new PlatformProperty()).platform == Platform.ZEPHYR) { + if (targetConfig.get(PlatformProperty.INSTANCE).platform == Platform.ZEPHYR) { FileUtil.copyFromClassPath( "/lib/platform/zephyr/boards", fileConfig.getSrcGenPath(), false, false); FileUtil.copyFileFromClassPath( @@ -904,7 +904,7 @@ protected void copyTargetFiles() throws IOException { } // For the pico src-gen, copy over vscode configurations for debugging - if (targetConfig.get(new PlatformProperty()).platform == Platform.RP2040) { + if (targetConfig.get(PlatformProperty.INSTANCE).platform == Platform.RP2040) { Path vscodePath = fileConfig.getSrcGenPath().resolve(".vscode"); // If pico-sdk-path not defined, this can be used to pull the sdk into src-gen FileUtil.copyFileFromClassPath( @@ -951,7 +951,7 @@ private void generateReactorClass(TypeParameterizedReactor tpr) throws IOExcepti fileConfig.getSrcGenPath().resolve(headerName), true); var extension = - targetConfig.get(new PlatformProperty()).platform == Platform.ARDUINO + targetConfig.get(PlatformProperty.INSTANCE).platform == Platform.ARDUINO ? ".ino" : CCppMode ? ".cpp" : ".c"; FileUtil.writeToFile( @@ -1942,7 +1942,7 @@ protected void setUpGeneralParameters() { // So that each separate compile knows about modal reactors, do this: CompileDefinitionsProperty.INSTANCE.update(targetConfig, Map.of("MODAL_REACTORS", "TRUE")); } - final var platformOptions = targetConfig.get(new PlatformProperty()); + final var platformOptions = targetConfig.get(PlatformProperty.INSTANCE); if (targetConfig.get(new ThreadingProperty()) && platformOptions.platform == Platform.ARDUINO && (platformOptions.board == null || !platformOptions.board.contains("mbed"))) { diff --git a/core/src/main/java/org/lflang/generator/c/CMainFunctionGenerator.java b/core/src/main/java/org/lflang/generator/c/CMainFunctionGenerator.java index 0cac08f682..a6fc315d3a 100644 --- a/core/src/main/java/org/lflang/generator/c/CMainFunctionGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CMainFunctionGenerator.java @@ -37,7 +37,7 @@ public String generateCode() { /** Generate the {@code main} function. */ private String generateMainFunction() { - if (targetConfig.get(new PlatformProperty()).platform == Platform.ARDUINO) { + if (targetConfig.get(PlatformProperty.INSTANCE).platform == Platform.ARDUINO) { /** * By default, we must have a serial begin line prior to calling lf_reactor_c_main due to * internal debugging messages requiring a print buffer. For the future, we can check whether @@ -52,12 +52,12 @@ private String generateMainFunction() { "}\n", "// Arduino setup() and loop() functions", "void setup() {", - "\tSerial.begin(" + targetConfig.get(new PlatformProperty()).baudRate + ");", + "\tSerial.begin(" + targetConfig.get(PlatformProperty.INSTANCE).baudRate + ");", "\tlf_register_print_function(&_lf_arduino_print_message_function, LOG_LEVEL);", "\tlf_reactor_c_main(0, NULL);", "}\n", "void loop() {}"); - } else if (targetConfig.get(new PlatformProperty()).platform == Platform.ZEPHYR) { + } else if (targetConfig.get(PlatformProperty.INSTANCE).platform == Platform.ZEPHYR) { // The Zephyr "runtime" does not terminate when main returns. // Rather, {@code exit} should be called explicitly. return String.join( @@ -66,7 +66,7 @@ private String generateMainFunction() { " int res = lf_reactor_c_main(0, NULL);", " exit(res);", "}"); - } else if (targetConfig.get(new PlatformProperty()).platform == Platform.RP2040) { + } else if (targetConfig.get(PlatformProperty.INSTANCE).platform == Platform.RP2040) { // Pico platform cannot use command line args. return String.join("\n", "int main(void) {", " return lf_reactor_c_main(0, NULL);", "}"); } else { 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 14de2ae16d..dd0b5c5591 100644 --- a/core/src/main/java/org/lflang/generator/c/CPreambleGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CPreambleGenerator.java @@ -35,7 +35,7 @@ public class CPreambleGenerator { public static String generateIncludeStatements(TargetConfig targetConfig, boolean cppMode) { CodeBuilder code = new CodeBuilder(); - if (cppMode || targetConfig.get(new PlatformProperty()).platform == Platform.ARDUINO) { + if (cppMode || targetConfig.get(PlatformProperty.INSTANCE).platform == Platform.ARDUINO) { code.pr("extern \"C\" {"); } code.pr("#include "); @@ -60,7 +60,7 @@ public static String generateIncludeStatements(TargetConfig targetConfig, boolea code.pr("#include \"include/core/federated/federate.h\""); code.pr("#include \"include/core/federated/net_common.h\""); } - if (cppMode || targetConfig.get(new PlatformProperty()).platform == Platform.ARDUINO) { + if (cppMode || targetConfig.get(PlatformProperty.INSTANCE).platform == Platform.ARDUINO) { code.pr("}"); } return code.toString(); diff --git a/core/src/main/java/org/lflang/target/TargetConfig.java b/core/src/main/java/org/lflang/target/TargetConfig.java index efbf3eb6a4..9a4e8f530f 100644 --- a/core/src/main/java/org/lflang/target/TargetConfig.java +++ b/core/src/main/java/org/lflang/target/TargetConfig.java @@ -48,7 +48,6 @@ import org.lflang.target.property.FastProperty; import org.lflang.target.property.LoggingProperty; import org.lflang.target.property.NoCompileProperty; -import org.lflang.target.property.PlatformProperty; import org.lflang.target.property.PrintStatisticsProperty; import org.lflang.target.property.ProtobufsProperty; import org.lflang.target.property.Ros2DependenciesProperty; @@ -92,7 +91,6 @@ public TargetConfig(Target target) { FastProperty.INSTANCE, LoggingProperty.INSTANCE, NoCompileProperty.INSTANCE, - new PlatformProperty(), new PrintStatisticsProperty(), new ProtobufsProperty(), new Ros2DependenciesProperty(), 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 73287acd83..988ae43ccd 100644 --- a/core/src/main/java/org/lflang/target/property/PlatformProperty.java +++ b/core/src/main/java/org/lflang/target/property/PlatformProperty.java @@ -24,9 +24,12 @@ * Directive to specify the platform for cross code generation. This is either a string of the * platform or a dictionary of options that includes the string name. */ -public class PlatformProperty extends TargetProperty { +public final class PlatformProperty extends TargetProperty { - public PlatformProperty() { + /** Singleton target property instance. */ + public static final PlatformProperty INSTANCE = new PlatformProperty(); + + private PlatformProperty() { super(UnionType.PLATFORM_STRING_OR_DICTIONARY); } diff --git a/core/src/main/java/org/lflang/util/ArduinoUtil.java b/core/src/main/java/org/lflang/util/ArduinoUtil.java index a94097ee54..17331d986d 100644 --- a/core/src/main/java/org/lflang/util/ArduinoUtil.java +++ b/core/src/main/java/org/lflang/util/ArduinoUtil.java @@ -69,11 +69,11 @@ private LFCommand arduinoCompileCommand(FileConfig fileConfig, TargetConfig targ var fileWriter = new FileWriter(testScript.getAbsoluteFile(), true); BufferedWriter bufferedWriter = new BufferedWriter(fileWriter); String board = - targetConfig.get(new PlatformProperty()).board != null - ? targetConfig.get(new PlatformProperty()).board + targetConfig.get(PlatformProperty.INSTANCE).board != null + ? targetConfig.get(PlatformProperty.INSTANCE).board : "arduino:avr:leonardo"; String isThreaded = - targetConfig.get(new PlatformProperty()).board.contains("mbed") + targetConfig.get(PlatformProperty.INSTANCE).board.contains("mbed") ? "-DLF_THREADED" : "-DLF_UNTHREADED"; bufferedWriter.write( @@ -123,8 +123,8 @@ public void buildArduino(FileConfig fileConfig, TargetConfig targetConfig) { "SUCCESS: Compiling generated code for " + fileConfig.name + " finished with no errors."); - if (targetConfig.get(new PlatformProperty()).flash) { - if (targetConfig.get(new PlatformProperty()).port != null) { + if (targetConfig.get(PlatformProperty.INSTANCE).flash) { + if (targetConfig.get(PlatformProperty.INSTANCE).port != null) { messageReporter.nowhere().info("Invoking flash command for Arduino"); LFCommand flash = commandFactory.createCommand( @@ -132,9 +132,9 @@ public void buildArduino(FileConfig fileConfig, TargetConfig targetConfig) { List.of( "upload", "-b", - targetConfig.get(new PlatformProperty()).board, + targetConfig.get(PlatformProperty.INSTANCE).board, "-p", - targetConfig.get(new PlatformProperty()).port), + targetConfig.get(PlatformProperty.INSTANCE).port), fileConfig.getSrcGenPath()); if (flash == null) { messageReporter.nowhere().error("Could not create arduino-cli flash command."); 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 88b2633943..037a779a77 100644 --- a/core/src/test/java/org/lflang/tests/compiler/LinguaFrancaValidationTest.java +++ b/core/src/test/java/org/lflang/tests/compiler/LinguaFrancaValidationTest.java @@ -1594,21 +1594,21 @@ public void checkCargoDependencyProperty() throws Exception { // vvvvvvvvvvv validator.assertError( - createModel(Target.C, prop, "{ dep: {/*empty*/} }"), + createModel(Target.Rust, prop, "{ dep: {/*empty*/} }"), LfPackage.eINSTANCE.getKeyValuePairs(), null, "Must specify one of 'version', 'path', or 'git'"); // vvvvvvvvvvv validator.assertError( - createModel(Target.C, prop, "{ dep: { unknown_key: \"\"} }"), + createModel(Target.Rust, prop, "{ dep: { unknown_key: \"\"} }"), LfPackage.eINSTANCE.getKeyValuePair(), null, "Unknown key: 'unknown_key'"); // vvvv validator.assertError( - createModel(Target.C, prop, "{ dep: { features: \"\" } }"), + createModel(Target.Rust, prop, "{ dep: { features: \"\" } }"), LfPackage.eINSTANCE.getElement(), null, "Expected an array of strings for key 'features'"); @@ -1617,17 +1617,17 @@ public void checkCargoDependencyProperty() throws Exception { @Test public void checkPlatformProperty() throws Exception { validator.assertNoErrors( - createModel(Target.C, new PlatformProperty(), Platform.ARDUINO.toString())); + createModel(Target.C, PlatformProperty.INSTANCE, Platform.ARDUINO.toString())); validator.assertNoErrors( createModel( - Target.C, new PlatformProperty(), String.format("{name: %s}", Platform.ZEPHYR))); + Target.C, PlatformProperty.INSTANCE, String.format("{name: %s}", Platform.ZEPHYR))); validator.assertError( - createModel(Target.C, new PlatformProperty(), "foobar"), + createModel(Target.C, PlatformProperty.INSTANCE, "foobar"), LfPackage.eINSTANCE.getKeyValuePair(), null, new PlatformType().toString()); validator.assertError( - createModel(Target.C, new PlatformProperty(), "{ name: foobar }"), + createModel(Target.C, PlatformProperty.INSTANCE, "{ name: foobar }"), LfPackage.eINSTANCE.getElement(), null, new PlatformType().toString()); diff --git a/core/src/testFixtures/java/org/lflang/tests/Configurators.java b/core/src/testFixtures/java/org/lflang/tests/Configurators.java index 65fb9b9975..5134ad2df7 100644 --- a/core/src/testFixtures/java/org/lflang/tests/Configurators.java +++ b/core/src/testFixtures/java/org/lflang/tests/Configurators.java @@ -70,9 +70,9 @@ public static boolean makeZephyrCompatibleUnthreaded(LFTest test) { test.getContext().getArgs().setProperty("tracing", "false"); new ThreadingProperty().override(test.getContext().getTargetConfig(), false); // FIXME: use a record and override. - test.getContext().getTargetConfig().get(new PlatformProperty()).platform = Platform.ZEPHYR; - test.getContext().getTargetConfig().get(new PlatformProperty()).flash = false; - test.getContext().getTargetConfig().get(new PlatformProperty()).board = "qemu_cortex_m3"; + test.getContext().getTargetConfig().get(PlatformProperty.INSTANCE).platform = Platform.ZEPHYR; + test.getContext().getTargetConfig().get(PlatformProperty.INSTANCE).flash = false; + test.getContext().getTargetConfig().get(PlatformProperty.INSTANCE).board = "qemu_cortex_m3"; // FIXME: Zephyr emulations fails with debug log-levels. LoggingProperty.INSTANCE.override(test.getContext().getTargetConfig(), LogLevel.WARN); @@ -82,9 +82,9 @@ public static boolean makeZephyrCompatibleUnthreaded(LFTest test) { public static boolean makeZephyrCompatible(LFTest test) { test.getContext().getArgs().setProperty("tracing", "false"); - test.getContext().getTargetConfig().get(new PlatformProperty()).platform = Platform.ZEPHYR; - test.getContext().getTargetConfig().get(new PlatformProperty()).flash = false; - test.getContext().getTargetConfig().get(new PlatformProperty()).board = "qemu_cortex_m3"; + test.getContext().getTargetConfig().get(PlatformProperty.INSTANCE).platform = Platform.ZEPHYR; + test.getContext().getTargetConfig().get(PlatformProperty.INSTANCE).flash = false; + test.getContext().getTargetConfig().get(PlatformProperty.INSTANCE).board = "qemu_cortex_m3"; // FIXME: Zephyr emulations fails with debug log-levels. LoggingProperty.INSTANCE.override(test.getContext().getTargetConfig(), LogLevel.WARN); From d8a9ac8fc89a35b8f071e890be3ef1e30d0db651 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Mon, 16 Oct 2023 18:49:02 -0700 Subject: [PATCH 096/145] More progress towards moving target property registration --- .../org/lflang/tests/runtime/CppRos2Test.java | 2 +- core/src/main/java/org/lflang/Target.java | 23 +++++++++++++++---- .../federated/generator/FedFileConfig.java | 2 +- .../lflang/generator/c/CCmakeGenerator.java | 2 +- .../org/lflang/generator/c/CGenerator.java | 4 ++-- .../generator/python/PythonGenerator.java | 2 +- .../java/org/lflang/target/TargetConfig.java | 10 -------- .../property/PrintStatisticsProperty.java | 9 +++++++- .../target/property/ProtobufsProperty.java | 9 +++++++- .../property/Ros2DependenciesProperty.java | 9 +++++--- .../lflang/target/property/Ros2Property.java | 9 +++++++- .../property/RuntimeVersionProperty.java | 9 +++++++- .../target/property/SchedulerProperty.java | 2 +- .../org/lflang/generator/cpp/CppGenerator.kt | 6 ++--- .../generator/cpp/CppPlatformGenerator.kt | 2 +- .../generator/cpp/CppRos2PackageGenerator.kt | 4 ++-- .../cpp/CppStandaloneCmakeGenerator.kt | 2 +- .../org/lflang/generator/rust/RustModel.kt | 4 ++-- .../org/lflang/generator/ts/TSGenerator.kt | 8 +++---- 19 files changed, 76 insertions(+), 42 deletions(-) diff --git a/core/src/integrationTest/java/org/lflang/tests/runtime/CppRos2Test.java b/core/src/integrationTest/java/org/lflang/tests/runtime/CppRos2Test.java index efb051944b..b21a932bdd 100644 --- a/core/src/integrationTest/java/org/lflang/tests/runtime/CppRos2Test.java +++ b/core/src/integrationTest/java/org/lflang/tests/runtime/CppRos2Test.java @@ -31,7 +31,7 @@ public void runWithRos2() { Message.DESC_ROS2, it -> true, it -> { - new Ros2Property().override(it.getContext().getTargetConfig(), true); + Ros2Property.INSTANCE.override(it.getContext().getTargetConfig(), true); return true; }, TestLevel.EXECUTION, diff --git a/core/src/main/java/org/lflang/Target.java b/core/src/main/java/org/lflang/Target.java index 9ec0998bd3..166a047526 100644 --- a/core/src/main/java/org/lflang/Target.java +++ b/core/src/main/java/org/lflang/Target.java @@ -49,6 +49,11 @@ import org.lflang.target.property.KeepaliveProperty; import org.lflang.target.property.NoRuntimeValidationProperty; import org.lflang.target.property.PlatformProperty; +import org.lflang.target.property.PrintStatisticsProperty; +import org.lflang.target.property.ProtobufsProperty; +import org.lflang.target.property.Ros2DependenciesProperty; +import org.lflang.target.property.Ros2Property; +import org.lflang.target.property.RuntimeVersionProperty; import org.lflang.target.property.RustIncludeProperty; /** @@ -590,14 +595,19 @@ public void initialize(TargetConfig config) { HierarchicalBinProperty.INSTANCE, KeepaliveProperty.INSTANCE, NoRuntimeValidationProperty.INSTANCE, - PlatformProperty.INSTANCE); + PlatformProperty.INSTANCE, + ProtobufsProperty.INSTANCE); case CPP -> config.register( BuildTypeProperty.INSTANCE, CmakeIncludeProperty.INSTANCE, CompilerProperty.INSTANCE, ExportDependencyGraphProperty.INSTANCE, ExportToYamlProperty.INSTANCE, - ExternalRuntimePathProperty.INSTANCE); + ExternalRuntimePathProperty.INSTANCE, + PrintStatisticsProperty.INSTANCE, + Ros2DependenciesProperty.INSTANCE, + Ros2Property.INSTANCE, + RuntimeVersionProperty.INSTANCE); case Python -> config.register( BuildTypeProperty.INSTANCE, ClockSyncModeProperty.INSTANCE, @@ -607,7 +617,8 @@ public void initialize(TargetConfig config) { CoordinationProperty.INSTANCE, DockerProperty.INSTANCE, FilesProperty.INSTANCE, - KeepaliveProperty.INSTANCE); + KeepaliveProperty.INSTANCE, + ProtobufsProperty.INSTANCE); case Rust -> config.register( BuildTypeProperty.INSTANCE, CargoDependenciesProperty.INSTANCE, @@ -618,12 +629,14 @@ public void initialize(TargetConfig config) { ExportDependencyGraphProperty.INSTANCE, ExternalRuntimePathProperty.INSTANCE, RustIncludeProperty.INSTANCE, - KeepaliveProperty.INSTANCE); + KeepaliveProperty.INSTANCE, + RuntimeVersionProperty.INSTANCE); case TS -> config.register( CoordinationOptionsProperty.INSTANCE, CoordinationProperty.INSTANCE, DockerProperty.INSTANCE, - KeepaliveProperty.INSTANCE); + KeepaliveProperty.INSTANCE, + ProtobufsProperty.INSTANCE); } } } diff --git a/core/src/main/java/org/lflang/federated/generator/FedFileConfig.java b/core/src/main/java/org/lflang/federated/generator/FedFileConfig.java index f3db2573c7..f7e8657b71 100644 --- a/core/src/main/java/org/lflang/federated/generator/FedFileConfig.java +++ b/core/src/main/java/org/lflang/federated/generator/FedFileConfig.java @@ -103,7 +103,7 @@ public void doClean() throws IOException { * the generated .lf file for the federate. */ public void relativizePaths(FedTargetConfig targetConfig) { - List.of(new ProtobufsProperty(), FilesProperty.INSTANCE, CmakeIncludeProperty.INSTANCE) + List.of(ProtobufsProperty.INSTANCE, FilesProperty.INSTANCE, CmakeIncludeProperty.INSTANCE) .forEach( p -> { p.override(targetConfig, relativizePathList(targetConfig.get(p))); 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 0eeb27dd34..95b548088a 100644 --- a/core/src/main/java/org/lflang/generator/c/CCmakeGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CCmakeGenerator.java @@ -393,7 +393,7 @@ CodeBuilder generateCMakeCode( } // link protobuf - if (!targetConfig.get(new ProtobufsProperty()).isEmpty()) { + if (!targetConfig.get(ProtobufsProperty.INSTANCE).isEmpty()) { cMakeCode.pr("include(FindPackageHandleStandardArgs)"); cMakeCode.pr("FIND_PATH( PROTOBUF_INCLUDE_DIR protobuf-c/protobuf-c.h)"); cMakeCode.pr( 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 fd93686166..82ed04e96f 100644 --- a/core/src/main/java/org/lflang/generator/c/CGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CGenerator.java @@ -1995,7 +1995,7 @@ protected void setUpGeneralParameters() { protected void handleProtoFiles() { // Handle .proto files. - for (String file : targetConfig.get(new ProtobufsProperty())) { + for (String file : targetConfig.get(ProtobufsProperty.INSTANCE)) { this.processProtoFile(file); } } @@ -2026,7 +2026,7 @@ protected String generateTopLevelPreambles(Reactor reactor) { .flatMap(it -> ASTUtils.allFileLevelPreambles(it).stream()) .collect(Collectors.toSet()) .forEach(it -> builder.pr(toText(it.getCode()))); - for (String file : targetConfig.get(new ProtobufsProperty())) { + for (String file : targetConfig.get(ProtobufsProperty.INSTANCE)) { var dotIndex = file.lastIndexOf("."); var rootFilename = file; if (dotIndex > 0) { diff --git a/core/src/main/java/org/lflang/generator/python/PythonGenerator.java b/core/src/main/java/org/lflang/generator/python/PythonGenerator.java index c2b8421bb9..fe7e3b6bf4 100644 --- a/core/src/main/java/org/lflang/generator/python/PythonGenerator.java +++ b/core/src/main/java/org/lflang/generator/python/PythonGenerator.java @@ -278,7 +278,7 @@ protected String generateTopLevelPreambles(Reactor ignored) { @Override protected void handleProtoFiles() { - for (String name : targetConfig.get(new ProtobufsProperty())) { + for (String name : targetConfig.get(ProtobufsProperty.INSTANCE)) { this.processProtoFile(name); int dotIndex = name.lastIndexOf("."); String rootFilename = dotIndex > 0 ? name.substring(0, dotIndex) : name; diff --git a/core/src/main/java/org/lflang/target/TargetConfig.java b/core/src/main/java/org/lflang/target/TargetConfig.java index 9a4e8f530f..bc19efbb1a 100644 --- a/core/src/main/java/org/lflang/target/TargetConfig.java +++ b/core/src/main/java/org/lflang/target/TargetConfig.java @@ -48,11 +48,6 @@ import org.lflang.target.property.FastProperty; import org.lflang.target.property.LoggingProperty; import org.lflang.target.property.NoCompileProperty; -import org.lflang.target.property.PrintStatisticsProperty; -import org.lflang.target.property.ProtobufsProperty; -import org.lflang.target.property.Ros2DependenciesProperty; -import org.lflang.target.property.Ros2Property; -import org.lflang.target.property.RuntimeVersionProperty; import org.lflang.target.property.SchedulerProperty; import org.lflang.target.property.SingleFileProjectProperty; import org.lflang.target.property.ThreadingProperty; @@ -91,11 +86,6 @@ public TargetConfig(Target target) { FastProperty.INSTANCE, LoggingProperty.INSTANCE, NoCompileProperty.INSTANCE, - new PrintStatisticsProperty(), - new ProtobufsProperty(), - new Ros2DependenciesProperty(), - new Ros2Property(), - new RuntimeVersionProperty(), new SchedulerProperty(), new SingleFileProjectProperty(), new ThreadingProperty(), diff --git a/core/src/main/java/org/lflang/target/property/PrintStatisticsProperty.java b/core/src/main/java/org/lflang/target/property/PrintStatisticsProperty.java index d682f40a6a..78b2ffd681 100644 --- a/core/src/main/java/org/lflang/target/property/PrintStatisticsProperty.java +++ b/core/src/main/java/org/lflang/target/property/PrintStatisticsProperty.java @@ -4,7 +4,14 @@ import org.lflang.Target; /** If true, instruct the runtime to collect and print execution statistics. */ -public class PrintStatisticsProperty extends BooleanProperty { +public final class PrintStatisticsProperty extends BooleanProperty { + + /** Singleton target property instance. */ + public static final PrintStatisticsProperty INSTANCE = new PrintStatisticsProperty(); + + private PrintStatisticsProperty() { + super(); + } @Override public List supportedTargets() { diff --git a/core/src/main/java/org/lflang/target/property/ProtobufsProperty.java b/core/src/main/java/org/lflang/target/property/ProtobufsProperty.java index 426723a93a..6845fb4c77 100644 --- a/core/src/main/java/org/lflang/target/property/ProtobufsProperty.java +++ b/core/src/main/java/org/lflang/target/property/ProtobufsProperty.java @@ -7,7 +7,14 @@ * Directive for specifying .proto files that need to be compiled and their code included in the * sources. */ -public class ProtobufsProperty extends FileListProperty { +public final class ProtobufsProperty extends FileListProperty { + + /** Singleton target property instance. */ + public static final ProtobufsProperty INSTANCE = new ProtobufsProperty(); + + private ProtobufsProperty() { + super(); + } @Override public List supportedTargets() { 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 ca5bfc1ffd..7dcd052083 100644 --- a/core/src/main/java/org/lflang/target/property/Ros2DependenciesProperty.java +++ b/core/src/main/java/org/lflang/target/property/Ros2DependenciesProperty.java @@ -13,9 +13,12 @@ import org.lflang.target.property.type.ArrayType; /** Directive to specify additional ROS2 packages that this LF program depends on. */ -public class Ros2DependenciesProperty extends TargetProperty, ArrayType> { +public final class Ros2DependenciesProperty extends TargetProperty, ArrayType> { - public Ros2DependenciesProperty() { + /** Singleton target property instance. */ + public static final Ros2DependenciesProperty INSTANCE = new Ros2DependenciesProperty(); + + private Ros2DependenciesProperty() { super(ArrayType.STRING_ARRAY); } @@ -41,7 +44,7 @@ public List supportedTargets() { @Override public void validate(KeyValuePair pair, Model ast, MessageReporter reporter) { - var ros2enabled = TargetProperty.getKeyValuePair(ast, new Ros2Property()); + var ros2enabled = TargetProperty.getKeyValuePair(ast, Ros2Property.INSTANCE); if (pair != null && (ros2enabled == null || !ASTUtils.toBoolean(ros2enabled.getValue()))) { reporter .at(pair, Literals.KEY_VALUE_PAIR__NAME) diff --git a/core/src/main/java/org/lflang/target/property/Ros2Property.java b/core/src/main/java/org/lflang/target/property/Ros2Property.java index a9c0b02431..f764fa9ce4 100644 --- a/core/src/main/java/org/lflang/target/property/Ros2Property.java +++ b/core/src/main/java/org/lflang/target/property/Ros2Property.java @@ -4,7 +4,14 @@ import org.lflang.Target; /** If true, generate ROS2 specific code. */ -public class Ros2Property extends BooleanProperty { +public final class Ros2Property extends BooleanProperty { + + /** Singleton target property instance. */ + public static final Ros2Property INSTANCE = new Ros2Property(); + + private Ros2Property() { + super(); + } @Override public List supportedTargets() { diff --git a/core/src/main/java/org/lflang/target/property/RuntimeVersionProperty.java b/core/src/main/java/org/lflang/target/property/RuntimeVersionProperty.java index ceb93cfc52..eda304a216 100644 --- a/core/src/main/java/org/lflang/target/property/RuntimeVersionProperty.java +++ b/core/src/main/java/org/lflang/target/property/RuntimeVersionProperty.java @@ -4,7 +4,14 @@ import org.lflang.Target; /** Directive for specifying a specific version of the reactor runtime library. */ -public class RuntimeVersionProperty extends StringProperty { +public final class RuntimeVersionProperty extends StringProperty { + + /** Singleton target property instance. */ + public static final RuntimeVersionProperty INSTANCE = new RuntimeVersionProperty(); + + private RuntimeVersionProperty() { + super(); + } @Override public List supportedTargets() { 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 d981009f58..7889c23e29 100644 --- a/core/src/main/java/org/lflang/target/property/SchedulerProperty.java +++ b/core/src/main/java/org/lflang/target/property/SchedulerProperty.java @@ -14,7 +14,7 @@ import org.lflang.target.property.type.SchedulerType.Scheduler; /** Directive for specifying the use of a specific runtime scheduler. */ -public class SchedulerProperty extends TargetProperty { +public final class SchedulerProperty extends TargetProperty { public SchedulerProperty() { super(new SchedulerType()); diff --git a/core/src/main/kotlin/org/lflang/generator/cpp/CppGenerator.kt b/core/src/main/kotlin/org/lflang/generator/cpp/CppGenerator.kt index 119fa5e449..ec97ea9b80 100644 --- a/core/src/main/kotlin/org/lflang/generator/cpp/CppGenerator.kt +++ b/core/src/main/kotlin/org/lflang/generator/cpp/CppGenerator.kt @@ -67,7 +67,7 @@ class CppGenerator( // create a platform-specific generator val platformGenerator: CppPlatformGenerator = - if (targetConfig.get(Ros2Property())) CppRos2Generator(this) else CppStandaloneGenerator(this) + if (targetConfig.get(Ros2Property.INSTANCE)) CppRos2Generator(this) else CppStandaloneGenerator(this) // generate all core files generateFiles(platformGenerator.srcGenPath) @@ -130,8 +130,8 @@ class CppGenerator( // copy or download reactor-cpp if (!targetConfig.isSet(ExternalRuntimePathProperty.INSTANCE)) { - if (targetConfig.isSet(RuntimeVersionProperty())) { - fetchReactorCpp(targetConfig.get(RuntimeVersionProperty())) + if (targetConfig.isSet(RuntimeVersionProperty.INSTANCE)) { + fetchReactorCpp(targetConfig.get(RuntimeVersionProperty.INSTANCE)) } else { FileUtil.copyFromClassPath( "$libDir/reactor-cpp", diff --git a/core/src/main/kotlin/org/lflang/generator/cpp/CppPlatformGenerator.kt b/core/src/main/kotlin/org/lflang/generator/cpp/CppPlatformGenerator.kt index a9afc8a376..f52bf0a9f3 100644 --- a/core/src/main/kotlin/org/lflang/generator/cpp/CppPlatformGenerator.kt +++ b/core/src/main/kotlin/org/lflang/generator/cpp/CppPlatformGenerator.kt @@ -32,7 +32,7 @@ abstract class CppPlatformGenerator(protected val generator: CppGenerator) { get() = listOf( "-DCMAKE_BUILD_TYPE=${targetConfig.get(BuildTypeProperty.INSTANCE)}", "-DREACTOR_CPP_VALIDATE=${if (targetConfig.get(NoRuntimeValidationProperty.INSTANCE)) "OFF" else "ON"}", - "-DREACTOR_CPP_PRINT_STATISTICS=${if (targetConfig.get(PrintStatisticsProperty())) "ON" else "OFF"}", + "-DREACTOR_CPP_PRINT_STATISTICS=${if (targetConfig.get(PrintStatisticsProperty.INSTANCE)) "ON" else "OFF"}", "-DREACTOR_CPP_TRACE=${if (targetConfig.get(TracingProperty()).isEnabled) "ON" else "OFF"}", "-DREACTOR_CPP_LOG_LEVEL=${targetConfig.get(LoggingProperty.INSTANCE).severity}", "-DLF_SRC_PKG_PATH=${fileConfig.srcPkgPath}", diff --git a/core/src/main/kotlin/org/lflang/generator/cpp/CppRos2PackageGenerator.kt b/core/src/main/kotlin/org/lflang/generator/cpp/CppRos2PackageGenerator.kt index 5f3aac1a84..ea7568e2c4 100644 --- a/core/src/main/kotlin/org/lflang/generator/cpp/CppRos2PackageGenerator.kt +++ b/core/src/main/kotlin/org/lflang/generator/cpp/CppRos2PackageGenerator.kt @@ -13,11 +13,11 @@ import java.nio.file.Path class CppRos2PackageGenerator(generator: CppGenerator, private val nodeName: String) { private val fileConfig = generator.fileConfig private val targetConfig = generator.targetConfig - val reactorCppSuffix: String = if (targetConfig.isSet(RuntimeVersionProperty())) targetConfig.get(RuntimeVersionProperty()) else "default" + val reactorCppSuffix: String = if (targetConfig.isSet(RuntimeVersionProperty.INSTANCE)) targetConfig.get(RuntimeVersionProperty.INSTANCE) else "default" val reactorCppName = "reactor-cpp-$reactorCppSuffix" private val dependencies = listOf("rclcpp", "rclcpp_components", reactorCppName) + ( - if (targetConfig.isSet(Ros2DependenciesProperty())) targetConfig.get(Ros2DependenciesProperty()) else listOf()) + if (targetConfig.isSet(Ros2DependenciesProperty.INSTANCE)) targetConfig.get(Ros2DependenciesProperty.INSTANCE) else listOf()) @Suppress("PrivatePropertyName") // allows us to use capital S as variable name below private val S = '$' // a little trick to escape the dollar sign with $S diff --git a/core/src/main/kotlin/org/lflang/generator/cpp/CppStandaloneCmakeGenerator.kt b/core/src/main/kotlin/org/lflang/generator/cpp/CppStandaloneCmakeGenerator.kt index c767aa892b..26790cc48d 100644 --- a/core/src/main/kotlin/org/lflang/generator/cpp/CppStandaloneCmakeGenerator.kt +++ b/core/src/main/kotlin/org/lflang/generator/cpp/CppStandaloneCmakeGenerator.kt @@ -141,7 +141,7 @@ class CppStandaloneCmakeGenerator(private val targetConfig: TargetConfig, privat val reactorCppTarget = when { targetConfig.isSet(ExternalRuntimePathProperty.INSTANCE) -> "reactor-cpp" - targetConfig.isSet(RuntimeVersionProperty()) -> "reactor-cpp-${targetConfig.get(RuntimeVersionProperty())}" + targetConfig.isSet(RuntimeVersionProperty.INSTANCE) -> "reactor-cpp-${targetConfig.get(RuntimeVersionProperty.INSTANCE)}" else -> "reactor-cpp-default" } 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 7b3e6637a3..bd69d96f0a 100644 --- a/core/src/main/kotlin/org/lflang/generator/rust/RustModel.kt +++ b/core/src/main/kotlin/org/lflang/generator/rust/RustModel.kt @@ -498,9 +498,9 @@ object RustModelBuilder { if (targetConfig.isSet(ExternalRuntimePathProperty.INSTANCE)) { spec.localPath = targetConfig.get(ExternalRuntimePathProperty.INSTANCE) - } else if (targetConfig.isSet(RuntimeVersionProperty())) { + } else if (targetConfig.isSet(RuntimeVersionProperty.INSTANCE)) { spec.gitRepo = RustEmitterBase.runtimeGitUrl - spec.rev = targetConfig.get(RuntimeVersionProperty()) + spec.rev = targetConfig.get(RuntimeVersionProperty.INSTANCE) } else { spec.useDefaultRuntimePath() } diff --git a/core/src/main/kotlin/org/lflang/generator/ts/TSGenerator.kt b/core/src/main/kotlin/org/lflang/generator/ts/TSGenerator.kt index 759aa559cd..8c764ae58d 100644 --- a/core/src/main/kotlin/org/lflang/generator/ts/TSGenerator.kt +++ b/core/src/main/kotlin/org/lflang/generator/ts/TSGenerator.kt @@ -140,7 +140,7 @@ class TSGenerator( context.unsuccessfulFinish() return } - if (targetConfig.get(ProtobufsProperty()).size != 0) { + if (targetConfig.get(ProtobufsProperty.INSTANCE).size != 0) { protoc() } else { println("No .proto files have been imported. Skipping protocol buffer compilation.") @@ -244,7 +244,7 @@ class TSGenerator( val tsCode = StringBuilder() val preambleGenerator = TSImportPreambleGenerator(fileConfig.srcFile, - targetConfig.get(ProtobufsProperty()), preambles) + targetConfig.get(ProtobufsProperty.INSTANCE), preambles) tsCode.append(preambleGenerator.generatePreamble()) val parameterGenerator = TSParameterPreambleGenerator(fileConfig, targetConfig, reactors) @@ -348,7 +348,7 @@ class TSGenerator( } private fun installProtoBufsIfNeeded(pnpmIsAvailable: Boolean, cwd: Path, cancelIndicator: CancelIndicator) { - if (targetConfig.get(ProtobufsProperty()).size != 0) { + if (targetConfig.get(ProtobufsProperty.INSTANCE).size != 0) { commandFactory.createCommand( if (pnpmIsAvailable) "pnpm" else "npm", listOf("install", "google-protobuf"), @@ -375,7 +375,7 @@ class TSGenerator( "--ts_out=$tsOutPath" ) ) - protocArgs.addAll(targetConfig.get(ProtobufsProperty())) + protocArgs.addAll(targetConfig.get(ProtobufsProperty.INSTANCE)) val protoc = commandFactory.createCommand("protoc", protocArgs, fileConfig.srcPath) if (protoc == null) { From 5d898289b8af3e3f049d9fa29e956cfa18a42812 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Tue, 17 Oct 2023 00:42:17 -0700 Subject: [PATCH 097/145] Move registration of remaining target properties to Target class --- .../lflang/tests/runtime/CVerifierTest.java | 2 +- core/src/main/java/org/lflang/Target.java | 28 ++++++++++++--- .../federated/extensions/CExtension.java | 4 +-- .../federated/generator/FedTargetConfig.java | 2 +- .../launcher/FedLauncherGenerator.java | 2 +- .../org/lflang/generator/GeneratorBase.java | 4 +-- .../lflang/generator/c/CCmakeGenerator.java | 7 ++-- .../c/CEnvironmentFunctionGenerator.java | 2 +- .../org/lflang/generator/c/CGenerator.java | 36 +++++++++---------- .../generator/c/CMainFunctionGenerator.java | 6 ++-- .../generator/c/CPreambleGenerator.java | 12 +++---- .../generator/c/CTriggerObjectsGenerator.java | 2 +- .../java/org/lflang/target/TargetConfig.java | 14 ++------ .../target/property/FedSetupProperty.java | 5 ++- .../target/property/PlatformProperty.java | 2 +- .../target/property/SchedulerProperty.java | 5 ++- .../property/SingleFileProjectProperty.java | 9 ++++- .../target/property/ThreadingProperty.java | 7 ++++ .../target/property/TimeOutProperty.java | 5 ++- .../target/property/TracingProperty.java | 7 ++-- .../target/property/VerifyProperty.java | 9 ++++- .../target/property/WorkersProperty.java | 7 ++-- .../generator/cpp/CppRos2NodeGenerator.kt | 4 +-- .../cpp/CppStandaloneMainGenerator.kt | 4 +-- .../org/lflang/generator/rust/RustModel.kt | 14 ++++---- .../ts/TSParameterPreambleGenerator.kt | 2 +- .../java/org/lflang/tests/Configurators.java | 2 +- 27 files changed, 125 insertions(+), 78 deletions(-) diff --git a/core/src/integrationTest/java/org/lflang/tests/runtime/CVerifierTest.java b/core/src/integrationTest/java/org/lflang/tests/runtime/CVerifierTest.java index 86d61464b0..e888854318 100644 --- a/core/src/integrationTest/java/org/lflang/tests/runtime/CVerifierTest.java +++ b/core/src/integrationTest/java/org/lflang/tests/runtime/CVerifierTest.java @@ -22,7 +22,7 @@ public void runVerifierTests() { Message.DESC_VERIFIER, TestRegistry.TestCategory.VERIFIER::equals, test -> { - new VerifyProperty().override(test.getContext().getTargetConfig(), true); + VerifyProperty.INSTANCE.override(test.getContext().getTargetConfig(), true); return true; }, TestLevel.BUILD, diff --git a/core/src/main/java/org/lflang/Target.java b/core/src/main/java/org/lflang/Target.java index 166a047526..33ddf7ea6e 100644 --- a/core/src/main/java/org/lflang/Target.java +++ b/core/src/main/java/org/lflang/Target.java @@ -55,6 +55,12 @@ import org.lflang.target.property.Ros2Property; import org.lflang.target.property.RuntimeVersionProperty; 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.TracingProperty; +import org.lflang.target.property.WorkersProperty; +import org.lflang.target.property.type.VerifyProperty; /** * Enumeration of targets and their associated properties. @@ -596,7 +602,12 @@ public void initialize(TargetConfig config) { KeepaliveProperty.INSTANCE, NoRuntimeValidationProperty.INSTANCE, PlatformProperty.INSTANCE, - ProtobufsProperty.INSTANCE); + ProtobufsProperty.INSTANCE, + SchedulerProperty.INSTANCE, + ThreadingProperty.INSTANCE, + TracingProperty.INSTANCE, + VerifyProperty.INSTANCE, + WorkersProperty.INSTANCE); case CPP -> config.register( BuildTypeProperty.INSTANCE, CmakeIncludeProperty.INSTANCE, @@ -607,7 +618,9 @@ public void initialize(TargetConfig config) { PrintStatisticsProperty.INSTANCE, Ros2DependenciesProperty.INSTANCE, Ros2Property.INSTANCE, - RuntimeVersionProperty.INSTANCE); + RuntimeVersionProperty.INSTANCE, + TracingProperty.INSTANCE, + WorkersProperty.INSTANCE); case Python -> config.register( BuildTypeProperty.INSTANCE, ClockSyncModeProperty.INSTANCE, @@ -618,7 +631,11 @@ public void initialize(TargetConfig config) { DockerProperty.INSTANCE, FilesProperty.INSTANCE, KeepaliveProperty.INSTANCE, - ProtobufsProperty.INSTANCE); + ProtobufsProperty.INSTANCE, + SchedulerProperty.INSTANCE, + ThreadingProperty.INSTANCE, + TracingProperty.INSTANCE, + WorkersProperty.INSTANCE); case Rust -> config.register( BuildTypeProperty.INSTANCE, CargoDependenciesProperty.INSTANCE, @@ -630,7 +647,10 @@ public void initialize(TargetConfig config) { ExternalRuntimePathProperty.INSTANCE, RustIncludeProperty.INSTANCE, KeepaliveProperty.INSTANCE, - RuntimeVersionProperty.INSTANCE); + RuntimeVersionProperty.INSTANCE, + SingleFileProjectProperty.INSTANCE, + ThreadingProperty.INSTANCE, + WorkersProperty.INSTANCE); case TS -> config.register( CoordinationOptionsProperty.INSTANCE, CoordinationProperty.INSTANCE, 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 ca0552b85e..1d50d14825 100644 --- a/core/src/main/java/org/lflang/federated/extensions/CExtension.java +++ b/core/src/main/java/org/lflang/federated/extensions/CExtension.java @@ -93,10 +93,10 @@ 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. - new ThreadingProperty().override(federate.targetConfig, true); + ThreadingProperty.INSTANCE.override(federate.targetConfig, true); // Include the fed setup file for this federate in the target property - new FedSetupProperty().override(federate.targetConfig, getPreamblePath(federate)); + FedSetupProperty.INSTANCE.override(federate.targetConfig, getPreamblePath(federate)); } /** Generate a cmake-include file for {@code federate} if needed. */ diff --git a/core/src/main/java/org/lflang/federated/generator/FedTargetConfig.java b/core/src/main/java/org/lflang/federated/generator/FedTargetConfig.java index 1a9d8188d9..4a618d0823 100644 --- a/core/src/main/java/org/lflang/federated/generator/FedTargetConfig.java +++ b/core/src/main/java/org/lflang/federated/generator/FedTargetConfig.java @@ -43,7 +43,7 @@ public FedTargetConfig(LFGeneratorContext context, Resource federateResource) { context.getArgs(), context.getErrorReporter()); - this.register(new FedSetupProperty()); + this.register(FedSetupProperty.INSTANCE); mergeImportedConfig( federateResource, context.getFileConfig().resource, context.getErrorReporter()); diff --git a/core/src/main/java/org/lflang/federated/launcher/FedLauncherGenerator.java b/core/src/main/java/org/lflang/federated/launcher/FedLauncherGenerator.java index f289918b7d..0986ad78dc 100644 --- a/core/src/main/java/org/lflang/federated/launcher/FedLauncherGenerator.java +++ b/core/src/main/java/org/lflang/federated/launcher/FedLauncherGenerator.java @@ -341,7 +341,7 @@ private String getRtiCommand(List federates, boolean isRemote) if (targetConfig.get(AuthProperty.INSTANCE)) { commands.add(" -a \\"); } - if (targetConfig.get(new TracingProperty()).isEnabled()) { + if (targetConfig.get(TracingProperty.INSTANCE).isEnabled()) { commands.add(" -t \\"); } commands.addAll( diff --git a/core/src/main/java/org/lflang/generator/GeneratorBase.java b/core/src/main/java/org/lflang/generator/GeneratorBase.java index 50cad851d5..c44767fed9 100644 --- a/core/src/main/java/org/lflang/generator/GeneratorBase.java +++ b/core/src/main/java/org/lflang/generator/GeneratorBase.java @@ -267,7 +267,7 @@ public void doGenerate(Resource resource, LFGeneratorContext context) { // Check for the existence and support of watchdogs hasWatchdogs = IterableExtensions.exists(reactors, it -> !it.getWatchdogs().isEmpty()); - checkWatchdogSupport(targetConfig.get(new ThreadingProperty()) && getTarget() == Target.C); + checkWatchdogSupport(targetConfig.get(ThreadingProperty.INSTANCE) && getTarget() == Target.C); additionalPostProcessingForModes(); } @@ -651,7 +651,7 @@ private void runVerifierIfPropertiesDetected(Resource resource, LFGeneratorConte uclidGenerator.doGenerate(resource, lfContext); // Check the generated uclid files. - if (uclidGenerator.targetConfig.get(new VerifyProperty())) { + if (uclidGenerator.targetConfig.get(VerifyProperty.INSTANCE)) { // Check if Uclid5 and Z3 are installed. if (commandFactory.createCommand("uclid", List.of()) == null 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 95b548088a..c860f685a8 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,8 @@ CodeBuilder generateCMakeCode( cMakeCode.newLine(); } - if (targetConfig.get(new ThreadingProperty()) && platformOptions.platform != Platform.ZEPHYR) { + if (targetConfig.get(ThreadingProperty.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,11 +366,11 @@ CodeBuilder generateCMakeCode( // Add additional flags so runtime can distinguish between multi-threaded and single-threaded // mode - if (targetConfig.get(new ThreadingProperty())) { + if (targetConfig.get(ThreadingProperty.INSTANCE)) { cMakeCode.pr("# Set the number of workers to enable threading/tracing"); cMakeCode.pr( "target_compile_definitions(${LF_MAIN_TARGET} PUBLIC NUMBER_OF_WORKERS=" - + targetConfig.get(new WorkersProperty()) + + targetConfig.get(WorkersProperty.INSTANCE) + ")"); cMakeCode.newLine(); cMakeCode.pr("# Set flag to indicate a multi-threaded runtime"); diff --git a/core/src/main/java/org/lflang/generator/c/CEnvironmentFunctionGenerator.java b/core/src/main/java/org/lflang/generator/c/CEnvironmentFunctionGenerator.java index b09d29c330..9b01a5a429 100644 --- a/core/src/main/java/org/lflang/generator/c/CEnvironmentFunctionGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CEnvironmentFunctionGenerator.java @@ -90,7 +90,7 @@ private String generateCreateEnvironments() { // Figure out the name of the trace file String traceFileName = "NULL"; - var tracing = targetConfig.get(new TracingProperty()); + var tracing = targetConfig.get(TracingProperty.INSTANCE); if (tracing.isEnabled()) { if (tracing.traceFileName != null) { if (enclave.isMainOrFederated()) { 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 82ed04e96f..f3b1fb8f2a 100644 --- a/core/src/main/java/org/lflang/generator/c/CGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CGenerator.java @@ -360,7 +360,7 @@ 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 = new ThreadingProperty(); + var threading = ThreadingProperty.INSTANCE; if (!targetConfig.get(threading) && !targetConfig.isSet(threading)) { threading.override(targetConfig, true); String message = @@ -473,7 +473,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(new ThreadingProperty())); + FileUtil.arduinoDeleteHelper(src, targetConfig.get(ThreadingProperty.INSTANCE)); FileUtil.relativeIncludeHelper(src, include, messageReporter); FileUtil.relativeIncludeHelper(include, include, messageReporter); } catch (IOException e) { @@ -611,9 +611,9 @@ private void generateCodeFor(String lfModuleName) throws IOException { code.pr(envFuncGen.generateDefinitions()); - if (targetConfig.isSet(new FedSetupProperty())) { + if (targetConfig.isSet(FedSetupProperty.INSTANCE)) { if (targetLanguageIsCpp()) code.pr("extern \"C\" {"); - code.pr("#include \"" + targetConfig.get(new FedSetupProperty()) + "\""); + code.pr("#include \"" + targetConfig.get(FedSetupProperty.INSTANCE) + "\""); if (targetLanguageIsCpp()) code.pr("}"); } @@ -671,11 +671,11 @@ protected String getConflictingConnectionsInModalReactorsBody(String source, Str private void pickScheduler() { // Don't use a scheduler that does not prioritize reactions based on deadlines // if the program contains a deadline (handler). Use the GEDF_NP scheduler instead. - if (!targetConfig.get(new SchedulerProperty()).prioritizesDeadline()) { + if (!targetConfig.get(SchedulerProperty.INSTANCE).prioritizesDeadline()) { // Check if a deadline is assigned to any reaction if (hasDeadlines(reactors)) { - if (!targetConfig.isSet(new SchedulerProperty())) { - new SchedulerProperty().override(targetConfig, Scheduler.GEDF_NP); + if (!targetConfig.isSet(SchedulerProperty.INSTANCE)) { + SchedulerProperty.INSTANCE.override(targetConfig, Scheduler.GEDF_NP); } } } @@ -745,14 +745,14 @@ protected void copyUserFiles(TargetConfig targetConfig, FileConfig fileConfig) { messageReporter, true); - if (!StringExtensions.isNullOrEmpty(targetConfig.get(new FedSetupProperty()))) { + if (!StringExtensions.isNullOrEmpty(targetConfig.get(FedSetupProperty.INSTANCE))) { try { - var file = targetConfig.get(new FedSetupProperty()); + var file = targetConfig.get(FedSetupProperty.INSTANCE); FileUtil.copyFile(fileConfig.srcFile.getParent().resolve(file), destination.resolve(file)); } catch (IOException e) { messageReporter .nowhere() - .error("Failed to find _fed_setup file " + targetConfig.get(new FedSetupProperty())); + .error("Failed to find _fed_setup file " + targetConfig.get(FedSetupProperty.INSTANCE)); } } } @@ -1377,7 +1377,7 @@ private void recordBuiltinTriggers(ReactorInstance instance) { foundOne = true; enclaveInfo.numShutdownReactions += reactor.getTotalWidth(); - if (targetConfig.get(new TracingProperty()).isEnabled()) { + if (targetConfig.get(TracingProperty.INSTANCE).isEnabled()) { var description = CUtil.getShortenedName(reactor); var reactorRef = CUtil.reactorRef(reactor); var envTraceRef = CUtil.getEnvironmentStruct(reactor) + ".trace"; @@ -1660,7 +1660,7 @@ public static String variableStructType(TriggerInstance portOrAction) { * @param instance The reactor instance. */ private void generateTraceTableEntries(ReactorInstance instance) { - if (targetConfig.get(new TracingProperty()).isEnabled()) { + if (targetConfig.get(TracingProperty.INSTANCE).isEnabled()) { initializeTriggerObjects.pr(CTracingGenerator.generateTraceTableEntries(instance)); } } @@ -1943,7 +1943,7 @@ protected void setUpGeneralParameters() { CompileDefinitionsProperty.INSTANCE.update(targetConfig, Map.of("MODAL_REACTORS", "TRUE")); } final var platformOptions = targetConfig.get(PlatformProperty.INSTANCE); - if (targetConfig.get(new ThreadingProperty()) + if (targetConfig.get(ThreadingProperty.INSTANCE) && platformOptions.platform == Platform.ARDUINO && (platformOptions.board == null || !platformOptions.board.contains("mbed"))) { // non-MBED boards should not use threading @@ -1952,7 +1952,7 @@ protected void setUpGeneralParameters() { .info( "Threading is incompatible on your current Arduino flavor. Setting threading to" + " false."); - new ThreadingProperty().override(targetConfig, false); + ThreadingProperty.INSTANCE.override(targetConfig, false); } if (platformOptions.platform == Platform.ARDUINO @@ -1969,7 +1969,7 @@ protected void setUpGeneralParameters() { } if (platformOptions.platform == Platform.ZEPHYR - && targetConfig.get(new ThreadingProperty()) + && targetConfig.get(ThreadingProperty.INSTANCE) && platformOptions.userThreads >= 0) { targetConfig .get(CompileDefinitionsProperty.INSTANCE) @@ -1982,12 +1982,12 @@ protected void setUpGeneralParameters() { + " This option will be ignored."); } - if (targetConfig.get(new ThreadingProperty())) { // FIXME: This logic is duplicated in CMake + if (targetConfig.get(ThreadingProperty.INSTANCE)) { // FIXME: This logic is duplicated in CMake pickScheduler(); // FIXME: this and pickScheduler should be combined. var map = new HashMap(); - map.put("SCHEDULER", targetConfig.get(new SchedulerProperty()).getSchedulerCompileDef()); - map.put("NUMBER_OF_WORKERS", String.valueOf(targetConfig.get(new WorkersProperty()))); + map.put("SCHEDULER", targetConfig.get(SchedulerProperty.INSTANCE).getSchedulerCompileDef()); + map.put("NUMBER_OF_WORKERS", String.valueOf(targetConfig.get(WorkersProperty.INSTANCE))); CompileDefinitionsProperty.INSTANCE.update(targetConfig, map); } pickCompilePlatform(); diff --git a/core/src/main/java/org/lflang/generator/c/CMainFunctionGenerator.java b/core/src/main/java/org/lflang/generator/c/CMainFunctionGenerator.java index a6fc315d3a..03d340ffd3 100644 --- a/core/src/main/java/org/lflang/generator/c/CMainFunctionGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CMainFunctionGenerator.java @@ -109,10 +109,10 @@ private void parseTargetParameters() { runCommand.add("-k"); runCommand.add("true"); } - if (targetConfig.get(new TimeOutProperty()) != null) { + if (targetConfig.isSet(TimeOutProperty.INSTANCE)) { runCommand.add("-o"); - runCommand.add(targetConfig.get(new TimeOutProperty()).getMagnitude() + ""); - runCommand.add(targetConfig.get(new TimeOutProperty()).unit.getCanonicalName()); + runCommand.add(targetConfig.get(TimeOutProperty.INSTANCE).getMagnitude() + ""); + runCommand.add(targetConfig.get(TimeOutProperty.INSTANCE).unit.getCanonicalName()); } // The runCommand has a first entry that is ignored but needed. if (runCommand.size() > 0) { 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 dd0b5c5591..b55aad3792 100644 --- a/core/src/main/java/org/lflang/generator/c/CPreambleGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CPreambleGenerator.java @@ -44,11 +44,11 @@ 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(new ThreadingProperty())) { + if (targetConfig.get(ThreadingProperty.INSTANCE)) { code.pr("#include \"include/core/threaded/scheduler.h\""); } - if (targetConfig.get(new TracingProperty()).isEnabled()) { + if (targetConfig.get(TracingProperty.INSTANCE).isEnabled()) { code.pr("#include \"include/core/trace.h\""); } code.pr("#include \"include/core/mixed_radix.h\""); @@ -56,7 +56,7 @@ public static String generateIncludeStatements(TargetConfig targetConfig, boolea code.pr("#include \"include/core/environment.h\""); code.pr("int lf_reactor_c_main(int argc, const char* argv[]);"); - if (targetConfig.isSet(new FedSetupProperty())) { + if (targetConfig.isSet(FedSetupProperty.INSTANCE)) { code.pr("#include \"include/core/federated/federate.h\""); code.pr("#include \"include/core/federated/net_common.h\""); } @@ -68,7 +68,7 @@ public static String generateIncludeStatements(TargetConfig targetConfig, boolea public static String generateDefineDirectives(TargetConfig targetConfig, Path srcGenPath) { int logLevel = targetConfig.get(LoggingProperty.INSTANCE).ordinal(); - var tracing = targetConfig.get(new TracingProperty()); + var tracing = targetConfig.get(TracingProperty.INSTANCE); CodeBuilder code = new CodeBuilder(); // TODO: Get rid of all of these code.pr("#define LOG_LEVEL " + logLevel); @@ -84,12 +84,12 @@ public static String generateDefineDirectives(TargetConfig targetConfig, Path sr // )); // } - if (targetConfig.get(new ThreadingProperty())) { + if (targetConfig.get(ThreadingProperty.INSTANCE)) { definitions.put("LF_THREADED", "1"); } else { definitions.put("LF_UNTHREADED", "1"); } - if (targetConfig.get(new ThreadingProperty())) { + if (targetConfig.get(ThreadingProperty.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 16130a3152..8dcbda1e3a 100644 --- a/core/src/main/java/org/lflang/generator/c/CTriggerObjectsGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CTriggerObjectsGenerator.java @@ -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(new ThreadingProperty())) { + if (!targetConfig.get(ThreadingProperty.INSTANCE)) { return ""; } var code = new CodeBuilder(); diff --git a/core/src/main/java/org/lflang/target/TargetConfig.java b/core/src/main/java/org/lflang/target/TargetConfig.java index bc19efbb1a..f22090e810 100644 --- a/core/src/main/java/org/lflang/target/TargetConfig.java +++ b/core/src/main/java/org/lflang/target/TargetConfig.java @@ -48,14 +48,9 @@ import org.lflang.target.property.FastProperty; import org.lflang.target.property.LoggingProperty; import org.lflang.target.property.NoCompileProperty; -import org.lflang.target.property.SchedulerProperty; -import org.lflang.target.property.SingleFileProjectProperty; -import org.lflang.target.property.ThreadingProperty; import org.lflang.target.property.TimeOutProperty; import org.lflang.target.property.TracingProperty; -import org.lflang.target.property.WorkersProperty; import org.lflang.target.property.type.TargetPropertyType; -import org.lflang.target.property.type.VerifyProperty; import org.lflang.validation.ValidatorMessageReporter; /** @@ -86,13 +81,8 @@ public TargetConfig(Target target) { FastProperty.INSTANCE, LoggingProperty.INSTANCE, NoCompileProperty.INSTANCE, - new SchedulerProperty(), - new SingleFileProjectProperty(), - new ThreadingProperty(), - new TimeOutProperty(), - new TracingProperty(), - new VerifyProperty(), - new WorkersProperty()); + TimeOutProperty.INSTANCE, + TracingProperty.INSTANCE); } public TargetConfig(TargetDecl target, Properties cliArgs, MessageReporter messageReporter) { diff --git a/core/src/main/java/org/lflang/target/property/FedSetupProperty.java b/core/src/main/java/org/lflang/target/property/FedSetupProperty.java index b532448bfd..48c6544fb7 100644 --- a/core/src/main/java/org/lflang/target/property/FedSetupProperty.java +++ b/core/src/main/java/org/lflang/target/property/FedSetupProperty.java @@ -15,7 +15,10 @@ */ public class FedSetupProperty extends TargetProperty { - public FedSetupProperty() { + /** Singleton target property instance. */ + public static final FedSetupProperty INSTANCE = new FedSetupProperty(); + + private FedSetupProperty() { super(PrimitiveType.FILE); } 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 988ae43ccd..04de0d6562 100644 --- a/core/src/main/java/org/lflang/target/property/PlatformProperty.java +++ b/core/src/main/java/org/lflang/target/property/PlatformProperty.java @@ -80,7 +80,7 @@ public List supportedTargets() { @Override public void validate(KeyValuePair pair, Model ast, MessageReporter reporter) { var config = fromAst(pair.getValue(), reporter); - var threading = TargetProperty.getKeyValuePair(ast, new ThreadingProperty()); + var threading = TargetProperty.getKeyValuePair(ast, ThreadingProperty.INSTANCE); if (threading != null && config.platform == Platform.RP2040) { reporter .at(pair, Literals.KEY_VALUE_PAIR__VALUE) 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 7889c23e29..404235b722 100644 --- a/core/src/main/java/org/lflang/target/property/SchedulerProperty.java +++ b/core/src/main/java/org/lflang/target/property/SchedulerProperty.java @@ -16,7 +16,10 @@ /** Directive for specifying the use of a specific runtime scheduler. */ public final class SchedulerProperty extends TargetProperty { - public SchedulerProperty() { + /** Singleton target property instance. */ + public static final SchedulerProperty INSTANCE = new SchedulerProperty(); + + private SchedulerProperty() { super(new SchedulerType()); } diff --git a/core/src/main/java/org/lflang/target/property/SingleFileProjectProperty.java b/core/src/main/java/org/lflang/target/property/SingleFileProjectProperty.java index 952c0c9f01..a20646531b 100644 --- a/core/src/main/java/org/lflang/target/property/SingleFileProjectProperty.java +++ b/core/src/main/java/org/lflang/target/property/SingleFileProjectProperty.java @@ -4,7 +4,14 @@ import org.lflang.Target; /** Directive to specify that all code is generated in a single file. */ -public class SingleFileProjectProperty extends BooleanProperty { +public final class SingleFileProjectProperty extends BooleanProperty { + + /** Singleton target property instance. */ + public static final SingleFileProjectProperty INSTANCE = new SingleFileProjectProperty(); + + private SingleFileProjectProperty() { + super(); + } @Override public List supportedTargets() { diff --git a/core/src/main/java/org/lflang/target/property/ThreadingProperty.java b/core/src/main/java/org/lflang/target/property/ThreadingProperty.java index 0071899c81..db970ffc11 100644 --- a/core/src/main/java/org/lflang/target/property/ThreadingProperty.java +++ b/core/src/main/java/org/lflang/target/property/ThreadingProperty.java @@ -6,6 +6,13 @@ /** Directive to indicate whether the runtime should use multi-threading. */ public class ThreadingProperty extends BooleanProperty { + /** Singleton target property instance. */ + public static final ThreadingProperty INSTANCE = new ThreadingProperty(); + + private ThreadingProperty() { + super(); + } + @Override public List supportedTargets() { return List.of(Target.C, Target.CCPP, Target.Python, Target.Rust); diff --git a/core/src/main/java/org/lflang/target/property/TimeOutProperty.java b/core/src/main/java/org/lflang/target/property/TimeOutProperty.java index b853822e12..a27553c2a7 100644 --- a/core/src/main/java/org/lflang/target/property/TimeOutProperty.java +++ b/core/src/main/java/org/lflang/target/property/TimeOutProperty.java @@ -12,7 +12,10 @@ /** The timeout to be observed during execution of the program. */ public class TimeOutProperty extends TargetProperty { - public TimeOutProperty() { + /** Singleton target property instance. */ + public static final TimeOutProperty INSTANCE = new TimeOutProperty(); + + private TimeOutProperty() { super(PrimitiveType.TIME_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 b0298a500f..8d6ff8e17a 100644 --- a/core/src/main/java/org/lflang/target/property/TracingProperty.java +++ b/core/src/main/java/org/lflang/target/property/TracingProperty.java @@ -22,7 +22,10 @@ /** Directive to configure the runtime environment to perform tracing. */ public class TracingProperty extends TargetProperty { - public TracingProperty() { + /** Singleton target property instance. */ + public static final TracingProperty INSTANCE = new TracingProperty(); + + private TracingProperty() { super(UnionType.TRACING_UNION); } @@ -63,7 +66,7 @@ public List supportedTargets() { 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, new ThreadingProperty()); + var threading = TargetProperty.getKeyValuePair(ast, ThreadingProperty.INSTANCE); if (threading != null) { if (!ASTUtils.toBoolean(threading.getValue())) { reporter diff --git a/core/src/main/java/org/lflang/target/property/VerifyProperty.java b/core/src/main/java/org/lflang/target/property/VerifyProperty.java index 99317847f7..086e19ecce 100644 --- a/core/src/main/java/org/lflang/target/property/VerifyProperty.java +++ b/core/src/main/java/org/lflang/target/property/VerifyProperty.java @@ -5,7 +5,14 @@ import org.lflang.target.property.BooleanProperty; /** If true, check the generated verification model. The default is false. */ -public class VerifyProperty extends BooleanProperty { +public final class VerifyProperty extends BooleanProperty { + + /** Singleton target property instance. */ + public static final VerifyProperty INSTANCE = new VerifyProperty(); + + private VerifyProperty() { + super(); + } @Override public List supportedTargets() { 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 fab1b4bb82..d613f04dc2 100644 --- a/core/src/main/java/org/lflang/target/property/WorkersProperty.java +++ b/core/src/main/java/org/lflang/target/property/WorkersProperty.java @@ -12,9 +12,12 @@ * The number of worker threads to deploy. The default is zero, which indicates that the runtime is * allowed to freely choose the number of workers. */ -public class WorkersProperty extends TargetProperty { +public final class WorkersProperty extends TargetProperty { - public WorkersProperty() { + /** Singleton target property instance. */ + public static final WorkersProperty INSTANCE = new WorkersProperty(); + + private WorkersProperty() { super(PrimitiveType.NON_NEGATIVE_INTEGER); } diff --git a/core/src/main/kotlin/org/lflang/generator/cpp/CppRos2NodeGenerator.kt b/core/src/main/kotlin/org/lflang/generator/cpp/CppRos2NodeGenerator.kt index e9f042d93d..69629f06db 100644 --- a/core/src/main/kotlin/org/lflang/generator/cpp/CppRos2NodeGenerator.kt +++ b/core/src/main/kotlin/org/lflang/generator/cpp/CppRos2NodeGenerator.kt @@ -60,9 +60,9 @@ class CppRos2NodeGenerator( | |$nodeName::$nodeName(const rclcpp::NodeOptions& node_options) | : Node("$nodeName", node_options) { - | unsigned workers = ${if (targetConfig.get(WorkersProperty()) != 0) targetConfig.get(WorkersProperty()) else "std::thread::hardware_concurrency()"}; + | unsigned workers = ${if (targetConfig.get(WorkersProperty.INSTANCE) != 0) targetConfig.get(WorkersProperty.INSTANCE) else "std::thread::hardware_concurrency()"}; | bool fast{${targetConfig.get(FastProperty.INSTANCE)}}; - | reactor::Duration lf_timeout{${if (targetConfig.isSet(TimeOutProperty())) targetConfig.get(TimeOutProperty()).toCppCode() else "reactor::Duration::max()"}}; + | reactor::Duration lf_timeout{${if (targetConfig.isSet(TimeOutProperty.INSTANCE)) targetConfig.get(TimeOutProperty.INSTANCE).toCppCode() else "reactor::Duration::max()"}}; | | // provide a globally accessible reference to this node | // FIXME: this is pretty hacky... diff --git a/core/src/main/kotlin/org/lflang/generator/cpp/CppStandaloneMainGenerator.kt b/core/src/main/kotlin/org/lflang/generator/cpp/CppStandaloneMainGenerator.kt index e0ee61a755..870f9ee267 100644 --- a/core/src/main/kotlin/org/lflang/generator/cpp/CppStandaloneMainGenerator.kt +++ b/core/src/main/kotlin/org/lflang/generator/cpp/CppStandaloneMainGenerator.kt @@ -63,9 +63,9 @@ class CppStandaloneMainGenerator( |int main(int argc, char **argv) { | cxxopts::Options options("${fileConfig.name}", "Reactor Program"); | - | unsigned workers = ${if (targetConfig.get(WorkersProperty()) != 0) targetConfig.get(WorkersProperty()) else "std::thread::hardware_concurrency()"}; + | unsigned workers = ${if (targetConfig.get(WorkersProperty.INSTANCE) != 0) targetConfig.get(WorkersProperty.INSTANCE) else "std::thread::hardware_concurrency()"}; | bool fast{${targetConfig.get(FastProperty.INSTANCE)}}; - | reactor::Duration timeout = ${if (targetConfig.isSet(TimeOutProperty())) targetConfig.get(TimeOutProperty()).toCppCode() else "reactor::Duration::max()"}; + | reactor::Duration timeout = ${if (targetConfig.isSet(TimeOutProperty.INSTANCE)) targetConfig.get(TimeOutProperty.INSTANCE).toCppCode() else "reactor::Duration::max()"}; | | // the timeout variable needs to be tested beyond fitting the Duration-type | options 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 bd69d96f0a..060a3b1772 100644 --- a/core/src/main/kotlin/org/lflang/generator/rust/RustModel.kt +++ b/core/src/main/kotlin/org/lflang/generator/rust/RustModel.kt @@ -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()) } + val parallelFeature = listOf(PARALLEL_RT_FEATURE).takeIf { targetConfig.get(ThreadingProperty.INSTANCE) } val spec = newCargoSpec( features = parallelFeature, @@ -516,11 +516,11 @@ object RustModelBuilder { } // enable parallel feature if asked - if (targetConfig.get(ThreadingProperty())) { + if (targetConfig.get(ThreadingProperty.INSTANCE)) { userSpec.features += PARALLEL_RT_FEATURE } - if (!targetConfig.get(ThreadingProperty()) && PARALLEL_RT_FEATURE in userSpec.features) { + if (!targetConfig.get(ThreadingProperty.INSTANCE) && PARALLEL_RT_FEATURE in userSpec.features) { messageReporter.nowhere().warning("Threading cannot be disabled as it was enabled manually as a runtime feature.") } @@ -531,10 +531,10 @@ object RustModelBuilder { private fun TargetConfig.toRustProperties(): RustTargetProperties = RustTargetProperties( keepAlive = this.get(KeepaliveProperty.INSTANCE), - timeout = this.get(TimeOutProperty())?.toRustTimeExpr(), - timeoutLf = this.get(TimeOutProperty()), - singleFile = this.get(SingleFileProjectProperty()), - workers = this.get(WorkersProperty()), + timeout = this.get(TimeOutProperty.INSTANCE)?.toRustTimeExpr(), + timeoutLf = this.get(TimeOutProperty.INSTANCE), + singleFile = this.get(SingleFileProjectProperty.INSTANCE), + workers = this.get(WorkersProperty.INSTANCE), dumpDependencyGraph = this.get(ExportDependencyGraphProperty.INSTANCE), ) diff --git a/core/src/main/kotlin/org/lflang/generator/ts/TSParameterPreambleGenerator.kt b/core/src/main/kotlin/org/lflang/generator/ts/TSParameterPreambleGenerator.kt index bbb6611805..971fd22a62 100644 --- a/core/src/main/kotlin/org/lflang/generator/ts/TSParameterPreambleGenerator.kt +++ b/core/src/main/kotlin/org/lflang/generator/ts/TSParameterPreambleGenerator.kt @@ -53,7 +53,7 @@ class TSParameterPreambleGenerator( ) { private fun getTimeoutTimeValue(): String = - targetConfig.get(TimeOutProperty())?.toTsTime() ?: "undefined" + targetConfig.get(TimeOutProperty.INSTANCE)?.toTsTime() ?: "undefined" private fun getParameters(): List { var mainReactor: Reactor? = null diff --git a/core/src/testFixtures/java/org/lflang/tests/Configurators.java b/core/src/testFixtures/java/org/lflang/tests/Configurators.java index 5134ad2df7..9885985e01 100644 --- a/core/src/testFixtures/java/org/lflang/tests/Configurators.java +++ b/core/src/testFixtures/java/org/lflang/tests/Configurators.java @@ -68,7 +68,7 @@ public static boolean disableThreading(LFTest test) { public static boolean makeZephyrCompatibleUnthreaded(LFTest test) { test.getContext().getArgs().setProperty("tracing", "false"); - new ThreadingProperty().override(test.getContext().getTargetConfig(), false); + ThreadingProperty.INSTANCE.override(test.getContext().getTargetConfig(), false); // FIXME: use a record and override. test.getContext().getTargetConfig().get(PlatformProperty.INSTANCE).platform = Platform.ZEPHYR; test.getContext().getTargetConfig().get(PlatformProperty.INSTANCE).flash = false; From 33dc1b1a791d2fa4813a86678ed588e8141b314c Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Tue, 17 Oct 2023 14:46:32 -0700 Subject: [PATCH 098/145] Fixes to deal with PythonGenerator accessing (through CGenerator) properties that it does not support --- core/src/main/java/org/lflang/Target.java | 2 + .../main/java/org/lflang/TargetProperty.java | 34 -- .../lflang/generator/c/CCmakeGenerator.java | 362 +++++++++--------- .../org/lflang/generator/c/CCompiler.java | 13 +- .../org/lflang/generator/c/CGenerator.java | 223 +++++------ .../generator/c/CMainFunctionGenerator.java | 84 ++-- .../generator/c/CPreambleGenerator.java | 10 +- .../java/org/lflang/target/TargetConfig.java | 35 +- .../lflang/target/property/AuthProperty.java | 9 - .../property/BuildCommandsProperty.java | 7 - .../target/property/BuildTypeProperty.java | 8 - .../property/CargoDependenciesProperty.java | 8 - .../property/CargoFeaturesProperty.java | 9 - .../property/ClockSyncModeProperty.java | 7 - .../property/ClockSyncOptionsProperty.java | 8 - .../target/property/CmakeIncludeProperty.java | 7 - .../property/CompileDefinitionsProperty.java | 8 - .../property/CompilerFlagsProperty.java | 9 - .../target/property/CompilerProperty.java | 8 - .../property/CoordinationOptionsProperty.java | 8 - .../target/property/CoordinationProperty.java | 8 - .../target/property/DockerProperty.java | 8 - .../ExportDependencyGraphProperty.java | 8 - .../target/property/ExportToYamlProperty.java | 8 - .../property/ExternalRuntimePathProperty.java | 8 - .../lflang/target/property/FastProperty.java | 6 - .../target/property/FedSetupProperty.java | 7 - .../lflang/target/property/FilesProperty.java | 8 - .../property/HierarchicalBinProperty.java | 9 - .../target/property/KeepaliveProperty.java | 8 - .../target/property/LoggingProperty.java | 7 - .../target/property/NoCompileProperty.java | 9 - .../property/NoRuntimeValidationProperty.java | 8 - .../target/property/PlatformProperty.java | 24 +- .../property/PrintStatisticsProperty.java | 8 - .../target/property/ProtobufsProperty.java | 8 - .../property/Ros2DependenciesProperty.java | 6 - .../lflang/target/property/Ros2Property.java | 8 - .../property/RuntimeVersionProperty.java | 8 - .../target/property/RustIncludeProperty.java | 6 - .../target/property/SchedulerProperty.java | 8 - .../property/SingleFileProjectProperty.java | 8 - .../target/property/ThreadingProperty.java | 8 - .../target/property/TimeOutProperty.java | 7 - .../target/property/TracingProperty.java | 7 - .../target/property/VerifyProperty.java | 7 - .../target/property/WorkersProperty.java | 7 - .../compiler/LinguaFrancaValidationTest.java | 31 +- 48 files changed, 425 insertions(+), 687 deletions(-) diff --git a/core/src/main/java/org/lflang/Target.java b/core/src/main/java/org/lflang/Target.java index 33ddf7ea6e..774d802c05 100644 --- a/core/src/main/java/org/lflang/Target.java +++ b/core/src/main/java/org/lflang/Target.java @@ -622,6 +622,8 @@ public void initialize(TargetConfig config) { TracingProperty.INSTANCE, WorkersProperty.INSTANCE); case Python -> config.register( + AuthProperty.INSTANCE, + BuildCommandsProperty.INSTANCE, BuildTypeProperty.INSTANCE, ClockSyncModeProperty.INSTANCE, ClockSyncOptionsProperty.INSTANCE, diff --git a/core/src/main/java/org/lflang/TargetProperty.java b/core/src/main/java/org/lflang/TargetProperty.java index 4de4ecc5cb..0f388eda08 100644 --- a/core/src/main/java/org/lflang/TargetProperty.java +++ b/core/src/main/java/org/lflang/TargetProperty.java @@ -29,27 +29,6 @@ protected TargetProperty(S type) { this.type = type; } - /** - * If this target property is not supported by the given target, report a warning through the - * message reporter at the location of the given key-value pair. - * - * @param pair The ast node that matches this target property. - * @param target The target to check against. - * @param reporter The reporter to issue a warning through if this property is not supported by - * the given target. - */ - public void checkSupport(KeyValuePair pair, Target target, MessageReporter reporter) { - if (!this.isSupported(target)) { - reporter - .at(pair, Literals.KEY_VALUE_PAIR__NAME) - .warning( - String.format( - "The target property: %s is not supported by the %s target and will thus be" - + " ignored.", - pair.getName(), target)); - } - } - /** * If the given key-value pair does not match the type required by this target property, report an * error through the given reporter. @@ -66,16 +45,6 @@ public void checkType(KeyValuePair pair, MessageReporter reporter) { } } - /** - * Return {@code true} if this target property is supported by the given target, {@code false} - * otherwise. - * - * @param target The target to check against. - */ - public final boolean isSupported(Target target) { - return supportedTargets().contains(target); - } - @Override public String toString() { return this.name(); @@ -116,9 +85,6 @@ public void validate(KeyValuePair pair, Model ast, MessageReporter reporter) {} */ protected abstract T fromString(String string, MessageReporter reporter); - /** Return a list of targets that support this target property. */ - public abstract List supportedTargets(); - /** * Return an AST node that represents this target property and the value currently assigned to it. */ 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 c860f685a8..ce03c21d8f 100644 --- a/core/src/main/java/org/lflang/generator/c/CCmakeGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CCmakeGenerator.java @@ -32,9 +32,8 @@ import java.util.List; import java.util.stream.Stream; import org.lflang.FileConfig; -import org.lflang.MessageReporter; import org.lflang.generator.CodeBuilder; -import org.lflang.target.TargetConfig; +import org.lflang.generator.LFGeneratorContext; import org.lflang.target.property.AuthProperty; import org.lflang.target.property.BuildTypeProperty; import org.lflang.target.property.CmakeIncludeProperty; @@ -42,6 +41,7 @@ import org.lflang.target.property.CompilerFlagsProperty; import org.lflang.target.property.CompilerProperty; import org.lflang.target.property.PlatformProperty; +import org.lflang.target.property.PlatformProperty.PlatformOptions; import org.lflang.target.property.ProtobufsProperty; import org.lflang.target.property.ThreadingProperty; import org.lflang.target.property.WorkersProperty; @@ -95,25 +95,24 @@ public CCmakeGenerator( * will be reported in the 'errorReporter'. * * @param sources A list of .c files to build. - * @param executableName The name of the output executable. - * @param messageReporter Used to report errors. * @param CppMode Indicate if the compilation should happen in C++ mode * @param hasMain Indicate if the .lf file has a main reactor or not. If not, a library target * will be created instead of an executable. * @param cMakeExtras CMake-specific code that should be appended to the CMakeLists.txt. - * @param targetConfig The TargetConfig instance to use. + * @param context The context of the code generator. * @return The content of the CMakeLists.txt. */ CodeBuilder generateCMakeCode( List sources, - String executableName, - MessageReporter messageReporter, boolean CppMode, boolean hasMain, String cMakeExtras, - TargetConfig targetConfig) { + LFGeneratorContext context) { CodeBuilder cMakeCode = new CodeBuilder(); + var targetConfig = context.getTargetConfig(); + var messageReporter = context.getErrorReporter(); + List additionalSources = new ArrayList<>(); for (String file : targetConfig.compileAdditionalSources) { var relativePath = @@ -122,84 +121,13 @@ CodeBuilder generateCMakeCode( .relativize(fileConfig.getSrcGenPath().resolve(Paths.get(file))); additionalSources.add(FileUtil.toUnixString(relativePath)); } - // Parse board option of the platform target property - // Specified as a series of colon spaced options - // Board syntax - // rp2040 : - // arduino - String[] boardProperties = {}; - var platformOptions = targetConfig.get(PlatformProperty.INSTANCE); - if (platformOptions.board != null) { - boardProperties = platformOptions.board.trim().split(":"); - // Ignore whitespace - for (int i = 0; i < boardProperties.length; i++) { - boardProperties[i] = boardProperties[i].trim(); - } - } additionalSources.addAll(this.additionalSources); cMakeCode.newLine(); cMakeCode.pr("cmake_minimum_required(VERSION " + MIN_CMAKE_VERSION + ")"); - // Setup the project header for different platforms - switch (platformOptions.platform) { - case ZEPHYR: - cMakeCode.pr("# Set default configuration file. To add custom configurations,"); - cMakeCode.pr("# pass -- -DOVERLAY_CONFIG=my_config.prj to either cmake or west"); - cMakeCode.pr("set(CONF_FILE prj_lf.conf)"); - if (platformOptions.board != null) { - cMakeCode.pr("# Selecting board specified in target property"); - cMakeCode.pr("set(BOARD " + platformOptions.board + ")"); - } else { - cMakeCode.pr("# Selecting default board"); - cMakeCode.pr("set(BOARD qemu_cortex_m3)"); - } - cMakeCode.pr("# We recommend Zephyr v3.4.0 but we are compatible with older versions also"); - cMakeCode.pr("find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE} 3.4.0)"); - cMakeCode.newLine(); - cMakeCode.pr("project(" + executableName + " LANGUAGES C)"); - cMakeCode.newLine(); - break; - case RP2040: - // Attempt to set PICO_SDK_PATH if it is not already set. - if (System.getenv("PICO_SDK_PATH") == null) { - Path picoSDKPath = fileConfig.srcPkgPath.resolve("pico-sdk"); - if (Files.isDirectory(picoSDKPath)) { - messageReporter - .nowhere() - .info( - "pico-sdk library found at " - + picoSDKPath.toString() - + ". You can override this by setting PICO_SDK_PATH."); - cMakeCode.pr("# Define the root of the pico-sdk library."); - cMakeCode.pr("set(PICO_SDK_PATH " + picoSDKPath + ")"); - } else { - messageReporter - .nowhere() - .warning( - "No PICO_SDK_PATH environment variable and no pico-sdk directory " - + "at the package root directory. Pico SDK will not be found."); - } - } - cMakeCode.pr("include(pico_sdk_import.cmake)"); - cMakeCode.pr("project(" + executableName + " LANGUAGES C CXX ASM)"); - cMakeCode.newLine(); - // board type for rp2040 based boards - if (platformOptions.board != null) { - if (boardProperties.length < 1 || boardProperties[0].equals("")) { - cMakeCode.pr("set(PICO_BOARD pico)"); - } else { - cMakeCode.pr("set(PICO_BOARD \"" + boardProperties[0] + "\")"); - } - } - // remove warnings for rp2040 only to make debug easier - cMakeCode.pr("set(CMAKE_C_FLAGS \"${CMAKE_C_FLAGS} -w\")"); - break; - default: - cMakeCode.pr("project(" + executableName + " LANGUAGES C)"); - cMakeCode.newLine(); - } + preTargetDefinitionPlatformConfig(context, hasMain, sources, cMakeCode); // The Test build type is the Debug type plus coverage generation cMakeCode.pr("if(CMAKE_BUILD_TYPE STREQUAL \"Test\")"); @@ -229,7 +157,8 @@ CodeBuilder generateCMakeCode( cMakeCode.pr("set(CMAKE_CXX_STANDARD 17)"); cMakeCode.pr("set(CMAKE_CXX_STANDARD_REQUIRED ON)"); cMakeCode.newLine(); - if (!targetConfig.get(CmakeIncludeProperty.INSTANCE).isEmpty()) { + if (targetConfig.isSet(CmakeIncludeProperty.INSTANCE) + && !targetConfig.get(CmakeIncludeProperty.INSTANCE).isEmpty()) { // The user might be using the non-keyword form of // target_link_libraries. Ideally we would detect whether they are // doing that, but it is easier to just always have a deprecation @@ -260,54 +189,6 @@ CodeBuilder generateCMakeCode( cMakeCode.newLine(); } - if (platformOptions.platform != Platform.AUTO) { - cMakeCode.pr("set(CMAKE_SYSTEM_NAME " + platformOptions.platform.getcMakeName() + ")"); - } - cMakeCode.newLine(); - cMakeCode.pr("# Set default values for build parameters\n"); - targetConfig - .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.indent(); - var v = "TRUE"; - if (value != null && !value.isEmpty()) { - v = value; - } - cMakeCode.pr("set(" + key + " " + v + ")\n"); - cMakeCode.unindent(); - cMakeCode.pr("endif()\n"); - }); - - // Setup main target for different platforms - switch (platformOptions.platform) { - case ZEPHYR: - cMakeCode.pr( - setUpMainTargetZephyr( - hasMain, - executableName, - Stream.concat(additionalSources.stream(), sources.stream()))); - break; - case RP2040: - cMakeCode.pr( - setUpMainTargetRp2040( - hasMain, - executableName, - Stream.concat(additionalSources.stream(), sources.stream()))); - break; - default: - cMakeCode.pr( - setUpMainTarget.getCmakeCode( - hasMain, - executableName, - Stream.concat(additionalSources.stream(), sources.stream()))); - } - // Ensure that the math library is linked cMakeCode.pr("find_library(MATH_LIBRARY m)"); cMakeCode.pr("if(MATH_LIBRARY)"); @@ -324,45 +205,9 @@ CodeBuilder generateCMakeCode( cMakeCode.pr("target_include_directories(${LF_MAIN_TARGET} PUBLIC include/core/modal_models)"); cMakeCode.pr("target_include_directories(${LF_MAIN_TARGET} PUBLIC include/core/utils)"); - // post target definition board configurations - switch (platformOptions.platform) { - case RP2040: - // set stdio output - boolean usb = true; - boolean uart = true; - if (platformOptions.board != null && boardProperties.length > 1) { - uart = !boardProperties[1].equals("usb"); - usb = !boardProperties[1].equals("uart"); - } - cMakeCode.pr("pico_enable_stdio_usb(${LF_MAIN_TARGET} " + (usb ? 1 : 0) + ")"); - cMakeCode.pr("pico_enable_stdio_uart(${LF_MAIN_TARGET} " + (uart ? 1 : 0) + ")"); - break; - } - - if (targetConfig.get(AuthProperty.INSTANCE)) { - // If security is requested, add the auth option. - var osName = System.getProperty("os.name").toLowerCase(); - // if platform target was set, use given platform instead - if (platformOptions.platform != Platform.AUTO) { - osName = platformOptions.platform.toString(); - } - if (osName.contains("mac")) { - cMakeCode.pr("set(OPENSSL_ROOT_DIR /usr/local/opt/openssl)"); - } - cMakeCode.pr("# Find OpenSSL and link to it"); - cMakeCode.pr("find_package(OpenSSL REQUIRED)"); - cMakeCode.pr("target_link_libraries( ${LF_MAIN_TARGET} PRIVATE OpenSSL::SSL)"); - cMakeCode.newLine(); - } + buildParameterDefaults(cMakeCode, context); - if (targetConfig.get(ThreadingProperty.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)"); - cMakeCode.pr("target_link_libraries(${LF_MAIN_TARGET} PRIVATE Threads::Threads)"); - cMakeCode.newLine(); - } + postTargetDefinitionPlatformConfig(cMakeCode, context); // Add additional flags so runtime can distinguish between multi-threaded and single-threaded // mode @@ -428,18 +273,191 @@ CodeBuilder generateCMakeCode( cMakeCode.pr(installCode); cMakeCode.newLine(); - // Add the include file - for (String includeFile : targetConfig.get(CmakeIncludeProperty.INSTANCE)) { - cMakeCode.pr("include(\"" + Path.of(includeFile).getFileName() + "\")"); + if (targetConfig.isSet(CmakeIncludeProperty.INSTANCE)) { + // Add the include file + for (String includeFile : targetConfig.get(CmakeIncludeProperty.INSTANCE)) { + cMakeCode.pr("include(\"" + Path.of(includeFile).getFileName() + "\")"); + } + cMakeCode.newLine(); } - cMakeCode.newLine(); - cMakeCode.pr(cMakeExtras); cMakeCode.newLine(); return cMakeCode; } + private void postTargetDefinitionPlatformConfig( + CodeBuilder cMakeCode, LFGeneratorContext context) { + var targetConfig = context.getTargetConfig(); + + var platformOptions = new PlatformOptions(); + if (targetConfig.isSet(PlatformProperty.INSTANCE)) { + platformOptions = targetConfig.get(PlatformProperty.INSTANCE); + } + // post target definition board configurations + switch (platformOptions.platform) { + case RP2040: + // set stdio output + boolean usb = true; + boolean uart = true; + var boardProperties = platformOptions.boardArray(); + if (boardProperties.length > 1) { + uart = !boardProperties[1].equals("usb"); + usb = !boardProperties[1].equals("uart"); + } + cMakeCode.pr("pico_enable_stdio_usb(${LF_MAIN_TARGET} " + (usb ? 1 : 0) + ")"); + cMakeCode.pr("pico_enable_stdio_uart(${LF_MAIN_TARGET} " + (uart ? 1 : 0) + ")"); + break; + } + + if (targetConfig.get(AuthProperty.INSTANCE)) { + // If security is requested, add the auth option. + var osName = System.getProperty("os.name").toLowerCase(); + // if platform target was set, use given platform instead + if (platformOptions.platform != Platform.AUTO) { + osName = platformOptions.platform.toString(); + } + if (osName.contains("mac")) { + cMakeCode.pr("set(OPENSSL_ROOT_DIR /usr/local/opt/openssl)"); + } + cMakeCode.pr("# Find OpenSSL and link to it"); + cMakeCode.pr("find_package(OpenSSL REQUIRED)"); + cMakeCode.pr("target_link_libraries( ${LF_MAIN_TARGET} PRIVATE OpenSSL::SSL)"); + cMakeCode.newLine(); + } + + if (targetConfig.get(ThreadingProperty.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)"); + cMakeCode.pr("target_link_libraries(${LF_MAIN_TARGET} PRIVATE Threads::Threads)"); + cMakeCode.newLine(); + } + } + + private void buildParameterDefaults(CodeBuilder cMakeCode, LFGeneratorContext context) { + cMakeCode.newLine(); + cMakeCode.pr("# Set default values for build parameters\n"); + context + .getTargetConfig() + .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.indent(); + var v = "TRUE"; + if (value != null && !value.isEmpty()) { + v = value; + } + cMakeCode.pr("set(" + key + " " + v + ")\n"); + cMakeCode.unindent(); + cMakeCode.pr("endif()\n"); + }); + } + + private void preTargetDefinitionPlatformConfig( + LFGeneratorContext context, boolean hasMain, List sources, CodeBuilder cMakeCode) { + var targetConfig = context.getTargetConfig(); + var messageReporter = context.getErrorReporter(); + var executableName = context.getFileConfig().name; + var platformOptions = new PlatformOptions(); + if (targetConfig.isSet(PlatformProperty.INSTANCE)) { + platformOptions = targetConfig.get(PlatformProperty.INSTANCE); + } + + // Setup the project header for different platforms + switch (platformOptions.platform) { + case ZEPHYR: + cMakeCode.pr("# Set default configuration file. To add custom configurations,"); + cMakeCode.pr("# pass -- -DOVERLAY_CONFIG=my_config.prj to either cmake or west"); + cMakeCode.pr("set(CONF_FILE prj_lf.conf)"); + if (platformOptions.board != null) { + cMakeCode.pr("# Selecting board specified in target property"); + cMakeCode.pr("set(BOARD " + platformOptions.board + ")"); + } else { + cMakeCode.pr("# Selecting default board"); + cMakeCode.pr("set(BOARD qemu_cortex_m3)"); + } + cMakeCode.pr("# We recommend Zephyr v3.4.0 but we are compatible with older versions also"); + cMakeCode.pr("find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE} 3.4.0)"); + cMakeCode.newLine(); + cMakeCode.pr("project(" + executableName + " LANGUAGES C)"); + cMakeCode.newLine(); + break; + case RP2040: + // Attempt to set PICO_SDK_PATH if it is not already set. + if (System.getenv("PICO_SDK_PATH") == null) { + Path picoSDKPath = fileConfig.srcPkgPath.resolve("pico-sdk"); + if (Files.isDirectory(picoSDKPath)) { + messageReporter + .nowhere() + .info( + "pico-sdk library found at " + + picoSDKPath.toString() + + ". You can override this by setting PICO_SDK_PATH."); + cMakeCode.pr("# Define the root of the pico-sdk library."); + cMakeCode.pr("set(PICO_SDK_PATH " + picoSDKPath + ")"); + } else { + messageReporter + .nowhere() + .warning( + "No PICO_SDK_PATH environment variable and no pico-sdk directory " + + "at the package root directory. Pico SDK will not be found."); + } + } + cMakeCode.pr("include(pico_sdk_import.cmake)"); + cMakeCode.pr("project(" + executableName + " LANGUAGES C CXX ASM)"); + cMakeCode.newLine(); + var boardProperties = platformOptions.boardArray(); + // board type for rp2040 based boards + if (boardProperties.length < 1 || boardProperties[0].equals("")) { + cMakeCode.pr("set(PICO_BOARD pico)"); + } else { + cMakeCode.pr("set(PICO_BOARD \"" + boardProperties[0] + "\")"); + } + + // remove warnings for rp2040 only to make debug easier + cMakeCode.pr("set(CMAKE_C_FLAGS \"${CMAKE_C_FLAGS} -w\")"); + break; + default: + cMakeCode.pr("project(" + executableName + " LANGUAGES C)"); + cMakeCode.newLine(); + } + + if (platformOptions.platform != Platform.AUTO) { + cMakeCode.pr("set(CMAKE_SYSTEM_NAME " + platformOptions.platform.getcMakeName() + ")"); + } + + // Setup main target for different platforms + switch (platformOptions.platform) { + case ZEPHYR: + cMakeCode.pr( + setUpMainTargetZephyr( + hasMain, + executableName, + Stream.concat(additionalSources.stream(), sources.stream()))); + break; + case RP2040: + cMakeCode.pr( + setUpMainTargetRp2040( + hasMain, + executableName, + Stream.concat(additionalSources.stream(), sources.stream()))); + break; + default: + cMakeCode.pr( + setUpMainTarget.getCmakeCode( + hasMain, + executableName, + Stream.concat(additionalSources.stream(), sources.stream()))); + } + } + /** Provide a strategy for configuring the main target of the CMake build. */ public interface SetUpMainTarget { // Implementation note: This indirection is necessary because the Python diff --git a/core/src/main/java/org/lflang/generator/c/CCompiler.java b/core/src/main/java/org/lflang/generator/c/CCompiler.java index c46230caa2..f050b4d84f 100644 --- a/core/src/main/java/org/lflang/generator/c/CCompiler.java +++ b/core/src/main/java/org/lflang/generator/c/CCompiler.java @@ -445,13 +445,18 @@ public LFCommand compileCCommand(String fileToCompile, boolean noBinary) { * .cpp files instead of .c files and uses a C++ compiler to compiler the code. */ static String getTargetFileName(String fileName, boolean cppMode, TargetConfig targetConfig) { - if (targetConfig.get(PlatformProperty.INSTANCE).platform == Platform.ARDUINO) { - return fileName + ".ino"; + return fileName + getFileExtension(cppMode, targetConfig); + } + + static String getFileExtension(boolean cppMode, TargetConfig targetConfig) { + if (targetConfig.isSet(PlatformProperty.INSTANCE) + && targetConfig.get(PlatformProperty.INSTANCE).platform == Platform.ARDUINO) { + return ".ino"; } if (cppMode) { // If the C++ mode is enabled, use a .cpp extension - return fileName + ".cpp"; + return ".cpp"; } - return fileName + ".c"; + return ".c"; } } 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 f3b1fb8f2a..a13cd3c440 100644 --- a/core/src/main/java/org/lflang/generator/c/CGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CGenerator.java @@ -50,7 +50,6 @@ import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.xtext.xbase.lib.Exceptions; import org.eclipse.xtext.xbase.lib.IterableExtensions; -import org.eclipse.xtext.xbase.lib.StringExtensions; import org.lflang.FileConfig; import org.lflang.Target; import org.lflang.ast.ASTUtils; @@ -74,6 +73,7 @@ import org.lflang.generator.TargetTypes; import org.lflang.generator.TimerInstance; import org.lflang.generator.TriggerInstance; +import org.lflang.generator.python.PythonGenerator; import org.lflang.lf.Action; import org.lflang.lf.ActionOrigin; import org.lflang.lf.Input; @@ -315,7 +315,7 @@ public class CGenerator extends GeneratorBase { private int watchdogCount = 0; // Indicate whether the generator is in Cpp mode or not - private final boolean CCppMode; + private final boolean cppMode; private final CTypes types; @@ -323,13 +323,13 @@ public class CGenerator extends GeneratorBase { protected CGenerator( LFGeneratorContext context, - boolean CCppMode, + boolean cppMode, CTypes types, CCmakeGenerator cmakeGenerator, DelayBodyGenerator delayConnectionBodyGenerator) { super(context); this.fileConfig = (CFileConfig) context.getFileConfig(); - this.CCppMode = CCppMode; + this.cppMode = cppMode; this.types = types; this.cmakeGenerator = cmakeGenerator; @@ -381,7 +381,7 @@ public void accommodatePhysicalActionsIfPresent() { */ protected boolean isOSCompatible() { if (GeneratorUtils.isHostWindows()) { - if (CCppMode) { + if (cppMode) { messageReporter .nowhere() .error( @@ -418,7 +418,7 @@ public void doGenerate(Resource resource, LFGeneratorContext context) { // Derive target filename from the .lf filename. var lfModuleName = fileConfig.name; - var cFilename = CCompiler.getTargetFileName(lfModuleName, this.CCppMode, targetConfig); + var cFilename = CCompiler.getTargetFileName(lfModuleName, this.cppMode, targetConfig); var targetFile = fileConfig.getSrcGenPath() + File.separator + cFilename; try { generateCodeFor(lfModuleName); @@ -446,30 +446,23 @@ public void doGenerate(Resource resource, LFGeneratorContext context) { } // If cmake is requested, generate the CMakeLists.txt - if (targetConfig.get(PlatformProperty.INSTANCE).platform != Platform.ARDUINO) { + if (!targetConfig.isSet(PlatformProperty.INSTANCE)) { var cmakeFile = fileConfig.getSrcGenPath() + File.separator + "CMakeLists.txt"; var sources = allTypeParameterizedReactors() .map(CUtil::getName) - .map(it -> it + (CCppMode ? ".cpp" : ".c")) + .map(it -> it + (cppMode ? ".cpp" : ".c")) .collect(Collectors.toCollection(ArrayList::new)); sources.add(cFilename); var cmakeCode = - cmakeGenerator.generateCMakeCode( - sources, - lfModuleName, - messageReporter, - CCppMode, - mainDef != null, - cMakeExtras, - targetConfig); + cmakeGenerator.generateCMakeCode(sources, cppMode, mainDef != null, cMakeExtras, context); try { cmakeCode.writeToFile(cmakeFile); } catch (IOException e) { //noinspection ThrowableNotThrown,ResultOfMethodCallIgnored Exceptions.sneakyThrow(e); } - } else { + } else if (targetConfig.get(PlatformProperty.INSTANCE).platform == Platform.ARDUINO) { try { Path include = fileConfig.getSrcGenPath().resolve("include/"); Path src = fileConfig.getSrcGenPath().resolve("src/"); @@ -530,7 +523,7 @@ public void doGenerate(Resource resource, LFGeneratorContext context) { var generator = this; // FIXME: currently only passed to report errors with line numbers in the Eclipse // IDE - var CppMode = CCppMode; + var CppMode = cppMode; // generatingContext.reportProgress( // String.format("Generated code for %d/%d executables. Compiling...", federateCount, // federates.size()), @@ -630,7 +623,8 @@ private void generateCodeFor(String lfModuleName) throws IOException { // is set to decentralized) or, if there are // downstream federates, will notify the RTI // that the specified logical time is complete. - if (CCppMode || targetConfig.get(PlatformProperty.INSTANCE).platform == Platform.ARDUINO) + if (!(this instanceof PythonGenerator) + && (cppMode || targetConfig.get(PlatformProperty.INSTANCE).platform == Platform.ARDUINO)) code.pr("extern \"C\""); code.pr( String.join( @@ -738,22 +732,24 @@ protected void copyUserFiles(TargetConfig targetConfig, FileConfig fileConfig) { // Must use class variable to determine destination! var destination = this.fileConfig.getSrcGenPath(); - FileUtil.copyFilesOrDirectories( - targetConfig.get(CmakeIncludeProperty.INSTANCE), - destination, - fileConfig, - messageReporter, - true); + if (!(this instanceof PythonGenerator)) { + FileUtil.copyFilesOrDirectories( + targetConfig.get(CmakeIncludeProperty.INSTANCE), + destination, + fileConfig, + messageReporter, + true); + } - if (!StringExtensions.isNullOrEmpty(targetConfig.get(FedSetupProperty.INSTANCE))) { - try { - var file = targetConfig.get(FedSetupProperty.INSTANCE); - FileUtil.copyFile(fileConfig.srcFile.getParent().resolve(file), destination.resolve(file)); - } catch (IOException e) { - messageReporter - .nowhere() - .error("Failed to find _fed_setup file " + targetConfig.get(FedSetupProperty.INSTANCE)); - } + try { + var file = targetConfig.get(FedSetupProperty.INSTANCE); + FileUtil.copyFile(fileConfig.srcFile.getParent().resolve(file), destination.resolve(file)); + } catch (IOException e) { + messageReporter + .nowhere() + .error("Failed to find _fed_setup file " + targetConfig.get(FedSetupProperty.INSTANCE)); + } catch (IllegalArgumentException e) { + // No FedSetupProperty defined. } } @@ -882,36 +878,42 @@ protected void copyTargetFiles() throws IOException { // Copy the core lib String coreLib = LFGeneratorContext.BuildParm.EXTERNAL_RUNTIME_PATH.getValue(context); Path dest = fileConfig.getSrcGenPath(); - if (targetConfig.get(PlatformProperty.INSTANCE).platform == Platform.ARDUINO) { - dest = dest.resolve("src"); + + if (targetConfig.isSet(PlatformProperty.INSTANCE)) { + var platform = targetConfig.get(PlatformProperty.INSTANCE).platform; + switch (platform) { + case ARDUINO -> { + // For Arduino, alter the destination directory. + dest = dest.resolve("src"); + } + case ZEPHYR -> { + // For the Zephyr target, copy default config and board files. + FileUtil.copyFromClassPath( + "/lib/platform/zephyr/boards", fileConfig.getSrcGenPath(), false, false); + FileUtil.copyFileFromClassPath( + "/lib/platform/zephyr/prj_lf.conf", fileConfig.getSrcGenPath(), true); + + FileUtil.copyFileFromClassPath( + "/lib/platform/zephyr/Kconfig", fileConfig.getSrcGenPath(), true); + } + case RP2040 -> { + // For the pico src-gen, copy over vscode configurations for debugging + Path vscodePath = fileConfig.getSrcGenPath().resolve(".vscode"); + // If pico-sdk-path not defined, this can be used to pull the sdk into src-gen + FileUtil.copyFileFromClassPath( + "/lib/platform/rp2040/pico_sdk_import.cmake", fileConfig.getSrcGenPath(), true); + // VS Code configurations + FileUtil.copyFileFromClassPath("/lib/platform/rp2040/launch.json", vscodePath, true); + } + } } + if (coreLib != null) { FileUtil.copyDirectoryContents(Path.of(coreLib), dest, true); } else { FileUtil.copyFromClassPath("/lib/c/reactor-c/core", dest, true, false); FileUtil.copyFromClassPath("/lib/c/reactor-c/lib", dest, true, false); } - - // For the Zephyr target, copy default config and board files. - if (targetConfig.get(PlatformProperty.INSTANCE).platform == Platform.ZEPHYR) { - FileUtil.copyFromClassPath( - "/lib/platform/zephyr/boards", fileConfig.getSrcGenPath(), false, false); - FileUtil.copyFileFromClassPath( - "/lib/platform/zephyr/prj_lf.conf", fileConfig.getSrcGenPath(), true); - - FileUtil.copyFileFromClassPath( - "/lib/platform/zephyr/Kconfig", fileConfig.getSrcGenPath(), true); - } - - // For the pico src-gen, copy over vscode configurations for debugging - if (targetConfig.get(PlatformProperty.INSTANCE).platform == Platform.RP2040) { - Path vscodePath = fileConfig.getSrcGenPath().resolve(".vscode"); - // If pico-sdk-path not defined, this can be used to pull the sdk into src-gen - FileUtil.copyFileFromClassPath( - "/lib/platform/rp2040/pico_sdk_import.cmake", fileConfig.getSrcGenPath(), true); - // VS Code configurations - FileUtil.copyFileFromClassPath("/lib/platform/rp2040/launch.json", vscodePath, true); - } } //////////////////////////////////////////// @@ -950,10 +952,7 @@ private void generateReactorClass(TypeParameterizedReactor tpr) throws IOExcepti CodeMap.fromGeneratedCode(header.toString()).getGeneratedCode(), fileConfig.getSrcGenPath().resolve(headerName), true); - var extension = - targetConfig.get(PlatformProperty.INSTANCE).platform == Platform.ARDUINO - ? ".ino" - : CCppMode ? ".cpp" : ".c"; + var extension = CCompiler.getFileExtension(cppMode, targetConfig); FileUtil.writeToFile( CodeMap.fromGeneratedCode(src.toString()).getGeneratedCode(), fileConfig.getSrcGenPath().resolve(CUtil.getName(tpr) + extension), @@ -962,14 +961,14 @@ private void generateReactorClass(TypeParameterizedReactor tpr) throws IOExcepti protected void generateReactorClassHeaders( TypeParameterizedReactor tpr, String headerName, CodeBuilder header, CodeBuilder src) { - if (CCppMode) { + if (cppMode) { src.pr("extern \"C\" {"); header.pr("extern \"C\" {"); } header.pr("#include \"include/core/reactor.h\""); src.pr("#include \"include/api/api.h\""); generateIncludes(tpr); - if (CCppMode) { + if (cppMode) { src.pr("}"); header.pr("}"); } @@ -1942,55 +1941,59 @@ protected void setUpGeneralParameters() { // So that each separate compile knows about modal reactors, do this: CompileDefinitionsProperty.INSTANCE.update(targetConfig, Map.of("MODAL_REACTORS", "TRUE")); } - final var platformOptions = targetConfig.get(PlatformProperty.INSTANCE); - if (targetConfig.get(ThreadingProperty.INSTANCE) - && platformOptions.platform == Platform.ARDUINO - && (platformOptions.board == null || !platformOptions.board.contains("mbed"))) { - // non-MBED boards should not use threading - messageReporter - .nowhere() - .info( - "Threading is incompatible on your current Arduino flavor. Setting threading to" - + " false."); - ThreadingProperty.INSTANCE.override(targetConfig, false); - } + if (!(this instanceof PythonGenerator)) { - if (platformOptions.platform == Platform.ARDUINO - && !targetConfig.get(NoCompileProperty.INSTANCE) - && platformOptions.board == null) { - messageReporter - .nowhere() - .info( - "To enable compilation for the Arduino platform, you must specify the fully-qualified" - + " board name (FQBN) in the target property. For example, platform: {name:" - + " arduino, board: arduino:avr:leonardo}. Entering \"no-compile\" mode and" - + " generating target code only."); - NoCompileProperty.INSTANCE.override(targetConfig, true); - } + final var platformOptions = targetConfig.get(PlatformProperty.INSTANCE); + if (targetConfig.get(ThreadingProperty.INSTANCE) + && platformOptions.platform == Platform.ARDUINO + && (platformOptions.board == null || !platformOptions.board.contains("mbed"))) { + // non-MBED boards should not use threading + messageReporter + .nowhere() + .info( + "Threading is incompatible on your current Arduino flavor. Setting threading to" + + " false."); + ThreadingProperty.INSTANCE.override(targetConfig, false); + } - if (platformOptions.platform == Platform.ZEPHYR - && targetConfig.get(ThreadingProperty.INSTANCE) - && platformOptions.userThreads >= 0) { - targetConfig - .get(CompileDefinitionsProperty.INSTANCE) - .put(PlatformOption.USER_THREADS.name(), String.valueOf(platformOptions.userThreads)); - } else if (platformOptions.userThreads > 0) { - messageReporter - .nowhere() - .warning( - "Specifying user threads is only for threaded Lingua Franca on the Zephyr platform." - + " This option will be ignored."); - } + if (platformOptions.platform == Platform.ARDUINO + && !targetConfig.get(NoCompileProperty.INSTANCE) + && platformOptions.board == null) { + messageReporter + .nowhere() + .info( + "To enable compilation for the Arduino platform, you must specify the" + + " fully-qualified board name (FQBN) in the target property. For example," + + " platform: {name: arduino, board: arduino:avr:leonardo}. Entering" + + " \"no-compile\" mode and generating target code only."); + NoCompileProperty.INSTANCE.override(targetConfig, true); + } - if (targetConfig.get(ThreadingProperty.INSTANCE)) { // FIXME: This logic is duplicated in CMake - pickScheduler(); - // FIXME: this and pickScheduler should be combined. - var map = new HashMap(); - map.put("SCHEDULER", targetConfig.get(SchedulerProperty.INSTANCE).getSchedulerCompileDef()); - map.put("NUMBER_OF_WORKERS", String.valueOf(targetConfig.get(WorkersProperty.INSTANCE))); - CompileDefinitionsProperty.INSTANCE.update(targetConfig, map); + if (platformOptions.platform == Platform.ZEPHYR + && targetConfig.get(ThreadingProperty.INSTANCE) + && platformOptions.userThreads >= 0) { + targetConfig + .get(CompileDefinitionsProperty.INSTANCE) + .put(PlatformOption.USER_THREADS.name(), String.valueOf(platformOptions.userThreads)); + } else if (platformOptions.userThreads > 0) { + messageReporter + .nowhere() + .warning( + "Specifying user threads is only for threaded Lingua Franca on the Zephyr platform." + + " This option will be ignored."); + } + + if (targetConfig.get( + ThreadingProperty.INSTANCE)) { // FIXME: This logic is duplicated in CMake + pickScheduler(); + // FIXME: this and pickScheduler should be combined. + var map = new HashMap(); + map.put("SCHEDULER", targetConfig.get(SchedulerProperty.INSTANCE).getSchedulerCompileDef()); + map.put("NUMBER_OF_WORKERS", String.valueOf(targetConfig.get(WorkersProperty.INSTANCE))); + CompileDefinitionsProperty.INSTANCE.update(targetConfig, map); + } + pickCompilePlatform(); } - pickCompilePlatform(); } protected void handleProtoFiles() { @@ -2009,7 +2012,7 @@ public String generateDirectives() { code.prComment("Code generated by the Lingua Franca compiler from:"); code.prComment("file:/" + FileUtil.toUnixString(fileConfig.srcFile)); code.pr(CPreambleGenerator.generateDefineDirectives(targetConfig, fileConfig.getSrcGenPath())); - code.pr(CPreambleGenerator.generateIncludeStatements(targetConfig, CCppMode)); + code.pr(CPreambleGenerator.generateIncludeStatements(targetConfig, cppMode)); return code.toString(); } @@ -2040,7 +2043,7 @@ protected String generateTopLevelPreambles(Reactor reactor) { } protected boolean targetLanguageIsCpp() { - return CCppMode; + return cppMode; } /** diff --git a/core/src/main/java/org/lflang/generator/c/CMainFunctionGenerator.java b/core/src/main/java/org/lflang/generator/c/CMainFunctionGenerator.java index 03d340ffd3..dd5dbc9121 100644 --- a/core/src/main/java/org/lflang/generator/c/CMainFunctionGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CMainFunctionGenerator.java @@ -37,44 +37,52 @@ public String generateCode() { /** Generate the {@code main} function. */ private String generateMainFunction() { - if (targetConfig.get(PlatformProperty.INSTANCE).platform == Platform.ARDUINO) { - /** - * By default, we must have a serial begin line prior to calling lf_reactor_c_main due to - * internal debugging messages requiring a print buffer. For the future, we can check whether - * internal LF logging is enabled or not before removing this line. - Logging - */ - return String.join( - "\n", - "\nvoid _lf_arduino_print_message_function(const char* format, va_list args) {", - "\tchar buf[128];", - "\tvsnprintf(buf, 128, format, args);", - "\tSerial.print(buf);", - "}\n", - "// Arduino setup() and loop() functions", - "void setup() {", - "\tSerial.begin(" + targetConfig.get(PlatformProperty.INSTANCE).baudRate + ");", - "\tlf_register_print_function(&_lf_arduino_print_message_function, LOG_LEVEL);", - "\tlf_reactor_c_main(0, NULL);", - "}\n", - "void loop() {}"); - } else if (targetConfig.get(PlatformProperty.INSTANCE).platform == Platform.ZEPHYR) { - // The Zephyr "runtime" does not terminate when main returns. - // Rather, {@code exit} should be called explicitly. - return String.join( - "\n", - "void main(void) {", - " int res = lf_reactor_c_main(0, NULL);", - " exit(res);", - "}"); - } else if (targetConfig.get(PlatformProperty.INSTANCE).platform == Platform.RP2040) { - // Pico platform cannot use command line args. - return String.join("\n", "int main(void) {", " return lf_reactor_c_main(0, NULL);", "}"); - } else { - return String.join( - "\n", - "int main(int argc, const char* argv[]) {", - " return lf_reactor_c_main(argc, argv);", - "}"); + var platform = Platform.AUTO; + if (targetConfig.isSet(PlatformProperty.INSTANCE)) { + platform = targetConfig.get(PlatformProperty.INSTANCE).platform; + } + switch (platform) { + case ARDUINO -> { + /** + * By default, we must have a serial begin line prior to calling lf_reactor_c_main due to + * internal debugging messages requiring a print buffer. For the future, we can check + * whether internal LF logging is enabled or not before removing this line. - Logging + */ + return String.join( + "\n", + "\nvoid _lf_arduino_print_message_function(const char* format, va_list args) {", + "\tchar buf[128];", + "\tvsnprintf(buf, 128, format, args);", + "\tSerial.print(buf);", + "}\n", + "// Arduino setup() and loop() functions", + "void setup() {", + "\tSerial.begin(" + targetConfig.get(PlatformProperty.INSTANCE).baudRate + ");", + "\tlf_register_print_function(&_lf_arduino_print_message_function, LOG_LEVEL);", + "\tlf_reactor_c_main(0, NULL);", + "}\n", + "void loop() {}"); + } + case ZEPHYR -> { + // The Zephyr "runtime" does not terminate when main returns. + // Rather, {@code exit} should be called explicitly. + return String.join( + "\n", + "void main(void) {", + " int res = lf_reactor_c_main(0, NULL);", + " exit(res);", + "}"); + } + case RP2040 -> { + return String.join("\n", "int main(void) {", " return lf_reactor_c_main(0, NULL);", "}"); + } + default -> { + return String.join( + "\n", + "int main(int argc, const char* argv[]) {", + " return lf_reactor_c_main(argc, argv);", + "}"); + } } } 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 b55aad3792..58319a4f3b 100644 --- a/core/src/main/java/org/lflang/generator/c/CPreambleGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CPreambleGenerator.java @@ -31,11 +31,15 @@ * @author Anirudh Rengarajan */ public class CPreambleGenerator { + + private static boolean arduinoBased(TargetConfig targetConfig) { + return targetConfig.isSet(PlatformProperty.INSTANCE) + && targetConfig.get(PlatformProperty.INSTANCE).platform == Platform.ARDUINO; + } /** Add necessary source files specific to the target language. */ public static String generateIncludeStatements(TargetConfig targetConfig, boolean cppMode) { - CodeBuilder code = new CodeBuilder(); - if (cppMode || targetConfig.get(PlatformProperty.INSTANCE).platform == Platform.ARDUINO) { + if (cppMode || arduinoBased(targetConfig)) { code.pr("extern \"C\" {"); } code.pr("#include "); @@ -60,7 +64,7 @@ public static String generateIncludeStatements(TargetConfig targetConfig, boolea code.pr("#include \"include/core/federated/federate.h\""); code.pr("#include \"include/core/federated/net_common.h\""); } - if (cppMode || targetConfig.get(PlatformProperty.INSTANCE).platform == Platform.ARDUINO) { + if (cppMode || arduinoBased(targetConfig)) { code.pr("}"); } return code.toString(); diff --git a/core/src/main/java/org/lflang/target/TargetConfig.java b/core/src/main/java/org/lflang/target/TargetConfig.java index f22090e810..0e6a7999fb 100644 --- a/core/src/main/java/org/lflang/target/TargetConfig.java +++ b/core/src/main/java/org/lflang/target/TargetConfig.java @@ -134,8 +134,16 @@ public void reset(TargetProperty property) { /** Return the value currently assigned to the given target property. */ @SuppressWarnings("unchecked") - public T get(TargetProperty property) { - return (T) properties.get(property); + public T get(TargetProperty property) + throws IllegalArgumentException { + var value = properties.get(property); + if (value != null) { + return (T) value; + } + throw new IllegalArgumentException( + String.format( + "Attempting to access target property '%s', which is not supported by the %s target.", + property.name(), this.target)); } /** @@ -239,14 +247,14 @@ public static List extractProperties(TargetConfig config) { * @return A generated TargetDecl. */ public TargetDecl extractTargetDecl() { - TargetDecl decl = LfFactory.eINSTANCE.createTargetDecl(); + TargetDecl declaration = LfFactory.eINSTANCE.createTargetDecl(); KeyValuePairs kvp = LfFactory.eINSTANCE.createKeyValuePairs(); for (KeyValuePair p : extractProperties(this)) { kvp.getPairs().add(p); } - decl.setName(target.toString()); - decl.setConfig(kvp); - return decl; + declaration.setName(target.toString()); + declaration.setConfig(kvp); + return declaration; } /** @@ -259,7 +267,8 @@ public TargetDecl extractTargetDecl() { */ public static void validate( KeyValuePairs pairs, Model ast, TargetConfig config, ValidatorMessageReporter reporter) { - pairs.getPairs().stream() + pairs + .getPairs() .forEach( pair -> { var match = @@ -268,17 +277,19 @@ public static void validate( .findAny(); if (match.isPresent()) { var p = match.get(); - p.checkSupport(pair, config.target, reporter); p.checkType(pair, reporter); p.validate(pair, ast, reporter); } else { reporter .at(pair, Literals.KEY_VALUE_PAIR__NAME) .warning( - "Unrecognized target property: " - + pair.getName() - + ". Recognized properties are: " - + config.listOfRegisteredProperties()); + String.format( + "The target property '%s' is not supported by the %s target and will" + + " thus be ignored.", + pair.getName(), config.target)); + reporter + .at(pair, Literals.KEY_VALUE_PAIR__NAME) + .info("Recognized properties are: " + config.listOfRegisteredProperties()); } }); } diff --git a/core/src/main/java/org/lflang/target/property/AuthProperty.java b/core/src/main/java/org/lflang/target/property/AuthProperty.java index fd760153b5..e7e173e791 100644 --- a/core/src/main/java/org/lflang/target/property/AuthProperty.java +++ b/core/src/main/java/org/lflang/target/property/AuthProperty.java @@ -1,9 +1,5 @@ package org.lflang.target.property; -import java.util.Arrays; -import java.util.List; -import org.lflang.Target; - /** Directive to allow including OpenSSL libraries and process HMAC authentication. */ public final class AuthProperty extends BooleanProperty { @@ -14,11 +10,6 @@ private AuthProperty() { super(); } - @Override - public List supportedTargets() { - return Arrays.asList(Target.C, Target.CCPP); - } - @Override public String name() { return "auth"; diff --git a/core/src/main/java/org/lflang/target/property/BuildCommandsProperty.java b/core/src/main/java/org/lflang/target/property/BuildCommandsProperty.java index e5a31daf65..8d7df554a1 100644 --- a/core/src/main/java/org/lflang/target/property/BuildCommandsProperty.java +++ b/core/src/main/java/org/lflang/target/property/BuildCommandsProperty.java @@ -1,10 +1,8 @@ package org.lflang.target.property; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import org.lflang.MessageReporter; -import org.lflang.Target; import org.lflang.TargetProperty; import org.lflang.ast.ASTUtils; import org.lflang.lf.Element; @@ -39,11 +37,6 @@ protected List fromString(String string, MessageReporter reporter) { throw new UnsupportedOperationException("Not supported yet."); } - @Override - public List supportedTargets() { - return Arrays.asList(Target.C, Target.CCPP); - } - @Override public Element toAstElement(List value) { return ASTUtils.toElement(value); diff --git a/core/src/main/java/org/lflang/target/property/BuildTypeProperty.java b/core/src/main/java/org/lflang/target/property/BuildTypeProperty.java index 94559a490a..0adfb98024 100644 --- a/core/src/main/java/org/lflang/target/property/BuildTypeProperty.java +++ b/core/src/main/java/org/lflang/target/property/BuildTypeProperty.java @@ -1,9 +1,6 @@ package org.lflang.target.property; -import java.util.Arrays; -import java.util.List; import org.lflang.MessageReporter; -import org.lflang.Target; import org.lflang.TargetProperty; import org.lflang.ast.ASTUtils; import org.lflang.lf.Element; @@ -47,9 +44,4 @@ protected BuildType fromString(String string, MessageReporter reporter) { public String name() { return "build-type"; } - - @Override - public List supportedTargets() { - return Arrays.asList(Target.C, Target.CCPP, Target.CPP, Target.Rust); - } } 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 16c4fac5ce..d33d344b51 100644 --- a/core/src/main/java/org/lflang/target/property/CargoDependenciesProperty.java +++ b/core/src/main/java/org/lflang/target/property/CargoDependenciesProperty.java @@ -1,11 +1,8 @@ package org.lflang.target.property; -import java.util.Arrays; import java.util.HashMap; -import java.util.List; import java.util.Map; import org.lflang.MessageReporter; -import org.lflang.Target; import org.lflang.TargetProperty; import org.lflang.generator.rust.CargoDependencySpec; import org.lflang.generator.rust.CargoDependencySpec.CargoDependenciesPropertyType; @@ -64,11 +61,6 @@ protected Map fromString(String string, MessageRepo throw new UnsupportedOperationException("Not supported yet."); } - @Override - public List supportedTargets() { - return Arrays.asList(Target.Rust); - } - @Override public Element toAstElement(Map value) { if (value.size() == 0) { diff --git a/core/src/main/java/org/lflang/target/property/CargoFeaturesProperty.java b/core/src/main/java/org/lflang/target/property/CargoFeaturesProperty.java index 02308b9bc4..762def85ff 100644 --- a/core/src/main/java/org/lflang/target/property/CargoFeaturesProperty.java +++ b/core/src/main/java/org/lflang/target/property/CargoFeaturesProperty.java @@ -1,9 +1,5 @@ package org.lflang.target.property; -import java.util.Arrays; -import java.util.List; -import org.lflang.Target; - /** Directive for specifying Cargo features of the generated program to enable. */ public final class CargoFeaturesProperty extends StringListProperty { @@ -14,11 +10,6 @@ private CargoFeaturesProperty() { super(); } - @Override - public List supportedTargets() { - return Arrays.asList(Target.Rust); - } - @Override public String name() { return "cargo-features"; 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 70195d9de6..526983a09c 100644 --- a/core/src/main/java/org/lflang/target/property/ClockSyncModeProperty.java +++ b/core/src/main/java/org/lflang/target/property/ClockSyncModeProperty.java @@ -1,9 +1,7 @@ package org.lflang.target.property; -import java.util.List; import java.util.Objects; import org.lflang.MessageReporter; -import org.lflang.Target; import org.lflang.TargetProperty; import org.lflang.ast.ASTUtils; import org.lflang.lf.Element; @@ -40,11 +38,6 @@ protected ClockSyncMode fromString(String string, MessageReporter reporter) { return this.type.forName(string); } - @Override - public List supportedTargets() { - return List.of(Target.C, Target.CCPP, Target.Python); - } - @Override public void validate(KeyValuePair pair, Model ast, MessageReporter reporter) { super.validate(pair, ast, reporter); 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 b962f45d8e..4e87412ff4 100644 --- a/core/src/main/java/org/lflang/target/property/ClockSyncOptionsProperty.java +++ b/core/src/main/java/org/lflang/target/property/ClockSyncOptionsProperty.java @@ -1,9 +1,6 @@ package org.lflang.target.property; -import java.util.Arrays; -import java.util.List; import org.lflang.MessageReporter; -import org.lflang.Target; import org.lflang.TargetProperty; import org.lflang.TimeUnit; import org.lflang.TimeValue; @@ -58,11 +55,6 @@ protected ClockSyncOptions fromString(String string, MessageReporter reporter) { throw new UnsupportedOperationException("Not supported yet."); } - @Override - public List supportedTargets() { - return Arrays.asList(Target.C, Target.CCPP, Target.Python); - } - @Override public Element toAstElement(ClockSyncOptions value) { Element e = LfFactory.eINSTANCE.createElement(); diff --git a/core/src/main/java/org/lflang/target/property/CmakeIncludeProperty.java b/core/src/main/java/org/lflang/target/property/CmakeIncludeProperty.java index a8e4cc0527..a47379fef1 100644 --- a/core/src/main/java/org/lflang/target/property/CmakeIncludeProperty.java +++ b/core/src/main/java/org/lflang/target/property/CmakeIncludeProperty.java @@ -1,9 +1,7 @@ package org.lflang.target.property; -import java.util.Arrays; import java.util.List; import org.lflang.MessageReporter; -import org.lflang.Target; import org.lflang.ast.ASTUtils; import org.lflang.lf.Element; @@ -32,11 +30,6 @@ protected List fromString(String string, MessageReporter reporter) { throw new UnsupportedOperationException("Not supported yet."); } - @Override - public List supportedTargets() { - return Arrays.asList(Target.CPP, Target.C, Target.CCPP); - } - @Override public Element toAstElement(List value) { return ASTUtils.toElement(value); diff --git a/core/src/main/java/org/lflang/target/property/CompileDefinitionsProperty.java b/core/src/main/java/org/lflang/target/property/CompileDefinitionsProperty.java index 2bab9c7722..f1b2d2c4ed 100644 --- a/core/src/main/java/org/lflang/target/property/CompileDefinitionsProperty.java +++ b/core/src/main/java/org/lflang/target/property/CompileDefinitionsProperty.java @@ -1,11 +1,8 @@ package org.lflang.target.property; -import java.util.Arrays; import java.util.HashMap; -import java.util.List; import java.util.Map; import org.lflang.MessageReporter; -import org.lflang.Target; import org.lflang.TargetProperty; import org.lflang.ast.ASTUtils; import org.lflang.lf.Element; @@ -58,11 +55,6 @@ protected Map fromString(String string, MessageReporter reporter throw new UnsupportedOperationException("Not supported yet."); } - @Override - public List supportedTargets() { - return Arrays.asList(Target.C, Target.CCPP, Target.Python); - } - @Override public Element toAstElement(Map value) { return ASTUtils.toElement(value); diff --git a/core/src/main/java/org/lflang/target/property/CompilerFlagsProperty.java b/core/src/main/java/org/lflang/target/property/CompilerFlagsProperty.java index b5f4e24a28..d137cc769f 100644 --- a/core/src/main/java/org/lflang/target/property/CompilerFlagsProperty.java +++ b/core/src/main/java/org/lflang/target/property/CompilerFlagsProperty.java @@ -1,9 +1,5 @@ package org.lflang.target.property; -import java.util.Arrays; -import java.util.List; -import org.lflang.Target; - /** Flags to pass to the compiler, unless a build command has been specified. */ public final class CompilerFlagsProperty extends StringListProperty { @@ -14,11 +10,6 @@ private CompilerFlagsProperty() { super(); } - @Override - public List supportedTargets() { - return Arrays.asList(Target.C, Target.CCPP); - } - @Override public String name() { return "compiler-flags"; diff --git a/core/src/main/java/org/lflang/target/property/CompilerProperty.java b/core/src/main/java/org/lflang/target/property/CompilerProperty.java index 5701155fb0..f1ed1f2ebf 100644 --- a/core/src/main/java/org/lflang/target/property/CompilerProperty.java +++ b/core/src/main/java/org/lflang/target/property/CompilerProperty.java @@ -1,8 +1,5 @@ package org.lflang.target.property; -import java.util.List; -import org.lflang.Target; - /** The compiler to invoke, unless a build command has been specified. */ public final class CompilerProperty extends StringProperty { @@ -13,11 +10,6 @@ private CompilerProperty() { super(); } - @Override - public List supportedTargets() { - return List.of(Target.C, Target.CCPP, Target.CPP); - } - @Override public String name() { return "compiler"; 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 129c710b37..e8848ea933 100644 --- a/core/src/main/java/org/lflang/target/property/CoordinationOptionsProperty.java +++ b/core/src/main/java/org/lflang/target/property/CoordinationOptionsProperty.java @@ -1,10 +1,7 @@ package org.lflang.target.property; -import java.util.Arrays; -import java.util.List; import java.util.Objects; import org.lflang.MessageReporter; -import org.lflang.Target; import org.lflang.TargetProperty; import org.lflang.TimeValue; import org.lflang.ast.ASTUtils; @@ -52,11 +49,6 @@ protected CoordinationOptions fromString(String string, MessageReporter reporter throw new UnsupportedOperationException("Not supported yet."); } - @Override - public List supportedTargets() { - return Arrays.asList(Target.C, Target.CCPP, Target.Python, Target.TS); - } - @Override public Element toAstElement(CoordinationOptions value) { Element e = LfFactory.eINSTANCE.createElement(); diff --git a/core/src/main/java/org/lflang/target/property/CoordinationProperty.java b/core/src/main/java/org/lflang/target/property/CoordinationProperty.java index abe044e943..ed57cbedef 100644 --- a/core/src/main/java/org/lflang/target/property/CoordinationProperty.java +++ b/core/src/main/java/org/lflang/target/property/CoordinationProperty.java @@ -1,9 +1,6 @@ package org.lflang.target.property; -import java.util.Arrays; -import java.util.List; import org.lflang.MessageReporter; -import org.lflang.Target; import org.lflang.TargetProperty; import org.lflang.ast.ASTUtils; import org.lflang.lf.Element; @@ -39,11 +36,6 @@ protected CoordinationMode fromString(String string, MessageReporter reporter) { return ((CoordinationModeType) this.type).forName(string); } - @Override - public List supportedTargets() { - return Arrays.asList(Target.C, Target.CCPP, Target.Python); - } - @Override public Element toAstElement(CoordinationMode value) { return ASTUtils.toElement(value.toString()); 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 2132c6cd78..6e01b980eb 100644 --- a/core/src/main/java/org/lflang/target/property/DockerProperty.java +++ b/core/src/main/java/org/lflang/target/property/DockerProperty.java @@ -1,10 +1,7 @@ package org.lflang.target.property; -import java.util.Arrays; -import java.util.List; import java.util.Objects; import org.lflang.MessageReporter; -import org.lflang.Target; import org.lflang.TargetProperty; import org.lflang.ast.ASTUtils; import org.lflang.lf.Element; @@ -60,11 +57,6 @@ protected DockerOptions fromString(String string, MessageReporter reporter) { throw new UnsupportedOperationException("Not supported yet."); } - @Override - public List supportedTargets() { - return Arrays.asList(Target.C, Target.CCPP, Target.Python, Target.TS); - } - @Override public Element toAstElement(DockerOptions value) { if (!value.enabled) { diff --git a/core/src/main/java/org/lflang/target/property/ExportDependencyGraphProperty.java b/core/src/main/java/org/lflang/target/property/ExportDependencyGraphProperty.java index e06295cbb9..56a7935fee 100644 --- a/core/src/main/java/org/lflang/target/property/ExportDependencyGraphProperty.java +++ b/core/src/main/java/org/lflang/target/property/ExportDependencyGraphProperty.java @@ -1,8 +1,5 @@ package org.lflang.target.property; -import java.util.List; -import org.lflang.Target; - /** * If true, the resulting binary will output a graph visualizing all reaction dependencies. * @@ -18,11 +15,6 @@ private ExportDependencyGraphProperty() { super(); } - @Override - public List supportedTargets() { - return List.of(Target.CPP, Target.Rust); - } - @Override public String name() { return "export-dependency-graph"; diff --git a/core/src/main/java/org/lflang/target/property/ExportToYamlProperty.java b/core/src/main/java/org/lflang/target/property/ExportToYamlProperty.java index 5abe77895d..e592c3d8ec 100644 --- a/core/src/main/java/org/lflang/target/property/ExportToYamlProperty.java +++ b/core/src/main/java/org/lflang/target/property/ExportToYamlProperty.java @@ -1,8 +1,5 @@ package org.lflang.target.property; -import java.util.List; -import org.lflang.Target; - /** * If true, the resulting binary will output a yaml file describing the whole reactor structure of * the program. @@ -19,11 +16,6 @@ private ExportToYamlProperty() { super(); } - @Override - public List supportedTargets() { - return List.of(Target.CPP); - } - @Override public String name() { return "export-to-yaml"; diff --git a/core/src/main/java/org/lflang/target/property/ExternalRuntimePathProperty.java b/core/src/main/java/org/lflang/target/property/ExternalRuntimePathProperty.java index ff6ae354c5..b07b7dd60e 100644 --- a/core/src/main/java/org/lflang/target/property/ExternalRuntimePathProperty.java +++ b/core/src/main/java/org/lflang/target/property/ExternalRuntimePathProperty.java @@ -1,8 +1,5 @@ package org.lflang.target.property; -import java.util.List; -import org.lflang.Target; - /** * Directive for specifying a path to an external runtime libray to link to instead of the default * one. @@ -16,11 +13,6 @@ private ExternalRuntimePathProperty() { super(); } - @Override - public List supportedTargets() { - return List.of(Target.CPP, Target.Rust); - } - @Override public String name() { return "external-runtime-path"; 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 fee019c94e..b48ab9e6f7 100644 --- a/core/src/main/java/org/lflang/target/property/FastProperty.java +++ b/core/src/main/java/org/lflang/target/property/FastProperty.java @@ -1,6 +1,5 @@ package org.lflang.target.property; -import java.util.List; import org.lflang.MessageReporter; import org.lflang.Target; import org.lflang.ast.ASTUtils; @@ -24,11 +23,6 @@ private FastProperty() { super(); } - @Override - public List supportedTargets() { - return Target.ALL; - } - @Override public String name() { return "fast"; diff --git a/core/src/main/java/org/lflang/target/property/FedSetupProperty.java b/core/src/main/java/org/lflang/target/property/FedSetupProperty.java index 48c6544fb7..f19594c2ec 100644 --- a/core/src/main/java/org/lflang/target/property/FedSetupProperty.java +++ b/core/src/main/java/org/lflang/target/property/FedSetupProperty.java @@ -1,8 +1,6 @@ package org.lflang.target.property; -import java.util.List; import org.lflang.MessageReporter; -import org.lflang.Target; import org.lflang.TargetProperty; import org.lflang.ast.ASTUtils; import org.lflang.lf.Element; @@ -37,11 +35,6 @@ protected String fromString(String string, MessageReporter reporter) { return string; } - @Override - public List supportedTargets() { - return List.of(Target.C, Target.CCPP, Target.Python); - } - @Override public Element toAstElement(String value) { return ASTUtils.toElement(value); diff --git a/core/src/main/java/org/lflang/target/property/FilesProperty.java b/core/src/main/java/org/lflang/target/property/FilesProperty.java index c3dff093fc..877939c41d 100644 --- a/core/src/main/java/org/lflang/target/property/FilesProperty.java +++ b/core/src/main/java/org/lflang/target/property/FilesProperty.java @@ -1,8 +1,5 @@ package org.lflang.target.property; -import java.util.List; -import org.lflang.Target; - /** Directive to stage particular files on the class path to be processed by the code generator. */ public final class FilesProperty extends FileListProperty { @@ -13,11 +10,6 @@ private FilesProperty() { super(); } - @Override - public List supportedTargets() { - return List.of(Target.C, Target.CCPP, Target.Python); - } - @Override public String name() { return "files"; diff --git a/core/src/main/java/org/lflang/target/property/HierarchicalBinProperty.java b/core/src/main/java/org/lflang/target/property/HierarchicalBinProperty.java index 5fa11e7f37..dbd3a1ed6f 100644 --- a/core/src/main/java/org/lflang/target/property/HierarchicalBinProperty.java +++ b/core/src/main/java/org/lflang/target/property/HierarchicalBinProperty.java @@ -1,9 +1,5 @@ package org.lflang.target.property; -import java.util.Arrays; -import java.util.List; -import org.lflang.Target; - /** * Whether the bin directory should have a flat or hierarchical organization. It is flat by default. */ @@ -16,11 +12,6 @@ private HierarchicalBinProperty() { super(); } - @Override - public List supportedTargets() { - return Arrays.asList(Target.C, Target.CCPP); - } - @Override public String name() { return "hierarchical-bin"; diff --git a/core/src/main/java/org/lflang/target/property/KeepaliveProperty.java b/core/src/main/java/org/lflang/target/property/KeepaliveProperty.java index 8b639179c8..ee073abbe0 100644 --- a/core/src/main/java/org/lflang/target/property/KeepaliveProperty.java +++ b/core/src/main/java/org/lflang/target/property/KeepaliveProperty.java @@ -1,8 +1,5 @@ package org.lflang.target.property; -import java.util.List; -import org.lflang.Target; - /** * If true, configure the execution environment to keep executing if there are no more events on the * event queue. The default is false. @@ -16,11 +13,6 @@ private KeepaliveProperty() { super(); } - @Override - public List supportedTargets() { - return List.of(Target.C, Target.CCPP, Target.Python, Target.TS, Target.Rust); - } - @Override public String name() { return "keepalive"; diff --git a/core/src/main/java/org/lflang/target/property/LoggingProperty.java b/core/src/main/java/org/lflang/target/property/LoggingProperty.java index 051b17c5de..ef6d47cbb9 100644 --- a/core/src/main/java/org/lflang/target/property/LoggingProperty.java +++ b/core/src/main/java/org/lflang/target/property/LoggingProperty.java @@ -1,8 +1,6 @@ package org.lflang.target.property; -import java.util.List; import org.lflang.MessageReporter; -import org.lflang.Target; import org.lflang.TargetProperty; import org.lflang.ast.ASTUtils; import org.lflang.lf.Element; @@ -36,11 +34,6 @@ protected LogLevel fromString(String string, MessageReporter reporter) { return LogLevel.valueOf(string.toUpperCase()); } - @Override - public List supportedTargets() { - return Target.ALL; - } - @Override public Element toAstElement(LogLevel value) { return ASTUtils.toElement(value.toString()); diff --git a/core/src/main/java/org/lflang/target/property/NoCompileProperty.java b/core/src/main/java/org/lflang/target/property/NoCompileProperty.java index 6e06552c8f..906899ca92 100644 --- a/core/src/main/java/org/lflang/target/property/NoCompileProperty.java +++ b/core/src/main/java/org/lflang/target/property/NoCompileProperty.java @@ -1,9 +1,5 @@ package org.lflang.target.property; -import java.util.Arrays; -import java.util.List; -import org.lflang.Target; - /** If true, do not invoke the target compiler or build command. The default is false. */ public final class NoCompileProperty extends BooleanProperty { @@ -14,11 +10,6 @@ private NoCompileProperty() { super(); } - @Override - public List supportedTargets() { - return Arrays.asList(Target.C, Target.CPP, Target.CCPP, Target.Python); - } - @Override public String name() { return "no-compile"; diff --git a/core/src/main/java/org/lflang/target/property/NoRuntimeValidationProperty.java b/core/src/main/java/org/lflang/target/property/NoRuntimeValidationProperty.java index a6eb771d2f..81720c4960 100644 --- a/core/src/main/java/org/lflang/target/property/NoRuntimeValidationProperty.java +++ b/core/src/main/java/org/lflang/target/property/NoRuntimeValidationProperty.java @@ -1,8 +1,5 @@ package org.lflang.target.property; -import java.util.List; -import org.lflang.Target; - /** If true, do not perform runtime validation. The default is false. */ public final class NoRuntimeValidationProperty extends BooleanProperty { @@ -13,11 +10,6 @@ private NoRuntimeValidationProperty() { super(); } - @Override - public List supportedTargets() { - return List.of(Target.CPP); - } - @Override public String name() { return "no-runtime-validation"; 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 04de0d6562..67dffe336b 100644 --- a/core/src/main/java/org/lflang/target/property/PlatformProperty.java +++ b/core/src/main/java/org/lflang/target/property/PlatformProperty.java @@ -1,8 +1,6 @@ package org.lflang.target.property; -import java.util.List; import org.lflang.MessageReporter; -import org.lflang.Target; import org.lflang.TargetProperty; import org.lflang.ast.ASTUtils; import org.lflang.lf.Element; @@ -72,11 +70,6 @@ protected PlatformOptions fromString(String string, MessageReporter reporter) { throw new UnsupportedOperationException("Not supported yet."); } - @Override - public List supportedTargets() { - return List.of(Target.C); - } - @Override public void validate(KeyValuePair pair, Model ast, MessageReporter reporter) { var config = fromAst(pair.getValue(), reporter); @@ -158,6 +151,23 @@ public static class PlatformOptions { // FIXME: use a record for this * Zephyr. */ public int userThreads = 0; + + public String[] boardArray() { + // Parse board option of the platform target property + // Specified as a series of colon spaced options + // Board syntax + // rp2040 : + // arduino + String[] boardProperties = {}; + if (this.board != null) { + boardProperties = this.board.trim().split(":"); + // Ignore whitespace + for (int i = 0; i < boardProperties.length; i++) { + boardProperties[i] = boardProperties[i].trim(); + } + } + return boardProperties; + } } /** diff --git a/core/src/main/java/org/lflang/target/property/PrintStatisticsProperty.java b/core/src/main/java/org/lflang/target/property/PrintStatisticsProperty.java index 78b2ffd681..a193e25417 100644 --- a/core/src/main/java/org/lflang/target/property/PrintStatisticsProperty.java +++ b/core/src/main/java/org/lflang/target/property/PrintStatisticsProperty.java @@ -1,8 +1,5 @@ package org.lflang.target.property; -import java.util.List; -import org.lflang.Target; - /** If true, instruct the runtime to collect and print execution statistics. */ public final class PrintStatisticsProperty extends BooleanProperty { @@ -13,11 +10,6 @@ private PrintStatisticsProperty() { super(); } - @Override - public List supportedTargets() { - return List.of(Target.CPP); - } - @Override public String name() { return "print-statistics"; diff --git a/core/src/main/java/org/lflang/target/property/ProtobufsProperty.java b/core/src/main/java/org/lflang/target/property/ProtobufsProperty.java index 6845fb4c77..c70049e3d3 100644 --- a/core/src/main/java/org/lflang/target/property/ProtobufsProperty.java +++ b/core/src/main/java/org/lflang/target/property/ProtobufsProperty.java @@ -1,8 +1,5 @@ package org.lflang.target.property; -import java.util.List; -import org.lflang.Target; - /** * Directive for specifying .proto files that need to be compiled and their code included in the * sources. @@ -16,11 +13,6 @@ private ProtobufsProperty() { super(); } - @Override - public List supportedTargets() { - return List.of(Target.C, Target.CCPP, Target.TS, Target.Python); - } - @Override public String name() { return "protobufs"; 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 7dcd052083..620970ec00 100644 --- a/core/src/main/java/org/lflang/target/property/Ros2DependenciesProperty.java +++ b/core/src/main/java/org/lflang/target/property/Ros2DependenciesProperty.java @@ -3,7 +3,6 @@ import java.util.ArrayList; import java.util.List; import org.lflang.MessageReporter; -import org.lflang.Target; import org.lflang.TargetProperty; import org.lflang.ast.ASTUtils; import org.lflang.lf.Element; @@ -37,11 +36,6 @@ protected List fromString(String string, MessageReporter reporter) { throw new UnsupportedOperationException("Not supported yet."); } - @Override - public List supportedTargets() { - return List.of(Target.CPP); - } - @Override public void validate(KeyValuePair pair, Model ast, MessageReporter reporter) { var ros2enabled = TargetProperty.getKeyValuePair(ast, Ros2Property.INSTANCE); diff --git a/core/src/main/java/org/lflang/target/property/Ros2Property.java b/core/src/main/java/org/lflang/target/property/Ros2Property.java index f764fa9ce4..9138e0aca7 100644 --- a/core/src/main/java/org/lflang/target/property/Ros2Property.java +++ b/core/src/main/java/org/lflang/target/property/Ros2Property.java @@ -1,8 +1,5 @@ package org.lflang.target.property; -import java.util.List; -import org.lflang.Target; - /** If true, generate ROS2 specific code. */ public final class Ros2Property extends BooleanProperty { @@ -13,11 +10,6 @@ private Ros2Property() { super(); } - @Override - public List supportedTargets() { - return List.of(Target.CPP); - } - @Override public String name() { return "ros2"; diff --git a/core/src/main/java/org/lflang/target/property/RuntimeVersionProperty.java b/core/src/main/java/org/lflang/target/property/RuntimeVersionProperty.java index eda304a216..be82a06848 100644 --- a/core/src/main/java/org/lflang/target/property/RuntimeVersionProperty.java +++ b/core/src/main/java/org/lflang/target/property/RuntimeVersionProperty.java @@ -1,8 +1,5 @@ package org.lflang.target.property; -import java.util.List; -import org.lflang.Target; - /** Directive for specifying a specific version of the reactor runtime library. */ public final class RuntimeVersionProperty extends StringProperty { @@ -13,11 +10,6 @@ private RuntimeVersionProperty() { super(); } - @Override - public List supportedTargets() { - return List.of(Target.CPP, Target.Rust); - } - @Override public String name() { return "runtime-version"; diff --git a/core/src/main/java/org/lflang/target/property/RustIncludeProperty.java b/core/src/main/java/org/lflang/target/property/RustIncludeProperty.java index a5ba132010..a2d9001e26 100644 --- a/core/src/main/java/org/lflang/target/property/RustIncludeProperty.java +++ b/core/src/main/java/org/lflang/target/property/RustIncludeProperty.java @@ -6,7 +6,6 @@ import java.util.List; import org.eclipse.emf.ecore.EObject; import org.lflang.MessageReporter; -import org.lflang.Target; import org.lflang.TargetProperty; import org.lflang.ast.ASTUtils; import org.lflang.lf.Array; @@ -31,11 +30,6 @@ private RustIncludeProperty() { super(UnionType.FILE_OR_FILE_ARRAY); } - @Override - public List supportedTargets() { - return List.of(Target.Rust); - } - @Override public List initialValue() { return new ArrayList<>(); 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 404235b722..d4c64d2dc3 100644 --- a/core/src/main/java/org/lflang/target/property/SchedulerProperty.java +++ b/core/src/main/java/org/lflang/target/property/SchedulerProperty.java @@ -1,9 +1,6 @@ package org.lflang.target.property; -import java.util.Arrays; -import java.util.List; import org.lflang.MessageReporter; -import org.lflang.Target; import org.lflang.TargetProperty; import org.lflang.ast.ASTUtils; import org.lflang.lf.Element; @@ -43,11 +40,6 @@ protected Scheduler fromString(String string, MessageReporter reporter) { return this.type.forName(string); } - @Override - public List supportedTargets() { - return Arrays.asList(Target.C, Target.CCPP, Target.Python); - } - @Override public Element toAstElement(Scheduler value) { return ASTUtils.toElement(value.toString()); diff --git a/core/src/main/java/org/lflang/target/property/SingleFileProjectProperty.java b/core/src/main/java/org/lflang/target/property/SingleFileProjectProperty.java index a20646531b..21d795526b 100644 --- a/core/src/main/java/org/lflang/target/property/SingleFileProjectProperty.java +++ b/core/src/main/java/org/lflang/target/property/SingleFileProjectProperty.java @@ -1,8 +1,5 @@ package org.lflang.target.property; -import java.util.List; -import org.lflang.Target; - /** Directive to specify that all code is generated in a single file. */ public final class SingleFileProjectProperty extends BooleanProperty { @@ -13,11 +10,6 @@ private SingleFileProjectProperty() { super(); } - @Override - public List supportedTargets() { - return List.of(Target.Rust); - } - @Override public String name() { return "single-file-project"; diff --git a/core/src/main/java/org/lflang/target/property/ThreadingProperty.java b/core/src/main/java/org/lflang/target/property/ThreadingProperty.java index db970ffc11..f953dc8f1d 100644 --- a/core/src/main/java/org/lflang/target/property/ThreadingProperty.java +++ b/core/src/main/java/org/lflang/target/property/ThreadingProperty.java @@ -1,8 +1,5 @@ package org.lflang.target.property; -import java.util.List; -import org.lflang.Target; - /** Directive to indicate whether the runtime should use multi-threading. */ public class ThreadingProperty extends BooleanProperty { @@ -13,11 +10,6 @@ private ThreadingProperty() { super(); } - @Override - public List supportedTargets() { - return List.of(Target.C, Target.CCPP, Target.Python, Target.Rust); - } - @Override public String name() { return "threading"; diff --git a/core/src/main/java/org/lflang/target/property/TimeOutProperty.java b/core/src/main/java/org/lflang/target/property/TimeOutProperty.java index a27553c2a7..1fb4071184 100644 --- a/core/src/main/java/org/lflang/target/property/TimeOutProperty.java +++ b/core/src/main/java/org/lflang/target/property/TimeOutProperty.java @@ -1,8 +1,6 @@ package org.lflang.target.property; -import java.util.List; import org.lflang.MessageReporter; -import org.lflang.Target; import org.lflang.TargetProperty; import org.lflang.TimeValue; import org.lflang.ast.ASTUtils; @@ -34,11 +32,6 @@ protected TimeValue fromString(String string, MessageReporter reporter) { throw new UnsupportedOperationException("Not supported yet."); } - @Override - public List supportedTargets() { - return Target.ALL; - } - @Override public Element toAstElement(TimeValue value) { return ASTUtils.toElement(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 8d6ff8e17a..b236bcad04 100644 --- a/core/src/main/java/org/lflang/target/property/TracingProperty.java +++ b/core/src/main/java/org/lflang/target/property/TracingProperty.java @@ -1,9 +1,7 @@ package org.lflang.target.property; -import java.util.List; import java.util.Objects; import org.lflang.MessageReporter; -import org.lflang.Target; import org.lflang.TargetProperty; import org.lflang.ast.ASTUtils; import org.lflang.lf.Element; @@ -57,11 +55,6 @@ protected TracingOptions fromString(String string, MessageReporter reporter) { throw new UnsupportedOperationException("Not supported yet."); } - @Override - public List supportedTargets() { - return List.of(Target.C, Target.CCPP, Target.CPP, Target.Python); - } - @Override public void validate(KeyValuePair pair, Model ast, MessageReporter reporter) { if (pair != null && this.fromAst(pair.getValue(), reporter) != null) { diff --git a/core/src/main/java/org/lflang/target/property/VerifyProperty.java b/core/src/main/java/org/lflang/target/property/VerifyProperty.java index 086e19ecce..f13d60a4b7 100644 --- a/core/src/main/java/org/lflang/target/property/VerifyProperty.java +++ b/core/src/main/java/org/lflang/target/property/VerifyProperty.java @@ -1,7 +1,5 @@ package org.lflang.target.property.type; -import java.util.List; -import org.lflang.Target; import org.lflang.target.property.BooleanProperty; /** If true, check the generated verification model. The default is false. */ @@ -14,11 +12,6 @@ private VerifyProperty() { super(); } - @Override - public List supportedTargets() { - return List.of(Target.C); - } - @Override public String name() { return "verify"; 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 d613f04dc2..79a86a4c79 100644 --- a/core/src/main/java/org/lflang/target/property/WorkersProperty.java +++ b/core/src/main/java/org/lflang/target/property/WorkersProperty.java @@ -1,8 +1,6 @@ package org.lflang.target.property; -import java.util.List; import org.lflang.MessageReporter; -import org.lflang.Target; import org.lflang.TargetProperty; import org.lflang.ast.ASTUtils; import org.lflang.lf.Element; @@ -36,11 +34,6 @@ protected Integer fromAst(Element node, MessageReporter reporter) { return ASTUtils.toInteger(node); } - @Override - public List supportedTargets() { - return List.of(Target.C, Target.CCPP, Target.Python, Target.CPP, Target.Rust); - } - @Override public Element toAstElement(Integer value) { return ASTUtils.toElement(value); 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 037a779a77..fb3e4a2e27 100644 --- a/core/src/test/java/org/lflang/tests/compiler/LinguaFrancaValidationTest.java +++ b/core/src/test/java/org/lflang/tests/compiler/LinguaFrancaValidationTest.java @@ -1830,10 +1830,15 @@ public void testInvalidTargetParam() throws Exception { target C { foobarbaz: true } main reactor {} """; - List issues = validator.validate(parseWithoutError(testCase)); - Assertions.assertTrue( - issues.size() == 1 - && issues.get(0).getMessage().contains("Unrecognized target property: foobarbaz")); + var model = parseWithoutError(testCase); + List issues = validator.validate(model); + Assertions.assertTrue(issues.size() == 2); + validator.assertWarning( + model, + LfPackage.eINSTANCE.getKeyValuePair(), + null, + "The target property 'foobarbaz' is not supported by the C target and will thus be" + + " ignored."); } @Test @@ -1843,15 +1848,15 @@ public void testTargetParamNotSupportedForTarget() throws Exception { target Python { cargo-features: "" } main reactor {} """; - List issues = validator.validate(parseWithoutError(testCase)); - Assertions.assertTrue( - issues.size() == 1 - && issues - .get(0) - .getMessage() - .contains( - "The target property: cargo-features" - + " is not supported by the Python target and will thus be ignored.")); + var model = parseWithoutError(testCase); + List issues = validator.validate(model); + Assertions.assertTrue(issues.size() == 2); + validator.assertWarning( + model, + LfPackage.eINSTANCE.getKeyValuePair(), + null, + "The target property 'cargo-features' is not supported by the Python target and will thus" + + " be ignored."); } @Test From b131cba90520b222e662b76c8158c72124dd081f Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Tue, 17 Oct 2023 14:50:29 -0700 Subject: [PATCH 099/145] Fix compilation --- .../kotlin/org/lflang/generator/cpp/CppPlatformGenerator.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/kotlin/org/lflang/generator/cpp/CppPlatformGenerator.kt b/core/src/main/kotlin/org/lflang/generator/cpp/CppPlatformGenerator.kt index f52bf0a9f3..220770b6a9 100644 --- a/core/src/main/kotlin/org/lflang/generator/cpp/CppPlatformGenerator.kt +++ b/core/src/main/kotlin/org/lflang/generator/cpp/CppPlatformGenerator.kt @@ -33,7 +33,7 @@ abstract class CppPlatformGenerator(protected val generator: CppGenerator) { "-DCMAKE_BUILD_TYPE=${targetConfig.get(BuildTypeProperty.INSTANCE)}", "-DREACTOR_CPP_VALIDATE=${if (targetConfig.get(NoRuntimeValidationProperty.INSTANCE)) "OFF" else "ON"}", "-DREACTOR_CPP_PRINT_STATISTICS=${if (targetConfig.get(PrintStatisticsProperty.INSTANCE)) "ON" else "OFF"}", - "-DREACTOR_CPP_TRACE=${if (targetConfig.get(TracingProperty()).isEnabled) "ON" else "OFF"}", + "-DREACTOR_CPP_TRACE=${if (targetConfig.get(TracingProperty.INSTANCE).isEnabled) "ON" else "OFF"}", "-DREACTOR_CPP_LOG_LEVEL=${targetConfig.get(LoggingProperty.INSTANCE).severity}", "-DLF_SRC_PKG_PATH=${fileConfig.srcPkgPath}", ) From 47686d44c38db310d12e3f82b010f3cfc7c8b79b Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Tue, 17 Oct 2023 16:23:28 -0700 Subject: [PATCH 100/145] Minor fixes --- .../org/lflang/cli/DiagramGenerationTest.java | 2 +- .../java/org/lflang/tests/RunSingleTest.java | 2 +- .../java/org/lflang/tests/RuntimeTest.java | 2 +- .../java/org/lflang/tests/lsp/LspTests.java | 2 +- .../org/lflang/tests/runtime/CArduinoTest.java | 2 +- .../java/org/lflang/tests/runtime/CCppTest.java | 2 +- .../org/lflang/tests/runtime/CSchedulerTest.java | 2 +- .../java/org/lflang/tests/runtime/CTest.java | 2 +- .../org/lflang/tests/runtime/CVerifierTest.java | 2 +- .../org/lflang/tests/runtime/CZephyrTest.java | 2 +- .../org/lflang/tests/runtime/CppRos2Test.java | 2 +- .../java/org/lflang/tests/runtime/CppTest.java | 2 +- .../org/lflang/tests/runtime/PythonTest.java | 2 +- .../java/org/lflang/tests/runtime/RustTest.java | 2 +- .../org/lflang/tests/runtime/TypeScriptTest.java | 2 +- .../tests/serialization/SerializationTest.java | 2 +- core/src/main/java/org/lflang/ModelInfo.java | 1 + .../lflang/analyses/uclid/UclidGenerator.java | 2 +- core/src/main/java/org/lflang/ast/ASTUtils.java | 2 +- .../main/java/org/lflang/ast/FormattingUtil.java | 2 +- core/src/main/java/org/lflang/ast/IsEqual.java | 2 +- core/src/main/java/org/lflang/ast/ToLf.java | 2 +- .../lflang/federated/extensions/CExtension.java | 2 +- .../extensions/FedTargetExtensionFactory.java | 2 +- .../lflang/federated/generator/FedGenerator.java | 2 +- .../federated/generator/FedTargetConfig.java | 2 +- .../FedNativePythonSerialization.java | 2 +- .../serialization/FedROS2CPPSerialization.java | 2 +- .../java/org/lflang/generator/GeneratorBase.java | 12 +++++++----- .../org/lflang/generator/GeneratorUtils.java | 2 +- .../java/org/lflang/generator/LFGenerator.java | 2 +- .../org/lflang/generator/c/CActionGenerator.java | 2 +- .../org/lflang/generator/c/CDockerGenerator.java | 2 +- .../java/org/lflang/generator/c/CGenerator.java | 2 +- .../org/lflang/generator/c/CPortGenerator.java | 2 +- .../lflang/generator/python/PythonGenerator.java | 2 +- .../python/PythonReactionGenerator.java | 2 +- .../java/org/lflang/{ => target}/Target.java | 3 +-- .../java/org/lflang/target/TargetConfig.java | 16 ++++++++-------- .../org/lflang/target/property/FastProperty.java | 2 +- .../target/property/type/DictionaryType.java | 2 +- .../lflang/target/property/type/UnionType.java | 2 +- .../java/org/lflang/validation/LFValidator.java | 2 +- .../org/lflang/generator/cpp/CppGenerator.kt | 2 +- .../org/lflang/generator/rust/RustGenerator.kt | 2 +- .../org/lflang/generator/ts/TSGenerator.kt | 3 +-- .../compiler/LinguaFrancaValidationTest.java | 2 +- .../lflang/tests/compiler/RoundTripTests.java | 2 +- .../java/org/lflang/tests/TestBase.java | 2 +- .../java/org/lflang/tests/TestRegistry.java | 2 +- 50 files changed, 63 insertions(+), 62 deletions(-) rename core/src/main/java/org/lflang/{ => target}/Target.java (99%) diff --git a/cli/lfd/src/test/java/org/lflang/cli/DiagramGenerationTest.java b/cli/lfd/src/test/java/org/lflang/cli/DiagramGenerationTest.java index 2fcb332fe6..73c5aafd58 100644 --- a/cli/lfd/src/test/java/org/lflang/cli/DiagramGenerationTest.java +++ b/cli/lfd/src/test/java/org/lflang/cli/DiagramGenerationTest.java @@ -23,8 +23,8 @@ import org.junit.jupiter.api.io.TempDir; import org.junit.jupiter.api.parallel.Execution; import org.junit.jupiter.api.parallel.ExecutionMode; -import org.lflang.Target; import org.lflang.lf.Model; +import org.lflang.target.Target; import org.lflang.tests.LFInjectorProvider; import org.lflang.tests.LFTest; import org.lflang.tests.TestRegistry; diff --git a/core/src/integrationTest/java/org/lflang/tests/RunSingleTest.java b/core/src/integrationTest/java/org/lflang/tests/RunSingleTest.java index fe813823bd..dc04a717c4 100644 --- a/core/src/integrationTest/java/org/lflang/tests/RunSingleTest.java +++ b/core/src/integrationTest/java/org/lflang/tests/RunSingleTest.java @@ -32,7 +32,7 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; import org.junit.jupiter.api.Test; -import org.lflang.Target; +import org.lflang.target.Target; import org.lflang.tests.runtime.CCppTest; import org.lflang.tests.runtime.CTest; import org.lflang.tests.runtime.CppTest; diff --git a/core/src/integrationTest/java/org/lflang/tests/RuntimeTest.java b/core/src/integrationTest/java/org/lflang/tests/RuntimeTest.java index 8f0ccdc8fd..add74ef30d 100644 --- a/core/src/integrationTest/java/org/lflang/tests/RuntimeTest.java +++ b/core/src/integrationTest/java/org/lflang/tests/RuntimeTest.java @@ -4,8 +4,8 @@ import java.util.List; import org.junit.jupiter.api.Assumptions; import org.junit.jupiter.api.Test; -import org.lflang.Target; import org.lflang.ast.ASTUtils; +import org.lflang.target.Target; import org.lflang.tests.TestRegistry.TestCategory; /** diff --git a/core/src/integrationTest/java/org/lflang/tests/lsp/LspTests.java b/core/src/integrationTest/java/org/lflang/tests/lsp/LspTests.java index 964963bd0e..6b92b46754 100644 --- a/core/src/integrationTest/java/org/lflang/tests/lsp/LspTests.java +++ b/core/src/integrationTest/java/org/lflang/tests/lsp/LspTests.java @@ -14,9 +14,9 @@ import org.eclipse.lsp4j.Diagnostic; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import org.lflang.Target; import org.lflang.generator.IntegratedBuilder; import org.lflang.generator.LanguageServerMessageReporter; +import org.lflang.target.Target; import org.lflang.tests.LFTest; import org.lflang.tests.LfInjectedTestBase; import org.lflang.tests.TestBase; diff --git a/core/src/integrationTest/java/org/lflang/tests/runtime/CArduinoTest.java b/core/src/integrationTest/java/org/lflang/tests/runtime/CArduinoTest.java index b8ae804a09..6a5abdf41d 100644 --- a/core/src/integrationTest/java/org/lflang/tests/runtime/CArduinoTest.java +++ b/core/src/integrationTest/java/org/lflang/tests/runtime/CArduinoTest.java @@ -3,7 +3,7 @@ import java.util.List; import org.junit.jupiter.api.Assumptions; import org.junit.jupiter.api.Test; -import org.lflang.Target; +import org.lflang.target.Target; import org.lflang.tests.Configurators; import org.lflang.tests.TestBase; import org.lflang.tests.TestRegistry.TestCategory; diff --git a/core/src/integrationTest/java/org/lflang/tests/runtime/CCppTest.java b/core/src/integrationTest/java/org/lflang/tests/runtime/CCppTest.java index 3bbbda7dad..47c4708114 100644 --- a/core/src/integrationTest/java/org/lflang/tests/runtime/CCppTest.java +++ b/core/src/integrationTest/java/org/lflang/tests/runtime/CCppTest.java @@ -2,8 +2,8 @@ import org.junit.jupiter.api.Assumptions; import org.junit.jupiter.api.Test; -import org.lflang.Target; import org.lflang.ast.ASTUtils; +import org.lflang.target.Target; import org.lflang.tests.TestBase; import org.lflang.tests.TestRegistry.TestCategory; diff --git a/core/src/integrationTest/java/org/lflang/tests/runtime/CSchedulerTest.java b/core/src/integrationTest/java/org/lflang/tests/runtime/CSchedulerTest.java index e8c13d73b0..3f48a22f29 100644 --- a/core/src/integrationTest/java/org/lflang/tests/runtime/CSchedulerTest.java +++ b/core/src/integrationTest/java/org/lflang/tests/runtime/CSchedulerTest.java @@ -2,7 +2,7 @@ import java.util.EnumSet; import org.junit.jupiter.api.Test; -import org.lflang.Target; +import org.lflang.target.Target; import org.lflang.target.property.type.SchedulerType.Scheduler; import org.lflang.tests.Configurators; import org.lflang.tests.TestBase; diff --git a/core/src/integrationTest/java/org/lflang/tests/runtime/CTest.java b/core/src/integrationTest/java/org/lflang/tests/runtime/CTest.java index 8da7d6117d..88c4aa89cf 100644 --- a/core/src/integrationTest/java/org/lflang/tests/runtime/CTest.java +++ b/core/src/integrationTest/java/org/lflang/tests/runtime/CTest.java @@ -27,7 +27,7 @@ import org.junit.jupiter.api.Assumptions; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; -import org.lflang.Target; +import org.lflang.target.Target; import org.lflang.tests.RuntimeTest; /** diff --git a/core/src/integrationTest/java/org/lflang/tests/runtime/CVerifierTest.java b/core/src/integrationTest/java/org/lflang/tests/runtime/CVerifierTest.java index e888854318..949b66276c 100644 --- a/core/src/integrationTest/java/org/lflang/tests/runtime/CVerifierTest.java +++ b/core/src/integrationTest/java/org/lflang/tests/runtime/CVerifierTest.java @@ -3,7 +3,7 @@ import java.util.List; import org.junit.jupiter.api.Assumptions; import org.junit.jupiter.api.Test; -import org.lflang.Target; +import org.lflang.target.Target; import org.lflang.target.property.type.VerifyProperty; import org.lflang.tests.TestBase; import org.lflang.tests.TestRegistry; diff --git a/core/src/integrationTest/java/org/lflang/tests/runtime/CZephyrTest.java b/core/src/integrationTest/java/org/lflang/tests/runtime/CZephyrTest.java index 08b18b2a72..2529710b80 100644 --- a/core/src/integrationTest/java/org/lflang/tests/runtime/CZephyrTest.java +++ b/core/src/integrationTest/java/org/lflang/tests/runtime/CZephyrTest.java @@ -27,7 +27,7 @@ import java.util.List; import org.junit.jupiter.api.Assumptions; import org.junit.jupiter.api.Test; -import org.lflang.Target; +import org.lflang.target.Target; import org.lflang.tests.Configurators; import org.lflang.tests.TestBase; import org.lflang.tests.TestRegistry.TestCategory; diff --git a/core/src/integrationTest/java/org/lflang/tests/runtime/CppRos2Test.java b/core/src/integrationTest/java/org/lflang/tests/runtime/CppRos2Test.java index b21a932bdd..9970b18424 100644 --- a/core/src/integrationTest/java/org/lflang/tests/runtime/CppRos2Test.java +++ b/core/src/integrationTest/java/org/lflang/tests/runtime/CppRos2Test.java @@ -2,9 +2,9 @@ import org.junit.jupiter.api.Assumptions; import org.junit.jupiter.api.Test; -import org.lflang.Target; import org.lflang.lf.Element; import org.lflang.lf.LfFactory; +import org.lflang.target.Target; import org.lflang.target.property.Ros2Property; import org.lflang.tests.TestBase; diff --git a/core/src/integrationTest/java/org/lflang/tests/runtime/CppTest.java b/core/src/integrationTest/java/org/lflang/tests/runtime/CppTest.java index b284e8b7af..59e26fca69 100644 --- a/core/src/integrationTest/java/org/lflang/tests/runtime/CppTest.java +++ b/core/src/integrationTest/java/org/lflang/tests/runtime/CppTest.java @@ -27,7 +27,7 @@ package org.lflang.tests.runtime; import org.junit.jupiter.api.Test; -import org.lflang.Target; +import org.lflang.target.Target; import org.lflang.tests.RuntimeTest; /** diff --git a/core/src/integrationTest/java/org/lflang/tests/runtime/PythonTest.java b/core/src/integrationTest/java/org/lflang/tests/runtime/PythonTest.java index c227018d16..35ea43fdfa 100644 --- a/core/src/integrationTest/java/org/lflang/tests/runtime/PythonTest.java +++ b/core/src/integrationTest/java/org/lflang/tests/runtime/PythonTest.java @@ -28,7 +28,7 @@ import org.junit.jupiter.api.Assumptions; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; -import org.lflang.Target; +import org.lflang.target.Target; import org.lflang.target.TargetConfig; import org.lflang.tests.RuntimeTest; diff --git a/core/src/integrationTest/java/org/lflang/tests/runtime/RustTest.java b/core/src/integrationTest/java/org/lflang/tests/runtime/RustTest.java index 75c1de4e15..3db509bb32 100644 --- a/core/src/integrationTest/java/org/lflang/tests/runtime/RustTest.java +++ b/core/src/integrationTest/java/org/lflang/tests/runtime/RustTest.java @@ -25,7 +25,7 @@ package org.lflang.tests.runtime; import org.junit.jupiter.api.Test; -import org.lflang.Target; +import org.lflang.target.Target; import org.lflang.tests.RuntimeTest; /** */ diff --git a/core/src/integrationTest/java/org/lflang/tests/runtime/TypeScriptTest.java b/core/src/integrationTest/java/org/lflang/tests/runtime/TypeScriptTest.java index 8fb223fe07..bc107af40b 100644 --- a/core/src/integrationTest/java/org/lflang/tests/runtime/TypeScriptTest.java +++ b/core/src/integrationTest/java/org/lflang/tests/runtime/TypeScriptTest.java @@ -2,7 +2,7 @@ import org.junit.jupiter.api.Assumptions; import org.junit.jupiter.api.Test; -import org.lflang.Target; +import org.lflang.target.Target; import org.lflang.tests.RuntimeTest; /** diff --git a/core/src/integrationTest/java/org/lflang/tests/serialization/SerializationTest.java b/core/src/integrationTest/java/org/lflang/tests/serialization/SerializationTest.java index d72495e540..ba6c3188a0 100644 --- a/core/src/integrationTest/java/org/lflang/tests/serialization/SerializationTest.java +++ b/core/src/integrationTest/java/org/lflang/tests/serialization/SerializationTest.java @@ -3,7 +3,7 @@ import java.util.Properties; import org.junit.jupiter.api.Assumptions; import org.junit.jupiter.api.Test; -import org.lflang.Target; +import org.lflang.target.Target; import org.lflang.target.TargetConfig; import org.lflang.tests.Configurators; import org.lflang.tests.TestBase; diff --git a/core/src/main/java/org/lflang/ModelInfo.java b/core/src/main/java/org/lflang/ModelInfo.java index 765cebb916..24f62c550d 100644 --- a/core/src/main/java/org/lflang/ModelInfo.java +++ b/core/src/main/java/org/lflang/ModelInfo.java @@ -47,6 +47,7 @@ import org.lflang.lf.ParameterReference; import org.lflang.lf.Reactor; import org.lflang.lf.STP; +import org.lflang.target.Target; import org.lflang.util.FileUtil; /** diff --git a/core/src/main/java/org/lflang/analyses/uclid/UclidGenerator.java b/core/src/main/java/org/lflang/analyses/uclid/UclidGenerator.java index c563356edf..b3e7984133 100644 --- a/core/src/main/java/org/lflang/analyses/uclid/UclidGenerator.java +++ b/core/src/main/java/org/lflang/analyses/uclid/UclidGenerator.java @@ -37,7 +37,6 @@ import org.antlr.v4.runtime.CharStreams; import org.antlr.v4.runtime.CommonTokenStream; import org.eclipse.emf.ecore.resource.Resource; -import org.lflang.Target; import org.lflang.TimeUnit; import org.lflang.TimeValue; import org.lflang.analyses.c.AstUtils; @@ -76,6 +75,7 @@ import org.lflang.lf.Connection; import org.lflang.lf.Expression; import org.lflang.lf.Time; +import org.lflang.target.Target; import org.lflang.util.StringUtil; /** (EXPERIMENTAL) Generator for Uclid5 models. */ diff --git a/core/src/main/java/org/lflang/ast/ASTUtils.java b/core/src/main/java/org/lflang/ast/ASTUtils.java index ed2141dbe2..257d387843 100644 --- a/core/src/main/java/org/lflang/ast/ASTUtils.java +++ b/core/src/main/java/org/lflang/ast/ASTUtils.java @@ -60,7 +60,6 @@ import org.eclipse.xtext.xbase.lib.StringExtensions; import org.lflang.InferredType; import org.lflang.MessageReporter; -import org.lflang.Target; import org.lflang.TimeUnit; import org.lflang.TimeValue; import org.lflang.generator.CodeMap; @@ -101,6 +100,7 @@ import org.lflang.lf.Watchdog; import org.lflang.lf.WidthSpec; import org.lflang.lf.WidthTerm; +import org.lflang.target.Target; import org.lflang.target.TargetConfig; import org.lflang.target.property.CompileDefinitionsProperty; import org.lflang.util.StringUtil; diff --git a/core/src/main/java/org/lflang/ast/FormattingUtil.java b/core/src/main/java/org/lflang/ast/FormattingUtil.java index 113bcb27c8..ff5e786b5a 100644 --- a/core/src/main/java/org/lflang/ast/FormattingUtil.java +++ b/core/src/main/java/org/lflang/ast/FormattingUtil.java @@ -9,8 +9,8 @@ import java.util.stream.Collectors; import java.util.stream.Stream; import org.eclipse.emf.ecore.EObject; -import org.lflang.Target; import org.lflang.lf.Model; +import org.lflang.target.Target; /** * Utility functions that determine the specific behavior of the LF formatter. diff --git a/core/src/main/java/org/lflang/ast/IsEqual.java b/core/src/main/java/org/lflang/ast/IsEqual.java index 9ac2a0a389..693abdcdb9 100644 --- a/core/src/main/java/org/lflang/ast/IsEqual.java +++ b/core/src/main/java/org/lflang/ast/IsEqual.java @@ -7,7 +7,6 @@ import java.util.function.Function; import java.util.stream.Collectors; import org.eclipse.emf.ecore.EObject; -import org.lflang.Target; import org.lflang.TimeUnit; import org.lflang.lf.Action; import org.lflang.lf.Array; @@ -64,6 +63,7 @@ import org.lflang.lf.WidthSpec; import org.lflang.lf.WidthTerm; import org.lflang.lf.util.LfSwitch; +import org.lflang.target.Target; /** * Switch class that checks if subtrees of the AST are semantically equivalent to each other. Return diff --git a/core/src/main/java/org/lflang/ast/ToLf.java b/core/src/main/java/org/lflang/ast/ToLf.java index dd8096a5e3..722e791a5f 100644 --- a/core/src/main/java/org/lflang/ast/ToLf.java +++ b/core/src/main/java/org/lflang/ast/ToLf.java @@ -20,7 +20,6 @@ import org.eclipse.xtext.nodemodel.INode; import org.eclipse.xtext.nodemodel.util.NodeModelUtils; import org.eclipse.xtext.xbase.lib.StringExtensions; -import org.lflang.Target; import org.lflang.ast.MalleableString.Builder; import org.lflang.ast.MalleableString.Joiner; import org.lflang.lf.Action; @@ -79,6 +78,7 @@ import org.lflang.lf.WidthSpec; import org.lflang.lf.WidthTerm; import org.lflang.lf.util.LfSwitch; +import org.lflang.target.Target; import org.lflang.util.StringUtil; /** 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 1d50d14825..b7191b9072 100644 --- a/core/src/main/java/org/lflang/federated/extensions/CExtension.java +++ b/core/src/main/java/org/lflang/federated/extensions/CExtension.java @@ -35,7 +35,6 @@ import java.util.List; import org.lflang.InferredType; import org.lflang.MessageReporter; -import org.lflang.Target; import org.lflang.TimeValue; import org.lflang.ast.ASTUtils; import org.lflang.federated.generator.FedASTUtils; @@ -56,6 +55,7 @@ import org.lflang.lf.Port; import org.lflang.lf.Reactor; import org.lflang.lf.VarRef; +import org.lflang.target.Target; import org.lflang.target.property.ClockSyncOptionsProperty; import org.lflang.target.property.CoordinationOptionsProperty; import org.lflang.target.property.CoordinationProperty; diff --git a/core/src/main/java/org/lflang/federated/extensions/FedTargetExtensionFactory.java b/core/src/main/java/org/lflang/federated/extensions/FedTargetExtensionFactory.java index 612aa02f7c..114735307f 100644 --- a/core/src/main/java/org/lflang/federated/extensions/FedTargetExtensionFactory.java +++ b/core/src/main/java/org/lflang/federated/extensions/FedTargetExtensionFactory.java @@ -1,6 +1,6 @@ package org.lflang.federated.extensions; -import org.lflang.Target; +import org.lflang.target.Target; /** * Class for instantiating target extensions. 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 682d12d1eb..07b887c5ab 100644 --- a/core/src/main/java/org/lflang/federated/generator/FedGenerator.java +++ b/core/src/main/java/org/lflang/federated/generator/FedGenerator.java @@ -30,7 +30,6 @@ import org.lflang.FileConfig; import org.lflang.LFStandaloneSetup; import org.lflang.MessageReporter; -import org.lflang.Target; import org.lflang.ast.ASTUtils; import org.lflang.federated.launcher.FedLauncherGenerator; import org.lflang.federated.launcher.RtiConfig; @@ -57,6 +56,7 @@ import org.lflang.lf.Reactor; import org.lflang.lf.TargetDecl; import org.lflang.lf.VarRef; +import org.lflang.target.Target; import org.lflang.target.TargetConfig; import org.lflang.target.property.CoordinationProperty; import org.lflang.target.property.DockerProperty; diff --git a/core/src/main/java/org/lflang/federated/generator/FedTargetConfig.java b/core/src/main/java/org/lflang/federated/generator/FedTargetConfig.java index 4a618d0823..bfc8dd6194 100644 --- a/core/src/main/java/org/lflang/federated/generator/FedTargetConfig.java +++ b/core/src/main/java/org/lflang/federated/generator/FedTargetConfig.java @@ -7,12 +7,12 @@ import java.util.Objects; import org.eclipse.emf.ecore.resource.Resource; import org.lflang.MessageReporter; -import org.lflang.Target; import org.lflang.ast.ASTUtils; 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; diff --git a/core/src/main/java/org/lflang/federated/serialization/FedNativePythonSerialization.java b/core/src/main/java/org/lflang/federated/serialization/FedNativePythonSerialization.java index 7e6b7b2869..f9f863a306 100644 --- a/core/src/main/java/org/lflang/federated/serialization/FedNativePythonSerialization.java +++ b/core/src/main/java/org/lflang/federated/serialization/FedNativePythonSerialization.java @@ -27,8 +27,8 @@ package org.lflang.federated.serialization; -import org.lflang.Target; import org.lflang.generator.GeneratorBase; +import org.lflang.target.Target; /** * Enables support for Python pickle serialization. diff --git a/core/src/main/java/org/lflang/federated/serialization/FedROS2CPPSerialization.java b/core/src/main/java/org/lflang/federated/serialization/FedROS2CPPSerialization.java index 225d519d77..447b509582 100644 --- a/core/src/main/java/org/lflang/federated/serialization/FedROS2CPPSerialization.java +++ b/core/src/main/java/org/lflang/federated/serialization/FedROS2CPPSerialization.java @@ -27,8 +27,8 @@ package org.lflang.federated.serialization; -import org.lflang.Target; import org.lflang.generator.GeneratorBase; +import org.lflang.target.Target; import org.lflang.target.property.CompilerProperty; /** diff --git a/core/src/main/java/org/lflang/generator/GeneratorBase.java b/core/src/main/java/org/lflang/generator/GeneratorBase.java index c44767fed9..b194c72c5e 100644 --- a/core/src/main/java/org/lflang/generator/GeneratorBase.java +++ b/core/src/main/java/org/lflang/generator/GeneratorBase.java @@ -48,7 +48,6 @@ import org.lflang.FileConfig; import org.lflang.MainConflictChecker; import org.lflang.MessageReporter; -import org.lflang.Target; import org.lflang.analyses.uclid.UclidGenerator; import org.lflang.ast.ASTUtils; import org.lflang.ast.AstTransformation; @@ -60,6 +59,7 @@ import org.lflang.lf.Mode; import org.lflang.lf.Reaction; import org.lflang.lf.Reactor; +import org.lflang.target.Target; import org.lflang.target.TargetConfig; import org.lflang.target.property.FilesProperty; import org.lflang.target.property.ThreadingProperty; @@ -267,7 +267,7 @@ public void doGenerate(Resource resource, LFGeneratorContext context) { // Check for the existence and support of watchdogs hasWatchdogs = IterableExtensions.exists(reactors, it -> !it.getWatchdogs().isEmpty()); - checkWatchdogSupport(targetConfig.get(ThreadingProperty.INSTANCE) && getTarget() == Target.C); + checkWatchdogSupport(getTarget() == Target.C && targetConfig.get(ThreadingProperty.INSTANCE)); additionalPostProcessingForModes(); } @@ -332,9 +332,11 @@ protected void setReactorsAndInstantiationGraph(LFGeneratorContext.Mode mode) { * @param fileConfig The fileConfig used to make the copy and resolve paths. */ protected void copyUserFiles(TargetConfig targetConfig, FileConfig fileConfig) { - var dst = this.context.getFileConfig().getSrcGenPath(); - FileUtil.copyFilesOrDirectories( - targetConfig.get(FilesProperty.INSTANCE), dst, fileConfig, messageReporter, false); + if (targetConfig.isSet(FilesProperty.INSTANCE)) { + var dst = this.context.getFileConfig().getSrcGenPath(); + FileUtil.copyFilesOrDirectories( + targetConfig.get(FilesProperty.INSTANCE), dst, fileConfig, messageReporter, false); + } } /** diff --git a/core/src/main/java/org/lflang/generator/GeneratorUtils.java b/core/src/main/java/org/lflang/generator/GeneratorUtils.java index 1ce0cac900..43854e9217 100644 --- a/core/src/main/java/org/lflang/generator/GeneratorUtils.java +++ b/core/src/main/java/org/lflang/generator/GeneratorUtils.java @@ -12,7 +12,6 @@ import org.eclipse.xtext.xbase.lib.IteratorExtensions; import org.lflang.FileConfig; import org.lflang.MessageReporter; -import org.lflang.Target; import org.lflang.ast.ASTUtils; import org.lflang.generator.LFGeneratorContext.Mode; import org.lflang.lf.Action; @@ -22,6 +21,7 @@ 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; diff --git a/core/src/main/java/org/lflang/generator/LFGenerator.java b/core/src/main/java/org/lflang/generator/LFGenerator.java index 701c57fb5a..a7776c7b57 100644 --- a/core/src/main/java/org/lflang/generator/LFGenerator.java +++ b/core/src/main/java/org/lflang/generator/LFGenerator.java @@ -12,7 +12,6 @@ import org.eclipse.xtext.util.RuntimeIOException; import org.lflang.FileConfig; import org.lflang.MessageReporter; -import org.lflang.Target; import org.lflang.ast.ASTUtils; import org.lflang.federated.generator.FedASTUtils; import org.lflang.federated.generator.FedFileConfig; @@ -28,6 +27,7 @@ import org.lflang.generator.ts.TSFileConfig; import org.lflang.generator.ts.TSGenerator; import org.lflang.scoping.LFGlobalScopeProvider; +import org.lflang.target.Target; /** Generates code from your model files on save. */ public class LFGenerator extends AbstractGenerator { diff --git a/core/src/main/java/org/lflang/generator/c/CActionGenerator.java b/core/src/main/java/org/lflang/generator/c/CActionGenerator.java index 83f47a3afc..8189a1db4a 100644 --- a/core/src/main/java/org/lflang/generator/c/CActionGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CActionGenerator.java @@ -4,12 +4,12 @@ import java.util.ArrayList; import java.util.List; -import org.lflang.Target; import org.lflang.ast.ASTUtils; import org.lflang.generator.ActionInstance; import org.lflang.generator.CodeBuilder; import org.lflang.generator.ReactorInstance; import org.lflang.lf.Action; +import org.lflang.target.Target; /** * Generates code for actions (logical or physical) for the C and CCpp target. diff --git a/core/src/main/java/org/lflang/generator/c/CDockerGenerator.java b/core/src/main/java/org/lflang/generator/c/CDockerGenerator.java index 4f2cb10f1d..77fbc9dfe3 100644 --- a/core/src/main/java/org/lflang/generator/c/CDockerGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CDockerGenerator.java @@ -1,9 +1,9 @@ package org.lflang.generator.c; import org.eclipse.xtext.xbase.lib.IterableExtensions; -import org.lflang.Target; import org.lflang.generator.DockerGenerator; import org.lflang.generator.LFGeneratorContext; +import org.lflang.target.Target; import org.lflang.target.property.BuildCommandsProperty; import org.lflang.target.property.DockerProperty; import org.lflang.util.StringUtil; 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 a13cd3c440..d367b49d7b 100644 --- a/core/src/main/java/org/lflang/generator/c/CGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CGenerator.java @@ -51,7 +51,6 @@ import org.eclipse.xtext.xbase.lib.Exceptions; import org.eclipse.xtext.xbase.lib.IterableExtensions; import org.lflang.FileConfig; -import org.lflang.Target; import org.lflang.ast.ASTUtils; import org.lflang.ast.DelayedConnectionTransformation; import org.lflang.federated.extensions.CExtensionUtils; @@ -86,6 +85,7 @@ import org.lflang.lf.ReactorDecl; import org.lflang.lf.StateVar; import org.lflang.lf.Variable; +import org.lflang.target.Target; import org.lflang.target.TargetConfig; import org.lflang.target.property.BuildCommandsProperty; import org.lflang.target.property.CmakeIncludeProperty; diff --git a/core/src/main/java/org/lflang/generator/c/CPortGenerator.java b/core/src/main/java/org/lflang/generator/c/CPortGenerator.java index eafec3dce0..945a204a8e 100644 --- a/core/src/main/java/org/lflang/generator/c/CPortGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CPortGenerator.java @@ -4,7 +4,6 @@ import org.lflang.AttributeUtils; import org.lflang.MessageReporter; -import org.lflang.Target; import org.lflang.ast.ASTUtils; import org.lflang.generator.CodeBuilder; import org.lflang.generator.PortInstance; @@ -12,6 +11,7 @@ import org.lflang.lf.Output; import org.lflang.lf.Port; import org.lflang.lf.ReactorDecl; +import org.lflang.target.Target; /** * Generates C code to declare and initialize ports. diff --git a/core/src/main/java/org/lflang/generator/python/PythonGenerator.java b/core/src/main/java/org/lflang/generator/python/PythonGenerator.java index fe7e3b6bf4..9236e5e87d 100644 --- a/core/src/main/java/org/lflang/generator/python/PythonGenerator.java +++ b/core/src/main/java/org/lflang/generator/python/PythonGenerator.java @@ -38,7 +38,6 @@ import org.eclipse.xtext.xbase.lib.Exceptions; import org.lflang.AttributeUtils; import org.lflang.FileConfig; -import org.lflang.Target; import org.lflang.ast.ASTUtils; import org.lflang.generator.CodeBuilder; import org.lflang.generator.CodeMap; @@ -59,6 +58,7 @@ import org.lflang.lf.Port; import org.lflang.lf.Reaction; import org.lflang.lf.Reactor; +import org.lflang.target.Target; import org.lflang.target.property.CompilerFlagsProperty; import org.lflang.target.property.CompilerProperty; import org.lflang.target.property.ProtobufsProperty; diff --git a/core/src/main/java/org/lflang/generator/python/PythonReactionGenerator.java b/core/src/main/java/org/lflang/generator/python/PythonReactionGenerator.java index c65d4ad3de..cd008cba8d 100644 --- a/core/src/main/java/org/lflang/generator/python/PythonReactionGenerator.java +++ b/core/src/main/java/org/lflang/generator/python/PythonReactionGenerator.java @@ -6,7 +6,6 @@ import java.util.Set; import org.lflang.AttributeUtils; import org.lflang.MessageReporter; -import org.lflang.Target; import org.lflang.ast.ASTUtils; import org.lflang.generator.CodeBuilder; import org.lflang.generator.ReactionInstance; @@ -28,6 +27,7 @@ import org.lflang.lf.ReactorDecl; import org.lflang.lf.TriggerRef; import org.lflang.lf.VarRef; +import org.lflang.target.Target; import org.lflang.util.StringUtil; public class PythonReactionGenerator { diff --git a/core/src/main/java/org/lflang/Target.java b/core/src/main/java/org/lflang/target/Target.java similarity index 99% rename from core/src/main/java/org/lflang/Target.java rename to core/src/main/java/org/lflang/target/Target.java index 774d802c05..91e4e3c8f0 100644 --- a/core/src/main/java/org/lflang/Target.java +++ b/core/src/main/java/org/lflang/target/Target.java @@ -15,7 +15,7 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package org.lflang; +package org.lflang.target; import java.util.Arrays; import java.util.Collection; @@ -26,7 +26,6 @@ import java.util.Set; import net.jcip.annotations.Immutable; import org.lflang.lf.TargetDecl; -import org.lflang.target.TargetConfig; import org.lflang.target.property.AuthProperty; import org.lflang.target.property.BuildCommandsProperty; import org.lflang.target.property.BuildTypeProperty; diff --git a/core/src/main/java/org/lflang/target/TargetConfig.java b/core/src/main/java/org/lflang/target/TargetConfig.java index 0e6a7999fb..0aa1f38bcc 100644 --- a/core/src/main/java/org/lflang/target/TargetConfig.java +++ b/core/src/main/java/org/lflang/target/TargetConfig.java @@ -37,7 +37,6 @@ import java.util.Set; import java.util.stream.Collectors; import org.lflang.MessageReporter; -import org.lflang.Target; import org.lflang.TargetProperty; import org.lflang.lf.KeyValuePair; import org.lflang.lf.KeyValuePairs; @@ -136,14 +135,15 @@ public void reset(TargetProperty property) { @SuppressWarnings("unchecked") public T get(TargetProperty property) throws IllegalArgumentException { - var value = properties.get(property); - if (value != null) { + if (properties.containsKey(property)) { + var value = properties.get(property); return (T) value; + } else { + throw new IllegalArgumentException( + String.format( + "Attempting to access target property '%s', which is not supported by the %s target.", + property.name(), this.target)); } - throw new IllegalArgumentException( - String.format( - "Attempting to access target property '%s', which is not supported by the %s target.", - property.name(), this.target)); } /** @@ -185,7 +185,7 @@ public void load(Properties properties, MessageReporter err) { var property = p.get(); property.update(this, (String) properties.get(key), err); } else { - throw new RuntimeException("Attempting to load unrecognized target property: " + key); + err.nowhere().warning("Attempting to load unrecognized target property: " + key); } } } 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 b48ab9e6f7..d2509b81c3 100644 --- a/core/src/main/java/org/lflang/target/property/FastProperty.java +++ b/core/src/main/java/org/lflang/target/property/FastProperty.java @@ -1,7 +1,6 @@ package org.lflang.target.property; import org.lflang.MessageReporter; -import org.lflang.Target; import org.lflang.ast.ASTUtils; import org.lflang.lf.Action; import org.lflang.lf.ActionOrigin; @@ -9,6 +8,7 @@ import org.lflang.lf.LfPackage.Literals; import org.lflang.lf.Model; import org.lflang.lf.Reactor; +import org.lflang.target.Target; /** * If true, configure the execution environment such that it does not wait for physical time to diff --git a/core/src/main/java/org/lflang/target/property/type/DictionaryType.java b/core/src/main/java/org/lflang/target/property/type/DictionaryType.java index 00aae0a870..1dc8e057e6 100644 --- a/core/src/main/java/org/lflang/target/property/type/DictionaryType.java +++ b/core/src/main/java/org/lflang/target/property/type/DictionaryType.java @@ -5,11 +5,11 @@ import java.util.Optional; import java.util.stream.Collectors; import org.lflang.MessageReporter; -import org.lflang.Target; import org.lflang.lf.Element; import org.lflang.lf.KeyValuePair; import org.lflang.lf.KeyValuePairs; import org.lflang.lf.LfPackage.Literals; +import org.lflang.target.Target; import org.lflang.target.property.ClockSyncOptionsProperty.ClockSyncOption; import org.lflang.target.property.CoordinationOptionsProperty.CoordinationOption; import org.lflang.target.property.DockerProperty.DockerOption; diff --git a/core/src/main/java/org/lflang/target/property/type/UnionType.java b/core/src/main/java/org/lflang/target/property/type/UnionType.java index 66abb1d1ef..dc53fc26b5 100644 --- a/core/src/main/java/org/lflang/target/property/type/UnionType.java +++ b/core/src/main/java/org/lflang/target/property/type/UnionType.java @@ -5,8 +5,8 @@ import java.util.Optional; import java.util.stream.Collectors; import org.lflang.MessageReporter; -import org.lflang.Target; import org.lflang.lf.Element; +import org.lflang.target.Target; /** * A type that can assume one of several types. diff --git a/core/src/main/java/org/lflang/validation/LFValidator.java b/core/src/main/java/org/lflang/validation/LFValidator.java index 218d5e1d4d..bd98c4b416 100644 --- a/core/src/main/java/org/lflang/validation/LFValidator.java +++ b/core/src/main/java/org/lflang/validation/LFValidator.java @@ -58,7 +58,6 @@ import org.lflang.AttributeUtils; import org.lflang.InferredType; import org.lflang.ModelInfo; -import org.lflang.Target; import org.lflang.TimeValue; import org.lflang.ast.ASTUtils; import org.lflang.federated.serialization.SupportedSerializers; @@ -113,6 +112,7 @@ import org.lflang.lf.Visibility; import org.lflang.lf.WidthSpec; import org.lflang.lf.WidthTerm; +import org.lflang.target.Target; import org.lflang.target.TargetConfig; import org.lflang.util.FileUtil; diff --git a/core/src/main/kotlin/org/lflang/generator/cpp/CppGenerator.kt b/core/src/main/kotlin/org/lflang/generator/cpp/CppGenerator.kt index ec97ea9b80..ea8826ec15 100644 --- a/core/src/main/kotlin/org/lflang/generator/cpp/CppGenerator.kt +++ b/core/src/main/kotlin/org/lflang/generator/cpp/CppGenerator.kt @@ -27,7 +27,7 @@ package org.lflang.generator.cpp import org.eclipse.emf.ecore.resource.Resource -import org.lflang.Target +import org.lflang.target.Target import org.lflang.generator.* import org.lflang.generator.GeneratorUtils.canGenerate import org.lflang.generator.LFGeneratorContext.Mode diff --git a/core/src/main/kotlin/org/lflang/generator/rust/RustGenerator.kt b/core/src/main/kotlin/org/lflang/generator/rust/RustGenerator.kt index a3ae57ba21..b37fe1b2a1 100644 --- a/core/src/main/kotlin/org/lflang/generator/rust/RustGenerator.kt +++ b/core/src/main/kotlin/org/lflang/generator/rust/RustGenerator.kt @@ -25,7 +25,7 @@ package org.lflang.generator.rust import org.eclipse.emf.ecore.resource.Resource -import org.lflang.Target +import org.lflang.target.Target import org.lflang.generator.* import org.lflang.generator.GeneratorUtils.canGenerate import org.lflang.joinWithCommas diff --git a/core/src/main/kotlin/org/lflang/generator/ts/TSGenerator.kt b/core/src/main/kotlin/org/lflang/generator/ts/TSGenerator.kt index 8c764ae58d..f5cc708384 100644 --- a/core/src/main/kotlin/org/lflang/generator/ts/TSGenerator.kt +++ b/core/src/main/kotlin/org/lflang/generator/ts/TSGenerator.kt @@ -27,7 +27,7 @@ package org.lflang.generator.ts import org.eclipse.emf.ecore.resource.Resource import org.eclipse.xtext.util.CancelIndicator -import org.lflang.Target +import org.lflang.target.Target import org.lflang.TimeValue import org.lflang.ast.DelayedConnectionTransformation import org.lflang.generator.* @@ -38,7 +38,6 @@ import org.lflang.scoping.LFGlobalScopeProvider import org.lflang.target.property.DockerProperty import org.lflang.target.property.NoCompileProperty import org.lflang.target.property.ProtobufsProperty -import org.lflang.target.property.type.PrimitiveType import org.lflang.util.FileUtil import java.nio.file.Files import java.nio.file.Path 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 fb3e4a2e27..89582b475d 100644 --- a/core/src/test/java/org/lflang/tests/compiler/LinguaFrancaValidationTest.java +++ b/core/src/test/java/org/lflang/tests/compiler/LinguaFrancaValidationTest.java @@ -44,12 +44,12 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestFactory; import org.junit.jupiter.api.extension.ExtendWith; -import org.lflang.Target; import org.lflang.TargetProperty; import org.lflang.TimeValue; import org.lflang.lf.LfPackage; import org.lflang.lf.Model; import org.lflang.lf.Visibility; +import org.lflang.target.Target; import org.lflang.target.TargetConfig; import org.lflang.target.property.CargoDependenciesProperty; import org.lflang.target.property.PlatformProperty; diff --git a/core/src/test/java/org/lflang/tests/compiler/RoundTripTests.java b/core/src/test/java/org/lflang/tests/compiler/RoundTripTests.java index 9dc4957f2c..3be9ec6b07 100644 --- a/core/src/test/java/org/lflang/tests/compiler/RoundTripTests.java +++ b/core/src/test/java/org/lflang/tests/compiler/RoundTripTests.java @@ -19,11 +19,11 @@ import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.parallel.Execution; import org.junit.jupiter.api.parallel.ExecutionMode; -import org.lflang.Target; import org.lflang.ast.FormattingUtil; import org.lflang.ast.IsEqual; import org.lflang.ast.LfParsingHelper; import org.lflang.lf.Model; +import org.lflang.target.Target; import org.lflang.tests.LFInjectorProvider; import org.lflang.tests.LFTest; import org.lflang.tests.LfParsingTestHelper; diff --git a/core/src/testFixtures/java/org/lflang/tests/TestBase.java b/core/src/testFixtures/java/org/lflang/tests/TestBase.java index d9d36b2ea7..73fb9155d5 100644 --- a/core/src/testFixtures/java/org/lflang/tests/TestBase.java +++ b/core/src/testFixtures/java/org/lflang/tests/TestBase.java @@ -38,12 +38,12 @@ import org.lflang.FileConfig; import org.lflang.LFRuntimeModule; import org.lflang.LFStandaloneSetup; -import org.lflang.Target; import org.lflang.generator.GeneratorResult; import org.lflang.generator.LFGenerator; import org.lflang.generator.LFGeneratorContext; import org.lflang.generator.LFGeneratorContext.BuildParm; import org.lflang.generator.MainContext; +import org.lflang.target.Target; import org.lflang.target.TargetConfig; import org.lflang.target.property.LoggingProperty; import org.lflang.tests.Configurators.Configurator; diff --git a/core/src/testFixtures/java/org/lflang/tests/TestRegistry.java b/core/src/testFixtures/java/org/lflang/tests/TestRegistry.java index 06024a3e29..92876aa5f6 100644 --- a/core/src/testFixtures/java/org/lflang/tests/TestRegistry.java +++ b/core/src/testFixtures/java/org/lflang/tests/TestRegistry.java @@ -27,8 +27,8 @@ import org.eclipse.emf.ecore.resource.ResourceSet; import org.eclipse.xtext.xbase.lib.IteratorExtensions; import org.lflang.LFResourceProvider; -import org.lflang.Target; import org.lflang.lf.Reactor; +import org.lflang.target.Target; import org.lflang.tests.TestBase.TestLevel; /** From 50e3780d6c2d31023215650a4fe9a225a1a86d42 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Tue, 17 Oct 2023 17:33:34 -0700 Subject: [PATCH 101/145] Undo refactoring of CCmakeGenerator because its just too far gone --- .../lflang/generator/c/CCmakeGenerator.java | 353 +++++++++--------- .../org/lflang/generator/c/CGenerator.java | 4 + 2 files changed, 172 insertions(+), 185 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 ce03c21d8f..ea783b162a 100644 --- a/core/src/main/java/org/lflang/generator/c/CCmakeGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CCmakeGenerator.java @@ -32,8 +32,10 @@ import java.util.List; import java.util.stream.Stream; import org.lflang.FileConfig; +import org.lflang.MessageReporter; import org.lflang.generator.CodeBuilder; import org.lflang.generator.LFGeneratorContext; +import org.lflang.target.TargetConfig; import org.lflang.target.property.AuthProperty; import org.lflang.target.property.BuildTypeProperty; import org.lflang.target.property.CmakeIncludeProperty; @@ -41,7 +43,6 @@ import org.lflang.target.property.CompilerFlagsProperty; import org.lflang.target.property.CompilerProperty; import org.lflang.target.property.PlatformProperty; -import org.lflang.target.property.PlatformProperty.PlatformOptions; import org.lflang.target.property.ProtobufsProperty; import org.lflang.target.property.ThreadingProperty; import org.lflang.target.property.WorkersProperty; @@ -108,8 +109,9 @@ CodeBuilder generateCMakeCode( boolean hasMain, String cMakeExtras, LFGeneratorContext context) { - CodeBuilder cMakeCode = new CodeBuilder(); + CodeBuilder cMakeCode = new CodeBuilder(); + var executableName = context.getFileConfig().name; var targetConfig = context.getTargetConfig(); var messageReporter = context.getErrorReporter(); @@ -121,13 +123,84 @@ CodeBuilder generateCMakeCode( .relativize(fileConfig.getSrcGenPath().resolve(Paths.get(file))); additionalSources.add(FileUtil.toUnixString(relativePath)); } + // Parse board option of the platform target property + // Specified as a series of colon spaced options + // Board syntax + // rp2040 : + // arduino + String[] boardProperties = {}; + var platformOptions = targetConfig.get(PlatformProperty.INSTANCE); + if (platformOptions.board != null) { + boardProperties = platformOptions.board.trim().split(":"); + // Ignore whitespace + for (int i = 0; i < boardProperties.length; i++) { + boardProperties[i] = boardProperties[i].trim(); + } + } additionalSources.addAll(this.additionalSources); cMakeCode.newLine(); cMakeCode.pr("cmake_minimum_required(VERSION " + MIN_CMAKE_VERSION + ")"); - preTargetDefinitionPlatformConfig(context, hasMain, sources, cMakeCode); + // Setup the project header for different platforms + switch (platformOptions.platform) { + case ZEPHYR: + cMakeCode.pr("# Set default configuration file. To add custom configurations,"); + cMakeCode.pr("# pass -- -DOVERLAY_CONFIG=my_config.prj to either cmake or west"); + cMakeCode.pr("set(CONF_FILE prj_lf.conf)"); + if (platformOptions.board != null) { + cMakeCode.pr("# Selecting board specified in target property"); + cMakeCode.pr("set(BOARD " + platformOptions.board + ")"); + } else { + cMakeCode.pr("# Selecting default board"); + cMakeCode.pr("set(BOARD qemu_cortex_m3)"); + } + cMakeCode.pr("# We recommend Zephyr v3.4.0 but we are compatible with older versions also"); + cMakeCode.pr("find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE} 3.4.0)"); + cMakeCode.newLine(); + cMakeCode.pr("project(" + executableName + " LANGUAGES C)"); + cMakeCode.newLine(); + break; + case RP2040: + // Attempt to set PICO_SDK_PATH if it is not already set. + if (System.getenv("PICO_SDK_PATH") == null) { + Path picoSDKPath = fileConfig.srcPkgPath.resolve("pico-sdk"); + if (Files.isDirectory(picoSDKPath)) { + messageReporter + .nowhere() + .info( + "pico-sdk library found at " + + picoSDKPath.toString() + + ". You can override this by setting PICO_SDK_PATH."); + cMakeCode.pr("# Define the root of the pico-sdk library."); + cMakeCode.pr("set(PICO_SDK_PATH " + picoSDKPath + ")"); + } else { + messageReporter + .nowhere() + .warning( + "No PICO_SDK_PATH environment variable and no pico-sdk directory " + + "at the package root directory. Pico SDK will not be found."); + } + } + cMakeCode.pr("include(pico_sdk_import.cmake)"); + cMakeCode.pr("project(" + executableName + " LANGUAGES C CXX ASM)"); + cMakeCode.newLine(); + // board type for rp2040 based boards + if (platformOptions.board != null) { + if (boardProperties.length < 1 || boardProperties[0].equals("")) { + cMakeCode.pr("set(PICO_BOARD pico)"); + } else { + cMakeCode.pr("set(PICO_BOARD \"" + boardProperties[0] + "\")"); + } + } + // remove warnings for rp2040 only to make debug easier + cMakeCode.pr("set(CMAKE_C_FLAGS \"${CMAKE_C_FLAGS} -w\")"); + break; + default: + cMakeCode.pr("project(" + executableName + " LANGUAGES C)"); + cMakeCode.newLine(); + } // The Test build type is the Debug type plus coverage generation cMakeCode.pr("if(CMAKE_BUILD_TYPE STREQUAL \"Test\")"); @@ -157,8 +230,7 @@ CodeBuilder generateCMakeCode( cMakeCode.pr("set(CMAKE_CXX_STANDARD 17)"); cMakeCode.pr("set(CMAKE_CXX_STANDARD_REQUIRED ON)"); cMakeCode.newLine(); - if (targetConfig.isSet(CmakeIncludeProperty.INSTANCE) - && !targetConfig.get(CmakeIncludeProperty.INSTANCE).isEmpty()) { + if (!targetConfig.get(CmakeIncludeProperty.INSTANCE).isEmpty()) { // The user might be using the non-keyword form of // target_link_libraries. Ideally we would detect whether they are // doing that, but it is easier to just always have a deprecation @@ -189,6 +261,54 @@ CodeBuilder generateCMakeCode( cMakeCode.newLine(); } + if (platformOptions.platform != Platform.AUTO) { + cMakeCode.pr("set(CMAKE_SYSTEM_NAME " + platformOptions.platform.getcMakeName() + ")"); + } + cMakeCode.newLine(); + cMakeCode.pr("# Set default values for build parameters\n"); + targetConfig + .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.indent(); + var v = "TRUE"; + if (value != null && !value.isEmpty()) { + v = value; + } + cMakeCode.pr("set(" + key + " " + v + ")\n"); + cMakeCode.unindent(); + cMakeCode.pr("endif()\n"); + }); + + // Setup main target for different platforms + switch (platformOptions.platform) { + case ZEPHYR: + cMakeCode.pr( + setUpMainTargetZephyr( + hasMain, + executableName, + Stream.concat(additionalSources.stream(), sources.stream()))); + break; + case RP2040: + cMakeCode.pr( + setUpMainTargetRp2040( + hasMain, + executableName, + Stream.concat(additionalSources.stream(), sources.stream()))); + break; + default: + cMakeCode.pr( + setUpMainTarget.getCmakeCode( + hasMain, + executableName, + Stream.concat(additionalSources.stream(), sources.stream()))); + } + // Ensure that the math library is linked cMakeCode.pr("find_library(MATH_LIBRARY m)"); cMakeCode.pr("if(MATH_LIBRARY)"); @@ -205,9 +325,45 @@ CodeBuilder generateCMakeCode( cMakeCode.pr("target_include_directories(${LF_MAIN_TARGET} PUBLIC include/core/modal_models)"); cMakeCode.pr("target_include_directories(${LF_MAIN_TARGET} PUBLIC include/core/utils)"); - buildParameterDefaults(cMakeCode, context); + // post target definition board configurations + switch (platformOptions.platform) { + case RP2040: + // set stdio output + boolean usb = true; + boolean uart = true; + if (platformOptions.board != null && boardProperties.length > 1) { + uart = !boardProperties[1].equals("usb"); + usb = !boardProperties[1].equals("uart"); + } + cMakeCode.pr("pico_enable_stdio_usb(${LF_MAIN_TARGET} " + (usb ? 1 : 0) + ")"); + cMakeCode.pr("pico_enable_stdio_uart(${LF_MAIN_TARGET} " + (uart ? 1 : 0) + ")"); + break; + } - postTargetDefinitionPlatformConfig(cMakeCode, context); + if (targetConfig.get(AuthProperty.INSTANCE)) { + // If security is requested, add the auth option. + var osName = System.getProperty("os.name").toLowerCase(); + // if platform target was set, use given platform instead + if (platformOptions.platform != Platform.AUTO) { + osName = platformOptions.platform.toString(); + } + if (osName.contains("mac")) { + cMakeCode.pr("set(OPENSSL_ROOT_DIR /usr/local/opt/openssl)"); + } + cMakeCode.pr("# Find OpenSSL and link to it"); + cMakeCode.pr("find_package(OpenSSL REQUIRED)"); + cMakeCode.pr("target_link_libraries( ${LF_MAIN_TARGET} PRIVATE OpenSSL::SSL)"); + cMakeCode.newLine(); + } + + if (targetConfig.get(ThreadingProperty.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)"); + cMakeCode.pr("target_link_libraries(${LF_MAIN_TARGET} PRIVATE Threads::Threads)"); + cMakeCode.newLine(); + } // Add additional flags so runtime can distinguish between multi-threaded and single-threaded // mode @@ -273,189 +429,16 @@ CodeBuilder generateCMakeCode( cMakeCode.pr(installCode); cMakeCode.newLine(); - if (targetConfig.isSet(CmakeIncludeProperty.INSTANCE)) { - // Add the include file - for (String includeFile : targetConfig.get(CmakeIncludeProperty.INSTANCE)) { - cMakeCode.pr("include(\"" + Path.of(includeFile).getFileName() + "\")"); - } - cMakeCode.newLine(); + // Add the include file + for (String includeFile : targetConfig.get(CmakeIncludeProperty.INSTANCE)) { + cMakeCode.pr("include(\"" + Path.of(includeFile).getFileName() + "\")"); } - cMakeCode.pr(cMakeExtras); cMakeCode.newLine(); - return cMakeCode; - } - - private void postTargetDefinitionPlatformConfig( - CodeBuilder cMakeCode, LFGeneratorContext context) { - var targetConfig = context.getTargetConfig(); - - var platformOptions = new PlatformOptions(); - if (targetConfig.isSet(PlatformProperty.INSTANCE)) { - platformOptions = targetConfig.get(PlatformProperty.INSTANCE); - } - // post target definition board configurations - switch (platformOptions.platform) { - case RP2040: - // set stdio output - boolean usb = true; - boolean uart = true; - var boardProperties = platformOptions.boardArray(); - if (boardProperties.length > 1) { - uart = !boardProperties[1].equals("usb"); - usb = !boardProperties[1].equals("uart"); - } - cMakeCode.pr("pico_enable_stdio_usb(${LF_MAIN_TARGET} " + (usb ? 1 : 0) + ")"); - cMakeCode.pr("pico_enable_stdio_uart(${LF_MAIN_TARGET} " + (uart ? 1 : 0) + ")"); - break; - } - - if (targetConfig.get(AuthProperty.INSTANCE)) { - // If security is requested, add the auth option. - var osName = System.getProperty("os.name").toLowerCase(); - // if platform target was set, use given platform instead - if (platformOptions.platform != Platform.AUTO) { - osName = platformOptions.platform.toString(); - } - if (osName.contains("mac")) { - cMakeCode.pr("set(OPENSSL_ROOT_DIR /usr/local/opt/openssl)"); - } - cMakeCode.pr("# Find OpenSSL and link to it"); - cMakeCode.pr("find_package(OpenSSL REQUIRED)"); - cMakeCode.pr("target_link_libraries( ${LF_MAIN_TARGET} PRIVATE OpenSSL::SSL)"); - cMakeCode.newLine(); - } - - if (targetConfig.get(ThreadingProperty.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)"); - cMakeCode.pr("target_link_libraries(${LF_MAIN_TARGET} PRIVATE Threads::Threads)"); - cMakeCode.newLine(); - } - } - - private void buildParameterDefaults(CodeBuilder cMakeCode, LFGeneratorContext context) { + cMakeCode.pr(cMakeExtras); cMakeCode.newLine(); - cMakeCode.pr("# Set default values for build parameters\n"); - context - .getTargetConfig() - .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.indent(); - var v = "TRUE"; - if (value != null && !value.isEmpty()) { - v = value; - } - cMakeCode.pr("set(" + key + " " + v + ")\n"); - cMakeCode.unindent(); - cMakeCode.pr("endif()\n"); - }); - } - - private void preTargetDefinitionPlatformConfig( - LFGeneratorContext context, boolean hasMain, List sources, CodeBuilder cMakeCode) { - var targetConfig = context.getTargetConfig(); - var messageReporter = context.getErrorReporter(); - var executableName = context.getFileConfig().name; - var platformOptions = new PlatformOptions(); - if (targetConfig.isSet(PlatformProperty.INSTANCE)) { - platformOptions = targetConfig.get(PlatformProperty.INSTANCE); - } - - // Setup the project header for different platforms - switch (platformOptions.platform) { - case ZEPHYR: - cMakeCode.pr("# Set default configuration file. To add custom configurations,"); - cMakeCode.pr("# pass -- -DOVERLAY_CONFIG=my_config.prj to either cmake or west"); - cMakeCode.pr("set(CONF_FILE prj_lf.conf)"); - if (platformOptions.board != null) { - cMakeCode.pr("# Selecting board specified in target property"); - cMakeCode.pr("set(BOARD " + platformOptions.board + ")"); - } else { - cMakeCode.pr("# Selecting default board"); - cMakeCode.pr("set(BOARD qemu_cortex_m3)"); - } - cMakeCode.pr("# We recommend Zephyr v3.4.0 but we are compatible with older versions also"); - cMakeCode.pr("find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE} 3.4.0)"); - cMakeCode.newLine(); - cMakeCode.pr("project(" + executableName + " LANGUAGES C)"); - cMakeCode.newLine(); - break; - case RP2040: - // Attempt to set PICO_SDK_PATH if it is not already set. - if (System.getenv("PICO_SDK_PATH") == null) { - Path picoSDKPath = fileConfig.srcPkgPath.resolve("pico-sdk"); - if (Files.isDirectory(picoSDKPath)) { - messageReporter - .nowhere() - .info( - "pico-sdk library found at " - + picoSDKPath.toString() - + ". You can override this by setting PICO_SDK_PATH."); - cMakeCode.pr("# Define the root of the pico-sdk library."); - cMakeCode.pr("set(PICO_SDK_PATH " + picoSDKPath + ")"); - } else { - messageReporter - .nowhere() - .warning( - "No PICO_SDK_PATH environment variable and no pico-sdk directory " - + "at the package root directory. Pico SDK will not be found."); - } - } - cMakeCode.pr("include(pico_sdk_import.cmake)"); - cMakeCode.pr("project(" + executableName + " LANGUAGES C CXX ASM)"); - cMakeCode.newLine(); - var boardProperties = platformOptions.boardArray(); - // board type for rp2040 based boards - if (boardProperties.length < 1 || boardProperties[0].equals("")) { - cMakeCode.pr("set(PICO_BOARD pico)"); - } else { - cMakeCode.pr("set(PICO_BOARD \"" + boardProperties[0] + "\")"); - } - - // remove warnings for rp2040 only to make debug easier - cMakeCode.pr("set(CMAKE_C_FLAGS \"${CMAKE_C_FLAGS} -w\")"); - break; - default: - cMakeCode.pr("project(" + executableName + " LANGUAGES C)"); - cMakeCode.newLine(); - } - if (platformOptions.platform != Platform.AUTO) { - cMakeCode.pr("set(CMAKE_SYSTEM_NAME " + platformOptions.platform.getcMakeName() + ")"); - } - - // Setup main target for different platforms - switch (platformOptions.platform) { - case ZEPHYR: - cMakeCode.pr( - setUpMainTargetZephyr( - hasMain, - executableName, - Stream.concat(additionalSources.stream(), sources.stream()))); - break; - case RP2040: - cMakeCode.pr( - setUpMainTargetRp2040( - hasMain, - executableName, - Stream.concat(additionalSources.stream(), sources.stream()))); - break; - default: - cMakeCode.pr( - setUpMainTarget.getCmakeCode( - hasMain, - executableName, - Stream.concat(additionalSources.stream(), sources.stream()))); - } + return cMakeCode; } /** Provide a strategy for configuring the main target of the CMake build. */ 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 d367b49d7b..20d097138e 100644 --- a/core/src/main/java/org/lflang/generator/c/CGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CGenerator.java @@ -405,6 +405,10 @@ protected boolean isOSCompatible() { public void doGenerate(Resource resource, LFGeneratorContext context) { super.doGenerate(resource, context); + // Ensure that all target properties are loaded (subclasses might serve targets that do not + // support all of them (e.g., PythonGenerator). + Target.C.initialize(context.getTargetConfig()); + if (!GeneratorUtils.canGenerate(errorsOccurred(), mainDef, messageReporter, context)) return; if (!isOSCompatible()) return; // Incompatible OS and configuration From 3a7da58503a6223d896a8ff16a181b51cd302488 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Tue, 17 Oct 2023 23:12:28 -0700 Subject: [PATCH 102/145] More fixes --- .../org/lflang/federated/generator/FedFileConfig.java | 4 +++- .../java/org/lflang/generator/c/CCmakeGenerator.java | 2 -- .../main/java/org/lflang/generator/c/CGenerator.java | 10 ++++------ .../org/lflang/generator/python/PythonGenerator.java | 2 ++ .../Python/src/multiport/MultiportFromBankHierarchy.lf | 1 + 5 files changed, 10 insertions(+), 9 deletions(-) diff --git a/core/src/main/java/org/lflang/federated/generator/FedFileConfig.java b/core/src/main/java/org/lflang/federated/generator/FedFileConfig.java index f7e8657b71..97331fb14f 100644 --- a/core/src/main/java/org/lflang/federated/generator/FedFileConfig.java +++ b/core/src/main/java/org/lflang/federated/generator/FedFileConfig.java @@ -106,7 +106,9 @@ public void relativizePaths(FedTargetConfig targetConfig) { List.of(ProtobufsProperty.INSTANCE, FilesProperty.INSTANCE, CmakeIncludeProperty.INSTANCE) .forEach( p -> { - p.override(targetConfig, relativizePathList(targetConfig.get(p))); + if (targetConfig.isSet(p)) { + p.override(targetConfig, relativizePathList(targetConfig.get(p))); + } }); } 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 ea783b162a..5076f654fa 100644 --- a/core/src/main/java/org/lflang/generator/c/CCmakeGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CCmakeGenerator.java @@ -32,10 +32,8 @@ import java.util.List; import java.util.stream.Stream; import org.lflang.FileConfig; -import org.lflang.MessageReporter; import org.lflang.generator.CodeBuilder; import org.lflang.generator.LFGeneratorContext; -import org.lflang.target.TargetConfig; import org.lflang.target.property.AuthProperty; import org.lflang.target.property.BuildTypeProperty; import org.lflang.target.property.CmakeIncludeProperty; 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 20d097138e..3597933a73 100644 --- a/core/src/main/java/org/lflang/generator/c/CGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CGenerator.java @@ -405,10 +405,6 @@ protected boolean isOSCompatible() { public void doGenerate(Resource resource, LFGeneratorContext context) { super.doGenerate(resource, context); - // Ensure that all target properties are loaded (subclasses might serve targets that do not - // support all of them (e.g., PythonGenerator). - Target.C.initialize(context.getTargetConfig()); - if (!GeneratorUtils.canGenerate(errorsOccurred(), mainDef, messageReporter, context)) return; if (!isOSCompatible()) return; // Incompatible OS and configuration @@ -717,8 +713,10 @@ private void inspectReactorEResource(ReactorDecl reactor) { // Copy the user files and cmake-includes to the src-gen path of the main .lf file copyUserFiles(lfResource.getTargetConfig(), lfResource.getFileConfig()); // Merge the CMake includes from the imported file into the target config - CmakeIncludeProperty.INSTANCE.update( - this.targetConfig, lfResource.getTargetConfig().get(CmakeIncludeProperty.INSTANCE)); + if (lfResource.getTargetConfig().isSet(CmakeIncludeProperty.INSTANCE)) { + CmakeIncludeProperty.INSTANCE.update( + this.targetConfig, lfResource.getTargetConfig().get(CmakeIncludeProperty.INSTANCE)); + } } } } diff --git a/core/src/main/java/org/lflang/generator/python/PythonGenerator.java b/core/src/main/java/org/lflang/generator/python/PythonGenerator.java index 9236e5e87d..b64eb831a0 100644 --- a/core/src/main/java/org/lflang/generator/python/PythonGenerator.java +++ b/core/src/main/java/org/lflang/generator/python/PythonGenerator.java @@ -109,6 +109,8 @@ public PythonGenerator(LFGeneratorContext context) { private PythonGenerator( LFGeneratorContext context, PythonTypes types, CCmakeGenerator cmakeGenerator) { super(context, false, types, cmakeGenerator, new PythonDelayBodyGenerator(types)); + // Add the C target properties because they are used in the C code generator. + Target.C.initialize(context.getTargetConfig()); CompilerProperty.INSTANCE.override(this.targetConfig, "gcc"); // FIXME: why? this.targetConfig.reset(CompilerFlagsProperty.INSTANCE); this.types = types; diff --git a/test/Python/src/multiport/MultiportFromBankHierarchy.lf b/test/Python/src/multiport/MultiportFromBankHierarchy.lf index 20a66f2e1f..83c33e2284 100644 --- a/test/Python/src/multiport/MultiportFromBankHierarchy.lf +++ b/test/Python/src/multiport/MultiportFromBankHierarchy.lf @@ -11,6 +11,7 @@ reactor Source(bank_index=0) { output out reaction(startup) -> out {= + +++++; out.set(self.bank_index) =} } From 0d5a49e6d44a782cbfafd37b3deca125bdcf30f6 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Tue, 17 Oct 2023 23:20:30 -0700 Subject: [PATCH 103/145] Move no-runtime-validation target property to cpp --- core/src/main/java/org/lflang/target/Target.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/org/lflang/target/Target.java b/core/src/main/java/org/lflang/target/Target.java index 91e4e3c8f0..c4cc869fed 100644 --- a/core/src/main/java/org/lflang/target/Target.java +++ b/core/src/main/java/org/lflang/target/Target.java @@ -599,7 +599,6 @@ public void initialize(TargetConfig config) { FilesProperty.INSTANCE, HierarchicalBinProperty.INSTANCE, KeepaliveProperty.INSTANCE, - NoRuntimeValidationProperty.INSTANCE, PlatformProperty.INSTANCE, ProtobufsProperty.INSTANCE, SchedulerProperty.INSTANCE, @@ -614,6 +613,7 @@ public void initialize(TargetConfig config) { ExportDependencyGraphProperty.INSTANCE, ExportToYamlProperty.INSTANCE, ExternalRuntimePathProperty.INSTANCE, + NoRuntimeValidationProperty.INSTANCE, PrintStatisticsProperty.INSTANCE, Ros2DependenciesProperty.INSTANCE, Ros2Property.INSTANCE, From 10ca8d7809e215510d6dca7e41bf72ae4a703ea5 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Tue, 17 Oct 2023 23:26:05 -0700 Subject: [PATCH 104/145] Add auth to TypeScript --- core/src/main/java/org/lflang/target/Target.java | 1 + 1 file changed, 1 insertion(+) diff --git a/core/src/main/java/org/lflang/target/Target.java b/core/src/main/java/org/lflang/target/Target.java index c4cc869fed..b68b80794d 100644 --- a/core/src/main/java/org/lflang/target/Target.java +++ b/core/src/main/java/org/lflang/target/Target.java @@ -653,6 +653,7 @@ public void initialize(TargetConfig config) { ThreadingProperty.INSTANCE, WorkersProperty.INSTANCE); case TS -> config.register( + AuthProperty.INSTANCE, CoordinationOptionsProperty.INSTANCE, CoordinationProperty.INSTANCE, DockerProperty.INSTANCE, From b5c45f21fe6d2ade9c26b24c5852e286b27a2b75 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Tue, 17 Oct 2023 23:43:37 -0700 Subject: [PATCH 105/145] Add getOrDefault method as convenience --- .../federated/launcher/FedLauncherGenerator.java | 14 +++++++------- core/src/main/java/org/lflang/target/Target.java | 1 - .../main/java/org/lflang/target/TargetConfig.java | 8 ++++++++ 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/core/src/main/java/org/lflang/federated/launcher/FedLauncherGenerator.java b/core/src/main/java/org/lflang/federated/launcher/FedLauncherGenerator.java index 0986ad78dc..c559a433db 100644 --- a/core/src/main/java/org/lflang/federated/launcher/FedLauncherGenerator.java +++ b/core/src/main/java/org/lflang/federated/launcher/FedLauncherGenerator.java @@ -338,26 +338,26 @@ private String getRtiCommand(List federates, boolean isRemote) } else { commands.add("RTI -i ${FEDERATION_ID} \\"); } - if (targetConfig.get(AuthProperty.INSTANCE)) { + if (targetConfig.getOrDefault(AuthProperty.INSTANCE)) { commands.add(" -a \\"); } - if (targetConfig.get(TracingProperty.INSTANCE).isEnabled()) { + if (targetConfig.getOrDefault(TracingProperty.INSTANCE).isEnabled()) { commands.add(" -t \\"); } commands.addAll( List.of( " -n " + federates.size() + " \\", " -c " - + targetConfig.get(ClockSyncModeProperty.INSTANCE).toString() + + targetConfig.getOrDefault(ClockSyncModeProperty.INSTANCE).toString() + " \\")); - if (targetConfig.get(ClockSyncModeProperty.INSTANCE).equals(ClockSyncMode.ON)) { + if (targetConfig.getOrDefault(ClockSyncModeProperty.INSTANCE).equals(ClockSyncMode.ON)) { commands.add( "period " - + targetConfig.get(ClockSyncOptionsProperty.INSTANCE).period.toNanoSeconds() + + targetConfig.getOrDefault(ClockSyncOptionsProperty.INSTANCE).period.toNanoSeconds() + " \\"); } - if (targetConfig.get(ClockSyncModeProperty.INSTANCE).equals(ClockSyncMode.ON) - || targetConfig.get(ClockSyncModeProperty.INSTANCE).equals(ClockSyncMode.INIT)) { + if (targetConfig.getOrDefault(ClockSyncModeProperty.INSTANCE).equals(ClockSyncMode.ON) + || targetConfig.getOrDefault(ClockSyncModeProperty.INSTANCE).equals(ClockSyncMode.INIT)) { commands.add( "exchanges-per-interval " + targetConfig.get(ClockSyncOptionsProperty.INSTANCE).trials diff --git a/core/src/main/java/org/lflang/target/Target.java b/core/src/main/java/org/lflang/target/Target.java index b68b80794d..c4cc869fed 100644 --- a/core/src/main/java/org/lflang/target/Target.java +++ b/core/src/main/java/org/lflang/target/Target.java @@ -653,7 +653,6 @@ public void initialize(TargetConfig config) { ThreadingProperty.INSTANCE, WorkersProperty.INSTANCE); case TS -> config.register( - AuthProperty.INSTANCE, CoordinationOptionsProperty.INSTANCE, CoordinationProperty.INSTANCE, DockerProperty.INSTANCE, diff --git a/core/src/main/java/org/lflang/target/TargetConfig.java b/core/src/main/java/org/lflang/target/TargetConfig.java index 0aa1f38bcc..dc55f74d09 100644 --- a/core/src/main/java/org/lflang/target/TargetConfig.java +++ b/core/src/main/java/org/lflang/target/TargetConfig.java @@ -146,6 +146,14 @@ public T get(TargetProperty property) } } + public T getOrDefault(TargetProperty property) { + try { + return get(property); + } catch (IllegalArgumentException e) { + return property.initialValue(); + } + } + /** * Return {@code true} if this target property has been set (past initialization), {@code false} * otherwise. From e3926fc0e33f7980fbcf6edfec6b3afdf2609b13 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Tue, 17 Oct 2023 23:51:26 -0700 Subject: [PATCH 106/145] Missed another get --- .../org/lflang/federated/launcher/FedLauncherGenerator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/org/lflang/federated/launcher/FedLauncherGenerator.java b/core/src/main/java/org/lflang/federated/launcher/FedLauncherGenerator.java index c559a433db..45446d7796 100644 --- a/core/src/main/java/org/lflang/federated/launcher/FedLauncherGenerator.java +++ b/core/src/main/java/org/lflang/federated/launcher/FedLauncherGenerator.java @@ -360,7 +360,7 @@ private String getRtiCommand(List federates, boolean isRemote) || targetConfig.getOrDefault(ClockSyncModeProperty.INSTANCE).equals(ClockSyncMode.INIT)) { commands.add( "exchanges-per-interval " - + targetConfig.get(ClockSyncOptionsProperty.INSTANCE).trials + + targetConfig.getOrDefault(ClockSyncOptionsProperty.INSTANCE).trials + " \\"); } commands.add("&"); From 39588e69eb8c1301965c5d63b635c6b1b8883d0d Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Wed, 18 Oct 2023 00:18:22 -0700 Subject: [PATCH 107/145] Different way of addressing entanglement of Python and C codegen --- .../main/java/org/lflang/generator/c/CCmakeGenerator.java | 6 +++--- .../java/org/lflang/generator/python/PythonGenerator.java | 1 - 2 files changed, 3 insertions(+), 4 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 5076f654fa..fe24d9a7e7 100644 --- a/core/src/main/java/org/lflang/generator/c/CCmakeGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CCmakeGenerator.java @@ -127,7 +127,7 @@ CodeBuilder generateCMakeCode( // rp2040 : // arduino String[] boardProperties = {}; - var platformOptions = targetConfig.get(PlatformProperty.INSTANCE); + var platformOptions = targetConfig.getOrDefault(PlatformProperty.INSTANCE); if (platformOptions.board != null) { boardProperties = platformOptions.board.trim().split(":"); // Ignore whitespace @@ -228,7 +228,7 @@ CodeBuilder generateCMakeCode( cMakeCode.pr("set(CMAKE_CXX_STANDARD 17)"); cMakeCode.pr("set(CMAKE_CXX_STANDARD_REQUIRED ON)"); cMakeCode.newLine(); - if (!targetConfig.get(CmakeIncludeProperty.INSTANCE).isEmpty()) { + if (!targetConfig.getOrDefault(CmakeIncludeProperty.INSTANCE).isEmpty()) { // The user might be using the non-keyword form of // target_link_libraries. Ideally we would detect whether they are // doing that, but it is easier to just always have a deprecation @@ -428,7 +428,7 @@ CodeBuilder generateCMakeCode( cMakeCode.newLine(); // Add the include file - for (String includeFile : targetConfig.get(CmakeIncludeProperty.INSTANCE)) { + for (String includeFile : targetConfig.getOrDefault(CmakeIncludeProperty.INSTANCE)) { cMakeCode.pr("include(\"" + Path.of(includeFile).getFileName() + "\")"); } cMakeCode.newLine(); diff --git a/core/src/main/java/org/lflang/generator/python/PythonGenerator.java b/core/src/main/java/org/lflang/generator/python/PythonGenerator.java index b64eb831a0..e4477d2d0d 100644 --- a/core/src/main/java/org/lflang/generator/python/PythonGenerator.java +++ b/core/src/main/java/org/lflang/generator/python/PythonGenerator.java @@ -110,7 +110,6 @@ private PythonGenerator( LFGeneratorContext context, PythonTypes types, CCmakeGenerator cmakeGenerator) { super(context, false, types, cmakeGenerator, new PythonDelayBodyGenerator(types)); // Add the C target properties because they are used in the C code generator. - Target.C.initialize(context.getTargetConfig()); CompilerProperty.INSTANCE.override(this.targetConfig, "gcc"); // FIXME: why? this.targetConfig.reset(CompilerFlagsProperty.INSTANCE); this.types = types; From 077e577a57e5c04b8b87459370f5574dedb0d707 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Wed, 18 Oct 2023 00:31:18 -0700 Subject: [PATCH 108/145] Resolving more Python/C issues --- .../java/org/lflang/generator/c/CCompiler.java | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/core/src/main/java/org/lflang/generator/c/CCompiler.java b/core/src/main/java/org/lflang/generator/c/CCompiler.java index f050b4d84f..493b0be331 100644 --- a/core/src/main/java/org/lflang/generator/c/CCompiler.java +++ b/core/src/main/java/org/lflang/generator/c/CCompiler.java @@ -43,6 +43,7 @@ import org.lflang.target.property.CompilerFlagsProperty; import org.lflang.target.property.CompilerProperty; import org.lflang.target.property.PlatformProperty; +import org.lflang.target.property.PlatformProperty.PlatformOptions; import org.lflang.target.property.type.BuildTypeType.BuildType; import org.lflang.target.property.type.PlatformType.Platform; import org.lflang.util.FileUtil; @@ -187,11 +188,10 @@ public boolean runCCompiler(GeneratorBase generator, LFGeneratorContext context) + fileConfig.name + " finished with no errors."); } - - if (targetConfig.get(PlatformProperty.INSTANCE).platform == Platform.ZEPHYR - && targetConfig.get(PlatformProperty.INSTANCE).flash) { + var options = targetConfig.getOrDefault(PlatformProperty.INSTANCE); + if (options.platform == Platform.ZEPHYR && options.flash) { messageReporter.nowhere().info("Invoking flash command for Zephyr"); - LFCommand flash = buildWestFlashCommand(); + LFCommand flash = buildWestFlashCommand(options); int flashRet = flash.run(); if (flashRet != 0) { messageReporter.nowhere().error("West flash command failed with error code " + flashRet); @@ -316,10 +316,10 @@ public LFCommand buildCmakeCommand() { * qemu_* Return a flash command which runs the target as an emulation If ordinary target, return * {@code west flash} */ - public LFCommand buildWestFlashCommand() { + public LFCommand buildWestFlashCommand(PlatformOptions options) { // Set the build directory to be "build" Path buildPath = fileConfig.getSrcGenPath().resolve("build"); - String board = targetConfig.get(PlatformProperty.INSTANCE).board; + String board = options.board; LFCommand cmd; if (board == null || board.startsWith("qemu") || board.equals("native_posix")) { cmd = commandFactory.createCommand("west", List.of("build", "-t", "run"), buildPath); @@ -449,8 +449,7 @@ static String getTargetFileName(String fileName, boolean cppMode, TargetConfig t } static String getFileExtension(boolean cppMode, TargetConfig targetConfig) { - if (targetConfig.isSet(PlatformProperty.INSTANCE) - && targetConfig.get(PlatformProperty.INSTANCE).platform == Platform.ARDUINO) { + if (targetConfig.getOrDefault(PlatformProperty.INSTANCE).platform == Platform.ARDUINO) { return ".ino"; } if (cppMode) { From a92232e6e2df2620301029fcdfef3ea85a52addb Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Wed, 18 Oct 2023 13:27:53 -0700 Subject: [PATCH 109/145] Fix issue that was masked by #1859; fixed #1859 --- .../src/main/java/org/lflang/cli/CliBase.java | 18 +++++++++++++-- .../kotlin/org/lflang/cli/ReportingUtil.kt | 10 ++++++--- .../federated/extensions/CExtension.java | 22 ++++++++----------- .../federated/extensions/CExtensionUtils.java | 6 ++--- .../extensions/FedTargetExtension.java | 6 ++--- .../federated/extensions/PythonExtension.java | 8 +++---- .../federated/extensions/TSExtension.java | 6 ++--- .../federated/generator/FedEmitter.java | 6 ++--- .../federated/generator/FedGenerator.java | 8 +++---- .../federated/generator/FedImportEmitter.java | 2 +- .../generator/FedPreambleEmitter.java | 2 +- .../federated/generator/FedTargetEmitter.java | 2 +- ...tConfig.java => FederateTargetConfig.java} | 9 +++----- ...eConfig.java => FederationFileConfig.java} | 17 ++++++-------- .../federated/launcher/BuildConfig.java | 6 ++--- .../federated/launcher/CBuildConfig.java | 4 ++-- .../launcher/FedLauncherGenerator.java | 8 +++---- .../federated/launcher/PyBuildConfig.java | 4 ++-- .../federated/launcher/TsBuildConfig.java | 4 ++-- .../org/lflang/generator/LFGenerator.java | 4 ++-- .../org/lflang/generator/c/CCompiler.java | 14 ++---------- .../org/lflang/generator/c/CGenerator.java | 6 ++--- .../java/org/lflang/target/TargetConfig.java | 8 +++++++ .../tests/compiler/TargetConfigTests.java | 6 +++-- .../multiport/MultiportFromBankHierarchy.lf | 1 - 25 files changed, 95 insertions(+), 92 deletions(-) rename core/src/main/java/org/lflang/federated/generator/{FedTargetConfig.java => FederateTargetConfig.java} (94%) rename core/src/main/java/org/lflang/federated/generator/{FedFileConfig.java => FederationFileConfig.java} (88%) diff --git a/cli/base/src/main/java/org/lflang/cli/CliBase.java b/cli/base/src/main/java/org/lflang/cli/CliBase.java index 3e95afb334..f8c014ec46 100644 --- a/cli/base/src/main/java/org/lflang/cli/CliBase.java +++ b/cli/base/src/main/java/org/lflang/cli/CliBase.java @@ -223,7 +223,10 @@ protected Path getOutputRoot() { /** If some errors were collected, print them and abort execution. Otherwise, return. */ protected void exitIfCollectedErrors() { if (issueCollector.getErrorsOccurred()) { - // if there are errors, don't print warnings. + + // Print warnings if there are any. + printWarningsIfAny(); + List errors = printErrorsIfAny(); String cause = errors.size() + " previous error"; if (errors.size() > 1) { @@ -234,7 +237,18 @@ protected void exitIfCollectedErrors() { } /** - * If any errors were collected, print them, then return them. + * If any warnings were collected, print them, then return them. + * + * @return A list of collected warnings. + */ + public List printWarningsIfAny() { + List errors = issueCollector.getWarnings(); + errors.forEach(reporter::printIssue); + return errors; + } + + /** + * If any warnings were collected, print them, then return them. * * @return A list of collected errors. */ diff --git a/cli/base/src/main/kotlin/org/lflang/cli/ReportingUtil.kt b/cli/base/src/main/kotlin/org/lflang/cli/ReportingUtil.kt index b7c4826bdf..e2cc147ec2 100644 --- a/cli/base/src/main/kotlin/org/lflang/cli/ReportingUtil.kt +++ b/cli/base/src/main/kotlin/org/lflang/cli/ReportingUtil.kt @@ -176,7 +176,7 @@ data class LfIssue( @Singleton // one instance per injector class IssueCollector { private val map = mutableMapOf>() - /** Whether any errors occurred.*/ + /** Whether any errors occurred. */ val errorsOccurred: Boolean get() = map[Severity.ERROR]?.isNotEmpty() == true fun accept(issue: LfIssue) { @@ -184,9 +184,13 @@ class IssueCollector { set += issue } - /** Sorted list of all errors.*/ + /** Sorted list of all errors. */ val errors: List get() = map[Severity.ERROR].orEmpty().sorted() - /** Sorted list of all issues.*/ + + /** Sorted list of all warnings. */ + val warnings: List get() = map[Severity.WARNING].orEmpty().sorted() + + /** Sorted list of all issues. */ val allIssues: List get() = map.values.flatten().sorted() } 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 b7191b9072..7b6f1054f1 100644 --- a/core/src/main/java/org/lflang/federated/extensions/CExtension.java +++ b/core/src/main/java/org/lflang/federated/extensions/CExtension.java @@ -39,8 +39,8 @@ import org.lflang.ast.ASTUtils; import org.lflang.federated.generator.FedASTUtils; import org.lflang.federated.generator.FedConnectionInstance; -import org.lflang.federated.generator.FedFileConfig; import org.lflang.federated.generator.FederateInstance; +import org.lflang.federated.generator.FederationFileConfig; import org.lflang.federated.launcher.RtiConfig; import org.lflang.federated.serialization.FedROS2CPPSerialization; import org.lflang.generator.CodeBuilder; @@ -78,7 +78,7 @@ public void initializeTargetConfig( LFGeneratorContext context, int numOfFederates, FederateInstance federate, - FedFileConfig fileConfig, + FederationFileConfig fileConfig, MessageReporter messageReporter, RtiConfig rtiConfig) throws IOException { @@ -100,7 +100,7 @@ public void initializeTargetConfig( } /** Generate a cmake-include file for {@code federate} if needed. */ - protected void generateCMakeInclude(FederateInstance federate, FedFileConfig fileConfig) + protected void generateCMakeInclude(FederateInstance federate, FederationFileConfig fileConfig) throws IOException { CExtensionUtils.generateCMakeInclude(federate, fileConfig); } @@ -485,7 +485,7 @@ public String getNetworkBufferType() { /** Put the C preamble in a {@code include/_federate.name + _preamble.h} file. */ protected final void writePreambleFile( FederateInstance federate, - FedFileConfig fileConfig, + FederationFileConfig fileConfig, RtiConfig rtiConfig, MessageReporter messageReporter) throws IOException { @@ -505,7 +505,7 @@ protected final void writePreambleFile( @Override public String generatePreamble( FederateInstance federate, - FedFileConfig fileConfig, + FederationFileConfig fileConfig, RtiConfig rtiConfig, MessageReporter messageReporter) throws IOException { @@ -594,7 +594,7 @@ protected String makePreamble( /** Generate preamble code needed for enabled serializers of the federate. */ protected String generateSerializationIncludes( - FederateInstance federate, FedFileConfig fileConfig) { + FederateInstance federate, FederationFileConfig fileConfig) { return CExtensionUtils.generateSerializationIncludes(federate); } @@ -741,18 +741,14 @@ private String generateCodeToInitializeFederate(FederateInstance federate, RtiCo " _fed.sockets_for_outbound_p2p_connections[i] = -1;", "}")); } - + var clockSyncOptions = federate.targetConfig.getOrDefault(ClockSyncOptionsProperty.INSTANCE); // If a test clock offset has been specified, insert code to set it here. - if (federate.targetConfig.get(ClockSyncOptionsProperty.INSTANCE).testOffset != null) { + if (clockSyncOptions.testOffset != null) { code.pr( "lf_set_physical_clock_offset((1 + " + federate.id + ") * " - + federate - .targetConfig - .get(ClockSyncOptionsProperty.INSTANCE) - .testOffset - .toNanoSeconds() + + clockSyncOptions.testOffset.toNanoSeconds() + "LL);"); } diff --git a/core/src/main/java/org/lflang/federated/extensions/CExtensionUtils.java b/core/src/main/java/org/lflang/federated/extensions/CExtensionUtils.java index 6f535da595..2b60e60c11 100644 --- a/core/src/main/java/org/lflang/federated/extensions/CExtensionUtils.java +++ b/core/src/main/java/org/lflang/federated/extensions/CExtensionUtils.java @@ -10,8 +10,8 @@ import org.lflang.InferredType; import org.lflang.MessageReporter; import org.lflang.ast.ASTUtils; -import org.lflang.federated.generator.FedFileConfig; import org.lflang.federated.generator.FederateInstance; +import org.lflang.federated.generator.FederationFileConfig; import org.lflang.federated.launcher.RtiConfig; import org.lflang.federated.serialization.FedROS2CPPSerialization; import org.lflang.federated.serialization.SupportedSerializers; @@ -280,8 +280,8 @@ public static void addClockSyncCompileDefinitions(FederateInstance federate) { } /** Generate a file to be included by CMake. */ - public static void generateCMakeInclude(FederateInstance federate, FedFileConfig fileConfig) - throws IOException { + public static void generateCMakeInclude( + FederateInstance federate, FederationFileConfig fileConfig) throws IOException { Files.createDirectories(fileConfig.getSrcPath().resolve("include")); Path cmakeIncludePath = diff --git a/core/src/main/java/org/lflang/federated/extensions/FedTargetExtension.java b/core/src/main/java/org/lflang/federated/extensions/FedTargetExtension.java index 7afafa105c..e708c117d7 100644 --- a/core/src/main/java/org/lflang/federated/extensions/FedTargetExtension.java +++ b/core/src/main/java/org/lflang/federated/extensions/FedTargetExtension.java @@ -4,8 +4,8 @@ import org.lflang.InferredType; import org.lflang.MessageReporter; import org.lflang.federated.generator.FedConnectionInstance; -import org.lflang.federated.generator.FedFileConfig; import org.lflang.federated.generator.FederateInstance; +import org.lflang.federated.generator.FederationFileConfig; import org.lflang.federated.launcher.RtiConfig; import org.lflang.generator.LFGeneratorContext; import org.lflang.lf.Action; @@ -30,7 +30,7 @@ void initializeTargetConfig( LFGeneratorContext context, int numOfFederates, FederateInstance federate, - FedFileConfig fileConfig, + FederationFileConfig fileConfig, MessageReporter messageReporter, RtiConfig rtiConfig) throws IOException; @@ -112,7 +112,7 @@ default void annotateReaction(Reaction reaction) {} */ String generatePreamble( FederateInstance federate, - FedFileConfig fileConfig, + FederationFileConfig fileConfig, RtiConfig rtiConfig, MessageReporter messageReporter) throws IOException; diff --git a/core/src/main/java/org/lflang/federated/extensions/PythonExtension.java b/core/src/main/java/org/lflang/federated/extensions/PythonExtension.java index 25c7198fe9..d6dc3ce44a 100644 --- a/core/src/main/java/org/lflang/federated/extensions/PythonExtension.java +++ b/core/src/main/java/org/lflang/federated/extensions/PythonExtension.java @@ -31,8 +31,8 @@ import org.lflang.MessageReporter; import org.lflang.ast.ASTUtils; import org.lflang.federated.generator.FedConnectionInstance; -import org.lflang.federated.generator.FedFileConfig; import org.lflang.federated.generator.FederateInstance; +import org.lflang.federated.generator.FederationFileConfig; import org.lflang.federated.launcher.RtiConfig; import org.lflang.federated.serialization.FedNativePythonSerialization; import org.lflang.federated.serialization.FedSerialization; @@ -52,11 +52,11 @@ public class PythonExtension extends CExtension { @Override - protected void generateCMakeInclude(FederateInstance federate, FedFileConfig fileConfig) {} + protected void generateCMakeInclude(FederateInstance federate, FederationFileConfig fileConfig) {} @Override protected String generateSerializationIncludes( - FederateInstance federate, FedFileConfig fileConfig) { + FederateInstance federate, FederationFileConfig fileConfig) { CodeBuilder code = new CodeBuilder(); for (SupportedSerializers serialization : federate.enabledSerializers) { switch (serialization) { @@ -189,7 +189,7 @@ public void annotateReaction(Reaction reaction) { @Override public String generatePreamble( FederateInstance federate, - FedFileConfig fileConfig, + FederationFileConfig fileConfig, RtiConfig rtiConfig, MessageReporter messageReporter) throws IOException { diff --git a/core/src/main/java/org/lflang/federated/extensions/TSExtension.java b/core/src/main/java/org/lflang/federated/extensions/TSExtension.java index 88579137d3..9b0abce29f 100644 --- a/core/src/main/java/org/lflang/federated/extensions/TSExtension.java +++ b/core/src/main/java/org/lflang/federated/extensions/TSExtension.java @@ -11,8 +11,8 @@ import org.lflang.ast.ASTUtils; import org.lflang.federated.generator.FedASTUtils; import org.lflang.federated.generator.FedConnectionInstance; -import org.lflang.federated.generator.FedFileConfig; import org.lflang.federated.generator.FederateInstance; +import org.lflang.federated.generator.FederationFileConfig; import org.lflang.federated.launcher.RtiConfig; import org.lflang.generator.LFGeneratorContext; import org.lflang.generator.ReactorInstance; @@ -35,7 +35,7 @@ public void initializeTargetConfig( LFGeneratorContext context, int numOfFederates, FederateInstance federate, - FedFileConfig fileConfig, + FederationFileConfig fileConfig, MessageReporter messageReporter, RtiConfig rtiConfig) {} @@ -160,7 +160,7 @@ public String getNetworkBufferType() { @Override public String generatePreamble( FederateInstance federate, - FedFileConfig fileConfig, + FederationFileConfig fileConfig, RtiConfig rtiConfig, MessageReporter messageReporter) { var minOutputDelay = getMinOutputDelay(federate, messageReporter); diff --git a/core/src/main/java/org/lflang/federated/generator/FedEmitter.java b/core/src/main/java/org/lflang/federated/generator/FedEmitter.java index 91f85bd340..5d6452df77 100644 --- a/core/src/main/java/org/lflang/federated/generator/FedEmitter.java +++ b/core/src/main/java/org/lflang/federated/generator/FedEmitter.java @@ -14,13 +14,13 @@ /** Helper class to generate code for federates. */ public class FedEmitter { - private final FedFileConfig fileConfig; + private final FederationFileConfig fileConfig; private final Reactor originalMainReactor; private final MessageReporter messageReporter; private final RtiConfig rtiConfig; public FedEmitter( - FedFileConfig fileConfig, + FederationFileConfig fileConfig, Reactor originalMainReactor, MessageReporter messageReporter, RtiConfig rtiConfig) { @@ -66,7 +66,7 @@ Map generateFederate( return codeMapMap; } - public static Path lfFilePath(FedFileConfig fileConfig, FederateInstance federate) { + public static Path lfFilePath(FederationFileConfig fileConfig, FederateInstance federate) { return fileConfig.getSrcPath().resolve(federate.name + ".lf"); } } 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 07b887c5ab..3e56aa1ba0 100644 --- a/core/src/main/java/org/lflang/federated/generator/FedGenerator.java +++ b/core/src/main/java/org/lflang/federated/generator/FedGenerator.java @@ -77,7 +77,7 @@ public class FedGenerator { * File configuration to be used during the LF code generation stage (not the target code * generation stage of individual federates). */ - private final FedFileConfig fileConfig; + private final FederationFileConfig fileConfig; /** Configuration of the RTI. */ final RtiConfig rtiConfig = new RtiConfig(); @@ -105,7 +105,7 @@ public class FedGenerator { * reporter. */ public FedGenerator(LFGeneratorContext context) { - this.fileConfig = (FedFileConfig) context.getFileConfig(); + this.fileConfig = (FederationFileConfig) context.getFileConfig(); this.targetConfig = context.getTargetConfig(); this.messageReporter = context.getErrorReporter(); } @@ -472,9 +472,7 @@ private List getFederateInstances( // Assign an integer ID to the federate. int federateID = federates.size(); var resource = instantiation.getReactorClass().eResource(); - var federateTargetConfig = - new FedTargetConfig( - context, resource); // FIXME: Based on the target, need to load properties. + var federateTargetConfig = new FederateTargetConfig(context, resource); FederateInstance federateInstance = new FederateInstance( instantiation, federateID, i, bankWidth, federateTargetConfig, messageReporter); diff --git a/core/src/main/java/org/lflang/federated/generator/FedImportEmitter.java b/core/src/main/java/org/lflang/federated/generator/FedImportEmitter.java index 57eed50eb7..59b2fae58b 100644 --- a/core/src/main/java/org/lflang/federated/generator/FedImportEmitter.java +++ b/core/src/main/java/org/lflang/federated/generator/FedImportEmitter.java @@ -20,7 +20,7 @@ public class FedImportEmitter { private static final Set visitedImports = new HashSet<>(); /** Generate import statements for {@code federate}. */ - String generateImports(FederateInstance federate, FedFileConfig fileConfig) { + String generateImports(FederateInstance federate, FederationFileConfig fileConfig) { var imports = ((Model) federate.instantiation.eContainer().eContainer()) .getImports().stream().filter(federate::references).toList(); diff --git a/core/src/main/java/org/lflang/federated/generator/FedPreambleEmitter.java b/core/src/main/java/org/lflang/federated/generator/FedPreambleEmitter.java index 7966bc73dd..c74a605138 100644 --- a/core/src/main/java/org/lflang/federated/generator/FedPreambleEmitter.java +++ b/core/src/main/java/org/lflang/federated/generator/FedPreambleEmitter.java @@ -21,7 +21,7 @@ public FedPreambleEmitter() {} */ String generatePreamble( FederateInstance federate, - FedFileConfig fileConfig, + FederationFileConfig fileConfig, RtiConfig rtiConfig, MessageReporter messageReporter) throws IOException { diff --git a/core/src/main/java/org/lflang/federated/generator/FedTargetEmitter.java b/core/src/main/java/org/lflang/federated/generator/FedTargetEmitter.java index ff273e7ead..53f3823f72 100644 --- a/core/src/main/java/org/lflang/federated/generator/FedTargetEmitter.java +++ b/core/src/main/java/org/lflang/federated/generator/FedTargetEmitter.java @@ -13,7 +13,7 @@ String generateTarget( LFGeneratorContext context, int numOfFederates, FederateInstance federate, - FedFileConfig fileConfig, + FederationFileConfig fileConfig, MessageReporter messageReporter, RtiConfig rtiConfig) throws IOException { diff --git a/core/src/main/java/org/lflang/federated/generator/FedTargetConfig.java b/core/src/main/java/org/lflang/federated/generator/FederateTargetConfig.java similarity index 94% rename from core/src/main/java/org/lflang/federated/generator/FedTargetConfig.java rename to core/src/main/java/org/lflang/federated/generator/FederateTargetConfig.java index bfc8dd6194..556c3988da 100644 --- a/core/src/main/java/org/lflang/federated/generator/FedTargetConfig.java +++ b/core/src/main/java/org/lflang/federated/generator/FederateTargetConfig.java @@ -16,7 +16,6 @@ import org.lflang.target.TargetConfig; import org.lflang.target.property.ClockSyncModeProperty; import org.lflang.target.property.ClockSyncOptionsProperty; -import org.lflang.target.property.FedSetupProperty; import org.lflang.util.FileUtil; /** @@ -25,7 +24,7 @@ * * @author Marten Lohstroh */ -public class FedTargetConfig extends TargetConfig { +public class FederateTargetConfig extends TargetConfig { /** * Create a configuration for a federate given a main context and the resource in which the class @@ -34,7 +33,7 @@ public class FedTargetConfig extends TargetConfig { * @param context The generator context. * @param federateResource The resource in which to find the reactor class of the federate. */ - public FedTargetConfig(LFGeneratorContext context, Resource federateResource) { + 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( @@ -43,14 +42,12 @@ public FedTargetConfig(LFGeneratorContext context, Resource federateResource) { context.getArgs(), context.getErrorReporter()); - this.register(FedSetupProperty.INSTANCE); - mergeImportedConfig( federateResource, context.getFileConfig().resource, context.getErrorReporter()); clearPropertiesToIgnore(); - ((FedFileConfig) context.getFileConfig()).relativizePaths(this); + ((FederationFileConfig) context.getFileConfig()).relativizePaths(this); } /** diff --git a/core/src/main/java/org/lflang/federated/generator/FedFileConfig.java b/core/src/main/java/org/lflang/federated/generator/FederationFileConfig.java similarity index 88% rename from core/src/main/java/org/lflang/federated/generator/FedFileConfig.java rename to core/src/main/java/org/lflang/federated/generator/FederationFileConfig.java index 97331fb14f..d8946a2ad2 100644 --- a/core/src/main/java/org/lflang/federated/generator/FedFileConfig.java +++ b/core/src/main/java/org/lflang/federated/generator/FederationFileConfig.java @@ -38,20 +38,19 @@ import org.lflang.util.FileUtil; /** - * A subclass of @see FileConfig that extends the base functionality to add support for compiling - * federated LF programs. The code generator should create one instance of this class for each - * federate. + * A subclass of {@see FileConfig} that extends the base functionality to add support for compiling + * federated LF programs. * * @author Soroush Bateni */ -public class FedFileConfig extends FileConfig { +public class FederationFileConfig extends FileConfig { - public FedFileConfig(Resource resource, Path srcGenBasePath, boolean useHierarchicalBin) + public FederationFileConfig(Resource resource, Path srcGenBasePath, boolean useHierarchicalBin) throws IOException { super(resource, srcGenBasePath, useHierarchicalBin); } - public FedFileConfig(FileConfig fileConfig) throws IOException { + public FederationFileConfig(FileConfig fileConfig) throws IOException { super(fileConfig.resource, fileConfig.getSrcGenBasePath(), fileConfig.useHierarchicalBin); } @@ -102,13 +101,11 @@ public void doClean() throws IOException { * Relativize target properties that involve paths like files and cmake-include to be relative to * the generated .lf file for the federate. */ - public void relativizePaths(FedTargetConfig targetConfig) { + public void relativizePaths(FederateTargetConfig targetConfig) { List.of(ProtobufsProperty.INSTANCE, FilesProperty.INSTANCE, CmakeIncludeProperty.INSTANCE) .forEach( p -> { - if (targetConfig.isSet(p)) { - p.override(targetConfig, relativizePathList(targetConfig.get(p))); - } + p.override(targetConfig, relativizePathList(targetConfig.get(p))); }); } diff --git a/core/src/main/java/org/lflang/federated/launcher/BuildConfig.java b/core/src/main/java/org/lflang/federated/launcher/BuildConfig.java index 48b297da01..4863346217 100644 --- a/core/src/main/java/org/lflang/federated/launcher/BuildConfig.java +++ b/core/src/main/java/org/lflang/federated/launcher/BuildConfig.java @@ -1,8 +1,8 @@ package org.lflang.federated.launcher; import org.lflang.MessageReporter; -import org.lflang.federated.generator.FedFileConfig; import org.lflang.federated.generator.FederateInstance; +import org.lflang.federated.generator.FederationFileConfig; /** A collection of methods used for building target code for federates. */ public abstract class BuildConfig { @@ -14,7 +14,7 @@ public abstract class BuildConfig { protected final MessageReporter messageReporter; /** The file configuration of the federation that the federate belongs to. */ - protected final FedFileConfig fileConfig; + protected final FederationFileConfig fileConfig; /** * Create a new build configuration. @@ -24,7 +24,7 @@ public abstract class BuildConfig { * @param messageReporter An error reporter to report problems. */ public BuildConfig( - FederateInstance federate, FedFileConfig fileConfig, MessageReporter messageReporter) { + FederateInstance federate, FederationFileConfig fileConfig, MessageReporter messageReporter) { this.messageReporter = messageReporter; this.federate = federate; this.fileConfig = fileConfig; diff --git a/core/src/main/java/org/lflang/federated/launcher/CBuildConfig.java b/core/src/main/java/org/lflang/federated/launcher/CBuildConfig.java index 698da57b89..341ad3a066 100644 --- a/core/src/main/java/org/lflang/federated/launcher/CBuildConfig.java +++ b/core/src/main/java/org/lflang/federated/launcher/CBuildConfig.java @@ -27,8 +27,8 @@ import java.io.File; import org.lflang.MessageReporter; -import org.lflang.federated.generator.FedFileConfig; import org.lflang.federated.generator.FederateInstance; +import org.lflang.federated.generator.FederationFileConfig; import org.lflang.generator.c.CCompiler; /** @@ -41,7 +41,7 @@ public class CBuildConfig extends BuildConfig { public CBuildConfig( - FederateInstance federate, FedFileConfig fileConfig, MessageReporter messageReporter) { + FederateInstance federate, FederationFileConfig fileConfig, MessageReporter messageReporter) { super(federate, fileConfig, messageReporter); } diff --git a/core/src/main/java/org/lflang/federated/launcher/FedLauncherGenerator.java b/core/src/main/java/org/lflang/federated/launcher/FedLauncherGenerator.java index 45446d7796..ac827ceda7 100644 --- a/core/src/main/java/org/lflang/federated/launcher/FedLauncherGenerator.java +++ b/core/src/main/java/org/lflang/federated/launcher/FedLauncherGenerator.java @@ -34,8 +34,8 @@ import java.util.ArrayList; import java.util.List; import org.lflang.MessageReporter; -import org.lflang.federated.generator.FedFileConfig; import org.lflang.federated.generator.FederateInstance; +import org.lflang.federated.generator.FederationFileConfig; import org.lflang.target.TargetConfig; import org.lflang.target.property.AuthProperty; import org.lflang.target.property.ClockSyncModeProperty; @@ -51,7 +51,7 @@ */ public class FedLauncherGenerator { protected TargetConfig targetConfig; - protected FedFileConfig fileConfig; + protected FederationFileConfig fileConfig; protected MessageReporter messageReporter; /** @@ -61,7 +61,7 @@ public class FedLauncherGenerator { * generation */ public FedLauncherGenerator( - TargetConfig targetConfig, FedFileConfig fileConfig, MessageReporter messageReporter) { + TargetConfig targetConfig, FederationFileConfig fileConfig, MessageReporter messageReporter) { this.targetConfig = targetConfig; this.fileConfig = fileConfig; this.messageReporter = messageReporter; @@ -527,7 +527,7 @@ private String getFedLocalLaunchCode( * @param fileConfig The file configuration of the federation to which the federate belongs. */ private BuildConfig getBuildConfig( - FederateInstance federate, FedFileConfig fileConfig, MessageReporter messageReporter) { + FederateInstance federate, FederationFileConfig fileConfig, MessageReporter messageReporter) { return switch (federate.targetConfig.target) { case C, CCPP -> new CBuildConfig(federate, fileConfig, messageReporter); case Python -> new PyBuildConfig(federate, fileConfig, messageReporter); diff --git a/core/src/main/java/org/lflang/federated/launcher/PyBuildConfig.java b/core/src/main/java/org/lflang/federated/launcher/PyBuildConfig.java index 98f1c16ad6..00cf3a84dc 100644 --- a/core/src/main/java/org/lflang/federated/launcher/PyBuildConfig.java +++ b/core/src/main/java/org/lflang/federated/launcher/PyBuildConfig.java @@ -1,13 +1,13 @@ package org.lflang.federated.launcher; import org.lflang.MessageReporter; -import org.lflang.federated.generator.FedFileConfig; import org.lflang.federated.generator.FederateInstance; +import org.lflang.federated.generator.FederationFileConfig; public class PyBuildConfig extends BuildConfig { public PyBuildConfig( - FederateInstance federate, FedFileConfig fileConfig, MessageReporter messageReporter) { + FederateInstance federate, FederationFileConfig fileConfig, MessageReporter messageReporter) { super(federate, fileConfig, messageReporter); } diff --git a/core/src/main/java/org/lflang/federated/launcher/TsBuildConfig.java b/core/src/main/java/org/lflang/federated/launcher/TsBuildConfig.java index 82a0e2c7ae..43b5b476f4 100644 --- a/core/src/main/java/org/lflang/federated/launcher/TsBuildConfig.java +++ b/core/src/main/java/org/lflang/federated/launcher/TsBuildConfig.java @@ -26,8 +26,8 @@ package org.lflang.federated.launcher; import org.lflang.MessageReporter; -import org.lflang.federated.generator.FedFileConfig; import org.lflang.federated.generator.FederateInstance; +import org.lflang.federated.generator.FederationFileConfig; /** * Utility class that can be used to create a launcher for federated LF programs that are written in @@ -40,7 +40,7 @@ public class TsBuildConfig extends BuildConfig { public TsBuildConfig( - FederateInstance federate, FedFileConfig fileConfig, MessageReporter messageReporter) { + FederateInstance federate, FederationFileConfig fileConfig, MessageReporter messageReporter) { super(federate, fileConfig, messageReporter); } diff --git a/core/src/main/java/org/lflang/generator/LFGenerator.java b/core/src/main/java/org/lflang/generator/LFGenerator.java index a7776c7b57..b43254f1ae 100644 --- a/core/src/main/java/org/lflang/generator/LFGenerator.java +++ b/core/src/main/java/org/lflang/generator/LFGenerator.java @@ -14,8 +14,8 @@ import org.lflang.MessageReporter; import org.lflang.ast.ASTUtils; import org.lflang.federated.generator.FedASTUtils; -import org.lflang.federated.generator.FedFileConfig; import org.lflang.federated.generator.FedGenerator; +import org.lflang.federated.generator.FederationFileConfig; import org.lflang.generator.c.CFileConfig; import org.lflang.generator.c.CGenerator; import org.lflang.generator.cpp.CppFileConfig; @@ -52,7 +52,7 @@ public static FileConfig createFileConfig( try { if (FedASTUtils.findFederatedReactor(resource) != null) { - return new FedFileConfig(resource, srcGenBasePath, useHierarchicalBin); + return new FederationFileConfig(resource, srcGenBasePath, useHierarchicalBin); } return switch (target) { diff --git a/core/src/main/java/org/lflang/generator/c/CCompiler.java b/core/src/main/java/org/lflang/generator/c/CCompiler.java index 493b0be331..46e6175983 100644 --- a/core/src/main/java/org/lflang/generator/c/CCompiler.java +++ b/core/src/main/java/org/lflang/generator/c/CCompiler.java @@ -138,12 +138,7 @@ public boolean runCCompiler(GeneratorBase generator, LFGeneratorContext context) if (cMakeReturnCode != 0 && context.getMode() == LFGeneratorContext.Mode.STANDALONE && !outputContainsKnownCMakeErrors(compile.getErrors())) { - messageReporter - .nowhere() - .error( - targetConfig.get(CompilerProperty.INSTANCE) - + " failed with error code " - + cMakeReturnCode); + messageReporter.nowhere().error("CMake failed with error code " + cMakeReturnCode); } // For warnings (vs. errors), the return code is 0. @@ -164,12 +159,7 @@ public boolean runCCompiler(GeneratorBase generator, LFGeneratorContext context) if (makeReturnCode != 0 && context.getMode() == LFGeneratorContext.Mode.STANDALONE && !outputContainsKnownCMakeErrors(build.getErrors())) { - messageReporter - .nowhere() - .error( - targetConfig.get(CompilerProperty.INSTANCE) - + " failed with error code " - + makeReturnCode); + messageReporter.nowhere().error("CMake failed with error code " + makeReturnCode); } // For warnings (vs. errors), the return code is 0. 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 3597933a73..d367b49d7b 100644 --- a/core/src/main/java/org/lflang/generator/c/CGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CGenerator.java @@ -713,10 +713,8 @@ private void inspectReactorEResource(ReactorDecl reactor) { // Copy the user files and cmake-includes to the src-gen path of the main .lf file copyUserFiles(lfResource.getTargetConfig(), lfResource.getFileConfig()); // Merge the CMake includes from the imported file into the target config - if (lfResource.getTargetConfig().isSet(CmakeIncludeProperty.INSTANCE)) { - CmakeIncludeProperty.INSTANCE.update( - this.targetConfig, lfResource.getTargetConfig().get(CmakeIncludeProperty.INSTANCE)); - } + CmakeIncludeProperty.INSTANCE.update( + this.targetConfig, lfResource.getTargetConfig().get(CmakeIncludeProperty.INSTANCE)); } } } diff --git a/core/src/main/java/org/lflang/target/TargetConfig.java b/core/src/main/java/org/lflang/target/TargetConfig.java index dc55f74d09..35bfec5023 100644 --- a/core/src/main/java/org/lflang/target/TargetConfig.java +++ b/core/src/main/java/org/lflang/target/TargetConfig.java @@ -45,6 +45,7 @@ import org.lflang.lf.Model; import org.lflang.lf.TargetDecl; import org.lflang.target.property.FastProperty; +import org.lflang.target.property.FedSetupProperty; import org.lflang.target.property.LoggingProperty; import org.lflang.target.property.NoCompileProperty; import org.lflang.target.property.TimeOutProperty; @@ -103,6 +104,10 @@ public TargetConfig( Properties cliArgs, MessageReporter messageReporter) { this(target); + + // Load target properties for internal use. + this.register(FedSetupProperty.INSTANCE); + if (properties != null) { List pairs = properties.getPairs(); this.load(pairs, messageReporter); @@ -214,6 +219,9 @@ public void load(List pairs, MessageReporter err) { if (p.isPresent()) { var property = p.get(); property.update(this, pair.getValue(), err); + } else { + err.nowhere() + .warning("Attempting to load unrecognized target property: " + pair.getName()); } }); } diff --git a/core/src/test/java/org/lflang/tests/compiler/TargetConfigTests.java b/core/src/test/java/org/lflang/tests/compiler/TargetConfigTests.java index 8288d17876..dd5e4b882d 100644 --- a/core/src/test/java/org/lflang/tests/compiler/TargetConfigTests.java +++ b/core/src/test/java/org/lflang/tests/compiler/TargetConfigTests.java @@ -14,7 +14,7 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.io.TempDir; -import org.lflang.federated.generator.FedFileConfig; +import org.lflang.federated.generator.FederationFileConfig; import org.lflang.generator.GeneratorUtils; import org.lflang.generator.LFGenerator; import org.lflang.generator.LFGeneratorContext.Mode; @@ -97,7 +97,9 @@ public void testFederation(@TempDir Path tempDir) throws Exception { String lfSrc = Files.readAllLines( - ((FedFileConfig) context.getFileConfig()).getSrcPath().resolve("federate__a.lf")) + ((FederationFileConfig) context.getFileConfig()) + .getSrcPath() + .resolve("federate__a.lf")) .stream() .reduce("\n", String::concat); Model federate = parser.parse(lfSrc); diff --git a/test/Python/src/multiport/MultiportFromBankHierarchy.lf b/test/Python/src/multiport/MultiportFromBankHierarchy.lf index 83c33e2284..20a66f2e1f 100644 --- a/test/Python/src/multiport/MultiportFromBankHierarchy.lf +++ b/test/Python/src/multiport/MultiportFromBankHierarchy.lf @@ -11,7 +11,6 @@ reactor Source(bank_index=0) { output out reaction(startup) -> out {= - +++++; out.set(self.bank_index) =} } From 48f791cbfa5899dcbb307d7f90b44fa07c7edac3 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Wed, 18 Oct 2023 14:46:01 -0700 Subject: [PATCH 110/145] Fix unit tests --- .../main/java/org/lflang/generator/c/CGenerator.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 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 d367b49d7b..0dead892db 100644 --- a/core/src/main/java/org/lflang/generator/c/CGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CGenerator.java @@ -732,7 +732,7 @@ protected void copyUserFiles(TargetConfig targetConfig, FileConfig fileConfig) { // Must use class variable to determine destination! var destination = this.fileConfig.getSrcGenPath(); - if (!(this instanceof PythonGenerator)) { + if (targetConfig.isSet(CmakeIncludeProperty.INSTANCE)) { FileUtil.copyFilesOrDirectories( targetConfig.get(CmakeIncludeProperty.INSTANCE), destination, @@ -743,13 +743,13 @@ protected void copyUserFiles(TargetConfig targetConfig, FileConfig fileConfig) { try { var file = targetConfig.get(FedSetupProperty.INSTANCE); - FileUtil.copyFile(fileConfig.srcFile.getParent().resolve(file), destination.resolve(file)); + if (file != null) { + FileUtil.copyFile(fileConfig.srcFile.getParent().resolve(file), destination.resolve(file)); + } } catch (IOException e) { messageReporter .nowhere() .error("Failed to find _fed_setup file " + targetConfig.get(FedSetupProperty.INSTANCE)); - } catch (IllegalArgumentException e) { - // No FedSetupProperty defined. } } @@ -1941,7 +1941,7 @@ protected void setUpGeneralParameters() { // So that each separate compile knows about modal reactors, do this: CompileDefinitionsProperty.INSTANCE.update(targetConfig, Map.of("MODAL_REACTORS", "TRUE")); } - if (!(this instanceof PythonGenerator)) { + if (targetConfig.isSet(PlatformProperty.INSTANCE)) { final var platformOptions = targetConfig.get(PlatformProperty.INSTANCE); if (targetConfig.get(ThreadingProperty.INSTANCE) From 6b0637a447bac5a2c7d23f5965ff11a598429c74 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Wed, 18 Oct 2023 15:20:20 -0700 Subject: [PATCH 111/145] Move registration to main constructor --- core/src/main/java/org/lflang/target/TargetConfig.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/src/main/java/org/lflang/target/TargetConfig.java b/core/src/main/java/org/lflang/target/TargetConfig.java index 35bfec5023..82f42965db 100644 --- a/core/src/main/java/org/lflang/target/TargetConfig.java +++ b/core/src/main/java/org/lflang/target/TargetConfig.java @@ -76,6 +76,9 @@ public TargetConfig(Target target) { // Register target-specific properties target.initialize(this); + // Register target properties for internal use. + this.register(FedSetupProperty.INSTANCE); + // Register general-purpose properties this.register( FastProperty.INSTANCE, @@ -105,9 +108,6 @@ public TargetConfig( MessageReporter messageReporter) { this(target); - // Load target properties for internal use. - this.register(FedSetupProperty.INSTANCE); - if (properties != null) { List pairs = properties.getPairs(); this.load(pairs, messageReporter); From 6958d737d47961c7fee17f18dbee3f91e46686ae Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Wed, 18 Oct 2023 15:29:37 -0700 Subject: [PATCH 112/145] Only copy cmake includes if set --- core/src/main/java/org/lflang/generator/c/CGenerator.java | 6 ++++-- 1 file changed, 4 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 0dead892db..f052048228 100644 --- a/core/src/main/java/org/lflang/generator/c/CGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CGenerator.java @@ -713,8 +713,10 @@ private void inspectReactorEResource(ReactorDecl reactor) { // Copy the user files and cmake-includes to the src-gen path of the main .lf file copyUserFiles(lfResource.getTargetConfig(), lfResource.getFileConfig()); // Merge the CMake includes from the imported file into the target config - CmakeIncludeProperty.INSTANCE.update( - this.targetConfig, lfResource.getTargetConfig().get(CmakeIncludeProperty.INSTANCE)); + if (lfResource.getTargetConfig().isSet(CmakeIncludeProperty.INSTANCE)) { + CmakeIncludeProperty.INSTANCE.update( + this.targetConfig, lfResource.getTargetConfig().get(CmakeIncludeProperty.INSTANCE)); + } } } } From 3eaae53a5f73d3ac3ea92936e6c60c205a01c335 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Wed, 18 Oct 2023 16:57:23 -0700 Subject: [PATCH 113/145] Bring back reverted Python fix --- .../org/lflang/federated/generator/FederationFileConfig.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/org/lflang/federated/generator/FederationFileConfig.java b/core/src/main/java/org/lflang/federated/generator/FederationFileConfig.java index d8946a2ad2..c714c0586a 100644 --- a/core/src/main/java/org/lflang/federated/generator/FederationFileConfig.java +++ b/core/src/main/java/org/lflang/federated/generator/FederationFileConfig.java @@ -105,7 +105,9 @@ public void relativizePaths(FederateTargetConfig targetConfig) { List.of(ProtobufsProperty.INSTANCE, FilesProperty.INSTANCE, CmakeIncludeProperty.INSTANCE) .forEach( p -> { - p.override(targetConfig, relativizePathList(targetConfig.get(p))); + if (targetConfig.isSet(p)) { + p.override(targetConfig, relativizePathList(targetConfig.get(p))); + } }); } From 7223686f1a51eb074139fb6e17e97da02fde8a81 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Wed, 18 Oct 2023 17:10:43 -0700 Subject: [PATCH 114/145] Fix bug that prevented files from being copied --- core/src/main/java/org/lflang/generator/c/CGenerator.java | 7 +++++-- 1 file changed, 5 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 f052048228..c85fee17c6 100644 --- a/core/src/main/java/org/lflang/generator/c/CGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CGenerator.java @@ -445,8 +445,11 @@ public void doGenerate(Resource resource, LFGeneratorContext context) { } } + var isArduino = + targetConfig.getOrDefault(PlatformProperty.INSTANCE).platform == Platform.ARDUINO; + // If cmake is requested, generate the CMakeLists.txt - if (!targetConfig.isSet(PlatformProperty.INSTANCE)) { + if (!isArduino) { var cmakeFile = fileConfig.getSrcGenPath() + File.separator + "CMakeLists.txt"; var sources = allTypeParameterizedReactors() @@ -462,7 +465,7 @@ public void doGenerate(Resource resource, LFGeneratorContext context) { //noinspection ThrowableNotThrown,ResultOfMethodCallIgnored Exceptions.sneakyThrow(e); } - } else if (targetConfig.get(PlatformProperty.INSTANCE).platform == Platform.ARDUINO) { + } else { try { Path include = fileConfig.getSrcGenPath().resolve("include/"); Path src = fileConfig.getSrcGenPath().resolve("src/"); From d889a9c8d12492d48d5d3ca75464d96d42dc0e9f Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Wed, 18 Oct 2023 22:28:13 -0700 Subject: [PATCH 115/145] Address fixme --- .../lflang/generator/c/CCmakeGenerator.java | 28 ++--- .../org/lflang/generator/c/CCompiler.java | 6 +- .../org/lflang/generator/c/CGenerator.java | 27 ++--- .../generator/c/CMainFunctionGenerator.java | 4 +- .../generator/c/CPreambleGenerator.java | 2 +- .../target/property/PlatformProperty.java | 104 +++++++++--------- .../java/org/lflang/util/ArduinoUtil.java | 14 +-- .../java/org/lflang/tests/Configurators.java | 31 ++++-- 8 files changed, 117 insertions(+), 99 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 fe24d9a7e7..f3e4afeee8 100644 --- a/core/src/main/java/org/lflang/generator/c/CCmakeGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CCmakeGenerator.java @@ -128,8 +128,8 @@ CodeBuilder generateCMakeCode( // arduino String[] boardProperties = {}; var platformOptions = targetConfig.getOrDefault(PlatformProperty.INSTANCE); - if (platformOptions.board != null) { - boardProperties = platformOptions.board.trim().split(":"); + if (platformOptions.board() != null) { + boardProperties = platformOptions.board().trim().split(":"); // Ignore whitespace for (int i = 0; i < boardProperties.length; i++) { boardProperties[i] = boardProperties[i].trim(); @@ -142,14 +142,14 @@ CodeBuilder generateCMakeCode( cMakeCode.pr("cmake_minimum_required(VERSION " + MIN_CMAKE_VERSION + ")"); // Setup the project header for different platforms - switch (platformOptions.platform) { + switch (platformOptions.platform()) { case ZEPHYR: cMakeCode.pr("# Set default configuration file. To add custom configurations,"); cMakeCode.pr("# pass -- -DOVERLAY_CONFIG=my_config.prj to either cmake or west"); cMakeCode.pr("set(CONF_FILE prj_lf.conf)"); - if (platformOptions.board != null) { + if (platformOptions.board() != null) { cMakeCode.pr("# Selecting board specified in target property"); - cMakeCode.pr("set(BOARD " + platformOptions.board + ")"); + cMakeCode.pr("set(BOARD " + platformOptions.board() + ")"); } else { cMakeCode.pr("# Selecting default board"); cMakeCode.pr("set(BOARD qemu_cortex_m3)"); @@ -185,7 +185,7 @@ CodeBuilder generateCMakeCode( cMakeCode.pr("project(" + executableName + " LANGUAGES C CXX ASM)"); cMakeCode.newLine(); // board type for rp2040 based boards - if (platformOptions.board != null) { + if (platformOptions.board() != null) { if (boardProperties.length < 1 || boardProperties[0].equals("")) { cMakeCode.pr("set(PICO_BOARD pico)"); } else { @@ -259,8 +259,8 @@ CodeBuilder generateCMakeCode( cMakeCode.newLine(); } - if (platformOptions.platform != Platform.AUTO) { - cMakeCode.pr("set(CMAKE_SYSTEM_NAME " + platformOptions.platform.getcMakeName() + ")"); + if (platformOptions.platform() != Platform.AUTO) { + cMakeCode.pr("set(CMAKE_SYSTEM_NAME " + platformOptions.platform().getcMakeName() + ")"); } cMakeCode.newLine(); cMakeCode.pr("# Set default values for build parameters\n"); @@ -284,7 +284,7 @@ CodeBuilder generateCMakeCode( }); // Setup main target for different platforms - switch (platformOptions.platform) { + switch (platformOptions.platform()) { case ZEPHYR: cMakeCode.pr( setUpMainTargetZephyr( @@ -324,12 +324,12 @@ CodeBuilder generateCMakeCode( cMakeCode.pr("target_include_directories(${LF_MAIN_TARGET} PUBLIC include/core/utils)"); // post target definition board configurations - switch (platformOptions.platform) { + switch (platformOptions.platform()) { case RP2040: // set stdio output boolean usb = true; boolean uart = true; - if (platformOptions.board != null && boardProperties.length > 1) { + if (platformOptions.board() != null && boardProperties.length > 1) { uart = !boardProperties[1].equals("usb"); usb = !boardProperties[1].equals("uart"); } @@ -342,8 +342,8 @@ CodeBuilder generateCMakeCode( // If security is requested, add the auth option. var osName = System.getProperty("os.name").toLowerCase(); // if platform target was set, use given platform instead - if (platformOptions.platform != Platform.AUTO) { - osName = platformOptions.platform.toString(); + if (platformOptions.platform() != Platform.AUTO) { + osName = platformOptions.platform().toString(); } if (osName.contains("mac")) { cMakeCode.pr("set(OPENSSL_ROOT_DIR /usr/local/opt/openssl)"); @@ -355,7 +355,7 @@ CodeBuilder generateCMakeCode( } if (targetConfig.get(ThreadingProperty.INSTANCE) - && platformOptions.platform != Platform.ZEPHYR) { + && 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)"); diff --git a/core/src/main/java/org/lflang/generator/c/CCompiler.java b/core/src/main/java/org/lflang/generator/c/CCompiler.java index 46e6175983..69067fc14d 100644 --- a/core/src/main/java/org/lflang/generator/c/CCompiler.java +++ b/core/src/main/java/org/lflang/generator/c/CCompiler.java @@ -179,7 +179,7 @@ public boolean runCCompiler(GeneratorBase generator, LFGeneratorContext context) + " finished with no errors."); } var options = targetConfig.getOrDefault(PlatformProperty.INSTANCE); - if (options.platform == Platform.ZEPHYR && options.flash) { + if (options.platform() == Platform.ZEPHYR && options.flash()) { messageReporter.nowhere().info("Invoking flash command for Zephyr"); LFCommand flash = buildWestFlashCommand(options); int flashRet = flash.run(); @@ -309,7 +309,7 @@ public LFCommand buildCmakeCommand() { public LFCommand buildWestFlashCommand(PlatformOptions options) { // Set the build directory to be "build" Path buildPath = fileConfig.getSrcGenPath().resolve("build"); - String board = options.board; + String board = options.board(); LFCommand cmd; if (board == null || board.startsWith("qemu") || board.equals("native_posix")) { cmd = commandFactory.createCommand("west", List.of("build", "-t", "run"), buildPath); @@ -439,7 +439,7 @@ static String getTargetFileName(String fileName, boolean cppMode, TargetConfig t } static String getFileExtension(boolean cppMode, TargetConfig targetConfig) { - if (targetConfig.getOrDefault(PlatformProperty.INSTANCE).platform == Platform.ARDUINO) { + if (targetConfig.getOrDefault(PlatformProperty.INSTANCE).platform() == Platform.ARDUINO) { return ".ino"; } if (cppMode) { 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 c85fee17c6..d4c6917f62 100644 --- a/core/src/main/java/org/lflang/generator/c/CGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CGenerator.java @@ -446,7 +446,7 @@ public void doGenerate(Resource resource, LFGeneratorContext context) { } var isArduino = - targetConfig.getOrDefault(PlatformProperty.INSTANCE).platform == Platform.ARDUINO; + targetConfig.getOrDefault(PlatformProperty.INSTANCE).platform() == Platform.ARDUINO; // If cmake is requested, generate the CMakeLists.txt if (!isArduino) { @@ -627,7 +627,8 @@ private void generateCodeFor(String lfModuleName) throws IOException { // downstream federates, will notify the RTI // that the specified logical time is complete. if (!(this instanceof PythonGenerator) - && (cppMode || targetConfig.get(PlatformProperty.INSTANCE).platform == Platform.ARDUINO)) + && (cppMode + || targetConfig.get(PlatformProperty.INSTANCE).platform() == Platform.ARDUINO)) code.pr("extern \"C\""); code.pr( String.join( @@ -871,8 +872,8 @@ private void generateReactorChildren( private void pickCompilePlatform() { var osName = System.getProperty("os.name").toLowerCase(); // if platform target was set, use given platform instead - if (targetConfig.get(PlatformProperty.INSTANCE).platform != Platform.AUTO) { - osName = targetConfig.get(PlatformProperty.INSTANCE).platform.toString(); + if (targetConfig.get(PlatformProperty.INSTANCE).platform() != Platform.AUTO) { + osName = targetConfig.get(PlatformProperty.INSTANCE).platform().toString(); } else if (Stream.of("mac", "darwin", "win", "nux").noneMatch(osName::contains)) { messageReporter.nowhere().error("Platform " + osName + " is not supported"); } @@ -885,7 +886,7 @@ protected void copyTargetFiles() throws IOException { Path dest = fileConfig.getSrcGenPath(); if (targetConfig.isSet(PlatformProperty.INSTANCE)) { - var platform = targetConfig.get(PlatformProperty.INSTANCE).platform; + var platform = targetConfig.get(PlatformProperty.INSTANCE).platform(); switch (platform) { case ARDUINO -> { // For Arduino, alter the destination directory. @@ -1950,8 +1951,8 @@ protected void setUpGeneralParameters() { final var platformOptions = targetConfig.get(PlatformProperty.INSTANCE); if (targetConfig.get(ThreadingProperty.INSTANCE) - && platformOptions.platform == Platform.ARDUINO - && (platformOptions.board == null || !platformOptions.board.contains("mbed"))) { + && platformOptions.platform() == Platform.ARDUINO + && (platformOptions.board() == null || !platformOptions.board().contains("mbed"))) { // non-MBED boards should not use threading messageReporter .nowhere() @@ -1961,9 +1962,9 @@ protected void setUpGeneralParameters() { ThreadingProperty.INSTANCE.override(targetConfig, false); } - if (platformOptions.platform == Platform.ARDUINO + if (platformOptions.platform() == Platform.ARDUINO && !targetConfig.get(NoCompileProperty.INSTANCE) - && platformOptions.board == null) { + && platformOptions.board() == null) { messageReporter .nowhere() .info( @@ -1974,13 +1975,13 @@ protected void setUpGeneralParameters() { NoCompileProperty.INSTANCE.override(targetConfig, true); } - if (platformOptions.platform == Platform.ZEPHYR + if (platformOptions.platform() == Platform.ZEPHYR && targetConfig.get(ThreadingProperty.INSTANCE) - && platformOptions.userThreads >= 0) { + && platformOptions.userThreads() >= 0) { targetConfig .get(CompileDefinitionsProperty.INSTANCE) - .put(PlatformOption.USER_THREADS.name(), String.valueOf(platformOptions.userThreads)); - } else if (platformOptions.userThreads > 0) { + .put(PlatformOption.USER_THREADS.name(), String.valueOf(platformOptions.userThreads())); + } else if (platformOptions.userThreads() > 0) { messageReporter .nowhere() .warning( diff --git a/core/src/main/java/org/lflang/generator/c/CMainFunctionGenerator.java b/core/src/main/java/org/lflang/generator/c/CMainFunctionGenerator.java index dd5dbc9121..ebfff5a234 100644 --- a/core/src/main/java/org/lflang/generator/c/CMainFunctionGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CMainFunctionGenerator.java @@ -39,7 +39,7 @@ public String generateCode() { private String generateMainFunction() { var platform = Platform.AUTO; if (targetConfig.isSet(PlatformProperty.INSTANCE)) { - platform = targetConfig.get(PlatformProperty.INSTANCE).platform; + platform = targetConfig.get(PlatformProperty.INSTANCE).platform(); } switch (platform) { case ARDUINO -> { @@ -57,7 +57,7 @@ private String generateMainFunction() { "}\n", "// Arduino setup() and loop() functions", "void setup() {", - "\tSerial.begin(" + targetConfig.get(PlatformProperty.INSTANCE).baudRate + ");", + "\tSerial.begin(" + targetConfig.get(PlatformProperty.INSTANCE).baudRate() + ");", "\tlf_register_print_function(&_lf_arduino_print_message_function, LOG_LEVEL);", "\tlf_reactor_c_main(0, NULL);", "}\n", 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 58319a4f3b..d76e86fc86 100644 --- a/core/src/main/java/org/lflang/generator/c/CPreambleGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CPreambleGenerator.java @@ -34,7 +34,7 @@ public class CPreambleGenerator { private static boolean arduinoBased(TargetConfig targetConfig) { return targetConfig.isSet(PlatformProperty.INSTANCE) - && targetConfig.get(PlatformProperty.INSTANCE).platform == Platform.ARDUINO; + && targetConfig.get(PlatformProperty.INSTANCE).platform() == Platform.ARDUINO; } /** Add necessary source files specific to the target language. */ public static String generateIncludeStatements(TargetConfig targetConfig, boolean cppMode) { 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 67dffe336b..1a43ddd26c 100644 --- a/core/src/main/java/org/lflang/target/property/PlatformProperty.java +++ b/core/src/main/java/org/lflang/target/property/PlatformProperty.java @@ -33,14 +33,19 @@ private PlatformProperty() { @Override public PlatformOptions initialValue() { - return new PlatformOptions(); + return new PlatformOptions(Platform.AUTO, null, null, 9600, false, 0); } @Override public PlatformOptions fromAst(Element node, MessageReporter reporter) { - var config = new PlatformOptions(); + var platform = Platform.AUTO; + String board = null; + String port = null; + var baudRate = 9600; + var flash = false; + var userThreads = 0; if (node.getLiteral() != null || node.getId() != null) { - config.platform = new PlatformType().forName(ASTUtils.elementToSingleString(node)); + platform = new PlatformType().forName(ASTUtils.elementToSingleString(node)); } else { for (KeyValuePair entry : node.getKeyvalue().getPairs()) { PlatformOption option = @@ -50,19 +55,17 @@ public PlatformOptions fromAst(Element node, MessageReporter reporter) { } switch (option) { case NAME -> { - config.platform = - new PlatformType().forName(ASTUtils.elementToSingleString(entry.getValue())); + platform = new PlatformType().forName(ASTUtils.elementToSingleString(entry.getValue())); } - case BAUDRATE -> config.baudRate = ASTUtils.toInteger(entry.getValue()); - case BOARD -> config.board = ASTUtils.elementToSingleString(entry.getValue()); - case FLASH -> config.flash = ASTUtils.toBoolean(entry.getValue()); - case PORT -> config.port = ASTUtils.elementToSingleString(entry.getValue()); - case USER_THREADS -> config.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()); } } } - - return config; + return new PlatformOptions(platform, board, port, baudRate, flash, userThreads); } @Override @@ -111,46 +114,43 @@ public String name() { } /** Settings related to Platform Options. */ - public static class PlatformOptions { // FIXME: use a record for this - - /** - * The base platform we build our LF Files on. Should be set to AUTO by default unless - * developing for specific OS/Embedded Platform - */ - public Platform platform = Platform.AUTO; - - /** - * The string value used to determine what type of embedded board we work with and can be used - * to simplify the build process. This string has the form "board_name[:option]*" (zero or more - * options separated by colons). For example, "pico:usb" specifies a Raspberry Pi Pico where - * stdin and stdout go through a USB serial port. - */ - public String board = null; - - /** - * The string value used to determine the port on which to flash the compiled program (i.e. - * /dev/cu.usbmodem21301) - */ - public String port = null; - - /** - * The baud rate used as a parameter to certain embedded platforms. 9600 is a standard rate - * amongst systems like Arduino, so it's the default value. - */ - public int baudRate = 9600; - - /** - * The boolean statement used to determine whether we should automatically attempt to flash once - * we compile. This may require the use of board and port values depending on the infrastructure - * you use to flash the boards. - */ - public boolean flash = false; - - /** - * The int value is used to determine the number of needed threads for the user application in - * Zephyr. - */ - public int userThreads = 0; + public record PlatformOptions( + /** + * The base platform we build our LF Files on. Should be set to AUTO by default unless + * developing for specific OS/Embedded Platform + */ + Platform platform, + /** + * The string value used to determine what type of embedded board we work with and can be used + * to simplify the build process. This string has the form "board_name[:option]*" (zero or + * more options separated by colons). For example, "pico:usb" specifies a Raspberry Pi Pico + * where stdin and stdout go through a USB serial port. + */ + String board, + + /** + * The string value used to determine the port on which to flash the compiled program (i.e. + * /dev/cu.usbmodem21301) + */ + String port, + + /** + * The baud rate used as a parameter to certain embedded platforms. 9600 is a standard rate + * amongst systems like Arduino, so it's the default value. + */ + int baudRate, + + /** + * Whether we should automatically attempt to flash once we compile. This may require the use + * of board and port values depending on the infrastructure you use to flash the boards. + */ + boolean flash, + + /** + * The baud rate used as a parameter to certain embedded platforms. 9600 is a standard rate + * amongst systems like Arduino, so it's the default value. + */ + int userThreads) { public String[] boardArray() { // Parse board option of the platform target property diff --git a/core/src/main/java/org/lflang/util/ArduinoUtil.java b/core/src/main/java/org/lflang/util/ArduinoUtil.java index 17331d986d..75da247a12 100644 --- a/core/src/main/java/org/lflang/util/ArduinoUtil.java +++ b/core/src/main/java/org/lflang/util/ArduinoUtil.java @@ -69,11 +69,11 @@ private LFCommand arduinoCompileCommand(FileConfig fileConfig, TargetConfig targ 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 + targetConfig.get(PlatformProperty.INSTANCE).board() != null + ? targetConfig.get(PlatformProperty.INSTANCE).board() : "arduino:avr:leonardo"; String isThreaded = - targetConfig.get(PlatformProperty.INSTANCE).board.contains("mbed") + targetConfig.get(PlatformProperty.INSTANCE).board().contains("mbed") ? "-DLF_THREADED" : "-DLF_UNTHREADED"; bufferedWriter.write( @@ -123,8 +123,8 @@ public void buildArduino(FileConfig fileConfig, TargetConfig targetConfig) { "SUCCESS: Compiling generated code for " + fileConfig.name + " finished with no errors."); - if (targetConfig.get(PlatformProperty.INSTANCE).flash) { - if (targetConfig.get(PlatformProperty.INSTANCE).port != null) { + if (targetConfig.get(PlatformProperty.INSTANCE).flash()) { + if (targetConfig.get(PlatformProperty.INSTANCE).port() != null) { messageReporter.nowhere().info("Invoking flash command for Arduino"); LFCommand flash = commandFactory.createCommand( @@ -132,9 +132,9 @@ public void buildArduino(FileConfig fileConfig, TargetConfig targetConfig) { List.of( "upload", "-b", - targetConfig.get(PlatformProperty.INSTANCE).board, + targetConfig.get(PlatformProperty.INSTANCE).board(), "-p", - targetConfig.get(PlatformProperty.INSTANCE).port), + targetConfig.get(PlatformProperty.INSTANCE).port()), fileConfig.getSrcGenPath()); if (flash == null) { messageReporter.nowhere().error("Could not create arduino-cli flash command."); diff --git a/core/src/testFixtures/java/org/lflang/tests/Configurators.java b/core/src/testFixtures/java/org/lflang/tests/Configurators.java index 9885985e01..7cff60a65b 100644 --- a/core/src/testFixtures/java/org/lflang/tests/Configurators.java +++ b/core/src/testFixtures/java/org/lflang/tests/Configurators.java @@ -26,6 +26,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.type.LoggingType.LogLevel; import org.lflang.target.property.type.PlatformType.Platform; @@ -67,12 +68,20 @@ public static boolean disableThreading(LFTest test) { } public static boolean makeZephyrCompatibleUnthreaded(LFTest test) { + test.getContext().getArgs().setProperty("tracing", "false"); ThreadingProperty.INSTANCE.override(test.getContext().getTargetConfig(), false); - // FIXME: use a record and override. - test.getContext().getTargetConfig().get(PlatformProperty.INSTANCE).platform = Platform.ZEPHYR; - test.getContext().getTargetConfig().get(PlatformProperty.INSTANCE).flash = false; - test.getContext().getTargetConfig().get(PlatformProperty.INSTANCE).board = "qemu_cortex_m3"; + var targetConfig = test.getContext().getTargetConfig(); + var platform = targetConfig.get(PlatformProperty.INSTANCE); + PlatformProperty.INSTANCE.override( + targetConfig, + new PlatformOptions( + Platform.ZEPHYR, + "qemu_cortex_m3", + platform.port(), + platform.baudRate(), + false, + platform.userThreads())); // FIXME: Zephyr emulations fails with debug log-levels. LoggingProperty.INSTANCE.override(test.getContext().getTargetConfig(), LogLevel.WARN); @@ -82,9 +91,17 @@ public static boolean makeZephyrCompatibleUnthreaded(LFTest test) { public static boolean makeZephyrCompatible(LFTest test) { test.getContext().getArgs().setProperty("tracing", "false"); - test.getContext().getTargetConfig().get(PlatformProperty.INSTANCE).platform = Platform.ZEPHYR; - test.getContext().getTargetConfig().get(PlatformProperty.INSTANCE).flash = false; - test.getContext().getTargetConfig().get(PlatformProperty.INSTANCE).board = "qemu_cortex_m3"; + var targetConfig = test.getContext().getTargetConfig(); + var platform = targetConfig.get(PlatformProperty.INSTANCE); + PlatformProperty.INSTANCE.override( + targetConfig, + new PlatformOptions( + Platform.ZEPHYR, + "qemu_cortex_m3", + platform.port(), + platform.baudRate(), + false, + platform.userThreads())); // FIXME: Zephyr emulations fails with debug log-levels. LoggingProperty.INSTANCE.override(test.getContext().getTargetConfig(), LogLevel.WARN); From 3fd65197b30bfd2e91acc4b2aced16ae7476b25a Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Sun, 29 Oct 2023 01:38:01 -0700 Subject: [PATCH 116/145] Handling of JSON input --- .../src/main/java/org/lflang/cli/CliBase.java | 134 ++++++++---------- cli/lfc/src/main/java/org/lflang/cli/Lfc.java | 96 +++++-------- .../test/java/org/lflang/cli/LfcCliTest.java | 57 +++++--- .../lflang/tests/runtime/CSchedulerTest.java | 2 +- .../lflang/tests/runtime/CVerifierTest.java | 2 +- .../org/lflang/tests/runtime/PythonTest.java | 7 +- .../serialization/SerializationTest.java | 7 +- core/src/main/java/org/lflang/FileConfig.java | 18 ++- .../main/java/org/lflang/TargetProperty.java | 25 +++- .../federated/generator/FedGenerator.java | 43 ++---- .../org/lflang/generator/GeneratorBase.java | 6 +- .../lflang/generator/IntegratedBuilder.java | 3 +- .../lflang/generator/LFGeneratorContext.java | 46 +----- .../org/lflang/generator/MainContext.java | 16 +-- .../java/org/lflang/generator/SubContext.java | 3 +- .../java/org/lflang/generator/Validator.java | 2 +- .../org/lflang/generator/c/CGenerator.java | 10 +- .../main/java/org/lflang/target/Target.java | 2 +- .../java/org/lflang/target/TargetConfig.java | 49 +++---- .../target/property/BuildTypeProperty.java | 16 +++ .../target/property/CompilerProperty.java | 7 + .../property/ExternalRuntimePathProperty.java | 8 ++ .../property/HierarchicalBinProperty.java | 18 +++ .../target/property/LoggingProperty.java | 6 + .../target/property/NoCompileProperty.java | 7 + .../property/PrintStatisticsProperty.java | 7 + .../property/RuntimeVersionProperty.java | 7 + .../target/property/SchedulerProperty.java | 6 + .../target/property/TracingProperty.java | 20 +++ .../target/property/VerifyProperty.java | 8 +- .../target/property/WorkersProperty.java | 6 + .../org/lflang/validation/LFValidator.java | 3 +- .../org/lflang/generator/ts/TSGenerator.kt | 11 +- .../java/org/lflang/tests/Configurators.java | 26 ++-- .../java/org/lflang/tests/TestBase.java | 35 ++--- 35 files changed, 388 insertions(+), 331 deletions(-) diff --git a/cli/base/src/main/java/org/lflang/cli/CliBase.java b/cli/base/src/main/java/org/lflang/cli/CliBase.java index f8c014ec46..4e6f107cc4 100644 --- a/cli/base/src/main/java/org/lflang/cli/CliBase.java +++ b/cli/base/src/main/java/org/lflang/cli/CliBase.java @@ -1,6 +1,5 @@ package org.lflang.cli; -import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParseException; import com.google.gson.JsonParser; @@ -17,8 +16,6 @@ import java.nio.file.Path; import java.util.ArrayList; import java.util.List; -import java.util.Map.Entry; -import java.util.Set; import java.util.stream.Collectors; import org.eclipse.emf.common.util.URI; import org.eclipse.emf.ecore.resource.Resource; @@ -62,10 +59,10 @@ static class MutuallyExclusive { protected List files; @Option(names = "--json", description = "JSON object containing CLI arguments.") - private String jsonString; + String jsonString; @Option(names = "--json-file", description = "JSON file containing CLI arguments.") - private Path jsonFile; + Path jsonFile; @Option(names = "--stdin", description = "Read paths to Lingua Franca programs from stdin.") private boolean stdin; @@ -99,6 +96,8 @@ static class MutuallyExclusive { /** Injected resource validator. */ @Inject private IResourceValidator validator; + private JsonObject jsonObject; + protected static void cliMain( String toolName, Class toolClass, Io io, String[] args) { // Injector used to obtain Main instance. @@ -123,27 +122,7 @@ public void doExecute(Io io, String[] args) { * the Runnable interface, is instantiated. */ public void run() { - // If args are given in a json file, store its contents in jsonString. - if (topLevelArg.jsonFile != null) { - try { - topLevelArg.jsonString = - new String(Files.readAllBytes(io.getWd().resolve(topLevelArg.jsonFile))); - } catch (IOException e) { - reporter.printFatalErrorAndExit("No such file: " + topLevelArg.jsonFile); - } - } - // If args are given in a json string, unpack them and re-run - // picocli argument validation. - if (topLevelArg.jsonString != null) { - // Unpack args from json string. - String[] args = jsonStringToArgs(topLevelArg.jsonString); - // Execute application on unpacked args. - CommandLine cmd = spec.commandLine(); - cmd.execute(args); - // If args are already unpacked, invoke tool-specific logic. - } else { - doRun(); - } + doRun(); } /* @@ -183,6 +162,23 @@ protected List getInputPaths() { } if (line == null) return List.of(); return List.of(Path.of(line)); + } else if (topLevelArg.jsonFile != null || topLevelArg.jsonString != null) { + paths = new ArrayList<>(); + var filesObj = getJsonObject().get("src"); + if (filesObj != null) { + if (filesObj.isJsonPrimitive()) { + paths = List.of(Path.of(filesObj.getAsString())); + } else if (filesObj.isJsonArray()) { + paths = + filesObj.getAsJsonArray().asList().stream() + .map(e -> Path.of(e.getAsString())) + .collect(Collectors.toUnmodifiableList()); + } else { + reporter.printFatalErrorAndExit("JSON Parse Exception: field \"src\" not found."); + } + } else { + reporter.printFatalErrorAndExit("No source files specified in given JSON."); + } } else { paths = topLevelArg.files.stream().map(io.getWd()::resolve).collect(Collectors.toList()); } @@ -196,6 +192,29 @@ protected List getInputPaths() { return paths; } + protected final JsonObject getJsonObject() { + if (jsonObject != null) { + return jsonObject; + } + var jsonString = topLevelArg.jsonString; + // If args are given in a json file, store its contents in jsonString. + if (topLevelArg.jsonFile != null) { + try { + jsonString = new String(Files.readAllBytes(io.getWd().resolve(topLevelArg.jsonFile))); + } catch (IOException e) { + reporter.printFatalErrorAndExit("No such file: " + topLevelArg.jsonFile); + } + } + if (jsonString != null) { + try { + jsonObject = JsonParser.parseString(jsonString).getAsJsonObject(); + } catch (JsonParseException e) { + messageReporter.nowhere().error((String.format("Invalid JSON string:%n %s", jsonString))); + } + } + return jsonObject; + } + protected final boolean stdinMode() { return topLevelArg.stdin; } @@ -207,16 +226,29 @@ protected final boolean stdinMode() { */ protected Path getOutputRoot() { Path root = null; + Path path = null; + if (!outputPath.toString().isEmpty()) { + path = outputPath; + } else { + var json = getJsonObject(); + if (json != null) { + var obj = json.get("out"); + if (obj != null) { + path = Path.of(obj.getAsString()); + } + } + } + + if (path != null) { root = io.getWd().resolve(outputPath).normalize(); - if (!Files.exists(root)) { // FIXME: Create it instead? + if (!Files.exists(root)) { reporter.printFatalErrorAndExit(root + ": Output location does not exist."); } if (!Files.isDirectory(root)) { reporter.printFatalErrorAndExit(root + ": Output location is not a directory."); } } - return root; } @@ -307,50 +339,4 @@ public Resource getResource(Path path) { return null; } } - - private String[] jsonStringToArgs(String jsonString) { - ArrayList argsList = new ArrayList<>(); - JsonObject jsonObject = new JsonObject(); - - // Parse JSON string and get top-level JSON object. - try { - jsonObject = JsonParser.parseString(jsonString).getAsJsonObject(); - } catch (JsonParseException e) { - reporter.printFatalErrorAndExit(String.format("Invalid JSON string:%n %s", jsonString)); - } - // Append input paths. - JsonElement src = jsonObject.get("src"); - if (src == null) { - reporter.printFatalErrorAndExit("JSON Parse Exception: field \"src\" not found."); - } - assert src != null; - argsList.add(src.getAsString()); - // Append output path if given. - JsonElement out = jsonObject.get("out"); - if (out != null) { - argsList.add("--output-path"); - argsList.add(out.getAsString()); - } - - // If there are no other properties, return args array. - JsonElement properties = jsonObject.get("properties"); - if (properties != null) { - // Get the remaining properties. - Set> entrySet = properties.getAsJsonObject().entrySet(); - // Append the remaining properties to the args array. - for (Entry entry : entrySet) { - String property = entry.getKey(); - String value = entry.getValue().getAsString(); - - // Append option. - argsList.add("--" + property); - // Append argument for non-boolean options. - if (!value.equals("true") || property.equals("threading")) { - argsList.add(value); - } - } - } - - return argsList.toArray(new String[0]); - } } 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 48cc85b7d0..fce3d08e23 100644 --- a/cli/lfc/src/main/java/org/lflang/cli/Lfc.java +++ b/cli/lfc/src/main/java/org/lflang/cli/Lfc.java @@ -4,15 +4,14 @@ import java.nio.file.Files; import java.nio.file.Path; import java.util.List; -import java.util.Properties; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.xtext.generator.GeneratorDelegate; import org.eclipse.xtext.generator.JavaIoFileSystemAccess; import org.eclipse.xtext.util.CancelIndicator; import org.lflang.FileConfig; import org.lflang.ast.ASTUtils; +import org.lflang.generator.GeneratorArguments; import org.lflang.generator.LFGeneratorContext; -import org.lflang.generator.LFGeneratorContext.BuildParm; import org.lflang.generator.MainContext; import org.lflang.target.property.type.BuildTypeType; import org.lflang.target.property.type.LoggingType; @@ -150,21 +149,21 @@ public static void main(Io io, final String... args) { public void doRun() { List paths = getInputPaths(); final Path outputRoot = getOutputRoot(); - // Hard code the props based on the options we want. - Properties properties = this.getGeneratorArgs(); + var args = this.getArgs(); try { // Invoke the generator on all input file paths. - invokeGenerator(paths, outputRoot, properties); + invokeGenerator(paths, outputRoot, args); } catch (RuntimeException e) { reporter.printFatalErrorAndExit("An unexpected error occurred:", e); } } /** Invoke the code generator on the given validated file paths. */ - private void invokeGenerator(List files, Path root, Properties properties) { + private void invokeGenerator(List files, Path root, GeneratorArguments args) { for (Path path : files) { path = toAbsolutePath(path); + String outputPath = getActualOutputPath(root, path).toString(); this.fileAccess.setOutputPath(outputPath); @@ -186,11 +185,14 @@ private void invokeGenerator(List files, Path root, Properties properties) LFGeneratorContext.Mode.STANDALONE, CancelIndicator.NullImpl, (m, p) -> {}, - properties, + args, resource, this.fileAccess, fileConfig -> messageReporter); + // Exit if there were problems creating the main context. + exitIfCollectedErrors(); + try { this.generator.generate(resource, this.fileAccess, context); } catch (Exception e) { @@ -214,90 +216,64 @@ private Path getActualOutputPath(Path root, Path path) { } } - /** - * Filter the command-line arguments needed by the code generator, and return them as properties. - * - * @return Properties for the code generator. - */ - public Properties getGeneratorArgs() { - Properties props = new Properties(); - + /** Check the values of the commandline arguments and return them. */ + public GeneratorArguments getArgs() { + var args = new GeneratorArguments(); if (buildType != null) { // Validate build type. - if (new BuildTypeType().forName(buildType) == null) { + var resolved = new BuildTypeType().forName(buildType); + if (resolved == null) { reporter.printFatalErrorAndExit(buildType + ": Invalid build type."); } - props.setProperty(BuildParm.BUILD_TYPE.getKey(), buildType); - } - - if (clean) { - props.setProperty(BuildParm.CLEAN.getKey(), "true"); + args.buildType = resolved; } + args.clean = clean; + args.compiler = targetCompiler; if (externalRuntimePath != null) { - props.setProperty(BuildParm.EXTERNAL_RUNTIME_PATH.getKey(), externalRuntimePath.toString()); + args.externalRuntimeUri = externalRuntimePath.toUri(); } - if (lint) { - props.setProperty(BuildParm.LINT.getKey(), "true"); - } + args.jsonObject = getJsonObject(); + + args.lint = lint; if (logging != null) { // Validate log level. - if (new LoggingType().forName(logging) == null) { + var resolved = new LoggingType().forName(logging); + if (resolved == null) { reporter.printFatalErrorAndExit(logging + ": Invalid log level."); } - props.setProperty(BuildParm.LOGGING.getKey(), logging); - } - - if (printStatistics) { - props.setProperty(BuildParm.PRINT_STATISTICS.getKey(), "true"); - } - - if (noCompile) { - props.setProperty(BuildParm.NO_COMPILE.getKey(), "true"); - } - - if (verify) { - props.setProperty(BuildParm.VERIFY.getKey(), "true"); - } - - if (targetCompiler != null) { - props.setProperty(BuildParm.COMPILER.getKey(), targetCompiler); + args.logging = resolved; } - if (quiet) { - props.setProperty(BuildParm.QUIET.getKey(), "true"); - } + args.noCompile = noCompile; + args.printStatistics = printStatistics; + args.quiet = quiet; if (rti != null) { // Validate RTI path. if (!Files.exists(io.getWd().resolve(rti))) { reporter.printFatalErrorAndExit(rti + ": Invalid RTI path."); } - props.setProperty(BuildParm.RTI.getKey(), rti.toString()); + args.rti = rti.toUri(); } - if (runtimeVersion != null) { - props.setProperty(BuildParm.RUNTIME_VERSION.getKey(), runtimeVersion); - } + args.runtimeVersion = runtimeVersion; if (scheduler != null) { // Validate scheduler. - if (new SchedulerType().forName(scheduler) == null) { + var resolved = new SchedulerType().forName(scheduler); + if (resolved == null) { reporter.printFatalErrorAndExit(scheduler + ": Invalid scheduler."); } - props.setProperty(BuildParm.SCHEDULER.getKey(), scheduler); + args.scheduler = resolved; } - if (threading != null) { - props.setProperty(BuildParm.THREADING.getKey(), threading); - } - - if (workers != null) { - props.setProperty(BuildParm.WORKERS.getKey(), workers.toString()); - } + args.threading = Boolean.parseBoolean(threading); + args.verify = verify; + args.workers = workers; - return props; + return args; } } 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 2408971256..2c796d3434 100644 --- a/cli/lfc/src/test/java/org/lflang/cli/LfcCliTest.java +++ b/cli/lfc/src/test/java/org/lflang/cli/LfcCliTest.java @@ -32,16 +32,19 @@ import static org.lflang.cli.TestUtils.isDirectory; import static org.lflang.cli.TestUtils.isRegularFile; +import com.google.gson.JsonParser; import com.google.inject.Injector; import java.io.File; import java.io.IOException; import java.nio.file.Path; -import java.util.Properties; +import java.nio.file.Paths; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; import org.lflang.LocalStrings; import org.lflang.cli.TestUtils.TempDirBuilder; -import org.lflang.generator.LFGeneratorContext.BuildParm; +import org.lflang.target.property.type.BuildTypeType.BuildType; +import org.lflang.target.property.type.LoggingType.LogLevel; +import org.lflang.target.property.type.SchedulerType.Scheduler; /** * @author Clément Fournier @@ -243,23 +246,37 @@ public void verifyGeneratorArgs(Path tempDir, String[] args) { .verify( result -> { // Don't validate execution because args are dummy args. - Properties properties = fixture.lfc.getGeneratorArgs(); - assertEquals(properties.getProperty(BuildParm.BUILD_TYPE.getKey()), "Release"); - assertEquals(properties.getProperty(BuildParm.CLEAN.getKey()), "true"); - assertEquals(properties.getProperty(BuildParm.COMPILER.getKey()), "gcc"); - assertEquals(properties.getProperty(BuildParm.EXTERNAL_RUNTIME_PATH.getKey()), "src"); - assertEquals(properties.getProperty(BuildParm.LOGGING.getKey()), "info"); - assertEquals(properties.getProperty(BuildParm.LINT.getKey()), "true"); - assertEquals(properties.getProperty(BuildParm.NO_COMPILE.getKey()), "true"); - assertEquals(properties.getProperty(BuildParm.PRINT_STATISTICS.getKey()), "true"); - assertEquals(properties.getProperty(BuildParm.QUIET.getKey()), "true"); + var genArgs = fixture.lfc.getArgs(); + assertEquals(BuildType.RELEASE, genArgs.buildType); + assertEquals(true, genArgs.clean); + assertEquals("gcc", genArgs.compiler); + assertEquals("src", Path.of(genArgs.externalRuntimeUri).getFileName().toString()); + assertEquals(LogLevel.INFO, genArgs.logging); + assertEquals(true, genArgs.lint); + assertEquals(true, genArgs.noCompile); + assertEquals(true, genArgs.printStatistics); + assertEquals(true, genArgs.quiet); assertEquals( - properties.getProperty(BuildParm.RTI.getKey()), - "path" + File.separator + "to" + File.separator + "rti"); - assertEquals(properties.getProperty(BuildParm.RUNTIME_VERSION.getKey()), "rs"); - assertEquals(properties.getProperty(BuildParm.SCHEDULER.getKey()), "GEDF_NP"); - assertEquals(properties.getProperty(BuildParm.THREADING.getKey()), "false"); - assertEquals(properties.getProperty(BuildParm.WORKERS.getKey()), "1"); + Path.of("path", "to", "rti"), + Path.of(new File("").getAbsolutePath()).relativize(Paths.get(genArgs.rti))); + assertEquals("rs", genArgs.runtimeVersion); + assertEquals(Scheduler.GEDF_NP, genArgs.scheduler); + assertEquals(false, genArgs.threading); + assertEquals(1, genArgs.workers); + }); + } + + public void verifyJsonGeneratorArgs(Path tempDir, String[] args) { + LfcOneShotTestFixture fixture = new LfcOneShotTestFixture(); + + fixture + .run(tempDir, args) + .verify( + result -> { + // Don't validate execution because args are dummy args. + var genArgs = fixture.lfc.getArgs(); + assertEquals( + JsonParser.parseString(JSON_STRING).getAsJsonObject(), genArgs.jsonObject); }); } @@ -308,7 +325,7 @@ public void testGeneratorArgsJsonString(@TempDir Path tempDir) throws IOExceptio dir.mkdirs("path/to/rti"); String[] args = {"--json", JSON_STRING}; - verifyGeneratorArgs(tempDir, args); + verifyJsonGeneratorArgs(tempDir, args); } @Test @@ -319,7 +336,7 @@ public void testGeneratorArgsJsonFile(@TempDir Path tempDir) throws IOException dir.mkdirs("path/to/rti"); String[] args = {"--json-file", "src/test.json"}; - verifyGeneratorArgs(tempDir, args); + verifyJsonGeneratorArgs(tempDir, args); } static class LfcTestFixture extends CliToolTestFixture { diff --git a/core/src/integrationTest/java/org/lflang/tests/runtime/CSchedulerTest.java b/core/src/integrationTest/java/org/lflang/tests/runtime/CSchedulerTest.java index 3f48a22f29..6ba74d3bdd 100644 --- a/core/src/integrationTest/java/org/lflang/tests/runtime/CSchedulerTest.java +++ b/core/src/integrationTest/java/org/lflang/tests/runtime/CSchedulerTest.java @@ -54,7 +54,7 @@ private void runTest(Scheduler scheduler, EnumSet categories) { Message.DESC_SCHED_SWAPPING + scheduler.toString() + ".", categories::contains, test -> { - test.getContext().getArgs().setProperty("scheduler", scheduler.toString()); + test.getContext().getArgs().scheduler = scheduler; return Configurators.noChanges(test); }, TestLevel.EXECUTION, diff --git a/core/src/integrationTest/java/org/lflang/tests/runtime/CVerifierTest.java b/core/src/integrationTest/java/org/lflang/tests/runtime/CVerifierTest.java index 949b66276c..0486ddb0c1 100644 --- a/core/src/integrationTest/java/org/lflang/tests/runtime/CVerifierTest.java +++ b/core/src/integrationTest/java/org/lflang/tests/runtime/CVerifierTest.java @@ -4,7 +4,7 @@ import org.junit.jupiter.api.Assumptions; import org.junit.jupiter.api.Test; import org.lflang.target.Target; -import org.lflang.target.property.type.VerifyProperty; +import org.lflang.target.property.VerifyProperty; import org.lflang.tests.TestBase; import org.lflang.tests.TestRegistry; diff --git a/core/src/integrationTest/java/org/lflang/tests/runtime/PythonTest.java b/core/src/integrationTest/java/org/lflang/tests/runtime/PythonTest.java index 35ea43fdfa..17db439518 100644 --- a/core/src/integrationTest/java/org/lflang/tests/runtime/PythonTest.java +++ b/core/src/integrationTest/java/org/lflang/tests/runtime/PythonTest.java @@ -24,12 +24,13 @@ ***************/ package org.lflang.tests.runtime; -import java.util.Properties; import org.junit.jupiter.api.Assumptions; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; +import org.lflang.generator.GeneratorArguments; import org.lflang.target.Target; import org.lflang.target.TargetConfig; +import org.lflang.target.property.type.BuildTypeType.BuildType; import org.lflang.tests.RuntimeTest; /** @@ -48,12 +49,12 @@ public PythonTest() { } @Override - protected void addExtraLfcArgs(Properties args, TargetConfig targetConfig) { + protected void addExtraLfcArgs(GeneratorArguments args, TargetConfig targetConfig) { super.addExtraLfcArgs(args, targetConfig); if (System.getProperty("os.name").startsWith("Windows")) { // Use the RelWithDebInfo build type on Windows as the Debug/Test build type produces linker // Errors in CI - args.setProperty("build-type", "RelWithDebInfo"); + args.buildType = BuildType.REL_WITH_DEB_INFO; } } diff --git a/core/src/integrationTest/java/org/lflang/tests/serialization/SerializationTest.java b/core/src/integrationTest/java/org/lflang/tests/serialization/SerializationTest.java index ba6c3188a0..01c377c59c 100644 --- a/core/src/integrationTest/java/org/lflang/tests/serialization/SerializationTest.java +++ b/core/src/integrationTest/java/org/lflang/tests/serialization/SerializationTest.java @@ -1,10 +1,11 @@ package org.lflang.tests.serialization; -import java.util.Properties; import org.junit.jupiter.api.Assumptions; import org.junit.jupiter.api.Test; +import org.lflang.generator.GeneratorArguments; import org.lflang.target.Target; import org.lflang.target.TargetConfig; +import org.lflang.target.property.type.BuildTypeType.BuildType; import org.lflang.tests.Configurators; import org.lflang.tests.TestBase; import org.lflang.tests.TestRegistry.TestCategory; @@ -16,10 +17,10 @@ protected SerializationTest() { } @Override - protected void addExtraLfcArgs(Properties args, TargetConfig targetConfig) { + protected void addExtraLfcArgs(GeneratorArguments args, TargetConfig targetConfig) { super.addExtraLfcArgs(args, targetConfig); // Use the Debug build type as coverage generation does not work for the serialization tests - args.setProperty("build-type", "Debug"); + args.buildType = BuildType.DEBUG; } @Test diff --git a/core/src/main/java/org/lflang/FileConfig.java b/core/src/main/java/org/lflang/FileConfig.java index eb2d53c655..bc565870f8 100644 --- a/core/src/main/java/org/lflang/FileConfig.java +++ b/core/src/main/java/org/lflang/FileConfig.java @@ -1,5 +1,9 @@ package org.lflang; +import static org.eclipse.emf.common.util.URI.createFileURI; + +import com.google.inject.Provider; +import java.io.File; import java.io.IOException; import java.nio.file.Path; import java.nio.file.Paths; @@ -10,7 +14,9 @@ import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.emf.common.util.URI; import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.emf.ecore.resource.ResourceSet; import org.eclipse.xtext.generator.IFileSystemAccess2; +import org.eclipse.xtext.resource.XtextResourceSet; import org.lflang.generator.GeneratorUtils; import org.lflang.util.FileUtil; import org.lflang.util.LFCommand; @@ -149,7 +155,7 @@ public FileConfig(Resource resource, Path srcGenBasePath, boolean useHierarchica } /** Get the directory a resource is located in relative to the root package */ - public Path getDirectory(Resource r) throws IOException { + public Path getDirectory(Resource r) { return getSubPkgPath(FileUtil.toPath(r).getParent()); } @@ -255,7 +261,7 @@ public void doClean() throws IOException { FileUtil.deleteDirectory(modelGenBasePath); } - private static Path getPkgPath(Resource resource) throws IOException { + private static Path getPkgPath(Resource resource) { if (resource.getURI().isPlatform()) { // We are in the RCA. Path srcFile = FileUtil.toPath(resource); @@ -309,4 +315,12 @@ protected String getExecutableExtension() { public Path getExecutable() { return binPath.resolve(name + getExecutableExtension()); } + + public static Resource getResource(File file, Provider resourceSetProvider) { + return resourceSetProvider.get().getResource(createFileURI(file.getAbsolutePath()), true); + } + + public static Resource getResource(Path path, XtextResourceSet xtextResourceSet) { + return xtextResourceSet.getResource(createFileURI(path.toAbsolutePath().toString()), true); + } } diff --git a/core/src/main/java/org/lflang/TargetProperty.java b/core/src/main/java/org/lflang/TargetProperty.java index 0f388eda08..5fd4122794 100644 --- a/core/src/main/java/org/lflang/TargetProperty.java +++ b/core/src/main/java/org/lflang/TargetProperty.java @@ -1,7 +1,9 @@ package org.lflang; +import com.google.gson.JsonObject; import java.util.List; import java.util.Optional; +import org.lflang.generator.GeneratorArguments; import org.lflang.lf.Element; import org.lflang.lf.KeyValuePair; import org.lflang.lf.LfPackage.Literals; @@ -112,6 +114,15 @@ public final void override(TargetConfig config, T value) { config.set(this, value); } + public void update(TargetConfig config, GeneratorArguments args, MessageReporter reporter) { + var value = value(args); + if (value != null) { + update(config, value); + } else if (args.jsonObject != null) { + update(config, fromJSON(args.jsonObject, reporter)); + } + } + /** * Update the given configuration using the given value. The default implementation simply assigns * the given value, overriding whatever value might have been assigned before. @@ -119,7 +130,7 @@ public final void override(TargetConfig config, T value) { * @param config The configuration to update. * @param value The value to perform the update with. */ - protected void update(TargetConfig config, T value) { + public void update(TargetConfig config, T value) { override(config, value); } @@ -160,6 +171,14 @@ public int hashCode() { return this.getClass().getName().hashCode(); } + protected T fromJSON(JsonObject jsonObject, MessageReporter reporter) { + T value = null; + if (jsonObject.has(name())) { + value = this.fromString(jsonObject.get(name()).getAsString(), reporter); + } + return value; + } + /** * Retrieve a key-value pair from the given AST that matches the given target property. * @@ -176,4 +195,8 @@ public static KeyValuePair getKeyValuePair(Model ast, TargetProperty prope assert properties.size() <= 1; return properties.size() > 0 ? properties.get(0) : null; } + + public T value(GeneratorArguments args) { + return null; + } } 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 3e56aa1ba0..9a28233b58 100644 --- a/core/src/main/java/org/lflang/federated/generator/FedGenerator.java +++ b/core/src/main/java/org/lflang/federated/generator/FedGenerator.java @@ -4,6 +4,7 @@ import com.google.inject.Injector; import java.io.IOException; +import java.net.URI; import java.nio.file.Path; import java.util.ArrayList; import java.util.Collections; @@ -12,15 +13,11 @@ import java.util.LinkedHashSet; import java.util.List; import java.util.Map; -import java.util.Properties; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import java.util.function.Consumer; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import org.eclipse.emf.common.util.URI; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.emf.ecore.util.EcoreUtil; import org.eclipse.xtext.generator.JavaIoFileSystemAccess; @@ -36,12 +33,12 @@ import org.lflang.generator.CodeMap; import org.lflang.generator.DockerData; import org.lflang.generator.FedDockerComposeGenerator; +import org.lflang.generator.GeneratorArguments; import org.lflang.generator.GeneratorResult.Status; import org.lflang.generator.GeneratorUtils; import org.lflang.generator.IntegratedBuilder; import org.lflang.generator.LFGenerator; import org.lflang.generator.LFGeneratorContext; -import org.lflang.generator.LFGeneratorContext.BuildParm; import org.lflang.generator.MixedRadixInt; import org.lflang.generator.PortInstance; import org.lflang.generator.ReactionInstanceGraph; @@ -227,7 +224,7 @@ private void createDockerFiles(LFGeneratorContext context, List subC * @param context Context in which the generator operates */ private void cleanIfNeeded(LFGeneratorContext context) { - if (context.getArgs().containsKey(BuildParm.CLEAN.getKey())) { + if (context.getArgs().clean) { try { fileConfig.doClean(); } catch (IOException e) { @@ -286,11 +283,7 @@ private Map compileFederates( final int id = i; compileThreadPool.execute( () -> { - Resource res = - rs.getResource( - URI.createFileURI( - FedEmitter.lfFilePath(fileConfig, fed).toAbsolutePath().toString()), - true); + Resource res = FileConfig.getResource(FedEmitter.lfFilePath(fileConfig, fed), rs); FileConfig subFileConfig = LFGenerator.createFileConfig(res, fileConfig.getSrcGenPath(), true); MessageReporter subContextMessageReporter = @@ -299,7 +292,7 @@ private Map compileFederates( TargetConfig subConfig = new TargetConfig( GeneratorUtils.findTargetDecl(subFileConfig.resource), - new Properties(), + new GeneratorArguments(), subContextMessageReporter); if (targetConfig.get(DockerProperty.INSTANCE).enabled && targetConfig.target.buildsUsingDocker()) { @@ -365,7 +358,7 @@ public TargetConfig getTargetConfig() { * @param context Context of the build process. */ private void processCLIArguments(LFGeneratorContext context) { - if (context.getArgs().containsKey("rti")) { + if (context.getArgs().rti != null) { setFederationRTIProperties(context); } } @@ -376,27 +369,15 @@ private void processCLIArguments(LFGeneratorContext context) { * @param context Context of the build process. */ private void setFederationRTIProperties(LFGeneratorContext context) { - String rtiAddr = context.getArgs().getProperty("rti"); - Pattern pattern = - Pattern.compile( - "([a-zA-Z\\d]+@)?([a-zA-Z\\d]+\\.?[a-z]{2,}|\\d+\\.\\d+\\.\\d+\\.\\d+):?(\\d+)?"); - Matcher matcher = pattern.matcher(rtiAddr); - - if (!matcher.find()) { - return; - } - - // the user match group contains a trailing "@" which needs to be removed. - String userWithAt = matcher.group(1); - String user = (userWithAt == null) ? null : userWithAt.substring(0, userWithAt.length() - 1); - String host = matcher.group(2); - String port = matcher.group(3); - + URI rtiAddr = context.getArgs().rti; + var host = rtiAddr.getHost(); + var port = rtiAddr.getPort(); + var user = rtiAddr.getUserInfo(); if (host != null) { rtiConfig.setHost(host); } - if (port != null) { - rtiConfig.setPort(Integer.parseInt(port)); + if (port >= 0) { + rtiConfig.setPort(port); } if (user != null) { rtiConfig.setUser(user); diff --git a/core/src/main/java/org/lflang/generator/GeneratorBase.java b/core/src/main/java/org/lflang/generator/GeneratorBase.java index b194c72c5e..1594347f5b 100644 --- a/core/src/main/java/org/lflang/generator/GeneratorBase.java +++ b/core/src/main/java/org/lflang/generator/GeneratorBase.java @@ -63,7 +63,7 @@ import org.lflang.target.TargetConfig; import org.lflang.target.property.FilesProperty; import org.lflang.target.property.ThreadingProperty; -import org.lflang.target.property.type.VerifyProperty; +import org.lflang.target.property.VerifyProperty; import org.lflang.util.FileUtil; import org.lflang.validation.AbstractLFValidator; @@ -194,7 +194,7 @@ public void doGenerate(Resource resource, LFGeneratorContext context) { // Configure the command factory commandFactory.setVerbose(); if (Objects.equal(context.getMode(), LFGeneratorContext.Mode.STANDALONE) - && context.getArgs().containsKey("quiet")) { + && context.getArgs().quiet) { commandFactory.setQuiet(); } @@ -616,7 +616,7 @@ public void reportCommandErrors(String stderr) { /** Check if a clean was requested from the standalone compiler and perform the clean step. */ protected void cleanIfNeeded(LFGeneratorContext context) { - if (context.getArgs().containsKey("clean")) { + if (context.getArgs().clean) { try { context.getFileConfig().doClean(); } catch (IOException e) { diff --git a/core/src/main/java/org/lflang/generator/IntegratedBuilder.java b/core/src/main/java/org/lflang/generator/IntegratedBuilder.java index 41ad7a4c3d..d0c3cbea74 100644 --- a/core/src/main/java/org/lflang/generator/IntegratedBuilder.java +++ b/core/src/main/java/org/lflang/generator/IntegratedBuilder.java @@ -4,7 +4,6 @@ import com.google.inject.Provider; import java.nio.file.Path; import java.util.List; -import java.util.Properties; import org.eclipse.emf.common.util.URI; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.resource.Resource; @@ -110,7 +109,7 @@ private GeneratorResult doGenerate( mustComplete ? Mode.LSP_SLOW : LFGeneratorContext.Mode.LSP_MEDIUM, cancelIndicator, reportProgress, - new Properties(), + new GeneratorArguments(), resource, fileAccess, fileConfig -> new LanguageServerMessageReporter(resource.getContents().get(0))); diff --git a/core/src/main/java/org/lflang/generator/LFGeneratorContext.java b/core/src/main/java/org/lflang/generator/LFGeneratorContext.java index 03b050f9a3..faa1363536 100644 --- a/core/src/main/java/org/lflang/generator/LFGeneratorContext.java +++ b/core/src/main/java/org/lflang/generator/LFGeneratorContext.java @@ -2,7 +2,6 @@ import java.nio.file.Path; import java.util.Map; -import java.util.Properties; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.xtext.generator.IFileSystemAccess2; import org.eclipse.xtext.generator.IGeneratorContext; @@ -18,49 +17,6 @@ */ public interface LFGeneratorContext extends IGeneratorContext { - /** Enumeration of keys used to parameterize the build process. */ - enum BuildParm { - BUILD_TYPE("The build type to use"), - CLEAN("Clean before building."), - EXTERNAL_RUNTIME_PATH("Specify an external runtime library to be used by the compiled binary."), - FEDERATED("Treat main reactor as federated."), - HELP("Display this information."), - LOGGING("The logging level to use by the generated binary"), - LINT("Enable or disable linting of generated code."), - NO_COMPILE("Do not invoke target compiler."), - VERIFY("Check the generated verification model."), - OUTPUT_PATH("Specify the root output directory."), - PRINT_STATISTICS("Instruct the runtime to collect and print statistics."), - QUIET("Suppress output of the target compiler and other commands"), - RTI("Specify the location of the RTI."), - RUNTIME_VERSION("Specify the version of the runtime library used for compiling LF programs."), - SCHEDULER("Specify the runtime scheduler (if supported)."), - COMPILER("Target compiler to invoke."), - THREADING("Specify whether the runtime should use multi-threading (true/false)."), - VERSION("Print version information."), - WORKERS("Specify the default number of worker threads."); - - public final String description; - - BuildParm(String description) { - this.description = description; - } - - /** Return the string to use as the key to store a value relating to this parameter. */ - public String getKey() { - return this.name().toLowerCase().replace('_', '-'); - } - - /** - * Return the value corresponding to this parameter or {@code null} if there is none. - * - * @param context The context passed to the code generator. - */ - public String getValue(LFGeneratorContext context) { - return context.getArgs().getProperty(this.getKey()); - } - } - enum Mode { STANDALONE, EPOCH, @@ -77,7 +33,7 @@ enum Mode { Mode getMode(); /** Return any arguments that will override target properties. */ - Properties getArgs(); + GeneratorArguments getArgs(); /** Get the error reporter for this context; construct one if it hasn't been constructed yet. */ MessageReporter getErrorReporter(); diff --git a/core/src/main/java/org/lflang/generator/MainContext.java b/core/src/main/java/org/lflang/generator/MainContext.java index 4e9dad4765..e2696142da 100644 --- a/core/src/main/java/org/lflang/generator/MainContext.java +++ b/core/src/main/java/org/lflang/generator/MainContext.java @@ -2,7 +2,6 @@ import java.io.IOException; import java.util.Objects; -import java.util.Properties; import java.util.function.Function; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.xtext.generator.IFileSystemAccess2; @@ -13,7 +12,6 @@ import org.lflang.MessageReporter; import org.lflang.generator.IntegratedBuilder.ReportProgress; import org.lflang.target.TargetConfig; -import org.lflang.target.property.HierarchicalBinProperty; /** * A {@code MainContext} is an {@code LFGeneratorContext} that is not nested in any other generator @@ -41,7 +39,7 @@ public class MainContext implements LFGeneratorContext { /** The result of the code generation process. */ private GeneratorResult result = null; - private final Properties args; + private final GeneratorArguments args; private final MessageReporter messageReporter; /** @@ -58,7 +56,7 @@ public MainContext( mode, cancelIndicator, (message, completion) -> {}, - new Properties(), + new GeneratorArguments(), resource, fsa, (mode == Mode.EPOCH && EPOCH_ERROR_REPORTER_CONSTRUCTOR != null) @@ -84,7 +82,7 @@ public MainContext( Mode mode, CancelIndicator cancelIndicator, ReportProgress reportProgress, - Properties args, + GeneratorArguments args, Resource resource, IFileSystemAccess2 fsa, Function constructErrorReporter) { @@ -94,12 +92,12 @@ public MainContext( this.args = args; try { - var key = HierarchicalBinProperty.INSTANCE.name(); - var useHierarchicalBin = args.contains(key) && Boolean.parseBoolean(args.getProperty(key)); fileConfig = Objects.requireNonNull( LFGenerator.createFileConfig( - resource, FileConfig.getSrcGenRoot(fsa), useHierarchicalBin)); + resource, + FileConfig.getSrcGenRoot(fsa), + Objects.requireNonNullElse(args.hierarchicalBin, false))); } catch (IOException e) { throw new RuntimeIOException("Error during FileConfig instantiation", e); } @@ -120,7 +118,7 @@ public Mode getMode() { } @Override - public Properties getArgs() { + public GeneratorArguments getArgs() { return args; } diff --git a/core/src/main/java/org/lflang/generator/SubContext.java b/core/src/main/java/org/lflang/generator/SubContext.java index 5c0198ec6e..ec9bcc774c 100644 --- a/core/src/main/java/org/lflang/generator/SubContext.java +++ b/core/src/main/java/org/lflang/generator/SubContext.java @@ -1,6 +1,5 @@ package org.lflang.generator; -import java.util.Properties; import org.eclipse.xtext.util.CancelIndicator; import org.lflang.FileConfig; import org.lflang.MessageReporter; @@ -50,7 +49,7 @@ public Mode getMode() { } @Override - public Properties getArgs() { + public GeneratorArguments getArgs() { return containingContext.getArgs(); } diff --git a/core/src/main/java/org/lflang/generator/Validator.java b/core/src/main/java/org/lflang/generator/Validator.java index 33eaec4238..468d1a8a87 100644 --- a/core/src/main/java/org/lflang/generator/Validator.java +++ b/core/src/main/java/org/lflang/generator/Validator.java @@ -91,7 +91,7 @@ public final void doValidate(LFGeneratorContext context) * @param context The context of the current build. */ private boolean validationEnabled(LFGeneratorContext context) { - return context.getArgs().containsKey("lint") || validationEnabledByDefault(context); + return context.getArgs().lint || validationEnabledByDefault(context); } /** 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 d4c6917f62..acb3fbabe5 100644 --- a/core/src/main/java/org/lflang/generator/c/CGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CGenerator.java @@ -39,6 +39,7 @@ import java.io.File; import java.io.IOException; import java.nio.file.Path; +import java.nio.file.Paths; import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedHashSet; @@ -881,10 +882,7 @@ private void pickCompilePlatform() { /** Copy target-specific header file to the src-gen directory. */ protected void copyTargetFiles() throws IOException { - // Copy the core lib - String coreLib = LFGeneratorContext.BuildParm.EXTERNAL_RUNTIME_PATH.getValue(context); Path dest = fileConfig.getSrcGenPath(); - if (targetConfig.isSet(PlatformProperty.INSTANCE)) { var platform = targetConfig.get(PlatformProperty.INSTANCE).platform(); switch (platform) { @@ -914,8 +912,10 @@ protected void copyTargetFiles() throws IOException { } } - if (coreLib != null) { - FileUtil.copyDirectoryContents(Path.of(coreLib), dest, true); + // Copy the core lib + if (context.getArgs().externalRuntimeUri != null) { + Path coreLib = Paths.get(context.getArgs().externalRuntimeUri); + FileUtil.copyDirectoryContents(coreLib, dest, true); } else { FileUtil.copyFromClassPath("/lib/c/reactor-c/core", dest, true, false); FileUtil.copyFromClassPath("/lib/c/reactor-c/lib", dest, true, false); diff --git a/core/src/main/java/org/lflang/target/Target.java b/core/src/main/java/org/lflang/target/Target.java index c4cc869fed..36685236fa 100644 --- a/core/src/main/java/org/lflang/target/Target.java +++ b/core/src/main/java/org/lflang/target/Target.java @@ -58,8 +58,8 @@ import org.lflang.target.property.SingleFileProjectProperty; import org.lflang.target.property.ThreadingProperty; import org.lflang.target.property.TracingProperty; +import org.lflang.target.property.VerifyProperty; import org.lflang.target.property.WorkersProperty; -import org.lflang.target.property.type.VerifyProperty; /** * Enumeration of targets and their associated properties. diff --git a/core/src/main/java/org/lflang/target/TargetConfig.java b/core/src/main/java/org/lflang/target/TargetConfig.java index 82f42965db..2f6b401c15 100644 --- a/core/src/main/java/org/lflang/target/TargetConfig.java +++ b/core/src/main/java/org/lflang/target/TargetConfig.java @@ -33,11 +33,11 @@ import java.util.List; import java.util.Map; import java.util.Optional; -import java.util.Properties; import java.util.Set; import java.util.stream.Collectors; import org.lflang.MessageReporter; import org.lflang.TargetProperty; +import org.lflang.generator.GeneratorArguments; import org.lflang.lf.KeyValuePair; import org.lflang.lf.KeyValuePairs; import org.lflang.lf.LfFactory; @@ -88,8 +88,8 @@ public TargetConfig(Target target) { TracingProperty.INSTANCE); } - public TargetConfig(TargetDecl target, Properties cliArgs, MessageReporter messageReporter) { - this(Target.fromDecl(target), target.getConfig(), cliArgs, messageReporter); + public TargetConfig(TargetDecl target, GeneratorArguments args, MessageReporter messageReporter) { + this(Target.fromDecl(target), target.getConfig(), args, messageReporter); } /** @@ -98,24 +98,24 @@ public TargetConfig(TargetDecl target, Properties cliArgs, MessageReporter messa * * @param target The target of this configuration. * @param properties The key-value pairs that represent the target properties. - * @param cliArgs Arguments passed on the commandline. + * @param args Arguments passed on the commandline. * @param messageReporter An error reporter to report problems. */ public TargetConfig( Target target, KeyValuePairs properties, - Properties cliArgs, + GeneratorArguments args, MessageReporter messageReporter) { this(target); + // Load properties from file if (properties != null) { List pairs = properties.getPairs(); this.load(pairs, messageReporter); } - if (cliArgs != null) { - this.load(cliArgs, messageReporter); - } + // Load properties from CLI args + load(args, messageReporter); } /** Additional sources to add to the compile command if appropriate. */ @@ -191,16 +191,13 @@ public String listOfRegisteredProperties() { .findFirst(); } - public void load(Properties properties, MessageReporter err) { - for (Object key : properties.keySet()) { - var p = this.forName(key.toString()); - if (p.isPresent()) { - var property = p.get(); - property.update(this, (String) properties.get(key), err); - } else { - err.nowhere().warning("Attempting to load unrecognized target property: " + key); - } - } + public void load(GeneratorArguments args, MessageReporter err) { + this.properties + .keySet() + .forEach( + p -> { + p.update(this, args, err); + }); } /** @@ -227,8 +224,10 @@ public void load(List pairs, MessageReporter err) { } public void set(TargetProperty property, T value) { - this.setProperties.add(property); - this.properties.put(property, value); + if (value != null) { + this.setProperties.add(property); + this.properties.put(property, value); + } } /** @@ -278,17 +277,15 @@ public TargetDecl extractTargetDecl() { * * @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 config A target configuration used to retrieve the corresponding target properties. * @param reporter A reporter to report errors and warnings through. */ - public static void validate( - KeyValuePairs pairs, Model ast, TargetConfig config, ValidatorMessageReporter reporter) { + public void validate(KeyValuePairs pairs, Model ast, ValidatorMessageReporter reporter) { pairs .getPairs() .forEach( pair -> { var match = - config.getRegisteredProperties().stream() + this.getRegisteredProperties().stream() .filter(prop -> prop.name().equalsIgnoreCase(pair.getName())) .findAny(); if (match.isPresent()) { @@ -302,10 +299,10 @@ public static void validate( String.format( "The target property '%s' is not supported by the %s target and will" + " thus be ignored.", - pair.getName(), config.target)); + pair.getName(), this.target)); reporter .at(pair, Literals.KEY_VALUE_PAIR__NAME) - .info("Recognized properties are: " + config.listOfRegisteredProperties()); + .info("Recognized properties are: " + this.listOfRegisteredProperties()); } }); } diff --git a/core/src/main/java/org/lflang/target/property/BuildTypeProperty.java b/core/src/main/java/org/lflang/target/property/BuildTypeProperty.java index 0adfb98024..4c9b8dc890 100644 --- a/core/src/main/java/org/lflang/target/property/BuildTypeProperty.java +++ b/core/src/main/java/org/lflang/target/property/BuildTypeProperty.java @@ -3,7 +3,9 @@ import org.lflang.MessageReporter; import org.lflang.TargetProperty; import org.lflang.ast.ASTUtils; +import org.lflang.generator.GeneratorArguments; import org.lflang.lf.Element; +import org.lflang.target.TargetConfig; import org.lflang.target.property.type.BuildTypeType; import org.lflang.target.property.type.BuildTypeType.BuildType; @@ -44,4 +46,18 @@ protected BuildType fromString(String string, MessageReporter reporter) { public String name() { return "build-type"; } + + @Override + public void update(TargetConfig config, GeneratorArguments args, MessageReporter reporter) { + if (args.buildType != null) { + config.set(this, args.buildType); + } else if (args.jsonObject != null) { + config.set(this, fromJSON(args.jsonObject, reporter)); + } + } + + @Override + public BuildType value(GeneratorArguments args) { + return args.buildType; + } } diff --git a/core/src/main/java/org/lflang/target/property/CompilerProperty.java b/core/src/main/java/org/lflang/target/property/CompilerProperty.java index f1ed1f2ebf..efff3c23f0 100644 --- a/core/src/main/java/org/lflang/target/property/CompilerProperty.java +++ b/core/src/main/java/org/lflang/target/property/CompilerProperty.java @@ -1,5 +1,7 @@ package org.lflang.target.property; +import org.lflang.generator.GeneratorArguments; + /** The compiler to invoke, unless a build command has been specified. */ public final class CompilerProperty extends StringProperty { @@ -14,4 +16,9 @@ private CompilerProperty() { public String name() { return "compiler"; } + + @Override + public String value(GeneratorArguments args) { + return args.compiler; + } } diff --git a/core/src/main/java/org/lflang/target/property/ExternalRuntimePathProperty.java b/core/src/main/java/org/lflang/target/property/ExternalRuntimePathProperty.java index b07b7dd60e..2829bfd6d9 100644 --- a/core/src/main/java/org/lflang/target/property/ExternalRuntimePathProperty.java +++ b/core/src/main/java/org/lflang/target/property/ExternalRuntimePathProperty.java @@ -1,5 +1,8 @@ package org.lflang.target.property; +import java.nio.file.Paths; +import org.lflang.generator.GeneratorArguments; + /** * Directive for specifying a path to an external runtime libray to link to instead of the default * one. @@ -17,4 +20,9 @@ private ExternalRuntimePathProperty() { public String name() { return "external-runtime-path"; } + + @Override + public String value(GeneratorArguments args) { + return Paths.get(args.externalRuntimeUri).toString(); + } } diff --git a/core/src/main/java/org/lflang/target/property/HierarchicalBinProperty.java b/core/src/main/java/org/lflang/target/property/HierarchicalBinProperty.java index dbd3a1ed6f..8b77cc14c0 100644 --- a/core/src/main/java/org/lflang/target/property/HierarchicalBinProperty.java +++ b/core/src/main/java/org/lflang/target/property/HierarchicalBinProperty.java @@ -1,5 +1,9 @@ package org.lflang.target.property; +import org.lflang.MessageReporter; +import org.lflang.generator.GeneratorArguments; +import org.lflang.target.TargetConfig; + /** * Whether the bin directory should have a flat or hierarchical organization. It is flat by default. */ @@ -16,4 +20,18 @@ private HierarchicalBinProperty() { public String name() { return "hierarchical-bin"; } + + @Override + public void update(TargetConfig config, GeneratorArguments args, MessageReporter reporter) { + if (args.hierarchicalBin != null) { + config.set(this, args.hierarchicalBin); + } else if (args.jsonObject != null) { + config.set(this, fromJSON(args.jsonObject, reporter)); + } + } + + @Override + public Boolean value(GeneratorArguments args) { + return args.hierarchicalBin; + } } diff --git a/core/src/main/java/org/lflang/target/property/LoggingProperty.java b/core/src/main/java/org/lflang/target/property/LoggingProperty.java index ef6d47cbb9..1edd6799c0 100644 --- a/core/src/main/java/org/lflang/target/property/LoggingProperty.java +++ b/core/src/main/java/org/lflang/target/property/LoggingProperty.java @@ -3,6 +3,7 @@ import org.lflang.MessageReporter; import org.lflang.TargetProperty; import org.lflang.ast.ASTUtils; +import org.lflang.generator.GeneratorArguments; import org.lflang.lf.Element; import org.lflang.target.property.type.LoggingType; import org.lflang.target.property.type.LoggingType.LogLevel; @@ -43,4 +44,9 @@ public Element toAstElement(LogLevel value) { public String name() { return "logging"; } + + @Override + public LogLevel value(GeneratorArguments args) { + return args.logging; + } } diff --git a/core/src/main/java/org/lflang/target/property/NoCompileProperty.java b/core/src/main/java/org/lflang/target/property/NoCompileProperty.java index 906899ca92..862aea76a2 100644 --- a/core/src/main/java/org/lflang/target/property/NoCompileProperty.java +++ b/core/src/main/java/org/lflang/target/property/NoCompileProperty.java @@ -1,5 +1,7 @@ package org.lflang.target.property; +import org.lflang.generator.GeneratorArguments; + /** If true, do not invoke the target compiler or build command. The default is false. */ public final class NoCompileProperty extends BooleanProperty { @@ -14,4 +16,9 @@ private NoCompileProperty() { public String name() { return "no-compile"; } + + @Override + public Boolean value(GeneratorArguments args) { + return args.noCompile; + } } diff --git a/core/src/main/java/org/lflang/target/property/PrintStatisticsProperty.java b/core/src/main/java/org/lflang/target/property/PrintStatisticsProperty.java index a193e25417..682c49e61f 100644 --- a/core/src/main/java/org/lflang/target/property/PrintStatisticsProperty.java +++ b/core/src/main/java/org/lflang/target/property/PrintStatisticsProperty.java @@ -1,5 +1,7 @@ package org.lflang.target.property; +import org.lflang.generator.GeneratorArguments; + /** If true, instruct the runtime to collect and print execution statistics. */ public final class PrintStatisticsProperty extends BooleanProperty { @@ -14,4 +16,9 @@ private PrintStatisticsProperty() { public String name() { return "print-statistics"; } + + @Override + public Boolean value(GeneratorArguments args) { + return args.printStatistics; + } } diff --git a/core/src/main/java/org/lflang/target/property/RuntimeVersionProperty.java b/core/src/main/java/org/lflang/target/property/RuntimeVersionProperty.java index be82a06848..320bdb7a5f 100644 --- a/core/src/main/java/org/lflang/target/property/RuntimeVersionProperty.java +++ b/core/src/main/java/org/lflang/target/property/RuntimeVersionProperty.java @@ -1,5 +1,7 @@ package org.lflang.target.property; +import org.lflang.generator.GeneratorArguments; + /** Directive for specifying a specific version of the reactor runtime library. */ public final class RuntimeVersionProperty extends StringProperty { @@ -14,4 +16,9 @@ private RuntimeVersionProperty() { public String name() { return "runtime-version"; } + + @Override + public String value(GeneratorArguments args) { + return args.runtimeVersion; + } } 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 d4c64d2dc3..27c7c25cb3 100644 --- a/core/src/main/java/org/lflang/target/property/SchedulerProperty.java +++ b/core/src/main/java/org/lflang/target/property/SchedulerProperty.java @@ -3,6 +3,7 @@ import org.lflang.MessageReporter; import org.lflang.TargetProperty; import org.lflang.ast.ASTUtils; +import org.lflang.generator.GeneratorArguments; import org.lflang.lf.Element; import org.lflang.lf.KeyValuePair; import org.lflang.lf.LfPackage.Literals; @@ -82,4 +83,9 @@ public void validate(KeyValuePair pair, Model ast, MessageReporter reporter) { } } } + + @Override + public Scheduler value(GeneratorArguments args) { + return args.scheduler; + } } 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 b236bcad04..5ccb9b5c86 100644 --- a/core/src/main/java/org/lflang/target/property/TracingProperty.java +++ b/core/src/main/java/org/lflang/target/property/TracingProperty.java @@ -4,12 +4,14 @@ import org.lflang.MessageReporter; import org.lflang.TargetProperty; import org.lflang.ast.ASTUtils; +import org.lflang.generator.GeneratorArguments; import org.lflang.lf.Element; 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.target.TargetConfig; import org.lflang.target.property.TracingProperty.TracingOptions; import org.lflang.target.property.type.DictionaryType; import org.lflang.target.property.type.DictionaryType.DictionaryElement; @@ -107,6 +109,24 @@ public String name() { return "tracing"; } + @Override + public void update(TargetConfig config, TracingOptions value) { + if (value.traceFileName == null) { + value.traceFileName = config.get(this).traceFileName; + } + config.set(this, value); + } + + @Override + public TracingOptions value(GeneratorArguments args) { + if (args.tracing != null) { + if (args.tracing) { + return new TracingOptions(true); + } + } + return null; + } + /** Settings related to tracing options. */ public static class TracingOptions { diff --git a/core/src/main/java/org/lflang/target/property/VerifyProperty.java b/core/src/main/java/org/lflang/target/property/VerifyProperty.java index f13d60a4b7..601823c485 100644 --- a/core/src/main/java/org/lflang/target/property/VerifyProperty.java +++ b/core/src/main/java/org/lflang/target/property/VerifyProperty.java @@ -1,6 +1,6 @@ -package org.lflang.target.property.type; +package org.lflang.target.property; -import org.lflang.target.property.BooleanProperty; +import org.lflang.generator.GeneratorArguments; /** If true, check the generated verification model. The default is false. */ public final class VerifyProperty extends BooleanProperty { @@ -16,4 +16,8 @@ private VerifyProperty() { public String name() { return "verify"; } + + public Boolean value(GeneratorArguments args) { + return args.verify; + } } 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 79a86a4c79..5f8c236279 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,7 @@ import org.lflang.MessageReporter; import org.lflang.TargetProperty; import org.lflang.ast.ASTUtils; +import org.lflang.generator.GeneratorArguments; import org.lflang.lf.Element; import org.lflang.target.property.type.PrimitiveType; @@ -43,4 +44,9 @@ public Element toAstElement(Integer value) { public String name() { return "workers"; } + + @Override + public Integer value(GeneratorArguments args) { + return args.workers; + } } diff --git a/core/src/main/java/org/lflang/validation/LFValidator.java b/core/src/main/java/org/lflang/validation/LFValidator.java index bd98c4b416..1b23bfe63d 100644 --- a/core/src/main/java/org/lflang/validation/LFValidator.java +++ b/core/src/main/java/org/lflang/validation/LFValidator.java @@ -1075,8 +1075,7 @@ public void checkTargetDecl(TargetDecl target) throws IOException { public void checkTargetProperties(KeyValuePairs targetProperties) { if (targetProperties.eContainer() instanceof TargetDecl) { // Only validate the target properties, not dictionaries that may be part of their values. - TargetConfig.validate( - targetProperties, this.info.model, new TargetConfig(this.target), getErrorReporter()); + new TargetConfig(this.target).validate(targetProperties, this.info.model, getErrorReporter()); } } diff --git a/core/src/main/kotlin/org/lflang/generator/ts/TSGenerator.kt b/core/src/main/kotlin/org/lflang/generator/ts/TSGenerator.kt index f5cc708384..9fdc2c4546 100644 --- a/core/src/main/kotlin/org/lflang/generator/ts/TSGenerator.kt +++ b/core/src/main/kotlin/org/lflang/generator/ts/TSGenerator.kt @@ -178,13 +178,12 @@ class TSGenerator( * Update package.json according to given build parameters. */ private fun updatePackageConfig(context: LFGeneratorContext) { - var rtPath = LFGeneratorContext.BuildParm.EXTERNAL_RUNTIME_PATH.getValue(context) - val rtVersion = LFGeneratorContext.BuildParm.RUNTIME_VERSION.getValue(context) + var rtUri = context.args.externalRuntimeUri + val rtVersion = context.args.runtimeVersion val sb = StringBuffer(""); val manifest = fileConfig.srcGenPath.resolve("package.json"); val rtRegex = Regex("(\"@lf-lang/reactor-ts\")(.+)") - if (rtPath != null) rtPath = formatRuntimePath(rtPath) - if (rtPath != null || rtVersion != null) { + if (rtUri != null || rtVersion != null) { devMode = true; } manifest.toFile().forEachLine { @@ -192,8 +191,8 @@ class TSGenerator( if (line.contains(rtRegex) && line.contains(RUNTIME_URL)) { devMode = true; } - if (rtPath != null) { - line = line.replace(rtRegex, "$1: \"$rtPath\",") + if (rtUri != null) { + line = line.replace(rtRegex, "$1: \"$rtUri\",") } else if (rtVersion != null) { line = line.replace(rtRegex, "$1: \"$RUNTIME_URL#$rtVersion\",") } diff --git a/core/src/testFixtures/java/org/lflang/tests/Configurators.java b/core/src/testFixtures/java/org/lflang/tests/Configurators.java index 7cff60a65b..37bc939294 100644 --- a/core/src/testFixtures/java/org/lflang/tests/Configurators.java +++ b/core/src/testFixtures/java/org/lflang/tests/Configurators.java @@ -24,10 +24,8 @@ package org.lflang.tests; -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.type.LoggingType.LogLevel; import org.lflang.target.property.type.PlatformType.Platform; import org.lflang.tests.TestRegistry.TestCategory; @@ -62,15 +60,18 @@ public interface Configurator { * @return True if successful, false otherwise. */ public static boolean disableThreading(LFTest test) { - test.getContext().getArgs().setProperty("threading", "false"); - test.getContext().getArgs().setProperty("workers", "1"); + test.getContext().getArgs().threading = false; + test.getContext().getArgs().workers = 1; return true; } public static boolean makeZephyrCompatibleUnthreaded(LFTest test) { - test.getContext().getArgs().setProperty("tracing", "false"); - ThreadingProperty.INSTANCE.override(test.getContext().getTargetConfig(), false); + // NOTE: Zephyr emulations fails with debug log-levels. + test.getContext().getArgs().logging = LogLevel.WARN; + test.getContext().getArgs().tracing = false; + test.getContext().getArgs().threading = false; + var targetConfig = test.getContext().getTargetConfig(); var platform = targetConfig.get(PlatformProperty.INSTANCE); PlatformProperty.INSTANCE.override( @@ -83,14 +84,14 @@ public static boolean makeZephyrCompatibleUnthreaded(LFTest test) { false, platform.userThreads())); - // FIXME: Zephyr emulations fails with debug log-levels. - LoggingProperty.INSTANCE.override(test.getContext().getTargetConfig(), LogLevel.WARN); - test.getContext().getArgs().setProperty("logging", "warning"); return true; } public static boolean makeZephyrCompatible(LFTest test) { - test.getContext().getArgs().setProperty("tracing", "false"); + // NOTE: Zephyr emulations fails with debug log-levels. + test.getContext().getArgs().logging = LogLevel.WARN; + test.getContext().getArgs().tracing = false; + var targetConfig = test.getContext().getTargetConfig(); var platform = targetConfig.get(PlatformProperty.INSTANCE); PlatformProperty.INSTANCE.override( @@ -102,11 +103,6 @@ public static boolean makeZephyrCompatible(LFTest test) { platform.baudRate(), false, platform.userThreads())); - - // FIXME: Zephyr emulations fails with debug log-levels. - LoggingProperty.INSTANCE.override(test.getContext().getTargetConfig(), LogLevel.WARN); - test.getContext().getArgs().setProperty("logging", "warning"); - return true; } /** diff --git a/core/src/testFixtures/java/org/lflang/tests/TestBase.java b/core/src/testFixtures/java/org/lflang/tests/TestBase.java index 73fb9155d5..51d028388a 100644 --- a/core/src/testFixtures/java/org/lflang/tests/TestBase.java +++ b/core/src/testFixtures/java/org/lflang/tests/TestBase.java @@ -13,19 +13,19 @@ import java.io.StringWriter; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; +import java.net.URI; +import java.net.URISyntaxException; import java.nio.file.Files; import java.nio.file.Path; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Objects; -import java.util.Properties; import java.util.Set; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Predicate; import java.util.stream.Collectors; -import org.eclipse.emf.common.util.URI; import org.eclipse.emf.ecore.resource.Resource.Diagnostic; import org.eclipse.emf.ecore.resource.ResourceSet; import org.eclipse.xtext.diagnostics.Severity; @@ -38,14 +38,16 @@ import org.lflang.FileConfig; import org.lflang.LFRuntimeModule; import org.lflang.LFStandaloneSetup; +import org.lflang.generator.GeneratorArguments; import org.lflang.generator.GeneratorResult; import org.lflang.generator.LFGenerator; import org.lflang.generator.LFGeneratorContext; -import org.lflang.generator.LFGeneratorContext.BuildParm; import org.lflang.generator.MainContext; import org.lflang.target.Target; import org.lflang.target.TargetConfig; import org.lflang.target.property.LoggingProperty; +import org.lflang.target.property.type.BuildTypeType.BuildType; +import org.lflang.target.property.type.LoggingType.LogLevel; import org.lflang.tests.Configurators.Configurator; import org.lflang.tests.LFTest.Result; import org.lflang.tests.TestRegistry.TestCategory; @@ -357,25 +359,26 @@ private static void checkAndReportFailures(Set tests) { * @param configurator The configurator to apply to the test. */ private void configure(LFTest test, Configurator configurator) throws TestError { - var props = new Properties(); - props.setProperty("hierarchical-bin", "true"); + + var args = new GeneratorArguments(); + args.hierarchicalBin = true; var sysProps = System.getProperties(); // Set the external-runtime-path property if it was specified. if (sysProps.containsKey("runtime")) { var rt = sysProps.get("runtime").toString(); if (!rt.isEmpty()) { - props.setProperty(BuildParm.EXTERNAL_RUNTIME_PATH.getKey(), rt); + try { + args.externalRuntimeUri = new URI(rt); + } catch (URISyntaxException e) { + throw new RuntimeException(e); + } System.out.println("Using runtime: " + sysProps.get("runtime").toString()); } } else { System.out.println("Using default runtime."); } - - var r = - resourceSetProvider - .get() - .getResource(URI.createFileURI(test.getSrcPath().toFile().getAbsolutePath()), true); + var r = FileConfig.getResource(test.getSrcPath().toFile(), resourceSetProvider); if (r.getErrors().size() > 0) { String message = @@ -394,11 +397,11 @@ private void configure(LFTest test, Configurator configurator) throws TestError LFGeneratorContext.Mode.STANDALONE, CancelIndicator.NullImpl, (m, p) -> {}, - props, + new GeneratorArguments(), r, fileAccess, fileConfig -> new DefaultMessageReporter()); - addExtraLfcArgs(props, context.getTargetConfig()); + addExtraLfcArgs(args, context.getTargetConfig()); test.configure(context); @@ -437,9 +440,9 @@ private void validate(LFTest test) throws TestError { } /** Override to add some LFC arguments to all runs of this test class. */ - protected void addExtraLfcArgs(Properties args, TargetConfig targetConfig) { - args.setProperty("build-type", "Test"); - if (!targetConfig.isSet(LoggingProperty.INSTANCE)) args.setProperty("logging", "Debug"); + protected void addExtraLfcArgs(GeneratorArguments args, TargetConfig targetConfig) { + args.buildType = BuildType.TEST; + if (!targetConfig.isSet(LoggingProperty.INSTANCE)) args.logging = LogLevel.DEBUG; } /** From 960f1ba8cf13bb4fc37aebaed46a84f6be839a58 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Sun, 29 Oct 2023 11:23:25 -0700 Subject: [PATCH 117/145] Minor fixes --- cli/base/src/main/java/org/lflang/cli/CliBase.java | 12 ++++++------ .../kotlin/org/lflang/generator/ts/TSGenerator.kt | 3 ++- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/cli/base/src/main/java/org/lflang/cli/CliBase.java b/cli/base/src/main/java/org/lflang/cli/CliBase.java index 4e6f107cc4..d37fdee14e 100644 --- a/cli/base/src/main/java/org/lflang/cli/CliBase.java +++ b/cli/base/src/main/java/org/lflang/cli/CliBase.java @@ -68,13 +68,12 @@ static class MutuallyExclusive { private boolean stdin; } - @ArgGroup(exclusive = true, multiplicity = "1") + @ArgGroup(multiplicity = "1") MutuallyExclusive topLevelArg; @Option( names = {"-o", "--output-path"}, defaultValue = "", - fallbackValue = "", description = "Specify the root output directory.") private Path outputPath; @@ -172,12 +171,13 @@ protected List getInputPaths() { paths = filesObj.getAsJsonArray().asList().stream() .map(e -> Path.of(e.getAsString())) - .collect(Collectors.toUnmodifiableList()); + .toList(); } else { - reporter.printFatalErrorAndExit("JSON Parse Exception: field \"src\" not found."); + reporter.printFatalErrorAndExit( + "JSON Parse Exception: field \"src\" must be a string or an array of strings."); } } else { - reporter.printFatalErrorAndExit("No source files specified in given JSON."); + reporter.printFatalErrorAndExit("JSON Parse Exception: field \"src\" not found."); } } else { paths = topLevelArg.files.stream().map(io.getWd()::resolve).collect(Collectors.toList()); @@ -209,7 +209,7 @@ protected final JsonObject getJsonObject() { try { jsonObject = JsonParser.parseString(jsonString).getAsJsonObject(); } catch (JsonParseException e) { - messageReporter.nowhere().error((String.format("Invalid JSON string:%n %s", jsonString))); + messageReporter.nowhere().error(String.format("Invalid JSON string:%n %s", jsonString)); } } return jsonObject; diff --git a/core/src/main/kotlin/org/lflang/generator/ts/TSGenerator.kt b/core/src/main/kotlin/org/lflang/generator/ts/TSGenerator.kt index 9fdc2c4546..61af132ba7 100644 --- a/core/src/main/kotlin/org/lflang/generator/ts/TSGenerator.kt +++ b/core/src/main/kotlin/org/lflang/generator/ts/TSGenerator.kt @@ -41,7 +41,8 @@ import org.lflang.target.property.ProtobufsProperty import org.lflang.util.FileUtil import java.nio.file.Files import java.nio.file.Path -import java.util.* +import java.util.LinkedList +import kotlin.collections.HashMap private const val NO_NPM_MESSAGE = "The TypeScript target requires npm >= 6.14.4. " + "For installation instructions, see: https://www.npmjs.com/get-npm. \n" + From 38f3377662c8ac4c4495f5589b23b4d10798e1f7 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Sun, 29 Oct 2023 11:46:18 -0700 Subject: [PATCH 118/145] Added missing class --- .../lflang/generator/GeneratorArguments.java | 90 +++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 core/src/main/java/org/lflang/generator/GeneratorArguments.java diff --git a/core/src/main/java/org/lflang/generator/GeneratorArguments.java b/core/src/main/java/org/lflang/generator/GeneratorArguments.java new file mode 100644 index 0000000000..e57982b52d --- /dev/null +++ b/core/src/main/java/org/lflang/generator/GeneratorArguments.java @@ -0,0 +1,90 @@ +package org.lflang.generator; + +import com.google.gson.JsonObject; +import java.net.URI; +import org.lflang.target.property.type.BuildTypeType.BuildType; +import org.lflang.target.property.type.LoggingType.LogLevel; +import org.lflang.target.property.type.SchedulerType.Scheduler; + +public class GeneratorArguments { + + /** + * @see org.lflang.target.property.BuildTypeProperty + */ + public BuildType buildType; + + /** Whether to clean before building. */ + public boolean clean; + + /** + * @see org.lflang.target.property.ExternalRuntimePathProperty + */ + public URI externalRuntimeUri; + + /** + * @see org.lflang.target.property.HierarchicalBinProperty + */ + public Boolean hierarchicalBin; + + /** Generator arguments and target properties, if they were passed to the application. */ + public JsonObject jsonObject; + + /** For enabling or disabling the linting of generated code */ + public boolean lint; + + /** + * @see org.lflang.target.property.LoggingProperty + */ + public LogLevel logging; + + /** + * @see org.lflang.target.property.PrintStatisticsProperty + */ + public Boolean printStatistics; + + /** + * @see org.lflang.target.property.NoCompileProperty + */ + public Boolean noCompile; + + /** + * @see org.lflang.target.property.VerifyProperty + */ + public Boolean verify; + + /** + * @see org.lflang.target.property.CompilerProperty + */ + public String compiler; + + /** Whether to suppress output of the target compiler and other commands. */ + public boolean quiet; + + /** The location of the rti. */ + public URI rti; + + /** + * @see org.lflang.target.property.RuntimeVersionProperty + */ + public String runtimeVersion; + + /** + * @see org.lflang.target.property.SchedulerProperty + */ + public Scheduler scheduler; + + /** + * @see org.lflang.target.property.SchedulerProperty + */ + public Boolean threading; + + /** + * @see org.lflang.target.property.SchedulerProperty + */ + public Boolean tracing; // FIXME add CLI arg for this + + /** + * @see org.lflang.target.property.WorkersProperty + */ + public Integer workers; +} From 8a8c929bf03dd1415a533e0696291f24b3a918c4 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Sun, 29 Oct 2023 11:56:40 -0700 Subject: [PATCH 119/145] Fix merge artifact --- .../org/lflang/generator/ts/TSParameterPreambleGenerator.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/kotlin/org/lflang/generator/ts/TSParameterPreambleGenerator.kt b/core/src/main/kotlin/org/lflang/generator/ts/TSParameterPreambleGenerator.kt index e555a81477..8aa818f57e 100644 --- a/core/src/main/kotlin/org/lflang/generator/ts/TSParameterPreambleGenerator.kt +++ b/core/src/main/kotlin/org/lflang/generator/ts/TSParameterPreambleGenerator.kt @@ -239,7 +239,7 @@ class TSParameterPreambleGenerator( | throw new Error("'logging' command line argument is malformed."); | } |} else { - | Log.setLevel(Log.LogLevel.${${targetConfig.get(LoggingProperty.INSTANCE).name}); // Default from target property. + | Log.setLevel(Log.LogLevel.${targetConfig.get(LoggingProperty.INSTANCE).name}); // Default from target property. |} | |// Help parameter (not a constructor parameter, but a command line option) From db5646df30bb70ce873889525227f9696893e69a Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Sun, 29 Oct 2023 17:18:28 -0700 Subject: [PATCH 120/145] Check for null --- .../lflang/target/property/ExternalRuntimePathProperty.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/org/lflang/target/property/ExternalRuntimePathProperty.java b/core/src/main/java/org/lflang/target/property/ExternalRuntimePathProperty.java index 2829bfd6d9..04a98e0098 100644 --- a/core/src/main/java/org/lflang/target/property/ExternalRuntimePathProperty.java +++ b/core/src/main/java/org/lflang/target/property/ExternalRuntimePathProperty.java @@ -23,6 +23,9 @@ public String name() { @Override public String value(GeneratorArguments args) { - return Paths.get(args.externalRuntimeUri).toString(); + if (args.externalRuntimeUri != null) { + return Paths.get(args.externalRuntimeUri).toString(); + } + return null; } } From 5f74a13533c5f7bdc05665f5f00cb232ab9daeaf Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Sun, 29 Oct 2023 18:42:29 -0700 Subject: [PATCH 121/145] Use release build type for Py/Win --- .../java/org/lflang/tests/runtime/PythonTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/integrationTest/java/org/lflang/tests/runtime/PythonTest.java b/core/src/integrationTest/java/org/lflang/tests/runtime/PythonTest.java index 17db439518..3712d7b3ed 100644 --- a/core/src/integrationTest/java/org/lflang/tests/runtime/PythonTest.java +++ b/core/src/integrationTest/java/org/lflang/tests/runtime/PythonTest.java @@ -54,7 +54,7 @@ protected void addExtraLfcArgs(GeneratorArguments args, TargetConfig targetConfi if (System.getProperty("os.name").startsWith("Windows")) { // Use the RelWithDebInfo build type on Windows as the Debug/Test build type produces linker // Errors in CI - args.buildType = BuildType.REL_WITH_DEB_INFO; + args.buildType = BuildType.RELEASE; } } From cab78d48fcf7e8a0ee584f737cd381c4fd224ba9 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Sun, 29 Oct 2023 19:07:25 -0700 Subject: [PATCH 122/145] Set args before using them --- .../java/org/lflang/tests/runtime/PythonTest.java | 7 +++---- .../lflang/tests/serialization/SerializationTest.java | 5 ++--- .../testFixtures/java/org/lflang/tests/TestBase.java | 10 +++------- 3 files changed, 8 insertions(+), 14 deletions(-) diff --git a/core/src/integrationTest/java/org/lflang/tests/runtime/PythonTest.java b/core/src/integrationTest/java/org/lflang/tests/runtime/PythonTest.java index 3712d7b3ed..c760deb563 100644 --- a/core/src/integrationTest/java/org/lflang/tests/runtime/PythonTest.java +++ b/core/src/integrationTest/java/org/lflang/tests/runtime/PythonTest.java @@ -29,7 +29,6 @@ import org.junit.jupiter.api.Test; import org.lflang.generator.GeneratorArguments; import org.lflang.target.Target; -import org.lflang.target.TargetConfig; import org.lflang.target.property.type.BuildTypeType.BuildType; import org.lflang.tests.RuntimeTest; @@ -49,12 +48,12 @@ public PythonTest() { } @Override - protected void addExtraLfcArgs(GeneratorArguments args, TargetConfig targetConfig) { - super.addExtraLfcArgs(args, targetConfig); + protected void addExtraLfcArgs(GeneratorArguments args) { + super.addExtraLfcArgs(args); if (System.getProperty("os.name").startsWith("Windows")) { // Use the RelWithDebInfo build type on Windows as the Debug/Test build type produces linker // Errors in CI - args.buildType = BuildType.RELEASE; + args.buildType = BuildType.REL_WITH_DEB_INFO; } } diff --git a/core/src/integrationTest/java/org/lflang/tests/serialization/SerializationTest.java b/core/src/integrationTest/java/org/lflang/tests/serialization/SerializationTest.java index 01c377c59c..43f2444694 100644 --- a/core/src/integrationTest/java/org/lflang/tests/serialization/SerializationTest.java +++ b/core/src/integrationTest/java/org/lflang/tests/serialization/SerializationTest.java @@ -4,7 +4,6 @@ import org.junit.jupiter.api.Test; import org.lflang.generator.GeneratorArguments; import org.lflang.target.Target; -import org.lflang.target.TargetConfig; import org.lflang.target.property.type.BuildTypeType.BuildType; import org.lflang.tests.Configurators; import org.lflang.tests.TestBase; @@ -17,8 +16,8 @@ protected SerializationTest() { } @Override - protected void addExtraLfcArgs(GeneratorArguments args, TargetConfig targetConfig) { - super.addExtraLfcArgs(args, targetConfig); + protected void addExtraLfcArgs(GeneratorArguments args) { + super.addExtraLfcArgs(args); // Use the Debug build type as coverage generation does not work for the serialization tests args.buildType = BuildType.DEBUG; } diff --git a/core/src/testFixtures/java/org/lflang/tests/TestBase.java b/core/src/testFixtures/java/org/lflang/tests/TestBase.java index 51d028388a..c651c72889 100644 --- a/core/src/testFixtures/java/org/lflang/tests/TestBase.java +++ b/core/src/testFixtures/java/org/lflang/tests/TestBase.java @@ -44,8 +44,6 @@ import org.lflang.generator.LFGeneratorContext; import org.lflang.generator.MainContext; import org.lflang.target.Target; -import org.lflang.target.TargetConfig; -import org.lflang.target.property.LoggingProperty; import org.lflang.target.property.type.BuildTypeType.BuildType; import org.lflang.target.property.type.LoggingType.LogLevel; import org.lflang.tests.Configurators.Configurator; @@ -392,6 +390,7 @@ private void configure(LFTest test, Configurator configurator) throws TestError FileConfig.findPackageRoot(test.getSrcPath(), s -> {}) .resolve(FileConfig.DEFAULT_SRC_GEN_DIR) .toString()); + addExtraLfcArgs(args); var context = new MainContext( LFGeneratorContext.Mode.STANDALONE, @@ -401,12 +400,9 @@ private void configure(LFTest test, Configurator configurator) throws TestError r, fileAccess, fileConfig -> new DefaultMessageReporter()); - addExtraLfcArgs(args, context.getTargetConfig()); test.configure(context); - // Reload in case target properties have changed. - context.loadTargetConfig(); // Update the test by applying the configuration. E.g., to carry out an AST transformation. if (configurator != null) { if (!configurator.configure(test)) { @@ -440,9 +436,9 @@ private void validate(LFTest test) throws TestError { } /** Override to add some LFC arguments to all runs of this test class. */ - protected void addExtraLfcArgs(GeneratorArguments args, TargetConfig targetConfig) { + protected void addExtraLfcArgs(GeneratorArguments args) { args.buildType = BuildType.TEST; - if (!targetConfig.isSet(LoggingProperty.INSTANCE)) args.logging = LogLevel.DEBUG; + args.logging = LogLevel.DEBUG; } /** From 6df9434d2be156575d49cac1a82cf296f6e20f0b Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Sun, 29 Oct 2023 19:42:12 -0700 Subject: [PATCH 123/145] Try building with Release again --- .../java/org/lflang/tests/runtime/PythonTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/integrationTest/java/org/lflang/tests/runtime/PythonTest.java b/core/src/integrationTest/java/org/lflang/tests/runtime/PythonTest.java index c760deb563..02c145c922 100644 --- a/core/src/integrationTest/java/org/lflang/tests/runtime/PythonTest.java +++ b/core/src/integrationTest/java/org/lflang/tests/runtime/PythonTest.java @@ -53,7 +53,7 @@ protected void addExtraLfcArgs(GeneratorArguments args) { if (System.getProperty("os.name").startsWith("Windows")) { // Use the RelWithDebInfo build type on Windows as the Debug/Test build type produces linker // Errors in CI - args.buildType = BuildType.REL_WITH_DEB_INFO; + args.buildType = BuildType.RELEASE; } } From 264393e012f30e58eb89d5d6d98a1ba41e098a61 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Sun, 29 Oct 2023 20:48:40 -0700 Subject: [PATCH 124/145] Bugfix and output useful for debugging --- .../org/lflang/analyses/uclid/UclidGenerator.java | 2 +- .../main/java/org/lflang/generator/GeneratorBase.java | 7 ++++--- .../src/main/java/org/lflang/target/TargetConfig.java | 11 +++++++++++ .../testFixtures/java/org/lflang/tests/TestBase.java | 7 +++++-- 4 files changed, 21 insertions(+), 6 deletions(-) diff --git a/core/src/main/java/org/lflang/analyses/uclid/UclidGenerator.java b/core/src/main/java/org/lflang/analyses/uclid/UclidGenerator.java index b3e7984133..540a2b5c81 100644 --- a/core/src/main/java/org/lflang/analyses/uclid/UclidGenerator.java +++ b/core/src/main/java/org/lflang/analyses/uclid/UclidGenerator.java @@ -188,7 +188,7 @@ public UclidGenerator(LFGeneratorContext context, List properties) { public void doGenerate(Resource resource, LFGeneratorContext context) { // Reuse parts of doGenerate() from GeneratorBase. - super.printInfo(context.getMode()); + super.printInfo(context); ASTUtils.setMainName(context.getFileConfig().resource, context.getFileConfig().name); super.createMainInstantiation(); super.setReactorsAndInstantiationGraph(context.getMode()); diff --git a/core/src/main/java/org/lflang/generator/GeneratorBase.java b/core/src/main/java/org/lflang/generator/GeneratorBase.java index 1594347f5b..e67397cffb 100644 --- a/core/src/main/java/org/lflang/generator/GeneratorBase.java +++ b/core/src/main/java/org/lflang/generator/GeneratorBase.java @@ -185,7 +185,7 @@ protected void registerTransformation(AstTransformation transformation) { */ public void doGenerate(Resource resource, LFGeneratorContext context) { - printInfo(context.getMode()); + printInfo(context); // Clear any IDE markers that may have been created by a previous build. // Markers mark problems in the Eclipse IDE when running in integrated mode. @@ -692,14 +692,15 @@ private void reportIssue(StringBuilder message, Integer lineNumber, Path path, i * Print to stdout information about what source file is being generated, what mode the generator * is in, and where the generated sources are to be put. */ - public void printInfo(LFGeneratorContext.Mode mode) { + public void printInfo(LFGeneratorContext context) { messageReporter .nowhere() .info("Generating code for: " + context.getFileConfig().resource.getURI().toString()); - messageReporter.nowhere().info("Generation mode: " + mode); + messageReporter.nowhere().info("Generation mode: " + context.getMode()); messageReporter .nowhere() .info("Generating sources into: " + context.getFileConfig().getSrcGenPath()); + messageReporter.nowhere().info(context.getTargetConfig().settings()); } /** Get the buffer type used for network messages */ diff --git a/core/src/main/java/org/lflang/target/TargetConfig.java b/core/src/main/java/org/lflang/target/TargetConfig.java index 2f6b401c15..3ab8423fd5 100644 --- a/core/src/main/java/org/lflang/target/TargetConfig.java +++ b/core/src/main/java/org/lflang/target/TargetConfig.java @@ -230,6 +230,17 @@ public void set(TargetProperty property, } } + public String settings() { + var s = new StringBuffer("Target Configuration:\n"); + this.properties.keySet().stream() + .filter(p -> this.setProperties.contains(p)) + .forEach( + p -> { + s.append(String.format(" - %s: %s\n", p.name(), this.get(p).toString())); + }); + return s.toString(); + } + /** * Extracts all properties as a list of key-value pairs from a TargetConfig. Only extracts * properties explicitly set by user. diff --git a/core/src/testFixtures/java/org/lflang/tests/TestBase.java b/core/src/testFixtures/java/org/lflang/tests/TestBase.java index c651c72889..ae3a2867bf 100644 --- a/core/src/testFixtures/java/org/lflang/tests/TestBase.java +++ b/core/src/testFixtures/java/org/lflang/tests/TestBase.java @@ -169,7 +169,7 @@ protected TestBase(List targets) { * @param selected A predicate that given a test category returns whether it should be included in * this test run or not. * @param configurator A procedure for configuring the tests. - * @param copy Whether or not to work on copies of tests in the test. registry. + * @param copy Whether to work on copies of tests in the test. registry. */ protected final void runTestsAndPrintResults( Target target, @@ -396,13 +396,16 @@ private void configure(LFTest test, Configurator configurator) throws TestError LFGeneratorContext.Mode.STANDALONE, CancelIndicator.NullImpl, (m, p) -> {}, - new GeneratorArguments(), + args, r, fileAccess, fileConfig -> new DefaultMessageReporter()); test.configure(context); + // Reload in case target properties have changed. + context.loadTargetConfig(); + // Update the test by applying the configuration. E.g., to carry out an AST transformation. if (configurator != null) { if (!configurator.configure(test)) { From 78e992ef041007aaa233edf885f549ef6486db31 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Sun, 29 Oct 2023 21:06:35 -0700 Subject: [PATCH 125/145] Minor fixes --- .../java/org/lflang/tests/runtime/PythonTest.java | 2 +- .../src/main/java/org/lflang/target/TargetConfig.java | 7 ++++--- .../org/lflang/target/property/BuildTypeProperty.java | 10 ---------- .../target/property/HierarchicalBinProperty.java | 11 ----------- 4 files changed, 5 insertions(+), 25 deletions(-) diff --git a/core/src/integrationTest/java/org/lflang/tests/runtime/PythonTest.java b/core/src/integrationTest/java/org/lflang/tests/runtime/PythonTest.java index 02c145c922..c760deb563 100644 --- a/core/src/integrationTest/java/org/lflang/tests/runtime/PythonTest.java +++ b/core/src/integrationTest/java/org/lflang/tests/runtime/PythonTest.java @@ -53,7 +53,7 @@ protected void addExtraLfcArgs(GeneratorArguments args) { if (System.getProperty("os.name").startsWith("Windows")) { // Use the RelWithDebInfo build type on Windows as the Debug/Test build type produces linker // Errors in CI - args.buildType = BuildType.RELEASE; + args.buildType = BuildType.REL_WITH_DEB_INFO; } } diff --git a/core/src/main/java/org/lflang/target/TargetConfig.java b/core/src/main/java/org/lflang/target/TargetConfig.java index 3ab8423fd5..9b0f14817c 100644 --- a/core/src/main/java/org/lflang/target/TargetConfig.java +++ b/core/src/main/java/org/lflang/target/TargetConfig.java @@ -231,14 +231,15 @@ public void set(TargetProperty property, } public String settings() { - var s = new StringBuffer("Target Configuration:\n"); + var sb = new StringBuffer("Target Configuration:\n"); this.properties.keySet().stream() .filter(p -> this.setProperties.contains(p)) .forEach( p -> { - s.append(String.format(" - %s: %s\n", p.name(), this.get(p).toString())); + sb.append(String.format(" - %s: %s\n", p.name(), this.get(p).toString())); }); - return s.toString(); + sb.setLength(sb.length() - 1); + return sb.toString(); } /** diff --git a/core/src/main/java/org/lflang/target/property/BuildTypeProperty.java b/core/src/main/java/org/lflang/target/property/BuildTypeProperty.java index 4c9b8dc890..6ed75f23e2 100644 --- a/core/src/main/java/org/lflang/target/property/BuildTypeProperty.java +++ b/core/src/main/java/org/lflang/target/property/BuildTypeProperty.java @@ -5,7 +5,6 @@ import org.lflang.ast.ASTUtils; import org.lflang.generator.GeneratorArguments; import org.lflang.lf.Element; -import org.lflang.target.TargetConfig; import org.lflang.target.property.type.BuildTypeType; import org.lflang.target.property.type.BuildTypeType.BuildType; @@ -47,15 +46,6 @@ public String name() { return "build-type"; } - @Override - public void update(TargetConfig config, GeneratorArguments args, MessageReporter reporter) { - if (args.buildType != null) { - config.set(this, args.buildType); - } else if (args.jsonObject != null) { - config.set(this, fromJSON(args.jsonObject, reporter)); - } - } - @Override public BuildType value(GeneratorArguments args) { return args.buildType; diff --git a/core/src/main/java/org/lflang/target/property/HierarchicalBinProperty.java b/core/src/main/java/org/lflang/target/property/HierarchicalBinProperty.java index 8b77cc14c0..c18c398c7c 100644 --- a/core/src/main/java/org/lflang/target/property/HierarchicalBinProperty.java +++ b/core/src/main/java/org/lflang/target/property/HierarchicalBinProperty.java @@ -1,8 +1,6 @@ package org.lflang.target.property; -import org.lflang.MessageReporter; import org.lflang.generator.GeneratorArguments; -import org.lflang.target.TargetConfig; /** * Whether the bin directory should have a flat or hierarchical organization. It is flat by default. @@ -21,15 +19,6 @@ public String name() { return "hierarchical-bin"; } - @Override - public void update(TargetConfig config, GeneratorArguments args, MessageReporter reporter) { - if (args.hierarchicalBin != null) { - config.set(this, args.hierarchicalBin); - } else if (args.jsonObject != null) { - config.set(this, fromJSON(args.jsonObject, reporter)); - } - } - @Override public Boolean value(GeneratorArguments args) { return args.hierarchicalBin; From 8cf38490df161ed16bdd8bda0959c5dd35f57330 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Mon, 30 Oct 2023 11:48:15 -0700 Subject: [PATCH 126/145] Reload after reconfiguration --- core/src/testFixtures/java/org/lflang/tests/TestBase.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/src/testFixtures/java/org/lflang/tests/TestBase.java b/core/src/testFixtures/java/org/lflang/tests/TestBase.java index ae3a2867bf..3512255fa3 100644 --- a/core/src/testFixtures/java/org/lflang/tests/TestBase.java +++ b/core/src/testFixtures/java/org/lflang/tests/TestBase.java @@ -403,15 +403,15 @@ private void configure(LFTest test, Configurator configurator) throws TestError test.configure(context); - // Reload in case target properties have changed. - context.loadTargetConfig(); - // Update the test by applying the configuration. E.g., to carry out an AST transformation. if (configurator != null) { if (!configurator.configure(test)) { throw new TestError("Test configuration unsuccessful.", Result.CONFIG_FAIL); } } + + // Reload in case target properties have changed. + context.loadTargetConfig(); } /** Validate the given test. Throw an TestError if validation failed. */ From 6fdf06599ef17b183ed95508834a99016c019d8b Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Mon, 30 Oct 2023 12:36:04 -0700 Subject: [PATCH 127/145] Attempt to fix threading problems in Python target --- .../lflang/generator/python/PythonDelayBodyGenerator.java | 4 ++-- .../java/org/lflang/generator/python/PythonGenerator.java | 5 +++++ 2 files changed, 7 insertions(+), 2 deletions(-) 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 38cf6b72e2..a950dbd718 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 NUMBER_OF_WORKERS > 0", + "#ifdef LF_THREADED", "// Need to lock the mutex first.", "lf_mutex_lock(&mutex);", "#endif", @@ -49,7 +49,7 @@ public String generateDelayBody(Action action, VarRef port) { + value + ", 1);", "Py_INCREF(" + value + ");", - "#if NUMBER_OF_WORKERS > 0", + "#ifdef LF_THREADED", "lf_mutex_unlock(&mutex);", "#endif", "", diff --git a/core/src/main/java/org/lflang/generator/python/PythonGenerator.java b/core/src/main/java/org/lflang/generator/python/PythonGenerator.java index e4477d2d0d..60d40275f0 100644 --- a/core/src/main/java/org/lflang/generator/python/PythonGenerator.java +++ b/core/src/main/java/org/lflang/generator/python/PythonGenerator.java @@ -62,6 +62,7 @@ import org.lflang.target.property.CompilerFlagsProperty; import org.lflang.target.property.CompilerProperty; import org.lflang.target.property.ProtobufsProperty; +import org.lflang.target.property.ThreadingProperty; import org.lflang.util.FileUtil; import org.lflang.util.LFCommand; import org.lflang.util.StringUtil; @@ -111,6 +112,10 @@ private PythonGenerator( super(context, false, types, cmakeGenerator, new PythonDelayBodyGenerator(types)); // Add the C target properties because they are used in the C code generator. CompilerProperty.INSTANCE.override(this.targetConfig, "gcc"); // FIXME: why? + if (!targetConfig.isSet(ThreadingProperty.INSTANCE)) { + // Disable threading by default. + targetConfig.set(ThreadingProperty.INSTANCE, false); + } this.targetConfig.reset(CompilerFlagsProperty.INSTANCE); this.types = types; } From 79059cb8475417260ecd3941ba98177765445ab0 Mon Sep 17 00:00:00 2001 From: erlingrj Date: Mon, 30 Oct 2023 20:55:32 +0100 Subject: [PATCH 128/145] Python: Generated after-delay use mutex on env-struct --- .../lflang/generator/python/PythonDelayBodyGenerator.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) 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 a950dbd718..2feb887bf7 100644 --- a/core/src/main/java/org/lflang/generator/python/PythonDelayBodyGenerator.java +++ b/core/src/main/java/org/lflang/generator/python/PythonDelayBodyGenerator.java @@ -39,9 +39,9 @@ public String generateDelayBody(Action action, VarRef port) { return String.join( "\n", "// Create a token.", - "#ifdef LF_THREADED", + "#if defined(LF_THREADED)", "// Need to lock the mutex first.", - "lf_mutex_lock(&mutex);", + "lf_mutex_lock(&self->base.environment->mutex);", "#endif", "lf_token_t* t = _lf_new_token((token_type_t*)" + action.getName() @@ -49,8 +49,8 @@ public String generateDelayBody(Action action, VarRef port) { + value + ", 1);", "Py_INCREF(" + value + ");", - "#ifdef LF_THREADED", - "lf_mutex_unlock(&mutex);", + "#if defined(LF_THREADED)", + "lf_mutex_unlock(&self->base.environment->mutex);", "#endif", "", "// Pass the token along", From d447e342048a9ead8d670d346ce10f3430dd0008 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Mon, 30 Oct 2023 16:57:04 -0700 Subject: [PATCH 129/145] Use threading by default in Python --- .../java/org/lflang/generator/python/PythonGenerator.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/core/src/main/java/org/lflang/generator/python/PythonGenerator.java b/core/src/main/java/org/lflang/generator/python/PythonGenerator.java index 60d40275f0..9f5f65a35b 100644 --- a/core/src/main/java/org/lflang/generator/python/PythonGenerator.java +++ b/core/src/main/java/org/lflang/generator/python/PythonGenerator.java @@ -112,10 +112,6 @@ private PythonGenerator( super(context, false, types, cmakeGenerator, new PythonDelayBodyGenerator(types)); // Add the C target properties because they are used in the C code generator. CompilerProperty.INSTANCE.override(this.targetConfig, "gcc"); // FIXME: why? - if (!targetConfig.isSet(ThreadingProperty.INSTANCE)) { - // Disable threading by default. - targetConfig.set(ThreadingProperty.INSTANCE, false); - } this.targetConfig.reset(CompilerFlagsProperty.INSTANCE); this.types = types; } From c96a7941026e93756795ded5f99eef8d803144aa Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Mon, 30 Oct 2023 17:55:24 -0700 Subject: [PATCH 130/145] Clean up dealings with target configurations and transformation in the test framework --- .../java/org/lflang/tests/RuntimeTest.java | 15 +++++- .../lflang/tests/runtime/CArduinoTest.java | 2 + .../org/lflang/tests/runtime/CCppTest.java | 4 +- .../lflang/tests/runtime/CSchedulerTest.java | 10 ++-- .../lflang/tests/runtime/CVerifierTest.java | 6 ++- .../org/lflang/tests/runtime/CZephyrTest.java | 6 +++ .../org/lflang/tests/runtime/CppRos2Test.java | 6 ++- .../serialization/SerializationTest.java | 3 ++ .../generator/python/PythonGenerator.java | 1 - .../java/org/lflang/tests/Configurators.java | 47 ++++++++++--------- .../java/org/lflang/tests/LFTest.java | 3 +- .../java/org/lflang/tests/TestBase.java | 43 +++++++++++------ .../java/org/lflang/tests/Transformers.java | 21 +++++++++ 13 files changed, 118 insertions(+), 49 deletions(-) create mode 100644 core/src/testFixtures/java/org/lflang/tests/Transformers.java diff --git a/core/src/integrationTest/java/org/lflang/tests/RuntimeTest.java b/core/src/integrationTest/java/org/lflang/tests/RuntimeTest.java index add74ef30d..36aca85be9 100644 --- a/core/src/integrationTest/java/org/lflang/tests/RuntimeTest.java +++ b/core/src/integrationTest/java/org/lflang/tests/RuntimeTest.java @@ -58,6 +58,7 @@ public void runBasicTests() { runTestsForTargets( Message.DESC_BASIC, TestCategory.BASIC::equals, + Transformers::noChanges, Configurators::noChanges, TestLevel.EXECUTION, false); @@ -68,6 +69,7 @@ public void runGenericsTests() { runTestsForTargets( Message.DESC_GENERICS, TestCategory.GENERICS::equals, + Transformers::noChanges, Configurators::noChanges, TestLevel.EXECUTION, false); @@ -78,6 +80,7 @@ public void runTargetSpecificTests() { runTestsForTargets( Message.DESC_TARGET_SPECIFIC, TestCategory.TARGET::equals, + Transformers::noChanges, Configurators::noChanges, TestLevel.EXECUTION, false); @@ -88,6 +91,7 @@ public void runMultiportTests() { runTestsForTargets( Message.DESC_MULTIPORT, TestCategory.MULTIPORT::equals, + Transformers::noChanges, Configurators::noChanges, TestLevel.EXECUTION, false); @@ -109,7 +113,8 @@ public void runAsFederated() { List.of(Target.C), Message.DESC_AS_FEDERATED, categories::contains, - it -> ASTUtils.makeFederated(it.getFileConfig().resource), + it -> ASTUtils.makeFederated(it), + Configurators::noChanges, TestLevel.EXECUTION, true); } @@ -119,6 +124,7 @@ public void runConcurrentTests() { runTestsForTargets( Message.DESC_CONCURRENT, TestCategory.CONCURRENT::equals, + Transformers::noChanges, Configurators::noChanges, TestLevel.EXECUTION, false); @@ -130,6 +136,7 @@ public void runFederatedTests() { runTestsForTargets( Message.DESC_FEDERATED, TestCategory.FEDERATED::equals, + Transformers::noChanges, Configurators::noChanges, TestLevel.EXECUTION, false); @@ -141,6 +148,7 @@ public void runModalTests() { runTestsForTargets( Message.DESC_MODAL, TestCategory.MODAL_MODELS::equals, + Transformers::noChanges, Configurators::noChanges, TestLevel.EXECUTION, false); @@ -152,6 +160,7 @@ public void runNoInliningTests() { runTestsForTargets( Message.DESC_MODAL, TestCategory.NO_INLINING::equals, + Transformers::noChanges, Configurators::noChanges, TestLevel.EXECUTION, false); @@ -168,6 +177,7 @@ public void runDockerTests() { runTestsForTargets( Message.DESC_DOCKER, TestCategory.DOCKER::equals, + Transformers::noChanges, Configurators::noChanges, TestLevel.EXECUTION, false); @@ -186,6 +196,7 @@ public void runDockerFederatedTests() { runTestsForTargets( Message.DESC_DOCKER_FEDERATED, TestCategory.DOCKER_FEDERATED::equals, + Transformers::noChanges, Configurators::noChanges, TestLevel.EXECUTION, false); @@ -197,6 +208,7 @@ public void runWithThreadingOff() { this.runTestsForTargets( Message.DESC_SINGLE_THREADED, Configurators::compatibleWithThreadingOff, + Transformers::noChanges, Configurators::disableThreading, TestLevel.EXECUTION, true); @@ -209,6 +221,7 @@ public void runEnclaveTests() { runTestsForTargets( Message.DESC_ENCLAVE, TestCategory.ENCLAVE::equals, + Transformers::noChanges, Configurators::noChanges, TestLevel.EXECUTION, false); diff --git a/core/src/integrationTest/java/org/lflang/tests/runtime/CArduinoTest.java b/core/src/integrationTest/java/org/lflang/tests/runtime/CArduinoTest.java index 6a5abdf41d..0b6968f069 100644 --- a/core/src/integrationTest/java/org/lflang/tests/runtime/CArduinoTest.java +++ b/core/src/integrationTest/java/org/lflang/tests/runtime/CArduinoTest.java @@ -7,6 +7,7 @@ import org.lflang.tests.Configurators; import org.lflang.tests.TestBase; import org.lflang.tests.TestRegistry.TestCategory; +import org.lflang.tests.Transformers; /** * Collection of Arduino tests for the C target. @@ -26,6 +27,7 @@ public void buildArduinoTests() { List.of(Target.C), Message.DESC_ARDUINO, TestCategory.ARDUINO::equals, + Transformers::noChanges, Configurators::noChanges, TestLevel.BUILD, false); diff --git a/core/src/integrationTest/java/org/lflang/tests/runtime/CCppTest.java b/core/src/integrationTest/java/org/lflang/tests/runtime/CCppTest.java index 47c4708114..cd890517f7 100644 --- a/core/src/integrationTest/java/org/lflang/tests/runtime/CCppTest.java +++ b/core/src/integrationTest/java/org/lflang/tests/runtime/CCppTest.java @@ -4,6 +4,7 @@ import org.junit.jupiter.api.Test; import org.lflang.ast.ASTUtils; import org.lflang.target.Target; +import org.lflang.tests.Configurators; import org.lflang.tests.TestBase; import org.lflang.tests.TestRegistry.TestCategory; @@ -31,7 +32,8 @@ public void runAsCCpp() { runTestsForTargets( Message.DESC_AS_CCPP, CCppTest::isExcludedFromCCpp, - it -> ASTUtils.changeTargetName(it.getFileConfig().resource, Target.CCPP.getDisplayName()), + resource -> ASTUtils.changeTargetName(resource, Target.CCPP.getDisplayName()), + Configurators::noChanges, TestLevel.EXECUTION, true); } diff --git a/core/src/integrationTest/java/org/lflang/tests/runtime/CSchedulerTest.java b/core/src/integrationTest/java/org/lflang/tests/runtime/CSchedulerTest.java index 6ba74d3bdd..0e241a1dd8 100644 --- a/core/src/integrationTest/java/org/lflang/tests/runtime/CSchedulerTest.java +++ b/core/src/integrationTest/java/org/lflang/tests/runtime/CSchedulerTest.java @@ -3,10 +3,11 @@ import java.util.EnumSet; import org.junit.jupiter.api.Test; import org.lflang.target.Target; +import org.lflang.target.property.SchedulerProperty; import org.lflang.target.property.type.SchedulerType.Scheduler; -import org.lflang.tests.Configurators; import org.lflang.tests.TestBase; import org.lflang.tests.TestRegistry.TestCategory; +import org.lflang.tests.Transformers; /** */ public class CSchedulerTest extends TestBase { @@ -53,9 +54,10 @@ private void runTest(Scheduler scheduler, EnumSet categories) { this.runTestsForTargets( Message.DESC_SCHED_SWAPPING + scheduler.toString() + ".", categories::contains, - test -> { - test.getContext().getArgs().scheduler = scheduler; - return Configurators.noChanges(test); + Transformers::noChanges, + config -> { + SchedulerProperty.INSTANCE.override(config, scheduler); + return true; }, TestLevel.EXECUTION, true); diff --git a/core/src/integrationTest/java/org/lflang/tests/runtime/CVerifierTest.java b/core/src/integrationTest/java/org/lflang/tests/runtime/CVerifierTest.java index 0486ddb0c1..ddc6697ce9 100644 --- a/core/src/integrationTest/java/org/lflang/tests/runtime/CVerifierTest.java +++ b/core/src/integrationTest/java/org/lflang/tests/runtime/CVerifierTest.java @@ -7,6 +7,7 @@ import org.lflang.target.property.VerifyProperty; import org.lflang.tests.TestBase; import org.lflang.tests.TestRegistry; +import org.lflang.tests.Transformers; public class CVerifierTest extends TestBase { protected CVerifierTest() { @@ -21,8 +22,9 @@ public void runVerifierTests() { List.of(Target.C), Message.DESC_VERIFIER, TestRegistry.TestCategory.VERIFIER::equals, - test -> { - VerifyProperty.INSTANCE.override(test.getContext().getTargetConfig(), true); + Transformers::noChanges, + config -> { + VerifyProperty.INSTANCE.override(config, true); return true; }, TestLevel.BUILD, diff --git a/core/src/integrationTest/java/org/lflang/tests/runtime/CZephyrTest.java b/core/src/integrationTest/java/org/lflang/tests/runtime/CZephyrTest.java index 2529710b80..a4e8035eed 100644 --- a/core/src/integrationTest/java/org/lflang/tests/runtime/CZephyrTest.java +++ b/core/src/integrationTest/java/org/lflang/tests/runtime/CZephyrTest.java @@ -31,6 +31,7 @@ import org.lflang.tests.Configurators; import org.lflang.tests.TestBase; import org.lflang.tests.TestRegistry.TestCategory; +import org.lflang.tests.Transformers; /** * Collection of Zephyr tests for the C target. @@ -50,6 +51,7 @@ public void buildZephyrUnthreadedTests() { List.of(Target.C), Message.DESC_ZEPHYR, TestCategory.ZEPHYR_UNTHREADED::equals, + Transformers::noChanges, Configurators::makeZephyrCompatibleUnthreaded, TestLevel.BUILD, false); @@ -62,6 +64,7 @@ public void buildZephyrBoardsTests() { List.of(Target.C), Message.DESC_ZEPHYR, TestCategory.ZEPHYR_BOARDS::equals, + Transformers::noChanges, Configurators::noChanges, TestLevel.BUILD, false); @@ -74,6 +77,7 @@ public void buildZephyrThreadedTests() { List.of(Target.C), Message.DESC_ZEPHYR, TestCategory.ZEPHYR_THREADED::equals, + Transformers::noChanges, Configurators::makeZephyrCompatible, TestLevel.BUILD, false); @@ -86,6 +90,7 @@ public void buildBasicTests() { List.of(Target.C), Message.DESC_BASIC, TestCategory.BASIC::equals, + Transformers::noChanges, Configurators::makeZephyrCompatibleUnthreaded, TestLevel.BUILD, false); @@ -99,6 +104,7 @@ public void buildConcurrentTests() { List.of(Target.C), Message.DESC_CONCURRENT, TestCategory.CONCURRENT::equals, + Transformers::noChanges, Configurators::makeZephyrCompatible, TestLevel.BUILD, false); diff --git a/core/src/integrationTest/java/org/lflang/tests/runtime/CppRos2Test.java b/core/src/integrationTest/java/org/lflang/tests/runtime/CppRos2Test.java index 9970b18424..334f9ef7aa 100644 --- a/core/src/integrationTest/java/org/lflang/tests/runtime/CppRos2Test.java +++ b/core/src/integrationTest/java/org/lflang/tests/runtime/CppRos2Test.java @@ -7,6 +7,7 @@ import org.lflang.target.Target; import org.lflang.target.property.Ros2Property; import org.lflang.tests.TestBase; +import org.lflang.tests.Transformers; /** * Run C++ tests using the ROS2 platform. @@ -30,8 +31,9 @@ public void runWithRos2() { runTestsForTargets( Message.DESC_ROS2, it -> true, - it -> { - Ros2Property.INSTANCE.override(it.getContext().getTargetConfig(), true); + Transformers::noChanges, + config -> { + Ros2Property.INSTANCE.override(config, true); return true; }, TestLevel.EXECUTION, diff --git a/core/src/integrationTest/java/org/lflang/tests/serialization/SerializationTest.java b/core/src/integrationTest/java/org/lflang/tests/serialization/SerializationTest.java index 43f2444694..ac33289ebd 100644 --- a/core/src/integrationTest/java/org/lflang/tests/serialization/SerializationTest.java +++ b/core/src/integrationTest/java/org/lflang/tests/serialization/SerializationTest.java @@ -8,6 +8,7 @@ import org.lflang.tests.Configurators; import org.lflang.tests.TestBase; import org.lflang.tests.TestRegistry.TestCategory; +import org.lflang.tests.Transformers; public class SerializationTest extends TestBase { @@ -28,6 +29,7 @@ public void runSerializationTestsWithThreadingOff() { runTestsForTargets( Message.DESC_SERIALIZATION, TestCategory.SERIALIZATION::equals, + Transformers::noChanges, Configurators::disableThreading, TestLevel.EXECUTION, false); @@ -39,6 +41,7 @@ public void runSerializationTests() { runTestsForTargets( Message.DESC_SERIALIZATION, TestCategory.SERIALIZATION::equals, + Transformers::noChanges, Configurators::noChanges, TestLevel.EXECUTION, false); diff --git a/core/src/main/java/org/lflang/generator/python/PythonGenerator.java b/core/src/main/java/org/lflang/generator/python/PythonGenerator.java index 9f5f65a35b..e4477d2d0d 100644 --- a/core/src/main/java/org/lflang/generator/python/PythonGenerator.java +++ b/core/src/main/java/org/lflang/generator/python/PythonGenerator.java @@ -62,7 +62,6 @@ import org.lflang.target.property.CompilerFlagsProperty; import org.lflang.target.property.CompilerProperty; import org.lflang.target.property.ProtobufsProperty; -import org.lflang.target.property.ThreadingProperty; import org.lflang.util.FileUtil; import org.lflang.util.LFCommand; import org.lflang.util.StringUtil; diff --git a/core/src/testFixtures/java/org/lflang/tests/Configurators.java b/core/src/testFixtures/java/org/lflang/tests/Configurators.java index 37bc939294..c415c66c76 100644 --- a/core/src/testFixtures/java/org/lflang/tests/Configurators.java +++ b/core/src/testFixtures/java/org/lflang/tests/Configurators.java @@ -24,8 +24,13 @@ package org.lflang.tests; +import org.lflang.target.TargetConfig; +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.TracingProperty; +import org.lflang.target.property.WorkersProperty; import org.lflang.target.property.type.LoggingType.LogLevel; import org.lflang.target.property.type.PlatformType.Platform; import org.lflang.tests.TestRegistry.TestCategory; @@ -38,7 +43,7 @@ */ public class Configurators { - /** Test configuration function. */ + /** Function to adapts a given target configuration. */ @FunctionalInterface public interface Configurator { @@ -46,7 +51,7 @@ public interface Configurator { * Apply a side effect to the given test case to change its default configuration. Return true * if configuration succeeded, false otherwise. */ - boolean configure(LFTest test); + boolean configure(TargetConfig config); } /** @@ -56,26 +61,25 @@ public interface Configurator { * unthreaded runtime. For targets that do not distinguish threaded and unthreaded runtime, the * number of workers is set to 1. * - * @param test The test to configure. + * @param config The target configuration to alter. * @return True if successful, false otherwise. */ - public static boolean disableThreading(LFTest test) { - test.getContext().getArgs().threading = false; - test.getContext().getArgs().workers = 1; + public static boolean disableThreading(TargetConfig config) { + ThreadingProperty.INSTANCE.override(config, false); + WorkersProperty.INSTANCE.override(config, 1); return true; } - public static boolean makeZephyrCompatibleUnthreaded(LFTest test) { + public static boolean makeZephyrCompatibleUnthreaded(TargetConfig config) { // NOTE: Zephyr emulations fails with debug log-levels. - test.getContext().getArgs().logging = LogLevel.WARN; - test.getContext().getArgs().tracing = false; - test.getContext().getArgs().threading = false; + LoggingProperty.INSTANCE.override(config, LogLevel.WARN); + TracingProperty.INSTANCE.override(config, TracingProperty.INSTANCE.initialValue()); + ThreadingProperty.INSTANCE.override(config, false); - var targetConfig = test.getContext().getTargetConfig(); - var platform = targetConfig.get(PlatformProperty.INSTANCE); + var platform = config.get(PlatformProperty.INSTANCE); PlatformProperty.INSTANCE.override( - targetConfig, + config, new PlatformOptions( Platform.ZEPHYR, "qemu_cortex_m3", @@ -87,15 +91,14 @@ public static boolean makeZephyrCompatibleUnthreaded(LFTest test) { return true; } - public static boolean makeZephyrCompatible(LFTest test) { + public static boolean makeZephyrCompatible(TargetConfig config) { // NOTE: Zephyr emulations fails with debug log-levels. - test.getContext().getArgs().logging = LogLevel.WARN; - test.getContext().getArgs().tracing = false; + LoggingProperty.INSTANCE.override(config, LogLevel.WARN); + TracingProperty.INSTANCE.override(config, TracingProperty.INSTANCE.initialValue()); - var targetConfig = test.getContext().getTargetConfig(); - var platform = targetConfig.get(PlatformProperty.INSTANCE); + var platform = config.get(PlatformProperty.INSTANCE); PlatformProperty.INSTANCE.override( - targetConfig, + config, new PlatformOptions( Platform.ZEPHYR, "qemu_cortex_m3", @@ -108,15 +111,15 @@ public static boolean makeZephyrCompatible(LFTest test) { /** * Make no changes to the configuration. * - * @param ignoredTest The test to configure. + * @param config The target configuration. * @return True */ - public static boolean noChanges(LFTest ignoredTest) { + public static boolean noChanges(TargetConfig config) { return true; } /** Given a test category, return true if it is compatible with single-threaded execution. */ - public static boolean compatibleWithThreadingOff(TestCategory category) { + public static boolean compatibleWithThreadingOff(TestCategory category) { // FIXME: move this // CONCURRENT, FEDERATED, DOCKER_FEDERATED, DOCKER // are not compatible with single-threaded execution. diff --git a/core/src/testFixtures/java/org/lflang/tests/LFTest.java b/core/src/testFixtures/java/org/lflang/tests/LFTest.java index b003a95264..dc293e64c0 100644 --- a/core/src/testFixtures/java/org/lflang/tests/LFTest.java +++ b/core/src/testFixtures/java/org/lflang/tests/LFTest.java @@ -173,7 +173,7 @@ public void markPassed() { execLog.clear(); } - void configure(LFGeneratorContext context) { + void loadContext(LFGeneratorContext context) { this.context = context; } @@ -194,6 +194,7 @@ private static void printIfNotEmpty(String header, String message) { public enum Result { UNKNOWN("No information available."), CONFIG_FAIL("Could not apply configuration."), + TRANSFORM_FAIL("Could not apply transformation."), PARSE_FAIL("Unable to parse test."), VALIDATE_FAIL("Unable to validate test."), CODE_GEN_FAIL("Error while generating code for test."), diff --git a/core/src/testFixtures/java/org/lflang/tests/TestBase.java b/core/src/testFixtures/java/org/lflang/tests/TestBase.java index 3512255fa3..e8e07f1c09 100644 --- a/core/src/testFixtures/java/org/lflang/tests/TestBase.java +++ b/core/src/testFixtures/java/org/lflang/tests/TestBase.java @@ -49,6 +49,7 @@ import org.lflang.tests.Configurators.Configurator; import org.lflang.tests.LFTest.Result; import org.lflang.tests.TestRegistry.TestCategory; +import org.lflang.tests.Transformers.Transformer; import org.lflang.util.FileUtil; import org.lflang.util.LFCommand; @@ -175,6 +176,7 @@ protected final void runTestsAndPrintResults( Target target, Predicate selected, TestLevel level, + Transformer transformer, Configurator configurator, boolean copy) { var categories = Arrays.stream(TestCategory.values()).filter(selected).toList(); @@ -182,7 +184,7 @@ protected final void runTestsAndPrintResults( System.out.println(category.getHeader()); var tests = testRegistry.getRegisteredTests(target, category, copy); try { - validateAndRun(tests, configurator, level); + validateAndRun(tests, transformer, configurator, level); } catch (IOException e) { throw new RuntimeIOException(e); } @@ -203,11 +205,12 @@ protected final void runTestsAndPrintResults( protected void runTestsForTargets( String description, Predicate selected, + Transformer transformer, Configurator configurator, TestLevel level, boolean copy) { for (Target target : this.targets) { - runTestsFor(List.of(target), description, selected, configurator, level, copy); + runTestsFor(List.of(target), description, selected, transformer, configurator, level, copy); } } @@ -225,12 +228,13 @@ protected void runTestsFor( List subset, String description, Predicate selected, + Transformer transformer, Configurator configurator, TestLevel level, boolean copy) { for (Target target : subset) { printTestHeader(target, description); - runTestsAndPrintResults(target, selected, level, configurator, copy); + runTestsAndPrintResults(target, selected, level, transformer, configurator, copy); } } @@ -296,7 +300,7 @@ public static void runSingleTestAndPrintResults( Set tests = Set.of(test); try { - runner.validateAndRun(tests, t -> true, level); + runner.validateAndRun(tests, Transformers::noChanges, Configurators::noChanges, level); } catch (IOException e) { throw new RuntimeIOException(e); } @@ -350,13 +354,15 @@ private static void checkAndReportFailures(Set tests) { } /** - * Configure a test by applying the given configurator and return a generator context. If the - * configurator was not applied successfully, throw an AssertionError. + * Prepare a test by applying the given transformer and configurator. If either of them was not + * applied successfully, throw an AssertionError. * * @param test the test to configure. + * @param transformer The transformer to apply to the test. * @param configurator The configurator to apply to the test. */ - private void configure(LFTest test, Configurator configurator) throws TestError { + private void prepare(LFTest test, Transformer transformer, Configurator configurator) + throws TestError { var args = new GeneratorArguments(); args.hierarchicalBin = true; @@ -401,17 +407,22 @@ private void configure(LFTest test, Configurator configurator) throws TestError fileAccess, fileConfig -> new DefaultMessageReporter()); - test.configure(context); + // Update the test by applying the transformation. + if (transformer != null) { + if (!transformer.transform(test.getFileConfig().resource)) { + throw new TestError("Test transformation unsuccessful.", Result.TRANSFORM_FAIL); + } + } - // Update the test by applying the configuration. E.g., to carry out an AST transformation. + // Reload the context because properties may have changed as part of the transformation. + test.loadContext(context); + + // Update the configuration using the configurator. if (configurator != null) { - if (!configurator.configure(test)) { + if (!configurator.configure(test.getContext().getTargetConfig())) { throw new TestError("Test configuration unsuccessful.", Result.CONFIG_FAIL); } } - - // Reload in case target properties have changed. - context.loadTargetConfig(); } /** Validate the given test. Throw an TestError if validation failed. */ @@ -642,11 +653,13 @@ private ProcessBuilder getExecCommand(LFTest test) throws TestError { * have been run. * * @param tests A set of tests to run. + * @param transformer A procedure for transforming the tests. * @param configurator A procedure for configuring the tests. * @param level The level of testing. * @throws IOException If initial file configuration fails */ - private void validateAndRun(Set tests, Configurator configurator, TestLevel level) + private void validateAndRun( + Set tests, Transformer transformer, Configurator configurator, TestLevel level) throws IOException { final var x = 78f / tests.size(); var marks = 0; @@ -655,7 +668,7 @@ private void validateAndRun(Set tests, Configurator configurator, TestLe for (var test : tests) { try { test.redirectOutputs(); - configure(test, configurator); + prepare(test, transformer, configurator); validate(test); generateCode(test); if (level == TestLevel.EXECUTION) { diff --git a/core/src/testFixtures/java/org/lflang/tests/Transformers.java b/core/src/testFixtures/java/org/lflang/tests/Transformers.java new file mode 100644 index 0000000000..77131e6165 --- /dev/null +++ b/core/src/testFixtures/java/org/lflang/tests/Transformers.java @@ -0,0 +1,21 @@ +package org.lflang.tests; + +import org.eclipse.emf.ecore.resource.Resource; + +public class Transformers { + + /** Function to adapts a given resource. */ + @FunctionalInterface + public interface Transformer { + + /** + * Apply a side effect to the given test case to change its resource. Return true if + * transformation succeeded, false otherwise. + */ + boolean transform(Resource resource); + } + + public static boolean noChanges(Resource resource) { + return true; + } +} From 9bca9a09ae41f0925d1254980262bb2224a6b967 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Mon, 30 Oct 2023 18:03:12 -0700 Subject: [PATCH 131/145] Fix NPE --- .../testFixtures/java/org/lflang/tests/TestBase.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/core/src/testFixtures/java/org/lflang/tests/TestBase.java b/core/src/testFixtures/java/org/lflang/tests/TestBase.java index e8e07f1c09..09cfc6f6c0 100644 --- a/core/src/testFixtures/java/org/lflang/tests/TestBase.java +++ b/core/src/testFixtures/java/org/lflang/tests/TestBase.java @@ -382,11 +382,11 @@ private void prepare(LFTest test, Transformer transformer, Configurator configur } else { System.out.println("Using default runtime."); } - var r = FileConfig.getResource(test.getSrcPath().toFile(), resourceSetProvider); + var resource = FileConfig.getResource(test.getSrcPath().toFile(), resourceSetProvider); - if (r.getErrors().size() > 0) { + if (resource.getErrors().size() > 0) { String message = - r.getErrors().stream() + resource.getErrors().stream() .map(Diagnostic::toString) .collect(Collectors.joining(System.lineSeparator())); throw new TestError(message, Result.PARSE_FAIL); @@ -403,13 +403,13 @@ private void prepare(LFTest test, Transformer transformer, Configurator configur CancelIndicator.NullImpl, (m, p) -> {}, args, - r, + resource, fileAccess, fileConfig -> new DefaultMessageReporter()); // Update the test by applying the transformation. if (transformer != null) { - if (!transformer.transform(test.getFileConfig().resource)) { + if (!transformer.transform(resource)) { throw new TestError("Test transformation unsuccessful.", Result.TRANSFORM_FAIL); } } From 5ba08355198bbbb53319f43814949d6507e96d1c Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Mon, 30 Oct 2023 19:12:19 -0700 Subject: [PATCH 132/145] Exclude enclave tests from singleThreaded tests --- .../java/org/lflang/tests/RuntimeTest.java | 26 ++++++++++++++++++- .../java/org/lflang/tests/Configurators.java | 24 ----------------- 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/core/src/integrationTest/java/org/lflang/tests/RuntimeTest.java b/core/src/integrationTest/java/org/lflang/tests/RuntimeTest.java index 36aca85be9..12c71eed7c 100644 --- a/core/src/integrationTest/java/org/lflang/tests/RuntimeTest.java +++ b/core/src/integrationTest/java/org/lflang/tests/RuntimeTest.java @@ -207,7 +207,7 @@ public void runWithThreadingOff() { Assumptions.assumeTrue(supportsSingleThreadedExecution(), Message.NO_SINGLE_THREADED_SUPPORT); this.runTestsForTargets( Message.DESC_SINGLE_THREADED, - Configurators::compatibleWithThreadingOff, + RuntimeTest::compatibleWithThreadingOff, Transformers::noChanges, Configurators::disableThreading, TestLevel.EXECUTION, @@ -226,4 +226,28 @@ public void runEnclaveTests() { TestLevel.EXECUTION, false); } + + /** Given a test category, return true if it is compatible with single-threaded execution. */ + public static boolean compatibleWithThreadingOff(TestCategory category) { + + // CONCURRENT, FEDERATED, DOCKER_FEDERATED, DOCKER + // are not compatible with single-threaded execution. + // ARDUINO and ZEPHYR have their own test suites, so we don't need to rerun. + boolean excluded = + category == TestCategory.CONCURRENT + || category == TestCategory.SERIALIZATION + || category == TestCategory.FEDERATED + || category == TestCategory.DOCKER_FEDERATED + || category == TestCategory.DOCKER + || category == TestCategory.ENCLAVE + || category == TestCategory.ARDUINO + || category == TestCategory.VERIFIER + || category == TestCategory.ZEPHYR_UNTHREADED + || category == TestCategory.ZEPHYR_BOARDS + || category == TestCategory.ZEPHYR_THREADED; + + // SERIALIZATION and TARGET tests are excluded on Windows. + excluded |= isWindows() && category == TestCategory.TARGET; + return !excluded; + } } diff --git a/core/src/testFixtures/java/org/lflang/tests/Configurators.java b/core/src/testFixtures/java/org/lflang/tests/Configurators.java index c415c66c76..ddad28eb21 100644 --- a/core/src/testFixtures/java/org/lflang/tests/Configurators.java +++ b/core/src/testFixtures/java/org/lflang/tests/Configurators.java @@ -33,7 +33,6 @@ import org.lflang.target.property.WorkersProperty; import org.lflang.target.property.type.LoggingType.LogLevel; import org.lflang.target.property.type.PlatformType.Platform; -import org.lflang.tests.TestRegistry.TestCategory; /** * Configuration procedures for {@link TestBase} methods. @@ -117,27 +116,4 @@ public static boolean makeZephyrCompatible(TargetConfig config) { public static boolean noChanges(TargetConfig config) { return true; } - - /** Given a test category, return true if it is compatible with single-threaded execution. */ - public static boolean compatibleWithThreadingOff(TestCategory category) { // FIXME: move this - - // CONCURRENT, FEDERATED, DOCKER_FEDERATED, DOCKER - // are not compatible with single-threaded execution. - // ARDUINO and ZEPHYR have their own test suites, so we don't need to rerun. - boolean excluded = - category == TestCategory.CONCURRENT - || category == TestCategory.SERIALIZATION - || category == TestCategory.FEDERATED - || category == TestCategory.DOCKER_FEDERATED - || category == TestCategory.DOCKER - || category == TestCategory.ARDUINO - || category == TestCategory.VERIFIER - || category == TestCategory.ZEPHYR_UNTHREADED - || category == TestCategory.ZEPHYR_BOARDS - || category == TestCategory.ZEPHYR_THREADED; - - // SERIALIZATION and TARGET tests are excluded on Windows. - excluded |= TestBase.isWindows() && category == TestCategory.TARGET; - return !excluded; - } } From 90eefebcd27fc0b087a4f5b7ebc2e8b851c6bfed Mon Sep 17 00:00:00 2001 From: Erling Rennemo Jellum Date: Tue, 31 Oct 2023 09:32:20 +0100 Subject: [PATCH 133/145] Zephyr tests: Do not touch the tracing parameter. Compile, but dont run the tests which include tracing or other file IO --- .github/scripts/run-zephyr-tests.sh | 4 ++-- .../src/testFixtures/java/org/lflang/tests/Configurators.java | 4 +--- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/.github/scripts/run-zephyr-tests.sh b/.github/scripts/run-zephyr-tests.sh index f394ae9409..20dddda94c 100755 --- a/.github/scripts/run-zephyr-tests.sh +++ b/.github/scripts/run-zephyr-tests.sh @@ -8,8 +8,8 @@ num_successes=0 num_failures=0 failed_tests="" -# Skip -skip=("FileReader" "FilePkgReader" "Tracing" "ThreadedThreaded") +# Skip tests doing file IO and tracing +skip=("FileReader" "FilePkgReader" "Tracing" "ThreadedThreaded" "CountTest" "AsyncCallback") find_kconfig_folders() { if [ -f "$folder/CMakeLists.txt" ]; then diff --git a/core/src/testFixtures/java/org/lflang/tests/Configurators.java b/core/src/testFixtures/java/org/lflang/tests/Configurators.java index ddad28eb21..554b284002 100644 --- a/core/src/testFixtures/java/org/lflang/tests/Configurators.java +++ b/core/src/testFixtures/java/org/lflang/tests/Configurators.java @@ -72,9 +72,8 @@ public static boolean disableThreading(TargetConfig config) { public static boolean makeZephyrCompatibleUnthreaded(TargetConfig config) { // NOTE: Zephyr emulations fails with debug log-levels. + disableThreading(config); LoggingProperty.INSTANCE.override(config, LogLevel.WARN); - TracingProperty.INSTANCE.override(config, TracingProperty.INSTANCE.initialValue()); - ThreadingProperty.INSTANCE.override(config, false); var platform = config.get(PlatformProperty.INSTANCE); PlatformProperty.INSTANCE.override( @@ -93,7 +92,6 @@ public static boolean makeZephyrCompatibleUnthreaded(TargetConfig config) { public static boolean makeZephyrCompatible(TargetConfig config) { // NOTE: Zephyr emulations fails with debug log-levels. LoggingProperty.INSTANCE.override(config, LogLevel.WARN); - TracingProperty.INSTANCE.override(config, TracingProperty.INSTANCE.initialValue()); var platform = config.get(PlatformProperty.INSTANCE); PlatformProperty.INSTANCE.override( From f69c7058003190452777bf84eb5acc57d7b4d53f Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Tue, 31 Oct 2023 10:11:09 -0700 Subject: [PATCH 134/145] Apply formatter --- core/src/testFixtures/java/org/lflang/tests/Configurators.java | 1 - 1 file changed, 1 deletion(-) diff --git a/core/src/testFixtures/java/org/lflang/tests/Configurators.java b/core/src/testFixtures/java/org/lflang/tests/Configurators.java index 554b284002..5576f33dba 100644 --- a/core/src/testFixtures/java/org/lflang/tests/Configurators.java +++ b/core/src/testFixtures/java/org/lflang/tests/Configurators.java @@ -29,7 +29,6 @@ import org.lflang.target.property.PlatformProperty; import org.lflang.target.property.PlatformProperty.PlatformOptions; import org.lflang.target.property.ThreadingProperty; -import org.lflang.target.property.TracingProperty; import org.lflang.target.property.WorkersProperty; import org.lflang.target.property.type.LoggingType.LogLevel; import org.lflang.target.property.type.PlatformType.Platform; From 8018f7f2744f4522878056fc6317548a6ef08b27 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Wed, 1 Nov 2023 12:16:00 -0700 Subject: [PATCH 135/145] Moved TargetProperty class and added validation for tracing target property along with a test --- .../org/lflang/generator/GeneratorBase.java | 5 ----- .../java/org/lflang/target/TargetConfig.java | 6 ++---- .../target/property/BooleanProperty.java | 1 - .../property/BuildCommandsProperty.java | 1 - .../target/property/BuildTypeProperty.java | 1 - .../property/CargoDependenciesProperty.java | 1 - .../property/ClockSyncModeProperty.java | 1 - .../property/ClockSyncOptionsProperty.java | 1 - .../property/CompileDefinitionsProperty.java | 1 - .../property/CoordinationOptionsProperty.java | 1 - .../target/property/CoordinationProperty.java | 1 - .../target/property/DockerProperty.java | 1 - .../target/property/FedSetupProperty.java | 1 - .../target/property/FileListProperty.java | 1 - .../target/property/LoggingProperty.java | 1 - .../target/property/PlatformProperty.java | 1 - .../property/Ros2DependenciesProperty.java | 1 - .../target/property/RustIncludeProperty.java | 1 - .../target/property/SchedulerProperty.java | 1 - .../target/property/StringListProperty.java | 1 - .../target/property/StringProperty.java | 1 - .../{ => target/property}/TargetProperty.java | 3 ++- .../target/property/TimeOutProperty.java | 1 - .../target/property/TracingProperty.java | 9 ++++++++- .../target/property/WorkersProperty.java | 1 - .../compiler/LinguaFrancaValidationTest.java | 19 ++++++++++++++++++- 26 files changed, 30 insertions(+), 33 deletions(-) rename core/src/main/java/org/lflang/{ => target/property}/TargetProperty.java (98%) diff --git a/core/src/main/java/org/lflang/generator/GeneratorBase.java b/core/src/main/java/org/lflang/generator/GeneratorBase.java index e67397cffb..430b0a25d5 100644 --- a/core/src/main/java/org/lflang/generator/GeneratorBase.java +++ b/core/src/main/java/org/lflang/generator/GeneratorBase.java @@ -703,11 +703,6 @@ public void printInfo(LFGeneratorContext context) { messageReporter.nowhere().info(context.getTargetConfig().settings()); } - /** Get the buffer type used for network messages */ - public String getNetworkBufferType() { - return ""; - } - /** Return the Targets enum for the current target */ public abstract Target getTarget(); } diff --git a/core/src/main/java/org/lflang/target/TargetConfig.java b/core/src/main/java/org/lflang/target/TargetConfig.java index 9b0f14817c..27d6d6c768 100644 --- a/core/src/main/java/org/lflang/target/TargetConfig.java +++ b/core/src/main/java/org/lflang/target/TargetConfig.java @@ -36,7 +36,6 @@ import java.util.Set; import java.util.stream.Collectors; import org.lflang.MessageReporter; -import org.lflang.TargetProperty; import org.lflang.generator.GeneratorArguments; import org.lflang.lf.KeyValuePair; import org.lflang.lf.KeyValuePairs; @@ -48,8 +47,8 @@ import org.lflang.target.property.FedSetupProperty; import org.lflang.target.property.LoggingProperty; import org.lflang.target.property.NoCompileProperty; +import org.lflang.target.property.TargetProperty; import org.lflang.target.property.TimeOutProperty; -import org.lflang.target.property.TracingProperty; import org.lflang.target.property.type.TargetPropertyType; import org.lflang.validation.ValidatorMessageReporter; @@ -84,8 +83,7 @@ public TargetConfig(Target target) { FastProperty.INSTANCE, LoggingProperty.INSTANCE, NoCompileProperty.INSTANCE, - TimeOutProperty.INSTANCE, - TracingProperty.INSTANCE); + TimeOutProperty.INSTANCE); } public TargetConfig(TargetDecl target, GeneratorArguments args, MessageReporter messageReporter) { diff --git a/core/src/main/java/org/lflang/target/property/BooleanProperty.java b/core/src/main/java/org/lflang/target/property/BooleanProperty.java index adf1314480..ee12963a3a 100644 --- a/core/src/main/java/org/lflang/target/property/BooleanProperty.java +++ b/core/src/main/java/org/lflang/target/property/BooleanProperty.java @@ -1,7 +1,6 @@ package org.lflang.target.property; import org.lflang.MessageReporter; -import org.lflang.TargetProperty; import org.lflang.ast.ASTUtils; import org.lflang.lf.Element; import org.lflang.target.property.type.PrimitiveType; diff --git a/core/src/main/java/org/lflang/target/property/BuildCommandsProperty.java b/core/src/main/java/org/lflang/target/property/BuildCommandsProperty.java index 8d7df554a1..93a5e8f6e6 100644 --- a/core/src/main/java/org/lflang/target/property/BuildCommandsProperty.java +++ b/core/src/main/java/org/lflang/target/property/BuildCommandsProperty.java @@ -3,7 +3,6 @@ import java.util.ArrayList; import java.util.List; import org.lflang.MessageReporter; -import org.lflang.TargetProperty; import org.lflang.ast.ASTUtils; import org.lflang.lf.Element; import org.lflang.target.property.type.UnionType; diff --git a/core/src/main/java/org/lflang/target/property/BuildTypeProperty.java b/core/src/main/java/org/lflang/target/property/BuildTypeProperty.java index 6ed75f23e2..33f31c19f9 100644 --- a/core/src/main/java/org/lflang/target/property/BuildTypeProperty.java +++ b/core/src/main/java/org/lflang/target/property/BuildTypeProperty.java @@ -1,7 +1,6 @@ package org.lflang.target.property; import org.lflang.MessageReporter; -import org.lflang.TargetProperty; import org.lflang.ast.ASTUtils; import org.lflang.generator.GeneratorArguments; import org.lflang.lf.Element; 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 d33d344b51..764ab70c11 100644 --- a/core/src/main/java/org/lflang/target/property/CargoDependenciesProperty.java +++ b/core/src/main/java/org/lflang/target/property/CargoDependenciesProperty.java @@ -3,7 +3,6 @@ import java.util.HashMap; import java.util.Map; import org.lflang.MessageReporter; -import org.lflang.TargetProperty; import org.lflang.generator.rust.CargoDependencySpec; import org.lflang.generator.rust.CargoDependencySpec.CargoDependenciesPropertyType; import org.lflang.lf.Element; 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 526983a09c..115b781366 100644 --- a/core/src/main/java/org/lflang/target/property/ClockSyncModeProperty.java +++ b/core/src/main/java/org/lflang/target/property/ClockSyncModeProperty.java @@ -2,7 +2,6 @@ import java.util.Objects; import org.lflang.MessageReporter; -import org.lflang.TargetProperty; import org.lflang.ast.ASTUtils; import org.lflang.lf.Element; import org.lflang.lf.KeyValuePair; 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 4e87412ff4..b5d08eaedd 100644 --- a/core/src/main/java/org/lflang/target/property/ClockSyncOptionsProperty.java +++ b/core/src/main/java/org/lflang/target/property/ClockSyncOptionsProperty.java @@ -1,7 +1,6 @@ package org.lflang.target.property; import org.lflang.MessageReporter; -import org.lflang.TargetProperty; import org.lflang.TimeUnit; import org.lflang.TimeValue; import org.lflang.ast.ASTUtils; diff --git a/core/src/main/java/org/lflang/target/property/CompileDefinitionsProperty.java b/core/src/main/java/org/lflang/target/property/CompileDefinitionsProperty.java index f1b2d2c4ed..05bfd6d988 100644 --- a/core/src/main/java/org/lflang/target/property/CompileDefinitionsProperty.java +++ b/core/src/main/java/org/lflang/target/property/CompileDefinitionsProperty.java @@ -3,7 +3,6 @@ import java.util.HashMap; import java.util.Map; import org.lflang.MessageReporter; -import org.lflang.TargetProperty; import org.lflang.ast.ASTUtils; import org.lflang.lf.Element; import org.lflang.target.TargetConfig; 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 e8848ea933..9d0767ee31 100644 --- a/core/src/main/java/org/lflang/target/property/CoordinationOptionsProperty.java +++ b/core/src/main/java/org/lflang/target/property/CoordinationOptionsProperty.java @@ -2,7 +2,6 @@ import java.util.Objects; import org.lflang.MessageReporter; -import org.lflang.TargetProperty; import org.lflang.TimeValue; import org.lflang.ast.ASTUtils; import org.lflang.lf.Element; diff --git a/core/src/main/java/org/lflang/target/property/CoordinationProperty.java b/core/src/main/java/org/lflang/target/property/CoordinationProperty.java index ed57cbedef..6809aeb99d 100644 --- a/core/src/main/java/org/lflang/target/property/CoordinationProperty.java +++ b/core/src/main/java/org/lflang/target/property/CoordinationProperty.java @@ -1,7 +1,6 @@ package org.lflang.target.property; import org.lflang.MessageReporter; -import org.lflang.TargetProperty; import org.lflang.ast.ASTUtils; import org.lflang.lf.Element; import org.lflang.target.property.type.CoordinationModeType; 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 6e01b980eb..fc72cf245c 100644 --- a/core/src/main/java/org/lflang/target/property/DockerProperty.java +++ b/core/src/main/java/org/lflang/target/property/DockerProperty.java @@ -2,7 +2,6 @@ import java.util.Objects; import org.lflang.MessageReporter; -import org.lflang.TargetProperty; import org.lflang.ast.ASTUtils; import org.lflang.lf.Element; import org.lflang.lf.KeyValuePair; diff --git a/core/src/main/java/org/lflang/target/property/FedSetupProperty.java b/core/src/main/java/org/lflang/target/property/FedSetupProperty.java index f19594c2ec..d6bd3e517f 100644 --- a/core/src/main/java/org/lflang/target/property/FedSetupProperty.java +++ b/core/src/main/java/org/lflang/target/property/FedSetupProperty.java @@ -1,7 +1,6 @@ package org.lflang.target.property; import org.lflang.MessageReporter; -import org.lflang.TargetProperty; import org.lflang.ast.ASTUtils; import org.lflang.lf.Element; import org.lflang.target.property.type.PrimitiveType; diff --git a/core/src/main/java/org/lflang/target/property/FileListProperty.java b/core/src/main/java/org/lflang/target/property/FileListProperty.java index 0baaadec0c..3409fcde8f 100644 --- a/core/src/main/java/org/lflang/target/property/FileListProperty.java +++ b/core/src/main/java/org/lflang/target/property/FileListProperty.java @@ -3,7 +3,6 @@ import java.util.ArrayList; import java.util.List; import org.lflang.MessageReporter; -import org.lflang.TargetProperty; import org.lflang.ast.ASTUtils; import org.lflang.lf.Element; import org.lflang.target.TargetConfig; diff --git a/core/src/main/java/org/lflang/target/property/LoggingProperty.java b/core/src/main/java/org/lflang/target/property/LoggingProperty.java index 1edd6799c0..c539b82734 100644 --- a/core/src/main/java/org/lflang/target/property/LoggingProperty.java +++ b/core/src/main/java/org/lflang/target/property/LoggingProperty.java @@ -1,7 +1,6 @@ package org.lflang.target.property; import org.lflang.MessageReporter; -import org.lflang.TargetProperty; import org.lflang.ast.ASTUtils; import org.lflang.generator.GeneratorArguments; import org.lflang.lf.Element; 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 1a43ddd26c..98867d23e2 100644 --- a/core/src/main/java/org/lflang/target/property/PlatformProperty.java +++ b/core/src/main/java/org/lflang/target/property/PlatformProperty.java @@ -1,7 +1,6 @@ package org.lflang.target.property; import org.lflang.MessageReporter; -import org.lflang.TargetProperty; import org.lflang.ast.ASTUtils; import org.lflang.lf.Element; import org.lflang.lf.KeyValuePair; 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 620970ec00..ec21d58027 100644 --- a/core/src/main/java/org/lflang/target/property/Ros2DependenciesProperty.java +++ b/core/src/main/java/org/lflang/target/property/Ros2DependenciesProperty.java @@ -3,7 +3,6 @@ import java.util.ArrayList; import java.util.List; import org.lflang.MessageReporter; -import org.lflang.TargetProperty; import org.lflang.ast.ASTUtils; import org.lflang.lf.Element; import org.lflang.lf.KeyValuePair; diff --git a/core/src/main/java/org/lflang/target/property/RustIncludeProperty.java b/core/src/main/java/org/lflang/target/property/RustIncludeProperty.java index a2d9001e26..ee80e96409 100644 --- a/core/src/main/java/org/lflang/target/property/RustIncludeProperty.java +++ b/core/src/main/java/org/lflang/target/property/RustIncludeProperty.java @@ -6,7 +6,6 @@ import java.util.List; import org.eclipse.emf.ecore.EObject; import org.lflang.MessageReporter; -import org.lflang.TargetProperty; import org.lflang.ast.ASTUtils; import org.lflang.lf.Array; import org.lflang.lf.Element; 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 27c7c25cb3..8c92d73ff4 100644 --- a/core/src/main/java/org/lflang/target/property/SchedulerProperty.java +++ b/core/src/main/java/org/lflang/target/property/SchedulerProperty.java @@ -1,7 +1,6 @@ package org.lflang.target.property; import org.lflang.MessageReporter; -import org.lflang.TargetProperty; import org.lflang.ast.ASTUtils; import org.lflang.generator.GeneratorArguments; import org.lflang.lf.Element; diff --git a/core/src/main/java/org/lflang/target/property/StringListProperty.java b/core/src/main/java/org/lflang/target/property/StringListProperty.java index 1a010e0ea8..7fe58820e7 100644 --- a/core/src/main/java/org/lflang/target/property/StringListProperty.java +++ b/core/src/main/java/org/lflang/target/property/StringListProperty.java @@ -3,7 +3,6 @@ import java.util.ArrayList; import java.util.List; import org.lflang.MessageReporter; -import org.lflang.TargetProperty; import org.lflang.ast.ASTUtils; import org.lflang.lf.Element; import org.lflang.target.TargetConfig; diff --git a/core/src/main/java/org/lflang/target/property/StringProperty.java b/core/src/main/java/org/lflang/target/property/StringProperty.java index a3536ffff4..1d80dc78e2 100644 --- a/core/src/main/java/org/lflang/target/property/StringProperty.java +++ b/core/src/main/java/org/lflang/target/property/StringProperty.java @@ -1,7 +1,6 @@ package org.lflang.target.property; import org.lflang.MessageReporter; -import org.lflang.TargetProperty; import org.lflang.ast.ASTUtils; import org.lflang.lf.Element; import org.lflang.target.property.type.PrimitiveType; diff --git a/core/src/main/java/org/lflang/TargetProperty.java b/core/src/main/java/org/lflang/target/property/TargetProperty.java similarity index 98% rename from core/src/main/java/org/lflang/TargetProperty.java rename to core/src/main/java/org/lflang/target/property/TargetProperty.java index 5fd4122794..41372dc6b8 100644 --- a/core/src/main/java/org/lflang/TargetProperty.java +++ b/core/src/main/java/org/lflang/target/property/TargetProperty.java @@ -1,8 +1,9 @@ -package org.lflang; +package org.lflang.target.property; import com.google.gson.JsonObject; import java.util.List; import java.util.Optional; +import org.lflang.MessageReporter; import org.lflang.generator.GeneratorArguments; import org.lflang.lf.Element; import org.lflang.lf.KeyValuePair; diff --git a/core/src/main/java/org/lflang/target/property/TimeOutProperty.java b/core/src/main/java/org/lflang/target/property/TimeOutProperty.java index 1fb4071184..edb9818fb8 100644 --- a/core/src/main/java/org/lflang/target/property/TimeOutProperty.java +++ b/core/src/main/java/org/lflang/target/property/TimeOutProperty.java @@ -1,7 +1,6 @@ package org.lflang.target.property; import org.lflang.MessageReporter; -import org.lflang.TargetProperty; import org.lflang.TimeValue; import org.lflang.ast.ASTUtils; import org.lflang.lf.Element; 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 5ccb9b5c86..3c35049c59 100644 --- a/core/src/main/java/org/lflang/target/property/TracingProperty.java +++ b/core/src/main/java/org/lflang/target/property/TracingProperty.java @@ -2,7 +2,6 @@ import java.util.Objects; import org.lflang.MessageReporter; -import org.lflang.TargetProperty; import org.lflang.ast.ASTUtils; import org.lflang.generator.GeneratorArguments; import org.lflang.lf.Element; @@ -11,6 +10,7 @@ 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; import org.lflang.target.property.type.DictionaryType; @@ -73,6 +73,13 @@ public void validate(KeyValuePair pair, Model ast, MessageReporter reporter) { } } } + 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 5f8c236279..b61fa21aaa 100644 --- a/core/src/main/java/org/lflang/target/property/WorkersProperty.java +++ b/core/src/main/java/org/lflang/target/property/WorkersProperty.java @@ -1,7 +1,6 @@ package org.lflang.target.property; import org.lflang.MessageReporter; -import org.lflang.TargetProperty; import org.lflang.ast.ASTUtils; import org.lflang.generator.GeneratorArguments; import org.lflang.lf.Element; 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 89582b475d..169cfa3480 100644 --- a/core/src/test/java/org/lflang/tests/compiler/LinguaFrancaValidationTest.java +++ b/core/src/test/java/org/lflang/tests/compiler/LinguaFrancaValidationTest.java @@ -44,7 +44,6 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestFactory; import org.junit.jupiter.api.extension.ExtendWith; -import org.lflang.TargetProperty; import org.lflang.TimeValue; import org.lflang.lf.LfPackage; import org.lflang.lf.Model; @@ -53,6 +52,7 @@ import org.lflang.target.TargetConfig; import org.lflang.target.property.CargoDependenciesProperty; import org.lflang.target.property.PlatformProperty; +import org.lflang.target.property.TargetProperty; import org.lflang.target.property.type.ArrayType; import org.lflang.target.property.type.DictionaryType; import org.lflang.target.property.type.DictionaryType.DictionaryElement; @@ -108,6 +108,23 @@ private Model parseWithError(String s) throws Exception { return model; } + /** Ensure that duplicate identifiers for actions reported. */ + @Test + public void tracingOptionsCpp() throws Exception { + String testCase = + """ + target Cpp{ + tracing: {trace-file-name: "Bar"} + }; + main reactor {} + """; + validator.assertWarning( + parseWithoutError(testCase), + LfPackage.eINSTANCE.getKeyValuePair(), + null, + "The C++ target only supports 'true' or 'false'"); + } + /** Ensure that duplicate identifiers for actions reported. */ @Test public void duplicateVariable() throws Exception { From 06d575f672a28ad2f7da9ee05bd1d9e85721b4e6 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Wed, 1 Nov 2023 12:44:59 -0700 Subject: [PATCH 136/145] Point workflow back to Epoch master --- .github/workflows/build.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f444bc02f8..da1990ca3f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -36,5 +36,4 @@ jobs: with: lingua-franca-ref: ${{ github.head_ref || github.ref_name }} lingua-franca-repo: ${{ github.event.pull_request.head.repo.full_name }} - epoch-ref: message-reporter upload-artifacts: false From 12870248959f1aaed896475e9d3e2ea0ee2efeb2 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Wed, 1 Nov 2023 14:08:40 -0700 Subject: [PATCH 137/145] Address FIXME --- cli/lfc/src/main/java/org/lflang/cli/Lfc.java | 7 +++++ .../lflang/generator/GeneratorArguments.java | 3 ++- .../java/org/lflang/target/TargetConfig.java | 26 +++++++++---------- 3 files changed, 22 insertions(+), 14 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 fce3d08e23..b46cc1ea68 100644 --- a/cli/lfc/src/main/java/org/lflang/cli/Lfc.java +++ b/cli/lfc/src/main/java/org/lflang/cli/Lfc.java @@ -120,6 +120,12 @@ public class Lfc extends CliBase { description = "Specify whether the runtime should use multi-threading" + " (true/false).") private String threading; + @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.") @@ -271,6 +277,7 @@ public GeneratorArguments getArgs() { } args.threading = Boolean.parseBoolean(threading); + args.tracing = tracing; args.verify = verify; args.workers = workers; diff --git a/core/src/main/java/org/lflang/generator/GeneratorArguments.java b/core/src/main/java/org/lflang/generator/GeneratorArguments.java index e57982b52d..cb6ef5d674 100644 --- a/core/src/main/java/org/lflang/generator/GeneratorArguments.java +++ b/core/src/main/java/org/lflang/generator/GeneratorArguments.java @@ -6,6 +6,7 @@ import org.lflang.target.property.type.LoggingType.LogLevel; import org.lflang.target.property.type.SchedulerType.Scheduler; +/** */ public class GeneratorArguments { /** @@ -81,7 +82,7 @@ public class GeneratorArguments { /** * @see org.lflang.target.property.SchedulerProperty */ - public Boolean tracing; // FIXME add CLI arg for this + public Boolean tracing; /** * @see org.lflang.target.property.WorkersProperty diff --git a/core/src/main/java/org/lflang/target/TargetConfig.java b/core/src/main/java/org/lflang/target/TargetConfig.java index 27d6d6c768..2609b4ca0a 100644 --- a/core/src/main/java/org/lflang/target/TargetConfig.java +++ b/core/src/main/java/org/lflang/target/TargetConfig.java @@ -205,20 +205,20 @@ public void load(GeneratorArguments args, MessageReporter err) { * @param err Error reporter on which property format errors will be reported */ public void load(List pairs, MessageReporter err) { - if (pairs == null) { - return; + if (pairs != null) { + + pairs.forEach( + pair -> { + var p = forName(pair.getName()); + if (p.isPresent()) { + var property = p.get(); + property.update(this, pair.getValue(), err); + } else { + err.nowhere() + .warning("Attempting to load unrecognized target property: " + pair.getName()); + } + }); } - pairs.forEach( - pair -> { - var p = forName(pair.getName()); - if (p.isPresent()) { - var property = p.get(); - property.update(this, pair.getValue(), err); - } else { - err.nowhere() - .warning("Attempting to load unrecognized target property: " + pair.getName()); - } - }); } public void set(TargetProperty property, T value) { From 9603e4c97ace8eb25894b242c4f6520e05f4e934 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Thu, 2 Nov 2023 17:17:24 -0700 Subject: [PATCH 138/145] Revise GeneratorArguments and deal with JSON --- cli/lfc/src/main/java/org/lflang/cli/Lfc.java | 167 ++++++++++++++---- .../test/java/org/lflang/cli/LfcCliTest.java | 53 ++++-- .../org/lflang/tests/runtime/PythonTest.java | 9 +- .../serialization/SerializationTest.java | 9 +- .../federated/generator/FedGenerator.java | 8 +- .../lflang/generator/GeneratorArguments.java | 117 ++++-------- .../org/lflang/generator/GeneratorBase.java | 4 +- .../lflang/generator/IntegratedBuilder.java | 7 +- .../org/lflang/generator/MainContext.java | 4 +- .../java/org/lflang/generator/Validator.java | 2 +- .../org/lflang/generator/c/CGenerator.java | 4 +- .../main/java/org/lflang/target/Target.java | 3 +- .../java/org/lflang/target/TargetConfig.java | 49 +++-- .../target/property/BuildTypeProperty.java | 6 - .../target/property/CompilerProperty.java | 7 - .../property/ExternalRuntimePathProperty.java | 16 +- .../property/HierarchicalBinProperty.java | 7 - .../target/property/LoggingProperty.java | 6 - .../target/property/NoCompileProperty.java | 7 - .../property/PrintStatisticsProperty.java | 7 - .../property/RuntimeVersionProperty.java | 7 - .../target/property/SchedulerProperty.java | 6 - .../target/property/TargetProperty.java | 30 ++-- .../target/property/TracingProperty.java | 13 +- .../target/property/VerifyProperty.java | 6 - .../target/property/WorkersProperty.java | 6 - .../org/lflang/generator/ts/TSGenerator.kt | 3 +- .../compiler/LinguaFrancaValidationTest.java | 3 +- .../java/org/lflang/tests/TestBase.java | 70 +++++--- 29 files changed, 329 insertions(+), 307 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 b46cc1ea68..c76516b002 100644 --- a/cli/lfc/src/main/java/org/lflang/cli/Lfc.java +++ b/cli/lfc/src/main/java/org/lflang/cli/Lfc.java @@ -1,21 +1,41 @@ package org.lflang.cli; import com.google.inject.Inject; +import java.net.URI; import java.nio.file.Files; import java.nio.file.Path; +import java.util.ArrayList; import java.util.List; +import java.util.Objects; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.xtext.generator.GeneratorDelegate; import org.eclipse.xtext.generator.JavaIoFileSystemAccess; import org.eclipse.xtext.util.CancelIndicator; import org.lflang.FileConfig; import org.lflang.ast.ASTUtils; +import org.lflang.generator.Argument; import org.lflang.generator.GeneratorArguments; import org.lflang.generator.LFGeneratorContext; import org.lflang.generator.MainContext; +import org.lflang.target.property.BuildTypeProperty; +import org.lflang.target.property.CompilerProperty; +import org.lflang.target.property.HierarchicalBinProperty; +import org.lflang.target.property.LoggingProperty; +import org.lflang.target.property.NoCompileProperty; +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.TracingProperty; +import org.lflang.target.property.TracingProperty.TracingOptions; +import org.lflang.target.property.VerifyProperty; +import org.lflang.target.property.WorkersProperty; import org.lflang.target.property.type.BuildTypeType; +import org.lflang.target.property.type.BuildTypeType.BuildType; import org.lflang.target.property.type.LoggingType; +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.Command; import picocli.CommandLine.Option; @@ -65,38 +85,46 @@ public class Lfc extends CliBase { description = "Treat main reactor as federated.") private boolean federated; - @Option(names = "--logging", description = "The logging level to use by the generated binary") + @Option( + names = {"--hierarchical-bin"}, + arity = "0", + description = + "Organize the generated binaries hierarchically, reflecting the structure of the source" + + " tree.") + private Boolean hierarchicalBin; + + @Option(names = "--logging", description = "The logging level to use by the generated binary.") private String logging; @Option( names = {"-l", "--lint"}, arity = "0", description = "Enable linting of generated code.") - private boolean lint; + private Boolean lint; @Option( names = {"-n", "--no-compile"}, arity = "0", description = "Do not invoke target compiler.") - private boolean noCompile; + private Boolean noCompile; @Option( names = {"--verify"}, arity = "0", description = "Run the generated verification models.") - private boolean verify; + private Boolean verify; @Option( names = {"--print-statistics"}, arity = "0", description = "Instruct the runtime to collect and print statistics.") - private boolean printStatistics; + private Boolean printStatistics; @Option( names = {"-q", "--quiet"}, arity = "0", description = "Suppress output of the target compiler and other commands") - private boolean quiet; + private Boolean quiet; @Option( names = {"-r", "--rti"}, @@ -124,7 +152,7 @@ public class Lfc extends CliBase { names = {"--tracing"}, arity = "0", description = "Specify whether to enable run-time tracing (if supported).") - private boolean tracing; + private Boolean tracing; @Option( names = {"-w", "--workers"}, @@ -213,6 +241,7 @@ private void invokeGenerator(List files, Path root, GeneratorArguments arg } } + /** Return a resolved path that designates where to write files to. */ private Path getActualOutputPath(Path root, Path path) { if (root != null) { return root.resolve("src-gen"); @@ -222,65 +251,127 @@ private Path getActualOutputPath(Path root, Path path) { } } - /** Check the values of the commandline arguments and return them. */ - public GeneratorArguments getArgs() { - var args = new GeneratorArguments(); + /** + * Return a build type if one has been specified via the CLI arguments, or {@code null} otherwise. + */ + private BuildType getBuildType() { + BuildType resolved = null; if (buildType != null) { // Validate build type. - var resolved = new BuildTypeType().forName(buildType); + resolved = new BuildTypeType().forName(buildType); if (resolved == null) { reporter.printFatalErrorAndExit(buildType + ": Invalid build type."); } - args.buildType = resolved; - } - - args.clean = clean; - args.compiler = targetCompiler; - if (externalRuntimePath != null) { - args.externalRuntimeUri = externalRuntimePath.toUri(); } + return resolved; + } - args.jsonObject = getJsonObject(); - - args.lint = lint; - + /** + * Return a log level if one has been specified via the CLI arguments, or {@code null} otherwise. + */ + private LogLevel getLogging() { + LogLevel resolved = null; if (logging != null) { // Validate log level. - var resolved = new LoggingType().forName(logging); + resolved = new LoggingType().forName(logging); if (resolved == null) { reporter.printFatalErrorAndExit(logging + ": Invalid log level."); } - args.logging = resolved; } + return resolved; + } - args.noCompile = noCompile; - args.printStatistics = printStatistics; - args.quiet = quiet; - + /** + * Return a URI that points to the RTI if one has been specified via the CLI arguments, or {@code + * null} otherwise. + */ + private URI getRtiUri() { + URI uri = null; if (rti != null) { // Validate RTI path. if (!Files.exists(io.getWd().resolve(rti))) { reporter.printFatalErrorAndExit(rti + ": Invalid RTI path."); } - args.rti = rti.toUri(); + uri = rti.toUri(); } + return uri; + } - args.runtimeVersion = runtimeVersion; - + /** Return a scheduler one has been specified via the CLI arguments, or {@code null} otherwise. */ + private Scheduler getScheduler() { + Scheduler resolved = null; if (scheduler != null) { // Validate scheduler. - var resolved = new SchedulerType().forName(scheduler); + resolved = new SchedulerType().forName(scheduler); if (resolved == null) { reporter.printFatalErrorAndExit(scheduler + ": Invalid scheduler."); } - args.scheduler = resolved; } + return resolved; + } - args.threading = Boolean.parseBoolean(threading); - args.tracing = tracing; - args.verify = verify; - args.workers = workers; + /** + * Return a URI that points to an external runtime if one has been specified via the CLI + * arguments, or {@code null} otherwise. + */ + private URI getExternalRuntimeUri() { + URI externalRuntimeUri = null; + if (externalRuntimePath != null) { + externalRuntimeUri = externalRuntimePath.toUri(); + } + return externalRuntimeUri; + } + + /** + * Return tracing options if tracing has been explicitly disabled or enabled via the CLI + * arguments, or {@code null} otherwise. + */ + private TracingOptions getTracingOptions() { + if (tracing != null) { + return new TracingOptions(tracing); + } else { + return null; + } + } + + /** 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() { + + List> args = new ArrayList<>(); + + if (buildType != null) { + args.add(new Argument<>(BuildTypeProperty.INSTANCE, getBuildType())); + } - return args; + return new GeneratorArguments( + Objects.requireNonNullElse(clean, false), + getExternalRuntimeUri(), + Objects.requireNonNullElse(hierarchicalBin, false), + getJsonObject(), + Objects.requireNonNullElse(lint, false), + Objects.requireNonNullElse(quiet, false), + getRtiUri(), + List.of( + new Argument<>(BuildTypeProperty.INSTANCE, getBuildType()), + new Argument<>(CompilerProperty.INSTANCE, targetCompiler), + new Argument<>(HierarchicalBinProperty.INSTANCE, hierarchicalBin), + new Argument<>(LoggingProperty.INSTANCE, getLogging()), + new Argument<>(PrintStatisticsProperty.INSTANCE, printStatistics), + new Argument<>(NoCompileProperty.INSTANCE, noCompile), + new Argument<>(VerifyProperty.INSTANCE, verify), + new Argument<>(RuntimeVersionProperty.INSTANCE, runtimeVersion), + new Argument<>(SchedulerProperty.INSTANCE, getScheduler()), + new Argument<>(ThreadingProperty.INSTANCE, getThreading()), + 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 2c796d3434..ef7a7676c8 100644 --- a/cli/lfc/src/test/java/org/lflang/cli/LfcCliTest.java +++ b/cli/lfc/src/test/java/org/lflang/cli/LfcCliTest.java @@ -42,6 +42,17 @@ import org.junit.jupiter.api.io.TempDir; import org.lflang.LocalStrings; import org.lflang.cli.TestUtils.TempDirBuilder; +import org.lflang.generator.GeneratorArguments; +import org.lflang.target.property.BuildTypeProperty; +import org.lflang.target.property.CompilerProperty; +import org.lflang.target.property.LoggingProperty; +import org.lflang.target.property.NoCompileProperty; +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.ThreadingProperty; +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; @@ -247,25 +258,37 @@ public void verifyGeneratorArgs(Path tempDir, String[] args) { result -> { // Don't validate execution because args are dummy args. var genArgs = fixture.lfc.getArgs(); - assertEquals(BuildType.RELEASE, genArgs.buildType); - assertEquals(true, genArgs.clean); - assertEquals("gcc", genArgs.compiler); - assertEquals("src", Path.of(genArgs.externalRuntimeUri).getFileName().toString()); - assertEquals(LogLevel.INFO, genArgs.logging); - assertEquals(true, genArgs.lint); - assertEquals(true, genArgs.noCompile); - assertEquals(true, genArgs.printStatistics); - assertEquals(true, genArgs.quiet); + checkOverrideValue(genArgs, BuildTypeProperty.INSTANCE, BuildType.RELEASE); + checkOverrideValue(genArgs, CompilerProperty.INSTANCE, "gcc"); + checkOverrideValue(genArgs, LoggingProperty.INSTANCE, LogLevel.INFO); + checkOverrideValue(genArgs, NoCompileProperty.INSTANCE, true); + checkOverrideValue(genArgs, PrintStatisticsProperty.INSTANCE, true); + checkOverrideValue(genArgs, RuntimeVersionProperty.INSTANCE, "rs"); + checkOverrideValue(genArgs, SchedulerProperty.INSTANCE, Scheduler.GEDF_NP); + checkOverrideValue(genArgs, ThreadingProperty.INSTANCE, false); + checkOverrideValue(genArgs, WorkersProperty.INSTANCE, 1); + + assertEquals(true, genArgs.clean()); + assertEquals("src", Path.of(genArgs.externalRuntimeUri()).getFileName().toString()); + assertEquals(true, genArgs.lint()); + assertEquals(true, genArgs.quiet()); assertEquals( Path.of("path", "to", "rti"), - Path.of(new File("").getAbsolutePath()).relativize(Paths.get(genArgs.rti))); - assertEquals("rs", genArgs.runtimeVersion); - assertEquals(Scheduler.GEDF_NP, genArgs.scheduler); - assertEquals(false, genArgs.threading); - assertEquals(1, genArgs.workers); + Path.of(new File("").getAbsolutePath()).relativize(Paths.get(genArgs.rti()))); }); } + private void checkOverrideValue( + GeneratorArguments args, TargetProperty property, Object expected) { + var value = + args.overrides().stream() + .filter(a -> a.property().equals(property)) + .findFirst() + .get() + .value(); + assertEquals(expected, value); + } + public void verifyJsonGeneratorArgs(Path tempDir, String[] args) { LfcOneShotTestFixture fixture = new LfcOneShotTestFixture(); @@ -276,7 +299,7 @@ public void verifyJsonGeneratorArgs(Path tempDir, String[] args) { // Don't validate execution because args are dummy args. var genArgs = fixture.lfc.getArgs(); assertEquals( - JsonParser.parseString(JSON_STRING).getAsJsonObject(), genArgs.jsonObject); + JsonParser.parseString(JSON_STRING).getAsJsonObject(), genArgs.jsonObject()); }); } diff --git a/core/src/integrationTest/java/org/lflang/tests/runtime/PythonTest.java b/core/src/integrationTest/java/org/lflang/tests/runtime/PythonTest.java index c760deb563..5880a30f46 100644 --- a/core/src/integrationTest/java/org/lflang/tests/runtime/PythonTest.java +++ b/core/src/integrationTest/java/org/lflang/tests/runtime/PythonTest.java @@ -27,8 +27,9 @@ import org.junit.jupiter.api.Assumptions; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; -import org.lflang.generator.GeneratorArguments; import org.lflang.target.Target; +import org.lflang.target.TargetConfig; +import org.lflang.target.property.BuildTypeProperty; import org.lflang.target.property.type.BuildTypeType.BuildType; import org.lflang.tests.RuntimeTest; @@ -48,12 +49,12 @@ public PythonTest() { } @Override - protected void addExtraLfcArgs(GeneratorArguments args) { - super.addExtraLfcArgs(args); + protected void applyDefaultConfiguration(TargetConfig config) { + super.applyDefaultConfiguration(config); if (System.getProperty("os.name").startsWith("Windows")) { // Use the RelWithDebInfo build type on Windows as the Debug/Test build type produces linker // Errors in CI - args.buildType = BuildType.REL_WITH_DEB_INFO; + BuildTypeProperty.INSTANCE.override(config, BuildType.REL_WITH_DEB_INFO); } } diff --git a/core/src/integrationTest/java/org/lflang/tests/serialization/SerializationTest.java b/core/src/integrationTest/java/org/lflang/tests/serialization/SerializationTest.java index ac33289ebd..735441dba6 100644 --- a/core/src/integrationTest/java/org/lflang/tests/serialization/SerializationTest.java +++ b/core/src/integrationTest/java/org/lflang/tests/serialization/SerializationTest.java @@ -2,8 +2,9 @@ import org.junit.jupiter.api.Assumptions; import org.junit.jupiter.api.Test; -import org.lflang.generator.GeneratorArguments; import org.lflang.target.Target; +import org.lflang.target.TargetConfig; +import org.lflang.target.property.BuildTypeProperty; import org.lflang.target.property.type.BuildTypeType.BuildType; import org.lflang.tests.Configurators; import org.lflang.tests.TestBase; @@ -17,10 +18,10 @@ protected SerializationTest() { } @Override - protected void addExtraLfcArgs(GeneratorArguments args) { - super.addExtraLfcArgs(args); + protected void applyDefaultConfiguration(TargetConfig config) { + super.applyDefaultConfiguration(config); // Use the Debug build type as coverage generation does not work for the serialization tests - args.buildType = BuildType.DEBUG; + BuildTypeProperty.INSTANCE.override(config, BuildType.DEBUG); } @Test 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 9a28233b58..e070c68c8d 100644 --- a/core/src/main/java/org/lflang/federated/generator/FedGenerator.java +++ b/core/src/main/java/org/lflang/federated/generator/FedGenerator.java @@ -224,7 +224,7 @@ private void createDockerFiles(LFGeneratorContext context, List subC * @param context Context in which the generator operates */ private void cleanIfNeeded(LFGeneratorContext context) { - if (context.getArgs().clean) { + if (context.getArgs().clean()) { try { fileConfig.doClean(); } catch (IOException e) { @@ -292,7 +292,7 @@ private Map compileFederates( TargetConfig subConfig = new TargetConfig( GeneratorUtils.findTargetDecl(subFileConfig.resource), - new GeneratorArguments(), + GeneratorArguments.none(), subContextMessageReporter); if (targetConfig.get(DockerProperty.INSTANCE).enabled && targetConfig.target.buildsUsingDocker()) { @@ -358,7 +358,7 @@ public TargetConfig getTargetConfig() { * @param context Context of the build process. */ private void processCLIArguments(LFGeneratorContext context) { - if (context.getArgs().rti != null) { + if (context.getArgs().rti() != null) { setFederationRTIProperties(context); } } @@ -369,7 +369,7 @@ private void processCLIArguments(LFGeneratorContext context) { * @param context Context of the build process. */ private void setFederationRTIProperties(LFGeneratorContext context) { - URI rtiAddr = context.getArgs().rti; + URI rtiAddr = context.getArgs().rti(); var host = rtiAddr.getHost(); var port = rtiAddr.getPort(); var user = rtiAddr.getUserInfo(); diff --git a/core/src/main/java/org/lflang/generator/GeneratorArguments.java b/core/src/main/java/org/lflang/generator/GeneratorArguments.java index cb6ef5d674..8600804485 100644 --- a/core/src/main/java/org/lflang/generator/GeneratorArguments.java +++ b/core/src/main/java/org/lflang/generator/GeneratorArguments.java @@ -2,90 +2,35 @@ import com.google.gson.JsonObject; import java.net.URI; -import org.lflang.target.property.type.BuildTypeType.BuildType; -import org.lflang.target.property.type.LoggingType.LogLevel; -import org.lflang.target.property.type.SchedulerType.Scheduler; - -/** */ -public class GeneratorArguments { - - /** - * @see org.lflang.target.property.BuildTypeProperty - */ - public BuildType buildType; - - /** Whether to clean before building. */ - public boolean clean; - - /** - * @see org.lflang.target.property.ExternalRuntimePathProperty - */ - public URI externalRuntimeUri; - - /** - * @see org.lflang.target.property.HierarchicalBinProperty - */ - public Boolean hierarchicalBin; - - /** Generator arguments and target properties, if they were passed to the application. */ - public JsonObject jsonObject; - - /** For enabling or disabling the linting of generated code */ - public boolean lint; - - /** - * @see org.lflang.target.property.LoggingProperty - */ - public LogLevel logging; - - /** - * @see org.lflang.target.property.PrintStatisticsProperty - */ - public Boolean printStatistics; - - /** - * @see org.lflang.target.property.NoCompileProperty - */ - public Boolean noCompile; - - /** - * @see org.lflang.target.property.VerifyProperty - */ - public Boolean verify; - - /** - * @see org.lflang.target.property.CompilerProperty - */ - public String compiler; - - /** Whether to suppress output of the target compiler and other commands. */ - public boolean quiet; - - /** The location of the rti. */ - public URI rti; - - /** - * @see org.lflang.target.property.RuntimeVersionProperty - */ - public String runtimeVersion; - - /** - * @see org.lflang.target.property.SchedulerProperty - */ - public Scheduler scheduler; - - /** - * @see org.lflang.target.property.SchedulerProperty - */ - public Boolean threading; - - /** - * @see org.lflang.target.property.SchedulerProperty - */ - public Boolean tracing; - - /** - * @see org.lflang.target.property.WorkersProperty - */ - public Integer workers; +import java.util.List; + +/** + * Arguments to be passed from the command-line interface to the code generators. + * + *

+ * + * @param clean Whether to clean before building. + * @param externalRuntimeUri FIXME: change type of + * org.lflang.target.property.ExternalRuntimePathProperty to URI + * @param jsonObject Generator arguments and target properties in JSON format. + * @param lint For enabling or disabling the linting of generated code. + * @param quiet Whether to suppress output of the target compiler and other commands. + * @param rti The location of the rti. + * @param overrides List of arguments that are meant to override target properties + * @author Marten Lohstroh + */ +public record GeneratorArguments( + boolean clean, + URI externalRuntimeUri, + boolean hierarchicalBin, + JsonObject jsonObject, + boolean lint, + boolean quiet, + URI rti, + List> overrides) { + + /** Return a record with none of the arguments set. */ + public static GeneratorArguments none() { + return new GeneratorArguments(false, null, false, null, false, false, null, List.of()); + } } diff --git a/core/src/main/java/org/lflang/generator/GeneratorBase.java b/core/src/main/java/org/lflang/generator/GeneratorBase.java index 430b0a25d5..c1851ec361 100644 --- a/core/src/main/java/org/lflang/generator/GeneratorBase.java +++ b/core/src/main/java/org/lflang/generator/GeneratorBase.java @@ -194,7 +194,7 @@ public void doGenerate(Resource resource, LFGeneratorContext context) { // Configure the command factory commandFactory.setVerbose(); if (Objects.equal(context.getMode(), LFGeneratorContext.Mode.STANDALONE) - && context.getArgs().quiet) { + && context.getArgs().quiet()) { commandFactory.setQuiet(); } @@ -616,7 +616,7 @@ public void reportCommandErrors(String stderr) { /** Check if a clean was requested from the standalone compiler and perform the clean step. */ protected void cleanIfNeeded(LFGeneratorContext context) { - if (context.getArgs().clean) { + if (context.getArgs().clean()) { try { context.getFileConfig().doClean(); } catch (IOException e) { diff --git a/core/src/main/java/org/lflang/generator/IntegratedBuilder.java b/core/src/main/java/org/lflang/generator/IntegratedBuilder.java index d0c3cbea74..1e88a15817 100644 --- a/core/src/main/java/org/lflang/generator/IntegratedBuilder.java +++ b/core/src/main/java/org/lflang/generator/IntegratedBuilder.java @@ -109,7 +109,7 @@ private GeneratorResult doGenerate( mustComplete ? Mode.LSP_SLOW : LFGeneratorContext.Mode.LSP_MEDIUM, cancelIndicator, reportProgress, - new GeneratorArguments(), + getArgs(), resource, fileAccess, fileConfig -> new LanguageServerMessageReporter(resource.getContents().get(0))); @@ -135,4 +135,9 @@ static DiagnosticSeverity convertSeverity(Severity severity) { case IGNORE -> DiagnosticSeverity.Hint; }; } + + /** Return arguments to feed to the code generator. Currently, no arguments are being set. */ + protected GeneratorArguments getArgs() { + return GeneratorArguments.none(); + } } diff --git a/core/src/main/java/org/lflang/generator/MainContext.java b/core/src/main/java/org/lflang/generator/MainContext.java index e2696142da..b3455b37e2 100644 --- a/core/src/main/java/org/lflang/generator/MainContext.java +++ b/core/src/main/java/org/lflang/generator/MainContext.java @@ -56,7 +56,7 @@ public MainContext( mode, cancelIndicator, (message, completion) -> {}, - new GeneratorArguments(), + GeneratorArguments.none(), resource, fsa, (mode == Mode.EPOCH && EPOCH_ERROR_REPORTER_CONSTRUCTOR != null) @@ -97,7 +97,7 @@ public MainContext( LFGenerator.createFileConfig( resource, FileConfig.getSrcGenRoot(fsa), - Objects.requireNonNullElse(args.hierarchicalBin, false))); + Objects.requireNonNullElse(args.hierarchicalBin(), false))); } catch (IOException e) { throw new RuntimeIOException("Error during FileConfig instantiation", e); } diff --git a/core/src/main/java/org/lflang/generator/Validator.java b/core/src/main/java/org/lflang/generator/Validator.java index 468d1a8a87..955b37599a 100644 --- a/core/src/main/java/org/lflang/generator/Validator.java +++ b/core/src/main/java/org/lflang/generator/Validator.java @@ -91,7 +91,7 @@ public final void doValidate(LFGeneratorContext context) * @param context The context of the current build. */ private boolean validationEnabled(LFGeneratorContext context) { - return context.getArgs().lint || validationEnabledByDefault(context); + return context.getArgs().lint() || validationEnabledByDefault(context); } /** 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 acb3fbabe5..1c277f5d29 100644 --- a/core/src/main/java/org/lflang/generator/c/CGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CGenerator.java @@ -913,8 +913,8 @@ protected void copyTargetFiles() throws IOException { } // Copy the core lib - if (context.getArgs().externalRuntimeUri != null) { - Path coreLib = Paths.get(context.getArgs().externalRuntimeUri); + if (context.getArgs().externalRuntimeUri() != null) { + Path coreLib = Paths.get(context.getArgs().externalRuntimeUri()); FileUtil.copyDirectoryContents(coreLib, dest, true); } else { FileUtil.copyFromClassPath("/lib/c/reactor-c/core", dest, true, false); diff --git a/core/src/main/java/org/lflang/target/Target.java b/core/src/main/java/org/lflang/target/Target.java index 36685236fa..98fd3179d2 100644 --- a/core/src/main/java/org/lflang/target/Target.java +++ b/core/src/main/java/org/lflang/target/Target.java @@ -657,7 +657,8 @@ public void initialize(TargetConfig config) { CoordinationProperty.INSTANCE, DockerProperty.INSTANCE, KeepaliveProperty.INSTANCE, - ProtobufsProperty.INSTANCE); + ProtobufsProperty.INSTANCE, + RuntimeVersionProperty.INSTANCE); } } } diff --git a/core/src/main/java/org/lflang/target/TargetConfig.java b/core/src/main/java/org/lflang/target/TargetConfig.java index 2609b4ca0a..671c6b8955 100644 --- a/core/src/main/java/org/lflang/target/TargetConfig.java +++ b/core/src/main/java/org/lflang/target/TargetConfig.java @@ -24,6 +24,7 @@ ***************/ package org.lflang.target; +import com.google.gson.JsonObject; import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; @@ -112,10 +113,36 @@ public TargetConfig( this.load(pairs, messageReporter); } + // Load properties from Json + load(args.jsonObject(), messageReporter); + // Load properties from CLI args load(args, messageReporter); } + private void load(JsonObject jsonObject, MessageReporter messageReporter) { + if (jsonObject != null && jsonObject.has("properties")) { + var map = jsonObject.getAsJsonObject("properties").asMap(); + map.keySet() + .forEach( + name -> { + var property = this.forName(name); + if (property.isPresent()) { + property.get().update(this, map.get(name), messageReporter); + } else { + reportUnsupportedTargetProperty(name, messageReporter.nowhere()); + } + }); + } + } + + public void reportUnsupportedTargetProperty(String name, MessageReporter.Stage2 stage2) { + stage2.warning( + String.format( + "The target property '%s' is not supported by the %s target and is thus ignored.", + name, this.target)); + } + /** Additional sources to add to the compile command if appropriate. */ public final List compileAdditionalSources = new ArrayList<>(); @@ -189,13 +216,14 @@ public String listOfRegisteredProperties() { .findFirst(); } + /** + * Load overrides passed in as CLI arguments. + * + * @param args List of overrides that may or may not be set + * @param err Message reporter to report attempts to set unsupported target properties. + */ public void load(GeneratorArguments args, MessageReporter err) { - this.properties - .keySet() - .forEach( - p -> { - p.update(this, args, err); - }); + args.overrides().stream().forEach(a -> a.update(this, err)); } /** @@ -303,13 +331,8 @@ public void validate(KeyValuePairs pairs, Model ast, ValidatorMessageReporter re p.checkType(pair, reporter); p.validate(pair, ast, reporter); } else { - reporter - .at(pair, Literals.KEY_VALUE_PAIR__NAME) - .warning( - String.format( - "The target property '%s' is not supported by the %s target and will" - + " thus be ignored.", - pair.getName(), this.target)); + 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()); diff --git a/core/src/main/java/org/lflang/target/property/BuildTypeProperty.java b/core/src/main/java/org/lflang/target/property/BuildTypeProperty.java index 33f31c19f9..1de0363246 100644 --- a/core/src/main/java/org/lflang/target/property/BuildTypeProperty.java +++ b/core/src/main/java/org/lflang/target/property/BuildTypeProperty.java @@ -2,7 +2,6 @@ import org.lflang.MessageReporter; import org.lflang.ast.ASTUtils; -import org.lflang.generator.GeneratorArguments; import org.lflang.lf.Element; import org.lflang.target.property.type.BuildTypeType; import org.lflang.target.property.type.BuildTypeType.BuildType; @@ -44,9 +43,4 @@ protected BuildType fromString(String string, MessageReporter reporter) { public String name() { return "build-type"; } - - @Override - public BuildType value(GeneratorArguments args) { - return args.buildType; - } } diff --git a/core/src/main/java/org/lflang/target/property/CompilerProperty.java b/core/src/main/java/org/lflang/target/property/CompilerProperty.java index efff3c23f0..f1ed1f2ebf 100644 --- a/core/src/main/java/org/lflang/target/property/CompilerProperty.java +++ b/core/src/main/java/org/lflang/target/property/CompilerProperty.java @@ -1,7 +1,5 @@ package org.lflang.target.property; -import org.lflang.generator.GeneratorArguments; - /** The compiler to invoke, unless a build command has been specified. */ public final class CompilerProperty extends StringProperty { @@ -16,9 +14,4 @@ private CompilerProperty() { public String name() { return "compiler"; } - - @Override - public String value(GeneratorArguments args) { - return args.compiler; - } } diff --git a/core/src/main/java/org/lflang/target/property/ExternalRuntimePathProperty.java b/core/src/main/java/org/lflang/target/property/ExternalRuntimePathProperty.java index 04a98e0098..14ee05b18f 100644 --- a/core/src/main/java/org/lflang/target/property/ExternalRuntimePathProperty.java +++ b/core/src/main/java/org/lflang/target/property/ExternalRuntimePathProperty.java @@ -1,8 +1,5 @@ package org.lflang.target.property; -import java.nio.file.Paths; -import org.lflang.generator.GeneratorArguments; - /** * Directive for specifying a path to an external runtime libray to link to instead of the default * one. @@ -21,11 +18,10 @@ public String name() { return "external-runtime-path"; } - @Override - public String value(GeneratorArguments args) { - if (args.externalRuntimeUri != null) { - return Paths.get(args.externalRuntimeUri).toString(); - } - return null; - } + // public String value(GeneratorArguments args) { + // if (args.externalRuntimeUri() != null) { + // return Paths.get(args.externalRuntimeUri()).toString(); + // } + // return null; + // } } diff --git a/core/src/main/java/org/lflang/target/property/HierarchicalBinProperty.java b/core/src/main/java/org/lflang/target/property/HierarchicalBinProperty.java index c18c398c7c..dbd3a1ed6f 100644 --- a/core/src/main/java/org/lflang/target/property/HierarchicalBinProperty.java +++ b/core/src/main/java/org/lflang/target/property/HierarchicalBinProperty.java @@ -1,7 +1,5 @@ package org.lflang.target.property; -import org.lflang.generator.GeneratorArguments; - /** * Whether the bin directory should have a flat or hierarchical organization. It is flat by default. */ @@ -18,9 +16,4 @@ private HierarchicalBinProperty() { public String name() { return "hierarchical-bin"; } - - @Override - public Boolean value(GeneratorArguments args) { - return args.hierarchicalBin; - } } diff --git a/core/src/main/java/org/lflang/target/property/LoggingProperty.java b/core/src/main/java/org/lflang/target/property/LoggingProperty.java index c539b82734..f47a7d7f6e 100644 --- a/core/src/main/java/org/lflang/target/property/LoggingProperty.java +++ b/core/src/main/java/org/lflang/target/property/LoggingProperty.java @@ -2,7 +2,6 @@ import org.lflang.MessageReporter; import org.lflang.ast.ASTUtils; -import org.lflang.generator.GeneratorArguments; import org.lflang.lf.Element; import org.lflang.target.property.type.LoggingType; import org.lflang.target.property.type.LoggingType.LogLevel; @@ -43,9 +42,4 @@ public Element toAstElement(LogLevel value) { public String name() { return "logging"; } - - @Override - public LogLevel value(GeneratorArguments args) { - return args.logging; - } } diff --git a/core/src/main/java/org/lflang/target/property/NoCompileProperty.java b/core/src/main/java/org/lflang/target/property/NoCompileProperty.java index 862aea76a2..906899ca92 100644 --- a/core/src/main/java/org/lflang/target/property/NoCompileProperty.java +++ b/core/src/main/java/org/lflang/target/property/NoCompileProperty.java @@ -1,7 +1,5 @@ package org.lflang.target.property; -import org.lflang.generator.GeneratorArguments; - /** If true, do not invoke the target compiler or build command. The default is false. */ public final class NoCompileProperty extends BooleanProperty { @@ -16,9 +14,4 @@ private NoCompileProperty() { public String name() { return "no-compile"; } - - @Override - public Boolean value(GeneratorArguments args) { - return args.noCompile; - } } diff --git a/core/src/main/java/org/lflang/target/property/PrintStatisticsProperty.java b/core/src/main/java/org/lflang/target/property/PrintStatisticsProperty.java index 682c49e61f..a193e25417 100644 --- a/core/src/main/java/org/lflang/target/property/PrintStatisticsProperty.java +++ b/core/src/main/java/org/lflang/target/property/PrintStatisticsProperty.java @@ -1,7 +1,5 @@ package org.lflang.target.property; -import org.lflang.generator.GeneratorArguments; - /** If true, instruct the runtime to collect and print execution statistics. */ public final class PrintStatisticsProperty extends BooleanProperty { @@ -16,9 +14,4 @@ private PrintStatisticsProperty() { public String name() { return "print-statistics"; } - - @Override - public Boolean value(GeneratorArguments args) { - return args.printStatistics; - } } diff --git a/core/src/main/java/org/lflang/target/property/RuntimeVersionProperty.java b/core/src/main/java/org/lflang/target/property/RuntimeVersionProperty.java index 320bdb7a5f..be82a06848 100644 --- a/core/src/main/java/org/lflang/target/property/RuntimeVersionProperty.java +++ b/core/src/main/java/org/lflang/target/property/RuntimeVersionProperty.java @@ -1,7 +1,5 @@ package org.lflang.target.property; -import org.lflang.generator.GeneratorArguments; - /** Directive for specifying a specific version of the reactor runtime library. */ public final class RuntimeVersionProperty extends StringProperty { @@ -16,9 +14,4 @@ private RuntimeVersionProperty() { public String name() { return "runtime-version"; } - - @Override - public String value(GeneratorArguments args) { - return args.runtimeVersion; - } } 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 8c92d73ff4..52bc48cc0b 100644 --- a/core/src/main/java/org/lflang/target/property/SchedulerProperty.java +++ b/core/src/main/java/org/lflang/target/property/SchedulerProperty.java @@ -2,7 +2,6 @@ import org.lflang.MessageReporter; import org.lflang.ast.ASTUtils; -import org.lflang.generator.GeneratorArguments; import org.lflang.lf.Element; import org.lflang.lf.KeyValuePair; import org.lflang.lf.LfPackage.Literals; @@ -82,9 +81,4 @@ public void validate(KeyValuePair pair, Model ast, MessageReporter reporter) { } } } - - @Override - public Scheduler value(GeneratorArguments args) { - return args.scheduler; - } } 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 41372dc6b8..556de91e63 100644 --- a/core/src/main/java/org/lflang/target/property/TargetProperty.java +++ b/core/src/main/java/org/lflang/target/property/TargetProperty.java @@ -1,10 +1,9 @@ package org.lflang.target.property; -import com.google.gson.JsonObject; +import com.google.gson.JsonElement; import java.util.List; import java.util.Optional; import org.lflang.MessageReporter; -import org.lflang.generator.GeneratorArguments; import org.lflang.lf.Element; import org.lflang.lf.KeyValuePair; import org.lflang.lf.LfPackage.Literals; @@ -13,7 +12,7 @@ import org.lflang.target.property.type.TargetPropertyType; /** - * A abstract base class for target properties. + * An abstract base class for target properties. * * @param The data type of the value assigned to the target property. * @author Marten Lohstroh @@ -115,15 +114,6 @@ public final void override(TargetConfig config, T value) { config.set(this, value); } - public void update(TargetConfig config, GeneratorArguments args, MessageReporter reporter) { - var value = value(args); - if (value != null) { - update(config, value); - } else if (args.jsonObject != null) { - update(config, fromJSON(args.jsonObject, reporter)); - } - } - /** * Update the given configuration using the given value. The default implementation simply assigns * the given value, overriding whatever value might have been assigned before. @@ -146,6 +136,10 @@ public final void update(TargetConfig config, Element node, MessageReporter repo this.update(config, fromAst(node, 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. * @@ -172,10 +166,12 @@ public int hashCode() { return this.getClass().getName().hashCode(); } - protected T fromJSON(JsonObject jsonObject, MessageReporter reporter) { + protected T fromJSON(JsonElement element, MessageReporter reporter) { T value = null; - if (jsonObject.has(name())) { - value = this.fromString(jsonObject.get(name()).getAsString(), reporter); + if (element.isJsonPrimitive()) { + value = this.fromString(element.getAsString(), reporter); + } else { + reporter.nowhere().error("Encountered non-primitive JSON element; no method for handling it"); } return value; } @@ -196,8 +192,4 @@ public static KeyValuePair getKeyValuePair(Model ast, TargetProperty prope assert properties.size() <= 1; return properties.size() > 0 ? properties.get(0) : null; } - - public T value(GeneratorArguments args) { - return 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 3c35049c59..a403c906a9 100644 --- a/core/src/main/java/org/lflang/target/property/TracingProperty.java +++ b/core/src/main/java/org/lflang/target/property/TracingProperty.java @@ -3,7 +3,6 @@ import java.util.Objects; import org.lflang.MessageReporter; import org.lflang.ast.ASTUtils; -import org.lflang.generator.GeneratorArguments; import org.lflang.lf.Element; import org.lflang.lf.KeyValuePair; import org.lflang.lf.KeyValuePairs; @@ -124,22 +123,12 @@ public void update(TargetConfig config, TracingOptions value) { config.set(this, value); } - @Override - public TracingOptions value(GeneratorArguments args) { - if (args.tracing != null) { - if (args.tracing) { - return new TracingOptions(true); - } - } - return null; - } - /** Settings related to tracing options. */ public static class TracingOptions { protected boolean enabled; - TracingOptions(boolean enabled) { + public TracingOptions(boolean enabled) { this.enabled = enabled; } diff --git a/core/src/main/java/org/lflang/target/property/VerifyProperty.java b/core/src/main/java/org/lflang/target/property/VerifyProperty.java index 601823c485..c86314f1c2 100644 --- a/core/src/main/java/org/lflang/target/property/VerifyProperty.java +++ b/core/src/main/java/org/lflang/target/property/VerifyProperty.java @@ -1,7 +1,5 @@ package org.lflang.target.property; -import org.lflang.generator.GeneratorArguments; - /** If true, check the generated verification model. The default is false. */ public final class VerifyProperty extends BooleanProperty { @@ -16,8 +14,4 @@ private VerifyProperty() { public String name() { return "verify"; } - - public Boolean value(GeneratorArguments args) { - return args.verify; - } } 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 b61fa21aaa..defbf97740 100644 --- a/core/src/main/java/org/lflang/target/property/WorkersProperty.java +++ b/core/src/main/java/org/lflang/target/property/WorkersProperty.java @@ -2,7 +2,6 @@ import org.lflang.MessageReporter; import org.lflang.ast.ASTUtils; -import org.lflang.generator.GeneratorArguments; import org.lflang.lf.Element; import org.lflang.target.property.type.PrimitiveType; @@ -43,9 +42,4 @@ public Element toAstElement(Integer value) { public String name() { return "workers"; } - - @Override - public Integer value(GeneratorArguments args) { - return args.workers; - } } diff --git a/core/src/main/kotlin/org/lflang/generator/ts/TSGenerator.kt b/core/src/main/kotlin/org/lflang/generator/ts/TSGenerator.kt index 61af132ba7..995bbf2a84 100644 --- a/core/src/main/kotlin/org/lflang/generator/ts/TSGenerator.kt +++ b/core/src/main/kotlin/org/lflang/generator/ts/TSGenerator.kt @@ -38,6 +38,7 @@ import org.lflang.scoping.LFGlobalScopeProvider import org.lflang.target.property.DockerProperty import org.lflang.target.property.NoCompileProperty import org.lflang.target.property.ProtobufsProperty +import org.lflang.target.property.RuntimeVersionProperty import org.lflang.util.FileUtil import java.nio.file.Files import java.nio.file.Path @@ -180,7 +181,7 @@ class TSGenerator( */ private fun updatePackageConfig(context: LFGeneratorContext) { var rtUri = context.args.externalRuntimeUri - val rtVersion = context.args.runtimeVersion + val rtVersion = context.targetConfig.get(RuntimeVersionProperty.INSTANCE) val sb = StringBuffer(""); val manifest = fileConfig.srcGenPath.resolve("package.json"); val rtRegex = Regex("(\"@lf-lang/reactor-ts\")(.+)") 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 169cfa3480..6e78ac803d 100644 --- a/core/src/test/java/org/lflang/tests/compiler/LinguaFrancaValidationTest.java +++ b/core/src/test/java/org/lflang/tests/compiler/LinguaFrancaValidationTest.java @@ -1854,8 +1854,7 @@ public void testInvalidTargetParam() throws Exception { model, LfPackage.eINSTANCE.getKeyValuePair(), null, - "The target property 'foobarbaz' is not supported by the C target and will thus be" - + " ignored."); + "The target property 'foobarbaz' is not supported by the C target and is thus ignored."); } @Test diff --git a/core/src/testFixtures/java/org/lflang/tests/TestBase.java b/core/src/testFixtures/java/org/lflang/tests/TestBase.java index 09cfc6f6c0..f9feae0fa2 100644 --- a/core/src/testFixtures/java/org/lflang/tests/TestBase.java +++ b/core/src/testFixtures/java/org/lflang/tests/TestBase.java @@ -44,6 +44,9 @@ import org.lflang.generator.LFGeneratorContext; import org.lflang.generator.MainContext; import org.lflang.target.Target; +import org.lflang.target.TargetConfig; +import org.lflang.target.property.BuildTypeProperty; +import org.lflang.target.property.LoggingProperty; import org.lflang.target.property.type.BuildTypeType.BuildType; import org.lflang.target.property.type.LoggingType.LogLevel; import org.lflang.tests.Configurators.Configurator; @@ -200,7 +203,7 @@ protected final void runTestsAndPrintResults( * @param selected A predicate that given a test category returns whether it should be included in * this test run or not. * @param configurator A procedure for configuring the tests. - * @param copy Whether or not to work on copies of tests in the test. registry. + * @param copy Whether to work on copies of tests in the test. registry. */ protected void runTestsForTargets( String description, @@ -364,24 +367,6 @@ private static void checkAndReportFailures(Set tests) { private void prepare(LFTest test, Transformer transformer, Configurator configurator) throws TestError { - var args = new GeneratorArguments(); - args.hierarchicalBin = true; - - var sysProps = System.getProperties(); - // Set the external-runtime-path property if it was specified. - if (sysProps.containsKey("runtime")) { - var rt = sysProps.get("runtime").toString(); - if (!rt.isEmpty()) { - try { - args.externalRuntimeUri = new URI(rt); - } catch (URISyntaxException e) { - throw new RuntimeException(e); - } - System.out.println("Using runtime: " + sysProps.get("runtime").toString()); - } - } else { - System.out.println("Using default runtime."); - } var resource = FileConfig.getResource(test.getSrcPath().toFile(), resourceSetProvider); if (resource.getErrors().size() > 0) { @@ -396,13 +381,12 @@ private void prepare(LFTest test, Transformer transformer, Configurator configur FileConfig.findPackageRoot(test.getSrcPath(), s -> {}) .resolve(FileConfig.DEFAULT_SRC_GEN_DIR) .toString()); - addExtraLfcArgs(args); var context = new MainContext( LFGeneratorContext.Mode.STANDALONE, CancelIndicator.NullImpl, (m, p) -> {}, - args, + getGeneratorArguments(), resource, fileAccess, fileConfig -> new DefaultMessageReporter()); @@ -417,7 +401,9 @@ private void prepare(LFTest test, Transformer transformer, Configurator configur // Reload the context because properties may have changed as part of the transformation. test.loadContext(context); - // Update the configuration using the configurator. + applyDefaultConfiguration(test.getContext().getTargetConfig()); + + // Update the configuration using the supplied configurator. if (configurator != null) { if (!configurator.configure(test.getContext().getTargetConfig())) { throw new TestError("Test configuration unsuccessful.", Result.CONFIG_FAIL); @@ -425,6 +411,40 @@ private void prepare(LFTest test, Transformer transformer, Configurator configur } } + /** Return a URI pointing to an external runtime if there is one, {@code null} otherwise. */ + private URI getExternalRuntimeUri() { + var sysProps = System.getProperties(); + URI uri = null; + // Set the external-runtime-path property if it was specified. + if (sysProps.containsKey("runtime")) { + var rt = sysProps.get("runtime").toString(); + if (!rt.isEmpty()) { + try { + uri = new URI(rt); + } catch (URISyntaxException e) { + throw new RuntimeException(e); + } + System.out.println("Using runtime: " + sysProps.get("runtime").toString()); + } + } else { + System.out.println("Using default runtime."); + } + return uri; + } + + /** Return generator arguments suitable for testing. */ + protected GeneratorArguments getGeneratorArguments() { + return new GeneratorArguments( + false, + getExternalRuntimeUri(), // Passed in as parameter to Gradle. + true, // To avoid name clashes in the bin directory. + null, + false, + false, + null, + List.of()); + } + /** Validate the given test. Throw an TestError if validation failed. */ private void validate(LFTest test) throws TestError { // Validate the resource and store issues in the test object. @@ -450,9 +470,9 @@ private void validate(LFTest test) throws TestError { } /** Override to add some LFC arguments to all runs of this test class. */ - protected void addExtraLfcArgs(GeneratorArguments args) { - args.buildType = BuildType.TEST; - args.logging = LogLevel.DEBUG; + protected void applyDefaultConfiguration(TargetConfig config) { + BuildTypeProperty.INSTANCE.override(config, BuildType.TEST); + LoggingProperty.INSTANCE.override(config, LogLevel.DEBUG); } /** From b0ba0b4643d4ca3e01c629e64431b7ace1554a44 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Thu, 2 Nov 2023 17:19:37 -0700 Subject: [PATCH 139/145] Add Argument class --- .../java/org/lflang/generator/Argument.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 core/src/main/java/org/lflang/generator/Argument.java diff --git a/core/src/main/java/org/lflang/generator/Argument.java b/core/src/main/java/org/lflang/generator/Argument.java new file mode 100644 index 0000000000..60f5117d4a --- /dev/null +++ b/core/src/main/java/org/lflang/generator/Argument.java @@ -0,0 +1,18 @@ +package org.lflang.generator; + +import org.lflang.MessageReporter; +import org.lflang.target.TargetConfig; +import org.lflang.target.property.TargetProperty; + +public record Argument(TargetProperty property, T value) { + + public void update(TargetConfig config, MessageReporter reporter) { + if (value != null) { + if (!config.forName(property.name()).isPresent()) { + config.reportUnsupportedTargetProperty(property().name(), reporter.nowhere()); + } else { + property.update(config, value); + } + } + } +} From df817eee1061c811af4fd1ef3959ceab559beac7 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Thu, 2 Nov 2023 18:26:24 -0700 Subject: [PATCH 140/145] Fix unit test --- .../org/lflang/tests/compiler/LinguaFrancaValidationTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 6e78ac803d..a29655e4de 100644 --- a/core/src/test/java/org/lflang/tests/compiler/LinguaFrancaValidationTest.java +++ b/core/src/test/java/org/lflang/tests/compiler/LinguaFrancaValidationTest.java @@ -1871,8 +1871,8 @@ public void testTargetParamNotSupportedForTarget() throws Exception { model, LfPackage.eINSTANCE.getKeyValuePair(), null, - "The target property 'cargo-features' is not supported by the Python target and will thus" - + " be ignored."); + "The target property 'cargo-features' is not supported by the Python target and is thus" + + " ignored."); } @Test From b0bc88d37acee63d8e8b5f613347f44718e76a08 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Thu, 2 Nov 2023 20:18:49 -0700 Subject: [PATCH 141/145] Update core/src/main/java/org/lflang/validation/LFValidator.java --- core/src/main/java/org/lflang/validation/LFValidator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/org/lflang/validation/LFValidator.java b/core/src/main/java/org/lflang/validation/LFValidator.java index 3a9207a3f4..4b81555710 100644 --- a/core/src/main/java/org/lflang/validation/LFValidator.java +++ b/core/src/main/java/org/lflang/validation/LFValidator.java @@ -1074,7 +1074,7 @@ public void checkTargetDecl(TargetDecl target) throws IOException { @Check(CheckType.NORMAL) public void checkTargetProperties(KeyValuePairs targetProperties) { if (targetProperties.eContainer() instanceof TargetDecl) { - // Only validate the target properties, not dictionaries that may be part of their values. + // 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()); } } From 180ee5229595a409777d0922125da34d12aed06d Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Thu, 2 Nov 2023 20:30:30 -0700 Subject: [PATCH 142/145] Cleanup --- cli/lfc/src/main/java/org/lflang/cli/Lfc.java | 24 +++----- core/src/main/java/org/lflang/FileConfig.java | 12 ++++ .../federated/generator/FedGenerator.java | 5 +- .../generator/FederateTargetConfig.java | 3 +- .../java/org/lflang/generator/Argument.java | 14 +++++ .../lflang/generator/GeneratorArguments.java | 3 +- .../org/lflang/generator/MainContext.java | 4 +- .../org/lflang/generator/c/CCompiler.java | 6 ++ .../main/java/org/lflang/target/Target.java | 2 - .../java/org/lflang/target/TargetConfig.java | 60 +++++++++++++++---- .../property/HierarchicalBinProperty.java | 19 ------ .../target/property/TargetProperty.java | 3 +- 12 files changed, 96 insertions(+), 59 deletions(-) delete mode 100644 core/src/main/java/org/lflang/target/property/HierarchicalBinProperty.java 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 c76516b002..163c1f4099 100644 --- a/cli/lfc/src/main/java/org/lflang/cli/Lfc.java +++ b/cli/lfc/src/main/java/org/lflang/cli/Lfc.java @@ -4,9 +4,7 @@ import java.net.URI; import java.nio.file.Files; import java.nio.file.Path; -import java.util.ArrayList; import java.util.List; -import java.util.Objects; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.xtext.generator.GeneratorDelegate; import org.eclipse.xtext.generator.JavaIoFileSystemAccess; @@ -19,7 +17,6 @@ import org.lflang.generator.MainContext; import org.lflang.target.property.BuildTypeProperty; import org.lflang.target.property.CompilerProperty; -import org.lflang.target.property.HierarchicalBinProperty; import org.lflang.target.property.LoggingProperty; import org.lflang.target.property.NoCompileProperty; import org.lflang.target.property.PrintStatisticsProperty; @@ -91,7 +88,7 @@ public class Lfc extends CliBase { description = "Organize the generated binaries hierarchically, reflecting the structure of the source" + " tree.") - private Boolean hierarchicalBin; + private boolean hierarchicalBin; @Option(names = "--logging", description = "The logging level to use by the generated binary.") private String logging; @@ -100,7 +97,7 @@ public class Lfc extends CliBase { names = {"-l", "--lint"}, arity = "0", description = "Enable linting of generated code.") - private Boolean lint; + private boolean lint; @Option( names = {"-n", "--no-compile"}, @@ -124,7 +121,7 @@ public class Lfc extends CliBase { names = {"-q", "--quiet"}, arity = "0", description = "Suppress output of the target compiler and other commands") - private Boolean quiet; + private boolean quiet; @Option( names = {"-r", "--rti"}, @@ -346,24 +343,17 @@ private Boolean getThreading() { /** Check the values of the commandline arguments and return them. */ public GeneratorArguments getArgs() { - List> args = new ArrayList<>(); - - if (buildType != null) { - args.add(new Argument<>(BuildTypeProperty.INSTANCE, getBuildType())); - } - return new GeneratorArguments( - Objects.requireNonNullElse(clean, false), + clean, getExternalRuntimeUri(), - Objects.requireNonNullElse(hierarchicalBin, false), + hierarchicalBin, getJsonObject(), - Objects.requireNonNullElse(lint, false), - Objects.requireNonNullElse(quiet, false), + lint, + quiet, getRtiUri(), List.of( new Argument<>(BuildTypeProperty.INSTANCE, getBuildType()), new Argument<>(CompilerProperty.INSTANCE, targetCompiler), - new Argument<>(HierarchicalBinProperty.INSTANCE, hierarchicalBin), new Argument<>(LoggingProperty.INSTANCE, getLogging()), new Argument<>(PrintStatisticsProperty.INSTANCE, printStatistics), new Argument<>(NoCompileProperty.INSTANCE, noCompile), diff --git a/core/src/main/java/org/lflang/FileConfig.java b/core/src/main/java/org/lflang/FileConfig.java index bc565870f8..5d402b1463 100644 --- a/core/src/main/java/org/lflang/FileConfig.java +++ b/core/src/main/java/org/lflang/FileConfig.java @@ -316,10 +316,22 @@ public Path getExecutable() { return binPath.resolve(name + getExecutableExtension()); } + /** + * Return a resource obtained from the given resource set provider that matches the given file. + * + * @param file The file to find a matching resource for. + * @param resourceSetProvider The resource set provider used to look up the resource. + */ public static Resource getResource(File file, Provider resourceSetProvider) { return resourceSetProvider.get().getResource(createFileURI(file.getAbsolutePath()), true); } + /** + * Return a resource obtained from the given resource set that matches the given path. + * + * @param path The path to find a matching resource for. + * @param xtextResourceSet The resource set used to look up the resource. + */ public static Resource getResource(Path path, XtextResourceSet xtextResourceSet) { return xtextResourceSet.getResource(createFileURI(path.toAbsolutePath().toString()), true); } 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 e070c68c8d..f6bbac3b3f 100644 --- a/core/src/main/java/org/lflang/federated/generator/FedGenerator.java +++ b/core/src/main/java/org/lflang/federated/generator/FedGenerator.java @@ -404,10 +404,9 @@ private void analyzeFederates(Reactor federation, LFGeneratorContext context) { rtiConfig.setHost(federation.getHost().getAddr()); } - var d = DockerProperty.INSTANCE; - var x = targetConfig.get(d); // If the federation is dockerized, use "rti" as the hostname. - if (rtiConfig.getHost().equals("localhost") && x.enabled) { + if (rtiConfig.getHost().equals("localhost") + && targetConfig.get(DockerProperty.INSTANCE).enabled) { rtiConfig.setHost("rti"); } 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 556c3988da..6fc29f7164 100644 --- a/core/src/main/java/org/lflang/federated/generator/FederateTargetConfig.java +++ b/core/src/main/java/org/lflang/federated/generator/FederateTargetConfig.java @@ -98,14 +98,13 @@ 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")) { - // FIXME: this logic doesn't really belong here. - // Also: what about other target properties that have paths? var array = LfFactory.eINSTANCE.createArray(); ASTUtils.elementToListOfStrings(pair.getValue()).stream() .map(relativePath::resolve) // assume all paths are relative diff --git a/core/src/main/java/org/lflang/generator/Argument.java b/core/src/main/java/org/lflang/generator/Argument.java index 60f5117d4a..82dc850f97 100644 --- a/core/src/main/java/org/lflang/generator/Argument.java +++ b/core/src/main/java/org/lflang/generator/Argument.java @@ -4,8 +4,22 @@ import org.lflang.target.TargetConfig; import org.lflang.target.property.TargetProperty; +/** + * A record that ties a target property to a value obtained as a parameter to a compilation run. + * + * @param property A target property. + * @param value The value to assign to it. + * @param The type of the value. + * @author Marten Lohstroh + */ public record Argument(TargetProperty property, T value) { + /** + * Update the target configuration if the value of this argument is not {@code null}. + * + * @param config The target configuration to update. + * @param reporter An error reporter to report the use of unsupported target properties. + */ public void update(TargetConfig config, MessageReporter reporter) { if (value != null) { if (!config.forName(property.name()).isPresent()) { diff --git a/core/src/main/java/org/lflang/generator/GeneratorArguments.java b/core/src/main/java/org/lflang/generator/GeneratorArguments.java index 8600804485..d44cf217d0 100644 --- a/core/src/main/java/org/lflang/generator/GeneratorArguments.java +++ b/core/src/main/java/org/lflang/generator/GeneratorArguments.java @@ -5,13 +5,14 @@ import java.util.List; /** - * Arguments to be passed from the command-line interface to the code generators. + * Arguments to be passed to a code generator. * *

* * @param clean Whether to clean before building. * @param externalRuntimeUri FIXME: change type of * org.lflang.target.property.ExternalRuntimePathProperty to URI + * @param hierarchicalBin Whether the bin directory should have a flat or hierarchical organization. * @param jsonObject Generator arguments and target properties in JSON format. * @param lint For enabling or disabling the linting of generated code. * @param quiet Whether to suppress output of the target compiler and other commands. diff --git a/core/src/main/java/org/lflang/generator/MainContext.java b/core/src/main/java/org/lflang/generator/MainContext.java index b3455b37e2..e670c5696d 100644 --- a/core/src/main/java/org/lflang/generator/MainContext.java +++ b/core/src/main/java/org/lflang/generator/MainContext.java @@ -95,9 +95,7 @@ public MainContext( fileConfig = Objects.requireNonNull( LFGenerator.createFileConfig( - resource, - FileConfig.getSrcGenRoot(fsa), - Objects.requireNonNullElse(args.hierarchicalBin(), false))); + resource, FileConfig.getSrcGenRoot(fsa), args.hierarchicalBin())); } catch (IOException e) { throw new RuntimeIOException("Error during FileConfig instantiation", e); } diff --git a/core/src/main/java/org/lflang/generator/c/CCompiler.java b/core/src/main/java/org/lflang/generator/c/CCompiler.java index 69067fc14d..8673856af8 100644 --- a/core/src/main/java/org/lflang/generator/c/CCompiler.java +++ b/core/src/main/java/org/lflang/generator/c/CCompiler.java @@ -438,6 +438,12 @@ static String getTargetFileName(String fileName, boolean cppMode, TargetConfig t return fileName + getFileExtension(cppMode, targetConfig); } + /** + * Return the file extension of the output source files. + * + * @param cppMode Whether we are building C code using a C++ compiler. + * @param targetConfig The target configuration that parameterizes the build process. + */ static String getFileExtension(boolean cppMode, TargetConfig targetConfig) { if (targetConfig.getOrDefault(PlatformProperty.INSTANCE).platform() == Platform.ARDUINO) { return ".ino"; diff --git a/core/src/main/java/org/lflang/target/Target.java b/core/src/main/java/org/lflang/target/Target.java index 98fd3179d2..eb2cedd588 100644 --- a/core/src/main/java/org/lflang/target/Target.java +++ b/core/src/main/java/org/lflang/target/Target.java @@ -44,7 +44,6 @@ import org.lflang.target.property.ExportToYamlProperty; import org.lflang.target.property.ExternalRuntimePathProperty; import org.lflang.target.property.FilesProperty; -import org.lflang.target.property.HierarchicalBinProperty; import org.lflang.target.property.KeepaliveProperty; import org.lflang.target.property.NoRuntimeValidationProperty; import org.lflang.target.property.PlatformProperty; @@ -597,7 +596,6 @@ public void initialize(TargetConfig config) { CoordinationProperty.INSTANCE, DockerProperty.INSTANCE, FilesProperty.INSTANCE, - HierarchicalBinProperty.INSTANCE, KeepaliveProperty.INSTANCE, PlatformProperty.INSTANCE, ProtobufsProperty.INSTANCE, diff --git a/core/src/main/java/org/lflang/target/TargetConfig.java b/core/src/main/java/org/lflang/target/TargetConfig.java index 671c6b8955..584b4e4694 100644 --- a/core/src/main/java/org/lflang/target/TargetConfig.java +++ b/core/src/main/java/org/lflang/target/TargetConfig.java @@ -87,6 +87,14 @@ 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 target AST node of a target declaration. + * @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); } @@ -136,6 +144,12 @@ private void load(JsonObject jsonObject, MessageReporter messageReporter) { } } + /** + * Report that a target property is not supported by the current target. + * + * @param name The name of the unsupported target property. + * @param stage2 The second stage an the error reporter through which to report the warning. + */ public void reportUnsupportedTargetProperty(String name, MessageReporter.Stage2 stage2) { stage2.warning( String.format( @@ -146,10 +160,17 @@ public void reportUnsupportedTargetProperty(String name, MessageReporter.Stage2 /** 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<>(); + /** Set of target properties that have been assigned a value */ private final Set> setProperties = new HashSet<>(); + /** + * Register target properties and assign them their initial value. + * + * @param properties The target properties to register. + */ public void register(TargetProperty... properties) { Arrays.stream(properties) .forEach(property -> this.properties.put(property, property.initialValue())); @@ -176,6 +197,15 @@ public T get(TargetProperty property) } } + /** + * Return the value currently assigned to the given target property, or its default value if none + * been set. + * + * @param property The property to get the value of + * @return The current value, or the initial value of none was assigned. + * @param The Java type of the returned value. + * @param The LF type of the returned value. + */ public T getOrDefault(TargetProperty property) { try { return get(property); @@ -192,6 +222,7 @@ public boolean isSet(TargetProperty property) { return this.setProperties.contains(property); } + /** Return the target properties that are currently registered. */ public String listOfRegisteredProperties() { return getRegisteredProperties().stream() .map(TargetProperty::toString) @@ -199,6 +230,7 @@ public String listOfRegisteredProperties() { .collect(Collectors.joining(", ")); } + /** Return the target properties that are currently registered. */ public List> getRegisteredProperties() { return this.properties.keySet().stream() .sorted(Comparator.comparing(p -> p.getClass().getName())) @@ -223,14 +255,14 @@ public String listOfRegisteredProperties() { * @param err Message reporter to report attempts to set unsupported target properties. */ public void load(GeneratorArguments args, MessageReporter err) { - args.overrides().stream().forEach(a -> a.update(this, err)); + args.overrides().forEach(a -> a.update(this, err)); } /** - * Set the configuration using the given pairs from the AST. + * Update the configuration using the given pairs from the AST. * * @param pairs AST node that holds all the target properties. - * @param err Error reporter on which property format errors will be reported + * @param err A message reporter for reporting errors and warnings. */ public void load(List pairs, MessageReporter err) { if (pairs != null) { @@ -242,13 +274,20 @@ public void load(List pairs, MessageReporter err) { var property = p.get(); property.update(this, pair.getValue(), err); } else { - err.nowhere() - .warning("Attempting to load unrecognized target property: " + pair.getName()); + reportUnsupportedTargetProperty(pair.getName(), err.nowhere()); } }); } } + /** + * Assign the given value to the given target property. + * + * @param property The target property to assign the value to. + * @param value The value to assign to the target property. + * @param The Java type of the value. + * @param The LF type of the value. + */ public void set(TargetProperty property, T value) { if (value != null) { this.setProperties.add(property); @@ -256,21 +295,20 @@ public void set(TargetProperty property, } } + /** Return a description of the current settings. */ public String settings() { var sb = new StringBuffer("Target Configuration:\n"); this.properties.keySet().stream() - .filter(p -> this.setProperties.contains(p)) + .filter(this.setProperties::contains) .forEach( - p -> { - sb.append(String.format(" - %s: %s\n", p.name(), this.get(p).toString())); - }); + p -> sb.append(String.format(" - %s: %s\n", p.name(), this.get(p).toString()))); sb.setLength(sb.length() - 1); return sb.toString(); } /** - * Extracts all properties as a list of key-value pairs from a TargetConfig. Only extracts - * properties explicitly set by user. + * Extract all properties as a list of key-value pairs from a TargetConfig. The returned list only + * includes properties that were explicitly set. * * @param config The TargetConfig to extract from. * @return The extracted properties. diff --git a/core/src/main/java/org/lflang/target/property/HierarchicalBinProperty.java b/core/src/main/java/org/lflang/target/property/HierarchicalBinProperty.java deleted file mode 100644 index dbd3a1ed6f..0000000000 --- a/core/src/main/java/org/lflang/target/property/HierarchicalBinProperty.java +++ /dev/null @@ -1,19 +0,0 @@ -package org.lflang.target.property; - -/** - * Whether the bin directory should have a flat or hierarchical organization. It is flat by default. - */ -public final class HierarchicalBinProperty extends BooleanProperty { - - /** Singleton target property instance. */ - public static final HierarchicalBinProperty INSTANCE = new HierarchicalBinProperty(); - - private HierarchicalBinProperty() { - super(); - } - - @Override - public String name() { - return "hierarchical-bin"; - } -} 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 556de91e63..1f3dc5182e 100644 --- a/core/src/main/java/org/lflang/target/property/TargetProperty.java +++ b/core/src/main/java/org/lflang/target/property/TargetProperty.java @@ -14,7 +14,8 @@ /** * An abstract base class for target properties. * - * @param The data type of the value assigned to the target property. + * @param The Java type of the value assigned to the target property. + * @param The LF type of the value assigned to the target property. * @author Marten Lohstroh */ public abstract class TargetProperty { From 2b94c5d45bd74ac0c9434f59b86b0e1985a0e620 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Thu, 2 Nov 2023 20:34:39 -0700 Subject: [PATCH 143/145] Add back tests that were accidentally deleted --- test/Rust/src/target/BuildProfileDefaultIsDev.lf | 10 ++++++++++ test/Rust/src/target/BuildProfileRelease.lf | 13 +++++++++++++ 2 files changed, 23 insertions(+) create mode 100644 test/Rust/src/target/BuildProfileDefaultIsDev.lf create mode 100644 test/Rust/src/target/BuildProfileRelease.lf diff --git a/test/Rust/src/target/BuildProfileDefaultIsDev.lf b/test/Rust/src/target/BuildProfileDefaultIsDev.lf new file mode 100644 index 0000000000..083794bdfc --- /dev/null +++ b/test/Rust/src/target/BuildProfileDefaultIsDev.lf @@ -0,0 +1,10 @@ +// Tests that the default build profile is dev. A proxy for checking this is to check that debug +// assertions are enabled. +target Rust + +main reactor { + reaction(startup) {= + assert!(cfg!(debug_assertions), "debug assertions should be enabled"); + println!("success"); + =} +} diff --git a/test/Rust/src/target/BuildProfileRelease.lf b/test/Rust/src/target/BuildProfileRelease.lf new file mode 100644 index 0000000000..0d9b607270 --- /dev/null +++ b/test/Rust/src/target/BuildProfileRelease.lf @@ -0,0 +1,13 @@ +// Tests that the we can enable the release profile A proxy for checking this is to check that debug +// assertions are disabled. +target Rust { + build-type: "Release" + } + + main reactor { + reaction(startup) {= + assert!(!cfg!(debug_assertions), "debug assertions should be disabled"); + println!("success"); + =} + } + \ No newline at end of file From 335d028dcc02c78ab3476b4b7bf367583c7abae6 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Thu, 2 Nov 2023 20:35:40 -0700 Subject: [PATCH 144/145] Apply formatter --- .../org/lflang/validation/LFValidator.java | 3 ++- test/Rust/src/target/BuildProfileRelease.lf | 19 +++++++++---------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/core/src/main/java/org/lflang/validation/LFValidator.java b/core/src/main/java/org/lflang/validation/LFValidator.java index 4b81555710..def6bcc8de 100644 --- a/core/src/main/java/org/lflang/validation/LFValidator.java +++ b/core/src/main/java/org/lflang/validation/LFValidator.java @@ -1074,7 +1074,8 @@ public void checkTargetDecl(TargetDecl target) throws IOException { @Check(CheckType.NORMAL) 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. + // 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()); } } diff --git a/test/Rust/src/target/BuildProfileRelease.lf b/test/Rust/src/target/BuildProfileRelease.lf index 0d9b607270..da19c0bc79 100644 --- a/test/Rust/src/target/BuildProfileRelease.lf +++ b/test/Rust/src/target/BuildProfileRelease.lf @@ -1,13 +1,12 @@ // Tests that the we can enable the release profile A proxy for checking this is to check that debug // assertions are disabled. target Rust { - build-type: "Release" - } - - main reactor { - reaction(startup) {= - assert!(!cfg!(debug_assertions), "debug assertions should be disabled"); - println!("success"); - =} - } - \ No newline at end of file + build-type: "Release" +} + +main reactor { + reaction(startup) {= + assert!(!cfg!(debug_assertions), "debug assertions should be disabled"); + println!("success"); + =} +} From a9f60c3775f9be834379492477a0855755b2f16f Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Thu, 2 Nov 2023 21:07:32 -0700 Subject: [PATCH 145/145] Do not touch build type of tests that explicitly set it --- core/src/testFixtures/java/org/lflang/tests/TestBase.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/core/src/testFixtures/java/org/lflang/tests/TestBase.java b/core/src/testFixtures/java/org/lflang/tests/TestBase.java index f9feae0fa2..b2d5475efa 100644 --- a/core/src/testFixtures/java/org/lflang/tests/TestBase.java +++ b/core/src/testFixtures/java/org/lflang/tests/TestBase.java @@ -469,9 +469,11 @@ private void validate(LFTest test) throws TestError { } } - /** Override to add some LFC arguments to all runs of this test class. */ + /** Adjust target configuration for all runs of this test class. */ protected void applyDefaultConfiguration(TargetConfig config) { - BuildTypeProperty.INSTANCE.override(config, BuildType.TEST); + if (!config.isSet(BuildTypeProperty.INSTANCE)) { + config.set(BuildTypeProperty.INSTANCE, BuildType.TEST); + } LoggingProperty.INSTANCE.override(config, LogLevel.DEBUG); }