From 51dfffe4f8215aaf82e90706f418a1642e66fa4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Thu, 3 Jun 2021 17:21:38 +0200 Subject: [PATCH 001/252] Add rust generator --- org.lflang/src/org/lflang/Target.java | 11 +- .../lflang/generator/rust/RustGenerator.kt | 104 ++++++++++++++++++ 2 files changed, 114 insertions(+), 1 deletion(-) create mode 100644 org.lflang/src/org/lflang/generator/rust/RustGenerator.kt diff --git a/org.lflang/src/org/lflang/Target.java b/org.lflang/src/org/lflang/Target.java index d47d5c5d9f..54bf205f10 100644 --- a/org.lflang/src/org/lflang/Target.java +++ b/org.lflang/src/org/lflang/Target.java @@ -336,7 +336,16 @@ public enum Target { "_Static_assert", // (since C11) "_Thread_local" // (since C11) ) - ); + ), + Rust("Rust", true, Arrays.asList( + "as", + "fn", + "trait", + "impl", + "struct" + // todo + ) + ); /** * String representation of this target. diff --git a/org.lflang/src/org/lflang/generator/rust/RustGenerator.kt b/org.lflang/src/org/lflang/generator/rust/RustGenerator.kt new file mode 100644 index 0000000000..094b2977e5 --- /dev/null +++ b/org.lflang/src/org/lflang/generator/rust/RustGenerator.kt @@ -0,0 +1,104 @@ +package org.lflang.generator.rust + +import org.eclipse.emf.ecore.resource.Resource +import org.eclipse.xtext.generator.IFileSystemAccess2 +import org.eclipse.xtext.generator.IGeneratorContext +import org.lflang.FileConfig +import org.lflang.Target +import org.lflang.generator.GeneratorBase +import org.lflang.lf.Action +import org.lflang.lf.VarRef + +/** + * Generates Rust code + */ +class RustGenerator : GeneratorBase() { + + + override fun doGenerate(resource: Resource, fsa: IFileSystemAccess2, context: IGeneratorContext) { + super.doGenerate(resource, fsa, context) + + // stop if there are any errors found in the program by doGenerate() in GeneratorBase + if (generatorErrorsOccurred) return + + // abort if there is no main reactor + if (mainDef == null) { + println("WARNING: The given Lingua Franca program does not define a main reactor. Therefore, no code was generated.") + return + } + + generateFiles(fsa) + + if (targetConfig.noCompile || generatorErrorsOccurred) { + println("Exiting before invoking target compiler.") + } else { + invokeRustCompiler() + } + } + + + private fun invokeRustCompiler() { + // let's assume we use cargo + val outPath = fileConfig.outPath + + val buildPath = outPath.resolve("build").resolve(topLevelName) + + // make sure the build directory exists + FileConfig.createDirectories(buildPath) + + val cargoBuilder = createCommand( + "cargo", listOf("build"), + outPath, + "The Rust target requires Cargo in the path. " + + "Auto-compiling can be disabled using the \"no-compile: true\" target property.", + true + ) ?: return + + + val cargoReturnCode = executeCommand(cargoBuilder) + + if (cargoReturnCode == 0) { + println("SUCCESS (compiling generated Rust code)") + println("Generated source code is in ${fileConfig.srcGenPath}") + println("Compiled binary is in ${fileConfig.binPath}") + } else { + reportError("cargo failed with error code $cargoReturnCode") + } + } + + + + + + override fun supportsGenerics(): Boolean = true + + override fun getTargetTimeType(): String = "LogicalTime" + + override fun getTargetTagType(): String = "Tag" + + override fun getTargetTagIntervalType(): String = "Duration" + + override fun getTargetUndefinedType(): String = TODO("what's that") + + override fun getTargetFixedSizeListType(baseType: String, size: Int): String = + "[ $baseType ; $size ]" + + override fun getTargetVariableSizeListType(baseType: String): String = + "Vec<$baseType>" + + override fun getTarget(): Target = Target.Rust + + + override fun generateDelayBody(action: Action, port: VarRef): String { + TODO("Not yet implemented") + } + + override fun generateForwardBody(action: Action, port: VarRef): String { + TODO("Not yet implemented") + } + + override fun generateDelayGeneric(): String { + TODO("Not yet implemented") + } + +} From 6c1e84148188e4af75d8dee63ce23a17d77beade Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Mon, 7 Jun 2021 17:19:07 +0200 Subject: [PATCH 002/252] Update to kotlin 1.5.10 Extensions for java.nio.Path are in this release https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.io.path/java.nio.file.-path/ --- build.gradle | 2 +- pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 647e41e7d8..6a6d27f522 100644 --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,5 @@ buildscript { - ext.kotlinVersion = "1.5.0" // sync with pom.xml + ext.kotlinVersion = "1.5.10" // sync with pom.xml repositories { mavenCentral() } diff --git a/pom.xml b/pom.xml index adba8c076d..7724f2b45a 100644 --- a/pom.xml +++ b/pom.xml @@ -30,7 +30,7 @@ - 1.5.0 + 1.5.10 11 11 2.3.0 From ac1e825f5fd1de07c46838a8500d996554fa55e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Tue, 8 Jun 2021 13:24:19 +0200 Subject: [PATCH 003/252] Add rust library as project submodule --- .gitmodules | 3 +++ org.lflang/src/lib/Rust/reactor-rust | 1 + 2 files changed, 4 insertions(+) create mode 160000 org.lflang/src/lib/Rust/reactor-rust diff --git a/.gitmodules b/.gitmodules index 05a57b645d..ea5453a3be 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "xtext/org.icyphy.linguafranca/src/lib/TS/reactor-ts"] path = org.lflang/src/lib/TS/reactor-ts url = https://github.com/icyphy/reactor-ts.git +[submodule "org.lflang/src/lib/Rust/reactor-rust"] + path = org.lflang/src/lib/Rust/reactor-rust + url = git@github.com:icyphy/reactor-rust.git diff --git a/org.lflang/src/lib/Rust/reactor-rust b/org.lflang/src/lib/Rust/reactor-rust new file mode 160000 index 0000000000..09f7924c2c --- /dev/null +++ b/org.lflang/src/lib/Rust/reactor-rust @@ -0,0 +1 @@ +Subproject commit 09f7924c2c5082b3126b08faf089703f4ee45ac6 From 197e5b8dacc6056827c77bbc8caa74c6e4d40c82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Tue, 8 Jun 2021 14:03:34 +0200 Subject: [PATCH 004/252] Refresh eclipse files --- org.lflang.diagram/.classpath | 1 + org.lflang.ide/.classpath | 285 +++++++- org.lflang.ide/.project | 36 +- .../.settings/org.eclipse.jdt.core.prefs | 12 +- org.lflang.tests/.classpath | 407 ++++++++++- org.lflang.tests/.project | 36 +- .../.settings/org.eclipse.jdt.core.prefs | 12 +- org.lflang.ui/.classpath | 1 + org.lflang.web/.classpath | 474 ++++++++++++- org.lflang.web/.project | 39 +- .../.settings/org.eclipse.jdt.core.prefs | 12 +- org.lflang/.classpath | 321 ++++++++- org.lflang/.project | 36 +- .../.settings/org.eclipse.jdt.core.prefs | 658 +++++++++--------- .../generator/rust/CargoTemplate.toml.vf | 10 + .../lflang/generator/rust/RustGenerator.kt | 16 + 16 files changed, 1910 insertions(+), 446 deletions(-) create mode 100644 org.lflang/src/org/lflang/generator/rust/CargoTemplate.toml.vf diff --git a/org.lflang.diagram/.classpath b/org.lflang.diagram/.classpath index 569afe1a8b..c06807d015 100644 --- a/org.lflang.diagram/.classpath +++ b/org.lflang.diagram/.classpath @@ -2,6 +2,7 @@ + diff --git a/org.lflang.ide/.classpath b/org.lflang.ide/.classpath index 91283994da..6b2b5c6bac 100644 --- a/org.lflang.ide/.classpath +++ b/org.lflang.ide/.classpath @@ -1,26 +1,301 @@ - + - + - + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.lflang.ide/.project b/org.lflang.ide/.project index d0c289aac8..15dda3eb9a 100644 --- a/org.lflang.ide/.project +++ b/org.lflang.ide/.project @@ -2,47 +2,40 @@ org.lflang.ide - - + + + org.eclipse.xtext.ui.shared.xtextNature + org.eclipse.jdt.core.javanature + org.eclipse.pde.PluginNature + org.eclipse.buildship.core.gradleprojectnature + org.jetbrains.kotlin.core.kotlinNature + org.jetbrains.kotlin.ui.kotlinBuilder - - + org.eclipse.jdt.core.javabuilder - - + org.eclipse.xtext.ui.shared.xtextBuilder - - + org.eclipse.buildship.core.gradleprojectbuilder - - + org.eclipse.pde.ManifestBuilder - - + org.eclipse.pde.SchemaBuilder - - + - - org.eclipse.xtext.ui.shared.xtextNature - org.eclipse.jdt.core.javanature - org.eclipse.pde.PluginNature - org.eclipse.buildship.core.gradleprojectnature - org.jetbrains.kotlin.core.kotlinNature - kotlin_bin @@ -50,4 +43,5 @@ org.jetbrains.kotlin.core.filesystem:/org.lflang.ide/kotlin_bin + diff --git a/org.lflang.ide/.settings/org.eclipse.jdt.core.prefs b/org.lflang.ide/.settings/org.eclipse.jdt.core.prefs index 3056f74d3b..d9331621bb 100644 --- a/org.lflang.ide/.settings/org.eclipse.jdt.core.prefs +++ b/org.lflang.ide/.settings/org.eclipse.jdt.core.prefs @@ -1,8 +1,10 @@ -eclipse.preferences.version=1 -org.eclipse.jdt.core.builder.resourceCopyExclusionFilter=*.kt +# +#Tue Jun 08 14:03:20 CEST 2021 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled -org.eclipse.jdt.core.compiler.codegen.targetPlatform=11 -org.eclipse.jdt.core.compiler.compliance=11 org.eclipse.jdt.core.compiler.problem.assertIdentifier=error -org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.codegen.targetPlatform=11 org.eclipse.jdt.core.compiler.source=11 +eclipse.preferences.version=1 +org.eclipse.jdt.core.builder.resourceCopyExclusionFilter=*.kt +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.compliance=11 diff --git a/org.lflang.tests/.classpath b/org.lflang.tests/.classpath index 90e203fa3a..c20e5851f6 100644 --- a/org.lflang.tests/.classpath +++ b/org.lflang.tests/.classpath @@ -1,28 +1,427 @@ - + - + - + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.lflang.tests/.project b/org.lflang.tests/.project index 76b0dc0dd0..03c3b00d39 100644 --- a/org.lflang.tests/.project +++ b/org.lflang.tests/.project @@ -2,47 +2,40 @@ org.lflang.tests - - + + + org.eclipse.xtext.ui.shared.xtextNature + org.eclipse.jdt.core.javanature + org.eclipse.pde.PluginNature + org.eclipse.buildship.core.gradleprojectnature + org.jetbrains.kotlin.core.kotlinNature + org.jetbrains.kotlin.ui.kotlinBuilder - - + org.eclipse.jdt.core.javabuilder - - + org.eclipse.xtext.ui.shared.xtextBuilder - - + org.eclipse.buildship.core.gradleprojectbuilder - - + org.eclipse.pde.ManifestBuilder - - + org.eclipse.pde.SchemaBuilder - - + - - org.eclipse.xtext.ui.shared.xtextNature - org.eclipse.jdt.core.javanature - org.eclipse.pde.PluginNature - org.eclipse.buildship.core.gradleprojectnature - org.jetbrains.kotlin.core.kotlinNature - kotlin_bin @@ -50,4 +43,5 @@ org.jetbrains.kotlin.core.filesystem:/org.lflang.tests/kotlin_bin + diff --git a/org.lflang.tests/.settings/org.eclipse.jdt.core.prefs b/org.lflang.tests/.settings/org.eclipse.jdt.core.prefs index 3056f74d3b..d9331621bb 100644 --- a/org.lflang.tests/.settings/org.eclipse.jdt.core.prefs +++ b/org.lflang.tests/.settings/org.eclipse.jdt.core.prefs @@ -1,8 +1,10 @@ -eclipse.preferences.version=1 -org.eclipse.jdt.core.builder.resourceCopyExclusionFilter=*.kt +# +#Tue Jun 08 14:03:20 CEST 2021 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled -org.eclipse.jdt.core.compiler.codegen.targetPlatform=11 -org.eclipse.jdt.core.compiler.compliance=11 org.eclipse.jdt.core.compiler.problem.assertIdentifier=error -org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.codegen.targetPlatform=11 org.eclipse.jdt.core.compiler.source=11 +eclipse.preferences.version=1 +org.eclipse.jdt.core.builder.resourceCopyExclusionFilter=*.kt +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.compliance=11 diff --git a/org.lflang.ui/.classpath b/org.lflang.ui/.classpath index 9081d4f703..2ad566785e 100644 --- a/org.lflang.ui/.classpath +++ b/org.lflang.ui/.classpath @@ -1,6 +1,7 @@ + diff --git a/org.lflang.web/.classpath b/org.lflang.web/.classpath index 4609f05ef3..001093a040 100644 --- a/org.lflang.web/.classpath +++ b/org.lflang.web/.classpath @@ -1,24 +1,23 @@ - + - + - + - @@ -27,4 +26,471 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.lflang.web/.project b/org.lflang.web/.project index 8d94631494..a798c094fd 100644 --- a/org.lflang.web/.project +++ b/org.lflang.web/.project @@ -2,48 +2,42 @@ org.lflang.web - - + + + org.eclipse.jdt.core.javanature + org.eclipse.xtext.ui.shared.xtextNature + org.eclipse.wst.common.project.facet.core.nature + org.eclipse.wst.common.modulecore.ModuleCoreNature + org.eclipse.buildship.core.gradleprojectnature + org.jetbrains.kotlin.core.kotlinNature + org.eclipse.jem.workbench.JavaEMFNature + org.jetbrains.kotlin.ui.kotlinBuilder - - + org.eclipse.jdt.core.javabuilder - - + org.eclipse.xtext.ui.shared.xtextBuilder - - + org.eclipse.wst.common.project.facet.core.builder - - + org.eclipse.wst.validation.validationbuilder - - + org.eclipse.buildship.core.gradleprojectbuilder - - + - - org.eclipse.jdt.core.javanature - org.eclipse.xtext.ui.shared.xtextNature - org.eclipse.wst.common.project.facet.core.nature - org.eclipse.wst.common.modulecore.ModuleCoreNature - org.eclipse.buildship.core.gradleprojectnature - org.jetbrains.kotlin.core.kotlinNature - kotlin_bin @@ -51,4 +45,5 @@ org.jetbrains.kotlin.core.filesystem:/org.lflang.web/kotlin_bin + diff --git a/org.lflang.web/.settings/org.eclipse.jdt.core.prefs b/org.lflang.web/.settings/org.eclipse.jdt.core.prefs index 3056f74d3b..d9331621bb 100644 --- a/org.lflang.web/.settings/org.eclipse.jdt.core.prefs +++ b/org.lflang.web/.settings/org.eclipse.jdt.core.prefs @@ -1,8 +1,10 @@ -eclipse.preferences.version=1 -org.eclipse.jdt.core.builder.resourceCopyExclusionFilter=*.kt +# +#Tue Jun 08 14:03:20 CEST 2021 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled -org.eclipse.jdt.core.compiler.codegen.targetPlatform=11 -org.eclipse.jdt.core.compiler.compliance=11 org.eclipse.jdt.core.compiler.problem.assertIdentifier=error -org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.codegen.targetPlatform=11 org.eclipse.jdt.core.compiler.source=11 +eclipse.preferences.version=1 +org.eclipse.jdt.core.builder.resourceCopyExclusionFilter=*.kt +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.compliance=11 diff --git a/org.lflang/.classpath b/org.lflang/.classpath index 1b604e5af8..9758f9d611 100644 --- a/org.lflang/.classpath +++ b/org.lflang/.classpath @@ -1,25 +1,336 @@ - + - + - + + + + + + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.lflang/.project b/org.lflang/.project index 3b22ebf011..8f7f2a25fc 100644 --- a/org.lflang/.project +++ b/org.lflang/.project @@ -2,47 +2,40 @@ org.lflang - - + + + org.eclipse.xtext.ui.shared.xtextNature + org.eclipse.jdt.core.javanature + org.eclipse.pde.PluginNature + org.eclipse.buildship.core.gradleprojectnature + org.jetbrains.kotlin.core.kotlinNature + org.eclipse.jdt.core.javabuilder - - + org.eclipse.xtext.ui.shared.xtextBuilder - - + org.eclipse.buildship.core.gradleprojectbuilder - - + org.jetbrains.kotlin.ui.kotlinBuilder - - + org.eclipse.pde.ManifestBuilder - - + org.eclipse.pde.SchemaBuilder - - + - - org.eclipse.xtext.ui.shared.xtextNature - org.eclipse.jdt.core.javanature - org.eclipse.pde.PluginNature - org.eclipse.buildship.core.gradleprojectnature - org.jetbrains.kotlin.core.kotlinNature - kotlin_bin @@ -50,4 +43,5 @@ org.jetbrains.kotlin.core.filesystem:/org.lflang/kotlin_bin + diff --git a/org.lflang/.settings/org.eclipse.jdt.core.prefs b/org.lflang/.settings/org.eclipse.jdt.core.prefs index 9d92e3c736..6364ad9aff 100644 --- a/org.lflang/.settings/org.eclipse.jdt.core.prefs +++ b/org.lflang/.settings/org.eclipse.jdt.core.prefs @@ -1,363 +1,365 @@ -eclipse.preferences.version=1 -org.eclipse.jdt.core.builder.resourceCopyExclusionFilter=*.kt -org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled -org.eclipse.jdt.core.compiler.codegen.targetPlatform=11 -org.eclipse.jdt.core.compiler.compliance=11 -org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +# +#Tue Jun 08 14:03:20 CEST 2021 +org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert +org.eclipse.jdt.core.formatter.parentheses_positions_in_for_statment=common_lines +org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=true +org.eclipse.jdt.core.formatter.insert_space_after_logical_operator=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert +org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package=insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert +org.eclipse.jdt.core.formatter.parentheses_positions_in_method_invocation=common_lines +org.eclipse.jdt.core.formatter.blank_lines_after_imports=1 +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert +org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert +org.eclipse.jdt.core.formatter.parentheses_positions_in_switch_statement=common_lines +org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true +org.eclipse.jdt.core.formatter.indentation.size=4 +org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert +org.eclipse.jdt.core.formatter.parentheses_positions_in_enum_constant_declaration=common_lines +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_arrow_in_switch_default=insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert +org.eclipse.jdt.core.formatter.align_with_spaces=false +org.eclipse.jdt.core.formatter.disabling_tag=@formatter\:off +org.eclipse.jdt.core.formatter.continuation_indentation=2 +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_switch_case_expressions=do not insert +org.eclipse.jdt.core.formatter.alignment_for_enum_constants=16 +org.eclipse.jdt.core.formatter.blank_lines_before_imports=1 +org.eclipse.jdt.core.formatter.blank_lines_after_package=1 +org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert +org.eclipse.jdt.core.formatter.parentheses_positions_in_if_while_statement=common_lines +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16 +org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert +org.eclipse.jdt.core.formatter.comment.indent_root_tags=false +org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true +org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on +org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert +org.eclipse.jdt.core.formatter.comment.count_line_length_from_starting_position=true +org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert +org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16 +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_arrow_in_switch_case=insert +org.eclipse.jdt.core.formatter.wrap_before_multiplicative_operator=true +org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert +org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1 +org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method=insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert +org.eclipse.jdt.core.formatter.alignment_for_parameterized_type_references=0 +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert +org.eclipse.jdt.core.formatter.alignment_for_logical_operator=16 +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert +org.eclipse.jdt.core.formatter.keep_annotation_declaration_on_one_line=one_line_never +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_enum_constant=insert +org.eclipse.jdt.core.formatter.insert_space_after_multiplicative_operator=insert +org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled org.eclipse.jdt.core.compiler.problem.enumIdentifier=error -org.eclipse.jdt.core.compiler.source=11 -org.eclipse.jdt.core.formatter.align_assignment_statements_on_columns=false -org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines=2147483647 -org.eclipse.jdt.core.formatter.align_type_members_on_columns=false +org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert +org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true +org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line +org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert +org.eclipse.jdt.core.formatter.comment.align_tags_descriptions_grouped=true +org.eclipse.jdt.core.formatter.comment.line_length=80 +org.eclipse.jdt.core.formatter.use_on_off_tags=false +org.eclipse.jdt.core.formatter.keep_method_body_on_one_line=one_line_never +org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.keep_loop_body_block_on_one_line=one_line_never +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert +org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=false +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert +org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line +org.eclipse.jdt.core.formatter.keep_enum_constant_declaration_on_one_line=one_line_never org.eclipse.jdt.core.formatter.align_variable_declarations_on_columns=false -org.eclipse.jdt.core.formatter.align_with_spaces=false +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert +org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch=16 +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert +org.eclipse.jdt.core.formatter.keep_type_declaration_on_one_line=one_line_never +org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0 +org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=do not insert +org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false +org.eclipse.jdt.core.formatter.alignment_for_binary_expression=16 +org.eclipse.jdt.core.formatter.parentheses_positions_in_catch_clause=common_lines org.eclipse.jdt.core.formatter.alignment_for_additive_operator=16 -org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16 -org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0 -org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16 +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16 -org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16 -org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16 -org.eclipse.jdt.core.formatter.alignment_for_assignment=0 -org.eclipse.jdt.core.formatter.alignment_for_binary_expression=16 -org.eclipse.jdt.core.formatter.alignment_for_bitwise_operator=16 -org.eclipse.jdt.core.formatter.alignment_for_compact_if=16 -org.eclipse.jdt.core.formatter.alignment_for_compact_loops=16 -org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80 -org.eclipse.jdt.core.formatter.alignment_for_conditional_expression_chain=0 -org.eclipse.jdt.core.formatter.alignment_for_enum_constants=16 -org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16 -org.eclipse.jdt.core.formatter.alignment_for_expressions_in_for_loop_header=0 -org.eclipse.jdt.core.formatter.alignment_for_logical_operator=16 -org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0 -org.eclipse.jdt.core.formatter.alignment_for_module_statements=16 -org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16 +org.eclipse.jdt.core.formatter.insert_space_before_relational_operator=insert org.eclipse.jdt.core.formatter.alignment_for_multiplicative_operator=16 -org.eclipse.jdt.core.formatter.alignment_for_parameterized_type_references=0 -org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=16 -org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16 -org.eclipse.jdt.core.formatter.alignment_for_relational_operator=0 -org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=80 -org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16 -org.eclipse.jdt.core.formatter.alignment_for_shift_operator=0 -org.eclipse.jdt.core.formatter.alignment_for_string_concatenation=16 -org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16 -org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16 -org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16 -org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16 -org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16 -org.eclipse.jdt.core.formatter.alignment_for_type_arguments=0 -org.eclipse.jdt.core.formatter.alignment_for_type_parameters=0 -org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch=16 -org.eclipse.jdt.core.formatter.blank_lines_after_imports=1 -org.eclipse.jdt.core.formatter.blank_lines_after_package=1 -org.eclipse.jdt.core.formatter.blank_lines_before_field=0 -org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0 -org.eclipse.jdt.core.formatter.blank_lines_before_imports=1 -org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1 -org.eclipse.jdt.core.formatter.blank_lines_before_method=1 -org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1 -org.eclipse.jdt.core.formatter.blank_lines_before_package=0 -org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1 -org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1 -org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line -org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line -org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line +org.eclipse.jdt.core.formatter.keep_anonymous_type_declaration_on_one_line=one_line_never +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_switch_case_expressions=insert +org.eclipse.jdt.core.formatter.wrap_before_shift_operator=true +org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line -org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line -org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line -org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line org.eclipse.jdt.core.formatter.brace_position_for_lambda_body=end_of_line -org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line -org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line -org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line -org.eclipse.jdt.core.formatter.comment.align_tags_descriptions_grouped=true -org.eclipse.jdt.core.formatter.comment.align_tags_names_descriptions=false +org.eclipse.jdt.core.formatter.compact_else_if=true +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_bitwise_operator=insert +org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true +org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=16 +org.eclipse.jdt.core.formatter.alignment_for_type_parameters=0 +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16 +org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16 +org.eclipse.jdt.core.formatter.alignment_for_compact_loops=16 +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=true +org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try=insert +org.eclipse.jdt.core.formatter.keep_simple_for_body_on_same_line=false +org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false -org.eclipse.jdt.core.formatter.comment.count_line_length_from_starting_position=true -org.eclipse.jdt.core.formatter.comment.format_block_comments=true -org.eclipse.jdt.core.formatter.comment.format_header=true -org.eclipse.jdt.core.formatter.comment.format_html=true -org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true -org.eclipse.jdt.core.formatter.comment.format_line_comments=true -org.eclipse.jdt.core.formatter.comment.format_source_code=true -org.eclipse.jdt.core.formatter.comment.indent_parameter_description=false -org.eclipse.jdt.core.formatter.comment.indent_root_tags=false -org.eclipse.jdt.core.formatter.comment.indent_tag_description=false -org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert -org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=do not insert -org.eclipse.jdt.core.formatter.comment.line_length=80 -org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=true -org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true -org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=false -org.eclipse.jdt.core.formatter.compact_else_if=true -org.eclipse.jdt.core.formatter.continuation_indentation=2 -org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2 -org.eclipse.jdt.core.formatter.disabling_tag=@formatter\:off -org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on -org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false +org.eclipse.jdt.core.formatter.alignment_for_relational_operator=0 +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert +org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert +org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert +org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16 org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=true -org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true -org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true -org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true -org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true -org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true -org.eclipse.jdt.core.formatter.indent_empty_lines=false -org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true -org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true -org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true -org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=true -org.eclipse.jdt.core.formatter.indentation.size=4 -org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_enum_constant=insert -org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field=insert -org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert -org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method=insert -org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package=insert -org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert -org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type=insert -org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert -org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert -org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation=do not insert -org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert -org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert -org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert -org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=do not insert -org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=do not insert -org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert +org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1 +org.eclipse.jdt.core.formatter.parentheses_positions_in_annotation=common_lines +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert +org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert org.eclipse.jdt.core.formatter.insert_space_after_additive_operator=insert -org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert -org.eclipse.jdt.core.formatter.insert_space_after_arrow_in_switch_case=insert -org.eclipse.jdt.core.formatter.insert_space_after_arrow_in_switch_default=insert -org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert -org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert -org.eclipse.jdt.core.formatter.insert_space_after_bitwise_operator=insert -org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert -org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert -org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert +org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources=do not insert org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert -org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert -org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert -org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_string_concatenation=insert +org.eclipse.jdt.core.formatter.comment.format_line_comments=true org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_switch_case_expressions=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert -org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert -org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow=insert -org.eclipse.jdt.core.formatter.insert_space_after_logical_operator=insert -org.eclipse.jdt.core.formatter.insert_space_after_multiplicative_operator=insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert +org.eclipse.jdt.core.formatter.align_type_members_on_columns=false +org.eclipse.jdt.core.formatter.alignment_for_assignment=0 +org.eclipse.jdt.core.formatter.alignment_for_module_statements=16 +org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert +org.eclipse.jdt.core.formatter.comment.align_tags_names_descriptions=false org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert +org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16 +org.eclipse.jdt.core.formatter.keep_if_then_body_block_on_one_line=one_line_never +org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0 +org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80 +org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false +org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert +org.eclipse.jdt.core.formatter.align_assignment_statements_on_columns=false +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert +org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line +org.eclipse.jdt.core.formatter.insert_space_before_arrow_in_switch_default=insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert +org.eclipse.jdt.core.formatter.alignment_for_conditional_expression_chain=0 +org.eclipse.jdt.core.formatter.comment.format_header=true +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16 +org.eclipse.jdt.core.formatter.insert_space_before_additive_operator=insert org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert +org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0 +org.eclipse.jdt.core.formatter.join_wrapped_lines=true +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert +org.eclipse.jdt.core.formatter.wrap_before_conditional_operator=true +org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true +org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert +org.eclipse.jdt.core.formatter.alignment_for_shift_operator=0 +org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines=2147483647 +org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true +org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line +org.eclipse.jdt.core.formatter.alignment_for_bitwise_operator=16 +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert +org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=80 +org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=true +org.eclipse.jdt.core.formatter.parentheses_positions_in_try_clause=common_lines +org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16 +org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false +org.eclipse.jdt.core.compiler.source=11 org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert -org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_relational_operator=insert -org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert +org.eclipse.jdt.core.formatter.keep_code_block_on_one_line=one_line_never +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert +org.eclipse.jdt.core.formatter.tabulation.size=4 +org.eclipse.jdt.core.formatter.insert_space_after_bitwise_operator=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert +org.eclipse.jdt.core.formatter.comment.format_source_code=true +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try=do not insert org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources=insert -org.eclipse.jdt.core.formatter.insert_space_after_shift_operator=insert -org.eclipse.jdt.core.formatter.insert_space_after_string_concatenation=insert +org.eclipse.jdt.core.formatter.blank_lines_before_field=0 +org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert +org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2 +org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert +org.eclipse.jdt.core.formatter.blank_lines_before_method=1 +org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16 +org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16 +org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert +org.eclipse.jdt.core.formatter.wrap_before_assignment_operator=false +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert +org.eclipse.jdt.core.compiler.codegen.targetPlatform=11 +org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert +org.eclipse.jdt.core.formatter.comment.format_html=true +org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert +org.eclipse.jdt.core.formatter.parentheses_positions_in_method_delcaration=common_lines +org.eclipse.jdt.core.formatter.alignment_for_compact_if=16 +org.eclipse.jdt.core.formatter.keep_lambda_body_block_on_one_line=one_line_never +org.eclipse.jdt.core.formatter.indent_empty_lines=false +eclipse.preferences.version=1 +org.eclipse.jdt.core.formatter.alignment_for_type_arguments=0 +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_additive_operator=insert -org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert -org.eclipse.jdt.core.formatter.insert_space_before_arrow_in_switch_case=insert -org.eclipse.jdt.core.formatter.insert_space_before_arrow_in_switch_default=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0 +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert +org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false +org.eclipse.jdt.core.builder.resourceCopyExclusionFilter=*.kt +org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=true +org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=do not insert org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert -org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert -org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert -org.eclipse.jdt.core.formatter.insert_space_before_bitwise_operator=insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert +org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1 +org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert +org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true +org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_arrow_in_switch_case=insert org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert -org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert -org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert -org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_switch_case_expressions=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow=insert +org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert +org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1 org.eclipse.jdt.core.formatter.insert_space_before_logical_operator=insert -org.eclipse.jdt.core.formatter.insert_space_before_multiplicative_operator=insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16 +org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert +org.eclipse.jdt.core.formatter.wrap_before_bitwise_operator=true +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert +org.eclipse.jdt.core.formatter.wrap_before_relational_operator=true +org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try=do not insert org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert +org.eclipse.jdt.core.formatter.comment.format_block_comments=true +org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow=insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert +org.eclipse.jdt.core.formatter.comment.indent_tag_description=false +org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert +org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16 +org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert +org.eclipse.jdt.core.formatter.alignment_for_string_concatenation=16 +org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try=insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert -org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert -org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert -org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert +org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true +org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16 +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert +org.eclipse.jdt.core.formatter.keep_simple_while_body_on_same_line=false org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert -org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_relational_operator=insert -org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources=do not insert +org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line +org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true +org.eclipse.jdt.core.formatter.wrap_before_logical_operator=true +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert org.eclipse.jdt.core.formatter.insert_space_before_shift_operator=insert -org.eclipse.jdt.core.formatter.insert_space_before_string_concatenation=insert -org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert -org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert +org.eclipse.jdt.core.compiler.compliance=11 +org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert +org.eclipse.jdt.core.formatter.parentheses_positions_in_lambda_declaration=common_lines +org.eclipse.jdt.core.formatter.insert_space_after_shift_operator=insert org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert -org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert -org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert -org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert -org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert -org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert -org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert -org.eclipse.jdt.core.formatter.join_lines_in_comments=true -org.eclipse.jdt.core.formatter.join_wrapped_lines=true -org.eclipse.jdt.core.formatter.keep_annotation_declaration_on_one_line=one_line_never -org.eclipse.jdt.core.formatter.keep_anonymous_type_declaration_on_one_line=one_line_never -org.eclipse.jdt.core.formatter.keep_code_block_on_one_line=one_line_never -org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false -org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false -org.eclipse.jdt.core.formatter.keep_enum_constant_declaration_on_one_line=one_line_never -org.eclipse.jdt.core.formatter.keep_enum_declaration_on_one_line=one_line_never -org.eclipse.jdt.core.formatter.keep_if_then_body_block_on_one_line=one_line_never -org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false -org.eclipse.jdt.core.formatter.keep_lambda_body_block_on_one_line=one_line_never -org.eclipse.jdt.core.formatter.keep_loop_body_block_on_one_line=one_line_never -org.eclipse.jdt.core.formatter.keep_method_body_on_one_line=one_line_never +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert org.eclipse.jdt.core.formatter.keep_simple_do_while_body_on_same_line=false -org.eclipse.jdt.core.formatter.keep_simple_for_body_on_same_line=false +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert +org.eclipse.jdt.core.formatter.keep_enum_declaration_on_one_line=one_line_never +org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true +org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert +org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line +org.eclipse.jdt.core.formatter.insert_space_before_multiplicative_operator=insert +org.eclipse.jdt.core.formatter.blank_lines_before_package=0 +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert +org.eclipse.jdt.core.formatter.alignment_for_expressions_in_for_loop_header=0 +org.eclipse.jdt.core.formatter.wrap_before_additive_operator=true org.eclipse.jdt.core.formatter.keep_simple_getter_setter_on_one_line=false -org.eclipse.jdt.core.formatter.keep_simple_while_body_on_same_line=false -org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false -org.eclipse.jdt.core.formatter.keep_type_declaration_on_one_line=one_line_never -org.eclipse.jdt.core.formatter.lineSplit=80 -org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false -org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false -org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0 -org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1 -org.eclipse.jdt.core.formatter.parentheses_positions_in_annotation=common_lines -org.eclipse.jdt.core.formatter.parentheses_positions_in_catch_clause=common_lines -org.eclipse.jdt.core.formatter.parentheses_positions_in_enum_constant_declaration=common_lines -org.eclipse.jdt.core.formatter.parentheses_positions_in_for_statment=common_lines -org.eclipse.jdt.core.formatter.parentheses_positions_in_if_while_statement=common_lines -org.eclipse.jdt.core.formatter.parentheses_positions_in_lambda_declaration=common_lines -org.eclipse.jdt.core.formatter.parentheses_positions_in_method_delcaration=common_lines -org.eclipse.jdt.core.formatter.parentheses_positions_in_method_invocation=common_lines -org.eclipse.jdt.core.formatter.parentheses_positions_in_switch_statement=common_lines -org.eclipse.jdt.core.formatter.parentheses_positions_in_try_clause=common_lines -org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert +org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true +org.eclipse.jdt.core.formatter.insert_space_before_string_concatenation=insert +org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert +org.eclipse.jdt.core.formatter.join_lines_in_comments=true +org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert +org.eclipse.jdt.core.javaFormatter=org.eclipse.jdt.core.defaultJavaFormatter +org.eclipse.jdt.core.formatter.comment.indent_parameter_description=false +org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=do not insert org.eclipse.jdt.core.formatter.tabulation.char=space -org.eclipse.jdt.core.formatter.tabulation.size=4 -org.eclipse.jdt.core.formatter.use_on_off_tags=false -org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=true -org.eclipse.jdt.core.formatter.wrap_before_additive_operator=true -org.eclipse.jdt.core.formatter.wrap_before_assignment_operator=false -org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true -org.eclipse.jdt.core.formatter.wrap_before_bitwise_operator=true -org.eclipse.jdt.core.formatter.wrap_before_conditional_operator=true -org.eclipse.jdt.core.formatter.wrap_before_logical_operator=true -org.eclipse.jdt.core.formatter.wrap_before_multiplicative_operator=true -org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true -org.eclipse.jdt.core.formatter.wrap_before_relational_operator=true -org.eclipse.jdt.core.formatter.wrap_before_shift_operator=true +org.eclipse.jdt.core.formatter.insert_space_after_relational_operator=insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert org.eclipse.jdt.core.formatter.wrap_before_string_concatenation=true -org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true -org.eclipse.jdt.core.javaFormatter=org.eclipse.jdt.core.defaultJavaFormatter +org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1 +org.eclipse.jdt.core.formatter.lineSplit=80 +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert diff --git a/org.lflang/src/org/lflang/generator/rust/CargoTemplate.toml.vf b/org.lflang/src/org/lflang/generator/rust/CargoTemplate.toml.vf new file mode 100644 index 0000000000..f159272c39 --- /dev/null +++ b/org.lflang/src/org/lflang/generator/rust/CargoTemplate.toml.vf @@ -0,0 +1,10 @@ +[package] +name = "$crate.name" +version = "$crate.version" +authors = ["$crate.author0"] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +reactor-rust = { $runtime.toml_spec } diff --git a/org.lflang/src/org/lflang/generator/rust/RustGenerator.kt b/org.lflang/src/org/lflang/generator/rust/RustGenerator.kt index 094b2977e5..e0b9f9bc75 100644 --- a/org.lflang/src/org/lflang/generator/rust/RustGenerator.kt +++ b/org.lflang/src/org/lflang/generator/rust/RustGenerator.kt @@ -9,6 +9,22 @@ import org.lflang.generator.GeneratorBase import org.lflang.lf.Action import org.lflang.lf.VarRef + +class VelocityGenerator( + val templatePath: String, +) { + +} + +data class VCrateSpec( + val name: String, + val version: String, + val author: String, +) + +data class VRuntimeSpec(val toml_spec: String) + + /** * Generates Rust code */ From 799690efe34752a3604fb68b5b608d2047e68a3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Tue, 8 Jun 2021 14:04:04 +0200 Subject: [PATCH 005/252] Refresh eclipse files --- org.lflang.ide/.classpath | 6 +++--- org.lflang.ide/.settings/org.eclipse.jdt.core.prefs | 2 +- org.lflang.tests/.classpath | 8 ++++---- org.lflang.tests/.settings/org.eclipse.jdt.core.prefs | 2 +- org.lflang.web/.classpath | 6 +++--- org.lflang.web/.settings/org.eclipse.jdt.core.prefs | 2 +- org.lflang/.classpath | 6 +++--- org.lflang/.settings/org.eclipse.jdt.core.prefs | 6 +++--- 8 files changed, 19 insertions(+), 19 deletions(-) diff --git a/org.lflang.ide/.classpath b/org.lflang.ide/.classpath index 6b2b5c6bac..96113596ef 100644 --- a/org.lflang.ide/.classpath +++ b/org.lflang.ide/.classpath @@ -63,12 +63,12 @@ - + - + @@ -203,7 +203,7 @@ - + diff --git a/org.lflang.ide/.settings/org.eclipse.jdt.core.prefs b/org.lflang.ide/.settings/org.eclipse.jdt.core.prefs index d9331621bb..2e14bd4626 100644 --- a/org.lflang.ide/.settings/org.eclipse.jdt.core.prefs +++ b/org.lflang.ide/.settings/org.eclipse.jdt.core.prefs @@ -1,5 +1,5 @@ # -#Tue Jun 08 14:03:20 CEST 2021 +#Tue Jun 08 14:03:53 CEST 2021 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled org.eclipse.jdt.core.compiler.problem.assertIdentifier=error org.eclipse.jdt.core.compiler.codegen.targetPlatform=11 diff --git a/org.lflang.tests/.classpath b/org.lflang.tests/.classpath index c20e5851f6..45fc34671f 100644 --- a/org.lflang.tests/.classpath +++ b/org.lflang.tests/.classpath @@ -30,13 +30,13 @@ - + @@ -49,12 +49,12 @@ - + - + @@ -79,7 +79,7 @@ - + diff --git a/org.lflang.tests/.settings/org.eclipse.jdt.core.prefs b/org.lflang.tests/.settings/org.eclipse.jdt.core.prefs index d9331621bb..7615f132fa 100644 --- a/org.lflang.tests/.settings/org.eclipse.jdt.core.prefs +++ b/org.lflang.tests/.settings/org.eclipse.jdt.core.prefs @@ -1,5 +1,5 @@ # -#Tue Jun 08 14:03:20 CEST 2021 +#Tue Jun 08 14:03:54 CEST 2021 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled org.eclipse.jdt.core.compiler.problem.assertIdentifier=error org.eclipse.jdt.core.compiler.codegen.targetPlatform=11 diff --git a/org.lflang.web/.classpath b/org.lflang.web/.classpath index 001093a040..73406051c3 100644 --- a/org.lflang.web/.classpath +++ b/org.lflang.web/.classpath @@ -103,13 +103,13 @@ - + - + @@ -307,7 +307,7 @@ - + diff --git a/org.lflang.web/.settings/org.eclipse.jdt.core.prefs b/org.lflang.web/.settings/org.eclipse.jdt.core.prefs index d9331621bb..7615f132fa 100644 --- a/org.lflang.web/.settings/org.eclipse.jdt.core.prefs +++ b/org.lflang.web/.settings/org.eclipse.jdt.core.prefs @@ -1,5 +1,5 @@ # -#Tue Jun 08 14:03:20 CEST 2021 +#Tue Jun 08 14:03:54 CEST 2021 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled org.eclipse.jdt.core.compiler.problem.assertIdentifier=error org.eclipse.jdt.core.compiler.codegen.targetPlatform=11 diff --git a/org.lflang/.classpath b/org.lflang/.classpath index 9758f9d611..8eff6ecbd2 100644 --- a/org.lflang/.classpath +++ b/org.lflang/.classpath @@ -73,12 +73,12 @@ - + - + @@ -238,7 +238,7 @@ - + diff --git a/org.lflang/.settings/org.eclipse.jdt.core.prefs b/org.lflang/.settings/org.eclipse.jdt.core.prefs index 6364ad9aff..4c3019d1bf 100644 --- a/org.lflang/.settings/org.eclipse.jdt.core.prefs +++ b/org.lflang/.settings/org.eclipse.jdt.core.prefs @@ -1,12 +1,12 @@ # -#Tue Jun 08 14:03:20 CEST 2021 +#Tue Jun 08 14:03:53 CEST 2021 org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert org.eclipse.jdt.core.formatter.parentheses_positions_in_for_statment=common_lines -org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=true org.eclipse.jdt.core.formatter.insert_space_after_logical_operator=insert +org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=true org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=do not insert org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package=insert @@ -14,8 +14,8 @@ org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constan org.eclipse.jdt.core.formatter.parentheses_positions_in_method_invocation=common_lines org.eclipse.jdt.core.formatter.blank_lines_after_imports=1 org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert -org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert +org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert org.eclipse.jdt.core.formatter.parentheses_positions_in_switch_statement=common_lines org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true From c7fb62127f397eecf5319cda6d47bccc3ac306a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Tue, 8 Jun 2021 15:24:15 +0200 Subject: [PATCH 006/252] Split extensions file --- org.lflang/src/org/lflang/AstExtensions.kt | 42 ----------- org.lflang/src/org/lflang/CommonExtensions.kt | 71 +++++++++++++++++++ .../lflang/generator/rust/RustGenerator.kt | 32 ++++++++- 3 files changed, 100 insertions(+), 45 deletions(-) create mode 100644 org.lflang/src/org/lflang/CommonExtensions.kt diff --git a/org.lflang/src/org/lflang/AstExtensions.kt b/org.lflang/src/org/lflang/AstExtensions.kt index e267354962..7575a71e90 100644 --- a/org.lflang/src/org/lflang/AstExtensions.kt +++ b/org.lflang/src/org/lflang/AstExtensions.kt @@ -148,15 +148,6 @@ fun Delay.toText(): String = parameter?.name ?: "$interval $unit" -/** - * Remove quotation marks surrounding the specified string. - */ -fun String.withoutQuotes(): String { - val r = removeSurrounding("\"") - return if (r !== this) this else removeSurrounding("'") -} - - /** * Return a string of the form either "name" or "container.name" depending * on in which form the variable reference was given. @@ -274,39 +265,6 @@ val WidthSpec.width: Int? get() = ASTUtils.width(this, null).takeIf { it >= 0 } -// more general extensions - -/** - * Parse and return an integer from this string, much - * like [String.toIntOrNull], but allows any radix. - * - * @see Integer.decode - */ -fun String.toIntOrNullAnyRadix(): Int? = - try { - Integer.decode(this) - } catch (e: NumberFormatException) { - null - } - -/** - * Return the sublist consisting of the tail elements of this list, - * ie, everything except the first elements. This is a list view, - * and does not copy the backing buffer (if any). - * - * @throws NoSuchElementException if the list is empty - */ -fun List.tail() = subList(1, size) - -/** - * Return a pair consisting of the [List.first] element and the [tail] sublist. - * This may be used to deconstruct a list recursively, as is usual in - * functional languages. - * - * @throws NoSuchElementException if the list is empty - */ -fun List.headAndTail() = Pair(first(), tail()) - /** * Given an initialization list, return an inferred type. Only two types * can be inferred: "time" and "timeList". Return the "undefined" type if diff --git a/org.lflang/src/org/lflang/CommonExtensions.kt b/org.lflang/src/org/lflang/CommonExtensions.kt new file mode 100644 index 0000000000..2745efc07c --- /dev/null +++ b/org.lflang/src/org/lflang/CommonExtensions.kt @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2021, 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 + +/** + * Parse and return an integer from this string, much + * like [String.toIntOrNull], but allows any radix. + * + * @see Integer.decode + */ +internal fun String.toIntOrNullAnyRadix(): Int? = + try { + Integer.decode(this) + } catch (e: NumberFormatException) { + null + } + +/** + * Return the sublist consisting of the tail elements of this list, + * ie, everything except the first elements. This is a list view, + * and does not copy the backing buffer (if any). + * + * @throws NoSuchElementException if the list is empty + */ +internal fun List.tail() = subList(1, size) + +/** + * Return a pair consisting of the [List.first] element and the [tail] sublist. + * This may be used to deconstruct a list recursively, as is usual in + * functional languages. + * + * @throws NoSuchElementException if the list is empty + */ +internal fun List.headAndTail() = Pair(first(), tail()) + +/** + * Return [this] string surrounded with double quotes. + */ +internal fun String.withDQuotes() = "\"$this\"" + + +/** + * Remove quotation marks (double XOR single quotes) + * surrounding the specified string. + */ +internal fun String.withoutQuotes(): String { + val r = removeSurrounding("\"") + return if (r !== this) this else removeSurrounding("'") +} diff --git a/org.lflang/src/org/lflang/generator/rust/RustGenerator.kt b/org.lflang/src/org/lflang/generator/rust/RustGenerator.kt index e0b9f9bc75..9e01d72d01 100644 --- a/org.lflang/src/org/lflang/generator/rust/RustGenerator.kt +++ b/org.lflang/src/org/lflang/generator/rust/RustGenerator.kt @@ -8,6 +8,7 @@ import org.lflang.Target import org.lflang.generator.GeneratorBase import org.lflang.lf.Action import org.lflang.lf.VarRef +import org.lflang.withDQuotes class VelocityGenerator( @@ -16,13 +17,21 @@ class VelocityGenerator( } -data class VCrateSpec( +private data class GenerationInfo( + val crate: CrateInfo, + val runtime: RuntimeInfo, +) + +private data class CrateInfo( val name: String, val version: String, - val author: String, + val authors: List, ) -data class VRuntimeSpec(val toml_spec: String) +private data class RuntimeInfo( + val toml_spec: String, + // options, etc +) /** @@ -53,6 +62,23 @@ class RustGenerator : GeneratorBase() { } + private fun makeCargoFile(sb: StringBuilder, gen: GenerationInfo) { + val (crate, runtime) = gen + """ + |[package] + |name = "${crate.name}" + |version = "${crate.version}" + |authors = [${crate.authors.joinToString(", ") { it.withDQuotes() }}] + |edition = "2018" + + |# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + + |[dependencies] + |reactor-rust = { $runtime .toml_spec } + """.trimMargin() + } + + private fun invokeRustCompiler() { // let's assume we use cargo val outPath = fileConfig.outPath From 6739e3b1e0ea0bd58a1ca9a99ea22b82211a415e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Tue, 8 Jun 2021 16:48:04 +0200 Subject: [PATCH 007/252] Add simple emitter helper --- .../lflang/generator/rust/RustFileConfig.kt | 52 +++++++++++++++++++ .../lflang/generator/rust/RustGenerator.kt | 29 ++++++++--- 2 files changed, 75 insertions(+), 6 deletions(-) create mode 100644 org.lflang/src/org/lflang/generator/rust/RustFileConfig.kt diff --git a/org.lflang/src/org/lflang/generator/rust/RustFileConfig.kt b/org.lflang/src/org/lflang/generator/rust/RustFileConfig.kt new file mode 100644 index 0000000000..439055d291 --- /dev/null +++ b/org.lflang/src/org/lflang/generator/rust/RustFileConfig.kt @@ -0,0 +1,52 @@ +package org.lflang.generator.rust + +import org.eclipse.emf.ecore.resource.Resource +import org.eclipse.xtext.generator.IFileSystemAccess2 +import org.eclipse.xtext.generator.IGeneratorContext +import org.lflang.FileConfig +import org.lflang.generator.cpp.name +import org.lflang.lf.Reactor +import java.io.Closeable +import java.io.IOException +import java.nio.file.Path + +class RustFileConfig(resource: Resource, fsa: IFileSystemAccess2, context: IGeneratorContext) : + FileConfig(resource, fsa, context) { + + /** + * Clean any artifacts produced by the C++ code generator. + */ + @Throws(IOException::class) + override fun doClean() { + super.doClean() + deleteDirectory(outPath.resolve("target")) + } + + /** Relative path to the directory where all source files for this resource should be generated in. */ + private fun getGenDir(r: Resource): Path = getDirectory(r).resolve(r.name) + + fun emit(p: Path, f:Emitter.()-> Unit) = Emitter(p) + fun emit(pathRelativeToOutDir: String) = emit(srcGenPath.resolve(pathRelativeToOutDir)) + + + /** Path to the source file corresponding to this reactor (needed for non generic reactors) */ + fun getReactorSourcePath(r: Reactor): Path = getGenDir(r.eResource()).resolve("${r.name}.cc") +} + +class Emitter( + private val output: Path, +) : Closeable { + + private val sb = StringBuilder() + + operator fun plusAssign(s: String) { + sb.append(s) + } + + override fun close() { + output.toFile().bufferedWriter().use { + it.write(sb.toString()) + } + } +} + diff --git a/org.lflang/src/org/lflang/generator/rust/RustGenerator.kt b/org.lflang/src/org/lflang/generator/rust/RustGenerator.kt index 9e01d72d01..d5632f6272 100644 --- a/org.lflang/src/org/lflang/generator/rust/RustGenerator.kt +++ b/org.lflang/src/org/lflang/generator/rust/RustGenerator.kt @@ -33,13 +33,11 @@ private data class RuntimeInfo( // options, etc ) - /** * Generates Rust code */ class RustGenerator : GeneratorBase() { - override fun doGenerate(resource: Resource, fsa: IFileSystemAccess2, context: IGeneratorContext) { super.doGenerate(resource, fsa, context) @@ -61,10 +59,29 @@ class RustGenerator : GeneratorBase() { } } + fun generateFiles(fsa: IFileSystemAccess2) { + val fileConfig = fileConfig as RustFileConfig + + val gen = makeGenerationInfo() + + fileConfig.emit("Cargo.toml").use { it.makeCargoFile(gen) } + fileConfig.emit("src/bin/main.rs").use { it.makeMainFile(gen) } + + } + + private fun Emitter.makeMainFile(gen:GenerationInfo) { + this += """ + | + |fn main() { + | + | + |} + """.trimIndent() + } - private fun makeCargoFile(sb: StringBuilder, gen: GenerationInfo) { + private fun Emitter.makeCargoFile(gen: GenerationInfo) { val (crate, runtime) = gen - """ + this += """ |[package] |name = "${crate.name}" |version = "${crate.version}" @@ -74,8 +91,8 @@ class RustGenerator : GeneratorBase() { |# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html |[dependencies] - |reactor-rust = { $runtime .toml_spec } - """.trimMargin() + |reactor-rust = { ${runtime.toml_spec} } + """ } From 98c7d933d5a69c279a4d9f2ce5c4b04818885c41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Wed, 9 Jun 2021 10:29:34 +0200 Subject: [PATCH 008/252] Add model classes to split design in 2 The first half creates model classes from the AST. The second half outputs code from the model classes. --- .../src/org/lflang/generator/LFGenerator.kt | 2 + .../org/lflang/generator/rust/RustEmitter.kt | 109 ++++++++++++++++++ .../lflang/generator/rust/RustFileConfig.kt | 28 ++++- .../lflang/generator/rust/RustGenerator.kt | 97 ++++++---------- .../org/lflang/generator/rust/RustModel.kt | 62 ++++++++++ 5 files changed, 234 insertions(+), 64 deletions(-) create mode 100644 org.lflang/src/org/lflang/generator/rust/RustEmitter.kt create mode 100644 org.lflang/src/org/lflang/generator/rust/RustModel.kt diff --git a/org.lflang/src/org/lflang/generator/LFGenerator.kt b/org.lflang/src/org/lflang/generator/LFGenerator.kt index 431a7ae6f0..6b84e111f2 100644 --- a/org.lflang/src/org/lflang/generator/LFGenerator.kt +++ b/org.lflang/src/org/lflang/generator/LFGenerator.kt @@ -27,6 +27,7 @@ import org.eclipse.xtext.generator.IFileSystemAccess2 import org.eclipse.xtext.generator.IGeneratorContext import org.lflang.Target import org.lflang.generator.cpp.CppGenerator +import org.lflang.generator.rust.RustGenerator import org.lflang.lf.TargetDecl import org.lflang.scoping.LFGlobalScopeProvider @@ -57,6 +58,7 @@ class LFGenerator : AbstractGenerator() { Target.CPP -> CppGenerator(scopeProvider) Target.TS -> TypeScriptGenerator() Target.Python -> PythonGenerator() + Target.Rust -> RustGenerator() } /** Returns true if some errors occurred. */ diff --git a/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt b/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt new file mode 100644 index 0000000000..317e1412da --- /dev/null +++ b/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt @@ -0,0 +1,109 @@ +/* + * 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.FileConfig +import org.lflang.Target +import org.lflang.generator.rust.RustEmitter.makeReactorModule +import org.lflang.lf.Action +import org.lflang.lf.VarRef +import org.lflang.withDQuotes + +/** + * Generates Rust code + */ +object RustEmitter { + + fun generateFiles(fileConfig: RustFileConfig, gen: GenerationInfo) { + + fileConfig.emit("Cargo.toml") { makeCargoFile(gen) } + fileConfig.emit("src/bin/main.rs") { makeMainFile(gen) } + fileConfig.emit("src/lib.rs") { makeMainFile(gen) } + for (reactor in gen.reactors) { + fileConfig.emit("src/${gen.crate.name}/${reactor.modName}.rs") { + makeReactorModule(reactor) + } + } + + } + + private fun Emitter.makeReactorModule(reactor: ReactorInfo) { + val out = this + with(reactor) { + out += """ + | + |struct $structName { + | // state vars + |} + | + | + |struct $dispatcherName { + | _impl: $structName, + | // actions & components + |} + | + | + |reaction_ids!( + | ${reactions.joinToString(", ", "enum $structName Reactions {", "}") { it.rustId } } + | ); + | + |impl ReactorDispatcher for $dispatcherName { + | type ReactionId = $reactionIdName; + | type Wrapped = $structName; + | type Params = $ctorParamTypes; + | + |} + """.trimMargin() + } + } + + private fun Emitter.makeMainFile(gen: GenerationInfo) { + this += """ + | + |fn main() { + | + | + |} + """.trimIndent() + } + + private fun Emitter.makeCargoFile(gen: GenerationInfo) { + val (crate, runtime) = gen + this += """ + |[package] + |name = "${crate.name}" + |version = "${crate.version}" + |authors = [${crate.authors.joinToString(", ") { it.withDQuotes() }}] + |edition = "2018" + + |# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + + |[dependencies] + |reactor-rust = { ${runtime.toml_spec} } + """ + } + + +} diff --git a/org.lflang/src/org/lflang/generator/rust/RustFileConfig.kt b/org.lflang/src/org/lflang/generator/rust/RustFileConfig.kt index 439055d291..b76b96f172 100644 --- a/org.lflang/src/org/lflang/generator/rust/RustFileConfig.kt +++ b/org.lflang/src/org/lflang/generator/rust/RustFileConfig.kt @@ -1,3 +1,27 @@ +/* + * 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.eclipse.emf.ecore.resource.Resource @@ -25,8 +49,8 @@ class RustFileConfig(resource: Resource, fsa: IFileSystemAccess2, context: IGene /** Relative path to the directory where all source files for this resource should be generated in. */ private fun getGenDir(r: Resource): Path = getDirectory(r).resolve(r.name) - fun emit(p: Path, f:Emitter.()-> Unit) = Emitter(p) - fun emit(pathRelativeToOutDir: String) = emit(srcGenPath.resolve(pathRelativeToOutDir)) + inline fun emit(p: Path, f: Emitter.() -> Unit) = Emitter(p).use { it.f() } + fun emit(pathRelativeToOutDir: String, f: Emitter.() -> Unit) = emit(srcGenPath.resolve(pathRelativeToOutDir), f) /** Path to the source file corresponding to this reactor (needed for non generic reactors) */ diff --git a/org.lflang/src/org/lflang/generator/rust/RustGenerator.kt b/org.lflang/src/org/lflang/generator/rust/RustGenerator.kt index d5632f6272..9834f67dbb 100644 --- a/org.lflang/src/org/lflang/generator/rust/RustGenerator.kt +++ b/org.lflang/src/org/lflang/generator/rust/RustGenerator.kt @@ -1,3 +1,27 @@ +/* + * 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.eclipse.emf.ecore.resource.Resource @@ -8,36 +32,16 @@ import org.lflang.Target import org.lflang.generator.GeneratorBase import org.lflang.lf.Action import org.lflang.lf.VarRef -import org.lflang.withDQuotes - - -class VelocityGenerator( - val templatePath: String, -) { - -} - -private data class GenerationInfo( - val crate: CrateInfo, - val runtime: RuntimeInfo, -) - -private data class CrateInfo( - val name: String, - val version: String, - val authors: List, -) - -private data class RuntimeInfo( - val toml_spec: String, - // options, etc -) /** - * Generates Rust code + * Generates Rust code. */ class RustGenerator : GeneratorBase() { + override fun setFileConfig(resource: Resource, fsa: IFileSystemAccess2, context: IGeneratorContext) { + super.fileConfig = RustFileConfig(resource, fsa, context) + } + override fun doGenerate(resource: Resource, fsa: IFileSystemAccess2, context: IGeneratorContext) { super.doGenerate(resource, fsa, context) @@ -50,7 +54,8 @@ class RustGenerator : GeneratorBase() { return } - generateFiles(fsa) + val gen = makeGenerationInfo() + RustEmitter.generateFiles(fileConfig as RustFileConfig, gen) if (targetConfig.noCompile || generatorErrorsOccurred) { println("Exiting before invoking target compiler.") @@ -59,42 +64,6 @@ class RustGenerator : GeneratorBase() { } } - fun generateFiles(fsa: IFileSystemAccess2) { - val fileConfig = fileConfig as RustFileConfig - - val gen = makeGenerationInfo() - - fileConfig.emit("Cargo.toml").use { it.makeCargoFile(gen) } - fileConfig.emit("src/bin/main.rs").use { it.makeMainFile(gen) } - - } - - private fun Emitter.makeMainFile(gen:GenerationInfo) { - this += """ - | - |fn main() { - | - | - |} - """.trimIndent() - } - - private fun Emitter.makeCargoFile(gen: GenerationInfo) { - val (crate, runtime) = gen - this += """ - |[package] - |name = "${crate.name}" - |version = "${crate.version}" - |authors = [${crate.authors.joinToString(", ") { it.withDQuotes() }}] - |edition = "2018" - - |# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - - |[dependencies] - |reactor-rust = { ${runtime.toml_spec} } - """ - } - private fun invokeRustCompiler() { // let's assume we use cargo @@ -161,3 +130,7 @@ class RustGenerator : GeneratorBase() { } } + +private fun makeGenerationInfo(): GenerationInfo { + +} diff --git a/org.lflang/src/org/lflang/generator/rust/RustModel.kt b/org.lflang/src/org/lflang/generator/rust/RustModel.kt new file mode 100644 index 0000000000..40cb4e44e6 --- /dev/null +++ b/org.lflang/src/org/lflang/generator/rust/RustModel.kt @@ -0,0 +1,62 @@ +/* + * 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 java.util.Locale + +/* + + */ + + +data class GenerationInfo( + val crate: CrateInfo, + val runtime: RuntimeInfo, + val reactors: List, + val mainReactor: ReactorInfo // it's also in the list +) + +data class ReactorInfo(val lfName: String, val reactions: List) { + val modName = lfName.lowercase(Locale.ROOT) + val structName = lfName + val dispatcherName = "${structName}Dispatcher" +} + +data class ReactionInfo( + val idx: Int, + val rustId: String = "r$idx", +) + +data class CrateInfo( + val name: String, + val version: String, + val authors: List, +) + +data class RuntimeInfo( + val toml_spec: String, + // options, etc +) From f62e8d15d5813a51daa48b1f79bf7c42190ac350 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Wed, 9 Jun 2021 11:05:58 +0200 Subject: [PATCH 009/252] Flesh out emitter --- org.lflang/src/org/lflang/CommonExtensions.kt | 6 + .../org/lflang/generator/rust/RustEmitter.kt | 118 +++++++++++++----- .../org/lflang/generator/rust/RustModel.kt | 32 ++++- 3 files changed, 124 insertions(+), 32 deletions(-) diff --git a/org.lflang/src/org/lflang/CommonExtensions.kt b/org.lflang/src/org/lflang/CommonExtensions.kt index 2745efc07c..a0422374fe 100644 --- a/org.lflang/src/org/lflang/CommonExtensions.kt +++ b/org.lflang/src/org/lflang/CommonExtensions.kt @@ -69,3 +69,9 @@ internal fun String.withoutQuotes(): String { val r = removeSurrounding("\"") return if (r !== this) this else removeSurrounding("'") } + +/** + * Join this list into a comma-separated string. The toString + * of members is used. Space must be irrelevant. + */ +internal fun List.joinWithCommas() = joinToString(", ") { it } diff --git a/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt b/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt index 317e1412da..aaa72e06eb 100644 --- a/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt +++ b/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt @@ -24,17 +24,16 @@ package org.lflang.generator.rust -import org.lflang.FileConfig -import org.lflang.Target -import org.lflang.generator.rust.RustEmitter.makeReactorModule -import org.lflang.lf.Action -import org.lflang.lf.VarRef +import org.lflang.generator.cpp.prependOperator +import org.lflang.generator.rust.RustEmitter.rsLibPath +import org.lflang.joinWithCommas import org.lflang.withDQuotes /** * Generates Rust code */ object RustEmitter { + const val rsLibPath = "reactorlib" fun generateFiles(fileConfig: RustFileConfig, gen: GenerationInfo) { @@ -52,30 +51,63 @@ object RustEmitter { private fun Emitter.makeReactorModule(reactor: ReactorInfo) { val out = this with(reactor) { - out += """ - | - |struct $structName { - | // state vars - |} - | - | - |struct $dispatcherName { - | _impl: $structName, - | // actions & components - |} - | - | - |reaction_ids!( - | ${reactions.joinToString(", ", "enum $structName Reactions {", "}") { it.rustId } } - | ); - | - |impl ReactorDispatcher for $dispatcherName { - | type ReactionId = $reactionIdName; - | type Wrapped = $structName; - | type Params = $ctorParamTypes; - | - |} + with(ReactorComponentEmitter) { + with(prependOperator) { + out += """ + | + |struct $structName { + | // TODO state vars + |} + | + | + |struct $dispatcherName { + | _impl: $structName, +${" | "..otherComponents.joinToString(",\n") { it.toStructField() }} + |} + | + | + |reaction_ids!( + | ${reactions.joinToString(", ", "enum $reactionIdName {", "}") { it.rustId }} + | ); + | + |impl $rsLibPath::ReactorDispatcher for $dispatcherName { + | type ReactionId = $reactionIdName; + | type Wrapped = $structName; + | type Params = (${ctorParamTypes.joinWithCommas()}); + | + | + | fn assemble(_params: Self::Params) -> Self { + | Self { + | _impl: RandomSource, +${" | "..otherComponents.joinToString(",\n") { it.toFieldInitializer() }} + | } + | } + | + | fn react(&mut self, ctx: &mut $rsLibPath::LogicalCtx, rid: Self::ReactionId) { + | match rid { +${" | "..reactionWrappers(reactor)} + | } + | } + | + | + |} """.trimMargin() + } + } + } + } + + private fun reactionWrappers(reactor: ReactorInfo): String { + + fun joinDependencies(n: ReactionInfo): String = + n.depends.joinToString(", ") { with(ReactorComponentEmitter) { it.toBorrow() } } + + return reactor.reactions.joinToString { n: ReactionInfo -> + """ + ${reactor.reactionIdName}::${n.rustId} => { + self._impl.${n.workerId}(ctx, ${joinDependencies(n)}) + } + """ } } @@ -107,3 +139,33 @@ object RustEmitter { } + + +object ReactorComponentEmitter { + + + fun ReactorComponent.toBorrow() = when (this) { + is PortData -> + if (input) "&self.$name" + else "&mut self.$name" + is ActionData -> "&self.$name" + } + + fun ReactorComponent.toType() = when (this) { + is ActionData -> + if (isLogical) "$rsLibPath::LogicalAction" + else "$rsLibPath::PhysicalAction" + is PortData -> + if (input) "$rsLibPath::InputPort<$dataType>" + else "$rsLibPath::OutputPort<$dataType>" + } + + fun ReactorComponent.toFieldInitializer() = when (this) { + is ActionData -> toType() + " (None, ${name.withDQuotes()})" + else -> "Default::default()" + } + + fun ReactorComponent.toStructField() = + "$name: ${toType()}" + +} diff --git a/org.lflang/src/org/lflang/generator/rust/RustModel.kt b/org.lflang/src/org/lflang/generator/rust/RustModel.kt index 40cb4e44e6..00a128b3b7 100644 --- a/org.lflang/src/org/lflang/generator/rust/RustModel.kt +++ b/org.lflang/src/org/lflang/generator/rust/RustModel.kt @@ -28,7 +28,7 @@ package org.lflang.generator.rust import java.util.Locale /* - + Model classes that serve as "intermediary representation" between the rust generator and emitter. */ @@ -39,17 +39,29 @@ data class GenerationInfo( val mainReactor: ReactorInfo // it's also in the list ) -data class ReactorInfo(val lfName: String, val reactions: List) { +data class ReactorInfo( + val lfName: String, + val reactions: List, + val otherComponents: List, + val ctorParamTypes: List = emptyList() +) { val modName = lfName.lowercase(Locale.ROOT) - val structName = lfName + val structName get() = lfName val dispatcherName = "${structName}Dispatcher" + val reactionIdName = "${structName}Reactions" } data class ReactionInfo( val idx: Int, - val rustId: String = "r$idx", + /** The ID of the reaction in the reaction enum. */ + val rustId: String = "R$idx", + /** The name of the worker function for this reaction. */ + val workerId: String = "react_$idx", + /** Dependencies declared by the reaction, which are served to the worker function. */ + val depends: List ) + data class CrateInfo( val name: String, val version: String, @@ -60,3 +72,15 @@ data class RuntimeInfo( val toml_spec: String, // options, etc ) + + +sealed class ReactorComponent { + abstract val name: String +} + +/** + * @property dataType A piece of target code + */ +data class PortData(override val name: String, val input: Boolean, val dataType: String) : ReactorComponent() +data class ActionData(override val name: String, val isLogical: Boolean) : ReactorComponent() + From cf9236da2e8f4d9097489a6d82b484abd6ac7f68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Wed, 9 Jun 2021 11:58:34 +0200 Subject: [PATCH 010/252] Sketch of 'IR' creation --- org.lflang/src/org/lflang/AstExtensions.kt | 12 +++++ .../org/lflang/generator/cpp/CppExtensions.kt | 5 +- .../org/lflang/generator/rust/RustEmitter.kt | 4 +- .../lflang/generator/rust/RustGenerator.kt | 48 +++++++++++++++---- .../org/lflang/generator/rust/RustModel.kt | 39 ++++++++++++++- 5 files changed, 92 insertions(+), 16 deletions(-) diff --git a/org.lflang/src/org/lflang/AstExtensions.kt b/org.lflang/src/org/lflang/AstExtensions.kt index 7575a71e90..0f4fc7d7bd 100644 --- a/org.lflang/src/org/lflang/AstExtensions.kt +++ b/org.lflang/src/org/lflang/AstExtensions.kt @@ -349,3 +349,15 @@ val StateVar.isInitialized :Boolean get() = (this.parens.size == 2) */ fun WidthSpec.getWidth(instantiations: List? = null) = ASTUtils.width(this, instantiations) + + +/** The index of a reaction in its containing reactor. */ +val Reaction.indexInContainer + get(): Int = containingReactor.reactions.lastIndexOf(this) + +/** The reactor containing a given reaction. */ +val Reaction.containingReactor get() = this.eContainer() as Reactor + +/** Returns true if this is an input port (not an output port). */ +val Port.isInput get() = this is Input + diff --git a/org.lflang/src/org/lflang/generator/cpp/CppExtensions.kt b/org.lflang/src/org/lflang/generator/cpp/CppExtensions.kt index 787aa8c2e0..f69d3ab4d4 100644 --- a/org.lflang/src/org/lflang/generator/cpp/CppExtensions.kt +++ b/org.lflang/src/org/lflang/generator/cpp/CppExtensions.kt @@ -56,10 +56,7 @@ val Resource.model: Model get() = this.allContents.asSequence().filterIsInstance /** Get the "name" a reaction is represented with in target code.*/ val Reaction.name - get(): String { - val r = this.eContainer() as Reactor - return "r" + r.reactions.lastIndexOf(this) - } + get(): String = "r$indexInContainer" /** Get a label representing the reaction. * diff --git a/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt b/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt index aaa72e06eb..7747585854 100644 --- a/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt +++ b/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt @@ -146,7 +146,7 @@ object ReactorComponentEmitter { fun ReactorComponent.toBorrow() = when (this) { is PortData -> - if (input) "&self.$name" + if (isInput) "&self.$name" else "&mut self.$name" is ActionData -> "&self.$name" } @@ -156,7 +156,7 @@ object ReactorComponentEmitter { if (isLogical) "$rsLibPath::LogicalAction" else "$rsLibPath::PhysicalAction" is PortData -> - if (input) "$rsLibPath::InputPort<$dataType>" + if (isInput) "$rsLibPath::InputPort<$dataType>" else "$rsLibPath::OutputPort<$dataType>" } diff --git a/org.lflang/src/org/lflang/generator/rust/RustGenerator.kt b/org.lflang/src/org/lflang/generator/rust/RustGenerator.kt index 9834f67dbb..b2984f5105 100644 --- a/org.lflang/src/org/lflang/generator/rust/RustGenerator.kt +++ b/org.lflang/src/org/lflang/generator/rust/RustGenerator.kt @@ -27,10 +27,12 @@ package org.lflang.generator.rust import org.eclipse.emf.ecore.resource.Resource import org.eclipse.xtext.generator.IFileSystemAccess2 import org.eclipse.xtext.generator.IGeneratorContext -import org.lflang.FileConfig +import org.lflang.* import org.lflang.Target import org.lflang.generator.GeneratorBase +import org.lflang.generator.cpp.name import org.lflang.lf.Action +import org.lflang.lf.Reaction import org.lflang.lf.VarRef /** @@ -54,7 +56,7 @@ class RustGenerator : GeneratorBase() { return } - val gen = makeGenerationInfo() + val gen = makeGenerationInfo(resource, fsa, context) RustEmitter.generateFiles(fileConfig as RustFileConfig, gen) if (targetConfig.noCompile || generatorErrorsOccurred) { @@ -64,6 +66,42 @@ class RustGenerator : GeneratorBase() { } } + private fun makeGenerationInfo(resource: Resource, fsa: IFileSystemAccess2, context: IGeneratorContext): GenerationInfo { + val reactors = makeReactorInfos() + + return GenerationInfo( + crate = CrateInfo("mycrate_todo", "0.0.0", authors = listOf("todo")), + runtime = makeRuntimeInfo(), + reactors = reactors, + mainReactor = reactors.first { it.isMain } + ) + } + + private fun makeReactorInfos() = reactors.map { reactor -> + val components = mutableMapOf() + for (component in reactor.allOutputs + reactor.allInputs + reactor.allActions) { + val irObj = ReactorComponent.from(component) ?: continue + components[irObj.name] = irObj + } + + val reactions = reactor.reactions.map { n: Reaction -> + val dependencies = (n.effects + n.sources).mapTo(LinkedHashSet()) { components[it.name]!! } + ReactionInfo(idx = n.indexInContainer, depends = dependencies, body = n.code.body) + } + + ReactorInfo( + lfName = reactor.name, + reactions = reactions, + otherComponents = components.values.toList(), + isMain = reactor.isMain + ) + } + + private fun makeRuntimeInfo(): RuntimeInfo { + // fixme + return RuntimeInfo("path: \"/home/clem/.eclipse/lingua-franca/git/lingua-franca/org.lflang/src/lib/Rust/reactor-rust\"") + } + private fun invokeRustCompiler() { // let's assume we use cargo @@ -96,8 +134,6 @@ class RustGenerator : GeneratorBase() { - - override fun supportsGenerics(): Boolean = true override fun getTargetTimeType(): String = "LogicalTime" @@ -130,7 +166,3 @@ class RustGenerator : GeneratorBase() { } } - -private fun makeGenerationInfo(): GenerationInfo { - -} diff --git a/org.lflang/src/org/lflang/generator/rust/RustModel.kt b/org.lflang/src/org/lflang/generator/rust/RustModel.kt index 00a128b3b7..54f096f3db 100644 --- a/org.lflang/src/org/lflang/generator/rust/RustModel.kt +++ b/org.lflang/src/org/lflang/generator/rust/RustModel.kt @@ -25,6 +25,11 @@ package org.lflang.generator.rust +import org.lflang.generator.cpp.isLogical +import org.lflang.generator.cpp.targetType +import org.lflang.isInput +import org.lflang.lf.* +import java.lang.UnsupportedOperationException import java.util.Locale /* @@ -42,6 +47,7 @@ data class GenerationInfo( data class ReactorInfo( val lfName: String, val reactions: List, + val isMain: Boolean, val otherComponents: List, val ctorParamTypes: List = emptyList() ) { @@ -52,13 +58,16 @@ data class ReactorInfo( } data class ReactionInfo( + /** Index in the containing reactor. */ val idx: Int, /** The ID of the reaction in the reaction enum. */ val rustId: String = "R$idx", /** The name of the worker function for this reaction. */ val workerId: String = "react_$idx", /** Dependencies declared by the reaction, which are served to the worker function. */ - val depends: List + val depends: Set, + /** Target code for the reaction body. */ + val body: String ) @@ -74,13 +83,39 @@ data class RuntimeInfo( ) +/* +TODO do we really need the following classes? + - I quite like that they are much simpler than the corresponding AST nodes (Input, Action, etc). + - Also we have control over them. AST classes are generated by Xtend. + - OTOH they're just a subset of the functionality of AST nodes for now. We could as well use them. + But this would make this "IR" a weird mix between data classes and AST nodes. + - Maybe the right data structures to use are the ReactorInstance, etc instead. But I feel like we're + generating code not for the instance tree, but for now, just generic code for each reactor (like the C++ + generator) + */ + + sealed class ReactorComponent { abstract val name: String + + companion object { + /** + * Convert an AST node for a reactor component to the corresponding dependency type. + * Since there's no reasonable common supertype we use [Variable], but maybe we should + * have another interface. + */ + fun from(v: Variable): ReactorComponent? = when (v) { + is Port -> PortData(name = v.name, isInput = v.isInput, dataType = v.targetType) + is Action -> ActionData(name = v.name, isLogical = v.isLogical) + else -> TODO("Unsupported: ${v.javaClass.simpleName} $v") + } + } } /** * @property dataType A piece of target code */ -data class PortData(override val name: String, val input: Boolean, val dataType: String) : ReactorComponent() +data class PortData(override val name: String, val isInput: Boolean, val dataType: String) : ReactorComponent() + data class ActionData(override val name: String, val isLogical: Boolean) : ReactorComponent() From d25827dd79cce7ebea0137e618617ae4c28466a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Wed, 9 Jun 2021 12:00:37 +0200 Subject: [PATCH 011/252] Add todo --- org.lflang/src/org/lflang/generator/rust/RustEmitter.kt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt b/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt index 13fe1ec365..fe51b25007 100644 --- a/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt +++ b/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt @@ -59,6 +59,11 @@ object RustEmitter { | // TODO state vars |} | + |impl $structName { + | + | // todo reaction worker functions + | + |} | |struct $dispatcherName { | _impl: $structName, From 2094bbbb1bf79a6c233630f18c4675c39ef33bc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Fri, 18 Jun 2021 15:43:49 +0200 Subject: [PATCH 012/252] Plug everything in, cargo runs --- .../src/org/lflang/generator/rust/RustEmitter.kt | 9 ++++----- .../org/lflang/generator/rust/RustFileConfig.kt | 13 ++++++++++--- .../src/org/lflang/generator/rust/RustGenerator.kt | 14 ++++---------- .../src/org/lflang/generator/rust/RustModel.kt | 2 +- 4 files changed, 19 insertions(+), 19 deletions(-) diff --git a/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt b/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt index fe51b25007..cdfe6df130 100644 --- a/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt +++ b/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt @@ -118,12 +118,11 @@ ${" | "..reactionWrappers(reactor)} private fun Emitter.makeMainFile(gen: GenerationInfo) { this += """ - | |fn main() { | | |} - """.trimIndent() + """.trimMargin() } private fun Emitter.makeCargoFile(gen: GenerationInfo) { @@ -137,9 +136,9 @@ ${" | "..reactionWrappers(reactor)} |# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - |[dependencies] - |reactor-rust = { ${runtime.toml_spec} } - """ + |[dependencies.reactor-rust] + |path = "${runtime.local_crate_path}" + """.trimMargin() } diff --git a/org.lflang/src/org/lflang/generator/rust/RustFileConfig.kt b/org.lflang/src/org/lflang/generator/rust/RustFileConfig.kt index ff7047d203..9e42678835 100644 --- a/org.lflang/src/org/lflang/generator/rust/RustFileConfig.kt +++ b/org.lflang/src/org/lflang/generator/rust/RustFileConfig.kt @@ -32,7 +32,10 @@ import org.lflang.lf.Reactor import org.lflang.name import java.io.Closeable import java.io.IOException +import java.nio.file.Files +import java.nio.file.OpenOption import java.nio.file.Path +import java.nio.file.StandardOpenOption class RustFileConfig(resource: Resource, fsa: IFileSystemAccess2, context: IGeneratorContext) : FileConfig(resource, fsa, context) { @@ -50,6 +53,8 @@ class RustFileConfig(resource: Resource, fsa: IFileSystemAccess2, context: IGene fun emit(pathRelativeToOutDir: String, f: Emitter.() -> Unit) = emit(srcGenPath.resolve(pathRelativeToOutDir), f) + val srcGenRoot: Path get() = srcGenPath + } class Emitter( @@ -63,9 +68,11 @@ class Emitter( } override fun close() { - output.toFile().bufferedWriter().use { - it.write(sb.toString()) - } + Files.createDirectories(output.parent) + Files.newBufferedWriter(output, StandardOpenOption.CREATE) + .use { + it.write(sb.toString()) + } } } diff --git a/org.lflang/src/org/lflang/generator/rust/RustGenerator.kt b/org.lflang/src/org/lflang/generator/rust/RustGenerator.kt index a29e828f98..f8dcf189aa 100644 --- a/org.lflang/src/org/lflang/generator/rust/RustGenerator.kt +++ b/org.lflang/src/org/lflang/generator/rust/RustGenerator.kt @@ -52,6 +52,8 @@ class RustGenerator(fileConfig: RustFileConfig, errorReporter: ErrorReporter) : return } + FileConfig.createDirectories(fileConfig.srcGenPath) + val gen = makeGenerationInfo(resource, fsa, context) RustEmitter.generateFiles(fileConfig as RustFileConfig, gen) @@ -95,22 +97,14 @@ class RustGenerator(fileConfig: RustFileConfig, errorReporter: ErrorReporter) : private fun makeRuntimeInfo(): RuntimeInfo { // fixme - return RuntimeInfo("path: \"/home/clem/.eclipse/lingua-franca/git/lingua-franca/org.lflang/src/lib/Rust/reactor-rust\"") + return RuntimeInfo(local_crate_path = "/home/clem/Documents/Cours/rust-reactors") } private fun invokeRustCompiler() { - // let's assume we use cargo - val outPath = fileConfig.outPath - - val buildPath = outPath.resolve("build").resolve(topLevelName) - - // make sure the build directory exists - FileConfig.createDirectories(buildPath) - val cargoBuilder = createCommand( "cargo", listOf("build"), - outPath, + fileConfig.srcGenPath, "The Rust target requires Cargo in the path. " + "Auto-compiling can be disabled using the \"no-compile: true\" target property.", true diff --git a/org.lflang/src/org/lflang/generator/rust/RustModel.kt b/org.lflang/src/org/lflang/generator/rust/RustModel.kt index 00ad3659d9..0e03fd974e 100644 --- a/org.lflang/src/org/lflang/generator/rust/RustModel.kt +++ b/org.lflang/src/org/lflang/generator/rust/RustModel.kt @@ -77,7 +77,7 @@ data class CrateInfo( ) data class RuntimeInfo( - val toml_spec: String, + val local_crate_path: String // options, etc ) From 36561fb71dead9a7f7a4f867b86442798ae91303 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Wed, 30 Jun 2021 18:05:22 +0200 Subject: [PATCH 013/252] Fix crate structure --- .../org/lflang/generator/rust/RustEmitter.kt | 64 +++++++++++++++---- 1 file changed, 52 insertions(+), 12 deletions(-) diff --git a/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt b/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt index cdfe6df130..8563907d7b 100644 --- a/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt +++ b/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt @@ -25,6 +25,7 @@ package org.lflang.generator.rust import org.lflang.generator.PrependOperator +import org.lflang.generator.rust.ReactorComponentEmitter.toBorrowedType import org.lflang.generator.rust.RustEmitter.rsLibPath import org.lflang.joinWithCommas import org.lflang.withDQuotes @@ -33,15 +34,16 @@ import org.lflang.withDQuotes * Generates Rust code */ object RustEmitter { - const val rsLibPath = "reactorlib" + const val libImport = "use reactor_rust as _rr;\n" + const val rsLibPath = "_rr" fun generateFiles(fileConfig: RustFileConfig, gen: GenerationInfo) { fileConfig.emit("Cargo.toml") { makeCargoFile(gen) } fileConfig.emit("src/bin/main.rs") { makeMainFile(gen) } - fileConfig.emit("src/lib.rs") { makeMainFile(gen) } + fileConfig.emit("src/lib.rs") { makeRootLibFile(gen) } for (reactor in gen.reactors) { - fileConfig.emit("src/${gen.crate.name}/${reactor.modName}.rs") { + fileConfig.emit("src/${reactor.modName}.rs") { makeReactorModule(reactor) } } @@ -49,11 +51,13 @@ object RustEmitter { } private fun Emitter.makeReactorModule(reactor: ReactorInfo) { - val out = this - with(reactor) { + this += with(reactor) { with(ReactorComponentEmitter) { with(PrependOperator) { - out += """ + """ + |$libImport + |use $rsLibPath::runtime::*; + |use $rsLibPath::*; | |struct $structName { | // TODO state vars @@ -62,6 +66,8 @@ object RustEmitter { |impl $structName { | | // todo reaction worker functions +${" | "..reactions.joinToString("\n\n") { it.toWorkerFunction() }} + | | |} | @@ -73,7 +79,7 @@ ${" | "..otherComponents.joinToString(",\n") { it.toStructField() | |reaction_ids!( | ${reactions.joinToString(", ", "enum $reactionIdName {", "}") { it.rustId }} - | ); + |); | |impl $rsLibPath::ReactorDispatcher for $dispatcherName { | type ReactionId = $reactionIdName; @@ -93,8 +99,6 @@ ${" | "..otherComponents.joinToString(",\n") { it.toField ${" | "..reactionWrappers(reactor)} | } | } - | - | |} """.trimMargin() } @@ -105,12 +109,15 @@ ${" | "..reactionWrappers(reactor)} private fun reactionWrappers(reactor: ReactorInfo): String { fun joinDependencies(n: ReactionInfo): String = - n.depends.joinToString(", ") { with(ReactorComponentEmitter) { it.toBorrow() } } + if (n.depends.isEmpty()) "" + else n.depends.joinToString(", ", prefix = ", ") { + with(ReactorComponentEmitter) { it.toBorrow() } + } return reactor.reactions.joinToString { n: ReactionInfo -> """ ${reactor.reactionIdName}::${n.rustId} => { - self._impl.${n.workerId}(ctx, ${joinDependencies(n)}) + self._impl.${n.workerId}(ctx${joinDependencies(n)}) } """ } @@ -118,13 +125,29 @@ ${" | "..reactionWrappers(reactor)} private fun Emitter.makeMainFile(gen: GenerationInfo) { this += """ - |fn main() { + |#[macro_use] + |extern crate ${gen.crate.name}; + | + |$libImport | + |fn main() { + | // todo | |} """.trimMargin() } + private fun Emitter.makeRootLibFile(gen: GenerationInfo) { + this += with(PrependOperator) { + """ + |//! Root of this crate + | +${" |"..gen.reactors.joinToString("\n") { "mod ${it.modName};" }} + | + """.trimMargin() + } + } + private fun Emitter.makeCargoFile(gen: GenerationInfo) { val (crate, runtime) = gen this += """ @@ -155,6 +178,10 @@ object ReactorComponentEmitter { is ActionData -> "&self.$name" } + fun ReactorComponent.toBorrowedType() = + if (this is PortData && !this.isInput) "&mut ${toType()}" + else "& ${toType()}" + fun ReactorComponent.toType() = when (this) { is ActionData -> if (isLogical) "$rsLibPath::LogicalAction" @@ -172,4 +199,17 @@ object ReactorComponentEmitter { fun ReactorComponent.toStructField() = "$name: ${toType()}" + + fun ReactionInfo.toWorkerFunction() = + """ + // todo metadata + fn ${this.workerId}(${reactionParams()}) { + ${this.body} + } + """.trimIndent() + + fun ReactionInfo.reactionParams() = + depends.joinToString(", ") { "${it.name}: ${it.toBorrowedType()}" } + + } From beb988ee6bfc3ce45cc61cb104a5e7892c4177cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Wed, 30 Jun 2021 18:40:06 +0200 Subject: [PATCH 014/252] Add minimal rust test --- test/Rust/src/Minimal.lf | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 test/Rust/src/Minimal.lf diff --git a/test/Rust/src/Minimal.lf b/test/Rust/src/Minimal.lf new file mode 100644 index 0000000000..6e21b84e1e --- /dev/null +++ b/test/Rust/src/Minimal.lf @@ -0,0 +1,7 @@ +// This is a smoke test of a minimal reactor. +target Rust; +main reactor Minimal { + reaction(startup) {= + println!("Hello World."); + =} +} From 4d40cac9184e8be618cccef6a9c4214b2bdb7953 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Mon, 5 Jul 2021 14:29:45 +0200 Subject: [PATCH 015/252] Fix overload resolution conflict --- org.lflang/src/org/lflang/FileConfig.java | 11 ++++++++--- .../org/lflang/generator/TypeScriptFileConfig.java | 2 +- .../src/org/lflang/generator/rust/RustFileConfig.kt | 6 ++---- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/org.lflang/src/org/lflang/FileConfig.java b/org.lflang/src/org/lflang/FileConfig.java index 529809e0c1..10c1a47546 100644 --- a/org.lflang/src/org/lflang/FileConfig.java +++ b/org.lflang/src/org/lflang/FileConfig.java @@ -143,7 +143,7 @@ public class FileConfig { * to the package root, then the generated sources will be put in x/y/Z * relative to srcGenBasePath. */ - protected Path srcGenPath; + private Path srcGenPath; /** * The directory that denotes the root of the package to which the @@ -191,9 +191,14 @@ public FileConfig(Resource resource, IFileSystemAccess2 fsa, IGeneratorContext c this.binPath = getBinPath(this.srcPkgPath, this.srcPath, this.outPath, context); this.iResource = getIResource(resource); } - + // Getters to be overridden in derived classes. - + + protected void setSrcGenPath(Path srcGenPath) { + this.srcGenPath = srcGenPath; + } + + /** * Get the iResource corresponding to the provided resource if it can be * found. diff --git a/org.lflang/src/org/lflang/generator/TypeScriptFileConfig.java b/org.lflang/src/org/lflang/generator/TypeScriptFileConfig.java index f6a39bb7cf..d9e1e58339 100644 --- a/org.lflang/src/org/lflang/generator/TypeScriptFileConfig.java +++ b/org.lflang/src/org/lflang/generator/TypeScriptFileConfig.java @@ -12,7 +12,7 @@ public class TypeScriptFileConfig extends FileConfig { public TypeScriptFileConfig(Resource resource, IFileSystemAccess2 fsa, IGeneratorContext context) throws IOException { super(resource, fsa, context); - this.srcGenPath = this.srcGenPath.resolve("src"); + this.setSrcGenPath(this.getSrcGenPath().resolve("src")); } } diff --git a/org.lflang/src/org/lflang/generator/rust/RustFileConfig.kt b/org.lflang/src/org/lflang/generator/rust/RustFileConfig.kt index 9e42678835..2a5c7495a8 100644 --- a/org.lflang/src/org/lflang/generator/rust/RustFileConfig.kt +++ b/org.lflang/src/org/lflang/generator/rust/RustFileConfig.kt @@ -49,11 +49,9 @@ class RustFileConfig(resource: Resource, fsa: IFileSystemAccess2, context: IGene deleteDirectory(outPath.resolve("target")) } - inline fun emit(p: Path, f: Emitter.() -> Unit) = Emitter(p).use { it.f() } + inline fun emit(p: Path, f: Emitter.() -> Unit): Unit = Emitter(p).use { it.f() } - fun emit(pathRelativeToOutDir: String, f: Emitter.() -> Unit) = emit(srcGenPath.resolve(pathRelativeToOutDir), f) - - val srcGenRoot: Path get() = srcGenPath + inline fun emit(pathRelativeToOutDir: String, f: Emitter.() -> Unit): Unit = emit(srcGenPath.resolve(pathRelativeToOutDir), f) } From c134bec7ad453d0dbb63ff233241f4e5a89e0678 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Mon, 5 Jul 2021 14:37:49 +0200 Subject: [PATCH 016/252] Move documentation onto setters --- org.lflang/src/org/lflang/FileConfig.java | 93 ++++++++++------------- 1 file changed, 39 insertions(+), 54 deletions(-) diff --git a/org.lflang/src/org/lflang/FileConfig.java b/org.lflang/src/org/lflang/FileConfig.java index 10c1a47546..1b8c618bc7 100644 --- a/org.lflang/src/org/lflang/FileConfig.java +++ b/org.lflang/src/org/lflang/FileConfig.java @@ -118,58 +118,17 @@ public class FileConfig { */ public final Path srcPath; - // Protected fields. + // Private fields. See doc on getters. - /** - * The parent of the directory designated for placing generated sources into (`./src-gen` by default). Additional - * directories (such as `bin` or `build`) should be created as siblings of the directory for generated sources, - * which means that such directories should be created relative to the path assigned to this class variable. - * - * The generated source directory is specified in the IDE (Project Properties->LF->Compiler->Output Folder). When - * invoking the standalone compiler, the output path is specified directly using the `-o` or `--output-path` option. - */ - protected Path outPath; + private final Path outPath; - /** - * Path representation of srcGenRoot, the root directory for generated - * sources. - */ - protected Path srcGenBasePath; + private final Path srcGenBasePath; - /** - * The directory in which to put the generated sources. - * This takes into account the location of the source file relative to the - * package root. Specifically, if the source file is x/y/Z.lf relative - * to the package root, then the generated sources will be put in x/y/Z - * relative to srcGenBasePath. - */ private Path srcGenPath; - /** - * The directory that denotes the root of the package to which the - * generated sources belong. Even if the target language does not have a - * notion of packages, this directory groups all files associated with a - * single main reactor. - * of packages. - */ - protected Path srcGenPkgPath; - - // Protected fields. - - /** - * URI representation of the directory that is the parent of the specified - * directory in which to store generated sources. - */ - protected final URI outputRoot; + private final Path srcGenPkgPath; + - /** - * URI representation of the directory in which to store generated sources. - * This is the root, meaning that if the source file is x/y/Z.lf relative - * to the package root, then the generated sources will be put in x/y/Z - * relative to this URI. - */ - protected final URI srcGenRoot; - public FileConfig(Resource resource, IFileSystemAccess2 fsa, IGeneratorContext context) throws IOException { this.resource = resource; this.fsa = fsa; @@ -179,15 +138,14 @@ public FileConfig(Resource resource, IFileSystemAccess2 fsa, IGeneratorContext c this.srcPath = srcFile.toPath().getParent(); this.srcPkgPath = getPkgPath(resource, context); - - this.srcGenRoot = getSrcGenRoot(fsa); - this.srcGenBasePath = toPath(this.srcGenRoot); - this.outputRoot = getOutputRoot(this.srcGenRoot); + + URI srcGenRoot = getSrcGenRoot(fsa); + this.srcGenBasePath = toPath(srcGenRoot); this.name = nameWithoutExtension(this.srcFile); this.srcGenPath = getSrcGenPath(this.srcGenBasePath, this.srcPkgPath, this.srcPath, name); this.srcGenPkgPath = this.srcGenPath; - this.outPath = toPath(this.outputRoot); + this.outPath = toPath(getOutputRoot(srcGenRoot)); this.binPath = getBinPath(this.srcPkgPath, this.srcPath, this.outPath, context); this.iResource = getIResource(resource); } @@ -277,20 +235,47 @@ public static String getName(Resource r) throws IOException { public Path getDirectory(Resource r) throws IOException { return getSubPkgPath(this.srcPkgPath, toPath(r).getParent()); } - + + /** + * The parent of the directory designated for placing generated sources into (`./src-gen` by default). Additional + * directories (such as `bin` or `build`) should be created as siblings of the directory for generated sources, + * which means that such directories should be created relative to the path assigned to this class variable. + * + * The generated source directory is specified in the IDE (Project Properties->LF->Compiler->Output Folder). When + * invoking the standalone compiler, the output path is specified directly using the `-o` or `--output-path` option. + */ public Path getOutPath() { return outPath; } - + + /** + * The directory in which to put the generated sources. + * This takes into account the location of the source file relative to the + * package root. Specifically, if the source file is x/y/Z.lf relative + * to the package root, then the generated sources will be put in x/y/Z + * relative to srcGenBasePath. + */ public Path getSrcGenPath() { return srcGenPath; } - + + /** + * Path representation of srcGenRoot, the root directory for generated + * sources. This is the root, meaning that if the source file is x/y/Z.lf + * relative to the package root, then the generated sources will be put in x/y/Z + * relative to this URI. + */ public Path getSrcGenBasePath() { return srcGenBasePath; } + /** + * The directory that denotes the root of the package to which the + * generated sources belong. Even if the target language does not have a + * notion of packages, this directory groups all files associated with a + * single main reactor. + */ public Path getSrcGenPkgPath() { return srcGenPkgPath; } From 120891cb1bbd862cc6c95d149d1c740232c7140f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Tue, 6 Jul 2021 08:23:33 +0200 Subject: [PATCH 017/252] Add generated by header, use ssh for dependency --- .../org/lflang/generator/rust/RustEmitter.kt | 27 ++++++++++++------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt b/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt index 8563907d7b..85611fd480 100644 --- a/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt +++ b/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt @@ -29,13 +29,15 @@ import org.lflang.generator.rust.ReactorComponentEmitter.toBorrowedType import org.lflang.generator.rust.RustEmitter.rsLibPath import org.lflang.joinWithCommas import org.lflang.withDQuotes +import java.time.Instant +import java.util.* /** * Generates Rust code */ object RustEmitter { - const val libImport = "use reactor_rust as _rr;\n" const val rsLibPath = "_rr" + const val libImport = "use reactor_rust as $rsLibPath;\n" fun generateFiles(fileConfig: RustFileConfig, gen: GenerationInfo) { @@ -55,9 +57,8 @@ object RustEmitter { with(ReactorComponentEmitter) { with(PrependOperator) { """ + |// ${generatedByHeader()} |$libImport - |use $rsLibPath::runtime::*; - |use $rsLibPath::*; | |struct $structName { | // TODO state vars @@ -89,7 +90,7 @@ ${" | "..otherComponents.joinToString(",\n") { it.toStructField() | | fn assemble(_params: Self::Params) -> Self { | Self { - | _impl: RandomSource, + | _impl: $structName {/*todo*/}, ${" | "..otherComponents.joinToString(",\n") { it.toFieldInitializer() }} | } | } @@ -125,6 +126,7 @@ ${" | "..reactionWrappers(reactor)} private fun Emitter.makeMainFile(gen: GenerationInfo) { this += """ + |// ${generatedByHeader()} |#[macro_use] |extern crate ${gen.crate.name}; | @@ -140,6 +142,7 @@ ${" | "..reactionWrappers(reactor)} private fun Emitter.makeRootLibFile(gen: GenerationInfo) { this += with(PrependOperator) { """ + |// ${generatedByHeader()} |//! Root of this crate | ${" |"..gen.reactors.joinToString("\n") { "mod ${it.modName};" }} @@ -149,8 +152,9 @@ ${" |"..gen.reactors.joinToString("\n") { "mod ${it.modName};" }} } private fun Emitter.makeCargoFile(gen: GenerationInfo) { - val (crate, runtime) = gen + val (crate, _) = gen this += """ + |#-- ${generatedByHeader()} --# |[package] |name = "${crate.name}" |version = "${crate.version}" @@ -159,12 +163,17 @@ ${" |"..gen.reactors.joinToString("\n") { "mod ${it.modName};" }} |# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - |[dependencies.reactor-rust] - |path = "${runtime.local_crate_path}" + |[dependencies.reactor_rust] + |#-- The reactor runtime --# + |# See https://doc.rust-lang.org/cargo/appendix/git-authentication.html#ssh-authentication + |# git = "ssh://git@github.com:icyphy/reactor-rust.git" + |path = "/home/clem/Documents/Cours/rust-reactors" """.trimMargin() } + private fun generatedByHeader() = "Generated by LFC @ todo time" + } @@ -203,12 +212,12 @@ object ReactorComponentEmitter { fun ReactionInfo.toWorkerFunction() = """ // todo metadata - fn ${this.workerId}(${reactionParams()}) { + fn ${this.workerId}(&mut self, ctx: &mut _rr::LogicalCtx, ${reactionParams()}) { ${this.body} } """.trimIndent() - fun ReactionInfo.reactionParams() = + private fun ReactionInfo.reactionParams() = depends.joinToString(", ") { "${it.name}: ${it.toBorrowedType()}" } From 67b28cbb49de05d7079e55751f8e59f5742f72de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Tue, 6 Jul 2021 08:47:28 +0200 Subject: [PATCH 018/252] Move extern crate declaration --- .../org/lflang/generator/rust/RustEmitter.kt | 31 +++++++++---------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt b/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt index 85611fd480..47e93d9015 100644 --- a/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt +++ b/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt @@ -25,19 +25,19 @@ package org.lflang.generator.rust import org.lflang.generator.PrependOperator -import org.lflang.generator.rust.ReactorComponentEmitter.toBorrowedType -import org.lflang.generator.rust.RustEmitter.rsLibPath +import org.lflang.generator.rust.RustEmitter.rsRuntime import org.lflang.joinWithCommas import org.lflang.withDQuotes -import java.time.Instant -import java.util.* /** * Generates Rust code */ object RustEmitter { - const val rsLibPath = "_rr" - const val libImport = "use reactor_rust as $rsLibPath;\n" + /** + * Name given to the Rust runtime crate within generated code, + * can be used to qualify names. + */ + const val rsRuntime = "_rr" fun generateFiles(fileConfig: RustFileConfig, gen: GenerationInfo) { @@ -58,7 +58,6 @@ object RustEmitter { with(PrependOperator) { """ |// ${generatedByHeader()} - |$libImport | |struct $structName { | // TODO state vars @@ -82,7 +81,7 @@ ${" | "..otherComponents.joinToString(",\n") { it.toStructField() | ${reactions.joinToString(", ", "enum $reactionIdName {", "}") { it.rustId }} |); | - |impl $rsLibPath::ReactorDispatcher for $dispatcherName { + |impl $rsRuntime::ReactorDispatcher for $dispatcherName { | type ReactionId = $reactionIdName; | type Wrapped = $structName; | type Params = (${ctorParamTypes.joinWithCommas()}); @@ -95,7 +94,7 @@ ${" | "..otherComponents.joinToString(",\n") { it.toField | } | } | - | fn react(&mut self, ctx: &mut $rsLibPath::LogicalCtx, rid: Self::ReactionId) { + | fn react(&mut self, ctx: &mut $rsRuntime::LogicalCtx, rid: Self::ReactionId) { | match rid { ${" | "..reactionWrappers(reactor)} | } @@ -127,10 +126,6 @@ ${" | "..reactionWrappers(reactor)} private fun Emitter.makeMainFile(gen: GenerationInfo) { this += """ |// ${generatedByHeader()} - |#[macro_use] - |extern crate ${gen.crate.name}; - | - |$libImport | |fn main() { | // todo @@ -144,6 +139,8 @@ ${" | "..reactionWrappers(reactor)} """ |// ${generatedByHeader()} |//! Root of this crate + |#[macro_use] + |extern crate ${gen.crate.name} as $rsRuntime; | ${" |"..gen.reactors.joinToString("\n") { "mod ${it.modName};" }} | @@ -193,11 +190,11 @@ object ReactorComponentEmitter { fun ReactorComponent.toType() = when (this) { is ActionData -> - if (isLogical) "$rsLibPath::LogicalAction" - else "$rsLibPath::PhysicalAction" + if (isLogical) "$rsRuntime::LogicalAction" + else "$rsRuntime::PhysicalAction" is PortData -> - if (isInput) "$rsLibPath::InputPort<$dataType>" - else "$rsLibPath::OutputPort<$dataType>" + if (isInput) "$rsRuntime::InputPort<$dataType>" + else "$rsRuntime::OutputPort<$dataType>" } fun ReactorComponent.toFieldInitializer() = when (this) { From a56b5eaf57cfa1036563e31a562aee51532c7767 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Tue, 6 Jul 2021 08:56:58 +0200 Subject: [PATCH 019/252] Fix torn file write Files.newBufferedWriter apparently duplicates part of the file to write, that's because I forgot the TRUNCATE_EXISTING option I think. Files.writeString does the trick. --- .../org/lflang/generator/rust/RustEmitter.kt | 5 ++++- .../lflang/generator/rust/RustFileConfig.kt | 18 ++++++++++-------- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt b/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt index 47e93d9015..29da93eaf9 100644 --- a/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt +++ b/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt @@ -126,6 +126,9 @@ ${" | "..reactionWrappers(reactor)} private fun Emitter.makeMainFile(gen: GenerationInfo) { this += """ |// ${generatedByHeader()} + |#[allow(unused_imports)] + |#[macro_use] + |extern crate ${gen.crate.name} as $rsRuntime; | |fn main() { | // todo @@ -140,7 +143,7 @@ ${" | "..reactionWrappers(reactor)} |// ${generatedByHeader()} |//! Root of this crate |#[macro_use] - |extern crate ${gen.crate.name} as $rsRuntime; + |extern crate reactor_rust as $rsRuntime; | ${" |"..gen.reactors.joinToString("\n") { "mod ${it.modName};" }} | diff --git a/org.lflang/src/org/lflang/generator/rust/RustFileConfig.kt b/org.lflang/src/org/lflang/generator/rust/RustFileConfig.kt index 2a5c7495a8..972be000e8 100644 --- a/org.lflang/src/org/lflang/generator/rust/RustFileConfig.kt +++ b/org.lflang/src/org/lflang/generator/rust/RustFileConfig.kt @@ -28,14 +28,12 @@ import org.eclipse.emf.ecore.resource.Resource import org.eclipse.xtext.generator.IFileSystemAccess2 import org.eclipse.xtext.generator.IGeneratorContext import org.lflang.FileConfig -import org.lflang.lf.Reactor -import org.lflang.name import java.io.Closeable import java.io.IOException import java.nio.file.Files -import java.nio.file.OpenOption import java.nio.file.Path import java.nio.file.StandardOpenOption +import kotlin.system.measureTimeMillis class RustFileConfig(resource: Resource, fsa: IFileSystemAccess2, context: IGeneratorContext) : FileConfig(resource, fsa, context) { @@ -49,7 +47,14 @@ class RustFileConfig(resource: Resource, fsa: IFileSystemAccess2, context: IGene deleteDirectory(outPath.resolve("target")) } - inline fun emit(p: Path, f: Emitter.() -> Unit): Unit = Emitter(p).use { it.f() } + inline fun emit(p: Path, f: Emitter.() -> Unit) { + // todo remove println + System.err.println("Generating file ${srcGenPath.relativize(p)}...") + val milliTime = measureTimeMillis { + Emitter(p).use { it.f() } + } + System.err.println("Done in $milliTime ms.") + } inline fun emit(pathRelativeToOutDir: String, f: Emitter.() -> Unit): Unit = emit(srcGenPath.resolve(pathRelativeToOutDir), f) @@ -67,10 +72,7 @@ class Emitter( override fun close() { Files.createDirectories(output.parent) - Files.newBufferedWriter(output, StandardOpenOption.CREATE) - .use { - it.write(sb.toString()) - } + Files.writeString(output, sb) } } From 133dece9f717581f694d5b09e941cccd9a7dbe7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Tue, 6 Jul 2021 09:40:16 +0200 Subject: [PATCH 020/252] Add assembler struct --- .../org/lflang/generator/rust/RustEmitter.kt | 65 ++++++++++++++++++- .../org/lflang/generator/rust/RustModel.kt | 3 + 2 files changed, 67 insertions(+), 1 deletion(-) diff --git a/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt b/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt index 29da93eaf9..8c38899188 100644 --- a/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt +++ b/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt @@ -58,6 +58,7 @@ object RustEmitter { with(PrependOperator) { """ |// ${generatedByHeader()} + |use std::sync::{Arc, Mutex}; | |struct $structName { | // TODO state vars @@ -65,7 +66,10 @@ object RustEmitter { | |impl $structName { | - | // todo reaction worker functions + | fn react_startup(link: $rsRuntime::SchedulerLink, ctx: &mut $rsRuntime::LogicalCtx) { + | // todo + | } + | ${" | "..reactions.joinToString("\n\n") { it.toWorkerFunction() }} | | @@ -100,6 +104,39 @@ ${" | "..reactionWrappers(reactor)} | } | } |} + | + |struct $assemblerName { + | _rstate: Arc>, +${" | "..reactionObjects(reactor)} + |} + | + |impl $rsRuntime::ReactorAssembler for $assemblerName { + | type RState = $dispatcherName; + | + | fn start(&mut self, link: $rsRuntime::SchedulerLink, ctx: &mut $rsRuntime::LogicalCtx) { + | let state = &self._rstate.lock().unwrap(); + | $structName::react_startup(link, ctx, /*todo dependencies*/); + | } + | + | fn assemble(reactor_id: &mut $rsRuntime::ReactorId, args: ::Params) -> Self { + | let mut _rstate = Arc::new(Mutex::new(::assemble(args))); + | let this_reactor = reactor_id.get_and_increment(); + | let mut reaction_id = 0; + | +${" | "..reactionObjectInitializers(reactor)} + | + | { // declare local dependencies + | let mut statemut = _rstate.lock().unwrap(); + | +${" | "..localDependencyDeclarations(reactor)} + | } + | + | Self { + | _rstate, +${" | "..reactions.joinToString(",\n") { it.invokerId }} + | } + | } + |} """.trimMargin() } } @@ -123,6 +160,32 @@ ${" | "..reactionWrappers(reactor)} } } + private fun reactionObjects(reactor: ReactorInfo): String = + reactor.reactions.joinToString(",\n") { + it.invokerId + ": Arc<$rsRuntime::ReactionInvoker>" + } + + private fun localDependencyDeclarations(reactor: ReactorInfo): String { + fun vecOfReactions(list: List) = + list.joinToString(", ", "vec![", "]") { it.invokerId + ".clone()" } + + return reactor.otherComponents.joinToString(",\n") { + "statemut.${it.name}.set_downstream(${vecOfReactions(reactor.influencedReactionsOf(it))}.into());" + } + } + + private fun ReactorInfo.influencedReactionsOf(component: ReactorComponent): List = + // todo transitive closure + reactions.filter { + component in it.depends + } + + + private fun reactionObjectInitializers(reactor: ReactorInfo): String = + reactor.reactions.joinToString("\n") { + "let ${it.invokerId} = new_reaction!(this_reactor, reaction_id, _rstate, ${it.rustId});" + } + private fun Emitter.makeMainFile(gen: GenerationInfo) { this += """ |// ${generatedByHeader()} diff --git a/org.lflang/src/org/lflang/generator/rust/RustModel.kt b/org.lflang/src/org/lflang/generator/rust/RustModel.kt index 0e03fd974e..1e41f25c25 100644 --- a/org.lflang/src/org/lflang/generator/rust/RustModel.kt +++ b/org.lflang/src/org/lflang/generator/rust/RustModel.kt @@ -53,6 +53,7 @@ data class ReactorInfo( val modName = lfName.toLowerCase(Locale.ROOT) // note: toLowercase is deprecated in kotlin 1.5.0 val structName get() = lfName val dispatcherName = "${structName}Dispatcher" + val assemblerName = "${structName}Assembler" val reactionIdName = "${structName}Reactions" } @@ -63,6 +64,8 @@ data class ReactionInfo( val rustId: String = "R$idx", /** The name of the worker function for this reaction. */ val workerId: String = "react_$idx", + /** The name of the ReactionInvoker field for this reaction. */ + val invokerId: String = "react_$idx", /** Dependencies declared by the reaction, which are served to the worker function. */ val depends: Set, /** Target code for the reaction body. */ From 5098650b3f3ffdb970ac2aad03f46fc31e8ab560 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Tue, 6 Jul 2021 09:44:19 +0200 Subject: [PATCH 021/252] Cleanup --- .../org/lflang/generator/rust/RustEmitter.kt | 21 +++++++------------ 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt b/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt index 8c38899188..809c91551f 100644 --- a/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt +++ b/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt @@ -107,7 +107,7 @@ ${" | "..reactionWrappers(reactor)} | |struct $assemblerName { | _rstate: Arc>, -${" | "..reactionObjects(reactor)} +${" | "..reactor.reactions.joinToString(",\n") { it.invokerFieldDeclaration() }} |} | |impl $rsRuntime::ReactorAssembler for $assemblerName { @@ -123,7 +123,7 @@ ${" | "..reactionObjects(reactor)} | let this_reactor = reactor_id.get_and_increment(); | let mut reaction_id = 0; | -${" | "..reactionObjectInitializers(reactor)} +${" | "..reactor.reactions.joinToString("\n") { it.reactionInvokerInitializer() }} | | { // declare local dependencies | let mut statemut = _rstate.lock().unwrap(); @@ -160,11 +160,6 @@ ${" | "..reactions.joinToString(",\n") { it.invokerId }} } } - private fun reactionObjects(reactor: ReactorInfo): String = - reactor.reactions.joinToString(",\n") { - it.invokerId + ": Arc<$rsRuntime::ReactionInvoker>" - } - private fun localDependencyDeclarations(reactor: ReactorInfo): String { fun vecOfReactions(list: List) = list.joinToString(", ", "vec![", "]") { it.invokerId + ".clone()" } @@ -181,11 +176,6 @@ ${" | "..reactions.joinToString(",\n") { it.invokerId }} } - private fun reactionObjectInitializers(reactor: ReactorInfo): String = - reactor.reactions.joinToString("\n") { - "let ${it.invokerId} = new_reaction!(this_reactor, reaction_id, _rstate, ${it.rustId});" - } - private fun Emitter.makeMainFile(gen: GenerationInfo) { this += """ |// ${generatedByHeader()} @@ -240,7 +230,7 @@ ${" |"..gen.reactors.joinToString("\n") { "mod ${it.modName};" }} } -object ReactorComponentEmitter { +private object ReactorComponentEmitter { fun ReactorComponent.toBorrow() = when (this) { @@ -271,6 +261,11 @@ object ReactorComponentEmitter { fun ReactorComponent.toStructField() = "$name: ${toType()}" + fun ReactionInfo.reactionInvokerInitializer() = + "let $invokerId = new_reaction!(this_reactor, reaction_id, _rstate, $rustId);" + + fun ReactionInfo.invokerFieldDeclaration() = + "$invokerId: Arc<$rsRuntime::ReactionInvoker>" fun ReactionInfo.toWorkerFunction() = """ From d0ea89f30715a10d6b40d1c26a3a84775d8540e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Tue, 6 Jul 2021 09:51:57 +0200 Subject: [PATCH 022/252] Support startup reaction --- org.lflang/src/org/lflang/generator/rust/RustEmitter.kt | 9 +++++---- .../src/org/lflang/generator/rust/RustGenerator.kt | 9 ++++++++- org.lflang/src/org/lflang/generator/rust/RustModel.kt | 6 +++++- 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt b/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt index 809c91551f..7753e9411a 100644 --- a/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt +++ b/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt @@ -60,18 +60,19 @@ object RustEmitter { |// ${generatedByHeader()} |use std::sync::{Arc, Mutex}; | + |// todo link to source |struct $structName { | // TODO state vars |} | |impl $structName { | - | fn react_startup(link: $rsRuntime::SchedulerLink, ctx: &mut $rsRuntime::LogicalCtx) { - | // todo - | } + | // TODO change this generation logic. There may be several reactions invoked on startup + | fn react_startup(link: $rsRuntime::SchedulerLink, ctx: &mut $rsRuntime::LogicalCtx) { +${" | "..reactions.firstOrNull { it.isStartup }?.body.orEmpty()} + | } | ${" | "..reactions.joinToString("\n\n") { it.toWorkerFunction() }} - | | |} | diff --git a/org.lflang/src/org/lflang/generator/rust/RustGenerator.kt b/org.lflang/src/org/lflang/generator/rust/RustGenerator.kt index f8dcf189aa..8b4bfaf3f5 100644 --- a/org.lflang/src/org/lflang/generator/rust/RustGenerator.kt +++ b/org.lflang/src/org/lflang/generator/rust/RustGenerator.kt @@ -33,6 +33,7 @@ import org.lflang.generator.GeneratorBase import org.lflang.generator.cpp.name import org.lflang.lf.Action import org.lflang.lf.Reaction +import org.lflang.lf.TriggerRef import org.lflang.lf.VarRef /** @@ -84,7 +85,13 @@ class RustGenerator(fileConfig: RustFileConfig, errorReporter: ErrorReporter) : val reactions = reactor.reactions.map { n: Reaction -> val dependencies = (n.effects + n.sources).mapTo(LinkedHashSet()) { components[it.name]!! } - ReactionInfo(idx = n.indexInContainer, depends = dependencies, body = n.code.body) + ReactionInfo( + idx = n.indexInContainer, + depends = dependencies, + body = n.code.body, + isStartup = n.triggers.any { it.isStartup }, + isShutdown = n.triggers.any { it.isShutdown } + ) } ReactorInfo( diff --git a/org.lflang/src/org/lflang/generator/rust/RustModel.kt b/org.lflang/src/org/lflang/generator/rust/RustModel.kt index 1e41f25c25..61b4cf2218 100644 --- a/org.lflang/src/org/lflang/generator/rust/RustModel.kt +++ b/org.lflang/src/org/lflang/generator/rust/RustModel.kt @@ -69,7 +69,11 @@ data class ReactionInfo( /** Dependencies declared by the reaction, which are served to the worker function. */ val depends: Set, /** Target code for the reaction body. */ - val body: String + val body: String, + /** Whether the reaction is triggered by the startup event. */ + val isStartup: Boolean, + /** Whether the reaction is triggered by the shutdown event. */ + val isShutdown: Boolean, ) From d96e93bc0e2379899f9ba774e63783e68daf6641 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Tue, 6 Jul 2021 09:52:11 +0200 Subject: [PATCH 023/252] Delete old vf template --- .../org/lflang/generator/rust/CargoTemplate.toml.vf | 10 ---------- 1 file changed, 10 deletions(-) delete mode 100644 org.lflang/src/org/lflang/generator/rust/CargoTemplate.toml.vf diff --git a/org.lflang/src/org/lflang/generator/rust/CargoTemplate.toml.vf b/org.lflang/src/org/lflang/generator/rust/CargoTemplate.toml.vf deleted file mode 100644 index f159272c39..0000000000 --- a/org.lflang/src/org/lflang/generator/rust/CargoTemplate.toml.vf +++ /dev/null @@ -1,10 +0,0 @@ -[package] -name = "$crate.name" -version = "$crate.version" -authors = ["$crate.author0"] -edition = "2018" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -reactor-rust = { $runtime.toml_spec } From 331f1889eee0c06d56cecba0560041f5f8792ef4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Tue, 6 Jul 2021 10:00:40 +0200 Subject: [PATCH 024/252] Improve name independence --- .../src/org/lflang/generator/rust/RustEmitter.kt | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt b/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt index 7753e9411a..7fd41c6e74 100644 --- a/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt +++ b/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt @@ -33,11 +33,11 @@ import org.lflang.withDQuotes * Generates Rust code */ object RustEmitter { - /** - * Name given to the Rust runtime crate within generated code, - * can be used to qualify names. - */ - const val rsRuntime = "_rr" + /** Alias of the rust runtime in the generated code. */ + const val rsRuntimeIdent = "_rr" + + /** Qualification prefix to refer to a member of the runtime library crate. */ + const val rsRuntime = "::$rsRuntimeIdent" fun generateFiles(fileConfig: RustFileConfig, gen: GenerationInfo) { @@ -182,7 +182,7 @@ ${" | "..reactions.joinToString(",\n") { it.invokerId }} |// ${generatedByHeader()} |#[allow(unused_imports)] |#[macro_use] - |extern crate ${gen.crate.name} as $rsRuntime; + |extern crate ${gen.crate.name} as $rsRuntimeIdent; | |fn main() { | // todo @@ -197,7 +197,7 @@ ${" | "..reactions.joinToString(",\n") { it.invokerId }} |// ${generatedByHeader()} |//! Root of this crate |#[macro_use] - |extern crate reactor_rust as $rsRuntime; + |extern crate reactor_rust as $rsRuntimeIdent; | ${" |"..gen.reactors.joinToString("\n") { "mod ${it.modName};" }} | From d89d5e398410a0d9c4d331817f0fcf48466b755e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Tue, 6 Jul 2021 10:01:03 +0200 Subject: [PATCH 025/252] Sketch of main code... needs some reworking --- org.lflang/src/org/lflang/generator/rust/RustEmitter.kt | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt b/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt index 7fd41c6e74..11a7e99a6a 100644 --- a/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt +++ b/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt @@ -185,8 +185,14 @@ ${" | "..reactions.joinToString(",\n") { it.invokerId }} |extern crate ${gen.crate.name} as $rsRuntimeIdent; | |fn main() { - | // todo + | let mut reactor_id = ReactorId::first(); | + | let mut scheduler = $rsRuntime::SyncScheduler::new(); + | scheduler.startup(|mut starter| { + | starter.start(&mut gcell); + | starter.start(&mut pcell); + | }); + | scheduler.launch_async(Duration::from_secs(10)).join().unwrap(); |} """.trimMargin() } From 07616589c9b2be1d519fc1695970be71477586ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Tue, 6 Jul 2021 15:50:58 +0200 Subject: [PATCH 026/252] Fix main code Hello world runs! --- .../org/lflang/generator/rust/RustEmitter.kt | 47 +++++++++++-------- 1 file changed, 27 insertions(+), 20 deletions(-) diff --git a/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt b/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt index 11a7e99a6a..e9b378a24f 100644 --- a/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt +++ b/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt @@ -42,10 +42,10 @@ object RustEmitter { fun generateFiles(fileConfig: RustFileConfig, gen: GenerationInfo) { fileConfig.emit("Cargo.toml") { makeCargoFile(gen) } - fileConfig.emit("src/bin/main.rs") { makeMainFile(gen) } - fileConfig.emit("src/lib.rs") { makeRootLibFile(gen) } + fileConfig.emit("src/main.rs") { makeMainFile(gen) } + fileConfig.emit("src/reactors/mod.rs") { makeReactorsAggregateModule(gen) } for (reactor in gen.reactors) { - fileConfig.emit("src/${reactor.modName}.rs") { + fileConfig.emit("src/reactors/${reactor.modName}.rs") { makeReactorModule(reactor) } } @@ -58,10 +58,12 @@ object RustEmitter { with(PrependOperator) { """ |// ${generatedByHeader()} + |#[allow(unused)] + | |use std::sync::{Arc, Mutex}; | |// todo link to source - |struct $structName { + |pub struct $structName { | // TODO state vars |} | @@ -76,14 +78,14 @@ ${" | "..reactions.joinToString("\n\n") { it.toWorkerFunction() } | |} | - |struct $dispatcherName { + |pub struct $dispatcherName { | _impl: $structName, ${" | "..otherComponents.joinToString(",\n") { it.toStructField() }} |} | | |reaction_ids!( - | ${reactions.joinToString(", ", "enum $reactionIdName {", "}") { it.rustId }} + | ${reactions.joinToString(", ", "pub enum $reactionIdName {", "}") { it.rustId }} |); | |impl $rsRuntime::ReactorDispatcher for $dispatcherName { @@ -106,7 +108,7 @@ ${" | "..reactionWrappers(reactor)} | } |} | - |struct $assemblerName { + |pub struct $assemblerName { | _rstate: Arc>, ${" | "..reactor.reactions.joinToString(",\n") { it.invokerFieldDeclaration() }} |} @@ -180,32 +182,33 @@ ${" | "..reactions.joinToString(",\n") { it.invokerId }} private fun Emitter.makeMainFile(gen: GenerationInfo) { this += """ |// ${generatedByHeader()} - |#[allow(unused_imports)] |#[macro_use] - |extern crate ${gen.crate.name} as $rsRuntimeIdent; + |extern crate reactor_rust as $rsRuntimeIdent; | - |fn main() { - | let mut reactor_id = ReactorId::first(); + |mod reactors; + | + |use $rsRuntime::*; + |use std::time::Duration; | - | let mut scheduler = $rsRuntime::SyncScheduler::new(); + |fn main() { + | let mut reactor_id = ReactorId::first(); + | let mut topcell = ::assemble(&mut reactor_id, (/*todo params*/)); + | let mut scheduler = SyncScheduler::new(); | scheduler.startup(|mut starter| { - | starter.start(&mut gcell); - | starter.start(&mut pcell); + | starter.start(&mut topcell); | }); - | scheduler.launch_async(Duration::from_secs(10)).join().unwrap(); + | let timeout = Duration::from_secs(10); + | scheduler.launch_async(timeout).join().unwrap(); |} """.trimMargin() } - private fun Emitter.makeRootLibFile(gen: GenerationInfo) { + private fun Emitter.makeReactorsAggregateModule(gen: GenerationInfo) { this += with(PrependOperator) { """ |// ${generatedByHeader()} - |//! Root of this crate - |#[macro_use] - |extern crate reactor_rust as $rsRuntimeIdent; | -${" |"..gen.reactors.joinToString("\n") { "mod ${it.modName};" }} +${" |"..gen.reactors.joinToString("\n") { "mod ${it.modName};\npub use self::${it.modName}::${it.assemblerName};" }} | """.trimMargin() } @@ -228,6 +231,10 @@ ${" |"..gen.reactors.joinToString("\n") { "mod ${it.modName};" }} |# See https://doc.rust-lang.org/cargo/appendix/git-authentication.html#ssh-authentication |# git = "ssh://git@github.com:icyphy/reactor-rust.git" |path = "/home/clem/Documents/Cours/rust-reactors" + | + |[[bin]] + |name = "a-reactor-program" + |path = "src/main.rs" """.trimMargin() } From 55929c1ba29be6625a06fa54e160687dc6aac983 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Tue, 6 Jul 2021 16:27:25 +0200 Subject: [PATCH 027/252] Doc --- org.lflang/src/org/lflang/generator/rust/RustEmitter.kt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt b/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt index e9b378a24f..fee0f6d4ca 100644 --- a/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt +++ b/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt @@ -172,8 +172,13 @@ ${" | "..reactions.joinToString(",\n") { it.invokerId }} } } + /** + * Returns a list of the reactions which need to be triggered + * when the [component] is set at a specific time step. Eg if + * the component is a port, the reactions to trigger are all + * those which have registered a dependency on that port. + */ private fun ReactorInfo.influencedReactionsOf(component: ReactorComponent): List = - // todo transitive closure reactions.filter { component in it.depends } From e5d968761436de759b05e373c38adf7b3e3db553 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Tue, 6 Jul 2021 16:53:58 +0200 Subject: [PATCH 028/252] Add rust test --- .../org/lflang/tests/runtime/RustTest.java | 46 +++++++++++++++++++ .../org/lflang/tests/runtime/TestBase.xtend | 3 +- .../org/lflang/generator/rust/RustEmitter.kt | 6 +-- .../lflang/generator/rust/RustGenerator.kt | 14 ++++-- .../org/lflang/generator/rust/RustModel.kt | 3 +- 5 files changed, 64 insertions(+), 8 deletions(-) create mode 100644 org.lflang.tests/src/org/lflang/tests/runtime/RustTest.java diff --git a/org.lflang.tests/src/org/lflang/tests/runtime/RustTest.java b/org.lflang.tests/src/org/lflang/tests/runtime/RustTest.java new file mode 100644 index 0000000000..9b198b2486 --- /dev/null +++ b/org.lflang.tests/src/org/lflang/tests/runtime/RustTest.java @@ -0,0 +1,46 @@ +/* + * 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.tests.runtime; + +import org.junit.jupiter.api.Test; + +import org.lflang.Target; + +/** + * + */ +public class RustTest extends TestBase { + + public RustTest() { + super.target = Target.Rust; + } + + + @Test + @Override + public void runGenericTests() { + super.runGenericTests(); + } +} diff --git a/org.lflang.tests/src/org/lflang/tests/runtime/TestBase.xtend b/org.lflang.tests/src/org/lflang/tests/runtime/TestBase.xtend index 3ce30badf6..e73b7be447 100644 --- a/org.lflang.tests/src/org/lflang/tests/runtime/TestBase.xtend +++ b/org.lflang.tests/src/org/lflang/tests/runtime/TestBase.xtend @@ -341,7 +341,8 @@ abstract class TestBase { switch(test.target) { case C, case CPP, - case CCPP: { + case CCPP, + case Rust: { val binPath = test.fileConfig.binPath var binaryName = nameOnly // Adjust binary extension if running on Window diff --git a/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt b/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt index fee0f6d4ca..9559ff08ed 100644 --- a/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt +++ b/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt @@ -41,7 +41,7 @@ object RustEmitter { fun generateFiles(fileConfig: RustFileConfig, gen: GenerationInfo) { - fileConfig.emit("Cargo.toml") { makeCargoFile(gen) } + fileConfig.emit("Cargo.toml") { makeCargoTomlFile(gen) } fileConfig.emit("src/main.rs") { makeMainFile(gen) } fileConfig.emit("src/reactors/mod.rs") { makeReactorsAggregateModule(gen) } for (reactor in gen.reactors) { @@ -219,7 +219,7 @@ ${" |"..gen.reactors.joinToString("\n") { "mod ${it.modName};\npub use s } } - private fun Emitter.makeCargoFile(gen: GenerationInfo) { + private fun Emitter.makeCargoTomlFile(gen: GenerationInfo) { val (crate, _) = gen this += """ |#-- ${generatedByHeader()} --# @@ -238,7 +238,7 @@ ${" |"..gen.reactors.joinToString("\n") { "mod ${it.modName};\npub use s |path = "/home/clem/Documents/Cours/rust-reactors" | |[[bin]] - |name = "a-reactor-program" + |name = "${gen.executableName}" |path = "src/main.rs" """.trimMargin() } diff --git a/org.lflang/src/org/lflang/generator/rust/RustGenerator.kt b/org.lflang/src/org/lflang/generator/rust/RustGenerator.kt index 8b4bfaf3f5..840f28216a 100644 --- a/org.lflang/src/org/lflang/generator/rust/RustGenerator.kt +++ b/org.lflang/src/org/lflang/generator/rust/RustGenerator.kt @@ -67,12 +67,14 @@ class RustGenerator(fileConfig: RustFileConfig, errorReporter: ErrorReporter) : private fun makeGenerationInfo(resource: Resource, fsa: IFileSystemAccess2, context: IGeneratorContext): GenerationInfo { val reactors = makeReactorInfos() + val mainReactor = reactors.lastOrNull { it.isMain } ?: reactors.last() return GenerationInfo( crate = CrateInfo("mycrate_todo", "0.0.0", authors = listOf("todo")), runtime = makeRuntimeInfo(), reactors = reactors, - mainReactor = reactors.first { it.isMain } + mainReactor = mainReactor, + executableName = mainReactor.modName ) } @@ -110,14 +112,20 @@ class RustGenerator(fileConfig: RustFileConfig, errorReporter: ErrorReporter) : private fun invokeRustCompiler() { val cargoBuilder = createCommand( - "cargo", listOf("build"), + "cargo", listOf( + "+nightly", + "build", + "--release", + // note that this option is unstable for now and requires rust nightly ... + "--out-dir", fileConfig.binPath.toAbsolutePath().toString(), + "-Z", "unstable-options" // ... and that feature flag + ), fileConfig.srcGenPath, "The Rust target requires Cargo in the path. " + "Auto-compiling can be disabled using the \"no-compile: true\" target property.", true ) ?: return - val cargoReturnCode = executeCommand(cargoBuilder) if (cargoReturnCode == 0) { diff --git a/org.lflang/src/org/lflang/generator/rust/RustModel.kt b/org.lflang/src/org/lflang/generator/rust/RustModel.kt index 61b4cf2218..22bc550d91 100644 --- a/org.lflang/src/org/lflang/generator/rust/RustModel.kt +++ b/org.lflang/src/org/lflang/generator/rust/RustModel.kt @@ -40,7 +40,8 @@ data class GenerationInfo( val crate: CrateInfo, val runtime: RuntimeInfo, val reactors: List, - val mainReactor: ReactorInfo // it's also in the list + val mainReactor: ReactorInfo, // it's also in the list + val executableName: String ) data class ReactorInfo( From 42f0547fb10cd55d33708b93c17e167ced4d2ad4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Tue, 6 Jul 2021 17:02:50 +0200 Subject: [PATCH 029/252] Delete RuntimeInfo bean --- org.lflang/src/org/lflang/generator/rust/RustEmitter.kt | 2 +- org.lflang/src/org/lflang/generator/rust/RustGenerator.kt | 6 ------ org.lflang/src/org/lflang/generator/rust/RustModel.kt | 7 ------- 3 files changed, 1 insertion(+), 14 deletions(-) diff --git a/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt b/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt index 9559ff08ed..490422d6fe 100644 --- a/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt +++ b/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt @@ -220,7 +220,7 @@ ${" |"..gen.reactors.joinToString("\n") { "mod ${it.modName};\npub use s } private fun Emitter.makeCargoTomlFile(gen: GenerationInfo) { - val (crate, _) = gen + val (crate) = gen this += """ |#-- ${generatedByHeader()} --# |[package] diff --git a/org.lflang/src/org/lflang/generator/rust/RustGenerator.kt b/org.lflang/src/org/lflang/generator/rust/RustGenerator.kt index 840f28216a..ea1f39dcba 100644 --- a/org.lflang/src/org/lflang/generator/rust/RustGenerator.kt +++ b/org.lflang/src/org/lflang/generator/rust/RustGenerator.kt @@ -71,7 +71,6 @@ class RustGenerator(fileConfig: RustFileConfig, errorReporter: ErrorReporter) : return GenerationInfo( crate = CrateInfo("mycrate_todo", "0.0.0", authors = listOf("todo")), - runtime = makeRuntimeInfo(), reactors = reactors, mainReactor = mainReactor, executableName = mainReactor.modName @@ -104,11 +103,6 @@ class RustGenerator(fileConfig: RustFileConfig, errorReporter: ErrorReporter) : ) } - private fun makeRuntimeInfo(): RuntimeInfo { - // fixme - return RuntimeInfo(local_crate_path = "/home/clem/Documents/Cours/rust-reactors") - } - private fun invokeRustCompiler() { val cargoBuilder = createCommand( diff --git a/org.lflang/src/org/lflang/generator/rust/RustModel.kt b/org.lflang/src/org/lflang/generator/rust/RustModel.kt index 22bc550d91..d18c24d264 100644 --- a/org.lflang/src/org/lflang/generator/rust/RustModel.kt +++ b/org.lflang/src/org/lflang/generator/rust/RustModel.kt @@ -38,7 +38,6 @@ import java.util.* data class GenerationInfo( val crate: CrateInfo, - val runtime: RuntimeInfo, val reactors: List, val mainReactor: ReactorInfo, // it's also in the list val executableName: String @@ -84,12 +83,6 @@ data class CrateInfo( val authors: List, ) -data class RuntimeInfo( - val local_crate_path: String - // options, etc -) - - /* TODO do we really need the following classes? - I quite like that they are much simpler than the corresponding AST nodes (Input, Action, etc). From a9672ce2652c8e7eb4f44d99359aa22db093f481 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Tue, 6 Jul 2021 17:04:52 +0200 Subject: [PATCH 030/252] Remove unused warnings in generated code --- org.lflang/src/org/lflang/generator/rust/RustEmitter.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt b/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt index 490422d6fe..132dc22664 100644 --- a/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt +++ b/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt @@ -58,7 +58,7 @@ object RustEmitter { with(PrependOperator) { """ |// ${generatedByHeader()} - |#[allow(unused)] + |#![allow(unused)] | |use std::sync::{Arc, Mutex}; | From 1d08408544bf6d797863412aaf0c751a28a4f741 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Mon, 12 Jul 2021 14:29:27 +0200 Subject: [PATCH 031/252] Second example --- .idea/codeStyles/Project.xml | 180 --------------------------------- test/Rust/src/StructAsState.lf | 20 ++++ 2 files changed, 20 insertions(+), 180 deletions(-) create mode 100644 test/Rust/src/StructAsState.lf diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml index 1f07a2494f..7cac1e825d 100644 --- a/.idea/codeStyles/Project.xml +++ b/.idea/codeStyles/Project.xml @@ -366,186 +366,6 @@ \ No newline at end of file diff --git a/test/Rust/src/StructAsState.lf b/test/Rust/src/StructAsState.lf new file mode 100644 index 0000000000..c629e80350 --- /dev/null +++ b/test/Rust/src/StructAsState.lf @@ -0,0 +1,20 @@ +// Check that a state variable can have a statically initialized struct as a value. +// Check how preambles work +target Rust; +main reactor StructAsState { + preamble {= + struct Hello { + name: String, + value: i32, + } + =} + // notice this uses parentheses + state s: {= Hello { name: "Earth".into(), value: 42 } =}; + reaction(startup) {= + println!("State s.name=\"{}\", value={}.", self.name, self.value); + if (self.value != 42) { + eprintln!("FAILED: Expected 42."); + std::process::exit(1); + } + =} +} From 35f1da490cb513f61c40c06d7cfc0f656d604e46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Tue, 13 Jul 2021 14:41:38 +0200 Subject: [PATCH 032/252] Add support for state vars --- org.lflang/src/org/lflang/generator/rust/RustEmitter.kt | 8 ++++++-- org.lflang/src/org/lflang/generator/rust/RustGenerator.kt | 5 ++++- org.lflang/src/org/lflang/generator/rust/RustModel.kt | 6 +++++- test/Rust/src/StructAsState.lf | 2 +- 4 files changed, 16 insertions(+), 5 deletions(-) diff --git a/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt b/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt index 132dc22664..26f01fe554 100644 --- a/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt +++ b/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt @@ -62,9 +62,11 @@ object RustEmitter { | |use std::sync::{Arc, Mutex}; | +${" |"..reactor.preambles.joinToString("\n\n")} + | |// todo link to source |pub struct $structName { - | // TODO state vars +${" | "..reactor.stateVars.joinToString(",\n") { it.lfName + ": " + it.type }} |} | |impl $structName { @@ -96,7 +98,9 @@ ${" | "..otherComponents.joinToString(",\n") { it.toStructField() | | fn assemble(_params: Self::Params) -> Self { | Self { - | _impl: $structName {/*todo*/}, + | _impl: $structName { +${" | "..reactor.stateVars.joinToString(",\n") { it.lfName + ": " + (it.init ?: "Default::default()") }} + | }, ${" | "..otherComponents.joinToString(",\n") { it.toFieldInitializer() }} | } | } diff --git a/org.lflang/src/org/lflang/generator/rust/RustGenerator.kt b/org.lflang/src/org/lflang/generator/rust/RustGenerator.kt index ea1f39dcba..17b9b935a9 100644 --- a/org.lflang/src/org/lflang/generator/rust/RustGenerator.kt +++ b/org.lflang/src/org/lflang/generator/rust/RustGenerator.kt @@ -31,6 +31,7 @@ import org.lflang.* import org.lflang.Target import org.lflang.generator.GeneratorBase import org.lflang.generator.cpp.name +import org.lflang.generator.cpp.targetType import org.lflang.lf.Action import org.lflang.lf.Reaction import org.lflang.lf.TriggerRef @@ -99,7 +100,9 @@ class RustGenerator(fileConfig: RustFileConfig, errorReporter: ErrorReporter) : lfName = reactor.name, reactions = reactions, otherComponents = components.values.toList(), - isMain = reactor.isMain + isMain = reactor.isMain, + preambles = reactor.preambles.map { it.code.toText() }, + stateVars = reactor.stateVars.map { StateVarInfo(it.name, it.targetType, init = it.init.singleOrNull()?.toText()) } ) } diff --git a/org.lflang/src/org/lflang/generator/rust/RustModel.kt b/org.lflang/src/org/lflang/generator/rust/RustModel.kt index d18c24d264..a3d07240f9 100644 --- a/org.lflang/src/org/lflang/generator/rust/RustModel.kt +++ b/org.lflang/src/org/lflang/generator/rust/RustModel.kt @@ -48,7 +48,9 @@ data class ReactorInfo( val reactions: List, val isMain: Boolean, val otherComponents: List, - val ctorParamTypes: List = emptyList() + val ctorParamTypes: List = emptyList(), + val preambles: List, + val stateVars: List ) { val modName = lfName.toLowerCase(Locale.ROOT) // note: toLowercase is deprecated in kotlin 1.5.0 val structName get() = lfName @@ -57,6 +59,8 @@ data class ReactorInfo( val reactionIdName = "${structName}Reactions" } +data class StateVarInfo(val lfName: String, val type: String, val init: String?) + data class ReactionInfo( /** Index in the containing reactor. */ val idx: Int, diff --git a/test/Rust/src/StructAsState.lf b/test/Rust/src/StructAsState.lf index c629e80350..caa164e872 100644 --- a/test/Rust/src/StructAsState.lf +++ b/test/Rust/src/StructAsState.lf @@ -9,7 +9,7 @@ main reactor StructAsState { } =} // notice this uses parentheses - state s: {= Hello { name: "Earth".into(), value: 42 } =}; + state s: Hello ({= Hello { name: "Earth".into(), value: 42 } =}); reaction(startup) {= println!("State s.name=\"{}\", value={}.", self.name, self.value); if (self.value != 42) { From 4dfc437113ef88d3dd35da6ba64cc9183abbda62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Tue, 13 Jul 2021 14:49:35 +0200 Subject: [PATCH 033/252] Preserve newlines in worker function body --- .../src/org/lflang/generator/rust/RustEmitter.kt | 14 ++++++++------ .../src/org/lflang/generator/rust/RustGenerator.kt | 2 +- test/Rust/src/StructAsState.lf | 2 +- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt b/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt index 26f01fe554..51d56584a8 100644 --- a/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt +++ b/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt @@ -291,12 +291,14 @@ private object ReactorComponentEmitter { "$invokerId: Arc<$rsRuntime::ReactionInvoker>" fun ReactionInfo.toWorkerFunction() = - """ - // todo metadata - fn ${this.workerId}(&mut self, ctx: &mut _rr::LogicalCtx, ${reactionParams()}) { - ${this.body} - } - """.trimIndent() + with(PrependOperator) { + """ + |// todo reproduce header & metadata here + |fn $workerId(&mut self, ctx: &mut _rr::LogicalCtx, ${reactionParams()}) { +${" | "..body} + |} + """.trimMargin() + } private fun ReactionInfo.reactionParams() = depends.joinToString(", ") { "${it.name}: ${it.toBorrowedType()}" } diff --git a/org.lflang/src/org/lflang/generator/rust/RustGenerator.kt b/org.lflang/src/org/lflang/generator/rust/RustGenerator.kt index 17b9b935a9..697019d75d 100644 --- a/org.lflang/src/org/lflang/generator/rust/RustGenerator.kt +++ b/org.lflang/src/org/lflang/generator/rust/RustGenerator.kt @@ -90,7 +90,7 @@ class RustGenerator(fileConfig: RustFileConfig, errorReporter: ErrorReporter) : ReactionInfo( idx = n.indexInContainer, depends = dependencies, - body = n.code.body, + body = n.code.toText(), isStartup = n.triggers.any { it.isStartup }, isShutdown = n.triggers.any { it.isShutdown } ) diff --git a/test/Rust/src/StructAsState.lf b/test/Rust/src/StructAsState.lf index caa164e872..fbbcdaf575 100644 --- a/test/Rust/src/StructAsState.lf +++ b/test/Rust/src/StructAsState.lf @@ -12,7 +12,7 @@ main reactor StructAsState { state s: Hello ({= Hello { name: "Earth".into(), value: 42 } =}); reaction(startup) {= println!("State s.name=\"{}\", value={}.", self.name, self.value); - if (self.value != 42) { + if self.value != 42 { eprintln!("FAILED: Expected 42."); std::process::exit(1); } From 06d1afbf76b1933dc4a541742c089d9a6cf97868 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Tue, 13 Jul 2021 15:02:53 +0200 Subject: [PATCH 034/252] Dont rename the runtime crate intellij-rust doesn't like it and it's not really necessary Also update runtime crate name to reactor_rt --- .../src/org/lflang/generator/rust/RustEmitter.kt | 12 ++++++------ test/Rust/src/StructAsState.lf | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt b/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt index 51d56584a8..6f37d989a4 100644 --- a/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt +++ b/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt @@ -33,11 +33,11 @@ import org.lflang.withDQuotes * Generates Rust code */ object RustEmitter { - /** Alias of the rust runtime in the generated code. */ - const val rsRuntimeIdent = "_rr" + /** Name of the runtime crate that is in its Cargo.toml.*/ + const val runtimeCrateFullName = "reactor_rt" /** Qualification prefix to refer to a member of the runtime library crate. */ - const val rsRuntime = "::$rsRuntimeIdent" + const val rsRuntime = "::$runtimeCrateFullName" fun generateFiles(fileConfig: RustFileConfig, gen: GenerationInfo) { @@ -192,7 +192,7 @@ ${" | "..reactions.joinToString(",\n") { it.invokerId }} this += """ |// ${generatedByHeader()} |#[macro_use] - |extern crate reactor_rust as $rsRuntimeIdent; + |extern crate $runtimeCrateFullName; | |mod reactors; | @@ -235,7 +235,7 @@ ${" |"..gen.reactors.joinToString("\n") { "mod ${it.modName};\npub use s |# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - |[dependencies.reactor_rust] + |[dependencies.$runtimeCrateFullName] |#-- The reactor runtime --# |# See https://doc.rust-lang.org/cargo/appendix/git-authentication.html#ssh-authentication |# git = "ssh://git@github.com:icyphy/reactor-rust.git" @@ -294,7 +294,7 @@ private object ReactorComponentEmitter { with(PrependOperator) { """ |// todo reproduce header & metadata here - |fn $workerId(&mut self, ctx: &mut _rr::LogicalCtx, ${reactionParams()}) { + |fn $workerId(&mut self, ctx: &mut $rsRuntime::LogicalCtx, ${reactionParams()}) { ${" | "..body} |} """.trimMargin() diff --git a/test/Rust/src/StructAsState.lf b/test/Rust/src/StructAsState.lf index fbbcdaf575..519e6122cd 100644 --- a/test/Rust/src/StructAsState.lf +++ b/test/Rust/src/StructAsState.lf @@ -11,8 +11,8 @@ main reactor StructAsState { // notice this uses parentheses state s: Hello ({= Hello { name: "Earth".into(), value: 42 } =}); reaction(startup) {= - println!("State s.name=\"{}\", value={}.", self.name, self.value); - if self.value != 42 { + println!("State s.name=\"{}\", s.value={}.", self.s.name, self.s.value); + if self.s.value != 42 { eprintln!("FAILED: Expected 42."); std::process::exit(1); } From 60ef32a7d834bb5c5e16545cc59fd751a25ab924 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Tue, 13 Jul 2021 15:14:44 +0200 Subject: [PATCH 035/252] Change startup logic not to depend on special startup reaction --- .../org/lflang/generator/rust/RustEmitter.kt | 24 ++++++++++--------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt b/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt index 6f37d989a4..1a1eebe2be 100644 --- a/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt +++ b/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt @@ -71,11 +71,6 @@ ${" | "..reactor.stateVars.joinToString(",\n") { it.lfName + ": " | |impl $structName { | - | // TODO change this generation logic. There may be several reactions invoked on startup - | fn react_startup(link: $rsRuntime::SchedulerLink, ctx: &mut $rsRuntime::LogicalCtx) { -${" | "..reactions.firstOrNull { it.isStartup }?.body.orEmpty()} - | } - | ${" | "..reactions.joinToString("\n\n") { it.toWorkerFunction() }} | |} @@ -112,21 +107,28 @@ ${" | "..reactionWrappers(reactor)} | } |} | + |use $rsRuntime::*; // after this point there's no user-written code + | |pub struct $assemblerName { | _rstate: Arc>, ${" | "..reactor.reactions.joinToString(",\n") { it.invokerFieldDeclaration() }} |} | - |impl $rsRuntime::ReactorAssembler for $assemblerName { + |impl ReactorAssembler for $assemblerName { | type RState = $dispatcherName; | - | fn start(&mut self, link: $rsRuntime::SchedulerLink, ctx: &mut $rsRuntime::LogicalCtx) { - | let state = &self._rstate.lock().unwrap(); - | $structName::react_startup(link, ctx, /*todo dependencies*/); + | fn start(&mut self, link: SchedulerLink, ctx: &mut LogicalCtx) { + | let dispatcher = &mut self._rstate.lock().unwrap(); +${" | "..reactor.reactions.filter { it.isStartup }.joinToString("\n") { + "dispatcher.react(ctx, $reactionIdName::${it.rustId});" +}} | } | - | fn assemble(reactor_id: &mut $rsRuntime::ReactorId, args: ::Params) -> Self { - | let mut _rstate = Arc::new(Mutex::new(::assemble(args))); + | fn assemble( + | reactor_id: &mut ReactorId, + | args: ::Params + | ) -> Self { + | let mut _rstate = Arc::new(Mutex::new(Self::RState::assemble(args))); | let this_reactor = reactor_id.get_and_increment(); | let mut reaction_id = 0; | From 021865ce443f883aab9c132e82245f93412b5446 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Tue, 13 Jul 2021 15:40:22 +0200 Subject: [PATCH 036/252] Update to support termination without timeout --- org.lflang/src/lib/Rust/reactor-rust | 2 +- .../src/org/lflang/generator/rust/RustEmitter.kt | 10 ++++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/org.lflang/src/lib/Rust/reactor-rust b/org.lflang/src/lib/Rust/reactor-rust index 09f7924c2c..9c1a038962 160000 --- a/org.lflang/src/lib/Rust/reactor-rust +++ b/org.lflang/src/lib/Rust/reactor-rust @@ -1 +1 @@ -Subproject commit 09f7924c2c5082b3126b08faf089703f4ee45ac6 +Subproject commit 9c1a03896276c3c2936c7282cc15d263298a931d diff --git a/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt b/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt index 1a1eebe2be..d76efe3ad0 100644 --- a/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt +++ b/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt @@ -199,17 +199,19 @@ ${" | "..reactions.joinToString(",\n") { it.invokerId }} |mod reactors; | |use $rsRuntime::*; - |use std::time::Duration; | |fn main() { | let mut reactor_id = ReactorId::first(); | let mut topcell = ::assemble(&mut reactor_id, (/*todo params*/)); - | let mut scheduler = SyncScheduler::new(); + | let options = SchedulerOptions { + | timeout: None, + | keep_alive: false + | }; + | let mut scheduler = SyncScheduler::new(options); | scheduler.startup(|mut starter| { | starter.start(&mut topcell); | }); - | let timeout = Duration::from_secs(10); - | scheduler.launch_async(timeout).join().unwrap(); + | scheduler.launch_async().join().unwrap(); |} """.trimMargin() } From b7eb2f3b00b1bfccb1fbd5a04865d754418ab7a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Tue, 13 Jul 2021 16:00:35 +0200 Subject: [PATCH 037/252] Update submodule --- org.lflang/src/lib/Rust/reactor-rust | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/org.lflang/src/lib/Rust/reactor-rust b/org.lflang/src/lib/Rust/reactor-rust index 9c1a038962..5db4058007 160000 --- a/org.lflang/src/lib/Rust/reactor-rust +++ b/org.lflang/src/lib/Rust/reactor-rust @@ -1 +1 @@ -Subproject commit 9c1a03896276c3c2936c7282cc15d263298a931d +Subproject commit 5db40580074be7b486cade5a939c0cdfcf3c83f9 From 790a71534443695b21504f4bc669066fb019be48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Tue, 13 Jul 2021 16:05:04 +0200 Subject: [PATCH 038/252] Remove hardcoded local path to rust lib Now we use an ssh connection to access the github repo. Be aware that you need a credentials helper for this to work as the repo is private and cargo will not prompt for a password. https://github.com/rust-lang/cargo/issues/1851 --- org.lflang/src/org/lflang/generator/rust/RustEmitter.kt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt b/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt index d76efe3ad0..3216403993 100644 --- a/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt +++ b/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt @@ -242,8 +242,7 @@ ${" |"..gen.reactors.joinToString("\n") { "mod ${it.modName};\npub use s |[dependencies.$runtimeCrateFullName] |#-- The reactor runtime --# |# See https://doc.rust-lang.org/cargo/appendix/git-authentication.html#ssh-authentication - |# git = "ssh://git@github.com:icyphy/reactor-rust.git" - |path = "/home/clem/Documents/Cours/rust-reactors" + |git = "ssh://git@github.com/icyphy/reactor-rust.git" | |[[bin]] |name = "${gen.executableName}" From 4fb98578fe04a7d07647d40fa09e5a218584b1b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Tue, 13 Jul 2021 16:13:45 +0200 Subject: [PATCH 039/252] Add other examples --- test/Rust/src/Preamble.lf | 11 +++++++++++ test/Rust/src/SimpleTimer.lf | 11 +++++++++++ 2 files changed, 22 insertions(+) create mode 100644 test/Rust/src/Preamble.lf create mode 100644 test/Rust/src/SimpleTimer.lf diff --git a/test/Rust/src/Preamble.lf b/test/Rust/src/Preamble.lf new file mode 100644 index 0000000000..9a08a34327 --- /dev/null +++ b/test/Rust/src/Preamble.lf @@ -0,0 +1,11 @@ +target Rust; +main reactor Preamble { + preamble {= + fn add_42(i: i32) -> i32 { + return i + 42; + } + =} + reaction(startup) {= + printf("42 plus 42 is %d.\n", add_42(42)); + =} +} diff --git a/test/Rust/src/SimpleTimer.lf b/test/Rust/src/SimpleTimer.lf new file mode 100644 index 0000000000..0f730aa60b --- /dev/null +++ b/test/Rust/src/SimpleTimer.lf @@ -0,0 +1,11 @@ +target Rust { + // timeout: 2 sec, + // fast: true +}; +main reactor SimpleTimer { + state i:i32(0); + timer t; + reaction(t) {= + println!("Tick {}", self.i); + =} +} From 092a4dc8d9bc939c68860877fec3faaede5f40b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Tue, 13 Jul 2021 16:20:37 +0200 Subject: [PATCH 040/252] Cleanup --- .../src/org/lflang/generator/rust/RustEmitter.kt | 12 +++++++----- test/Rust/src/Preamble.lf | 2 +- test/Rust/src/SimpleTimer.lf | 4 ++-- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt b/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt index 3216403993..b208ab72e6 100644 --- a/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt +++ b/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt @@ -57,7 +57,7 @@ object RustEmitter { with(ReactorComponentEmitter) { with(PrependOperator) { """ - |// ${generatedByHeader()} + |${generatedByComment("//")} |#![allow(unused)] | |use std::sync::{Arc, Mutex}; @@ -192,7 +192,9 @@ ${" | "..reactions.joinToString(",\n") { it.invokerId }} private fun Emitter.makeMainFile(gen: GenerationInfo) { this += """ - |// ${generatedByHeader()} + |${generatedByComment("//")} + |#![allow(unused_imports)] + | |#[macro_use] |extern crate $runtimeCrateFullName; | @@ -219,7 +221,7 @@ ${" | "..reactions.joinToString(",\n") { it.invokerId }} private fun Emitter.makeReactorsAggregateModule(gen: GenerationInfo) { this += with(PrependOperator) { """ - |// ${generatedByHeader()} + |${generatedByComment("//")} | ${" |"..gen.reactors.joinToString("\n") { "mod ${it.modName};\npub use self::${it.modName}::${it.assemblerName};" }} | @@ -230,7 +232,7 @@ ${" |"..gen.reactors.joinToString("\n") { "mod ${it.modName};\npub use s private fun Emitter.makeCargoTomlFile(gen: GenerationInfo) { val (crate) = gen this += """ - |#-- ${generatedByHeader()} --# + |${generatedByComment("#")} |[package] |name = "${crate.name}" |version = "${crate.version}" @@ -251,7 +253,7 @@ ${" |"..gen.reactors.joinToString("\n") { "mod ${it.modName};\npub use s } - private fun generatedByHeader() = "Generated by LFC @ todo time" + private fun generatedByComment(delim: String) = "$delim-- Generated by LFC @ todo time --$delim" } diff --git a/test/Rust/src/Preamble.lf b/test/Rust/src/Preamble.lf index 9a08a34327..34f2cda35d 100644 --- a/test/Rust/src/Preamble.lf +++ b/test/Rust/src/Preamble.lf @@ -6,6 +6,6 @@ main reactor Preamble { } =} reaction(startup) {= - printf("42 plus 42 is %d.\n", add_42(42)); + println!("42 plus 42 is {}.\n", add_42(42)); =} } diff --git a/test/Rust/src/SimpleTimer.lf b/test/Rust/src/SimpleTimer.lf index 0f730aa60b..de5d9374ab 100644 --- a/test/Rust/src/SimpleTimer.lf +++ b/test/Rust/src/SimpleTimer.lf @@ -1,7 +1,7 @@ -target Rust { +target Rust /*{ // timeout: 2 sec, // fast: true -}; +}*/; main reactor SimpleTimer { state i:i32(0); timer t; From b9b1e5d5c094a59f243109b0af0149bb05592c2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Tue, 13 Jul 2021 16:47:37 +0200 Subject: [PATCH 041/252] More cleanups --- .../org/lflang/generator/rust/RustEmitter.kt | 21 ++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt b/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt index b208ab72e6..fb843e3ba1 100644 --- a/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt +++ b/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt @@ -28,6 +28,12 @@ import org.lflang.generator.PrependOperator import org.lflang.generator.rust.RustEmitter.rsRuntime import org.lflang.joinWithCommas import org.lflang.withDQuotes +import java.time.LocalDateTime + +import java.time.format.DateTimeFormatter + + + /** * Generates Rust code @@ -118,10 +124,14 @@ ${" | "..reactor.reactions.joinToString(",\n") { it.invokerFieldDe | type RState = $dispatcherName; | | fn start(&mut self, link: SchedulerLink, ctx: &mut LogicalCtx) { - | let dispatcher = &mut self._rstate.lock().unwrap(); -${" | "..reactor.reactions.filter { it.isStartup }.joinToString("\n") { + | if ${reactor.reactions.any { it.isStartup }} { + | let dispatcher = &mut self._rstate.lock().unwrap(); + | + | // Execute reactions triggered by startup in order. +${" | "..reactor.reactions.filter { it.isStartup }.joinToString("\n") { "dispatcher.react(ctx, $reactionIdName::${it.rustId});" }} + | } | } | | fn assemble( @@ -134,7 +144,8 @@ ${" | "..reactor.reactions.filter { it.isStartup }.joinToStrin | ${" | "..reactor.reactions.joinToString("\n") { it.reactionInvokerInitializer() }} | - | { // declare local dependencies + | if ${reactor.otherComponents.any()} { + | // declare local dependencies | let mut statemut = _rstate.lock().unwrap(); | ${" | "..localDependencyDeclarations(reactor)} @@ -253,8 +264,8 @@ ${" |"..gen.reactors.joinToString("\n") { "mod ${it.modName};\npub use s } - private fun generatedByComment(delim: String) = "$delim-- Generated by LFC @ todo time --$delim" - + private val timeFormatter = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss") + private fun generatedByComment(delim: String) = "$delim-- Generated by LFC @ ${timeFormatter.format(LocalDateTime.now())} --$delim" } From a9f8a07148ea1a1bbe618c5563eb8d707c21bdf2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Tue, 13 Jul 2021 17:08:43 +0200 Subject: [PATCH 042/252] Update submodule --- org.lflang/src/lib/Rust/reactor-rust | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/org.lflang/src/lib/Rust/reactor-rust b/org.lflang/src/lib/Rust/reactor-rust index 5db4058007..29fff413dc 160000 --- a/org.lflang/src/lib/Rust/reactor-rust +++ b/org.lflang/src/lib/Rust/reactor-rust @@ -1 +1 @@ -Subproject commit 5db40580074be7b486cade5a939c0cdfcf3c83f9 +Subproject commit 29fff413dc4ef7246e14f6698438c3ad1259838e From 814a5958b979e8931c8ffa222b34d7074311f4bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Tue, 13 Jul 2021 19:13:38 +0200 Subject: [PATCH 043/252] Use original name for executable Tests pass \o/ --- org.lflang/src/org/lflang/generator/rust/RustGenerator.kt | 2 +- test/Rust/src/StructAsState.lf | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/org.lflang/src/org/lflang/generator/rust/RustGenerator.kt b/org.lflang/src/org/lflang/generator/rust/RustGenerator.kt index 697019d75d..9034c8ab2b 100644 --- a/org.lflang/src/org/lflang/generator/rust/RustGenerator.kt +++ b/org.lflang/src/org/lflang/generator/rust/RustGenerator.kt @@ -74,7 +74,7 @@ class RustGenerator(fileConfig: RustFileConfig, errorReporter: ErrorReporter) : crate = CrateInfo("mycrate_todo", "0.0.0", authors = listOf("todo")), reactors = reactors, mainReactor = mainReactor, - executableName = mainReactor.modName + executableName = mainReactor.lfName ) } diff --git a/test/Rust/src/StructAsState.lf b/test/Rust/src/StructAsState.lf index 519e6122cd..119349ea7a 100644 --- a/test/Rust/src/StructAsState.lf +++ b/test/Rust/src/StructAsState.lf @@ -9,7 +9,11 @@ main reactor StructAsState { } =} // notice this uses parentheses + // todo + // state s: Hello(name= "Earth".into(), value= 42); + // state s: Hello(name: "Earth".into(), value: 42); state s: Hello ({= Hello { name: "Earth".into(), value: 42 } =}); + reaction(startup) {= println!("State s.name=\"{}\", s.value={}.", self.s.name, self.s.value); if self.s.value != 42 { From ce795f9f9af79a0128e132acbc9926674a11bcb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Thu, 15 Jul 2021 15:12:39 +0200 Subject: [PATCH 044/252] Add composition test --- test/Rust/src/MiniComposition.lf | 19 +++++++++++++++++++ test/Rust/src/StructAsState.lf | 1 + 2 files changed, 20 insertions(+) create mode 100644 test/Rust/src/MiniComposition.lf diff --git a/test/Rust/src/MiniComposition.lf b/test/Rust/src/MiniComposition.lf new file mode 100644 index 0000000000..b1eb89fdd9 --- /dev/null +++ b/test/Rust/src/MiniComposition.lf @@ -0,0 +1,19 @@ + +target Rust; +reactor Component1 { + reaction(startup) {= + println!("c1 woke up"); + =} +} +reactor Component2 { + reaction(startup) {= + println!("c2 woke up"); + =} +} +main reactor MiniComposition { + c1 = new Component1(); + c2 = new Component2(); + reaction(startup) {= + println!("parent woke up"); + =} +} diff --git a/test/Rust/src/StructAsState.lf b/test/Rust/src/StructAsState.lf index 119349ea7a..c253547872 100644 --- a/test/Rust/src/StructAsState.lf +++ b/test/Rust/src/StructAsState.lf @@ -12,6 +12,7 @@ main reactor StructAsState { // todo // state s: Hello(name= "Earth".into(), value= 42); // state s: Hello(name: "Earth".into(), value: 42); + // state s: Hello { name: "Earth".into(), value: 42 }; state s: Hello ({= Hello { name: "Earth".into(), value: 42 } =}); reaction(startup) {= From 6203c26f722f051575a3b1005afd53dcee3770db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Thu, 15 Jul 2021 15:28:19 +0200 Subject: [PATCH 045/252] Fix crate name --- org.lflang/src/org/lflang/CommonExtensions.kt | 18 ++++++++++++++++++ .../org/lflang/generator/rust/RustEmitter.kt | 1 + .../org/lflang/generator/rust/RustGenerator.kt | 7 +++++-- 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/org.lflang/src/org/lflang/CommonExtensions.kt b/org.lflang/src/org/lflang/CommonExtensions.kt index a0422374fe..9fe2281193 100644 --- a/org.lflang/src/org/lflang/CommonExtensions.kt +++ b/org.lflang/src/org/lflang/CommonExtensions.kt @@ -24,6 +24,8 @@ package org.lflang +import java.util.Locale + /** * Parse and return an integer from this string, much * like [String.toIntOrNull], but allows any radix. @@ -75,3 +77,19 @@ internal fun String.withoutQuotes(): String { * of members is used. Space must be irrelevant. */ internal fun List.joinWithCommas() = joinToString(", ") { it } + + +/** + * Convert a string in Camel case to snake case. E.g. + * `MinimalReactor` will be converted to `minimal_reactor`. + * The string is assumed to be a single camel case identifier + * (no whitespace). + */ +fun String.camelToSnakeCase():String { + val words = this.split(Regex("(? Date: Thu, 15 Jul 2021 15:32:14 +0200 Subject: [PATCH 046/252] Make executable name snake case Refs rust-lang/rust#45127 --- .../src/org/lflang/tests/runtime/TestBase.xtend | 6 ++++++ org.lflang/src/org/lflang/generator/rust/RustGenerator.kt | 4 +++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/org.lflang.tests/src/org/lflang/tests/runtime/TestBase.xtend b/org.lflang.tests/src/org/lflang/tests/runtime/TestBase.xtend index e73b7be447..e9f4123e30 100644 --- a/org.lflang.tests/src/org/lflang/tests/runtime/TestBase.xtend +++ b/org.lflang.tests/src/org/lflang/tests/runtime/TestBase.xtend @@ -19,6 +19,7 @@ import org.eclipse.xtext.validation.CheckMode import org.eclipse.xtext.validation.IResourceValidator import org.eclipse.xtext.xbase.lib.Functions.Function1 import org.lflang.ASTUtils +import org.lflang.CommonExtensionsKt import org.lflang.FileConfig import org.lflang.Target import org.lflang.generator.StandaloneContext @@ -345,6 +346,11 @@ abstract class TestBase { case Rust: { val binPath = test.fileConfig.binPath var binaryName = nameOnly + if (test.target == Target.Rust) { + // Rust exec names are snake case, otherwise we get a cargo warning + // https://github.com/rust-lang/rust/issues/45127 + binaryName = CommonExtensionsKt.camelToSnakeCase(binaryName) + } // Adjust binary extension if running on Window if (System.getProperty("os.name").startsWith("Windows")) { binaryName = nameOnly + ".exe" diff --git a/org.lflang/src/org/lflang/generator/rust/RustGenerator.kt b/org.lflang/src/org/lflang/generator/rust/RustGenerator.kt index 01aab8ecb3..74bf1760cf 100644 --- a/org.lflang/src/org/lflang/generator/rust/RustGenerator.kt +++ b/org.lflang/src/org/lflang/generator/rust/RustGenerator.kt @@ -77,7 +77,9 @@ class RustGenerator(fileConfig: RustFileConfig, errorReporter: ErrorReporter) : ), reactors = reactors, mainReactor = mainReactor, - executableName = mainReactor.lfName + // Rust exec names are snake case, otherwise we get a cargo warning + // https://github.com/rust-lang/rust/issues/45127 + executableName = mainReactor.lfName.camelToSnakeCase() ) } From a9b602084ccfae01ed56ded1d995e8c7320947a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Thu, 15 Jul 2021 15:36:52 +0200 Subject: [PATCH 047/252] Cleanup an extension about FileConfig --- org.lflang/src/org/lflang/FileConfig.java | 10 ---------- org.lflang/src/org/lflang/FileConfigExtensions.kt | 7 +++++-- .../src/org/lflang/generator/cpp/CppGenerator.kt | 2 +- .../src/org/lflang/generator/rust/RustGenerator.kt | 3 ++- 4 files changed, 8 insertions(+), 14 deletions(-) diff --git a/org.lflang/src/org/lflang/FileConfig.java b/org.lflang/src/org/lflang/FileConfig.java index 1b8c618bc7..10a770d90f 100644 --- a/org.lflang/src/org/lflang/FileConfig.java +++ b/org.lflang/src/org/lflang/FileConfig.java @@ -354,16 +354,6 @@ private static Path getSubPkgPath(Path pkgPath, Path srcPath) { } return relSrcPath; } - - /** - * Create nested directories if the given path does not exist. - */ - public static void createDirectories(Path path) { - File file = path.toFile(); - if (!file.exists()) { - file.mkdirs(); - } - } /** * Check if a clean was requested from the standalone compiler and perform diff --git a/org.lflang/src/org/lflang/FileConfigExtensions.kt b/org.lflang/src/org/lflang/FileConfigExtensions.kt index 25486dce7a..416dd0ec51 100644 --- a/org.lflang/src/org/lflang/FileConfigExtensions.kt +++ b/org.lflang/src/org/lflang/FileConfigExtensions.kt @@ -25,6 +25,7 @@ package org.lflang import org.eclipse.emf.ecore.resource.Resource +import java.nio.file.Files import java.nio.file.Path /** @@ -43,7 +44,9 @@ fun Resource.toPath() = FileConfig.toPath(this) fun Path.toUnixString(): String = FileConfig.toUnixString(this) /** - * Create nested directories if the given path does not exist. + * Create parent directories if they do not exist. */ -fun Path.createDirectories() = FileConfig.createDirectories(this) +fun Path.createDirectories() { + parent?.let(Files::createDirectories) +} diff --git a/org.lflang/src/org/lflang/generator/cpp/CppGenerator.kt b/org.lflang/src/org/lflang/generator/cpp/CppGenerator.kt index 0580e97ec2..5025ab0f44 100644 --- a/org.lflang/src/org/lflang/generator/cpp/CppGenerator.kt +++ b/org.lflang/src/org/lflang/generator/cpp/CppGenerator.kt @@ -126,7 +126,7 @@ class CppGenerator(private val cppFileConfig: CppFileConfig, errorReporter: Erro val reactorCppPath = outPath.resolve("build").resolve("reactor-cpp") // make sure the build directory exists - FileConfig.createDirectories(buildPath) + buildPath.createDirectories() val cores = Runtime.getRuntime().availableProcessors() diff --git a/org.lflang/src/org/lflang/generator/rust/RustGenerator.kt b/org.lflang/src/org/lflang/generator/rust/RustGenerator.kt index 74bf1760cf..cc3bdd25b0 100644 --- a/org.lflang/src/org/lflang/generator/rust/RustGenerator.kt +++ b/org.lflang/src/org/lflang/generator/rust/RustGenerator.kt @@ -53,7 +53,7 @@ class RustGenerator(fileConfig: RustFileConfig, errorReporter: ErrorReporter) : return } - FileConfig.createDirectories(fileConfig.srcGenPath) + fileConfig.srcGenPath.createDirectories() val gen = makeGenerationInfo(resource, fsa, context) RustEmitter.generateFiles(fileConfig as RustFileConfig, gen) @@ -67,6 +67,7 @@ class RustGenerator(fileConfig: RustFileConfig, errorReporter: ErrorReporter) : private fun makeGenerationInfo(resource: Resource, fsa: IFileSystemAccess2, context: IGeneratorContext): GenerationInfo { val reactors = makeReactorInfos() + // todo how do we pick the main reactor? it seems like super.doGenerate sets that field... val mainReactor = reactors.lastOrNull { it.isMain } ?: reactors.last() return GenerationInfo( From 506c26e57bac1063cc9ee9c492253e085fc4f13c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Thu, 15 Jul 2021 15:55:38 +0200 Subject: [PATCH 048/252] Update rust lib --- org.lflang/src/lib/Rust/reactor-rust | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/org.lflang/src/lib/Rust/reactor-rust b/org.lflang/src/lib/Rust/reactor-rust index 29fff413dc..99d5ddf29e 160000 --- a/org.lflang/src/lib/Rust/reactor-rust +++ b/org.lflang/src/lib/Rust/reactor-rust @@ -1 +1 @@ -Subproject commit 29fff413dc4ef7246e14f6698438c3ad1259838e +Subproject commit 99d5ddf29e30fa72966e0ebeee472043319ea83a From 2ecb5751c629d907c450e8ac9c3a224d2fcdd6ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Thu, 15 Jul 2021 16:11:46 +0200 Subject: [PATCH 049/252] Doc --- .../org/lflang/generator/rust/RustEmitter.kt | 18 +- .../lflang/generator/rust/RustGenerator.kt | 66 ++----- .../org/lflang/generator/rust/RustModel.kt | 184 +++++++++++++++--- 3 files changed, 181 insertions(+), 87 deletions(-) diff --git a/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt b/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt index 1e2c395680..fa5f177282 100644 --- a/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt +++ b/org.lflang/src/org/lflang/generator/rust/RustEmitter.kt @@ -24,10 +24,8 @@ package org.lflang.generator.rust -import org.lflang.camelToSnakeCase import org.lflang.generator.PrependOperator import org.lflang.generator.rust.RustEmitter.rsRuntime -import org.lflang.joinWithCommas import org.lflang.withDQuotes import java.time.LocalDateTime @@ -95,7 +93,7 @@ ${" | "..otherComponents.joinToString(",\n") { it.toStructField() |impl $rsRuntime::ReactorDispatcher for $dispatcherName { | type ReactionId = $reactionIdName; | type Wrapped = $structName; - | type Params = (${ctorParamTypes.joinWithCommas()}); + | type Params = $ctorParamsTupleType; | | | fn assemble(_params: Self::Params) -> Self { @@ -186,7 +184,7 @@ ${" | "..reactions.joinToString(",\n") { it.invokerId }} list.joinToString(", ", "vec![", "]") { it.invokerId + ".clone()" } return reactor.otherComponents.joinToString(",\n") { - "statemut.${it.name}.set_downstream(${vecOfReactions(reactor.influencedReactionsOf(it))}.into());" + "statemut.${it.lfName}.set_downstream(${vecOfReactions(reactor.influencedReactionsOf(it))}.into());" } } @@ -275,9 +273,9 @@ private object ReactorComponentEmitter { fun ReactorComponent.toBorrow() = when (this) { is PortData -> - if (isInput) "&self.$name" - else "&mut self.$name" - is ActionData -> "&self.$name" + if (isInput) "&self.$lfName" + else "&mut self.$lfName" + is ActionData -> "&self.$lfName" } fun ReactorComponent.toBorrowedType() = @@ -294,12 +292,12 @@ private object ReactorComponentEmitter { } fun ReactorComponent.toFieldInitializer() = when (this) { - is ActionData -> toType() + " (None, ${name.withDQuotes()})" + is ActionData -> toType() + " (None, ${lfName.withDQuotes()})" else -> "Default::default()" } fun ReactorComponent.toStructField() = - "$name: ${toType()}" + "$lfName: ${toType()}" fun ReactionInfo.reactionInvokerInitializer() = "let $invokerId = new_reaction!(this_reactor, reaction_id, _rstate, $rustId);" @@ -318,7 +316,7 @@ ${" | "..body} } private fun ReactionInfo.reactionParams() = - depends.joinToString(", ") { "${it.name}: ${it.toBorrowedType()}" } + depends.joinToString(", ") { "${it.lfName}: ${it.toBorrowedType()}" } } diff --git a/org.lflang/src/org/lflang/generator/rust/RustGenerator.kt b/org.lflang/src/org/lflang/generator/rust/RustGenerator.kt index cc3bdd25b0..680352e15f 100644 --- a/org.lflang/src/org/lflang/generator/rust/RustGenerator.kt +++ b/org.lflang/src/org/lflang/generator/rust/RustGenerator.kt @@ -37,7 +37,17 @@ import org.lflang.lf.Reaction import org.lflang.lf.VarRef /** - * Generates Rust code. + * Generator for the Rust target language. The generation is + * organized around a sort of intermediate representation + * that is constructed from the AST in a first step, then + * handed off to the [RustEmitter]. This makes the emitter + * simpler, as it takes fewer design decisions. This is also + * meant to make it easier to port the emitter to a bunch of + * templates written in a template language like Velocity. + * + * See [GenerationInfo] for the main model class. + * + * @author Clément Fournier */ class RustGenerator(fileConfig: RustFileConfig, errorReporter: ErrorReporter) : GeneratorBase(fileConfig, errorReporter) { @@ -53,10 +63,12 @@ class RustGenerator(fileConfig: RustFileConfig, errorReporter: ErrorReporter) : return } + val fileConfig = fileConfig as RustFileConfig + fileConfig.srcGenPath.createDirectories() - val gen = makeGenerationInfo(resource, fsa, context) - RustEmitter.generateFiles(fileConfig as RustFileConfig, gen) + val gen = RustModelBuilder.makeGenerationInfo(this.reactors) + RustEmitter.generateFiles(fileConfig, gen) if (targetConfig.noCompile || errorsOccurred()) { println("Exiting before invoking target compiler.") @@ -65,54 +77,6 @@ class RustGenerator(fileConfig: RustFileConfig, errorReporter: ErrorReporter) : } } - private fun makeGenerationInfo(resource: Resource, fsa: IFileSystemAccess2, context: IGeneratorContext): GenerationInfo { - val reactors = makeReactorInfos() - // todo how do we pick the main reactor? it seems like super.doGenerate sets that field... - val mainReactor = reactors.lastOrNull { it.isMain } ?: reactors.last() - - return GenerationInfo( - crate = CrateInfo( - name = mainReactor.lfName.camelToSnakeCase(), - version = "1.0.0", - authors = listOf(System.getProperty("user.name")) - ), - reactors = reactors, - mainReactor = mainReactor, - // Rust exec names are snake case, otherwise we get a cargo warning - // https://github.com/rust-lang/rust/issues/45127 - executableName = mainReactor.lfName.camelToSnakeCase() - ) - } - - private fun makeReactorInfos() = reactors.map { reactor -> - val components = mutableMapOf() - for (component in reactor.allOutputs + reactor.allInputs + reactor.allActions) { - val irObj = ReactorComponent.from(component) ?: continue - components[irObj.name] = irObj - } - - val reactions = reactor.reactions.map { n: Reaction -> - val dependencies = (n.effects + n.sources).mapTo(LinkedHashSet()) { components[it.name]!! } - ReactionInfo( - idx = n.indexInContainer, - depends = dependencies, - body = n.code.toText(), - isStartup = n.triggers.any { it.isStartup }, - isShutdown = n.triggers.any { it.isShutdown } - ) - } - - ReactorInfo( - lfName = reactor.name, - reactions = reactions, - otherComponents = components.values.toList(), - isMain = reactor.isMain, - preambles = reactor.preambles.map { it.code.toText() }, - stateVars = reactor.stateVars.map { StateVarInfo(it.name, it.targetType, init = it.init.singleOrNull()?.toText()) } - ) - } - - private fun invokeRustCompiler() { val cargoBuilder = createCommand( "cargo", listOf( diff --git a/org.lflang/src/org/lflang/generator/rust/RustModel.kt b/org.lflang/src/org/lflang/generator/rust/RustModel.kt index a3d07240f9..f627a94613 100644 --- a/org.lflang/src/org/lflang/generator/rust/RustModel.kt +++ b/org.lflang/src/org/lflang/generator/rust/RustModel.kt @@ -25,17 +25,13 @@ package org.lflang.generator.rust +import org.lflang.* +import org.lflang.generator.cpp.name import org.lflang.generator.cpp.targetType -import org.lflang.isInput -import org.lflang.isLogical import org.lflang.lf.* import java.util.* -/* - Model classes that serve as "intermediary representation" between the rust generator and emitter. - */ - - +/** Root model class for the entire generation. */ data class GenerationInfo( val crate: CrateInfo, val reactors: List, @@ -43,47 +39,106 @@ data class GenerationInfo( val executableName: String ) +/** + * Model class for a reactor class. This will be emitted as + * several structs in a Rust module. + */ data class ReactorInfo( + /** Name of the reactor in LF. By LF conventions, this is a PascalCase identifier. */ val lfName: String, - val reactions: List, + /** Whether this is the main reactor. */ val isMain: Boolean, + /** A list of reactions, in order of their [ReactionInfo.idx]. */ + val reactions: List, + /** List of state variables. */ + val stateVars: List, + /** Other reactor components, like actions & timers. */ val otherComponents: List, - val ctorParamTypes: List = emptyList(), + /** List of ctor parameters. */ + val ctorParams: List = emptyList(), + /** List of preambles, will be outputted at the top of the file. */ val preambles: List, - val stateVars: List ) { - val modName = lfName.toLowerCase(Locale.ROOT) // note: toLowercase is deprecated in kotlin 1.5.0 + /** Name of the rust module (also of its containing file). */ + val modName = lfName.camelToSnakeCase() + + /** Name of the "user struct", which contains state + * variables as fields, and which the user manipulates in reactions. + */ val structName get() = lfName + + // Names of other implementation-detailistic structs. + val dispatcherName = "${structName}Dispatcher" val assemblerName = "${structName}Assembler" val reactionIdName = "${structName}Reactions" + + val ctorParamsTupleType: @TargetCode String + get() = "(${ctorParams.map { it.type }.joinWithCommas()})" } -data class StateVarInfo(val lfName: String, val type: String, val init: String?) +/** + * Model class for the parameters of a reactor constructor. + */ +data class CtorParamInfo( + val lfName: String, + val type: @TargetCode String, + val defaultValue: (@TargetCode String)? +) + +/** Model class for a state variable. */ +data class StateVarInfo( + /** + * Identifier of the state var. From within a reaction + * body, the state var is accessible as a field with type + * [type] declared on the `self` struct. + */ + val lfName: String, + /** Rust static type of the struct field. Must be `Sized`. */ + val type: @TargetCode String, + /** + * The field initializer, a Rust expression. If null, + * will default to `Default::default()`. + */ + val init: (@TargetCode String)? +) +/** + * Model class for a single reaction. + */ data class ReactionInfo( /** Index in the containing reactor. */ val idx: Int, - /** The ID of the reaction in the reaction enum. */ - val rustId: String = "R$idx", - /** The name of the worker function for this reaction. */ - val workerId: String = "react_$idx", - /** The name of the ReactionInvoker field for this reaction. */ - val invokerId: String = "react_$idx", + /** Target code for the reaction body. */ + val body: @TargetCode String, /** Dependencies declared by the reaction, which are served to the worker function. */ val depends: Set, - /** Target code for the reaction body. */ - val body: String, /** Whether the reaction is triggered by the startup event. */ val isStartup: Boolean, /** Whether the reaction is triggered by the shutdown event. */ val isShutdown: Boolean, -) +) { + // those are implementation details + + /** The ID of the reaction in the reaction enum. */ + val rustId: String = "R$idx" + + /** The name of the worker function for this reaction. */ + val workerId: String = "react_$idx" + /** The name of the `ReactionInvoker` field for this reaction. */ + val invokerId: String = "react_$idx" +} +/** + * Metadata about the generated crate. Mostly doesn't matter. + */ data class CrateInfo( + /** Name of the crate. According to Rust conventions this should be a snake_case name. */ val name: String, + /** Version of the crate. */ val version: String, + /** List of names of the credited authors. */ val authors: List, ) @@ -100,7 +155,7 @@ TODO do we really need the following classes? sealed class ReactorComponent { - abstract val name: String + abstract val lfName: String companion object { /** @@ -109,8 +164,8 @@ sealed class ReactorComponent { * have another interface. */ fun from(v: Variable): ReactorComponent? = when (v) { - is Port -> PortData(name = v.name, isInput = v.isInput, dataType = v.targetType) - is Action -> ActionData(name = v.name, isLogical = v.isLogical) + is Port -> PortData(lfName = v.name, isInput = v.isInput, dataType = v.targetType) + is Action -> ActionData(lfName = v.name, isLogical = v.isLogical) else -> TODO("Unsupported: ${v.javaClass.simpleName} $v") } } @@ -119,7 +174,84 @@ sealed class ReactorComponent { /** * @property dataType A piece of target code */ -data class PortData(override val name: String, val isInput: Boolean, val dataType: String) : ReactorComponent() +data class PortData( + override val lfName: String, + val isInput: Boolean, + /** Rust data type of the code. */ + val dataType: @TargetCode String +) : ReactorComponent() + +data class ActionData( + override val lfName: String, + val isLogical: Boolean +) : ReactorComponent() + +@Target(AnnotationTarget.TYPE) +@MustBeDocumented +@Retention(AnnotationRetention.SOURCE) +annotation class TargetCode + +/** + * Produce model classes from the AST. + */ +object RustModelBuilder { + + /** + * Given the input to the generator, produce the model classes. + */ + fun makeGenerationInfo(reactors: List): GenerationInfo { + val reactorsInfos = makeReactorInfos(reactors) + // todo how do we pick the main reactor? it seems like super.doGenerate sets that field... + val mainReactor = reactorsInfos.lastOrNull { it.isMain } ?: reactorsInfos.last() + + return GenerationInfo( + crate = CrateInfo( + name = mainReactor.lfName.camelToSnakeCase(), + version = "1.0.0", + authors = listOf(System.getProperty("user.name")) + ), + reactors = reactorsInfos, + mainReactor = mainReactor, + // Rust exec names are snake case, otherwise we get a cargo warning + // https://github.com/rust-lang/rust/issues/45127 + executableName = mainReactor.lfName.camelToSnakeCase() + ) + } + + private fun makeReactorInfos(reactors: List): List = + reactors.map { reactor -> + val components = mutableMapOf() + for (component in reactor.allOutputs + reactor.allInputs + reactor.allActions) { + val irObj = ReactorComponent.from(component) ?: continue + components[irObj.lfName] = irObj + } + + val reactions = reactor.reactions.map { n: Reaction -> + val dependencies = (n.effects + n.sources).mapTo(LinkedHashSet()) { components[it.name]!! } + ReactionInfo( + idx = n.indexInContainer, + depends = dependencies, + body = n.code.toText(), + isStartup = n.triggers.any { it.isStartup }, + isShutdown = n.triggers.any { it.isShutdown } + ) + } + + ReactorInfo( + lfName = reactor.name, + reactions = reactions, + otherComponents = components.values.toList(), + isMain = reactor.isMain, + preambles = reactor.preambles.map { it.code.toText() }, + stateVars = reactor.stateVars.map { + StateVarInfo( + it.name, + it.targetType, + init = it.init.singleOrNull()?.toText() + ) + } + ) + } +} -data class ActionData(override val name: String, val isLogical: Boolean) : ReactorComponent() From b2ad10756129ce27dd81e179c2320e5d758e5f4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Thu, 15 Jul 2021 16:48:02 +0200 Subject: [PATCH 050/252] More cleanups of models Model supports nested instantiations now, but parameter handling is still todo --- .idea/inspectionProfiles/Project_Default.xml | 3 + .../org/lflang/generator/rust/RustEmitter.kt | 11 ++- .../org/lflang/generator/rust/RustModel.kt | 80 ++++++++++++------- 3 files changed, 64 insertions(+), 30 deletions(-) diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml index 301ba19aa5..8a4c13d6e2 100644 --- a/.idea/inspectionProfiles/Project_Default.xml +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -37,6 +37,9 @@