From 15e76919dc74635a7917fc8ce35ef5dfe55e583e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Wed, 21 Apr 2021 16:38:15 +0200 Subject: [PATCH 01/88] Ignore idea config files --- .gitignore | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 0156b6bf42..fc89d55bb5 100644 --- a/.gitignore +++ b/.gitignore @@ -14,4 +14,8 @@ **/test-bin/ **/src-gen/ **/xtend-gen/ -**/.vscode/ \ No newline at end of file +**/.vscode/ +.idea +test/Cpp/include +test/Cpp/share +test/Cpp/lib From 49cc63a282769ae61d9037b8808ba7b29032c625 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Wed, 21 Apr 2021 18:16:34 +0200 Subject: [PATCH 02/88] Configure kotlin compiler alongside java --- build.gradle | 9 ++++++++- gradle/source-layout.gradle | 3 +++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index bfa33272e4..bfd17a2b93 100644 --- a/build.gradle +++ b/build.gradle @@ -4,11 +4,12 @@ buildscript { } dependencies { classpath 'org.xtext:xtext-gradle-plugin:2.0.8' + classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.4.32' } } plugins { - id "com.github.johnrengelman.shadow" version "6.0.0" + id 'com.github.johnrengelman.shadow' version '6.0.0' id 'java' id 'jacoco' } @@ -19,7 +20,13 @@ subprojects { mavenCentral() } + apply plugin: 'kotlin' apply plugin: 'java' + compileJava.dependsOn(compileKotlin) + compileKotlin { + destinationDir = compileJava.destinationDir + } + dependencies { implementation platform("org.eclipse.xtext:xtext-dev-bom:${xtextVersion}") // https://mvnrepository.com/artifact/com.google.inject/guice diff --git a/gradle/source-layout.gradle b/gradle/source-layout.gradle index d0f730b2e3..32a778fef1 100644 --- a/gradle/source-layout.gradle +++ b/gradle/source-layout.gradle @@ -2,10 +2,12 @@ if (name.endsWith(".tests")) { sourceSets { main { java.srcDirs = [] + kotlin.srcDirs = [] resources.srcDirs = [] } test { java.srcDirs = ['src', 'src-gen'] + kotlin.srcDirs = ['src', 'src-gen'] resources.srcDirs = ['src', 'src-gen'] xtendOutputDir = 'xtend-gen' } @@ -14,6 +16,7 @@ if (name.endsWith(".tests")) { sourceSets { main { java.srcDirs = ['src', 'src-gen'] + kotlin.srcDirs = ['src', 'src-gen', 'xtend-gen'] resources.srcDirs = ['src', 'src-gen'] xtendOutputDir = 'xtend-gen' } From 0827336042189e2faa463e03d48abefe0e65c499 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Wed, 21 Apr 2021 18:24:35 +0200 Subject: [PATCH 03/88] wip convert a file to kotlin --- .../org/lflang/generator/MultiportInstance.kt | 108 +++++++++++++++++ .../lflang/generator/MultiportInstance.xtend | 111 ------------------ 2 files changed, 108 insertions(+), 111 deletions(-) create mode 100644 org.lflang/src/org/lflang/generator/MultiportInstance.kt delete mode 100644 org.lflang/src/org/lflang/generator/MultiportInstance.xtend diff --git a/org.lflang/src/org/lflang/generator/MultiportInstance.kt b/org.lflang/src/org/lflang/generator/MultiportInstance.kt new file mode 100644 index 0000000000..49a2af84ca --- /dev/null +++ b/org.lflang/src/org/lflang/generator/MultiportInstance.kt @@ -0,0 +1,108 @@ +/* + * 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.generator + +import org.lflang.lf.Port + + +/** Representation of a runtime instance of a multiport. + * This contains an array of ports. + * + * @constructor Create a runtime instance from the specified definition + * and with the specified parent that instantiated it. + * @param definition The definition node in the AST. + * @param parent The parent. + * @param generator The generator (for error reporting). + * + * @author{Edward A. Lee } + */ +class MultiportInstance( + definition: Port, + parent: ReactorInstance, + generator: GeneratorBase +) : PortInstance(definition, parent) { + + /** The array of instances. */ + // todo does this need to be public mutable? + val instances = mutableListOf() + + init { + + if (definition.widthSpec == null) { + throw Exception("Port appears to not be a multiport: " + definition.name) + } + + if (definition.widthSpec.isOfVariableLength) { + generator.reportError(definition, "Variable-width multiports not supported (yet): " + definition.name) + } else { + // The width may be given by a parameter or even sum of parameters. + var width = 0 + for (term in definition.widthSpec.terms) { + if (term.parameter != null) { + val parameterValue = parent.initialIntParameterValue(term.parameter) + // Only a Literal is supported. + if (parameterValue != null) { + // This could throw NumberFormatException + width += parameterValue + } else { + generator.reportError(definition, "Width of a multiport must be given as an integer.") + } + } else { + width += term.width + } + } + + for (i in 0..width) { + val instancePort = PortInstance(definition, parent, i, this) + instances.add(instancePort) + // Inputs arriving at the instance port trigger the reactions + // that depend on the multiport. + instancePort.dependentReactions = this.dependentReactions + // Reactions that declare that they may send outputs via + // this port are able to send on any of the instances. + instancePort.dependsOnReactions = this.dependsOnReactions + } + } + } + + + /** Return the specified port instance in this multiport. */ + fun getInstance(position: Int): PortInstance = this[position] + + /** Return the specified port instance in this multiport. */ + operator fun get(index: Int): PortInstance { + if (index !in 0..width) { + throw IndexOutOfBoundsException("Port index out of range $index.") + } + return instances[index] + } + + + /** Return the width of this port, which is the size of the instances list. */ + val width get() = instances.size + +} diff --git a/org.lflang/src/org/lflang/generator/MultiportInstance.xtend b/org.lflang/src/org/lflang/generator/MultiportInstance.xtend deleted file mode 100644 index 71d9db93a0..0000000000 --- a/org.lflang/src/org/lflang/generator/MultiportInstance.xtend +++ /dev/null @@ -1,111 +0,0 @@ -/** A data structure for a multiport instance. */ - -/************* -Copyright (c) 2019, The University of California at Berkeley. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL -THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF -THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -***************/ -package org.lflang.generator - -import java.util.ArrayList -import org.lflang.lf.Port - -/** Representation of a runtime instance of a multiport. - * This contains an array of ports. - * - * @author{Edward A. Lee } - */ -class MultiportInstance extends PortInstance { - - /** Create a runtime instance from the specified definition - * and with the specified parent that instantiated it. - * @param instance The Instance statement in the AST. - * @param parent The parent. - * @param generator The generator (for error reporting). - */ - new(Port definition, ReactorInstance parent, GeneratorBase generator) { - super(definition, parent) - - if (definition.widthSpec === null) { - throw new Exception("Port appears to not be a multiport: " + definition.name) - } - - if (definition.widthSpec.ofVariableLength) { - generator.reportError(definition, - "Variable-width multiports not supported (yet): " + definition.name) - return - } - - // The width may be given by a parameter or even sum of parameters. - var width = 0 - for (term : definition.widthSpec.terms) { - if (term.parameter !== null) { - val parameterValue = parent.initialIntParameterValue(term.parameter) - // Only a Literal is supported. - if (parameterValue !== null) { - // This could throw NumberFormatException - width += parameterValue - } else { - generator.reportError(definition, - "Width of a multiport must be given as an integer. It is: " - + parameterValue - ) - } - } else { - width += term.width - } - } - - for (var i = 0; i < width; i++) { - val instancePort = new PortInstance(definition, parent, i, this) - instances.add(instancePort) - // Inputs arriving at the instance port trigger the reactions - // that depend on the multiport. - instancePort.dependentReactions = this.dependentReactions - // Reactions that declare that they may send outputs via - // this port are able to send on any of the instances. - instancePort.dependsOnReactions = this.dependsOnReactions - } - } - - /** - * Return the specified port instance in this multiport. - */ - def getInstance(int position) { - if (position < 0 || position >= instances.size) { - throw new Exception("Port index out of range.") - } - return instances.get(position) - } - - /** - * Return the width of this port, which is the size of the instances list. - */ - def getWidth() { - instances.size - } - - ///////////////////////////////////////////// - //// Public Fields - - /** The array of instances. */ - public val instances = new ArrayList() -} \ No newline at end of file From d2799639e298540bc818a1fc0a3ef457ccf807f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Wed, 21 Apr 2021 18:51:59 +0200 Subject: [PATCH 04/88] Port another --- .../org/lflang/generator/TriggerInstance.kt | 62 +++++++++++ .../lflang/generator/TriggerInstance.xtend | 101 ------------------ 2 files changed, 62 insertions(+), 101 deletions(-) create mode 100644 org.lflang/src/org/lflang/generator/TriggerInstance.kt delete mode 100644 org.lflang/src/org/lflang/generator/TriggerInstance.xtend diff --git a/org.lflang/src/org/lflang/generator/TriggerInstance.kt b/org.lflang/src/org/lflang/generator/TriggerInstance.kt new file mode 100644 index 0000000000..71fe621bc5 --- /dev/null +++ b/org.lflang/src/org/lflang/generator/TriggerInstance.kt @@ -0,0 +1,62 @@ +/* + * 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.generator + +import org.lflang.lf.Variable + +/** Instance of a trigger (port, action, or timer). + * + * @constructor Construct a new instance with the specified definition + * and parent. E.g., for a action instance, the definition + * is Action, and for a port instance, it is Port. These are + * nodes in the AST. This is protected because only subclasses + * should be constructed. + * + * @param definition The definition in the AST for this instance. + * @param parent The reactor instance that creates this instance. + * + * @author{Marten Lohstroh } + * @author{Edward A. Lee } + */ +open class TriggerInstance(definition: Variable, parent: ReactorInstance) : NamedInstance(definition, parent) { + + /** Reaction instances that are triggered by this trigger. */ + var dependentReactions = LinkedHashSet() + + /** Reaction instances that may send outputs via this port. */ + var dependsOnReactions = LinkedHashSet() // FIXME: Perhaps better to use a TreeSet here + + override fun getName(): String = this.definition.name + override fun main(): ReactorInstance = parent.main() + + /** Return true if this trigger is "shutdown". */ + var isShutdown: Boolean = false + protected set + + /** Return true if this trigger is "startup". */ + var isStartup: Boolean = false + protected set + +} diff --git a/org.lflang/src/org/lflang/generator/TriggerInstance.xtend b/org.lflang/src/org/lflang/generator/TriggerInstance.xtend deleted file mode 100644 index a2557fd7ad..0000000000 --- a/org.lflang/src/org/lflang/generator/TriggerInstance.xtend +++ /dev/null @@ -1,101 +0,0 @@ -/** Instance of a trigger (port, action, or timer). */ - -/************* -Copyright (c) 2019, The University of California at Berkeley. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL -THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF -THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -***************/ - -package org.lflang.generator - -import java.util.LinkedHashSet -import org.lflang.lf.Variable - -/** Instance of a trigger (port, action, or timer). - * - * @author{Marten Lohstroh } - * @author{Edward A. Lee } - */ -class TriggerInstance extends NamedInstance { - - /** Construct a new instance with the specified definition - * and parent. E.g., for a action instance, the definition - * is Action, and for a port instance, it is Port. These are - * nodes in the AST. This is protected because only subclasses - * should be constructed. - * @param definition The definition in the AST for this instance. - * @param parent The reactor instance that creates this instance. - */ - protected new(Variable definition, ReactorInstance parent) { - super(definition, parent) - } - - ///////////////////////////////////////////// - //// Public Fields - - /** Reaction instances that are triggered by this trigger. */ - public var dependentReactions = new LinkedHashSet(); - - /** Reaction instances that may send outputs via this port. */ - public var dependsOnReactions = new LinkedHashSet(); // FIXME: Perhaps better to use a TreeSet here - - ///////////////////////////////////////////// - //// Public Methods - - /** - * Return the name of this trigger. - * @return The name of this trigger. - */ - override getName() { - this.definition.name - } - - /** - * Return true if this trigger is "shutdown"./ - */ - def isShutdown() { - this.shutdown - } - - /** - * Return true if this trigger is "startup"./ - */ - def isStartup() { - this.startup - } - - /** Return the main reactor, which is the top-level parent. - * @return The top-level parent. - */ - override ReactorInstance main() { - this.parent.main - } - - /** - * Return true if this trigger is "startup". - */ - - ///////////////////////////////////////////// - //// Protected Fields - - protected var startup = false; - protected var shutdown = false; -} From 41781007b41757414721d8c7104d732a84d46da5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Wed, 21 Apr 2021 19:06:52 +0200 Subject: [PATCH 05/88] Generate Xtend sources before kotlin compilation Problem is, Xtend sources do not see the Kotlin classes. I assume the Xtend actually integrates a Java compiler and can compile mixed codebases of Java+Xtend. The Kotlin compiler does the same. But mixing both introduces a circular dependency. --- build.gradle | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index bfd17a2b93..1d2031417b 100644 --- a/build.gradle +++ b/build.gradle @@ -38,7 +38,10 @@ subprojects { apply plugin: 'org.xtext.xtend' apply from: "${rootDir}/gradle/source-layout.gradle" apply plugin: 'eclipse' - + + // generate xtend sources before kotlin compilation + compileKotlin.dependsOn("generateXtext") + group = 'org.lflang' version = '1.0.0-SNAPSHOT' From c92b19e5c2db42e1dbe8469226c2b732446c7d90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Wed, 21 Apr 2021 19:36:11 +0200 Subject: [PATCH 06/88] Revert "Port another" This reverts commit d2799639e298540bc818a1fc0a3ef457ccf807f2. --- .../org/lflang/generator/TriggerInstance.kt | 62 ----------- .../lflang/generator/TriggerInstance.xtend | 101 ++++++++++++++++++ 2 files changed, 101 insertions(+), 62 deletions(-) delete mode 100644 org.lflang/src/org/lflang/generator/TriggerInstance.kt create mode 100644 org.lflang/src/org/lflang/generator/TriggerInstance.xtend diff --git a/org.lflang/src/org/lflang/generator/TriggerInstance.kt b/org.lflang/src/org/lflang/generator/TriggerInstance.kt deleted file mode 100644 index 71fe621bc5..0000000000 --- a/org.lflang/src/org/lflang/generator/TriggerInstance.kt +++ /dev/null @@ -1,62 +0,0 @@ -/* - * 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.generator - -import org.lflang.lf.Variable - -/** Instance of a trigger (port, action, or timer). - * - * @constructor Construct a new instance with the specified definition - * and parent. E.g., for a action instance, the definition - * is Action, and for a port instance, it is Port. These are - * nodes in the AST. This is protected because only subclasses - * should be constructed. - * - * @param definition The definition in the AST for this instance. - * @param parent The reactor instance that creates this instance. - * - * @author{Marten Lohstroh } - * @author{Edward A. Lee } - */ -open class TriggerInstance(definition: Variable, parent: ReactorInstance) : NamedInstance(definition, parent) { - - /** Reaction instances that are triggered by this trigger. */ - var dependentReactions = LinkedHashSet() - - /** Reaction instances that may send outputs via this port. */ - var dependsOnReactions = LinkedHashSet() // FIXME: Perhaps better to use a TreeSet here - - override fun getName(): String = this.definition.name - override fun main(): ReactorInstance = parent.main() - - /** Return true if this trigger is "shutdown". */ - var isShutdown: Boolean = false - protected set - - /** Return true if this trigger is "startup". */ - var isStartup: Boolean = false - protected set - -} diff --git a/org.lflang/src/org/lflang/generator/TriggerInstance.xtend b/org.lflang/src/org/lflang/generator/TriggerInstance.xtend new file mode 100644 index 0000000000..a2557fd7ad --- /dev/null +++ b/org.lflang/src/org/lflang/generator/TriggerInstance.xtend @@ -0,0 +1,101 @@ +/** Instance of a trigger (port, action, or timer). */ + +/************* +Copyright (c) 2019, The University of California at Berkeley. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***************/ + +package org.lflang.generator + +import java.util.LinkedHashSet +import org.lflang.lf.Variable + +/** Instance of a trigger (port, action, or timer). + * + * @author{Marten Lohstroh } + * @author{Edward A. Lee } + */ +class TriggerInstance extends NamedInstance { + + /** Construct a new instance with the specified definition + * and parent. E.g., for a action instance, the definition + * is Action, and for a port instance, it is Port. These are + * nodes in the AST. This is protected because only subclasses + * should be constructed. + * @param definition The definition in the AST for this instance. + * @param parent The reactor instance that creates this instance. + */ + protected new(Variable definition, ReactorInstance parent) { + super(definition, parent) + } + + ///////////////////////////////////////////// + //// Public Fields + + /** Reaction instances that are triggered by this trigger. */ + public var dependentReactions = new LinkedHashSet(); + + /** Reaction instances that may send outputs via this port. */ + public var dependsOnReactions = new LinkedHashSet(); // FIXME: Perhaps better to use a TreeSet here + + ///////////////////////////////////////////// + //// Public Methods + + /** + * Return the name of this trigger. + * @return The name of this trigger. + */ + override getName() { + this.definition.name + } + + /** + * Return true if this trigger is "shutdown"./ + */ + def isShutdown() { + this.shutdown + } + + /** + * Return true if this trigger is "startup"./ + */ + def isStartup() { + this.startup + } + + /** Return the main reactor, which is the top-level parent. + * @return The top-level parent. + */ + override ReactorInstance main() { + this.parent.main + } + + /** + * Return true if this trigger is "startup". + */ + + ///////////////////////////////////////////// + //// Protected Fields + + protected var startup = false; + protected var shutdown = false; +} From 8388a3d65809f2209ceb9be59f302b9044d3dbc1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Wed, 21 Apr 2021 19:51:21 +0200 Subject: [PATCH 07/88] Rewrite kotlin -> java We can rewrite it to kotlin automatically later --- .../lflang/generator/MultiportInstance.java | 109 ++++++++++++++++++ .../org/lflang/generator/MultiportInstance.kt | 108 ----------------- 2 files changed, 109 insertions(+), 108 deletions(-) create mode 100644 org.lflang/src/org/lflang/generator/MultiportInstance.java delete mode 100644 org.lflang/src/org/lflang/generator/MultiportInstance.kt diff --git a/org.lflang/src/org/lflang/generator/MultiportInstance.java b/org.lflang/src/org/lflang/generator/MultiportInstance.java new file mode 100644 index 0000000000..9d21fffaa8 --- /dev/null +++ b/org.lflang/src/org/lflang/generator/MultiportInstance.java @@ -0,0 +1,109 @@ +/* + * 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.generator; + +import org.lflang.lf.Port; +import org.lflang.lf.WidthTerm; + + +/** Representation of a runtime instance of a multiport. + * This contains an array of ports. + * + * @author {Edward A. Lee } + */ +public class MultiportInstance extends PortInstance { + + /** Create a runtime instance from the specified definition + * and with the specified parent that instantiated it. + * @param instance The Instance statement in the AST. + * @param parent The parent. + * @param generator The generator (for error reporting). + */ + MultiportInstance(Port definition, ReactorInstance parent, GeneratorBase generator) { + super(definition, parent); + + if (definition.getWidthSpec() == null) { + throw new Exception("Port appears to not be a multiport: " + definition.getName()); + } + + if (definition.getWidthSpec().isOfVariableLength()) { + generator.reportError(definition, "Variable-width multiports not supported (yet): " + definition.getName()); + return; + } + + // The width may be given by a parameter or even sum of parameters. + int width = 0; + for (WidthTerm term : definition.getWidthSpec().getTerms()) { + if (term.getParameter() != null) { + Integer parameterValue = ASTUtils.initialIntParameterValue(parent, term.getParameter()); + // Only a Literal is supported. + if (parameterValue != null) { + // This could throw NumberFormatException + width += parameterValue; + } else { + generator.reportError(definition, + "Width of a multiport must be given as an integer. It is: " + + parameterValue + ); + } + } else { + width += term.width + } + } + + for (var i = 0; i < width; i++) { + PortInstance instancePort = new PortInstance(definition, parent, i, this); + instances.add(instancePort); + // Inputs arriving at the instance port trigger the reactions + // that depend on the multiport. + instancePort.dependentReactions = this.dependentReactions; + // Reactions that declare that they may send outputs via + // this port are able to send on any of the instances. + instancePort.dependsOnReactions = this.dependsOnReactions; + } + } + + /** + * Return the specified port instance in this multiport. + */ + PortInstance getInstance(int position) { + if (position < 0 || position >= instances.size) { + throw new IndexOutOfBoundsException("Port index out of range."); + } + return instances.get(position); + } + + /** + * Return the width of this port, which is the size of the instances list. + */ + int getWidth() { + return instances.size; + } + + ///////////////////////////////////////////// + //// Public Fields + + /** The array of instances. */ + public List instances = new ArrayList() diff --git a/org.lflang/src/org/lflang/generator/MultiportInstance.kt b/org.lflang/src/org/lflang/generator/MultiportInstance.kt deleted file mode 100644 index 49a2af84ca..0000000000 --- a/org.lflang/src/org/lflang/generator/MultiportInstance.kt +++ /dev/null @@ -1,108 +0,0 @@ -/* - * 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.generator - -import org.lflang.lf.Port - - -/** Representation of a runtime instance of a multiport. - * This contains an array of ports. - * - * @constructor Create a runtime instance from the specified definition - * and with the specified parent that instantiated it. - * @param definition The definition node in the AST. - * @param parent The parent. - * @param generator The generator (for error reporting). - * - * @author{Edward A. Lee } - */ -class MultiportInstance( - definition: Port, - parent: ReactorInstance, - generator: GeneratorBase -) : PortInstance(definition, parent) { - - /** The array of instances. */ - // todo does this need to be public mutable? - val instances = mutableListOf() - - init { - - if (definition.widthSpec == null) { - throw Exception("Port appears to not be a multiport: " + definition.name) - } - - if (definition.widthSpec.isOfVariableLength) { - generator.reportError(definition, "Variable-width multiports not supported (yet): " + definition.name) - } else { - // The width may be given by a parameter or even sum of parameters. - var width = 0 - for (term in definition.widthSpec.terms) { - if (term.parameter != null) { - val parameterValue = parent.initialIntParameterValue(term.parameter) - // Only a Literal is supported. - if (parameterValue != null) { - // This could throw NumberFormatException - width += parameterValue - } else { - generator.reportError(definition, "Width of a multiport must be given as an integer.") - } - } else { - width += term.width - } - } - - for (i in 0..width) { - val instancePort = PortInstance(definition, parent, i, this) - instances.add(instancePort) - // Inputs arriving at the instance port trigger the reactions - // that depend on the multiport. - instancePort.dependentReactions = this.dependentReactions - // Reactions that declare that they may send outputs via - // this port are able to send on any of the instances. - instancePort.dependsOnReactions = this.dependsOnReactions - } - } - } - - - /** Return the specified port instance in this multiport. */ - fun getInstance(position: Int): PortInstance = this[position] - - /** Return the specified port instance in this multiport. */ - operator fun get(index: Int): PortInstance { - if (index !in 0..width) { - throw IndexOutOfBoundsException("Port index out of range $index.") - } - return instances[index] - } - - - /** Return the width of this port, which is the size of the instances list. */ - val width get() = instances.size - -} From f769d486809a7f670db57ed74581de77f795bde9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Wed, 21 Apr 2021 19:52:04 +0200 Subject: [PATCH 08/88] Java -> xtend --- .../lflang/generator/MultiportInstance.java | 109 ----------------- .../lflang/generator/MultiportInstance.xtend | 111 ++++++++++++++++++ 2 files changed, 111 insertions(+), 109 deletions(-) delete mode 100644 org.lflang/src/org/lflang/generator/MultiportInstance.java create mode 100644 org.lflang/src/org/lflang/generator/MultiportInstance.xtend diff --git a/org.lflang/src/org/lflang/generator/MultiportInstance.java b/org.lflang/src/org/lflang/generator/MultiportInstance.java deleted file mode 100644 index 9d21fffaa8..0000000000 --- a/org.lflang/src/org/lflang/generator/MultiportInstance.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * 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.generator; - -import org.lflang.lf.Port; -import org.lflang.lf.WidthTerm; - - -/** Representation of a runtime instance of a multiport. - * This contains an array of ports. - * - * @author {Edward A. Lee } - */ -public class MultiportInstance extends PortInstance { - - /** Create a runtime instance from the specified definition - * and with the specified parent that instantiated it. - * @param instance The Instance statement in the AST. - * @param parent The parent. - * @param generator The generator (for error reporting). - */ - MultiportInstance(Port definition, ReactorInstance parent, GeneratorBase generator) { - super(definition, parent); - - if (definition.getWidthSpec() == null) { - throw new Exception("Port appears to not be a multiport: " + definition.getName()); - } - - if (definition.getWidthSpec().isOfVariableLength()) { - generator.reportError(definition, "Variable-width multiports not supported (yet): " + definition.getName()); - return; - } - - // The width may be given by a parameter or even sum of parameters. - int width = 0; - for (WidthTerm term : definition.getWidthSpec().getTerms()) { - if (term.getParameter() != null) { - Integer parameterValue = ASTUtils.initialIntParameterValue(parent, term.getParameter()); - // Only a Literal is supported. - if (parameterValue != null) { - // This could throw NumberFormatException - width += parameterValue; - } else { - generator.reportError(definition, - "Width of a multiport must be given as an integer. It is: " - + parameterValue - ); - } - } else { - width += term.width - } - } - - for (var i = 0; i < width; i++) { - PortInstance instancePort = new PortInstance(definition, parent, i, this); - instances.add(instancePort); - // Inputs arriving at the instance port trigger the reactions - // that depend on the multiport. - instancePort.dependentReactions = this.dependentReactions; - // Reactions that declare that they may send outputs via - // this port are able to send on any of the instances. - instancePort.dependsOnReactions = this.dependsOnReactions; - } - } - - /** - * Return the specified port instance in this multiport. - */ - PortInstance getInstance(int position) { - if (position < 0 || position >= instances.size) { - throw new IndexOutOfBoundsException("Port index out of range."); - } - return instances.get(position); - } - - /** - * Return the width of this port, which is the size of the instances list. - */ - int getWidth() { - return instances.size; - } - - ///////////////////////////////////////////// - //// Public Fields - - /** The array of instances. */ - public List instances = new ArrayList() diff --git a/org.lflang/src/org/lflang/generator/MultiportInstance.xtend b/org.lflang/src/org/lflang/generator/MultiportInstance.xtend new file mode 100644 index 0000000000..71d9db93a0 --- /dev/null +++ b/org.lflang/src/org/lflang/generator/MultiportInstance.xtend @@ -0,0 +1,111 @@ +/** A data structure for a multiport instance. */ + +/************* +Copyright (c) 2019, The University of California at Berkeley. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***************/ +package org.lflang.generator + +import java.util.ArrayList +import org.lflang.lf.Port + +/** Representation of a runtime instance of a multiport. + * This contains an array of ports. + * + * @author{Edward A. Lee } + */ +class MultiportInstance extends PortInstance { + + /** Create a runtime instance from the specified definition + * and with the specified parent that instantiated it. + * @param instance The Instance statement in the AST. + * @param parent The parent. + * @param generator The generator (for error reporting). + */ + new(Port definition, ReactorInstance parent, GeneratorBase generator) { + super(definition, parent) + + if (definition.widthSpec === null) { + throw new Exception("Port appears to not be a multiport: " + definition.name) + } + + if (definition.widthSpec.ofVariableLength) { + generator.reportError(definition, + "Variable-width multiports not supported (yet): " + definition.name) + return + } + + // The width may be given by a parameter or even sum of parameters. + var width = 0 + for (term : definition.widthSpec.terms) { + if (term.parameter !== null) { + val parameterValue = parent.initialIntParameterValue(term.parameter) + // Only a Literal is supported. + if (parameterValue !== null) { + // This could throw NumberFormatException + width += parameterValue + } else { + generator.reportError(definition, + "Width of a multiport must be given as an integer. It is: " + + parameterValue + ) + } + } else { + width += term.width + } + } + + for (var i = 0; i < width; i++) { + val instancePort = new PortInstance(definition, parent, i, this) + instances.add(instancePort) + // Inputs arriving at the instance port trigger the reactions + // that depend on the multiport. + instancePort.dependentReactions = this.dependentReactions + // Reactions that declare that they may send outputs via + // this port are able to send on any of the instances. + instancePort.dependsOnReactions = this.dependsOnReactions + } + } + + /** + * Return the specified port instance in this multiport. + */ + def getInstance(int position) { + if (position < 0 || position >= instances.size) { + throw new Exception("Port index out of range.") + } + return instances.get(position) + } + + /** + * Return the width of this port, which is the size of the instances list. + */ + def getWidth() { + instances.size + } + + ///////////////////////////////////////////// + //// Public Fields + + /** The array of instances. */ + public val instances = new ArrayList() +} \ No newline at end of file From db430df6e24ac108086494f951323adc395607bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Wed, 21 Apr 2021 20:05:41 +0200 Subject: [PATCH 09/88] Minor refactoring --- org.lflang/src/org/lflang/Target.java | 34 +++++++++++++++---- org.lflang/src/org/lflang/TargetProperty.java | 8 ++--- 2 files changed, 31 insertions(+), 11 deletions(-) diff --git a/org.lflang/src/org/lflang/Target.java b/org.lflang/src/org/lflang/Target.java index dbd59434a2..72c27bd061 100644 --- a/org.lflang/src/org/lflang/Target.java +++ b/org.lflang/src/org/lflang/Target.java @@ -22,6 +22,9 @@ import java.util.Arrays; import java.util.List; +import java.util.stream.Stream; + +import org.jetbrains.annotations.Nullable; /** * Enumeration of targets and their associated properties. These classes are @@ -390,7 +393,7 @@ public final static boolean hasForName(String name) { * @return The matching target (or null if there is none). */ public static Target forName(String name) { - return (Target)Target.match(name, Target.values()); + return Target.match(name, Target.values()); } /** @@ -400,17 +403,34 @@ public static Target forName(String name) { public String toString() { return this.description; } - + /** * Given a string and a list of candidate objects, return the first * candidate that matches, or null if no candidate matches. - * + * + * @param string The string to match against candidates. + * @param candidates The candidates to match the string against. + */ + @Nullable + public static T match(final String string, final Iterable candidates) { + // kotlin: candidates.firstOrNull { it.toString().equalsIgnoreCase(string) } + for (T candidate : candidates) { + if (candidate.toString().equalsIgnoreCase(string)) { + return candidate; + } + } + return null; + } + + /** + * Given a string and a list of candidate objects, return the first + * candidate that matches, or null if no candidate matches. + * * @param string The string to match against candidates. * @param candidates The candidates to match the string against. */ - public static Object match(final String string, final Object[] candidates) { - return Arrays.stream(candidates) - .filter(e -> (e.toString().equalsIgnoreCase(string))) - .findAny().orElse(null); + @Nullable + public static T match(final String string, final T[] candidates) { + return match(string, Arrays.asList(candidates)); } } diff --git a/org.lflang/src/org/lflang/TargetProperty.java b/org.lflang/src/org/lflang/TargetProperty.java index ac67e4af5d..6aec72b4db 100644 --- a/org.lflang/src/org/lflang/TargetProperty.java +++ b/org.lflang/src/org/lflang/TargetProperty.java @@ -345,7 +345,7 @@ public static void update(TargetConfig config, * @param name The string to match against. */ public static TargetProperty forName(String name) { - return (TargetProperty)Target.match(name, TargetProperty.values()); + return Target.match(name, TargetProperty.values()); } /** @@ -378,7 +378,7 @@ public interface DictionaryElement { * A dictionary type with a predefined set of possible keys and assignable * types. * - * @author{Marten Lohstroh } + * @author {Marten Lohstroh } * */ public enum DictionaryType implements TargetPropertyType { @@ -410,7 +410,7 @@ private DictionaryType(List options) { * @return The matching dictionary element (or null if there is none). */ public DictionaryElement forName(String name) { - return (DictionaryElement) Target.match(name, options.toArray()); + return Target.match(name, options); } /** @@ -515,7 +515,7 @@ private UnionType(List> options, Enum defaultOption) { * @return The matching dictionary element (or null if there is none). */ public Enum forName(String name) { - return (Enum) Target.match(name, options.toArray()); + return Target.match(name, options); } /** From 1f2cc68e774f6a7a9555088c231c34637ca8f25e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Wed, 21 Apr 2021 20:11:00 +0200 Subject: [PATCH 10/88] Port one leaf of the dependency graph to kotlin --- .../LFNamesAreUniqueValidationHelper.kt | 50 +++++++++++++++++++ .../LFNamesAreUniqueValidationHelper.xtend | 28 ----------- 2 files changed, 50 insertions(+), 28 deletions(-) create mode 100644 org.lflang/src/org/lflang/validation/LFNamesAreUniqueValidationHelper.kt delete mode 100644 org.lflang/src/org/lflang/validation/LFNamesAreUniqueValidationHelper.xtend diff --git a/org.lflang/src/org/lflang/validation/LFNamesAreUniqueValidationHelper.kt b/org.lflang/src/org/lflang/validation/LFNamesAreUniqueValidationHelper.kt new file mode 100644 index 0000000000..c69865c1b6 --- /dev/null +++ b/org.lflang/src/org/lflang/validation/LFNamesAreUniqueValidationHelper.kt @@ -0,0 +1,50 @@ +/* + * 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.validation + +import org.eclipse.emf.ecore.EClass +import org.eclipse.xtext.validation.NamesAreUniqueValidationHelper +import org.lflang.lf.LfPackage + +class LFNamesAreUniqueValidationHelper : NamesAreUniqueValidationHelper() { + + /** + * Lump all inputs, outputs, timers, actions, parameters, and + * instantiations in the same cluster type. This ensures that + * names amongst them are checked for uniqueness. + */ + override fun getAssociatedClusterType(eClass: EClass): EClass? { + return when (eClass) { + LfPackage.Literals.INPUT, + LfPackage.Literals.OUTPUT, + LfPackage.Literals.TIMER, + LfPackage.Literals.ACTION, + LfPackage.Literals.PARAMETER, + LfPackage.Literals.INSTANTIATION, + -> LfPackage.Literals.VARIABLE + else -> super.getAssociatedClusterType(eClass) + } + } +} diff --git a/org.lflang/src/org/lflang/validation/LFNamesAreUniqueValidationHelper.xtend b/org.lflang/src/org/lflang/validation/LFNamesAreUniqueValidationHelper.xtend deleted file mode 100644 index 2e7f0b6bd0..0000000000 --- a/org.lflang/src/org/lflang/validation/LFNamesAreUniqueValidationHelper.xtend +++ /dev/null @@ -1,28 +0,0 @@ -package org.lflang.validation; - -import org.eclipse.emf.ecore.EClass -import org.eclipse.xtext.validation.NamesAreUniqueValidationHelper -import org.lflang.lf.LfPackage - -class LFNamesAreUniqueValidationHelper extends - NamesAreUniqueValidationHelper { - - /** - * Lump all inputs, outputs, timers, actions, parameters, and - * instantiations in the same cluster type. This ensures that - * names amongst them are checked for uniqueness. - */ - override getAssociatedClusterType(EClass eClass) { - if (LfPackage.Literals.INPUT == eClass || - LfPackage.Literals.OUTPUT == eClass || - LfPackage.Literals.TIMER == eClass || - LfPackage.Literals.ACTION == eClass || - LfPackage.Literals.PARAMETER == eClass || - LfPackage.Literals.INSTANTIATION == eClass - ) { - return LfPackage.Literals.VARIABLE; - } - return super.getAssociatedClusterType(eClass); - } - -} \ No newline at end of file From 206a6d4c9d5a094da37b5805542b7318e8113b55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Wed, 21 Apr 2021 20:39:39 +0200 Subject: [PATCH 11/88] Try to port another --- build.gradle | 10 +- org.lflang.ide/.classpath | 289 +++++++++++++++++- org.lflang.ide/.project | 32 +- .../.settings/org.eclipse.jdt.core.prefs | 10 +- org.lflang/src/org/lflang/LFRuntimeModule.kt | 47 +++ .../src/org/lflang/LFRuntimeModule.xtend | 29 -- .../src/org/lflang/LFStandaloneSetup.kt | 36 +++ .../src/org/lflang/LFStandaloneSetup.xtend | 15 - .../src/org/lflang/scoping/LFScopeProvider.kt | 200 ++++++++++++ .../org/lflang/scoping/LFScopeProvider.xtend | 255 ---------------- 10 files changed, 597 insertions(+), 326 deletions(-) create mode 100644 org.lflang/src/org/lflang/LFRuntimeModule.kt delete mode 100644 org.lflang/src/org/lflang/LFRuntimeModule.xtend create mode 100644 org.lflang/src/org/lflang/LFStandaloneSetup.kt delete mode 100644 org.lflang/src/org/lflang/LFStandaloneSetup.xtend create mode 100644 org.lflang/src/org/lflang/scoping/LFScopeProvider.kt delete mode 100644 org.lflang/src/org/lflang/scoping/LFScopeProvider.xtend diff --git a/build.gradle b/build.gradle index 1d2031417b..04c923c4d3 100644 --- a/build.gradle +++ b/build.gradle @@ -1,10 +1,11 @@ buildscript { + ext.kotlinVersion = "1.5.0-RC" repositories { mavenCentral() } dependencies { classpath 'org.xtext:xtext-gradle-plugin:2.0.8' - classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.4.32' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion" } } @@ -25,6 +26,9 @@ subprojects { compileJava.dependsOn(compileKotlin) compileKotlin { destinationDir = compileJava.destinationDir + kotlinOptions { + jvmTarget = "1.8" + } } dependencies { @@ -33,6 +37,10 @@ subprojects { implementation group: 'com.google.inject', name: 'guice', version: '5.0.0-BETA-1' // https://mvnrepository.com/artifact/commons-cli/commons-cli implementation group: 'commons-cli', name: 'commons-cli', version: '1.4' + // https://mvnrepository.com/artifact/org.jetbrains.kotlin/kotlin-stdlib + implementation group: 'org.jetbrains.kotlin', name: 'kotlin-stdlib', version: "$kotlinVersion" + // https://mvnrepository.com/artifact/org.jetbrains.kotlin/kotlin-stdlib-jdk8 + implementation group: 'org.jetbrains.kotlin', name: 'kotlin-stdlib-jdk8', version: "$kotlinVersion" } apply plugin: 'org.xtext.xtend' diff --git a/org.lflang.ide/.classpath b/org.lflang.ide/.classpath index 1aa5319633..5aedde908f 100644 --- a/org.lflang.ide/.classpath +++ b/org.lflang.ide/.classpath @@ -1,24 +1,305 @@ - + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.lflang.ide/.project b/org.lflang.ide/.project index dd41def898..92f51d3431 100644 --- a/org.lflang.ide/.project +++ b/org.lflang.ide/.project @@ -2,39 +2,35 @@ org.lflang.ide - - + + + org.eclipse.xtext.ui.shared.xtextNature + org.eclipse.jdt.core.javanature + org.eclipse.pde.PluginNature + org.eclipse.buildship.core.gradleprojectnature + 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 - + + diff --git a/org.lflang.ide/.settings/org.eclipse.jdt.core.prefs b/org.lflang.ide/.settings/org.eclipse.jdt.core.prefs index f4d933e4eb..8f46b80aa0 100644 --- a/org.lflang.ide/.settings/org.eclipse.jdt.core.prefs +++ b/org.lflang.ide/.settings/org.eclipse.jdt.core.prefs @@ -1,7 +1,9 @@ -eclipse.preferences.version=1 +# +#Wed Apr 21 21:15:03 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.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.compliance=11 diff --git a/org.lflang/src/org/lflang/LFRuntimeModule.kt b/org.lflang/src/org/lflang/LFRuntimeModule.kt new file mode 100644 index 0000000000..2d59fb81ee --- /dev/null +++ b/org.lflang/src/org/lflang/LFRuntimeModule.kt @@ -0,0 +1,47 @@ +/* + * 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 + +import org.eclipse.xtext.resource.IDefaultResourceDescriptionStrategy +import org.eclipse.xtext.scoping.IGlobalScopeProvider +import org.eclipse.xtext.validation.INamesAreUniqueValidationHelper +import org.lflang.scoping.LFGlobalScopeProvider +import org.lflang.validation.LFNamesAreUniqueValidationHelper + +/** + * This class is used to register components to be used at runtime + * / without the Equinox extension registry. + */ +class LFRuntimeModule : AbstractLFRuntimeModule() { + + /** Establish a binding to our custom global scope provider. */ + override fun bindIGlobalScopeProvider(): Class = LFGlobalScopeProvider::class.java + + /** Establish a binding to a helper that checks that names are unique. */ + fun bindNamesAreUniqueValidationHelper(): Class = LFNamesAreUniqueValidationHelper::class.java + /** Establish a binding to our custom resource description strategy. */ +// fun bindIDefaultResourceDescriptionStrategy(): Class = LFResourceDescriptionStrategy::class.java + +} diff --git a/org.lflang/src/org/lflang/LFRuntimeModule.xtend b/org.lflang/src/org/lflang/LFRuntimeModule.xtend deleted file mode 100644 index e69b54f47f..0000000000 --- a/org.lflang/src/org/lflang/LFRuntimeModule.xtend +++ /dev/null @@ -1,29 +0,0 @@ -/* Runtime module for Lingua Franca. */ -package org.lflang - -import org.eclipse.xtext.resource.IDefaultResourceDescriptionStrategy -import org.eclipse.xtext.scoping.IGlobalScopeProvider -import org.eclipse.xtext.validation.INamesAreUniqueValidationHelper -import org.lflang.scoping.LFGlobalScopeProvider -import org.lflang.validation.LFNamesAreUniqueValidationHelper - -/** - * This class is used to register components to be used at runtime - * / without the Equinox extension registry. - */ -class LFRuntimeModule extends AbstractLFRuntimeModule { - /** Establish a binding to our custom resource description strategy. */ - def Class bindIDefaultResourceDescriptionStrategy() { - LFResourceDescriptionStrategy - } - - /** Establish a binding to our custom global scope provider. */ - override Class bindIGlobalScopeProvider() { - LFGlobalScopeProvider; - } - - /** Establish a binding to a helper that checks that names are unique. */ - def Class bindNamesAreUniqueValidationHelper() { - LFNamesAreUniqueValidationHelper; - } -} diff --git a/org.lflang/src/org/lflang/LFStandaloneSetup.kt b/org.lflang/src/org/lflang/LFStandaloneSetup.kt new file mode 100644 index 0000000000..ac21664eee --- /dev/null +++ b/org.lflang/src/org/lflang/LFStandaloneSetup.kt @@ -0,0 +1,36 @@ +/* + * 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 + +/** + * + */ +object LFStandaloneSetup : LFStandaloneSetupGenerated() { + + @JvmStatic + fun doSetup() { + createInjectorAndDoEMFRegistration() + } +} diff --git a/org.lflang/src/org/lflang/LFStandaloneSetup.xtend b/org.lflang/src/org/lflang/LFStandaloneSetup.xtend deleted file mode 100644 index 6f18804064..0000000000 --- a/org.lflang/src/org/lflang/LFStandaloneSetup.xtend +++ /dev/null @@ -1,15 +0,0 @@ -/* - * generated by Xtext 2.17.0 - */ -package org.lflang - - -/** - * Initialization support for running Xtext languages without Equinox extension registry. - */ -class LFStandaloneSetup extends LFStandaloneSetupGenerated { - - def static void doSetup() { - new LFStandaloneSetup().createInjectorAndDoEMFRegistration() - } -} diff --git a/org.lflang/src/org/lflang/scoping/LFScopeProvider.kt b/org.lflang/src/org/lflang/scoping/LFScopeProvider.kt new file mode 100644 index 0000000000..ac178c72d9 --- /dev/null +++ b/org.lflang/src/org/lflang/scoping/LFScopeProvider.kt @@ -0,0 +1,200 @@ +/* + * 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. + */ +/** + * Scope provider for Lingua Franca. + */ +package org.lflang.scoping + +import com.google.inject.Inject +import org.eclipse.emf.common.util.URI +import org.eclipse.emf.ecore.EObject +import org.eclipse.emf.ecore.EReference +import org.eclipse.xtext.naming.SimpleNameProvider +import org.eclipse.xtext.scoping.IScope +import org.eclipse.xtext.scoping.Scopes +import org.eclipse.xtext.scoping.impl.DelegatingScopeProvider +import org.eclipse.xtext.scoping.impl.SelectableBasedScope +import org.eclipse.xtext.xbase.lib.CollectionLiterals +import org.lflang.ASTUtils +import org.lflang.lf.* +import java.util.* +import java.util.Collections.emptyList +import kotlin.collections.* + +/** + * This class enforces custom rules. In particular, it resolves references to + * parameters, ports, actions, and timers. Ports can be referenced across at + * most one level of hierarchy. Parameters, actions, and timers can be + * referenced locally, within the reactor. + * + * @see https://www.eclipse.org/Xtext/documentation/303_runtime_concepts.html.scoping + * on how and when to use it. + * + * @author Marten Lohstroh + */ +class LFScopeProvider : DelegatingScopeProvider() { + /** + * Enumerate of the kinds of references. + */ + private enum class RefType { + NULL, TRIGGER, SOURCE, EFFECT, DEADLINE, CLEFT, CRIGHT + } + + @Inject + private val nameProvider: SimpleNameProvider? = null + + @Inject + private val scopeProvider: LFGlobalScopeProvider? = null + + /** + * Depending on the provided context, construct the appropriate scope + * for the given reference. + * @param context The AST node in which a to-be-resolved reference occurs. + * @param reference The reference to resolve. + */ + override fun getScope(context: EObject, reference: EReference): IScope { + return when (context) { + is VarRef -> getScopeForVarRef(context, reference) + is Instantiation -> getScopeForReactorDecl(context, reference) + is Reactor -> getScopeForReactorDecl(context, reference) + is ImportedReactor -> getScopeForImportedReactor(context, reference) + else -> super.getScope(context, reference) + } + } + + /** + * Filter out candidates that do not originate from the file listed in + * this particular import statement. + */ + protected fun getScopeForImportedReactor(context: ImportedReactor, reference: EReference): IScope { + val importURI = (context.eContainer() as Import).importURI ?: "" + val importedURI = scopeProvider!!.resolve(importURI, context.eResource()) + if (importedURI != null) { + val uniqueImportURIs: Set = scopeProvider.getImportedUris(context.eResource()) + val uri = uniqueImportURIs.first { it == importedURI } + val descriptions = scopeProvider.getResourceDescriptions(context.eResource(), uniqueImportURIs) + val description = descriptions.getResourceDescription(uri) + return SelectableBasedScope.createScope(IScope.NULLSCOPE, description, null, reference.eReferenceType, false) + } + return Scopes.scopeFor(CollectionLiterals.newLinkedList()) + } + + /** + * @param obj Instantiation or Reactor that has a ReactorDecl to resolve. + * @param reference The reference to link to a ReactorDecl node. + */ + private fun getScopeForReactorDecl(obj: EObject, reference: EReference?): IScope { + val locals = mutableListOf() + + // Find the local Model + val model = obj.eContainer() as? Model + ?: obj.eContainer().eContainer() as? Model + ?: return Scopes.scopeFor(emptyList()) + + // Collect eligible candidates, all of which are local (i.e., not in other files). + model.reactors?.forEach { locals.add(it) } + model.imports?.forEach { import -> + // Either point to the import statement (if it is renamed) + // or directly to the reactor definition. + import.reactorClasses?.forEach { + if (it.name != null) locals.add(it) + else if (it.reactorClass != null) locals.add(it.reactorClass) + } + } + return Scopes.scopeFor(locals) + } + + private fun getScopeForAssignment(assignment: Assignment, reference: EReference?): IScope { + + if (reference == LfPackage.Literals.ASSIGNMENT__LHS) { + val defn = ASTUtils.toDefinition((assignment.eContainer() as Instantiation).reactorClass) + if (defn != null) { + return Scopes.scopeFor(ASTUtils.allParameters(defn)) + } + } + if (reference == LfPackage.Literals.ASSIGNMENT__RHS) { + return Scopes.scopeFor((assignment.eContainer().eContainer() as Reactor).parameters) + } + return Scopes.scopeFor(emptyList()) + + } + + private fun getScopeForVarRef(variable: VarRef, reference: EReference?): IScope { + if (reference != LfPackage.Literals.VAR_REF__VARIABLE) { + return super.getScope(variable, reference) + } + + val reactor: Reactor = variable.eContainer().eContainer() as? Reactor + ?: return Scopes.scopeFor(emptyList()) + + val type = when (val eContainer = variable.eContainer()) { + is Deadline -> RefType.DEADLINE + is Reaction -> when (variable) { + in eContainer.triggers -> RefType.TRIGGER + in eContainer.sources -> RefType.SOURCE + in eContainer.effects -> RefType.EFFECT + else -> RefType.NULL + } + is Connection -> when (variable) { + in eContainer.leftPorts -> RefType.CLEFT + in eContainer.rightPorts -> RefType.CRIGHT + else -> RefType.NULL + } + else -> RefType.NULL + } + + if (variable.container != null) { // Resolve hierarchical port reference + val instanceName = nameProvider?.getFullyQualifiedName(variable.container) + val instances = reactor.instantiations + + for (instance in instances) { + val defn = ASTUtils.toDefinition(instance.reactorClass) + if (defn !== null && instanceName !== null && instance.name == instanceName.toString()) { + return when (type) { + RefType.TRIGGER, RefType.SOURCE, RefType.CLEFT -> Scopes.scopeFor(ASTUtils.allOutputs(defn)) + RefType.EFFECT, RefType.DEADLINE, RefType.CRIGHT -> Scopes.scopeFor(ASTUtils.allInputs(defn)) + else -> Scopes.scopeFor(emptyList()) + } + } + } + } + if (type == RefType.SOURCE) + return super.getScope(variable, reference) + + val candidates: List = when (type) { + RefType.TRIGGER -> mutableListOf().apply { + this += ASTUtils.allInputs(reactor) + this += ASTUtils.allActions(reactor) + this += ASTUtils.allTimers(reactor) + } + RefType.EFFECT -> ASTUtils.allOutputs(reactor) + ASTUtils.allActions(reactor) + RefType.DEADLINE -> ASTUtils.allInputs(reactor) + RefType.CLEFT -> ASTUtils.allInputs(reactor) + RefType.CRIGHT -> ASTUtils.allOutputs(reactor) + else -> emptyList() + } + + return Scopes.scopeFor(candidates) + } +} diff --git a/org.lflang/src/org/lflang/scoping/LFScopeProvider.xtend b/org.lflang/src/org/lflang/scoping/LFScopeProvider.xtend deleted file mode 100644 index f9c24d87d8..0000000000 --- a/org.lflang/src/org/lflang/scoping/LFScopeProvider.xtend +++ /dev/null @@ -1,255 +0,0 @@ -/* Scope provider for Lingua Franca. */ - -/************* -Copyright (c) 2020, 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.scoping - -import com.google.inject.Inject -import java.util.ArrayList -import org.eclipse.emf.ecore.EObject -import org.eclipse.emf.ecore.EReference -import org.eclipse.xtext.naming.SimpleNameProvider -import org.eclipse.xtext.scoping.IScope -import org.eclipse.xtext.scoping.Scopes -import org.eclipse.xtext.scoping.impl.SelectableBasedScope -import org.lflang.lf.Assignment -import org.lflang.lf.Connection -import org.lflang.lf.Deadline -import org.lflang.lf.Import -import org.lflang.lf.ImportedReactor -import org.lflang.lf.Instantiation -import org.lflang.lf.Model -import org.lflang.lf.Reaction -import org.lflang.lf.Reactor -import org.lflang.lf.VarRef -import org.lflang.lf.LfPackage - -import static extension org.lflang.ASTUtils.* - -/** - * This class enforces custom rules. In particular, it resolves references to - * parameters, ports, actions, and timers. Ports can be referenced across at - * most one level of hierarchy. Parameters, actions, and timers can be - * referenced locally, within the reactor. - * - * @see https://www.eclipse.org/Xtext/documentation/303_runtime_concepts.html#scoping - * on how and when to use it. - * @author Marten Lohstroh - */ -class LFScopeProvider extends AbstractLFScopeProvider { - - @Inject - SimpleNameProvider nameProvider - - @Inject - LFGlobalScopeProvider scopeProvider; - - /** - * Enumerate of the kinds of references. - */ - protected enum RefType { - NULL, - TRIGGER, - SOURCE, - EFFECT, - DEADLINE, - CLEFT, - CRIGHT - } - - /** - * Depending on the provided context, construct the appropriate scope - * for the given reference. - * @param context The AST node in which a to-be-resolved reference occurs. - * @param reference The reference to resolve. - */ - override getScope(EObject context, EReference reference) { - switch (context) { - VarRef: return getScopeForVarRef(context, reference) - Assignment: return getScopeForAssignment(context, reference) - Instantiation: return getScopeForReactorDecl(context, reference) - Reactor: return getScopeForReactorDecl(context, reference) - ImportedReactor: return getScopeForImportedReactor(context, reference) - } - return super.getScope(context, reference); - } - - /** - * Filter out candidates that do not originate from the file listed in - * this particular import statement. - */ - protected def getScopeForImportedReactor(ImportedReactor context, - EReference reference) { - val importedURI = scopeProvider.resolve( - (context.eContainer as Import).importURI ?: "", context.eResource) - if (importedURI !== null) { - - val uniqueImportURIs = scopeProvider.getImportedUris(context.eResource) - val descriptions = scopeProvider.getResourceDescriptions(context.eResource, uniqueImportURIs); - val uri = uniqueImportURIs.findFirst[it.equals(importedURI)] - val description = descriptions.getResourceDescription(uri); - return SelectableBasedScope.createScope(IScope.NULLSCOPE, description, null, reference.EReferenceType, false); - } - return Scopes.scopeFor(newLinkedList) - } - - /** - * - * @param obj Instantiation or Reactor that has a ReactorDecl to resolve. - * @param reference The reference to link to a ReactorDecl node. - */ - protected def getScopeForReactorDecl(EObject obj, EReference reference) { - var Model model - val locals = newLinkedList - - // Find the local Model - if (obj.eContainer instanceof Model) { - model = obj.eContainer as Model - } else if (obj.eContainer.eContainer instanceof Model) { - model = obj.eContainer.eContainer as Model - } else { - // Empty list - } - - // Collect eligible candidates, all of which are local (i.e., not in other files). - model.reactors?.forEach[locals.add(it)] - model.imports?.forEach [ - // Either point to the import statement (if it is renamed) - // or directly to the reactor definition. - it.reactorClasses?.forEach [ - (it.name !== null) ? locals.add(it) : - (it.reactorClass !== null) ? locals.add(it.reactorClass) - ] - ] - return Scopes.scopeFor(locals) - } - - /** - * - */ - protected def getScopeForAssignment(Assignment assignment, - EReference reference) { - - if (reference == LfPackage.Literals.ASSIGNMENT__LHS) { - val defn = (assignment.eContainer as Instantiation).reactorClass.toDefinition - if (defn !== null) { - return Scopes.scopeFor(defn.allParameters) - } - - } - if (reference == LfPackage.Literals.ASSIGNMENT__RHS) { - return Scopes.scopeFor( - (assignment.eContainer.eContainer as Reactor).parameters) - } - return Scopes.scopeFor(newLinkedList) - } - - /** - * - */ - protected def getScopeForVarRef(VarRef variable, EReference reference) { - if (reference == LfPackage.Literals.VAR_REF__VARIABLE) { - // Resolve hierarchical reference - val candidates = new ArrayList() - var type = RefType.NULL - var Reactor reactor = null - - if (variable.eContainer.eContainer instanceof Reactor) { - reactor = variable.eContainer.eContainer as Reactor - } else { - return Scopes.scopeFor(newLinkedList) - } - - if (variable.eContainer instanceof Deadline) { - type = RefType.DEADLINE - } else if (variable.eContainer instanceof Reaction) { - val reaction = variable.eContainer as Reaction - if (reaction.triggers.contains(variable)) { - type = RefType.TRIGGER - } else if (reaction.sources.contains(variable)) { - type = RefType.SOURCE - } else if (reaction.effects.contains(variable)) { - type = RefType.EFFECT - } - } else if (variable.eContainer instanceof Connection) { - val conn = variable.eContainer as Connection - if (conn.leftPorts.contains(variable)) { - type = RefType.CLEFT - } else if (conn.rightPorts.contains(variable)) { - type = RefType.CRIGHT - } - } - - if (variable.container !== null) { // Resolve hierarchical port reference - val instanceName = nameProvider. - getFullyQualifiedName(variable.container) - val instances = reactor.instantiations - - for (instance : instances) { - val defn = instance.reactorClass.toDefinition - if (defn !== null && instanceName !== null && - instance.name.equals(instanceName.toString)) { - if (type === RefType.TRIGGER || - type === RefType.SOURCE || type === RefType.CLEFT) { - return Scopes.scopeFor( - defn.allOutputs) - } else if (type === RefType.EFFECT || - type === RefType.DEADLINE || - type === RefType.CRIGHT) { - return Scopes.scopeFor(defn.allInputs) - } - } - } - return Scopes.scopeFor(candidates) // Empty list - } else { // Resolve local reference - switch (type) { - case RefType.TRIGGER: { - candidates.addAll(reactor.allInputs) - candidates.addAll(reactor.allActions) - candidates.addAll(reactor.allTimers) - } - case RefType.SOURCE: - return super.getScope(variable, reference) - case RefType.EFFECT: { - candidates.addAll(reactor.allOutputs) - candidates.addAll(reactor.allActions) - } - case RefType.DEADLINE: - return Scopes.scopeFor(reactor.allInputs) - case RefType.CLEFT: - return Scopes.scopeFor(reactor.allInputs) - case RefType.CRIGHT: - return Scopes.scopeFor(reactor.allOutputs) - default: { - } - } - return Scopes.scopeFor(candidates) - } - } else { // Resolve instance - return super.getScope(variable, reference) - } - } -} From 235077d69ad412f0d7ba138f319e7cc325ea7909 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Thu, 22 Apr 2021 00:02:36 +0200 Subject: [PATCH 12/88] Fix warnings --- org.lflang/src/org/lflang/scoping/LFScopeProvider.kt | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/org.lflang/src/org/lflang/scoping/LFScopeProvider.kt b/org.lflang/src/org/lflang/scoping/LFScopeProvider.kt index ac178c72d9..d4738251cc 100644 --- a/org.lflang/src/org/lflang/scoping/LFScopeProvider.kt +++ b/org.lflang/src/org/lflang/scoping/LFScopeProvider.kt @@ -21,9 +21,6 @@ * 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. */ -/** - * Scope provider for Lingua Franca. - */ package org.lflang.scoping import com.google.inject.Inject @@ -38,9 +35,7 @@ import org.eclipse.xtext.scoping.impl.SelectableBasedScope import org.eclipse.xtext.xbase.lib.CollectionLiterals import org.lflang.ASTUtils import org.lflang.lf.* -import java.util.* import java.util.Collections.emptyList -import kotlin.collections.* /** * This class enforces custom rules. In particular, it resolves references to @@ -48,8 +43,7 @@ import kotlin.collections.* * most one level of hierarchy. Parameters, actions, and timers can be * referenced locally, within the reactor. * - * @see https://www.eclipse.org/Xtext/documentation/303_runtime_concepts.html.scoping - * on how and when to use it. + * @see "https://www.eclipse.org/Xtext/documentation/303_runtime_concepts.html.scoping on how and when to use it." * * @author Marten Lohstroh */ @@ -76,6 +70,7 @@ class LFScopeProvider : DelegatingScopeProvider() { override fun getScope(context: EObject, reference: EReference): IScope { return when (context) { is VarRef -> getScopeForVarRef(context, reference) + is Assignment -> getScopeForAssignment(context, reference) is Instantiation -> getScopeForReactorDecl(context, reference) is Reactor -> getScopeForReactorDecl(context, reference) is ImportedReactor -> getScopeForImportedReactor(context, reference) @@ -87,7 +82,7 @@ class LFScopeProvider : DelegatingScopeProvider() { * Filter out candidates that do not originate from the file listed in * this particular import statement. */ - protected fun getScopeForImportedReactor(context: ImportedReactor, reference: EReference): IScope { + private fun getScopeForImportedReactor(context: ImportedReactor, reference: EReference): IScope { val importURI = (context.eContainer() as Import).importURI ?: "" val importedURI = scopeProvider!!.resolve(importURI, context.eResource()) if (importedURI != null) { From 619e44c4e8be063004321ce7d89329d1cb13d151 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Thu, 22 Apr 2021 00:28:20 +0200 Subject: [PATCH 13/88] Port LFGlobalScopeProvider We need to port the C++ generator for that to work --- .../lflang/scoping/LFGlobalScopeProvider.kt | 150 +++++++++++++++ .../scoping/LFGlobalScopeProvider.xtend | 177 ------------------ 2 files changed, 150 insertions(+), 177 deletions(-) create mode 100644 org.lflang/src/org/lflang/scoping/LFGlobalScopeProvider.kt delete mode 100644 org.lflang/src/org/lflang/scoping/LFGlobalScopeProvider.xtend diff --git a/org.lflang/src/org/lflang/scoping/LFGlobalScopeProvider.kt b/org.lflang/src/org/lflang/scoping/LFGlobalScopeProvider.kt new file mode 100644 index 0000000000..7415569c74 --- /dev/null +++ b/org.lflang/src/org/lflang/scoping/LFGlobalScopeProvider.kt @@ -0,0 +1,150 @@ +/* Custom global scope provider for Lingua Franca. */ + +/************* + * Copyright (c) 2019, The University of California at Berkeley. + + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ***************/ +package org.lflang.scoping + +import com.google.common.base.Splitter +import com.google.inject.Inject +import java.util.LinkedHashSet +import org.eclipse.emf.common.util.URI +import org.eclipse.emf.ecore.resource.Resource +import org.eclipse.xtext.EcoreUtil2 +import org.eclipse.xtext.resource.IResourceDescription +import org.eclipse.xtext.scoping.impl.ImportUriGlobalScopeProvider +import org.eclipse.xtext.util.IResourceScopeCache +import org.lflang.lf.LfPackage +import org.lflang.LFResourceDescriptionStrategy + +/** + * Global scope provider that limits access to only those files that were + * explicitly imported. + * + * Adapted from from Xtext manual, Chapter 8.7. + * @see "https://www.eclipse.org/Xtext/documentation/2.6.0/Xtext%20Documentation.pdf" + * @author {Marten Lohstroh } + */ +class LFGlobalScopeProvider : ImportUriGlobalScopeProvider() { + + @Inject + lateinit var descriptionManager: IResourceDescription.Manager + + @Inject + private lateinit var _cache: IResourceScopeCache + + + /** + * Return the set of URI objects pointing to the resources that must be + * included for compilation. + */ + override fun getImportedUris(resource: Resource): LinkedHashSet = + _cache.get(IMPORTED_URIS, resource) { + /** Helper method to recursively collect unique URIs. */ + fun collectImportUris(resource: Resource, uniqueImportURIs: MutableSet) { + for (imported in getImportedResources(resource, uniqueImportURIs)) { + collectImportUris(imported, uniqueImportURIs) + } + } + + val uniqueImportURIs = LinkedHashSet().also { + collectImportUris(resource, it) + } + + uniqueImportURIs.removeIf { + !EcoreUtil2.isValidUri(resource, it) + } + uniqueImportURIs + } + + /** + * Return the resources imported by the given resource. + * @param resource The resource to return the imported resources of. + */ + fun getImportedResources(resource: Resource): Unit = + _cache.get(IMPORTED_RESOURCES, resource) { + getImportedResources(resource, mutableSetOf()) + } + + + /** + * Resolve a resource identifier. + * + * @receiver resource identifier to resolve. + * @param resource resource to (initially) resolve it relative to. + */ + private fun String.resolve(resource: Resource): URI? { + var uriObj = URI.createURI(this) + val uriExtension = uriObj?.fileExtension() + if (uriExtension?.equals("lf", ignoreCase = true) == true) { + uriObj = uriObj.resolve(resource.uri) + // FIXME: If this doesn't work, try other things: + // (1) Look for a .project file up the file structure and try to + // resolve relative to the directory in which it is found. + // (2) Look for package description files try to resolve relative + // to the paths it includes. + // FIXME: potentially use a cache here to speed things up. + // See OnChangeEvictingCache + return uriObj + } + return null + } + + /** + * Return the resources imported by a given resource, excluding those + * already discovered and therefore are present in the given set of + * import URIs. + * + * @param resource The resource to analyze. + * @param uniqueImportURIs The set of discovered import URIs + */ + private fun getImportedResources(resource: Resource, uniqueImportURIs: MutableSet): Set { + val resourceDescription = descriptionManager.getResourceDescription(resource) + val result = LinkedHashSet() + for (model in resourceDescription.getExportedObjectsByType(LfPackage.Literals.MODEL)) { + val userData = model.getUserData(LFResourceDescriptionStrategy.INCLUDES) ?: continue + for (uri in SPLITTER.split(userData)) { + // Attempt to resolve the URI + val includedUri = uri.resolve(resource) ?: continue + if (uniqueImportURIs.add(includedUri)) { + try { + val loaded = resource.resourceSet.getResource(includedUri, true) + result.add(loaded) + } catch (e: Exception) { + System.err.println("Unable to import $includedUri") + } + } + } + } + return result + } + + companion object { + + /** Splitter used to process user-data annotations of Model nodes. */ + val SPLITTER: Splitter = Splitter.on(LFResourceDescriptionStrategy.DELIMITER) + const val IMPORTED_URIS = "IMPORTED_URIS" + const val IMPORTED_RESOURCES = "IMPORTED_RESOURCES" + + } +} diff --git a/org.lflang/src/org/lflang/scoping/LFGlobalScopeProvider.xtend b/org.lflang/src/org/lflang/scoping/LFGlobalScopeProvider.xtend deleted file mode 100644 index 6a1a83077e..0000000000 --- a/org.lflang/src/org/lflang/scoping/LFGlobalScopeProvider.xtend +++ /dev/null @@ -1,177 +0,0 @@ -/* Custom global scope provider for Lingua Franca. */ - -/************* - * Copyright (c) 2019, The University of California at Berkeley. - - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF - * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ***************/ -package org.lflang.scoping - -import com.google.common.base.Splitter -import com.google.inject.Inject -import com.google.inject.Provider -import java.util.LinkedHashSet -import org.eclipse.emf.common.util.URI -import org.eclipse.emf.ecore.resource.Resource -import org.eclipse.xtext.EcoreUtil2 -import org.eclipse.xtext.resource.IResourceDescription -import org.eclipse.xtext.scoping.impl.ImportUriGlobalScopeProvider -import org.eclipse.xtext.util.IResourceScopeCache -import org.lflang.lf.LfPackage -import org.lflang.LFResourceDescriptionStrategy - -/** - * Global scope provider that limits access to only those files that were - * explicitly imported. - * - * Adapted from from Xtext manual, Chapter 8.7. - * @see https://www.eclipse.org/Xtext/documentation/2.6.0/Xtext%20Documentation.pdf - * @author{Marten Lohstroh } - */ -class LFGlobalScopeProvider extends ImportUriGlobalScopeProvider { - - /** - * Splitter used to process user-data annotations of Model nodes. - */ - static final Splitter SPLITTER = Splitter.on( - org.lflang.LFResourceDescriptionStrategy.DELIMITER); - - static final String IMPORTED_URIS = "IMPORTED_URIS" - - static final String IMPORTED_RESOURCES = "IMPORTED_RESOURCES" - - @Inject - IResourceDescription.Manager descriptionManager; - - @Inject - IResourceScopeCache cache; - - /** - * Return the set of URI objects pointing to the resources that must be - * included for compilation. - */ - override protected getImportedUris(Resource resource) { - return cache.get(IMPORTED_URIS, resource, - new Provider>() { - /** - * Collect unique URIs in case the cache is not populated yet. - */ - override get() { - val uniqueImportURIs = collectImportUris(resource, - new LinkedHashSet(5)) - - val uriIter = uniqueImportURIs.iterator() - while (uriIter.hasNext()) { - if (!EcoreUtil2.isValidUri(resource, uriIter.next())) - uriIter.remove() - } - return uniqueImportURIs - } - - /** - * Helper method to recursively collect unique URIs. - */ - def LinkedHashSet collectImportUris(Resource resource, - LinkedHashSet uniqueImportURIs) { - for (imported : getImportedResources(resource, - uniqueImportURIs)) { - collectImportUris(imported, uniqueImportURIs) - } - return uniqueImportURIs - } - }); - } - - /** - * Return the resources imported by the given resource. - * @param resource The resource to return the imported resources of. - */ - def getImportedResources(Resource resource) { - return cache.get(IMPORTED_RESOURCES, resource, - new Provider>() { - override get() { - getImportedResources(resource, null) - } - }); - } - - /** - * Resolve a resource identifier. - * - * @param uriStr resource identifier to resolve. - * @param resource resource to (initially) resolve it relative to. - */ - protected def URI resolve(String uriStr, Resource resource) { - var uriObj = URI.createURI(uriStr) - val uriExtension = uriObj?.fileExtension - if (uriExtension !== null && uriExtension.equalsIgnoreCase('lf')) { - uriObj = uriObj.resolve(resource.URI) - // FIXME: If this doesn't work, try other things: - // (1) Look for a .project file up the file structure and try to - // resolve relative to the directory in which it is found. - // (2) Look for package description files try to resolve relative - // to the paths it includes. - // FIXME: potentially use a cache here to speed things up. - // See OnChangeEvictingCache - return uriObj - } - } - - /** - * Return the resources imported by a given resource, excluding those - * already discovered and therefore are present in the given set of - * import URIs. - * - * @param resource The resource to analyze. - * @param uniqueImportURIs The set of discovered import URIs - */ - protected def getImportedResources(Resource resource, - LinkedHashSet uniqueImportURIs) { - val resourceDescription = descriptionManager. - getResourceDescription(resource) - val models = resourceDescription.getExportedObjectsByType( - LfPackage.Literals.MODEL) - val resources = new LinkedHashSet() - models.forEach [ - val userData = getUserData( - LFResourceDescriptionStrategy.INCLUDES) - if (userData !== null) { - SPLITTER.split(userData).forEach [ uri | - // Attempt to resolve the URI - var includedUri = uri.resolve(resource) - if (includedUri !== null) { - try { - if (uniqueImportURIs === null || - uniqueImportURIs.add(includedUri)) { - resources.add( - resource.getResourceSet().getResource( - includedUri, true)) - } - } catch (Exception e) { - System.err.println("Unable to import " + includedUri) - } - } - ] - } - ] - return resources - } -} From bd26d888ca6159ee2432e04c4d29dc829ba3bd81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Thu, 22 Apr 2021 00:39:59 +0200 Subject: [PATCH 14/88] Add basic extensions taken from ASTUtils Kotlin extensions are much more ergonomic. --- org.lflang/src/org/lflang/Extensions.kt | 92 +++++++++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 org.lflang/src/org/lflang/Extensions.kt diff --git a/org.lflang/src/org/lflang/Extensions.kt b/org.lflang/src/org/lflang/Extensions.kt new file mode 100644 index 0000000000..70be0bd615 --- /dev/null +++ b/org.lflang/src/org/lflang/Extensions.kt @@ -0,0 +1,92 @@ +/* + * 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 + +import org.lflang.lf.* +import java.lang.AssertionError + + +fun ReactorDecl.toDefinition(): Reactor = when (this) { + is Reactor -> this + is ImportedReactor -> this.reactorClass + else -> throw AssertionError("unreachable") +} + +/** + * Given a reactor class, return a list of all its actions, + * which includes actions of base classes that it extends. + */ +val Reactor.allActions: List get() = superClassRecursor { actions } + +/** + * Given a reactor class, return a list of all its connections, + * which includes connections of base classes that it extends. + */ +val Reactor.allConnections: List get() = superClassRecursor { connections } + +/** + * Given a reactor class, return a list of all its inputs, + * which includes inputs of base classes that it extends. + */ +val Reactor.allInputs: List get() = superClassRecursor { inputs } + +/** + * Given a reactor class, return a list of all its outputs, + * which includes outputs of base classes that it extends. + */ +val Reactor.allOutputs: List get() = superClassRecursor { outputs } + +/** + * Given a reactor class, return a list of all its instantiations, + * which includes instantiations of base classes that it extends. + */ +val Reactor.allInstantiations: List get() = superClassRecursor { instantiations } + +/** + * Given a reactor class, return a list of all its parameters, + * which includes parameters of base classes that it extends. + */ +val Reactor.allParameters: List get() = superClassRecursor { parameters } + +/** + * Given a reactor class, return a list of all its reactions, + * which includes reactions of base classes that it extends. + */ +val Reactor.allReactions: List get() = superClassRecursor { reactions } + +/** + * Given a reactor class, return a list of all its state variables, + * which includes state variables of base classes that it extends. + */ +val Reactor.allStateVars: List get() = superClassRecursor { stateVars } + +/** + * Given a reactor class, return a list of all its timers, + * which includes timers of base classes that it extends. + */ +val Reactor.allTimers: List get() = superClassRecursor { timers } + +private fun Reactor.superClassRecursor(collector: Reactor.() -> List): List = + superClasses.orEmpty().flatMap { it.toDefinition().collector() } + this.collector() From 5a443348851b3f25dbe569b621040c72891dc862 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Thu, 22 Apr 2021 00:40:06 +0200 Subject: [PATCH 15/88] Revert "Port LFGlobalScopeProvider" This reverts commit 619e44c4e8be063004321ce7d89329d1cb13d151. --- .../lflang/scoping/LFGlobalScopeProvider.kt | 150 --------------- .../scoping/LFGlobalScopeProvider.xtend | 177 ++++++++++++++++++ 2 files changed, 177 insertions(+), 150 deletions(-) delete mode 100644 org.lflang/src/org/lflang/scoping/LFGlobalScopeProvider.kt create mode 100644 org.lflang/src/org/lflang/scoping/LFGlobalScopeProvider.xtend diff --git a/org.lflang/src/org/lflang/scoping/LFGlobalScopeProvider.kt b/org.lflang/src/org/lflang/scoping/LFGlobalScopeProvider.kt deleted file mode 100644 index 7415569c74..0000000000 --- a/org.lflang/src/org/lflang/scoping/LFGlobalScopeProvider.kt +++ /dev/null @@ -1,150 +0,0 @@ -/* Custom global scope provider for Lingua Franca. */ - -/************* - * Copyright (c) 2019, The University of California at Berkeley. - - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF - * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ***************/ -package org.lflang.scoping - -import com.google.common.base.Splitter -import com.google.inject.Inject -import java.util.LinkedHashSet -import org.eclipse.emf.common.util.URI -import org.eclipse.emf.ecore.resource.Resource -import org.eclipse.xtext.EcoreUtil2 -import org.eclipse.xtext.resource.IResourceDescription -import org.eclipse.xtext.scoping.impl.ImportUriGlobalScopeProvider -import org.eclipse.xtext.util.IResourceScopeCache -import org.lflang.lf.LfPackage -import org.lflang.LFResourceDescriptionStrategy - -/** - * Global scope provider that limits access to only those files that were - * explicitly imported. - * - * Adapted from from Xtext manual, Chapter 8.7. - * @see "https://www.eclipse.org/Xtext/documentation/2.6.0/Xtext%20Documentation.pdf" - * @author {Marten Lohstroh } - */ -class LFGlobalScopeProvider : ImportUriGlobalScopeProvider() { - - @Inject - lateinit var descriptionManager: IResourceDescription.Manager - - @Inject - private lateinit var _cache: IResourceScopeCache - - - /** - * Return the set of URI objects pointing to the resources that must be - * included for compilation. - */ - override fun getImportedUris(resource: Resource): LinkedHashSet = - _cache.get(IMPORTED_URIS, resource) { - /** Helper method to recursively collect unique URIs. */ - fun collectImportUris(resource: Resource, uniqueImportURIs: MutableSet) { - for (imported in getImportedResources(resource, uniqueImportURIs)) { - collectImportUris(imported, uniqueImportURIs) - } - } - - val uniqueImportURIs = LinkedHashSet().also { - collectImportUris(resource, it) - } - - uniqueImportURIs.removeIf { - !EcoreUtil2.isValidUri(resource, it) - } - uniqueImportURIs - } - - /** - * Return the resources imported by the given resource. - * @param resource The resource to return the imported resources of. - */ - fun getImportedResources(resource: Resource): Unit = - _cache.get(IMPORTED_RESOURCES, resource) { - getImportedResources(resource, mutableSetOf()) - } - - - /** - * Resolve a resource identifier. - * - * @receiver resource identifier to resolve. - * @param resource resource to (initially) resolve it relative to. - */ - private fun String.resolve(resource: Resource): URI? { - var uriObj = URI.createURI(this) - val uriExtension = uriObj?.fileExtension() - if (uriExtension?.equals("lf", ignoreCase = true) == true) { - uriObj = uriObj.resolve(resource.uri) - // FIXME: If this doesn't work, try other things: - // (1) Look for a .project file up the file structure and try to - // resolve relative to the directory in which it is found. - // (2) Look for package description files try to resolve relative - // to the paths it includes. - // FIXME: potentially use a cache here to speed things up. - // See OnChangeEvictingCache - return uriObj - } - return null - } - - /** - * Return the resources imported by a given resource, excluding those - * already discovered and therefore are present in the given set of - * import URIs. - * - * @param resource The resource to analyze. - * @param uniqueImportURIs The set of discovered import URIs - */ - private fun getImportedResources(resource: Resource, uniqueImportURIs: MutableSet): Set { - val resourceDescription = descriptionManager.getResourceDescription(resource) - val result = LinkedHashSet() - for (model in resourceDescription.getExportedObjectsByType(LfPackage.Literals.MODEL)) { - val userData = model.getUserData(LFResourceDescriptionStrategy.INCLUDES) ?: continue - for (uri in SPLITTER.split(userData)) { - // Attempt to resolve the URI - val includedUri = uri.resolve(resource) ?: continue - if (uniqueImportURIs.add(includedUri)) { - try { - val loaded = resource.resourceSet.getResource(includedUri, true) - result.add(loaded) - } catch (e: Exception) { - System.err.println("Unable to import $includedUri") - } - } - } - } - return result - } - - companion object { - - /** Splitter used to process user-data annotations of Model nodes. */ - val SPLITTER: Splitter = Splitter.on(LFResourceDescriptionStrategy.DELIMITER) - const val IMPORTED_URIS = "IMPORTED_URIS" - const val IMPORTED_RESOURCES = "IMPORTED_RESOURCES" - - } -} diff --git a/org.lflang/src/org/lflang/scoping/LFGlobalScopeProvider.xtend b/org.lflang/src/org/lflang/scoping/LFGlobalScopeProvider.xtend new file mode 100644 index 0000000000..6a1a83077e --- /dev/null +++ b/org.lflang/src/org/lflang/scoping/LFGlobalScopeProvider.xtend @@ -0,0 +1,177 @@ +/* Custom global scope provider for Lingua Franca. */ + +/************* + * Copyright (c) 2019, The University of California at Berkeley. + + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ***************/ +package org.lflang.scoping + +import com.google.common.base.Splitter +import com.google.inject.Inject +import com.google.inject.Provider +import java.util.LinkedHashSet +import org.eclipse.emf.common.util.URI +import org.eclipse.emf.ecore.resource.Resource +import org.eclipse.xtext.EcoreUtil2 +import org.eclipse.xtext.resource.IResourceDescription +import org.eclipse.xtext.scoping.impl.ImportUriGlobalScopeProvider +import org.eclipse.xtext.util.IResourceScopeCache +import org.lflang.lf.LfPackage +import org.lflang.LFResourceDescriptionStrategy + +/** + * Global scope provider that limits access to only those files that were + * explicitly imported. + * + * Adapted from from Xtext manual, Chapter 8.7. + * @see https://www.eclipse.org/Xtext/documentation/2.6.0/Xtext%20Documentation.pdf + * @author{Marten Lohstroh } + */ +class LFGlobalScopeProvider extends ImportUriGlobalScopeProvider { + + /** + * Splitter used to process user-data annotations of Model nodes. + */ + static final Splitter SPLITTER = Splitter.on( + org.lflang.LFResourceDescriptionStrategy.DELIMITER); + + static final String IMPORTED_URIS = "IMPORTED_URIS" + + static final String IMPORTED_RESOURCES = "IMPORTED_RESOURCES" + + @Inject + IResourceDescription.Manager descriptionManager; + + @Inject + IResourceScopeCache cache; + + /** + * Return the set of URI objects pointing to the resources that must be + * included for compilation. + */ + override protected getImportedUris(Resource resource) { + return cache.get(IMPORTED_URIS, resource, + new Provider>() { + /** + * Collect unique URIs in case the cache is not populated yet. + */ + override get() { + val uniqueImportURIs = collectImportUris(resource, + new LinkedHashSet(5)) + + val uriIter = uniqueImportURIs.iterator() + while (uriIter.hasNext()) { + if (!EcoreUtil2.isValidUri(resource, uriIter.next())) + uriIter.remove() + } + return uniqueImportURIs + } + + /** + * Helper method to recursively collect unique URIs. + */ + def LinkedHashSet collectImportUris(Resource resource, + LinkedHashSet uniqueImportURIs) { + for (imported : getImportedResources(resource, + uniqueImportURIs)) { + collectImportUris(imported, uniqueImportURIs) + } + return uniqueImportURIs + } + }); + } + + /** + * Return the resources imported by the given resource. + * @param resource The resource to return the imported resources of. + */ + def getImportedResources(Resource resource) { + return cache.get(IMPORTED_RESOURCES, resource, + new Provider>() { + override get() { + getImportedResources(resource, null) + } + }); + } + + /** + * Resolve a resource identifier. + * + * @param uriStr resource identifier to resolve. + * @param resource resource to (initially) resolve it relative to. + */ + protected def URI resolve(String uriStr, Resource resource) { + var uriObj = URI.createURI(uriStr) + val uriExtension = uriObj?.fileExtension + if (uriExtension !== null && uriExtension.equalsIgnoreCase('lf')) { + uriObj = uriObj.resolve(resource.URI) + // FIXME: If this doesn't work, try other things: + // (1) Look for a .project file up the file structure and try to + // resolve relative to the directory in which it is found. + // (2) Look for package description files try to resolve relative + // to the paths it includes. + // FIXME: potentially use a cache here to speed things up. + // See OnChangeEvictingCache + return uriObj + } + } + + /** + * Return the resources imported by a given resource, excluding those + * already discovered and therefore are present in the given set of + * import URIs. + * + * @param resource The resource to analyze. + * @param uniqueImportURIs The set of discovered import URIs + */ + protected def getImportedResources(Resource resource, + LinkedHashSet uniqueImportURIs) { + val resourceDescription = descriptionManager. + getResourceDescription(resource) + val models = resourceDescription.getExportedObjectsByType( + LfPackage.Literals.MODEL) + val resources = new LinkedHashSet() + models.forEach [ + val userData = getUserData( + LFResourceDescriptionStrategy.INCLUDES) + if (userData !== null) { + SPLITTER.split(userData).forEach [ uri | + // Attempt to resolve the URI + var includedUri = uri.resolve(resource) + if (includedUri !== null) { + try { + if (uniqueImportURIs === null || + uniqueImportURIs.add(includedUri)) { + resources.add( + resource.getResourceSet().getResource( + includedUri, true)) + } + } catch (Exception e) { + System.err.println("Unable to import " + includedUri) + } + } + ] + } + ] + return resources + } +} From e7bdd625a1f47c7aba37f510d61d3ae2e0f183e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Thu, 22 Apr 2021 00:43:44 +0200 Subject: [PATCH 16/88] Use new extensions --- org.lflang/src/org/lflang/Extensions.kt | 5 ++-- .../src/org/lflang/scoping/LFScopeProvider.kt | 28 +++++++++---------- 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/org.lflang/src/org/lflang/Extensions.kt b/org.lflang/src/org/lflang/Extensions.kt index 70be0bd615..28ac1a70a8 100644 --- a/org.lflang/src/org/lflang/Extensions.kt +++ b/org.lflang/src/org/lflang/Extensions.kt @@ -28,7 +28,8 @@ import org.lflang.lf.* import java.lang.AssertionError -fun ReactorDecl.toDefinition(): Reactor = when (this) { +fun ReactorDecl?.toDefinition(): Reactor? = when (this) { + null -> null is Reactor -> this is ImportedReactor -> this.reactorClass else -> throw AssertionError("unreachable") @@ -89,4 +90,4 @@ val Reactor.allStateVars: List get() = superClassRecursor { stateVars val Reactor.allTimers: List get() = superClassRecursor { timers } private fun Reactor.superClassRecursor(collector: Reactor.() -> List): List = - superClasses.orEmpty().flatMap { it.toDefinition().collector() } + this.collector() + superClasses.orEmpty().mapNotNull { it.toDefinition()?.collector() }.flatten() + this.collector() diff --git a/org.lflang/src/org/lflang/scoping/LFScopeProvider.kt b/org.lflang/src/org/lflang/scoping/LFScopeProvider.kt index d4738251cc..034e2a831a 100644 --- a/org.lflang/src/org/lflang/scoping/LFScopeProvider.kt +++ b/org.lflang/src/org/lflang/scoping/LFScopeProvider.kt @@ -33,7 +33,7 @@ import org.eclipse.xtext.scoping.Scopes import org.eclipse.xtext.scoping.impl.DelegatingScopeProvider import org.eclipse.xtext.scoping.impl.SelectableBasedScope import org.eclipse.xtext.xbase.lib.CollectionLiterals -import org.lflang.ASTUtils +import org.lflang.* import org.lflang.lf.* import java.util.Collections.emptyList @@ -123,9 +123,9 @@ class LFScopeProvider : DelegatingScopeProvider() { private fun getScopeForAssignment(assignment: Assignment, reference: EReference?): IScope { if (reference == LfPackage.Literals.ASSIGNMENT__LHS) { - val defn = ASTUtils.toDefinition((assignment.eContainer() as Instantiation).reactorClass) + val defn = ((assignment.eContainer() as Instantiation).reactorClass).toDefinition() if (defn != null) { - return Scopes.scopeFor(ASTUtils.allParameters(defn)) + return Scopes.scopeFor(defn.allParameters) } } if (reference == LfPackage.Literals.ASSIGNMENT__RHS) { @@ -164,11 +164,11 @@ class LFScopeProvider : DelegatingScopeProvider() { val instances = reactor.instantiations for (instance in instances) { - val defn = ASTUtils.toDefinition(instance.reactorClass) - if (defn !== null && instanceName !== null && instance.name == instanceName.toString()) { + val defn = instance.reactorClass.toDefinition() + if (defn != null && instanceName != null && instance.name == instanceName.toString()) { return when (type) { - RefType.TRIGGER, RefType.SOURCE, RefType.CLEFT -> Scopes.scopeFor(ASTUtils.allOutputs(defn)) - RefType.EFFECT, RefType.DEADLINE, RefType.CRIGHT -> Scopes.scopeFor(ASTUtils.allInputs(defn)) + RefType.TRIGGER, RefType.SOURCE, RefType.CLEFT -> Scopes.scopeFor(defn.allOutputs) + RefType.EFFECT, RefType.DEADLINE, RefType.CRIGHT -> Scopes.scopeFor(defn.allInputs) else -> Scopes.scopeFor(emptyList()) } } @@ -179,14 +179,14 @@ class LFScopeProvider : DelegatingScopeProvider() { val candidates: List = when (type) { RefType.TRIGGER -> mutableListOf().apply { - this += ASTUtils.allInputs(reactor) - this += ASTUtils.allActions(reactor) - this += ASTUtils.allTimers(reactor) + this += reactor.allInputs + this += reactor.allActions + this += reactor.allTimers } - RefType.EFFECT -> ASTUtils.allOutputs(reactor) + ASTUtils.allActions(reactor) - RefType.DEADLINE -> ASTUtils.allInputs(reactor) - RefType.CLEFT -> ASTUtils.allInputs(reactor) - RefType.CRIGHT -> ASTUtils.allOutputs(reactor) + RefType.EFFECT -> reactor.allOutputs + reactor.allActions + RefType.DEADLINE -> reactor.allInputs + RefType.CLEFT -> reactor.allInputs + RefType.CRIGHT -> reactor.allOutputs else -> emptyList() } From 166eb6e39fd665030d55b6085bbfa8178f362227 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Thu, 22 Apr 2021 01:01:24 +0200 Subject: [PATCH 17/88] Try to update LFGenerator --- .../src/org/lflang/generator/LFGenerator.java | 111 ++++++++++++++++++ .../org/lflang/generator/LFGenerator.xtend | 83 ------------- 2 files changed, 111 insertions(+), 83 deletions(-) create mode 100644 org.lflang/src/org/lflang/generator/LFGenerator.java delete mode 100644 org.lflang/src/org/lflang/generator/LFGenerator.xtend diff --git a/org.lflang/src/org/lflang/generator/LFGenerator.java b/org.lflang/src/org/lflang/generator/LFGenerator.java new file mode 100644 index 0000000000..de97390667 --- /dev/null +++ b/org.lflang/src/org/lflang/generator/LFGenerator.java @@ -0,0 +1,111 @@ +/* Generated by Xtext 2.17.0 and then modified to support specific targets. */ + +/************* + * Copyright (c) 2019-2020, 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.generator + +import java.lang.reflect.InvocationTargetException; +import java.util.EnumMap; +import java.util.Spliterators; +import java.util.stream.Stream; +import java.util.stream.StreamSupport; + +import org.eclipse.emf.common.util.TreeIterator; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.xtext.generator.AbstractGenerator; +import org.eclipse.xtext.generator.IFileSystemAccess2; +import org.eclipse.xtext.generator.IGeneratorContext; +import org.jetbrains.annotations.NotNull; +import org.lflang.Target; +import org.lflang.lf.TargetDecl; + +/** + * Generates code from your model files on save. + *

+ * See https://www.eclipse.org/Xtext/documentation/303_runtime_concepts.html#code-generation + */ +class LFGenerator extends AbstractGenerator { + + // Indicator of whether generator errors occurred. + private boolean generatorErrorsOccurred = false; + private static final EnumMap> TARGET_MAP; + + + static { + TARGET_MAP = new EnumMap<>(Target.class); + TARGET_MAP.put(Target.C, CGenerator.class); + TARGET_MAP.put(Target.CCPP, CCppGenerator.class); + TARGET_MAP.put(Target.CPP, CppGenerator.class); + TARGET_MAP.put(Target.TS, TypeScriptGenerator.class); + TARGET_MAP.put(Target.Python, PythonGenerator.class); + } + + + private static GeneratorBase getGenerator(Target target) { + assert target != null; + Class generatorClass = TARGET_MAP.get(target); + assert generatorClass != null; + try { + return generatorClass.getConstructor().newInstance(); + } catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) { + throw new AssertionError("Missing constructor in " + generatorClass, e); + } + } + + + @Override + public void doGenerate(Resource resource, IFileSystemAccess2 fsa, IGeneratorContext context) { + // Determine which target is desired. + + String targetName = findTargetNameOrThrow(resource); + Target target = Target.forName(targetName); + if (target == null) { + throw new AssertionError("Not a target '" + targetName + "'"); + } + GeneratorBase generator = getGenerator(target); + generator.doGenerate(resource, fsa, context); + generatorErrorsOccurred |= generator.errorsOccurred(); + } + + + private String findTargetNameOrThrow(Resource resource) { + return streamNodes(resource) + .filter(TargetDecl.class::isInstance) + .map(it -> ((TargetDecl) it).getName()) + .findFirst() + .orElseThrow(() -> new AssertionError("No target declaration")); + } + + + @NotNull + private Stream streamNodes(Resource resource) { + TreeIterator allContents = resource.getAllContents(); + return StreamSupport.stream(Spliterators.spliteratorUnknownSize(allContents, 0), false); + } + + + /** Return true if errors occurred in the last call to doGenerate(). */ + public boolean errorsOccurred() { + return generatorErrorsOccurred; + } + +} diff --git a/org.lflang/src/org/lflang/generator/LFGenerator.xtend b/org.lflang/src/org/lflang/generator/LFGenerator.xtend deleted file mode 100644 index c88af69517..0000000000 --- a/org.lflang/src/org/lflang/generator/LFGenerator.xtend +++ /dev/null @@ -1,83 +0,0 @@ -/* Generated by Xtext 2.17.0 and then modified to support specific targets. */ - -/************* - * Copyright (c) 2019-2020, 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.generator - -import org.eclipse.emf.ecore.resource.Resource -import org.eclipse.xtext.generator.AbstractGenerator -import org.eclipse.xtext.generator.IFileSystemAccess2 -import org.eclipse.xtext.generator.IGeneratorContext -import org.lflang.Target -import org.lflang.lf.TargetDecl - -/** - * Generates code from your model files on save. - * - * See https://www.eclipse.org/Xtext/documentation/303_runtime_concepts.html#code-generation - */ -class LFGenerator extends AbstractGenerator { - - // Indicator of whether generator errors occurred. - protected var generatorErrorsOccurred = false - - override void doGenerate(Resource resource, IFileSystemAccess2 fsa, - IGeneratorContext context) { - // Determine which target is desired. - var GeneratorBase generator - - val t = Target.forName( - resource.allContents.toIterable.filter(TargetDecl).head.name) - - switch (t) { - case C: { - generator = new CGenerator() - } - case CCPP: { - generator = new CCppGenerator() - } - case CPP: { - generator = new CppGenerator() - } - case TS: { - generator = new TypeScriptGenerator() - } - case Python: { - generator = new PythonGenerator() - } - } - - generator.doGenerate(resource, fsa, context) - generatorErrorsOccurred = generator.errorsOccurred() - } - - /** - * Return true if errors occurred in the last call to doGenerate(). - * @return True if errors occurred. - */ - def errorsOccurred() { - return generatorErrorsOccurred; - } - -} From 1bfbc83959c9753e383d44e1e0eedd38fb07ef15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Thu, 22 Apr 2021 01:15:46 +0200 Subject: [PATCH 18/88] Java -> kotlin --- .../src/org/lflang/generator/LFGenerator.java | 111 ------------------ .../src/org/lflang/generator/LFGenerator.kt | 76 ++++++++++++ 2 files changed, 76 insertions(+), 111 deletions(-) delete mode 100644 org.lflang/src/org/lflang/generator/LFGenerator.java create mode 100644 org.lflang/src/org/lflang/generator/LFGenerator.kt diff --git a/org.lflang/src/org/lflang/generator/LFGenerator.java b/org.lflang/src/org/lflang/generator/LFGenerator.java deleted file mode 100644 index de97390667..0000000000 --- a/org.lflang/src/org/lflang/generator/LFGenerator.java +++ /dev/null @@ -1,111 +0,0 @@ -/* Generated by Xtext 2.17.0 and then modified to support specific targets. */ - -/************* - * Copyright (c) 2019-2020, 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.generator - -import java.lang.reflect.InvocationTargetException; -import java.util.EnumMap; -import java.util.Spliterators; -import java.util.stream.Stream; -import java.util.stream.StreamSupport; - -import org.eclipse.emf.common.util.TreeIterator; -import org.eclipse.emf.ecore.EObject; -import org.eclipse.emf.ecore.resource.Resource; -import org.eclipse.xtext.generator.AbstractGenerator; -import org.eclipse.xtext.generator.IFileSystemAccess2; -import org.eclipse.xtext.generator.IGeneratorContext; -import org.jetbrains.annotations.NotNull; -import org.lflang.Target; -import org.lflang.lf.TargetDecl; - -/** - * Generates code from your model files on save. - *

- * See https://www.eclipse.org/Xtext/documentation/303_runtime_concepts.html#code-generation - */ -class LFGenerator extends AbstractGenerator { - - // Indicator of whether generator errors occurred. - private boolean generatorErrorsOccurred = false; - private static final EnumMap> TARGET_MAP; - - - static { - TARGET_MAP = new EnumMap<>(Target.class); - TARGET_MAP.put(Target.C, CGenerator.class); - TARGET_MAP.put(Target.CCPP, CCppGenerator.class); - TARGET_MAP.put(Target.CPP, CppGenerator.class); - TARGET_MAP.put(Target.TS, TypeScriptGenerator.class); - TARGET_MAP.put(Target.Python, PythonGenerator.class); - } - - - private static GeneratorBase getGenerator(Target target) { - assert target != null; - Class generatorClass = TARGET_MAP.get(target); - assert generatorClass != null; - try { - return generatorClass.getConstructor().newInstance(); - } catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) { - throw new AssertionError("Missing constructor in " + generatorClass, e); - } - } - - - @Override - public void doGenerate(Resource resource, IFileSystemAccess2 fsa, IGeneratorContext context) { - // Determine which target is desired. - - String targetName = findTargetNameOrThrow(resource); - Target target = Target.forName(targetName); - if (target == null) { - throw new AssertionError("Not a target '" + targetName + "'"); - } - GeneratorBase generator = getGenerator(target); - generator.doGenerate(resource, fsa, context); - generatorErrorsOccurred |= generator.errorsOccurred(); - } - - - private String findTargetNameOrThrow(Resource resource) { - return streamNodes(resource) - .filter(TargetDecl.class::isInstance) - .map(it -> ((TargetDecl) it).getName()) - .findFirst() - .orElseThrow(() -> new AssertionError("No target declaration")); - } - - - @NotNull - private Stream streamNodes(Resource resource) { - TreeIterator allContents = resource.getAllContents(); - return StreamSupport.stream(Spliterators.spliteratorUnknownSize(allContents, 0), false); - } - - - /** Return true if errors occurred in the last call to doGenerate(). */ - public boolean errorsOccurred() { - return generatorErrorsOccurred; - } - -} diff --git a/org.lflang/src/org/lflang/generator/LFGenerator.kt b/org.lflang/src/org/lflang/generator/LFGenerator.kt new file mode 100644 index 0000000000..fefd1690c6 --- /dev/null +++ b/org.lflang/src/org/lflang/generator/LFGenerator.kt @@ -0,0 +1,76 @@ +/* Generated by Xtext 2.17.0 and then modified to support specific targets. */ +/************* + * Copyright (c) 2019-2020, 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.generator + +import org.eclipse.emf.ecore.resource.Resource +import org.eclipse.xtext.generator.AbstractGenerator +import org.eclipse.xtext.generator.IFileSystemAccess2 +import org.eclipse.xtext.generator.IGeneratorContext +import org.lflang.Target +import org.lflang.lf.TargetDecl +import java.util.* + +/** + * Generates code from your model files on save. + * + * + * See https://www.eclipse.org/Xtext/documentation/303_runtime_concepts.html#code-generation + */ +internal class LFGenerator : AbstractGenerator() { + /** Indicator of whether generator errors occurred in the last call to doGenerate(). */ + var generatorErrorsOccurred = false + private set + + companion object { + private val TARGET_MAP: Map> = mapOf( + Target.C to CGenerator::class.java, + Target.CCPP to CCppGenerator::class.java, + Target.CPP to CppGenerator::class.java, + Target.TS to TypeScriptGenerator::class.java, + Target.Python to PythonGenerator::class.java + ) + + private fun getGenerator(target: Target): GeneratorBase { + val generatorClass = TARGET_MAP[target]!! + return try { + generatorClass.getConstructor().newInstance() + } catch (e: Exception) { + throw AssertionError("Missing constructor in $generatorClass", e) + } + } + } + + override fun doGenerate(resource: Resource, fsa: IFileSystemAccess2, context: IGeneratorContext) { + // Determine which target is desired. + val targetName = findTargetNameOrThrow(resource) + val target = Target.forName(targetName) ?: throw AssertionError("Not a target '$targetName'") + val generator = getGenerator(target) + generator.doGenerate(resource, fsa, context) + generatorErrorsOccurred = generatorErrorsOccurred or generator.errorsOccurred() + } + + private fun findTargetNameOrThrow(resource: Resource): String = + resource.allContents.asSequence() + .mapNotNull { it as? TargetDecl } + .firstOrNull() + ?.name + ?: throw AssertionError("No target declaration") +} From 244f5cef10d4ea1d067a614ddd593d84440b779f Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Wed, 21 Apr 2021 22:14:20 -0700 Subject: [PATCH 19/88] Let Xtext create Java files, not Xtend files. --- org.lflang/src/org/lflang/GenerateLinguaFranca.mwe2 | 2 ++ 1 file changed, 2 insertions(+) diff --git a/org.lflang/src/org/lflang/GenerateLinguaFranca.mwe2 b/org.lflang/src/org/lflang/GenerateLinguaFranca.mwe2 index 701d256666..c1a00e5687 100644 --- a/org.lflang/src/org/lflang/GenerateLinguaFranca.mwe2 +++ b/org.lflang/src/org/lflang/GenerateLinguaFranca.mwe2 @@ -27,6 +27,7 @@ Workflow { encoding = "UTF-8" lineDelimiter = "\n" fileHeader = "/*\n * generated by Xtext \${version}\n */" + preferXtendStubs = false } } language = StandardLanguage { @@ -43,6 +44,7 @@ Workflow { } junitSupport = { junitVersion = "5" + generateXtendStub = false } parserGenerator = { debugGrammar = true From 814e4cf7b23455c4138152f3cb683d54ad88667e Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Wed, 21 Apr 2021 22:15:54 -0700 Subject: [PATCH 20/88] Beginning to port auto-gen files to Java. --- .../src/org/lflang/LFRuntimeModule.java | 27 +++++++++ .../src/org/lflang/LFStandaloneSetup.java | 15 +++++ .../src/org/lflang/generator/LFGenerator.java | 60 +++++++++++++++++++ 3 files changed, 102 insertions(+) create mode 100644 org.lflang/src/org/lflang/LFRuntimeModule.java create mode 100644 org.lflang/src/org/lflang/LFStandaloneSetup.java create mode 100644 org.lflang/src/org/lflang/generator/LFGenerator.java diff --git a/org.lflang/src/org/lflang/LFRuntimeModule.java b/org.lflang/src/org/lflang/LFRuntimeModule.java new file mode 100644 index 0000000000..4d7d7fee34 --- /dev/null +++ b/org.lflang/src/org/lflang/LFRuntimeModule.java @@ -0,0 +1,27 @@ +/* + * generated by Xtext 2.23.0 + */ +package org.lflang; + +import org.lflang.scoping.LFGlobalScopeProvider; +import org.lflang.validation.LFNamesAreUniqueValidationHelper; + +/** + * Use this class to register components to be used at runtime / without the Equinox extension registry. + */ +public class LFRuntimeModule extends AbstractLFRuntimeModule { + /** Establish a binding to our custom global scope provider. */ + @Override + public Class bindIGlobalScopeProvider() { + return LFGlobalScopeProvider.class; + } + + /** Establish a binding to a helper that checks that names are unique. */ + public Class bindNamesAreUniqueValidationHelper() { + return LFNamesAreUniqueValidationHelper.class; + } + /** Establish a binding to our custom resource description strategy. */ +// fun bindIDefaultResourceDescriptionStrategy(): Class = LFResourceDescriptionStrategy::class.java + + +} diff --git a/org.lflang/src/org/lflang/LFStandaloneSetup.java b/org.lflang/src/org/lflang/LFStandaloneSetup.java new file mode 100644 index 0000000000..5c7d5ddb56 --- /dev/null +++ b/org.lflang/src/org/lflang/LFStandaloneSetup.java @@ -0,0 +1,15 @@ +/* + * generated by Xtext 2.23.0 + */ +package org.lflang; + + +/** + * Initialization support for running Xtext languages without Equinox extension registry. + */ +public class LFStandaloneSetup extends LFStandaloneSetupGenerated { + + public static void doSetup() { + new LFStandaloneSetup().createInjectorAndDoEMFRegistration(); + } +} diff --git a/org.lflang/src/org/lflang/generator/LFGenerator.java b/org.lflang/src/org/lflang/generator/LFGenerator.java new file mode 100644 index 0000000000..a5ebdadff2 --- /dev/null +++ b/org.lflang/src/org/lflang/generator/LFGenerator.java @@ -0,0 +1,60 @@ +package org.lflang.generator; + +import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.xtext.generator.AbstractGenerator; +import org.eclipse.xtext.generator.IFileSystemAccess2; +import org.eclipse.xtext.generator.IGeneratorContext; +import org.eclipse.xtext.xbase.lib.IteratorExtensions; +import org.lflang.Target; +import org.lflang.lf.TargetDecl + +/** + * Generates code from your model files on save. + * + * See https://www.eclipse.org/Xtext/documentation/303_runtime_concepts.html#code-generation + */ +public class LFGenerator extends AbstractGenerator { + + // Indicator of whether generator errors occurred. + protected boolean generatorErrorsOccurred = false; + + public void doGenerate(Resource resource, IFileSystemAccess2 fsa, + IGeneratorContext context) { + // Determine which target is desired. + GeneratorBase generator; + + Target t = Target.forName( + resource.getAllContents().filter(TargetDecl).head.name); + + switch (t) { + case C: { + generator = new CGenerator(); + } + case CCPP: { + generator = new CCppGenerator(); + } + case CPP: { + generator = new CppGenerator(); + } + case TS: { + generator = new TypeScriptGenerator(); + } + case Python: { + generator = new PythonGenerator(); + } + } + + generator.doGenerate(resource, fsa, context); + generatorErrorsOccurred = generator.errorsOccurred(); + } + + /** + * Return true if errors occurred in the last call to doGenerate(). + * @return + * @return True if errors occurred. + */ + public boolean errorsOccurred() { + return generatorErrorsOccurred; + } + +} \ No newline at end of file From dbe4c2d0db65547c039238965ff5d5cdf1aa2988 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Wed, 21 Apr 2021 22:16:37 -0700 Subject: [PATCH 21/88] Remove redundant files. --- org.lflang/src/org/lflang/LFRuntimeModule.kt | 47 ----------- .../src/org/lflang/LFStandaloneSetup.kt | 36 -------- .../org/lflang/generator/LFGenerator.xtend | 83 ------------------- 3 files changed, 166 deletions(-) delete mode 100644 org.lflang/src/org/lflang/LFRuntimeModule.kt delete mode 100644 org.lflang/src/org/lflang/LFStandaloneSetup.kt delete mode 100644 org.lflang/src/org/lflang/generator/LFGenerator.xtend diff --git a/org.lflang/src/org/lflang/LFRuntimeModule.kt b/org.lflang/src/org/lflang/LFRuntimeModule.kt deleted file mode 100644 index 2d59fb81ee..0000000000 --- a/org.lflang/src/org/lflang/LFRuntimeModule.kt +++ /dev/null @@ -1,47 +0,0 @@ -/* - * 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 - -import org.eclipse.xtext.resource.IDefaultResourceDescriptionStrategy -import org.eclipse.xtext.scoping.IGlobalScopeProvider -import org.eclipse.xtext.validation.INamesAreUniqueValidationHelper -import org.lflang.scoping.LFGlobalScopeProvider -import org.lflang.validation.LFNamesAreUniqueValidationHelper - -/** - * This class is used to register components to be used at runtime - * / without the Equinox extension registry. - */ -class LFRuntimeModule : AbstractLFRuntimeModule() { - - /** Establish a binding to our custom global scope provider. */ - override fun bindIGlobalScopeProvider(): Class = LFGlobalScopeProvider::class.java - - /** Establish a binding to a helper that checks that names are unique. */ - fun bindNamesAreUniqueValidationHelper(): Class = LFNamesAreUniqueValidationHelper::class.java - /** Establish a binding to our custom resource description strategy. */ -// fun bindIDefaultResourceDescriptionStrategy(): Class = LFResourceDescriptionStrategy::class.java - -} diff --git a/org.lflang/src/org/lflang/LFStandaloneSetup.kt b/org.lflang/src/org/lflang/LFStandaloneSetup.kt deleted file mode 100644 index ac21664eee..0000000000 --- a/org.lflang/src/org/lflang/LFStandaloneSetup.kt +++ /dev/null @@ -1,36 +0,0 @@ -/* - * 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 - -/** - * - */ -object LFStandaloneSetup : LFStandaloneSetupGenerated() { - - @JvmStatic - fun doSetup() { - createInjectorAndDoEMFRegistration() - } -} diff --git a/org.lflang/src/org/lflang/generator/LFGenerator.xtend b/org.lflang/src/org/lflang/generator/LFGenerator.xtend deleted file mode 100644 index c88af69517..0000000000 --- a/org.lflang/src/org/lflang/generator/LFGenerator.xtend +++ /dev/null @@ -1,83 +0,0 @@ -/* Generated by Xtext 2.17.0 and then modified to support specific targets. */ - -/************* - * Copyright (c) 2019-2020, 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.generator - -import org.eclipse.emf.ecore.resource.Resource -import org.eclipse.xtext.generator.AbstractGenerator -import org.eclipse.xtext.generator.IFileSystemAccess2 -import org.eclipse.xtext.generator.IGeneratorContext -import org.lflang.Target -import org.lflang.lf.TargetDecl - -/** - * Generates code from your model files on save. - * - * See https://www.eclipse.org/Xtext/documentation/303_runtime_concepts.html#code-generation - */ -class LFGenerator extends AbstractGenerator { - - // Indicator of whether generator errors occurred. - protected var generatorErrorsOccurred = false - - override void doGenerate(Resource resource, IFileSystemAccess2 fsa, - IGeneratorContext context) { - // Determine which target is desired. - var GeneratorBase generator - - val t = Target.forName( - resource.allContents.toIterable.filter(TargetDecl).head.name) - - switch (t) { - case C: { - generator = new CGenerator() - } - case CCPP: { - generator = new CCppGenerator() - } - case CPP: { - generator = new CppGenerator() - } - case TS: { - generator = new TypeScriptGenerator() - } - case Python: { - generator = new PythonGenerator() - } - } - - generator.doGenerate(resource, fsa, context) - generatorErrorsOccurred = generator.errorsOccurred() - } - - /** - * Return true if errors occurred in the last call to doGenerate(). - * @return True if errors occurred. - */ - def errorsOccurred() { - return generatorErrorsOccurred; - } - -} From 9911f4ce10eec14600e596ab31d7b49d8eba1d63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Thu, 22 Apr 2021 01:33:12 +0200 Subject: [PATCH 22/88] Start a kotlin generator base --- org.lflang/src/org/lflang/Extensions.kt | 6 +- .../src/org/lflang/generator/CppGenerator2.kt | 137 + .../lflang/generator/KotlinGeneratorBase.kt | 73 + .../src/org/lflang/generator/SomeKotlin.kt | 2244 +++++++++++++++++ 4 files changed, 2459 insertions(+), 1 deletion(-) create mode 100644 org.lflang/src/org/lflang/generator/CppGenerator2.kt create mode 100644 org.lflang/src/org/lflang/generator/KotlinGeneratorBase.kt create mode 100644 org.lflang/src/org/lflang/generator/SomeKotlin.kt diff --git a/org.lflang/src/org/lflang/Extensions.kt b/org.lflang/src/org/lflang/Extensions.kt index 28ac1a70a8..fae1b4d68a 100644 --- a/org.lflang/src/org/lflang/Extensions.kt +++ b/org.lflang/src/org/lflang/Extensions.kt @@ -25,7 +25,8 @@ package org.lflang import org.lflang.lf.* -import java.lang.AssertionError +import java.lang.Exception +import kotlin.reflect.KClass fun ReactorDecl?.toDefinition(): Reactor? = when (this) { @@ -91,3 +92,6 @@ val Reactor.allTimers: List get() = superClassRecursor { timers } private fun Reactor.superClassRecursor(collector: Reactor.() -> List): List = superClasses.orEmpty().mapNotNull { it.toDefinition()?.collector() }.flatten() + this.collector() + + +fun List.tail() = subList(1, size) diff --git a/org.lflang/src/org/lflang/generator/CppGenerator2.kt b/org.lflang/src/org/lflang/generator/CppGenerator2.kt new file mode 100644 index 0000000000..b5bf056870 --- /dev/null +++ b/org.lflang/src/org/lflang/generator/CppGenerator2.kt @@ -0,0 +1,137 @@ +/* + * 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.generator + +import org.lflang.ASTUtils +import org.lflang.InferredType +import org.lflang.Target +import org.lflang.lf.* + +/** + * + */ +class CppGenerator2 : GeneratorBase() { + + + /** + * Return a string representing the specified type in the target language. + * @param type The type. + */ + private fun getTargetType(type: InferredType, undefinedType ): String { + val _isUndefined = type.isUndefined + if (_isUndefined) { + return this.getTargetUndefinedType() + } else { + if (type.isTime.toBoolean()) { + return if (type.isFixedSizeList.toBoolean()) { + this.getTargetFixedSizeListType(this.getTargetTimeType(), type.listSize) + } else { + if (type.isVariableSizeList.toBoolean()) { + this.getTargetVariableSizeListType(this.getTargetTimeType()) + } else { + this.getTargetTimeType() + } + } + } else { + if (type.isFixedSizeList.toBoolean()) { + return this.getTargetFixedSizeListType(type.baseType(), type.listSize) + } else { + if (type.isVariableSizeList.toBoolean()) { + return this.getTargetVariableSizeListType(type.baseType()) + } + } + } + } + return type.toText() + } + + fun StateVar.getTargetType(): String = getTargetType(ASTUtils.getInferredType(this)) + fun Action.getTargetType(): String = getTargetType(ASTUtils.getInferredType(this)) + fun Port.getTargetType(): String = getTargetType(ASTUtils.getInferredType(this)) + fun Type.getTargetType(): String = getTargetType(ASTUtils.getInferredType(this)) + fun Parameter.getTargetType(): String = getTargetType(ASTUtils.getInferredType(this)) + + + +/* + + def declareParameters(Reactor r) ''' + «FOR p : r.parameters BEFORE '// parameters\n' AFTER '\n'» + std::add_const<«p.targetType»>::type «p.name»; + «ENDFOR» + ''' + */ + + fun Reactor.declareParameters() = + parameters.joinToString(prefix = "// parameters\n", postfix = "\n") { + "std::add_const<${it.targetType}>::type ${it.name};" + } + + + 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") + } + + override fun supportsGenerics(): Boolean { + TODO("Not yet implemented") + } + + override fun getTargetTimeType(): String { + TODO("Not yet implemented") + } + + override fun getTargetTagType(): String { + TODO("Not yet implemented") + } + + override fun getTargetTagIntervalType(): String { + TODO("Not yet implemented") + } + + override fun getTargetUndefinedType(): String { + TODO("Not yet implemented") + } + + override fun getTargetFixedSizeListType(baseType: String?, size: Int?): String { + TODO("Not yet implemented") + } + + override fun getTargetVariableSizeListType(baseType: String?): String { + TODO("Not yet implemented") + } + + override fun getTarget(): Target { + TODO("Not yet implemented") + } + +} diff --git a/org.lflang/src/org/lflang/generator/KotlinGeneratorBase.kt b/org.lflang/src/org/lflang/generator/KotlinGeneratorBase.kt new file mode 100644 index 0000000000..2997296fe2 --- /dev/null +++ b/org.lflang/src/org/lflang/generator/KotlinGeneratorBase.kt @@ -0,0 +1,73 @@ +/* + * 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.generator + +import org.lflang.ASTUtils +import org.lflang.InferredType +import org.lflang.Target +import org.lflang.lf.* + +/** + * + */ +abstract class KotlinGeneratorBase(val target: Target) { + + abstract fun generateDelayBody(action: Action, port: VarRef): String + abstract fun generateForwardBody(action: Action, port: VarRef): String + abstract fun generateDelayGeneric(): String + abstract fun supportsGenerics(): Boolean + abstract fun getTargetTimeType(): String + abstract fun getTargetTagType(): String + abstract fun getTargetTagIntervalType(): String + abstract fun getTargetUndefinedType(): String + abstract fun getTargetFixedSizeListType(baseType: String, size: Int): String + abstract fun getTargetVariableSizeListType(baseType: String): String + + + /** Return a string representing the specified type in the target language. */ + protected fun getTargetType(type: InferredType): String = when { + type.isUndefined -> this.getTargetUndefinedType() + type.isTime -> when { + type.isFixedSizeList -> this.getTargetFixedSizeListType(this.getTargetTimeType(), type.listSize) + type.isVariableSizeList -> this.getTargetVariableSizeListType(this.getTargetTimeType()) + else -> this.getTargetTimeType() + } + type.isFixedSizeList -> this.getTargetFixedSizeListType(type.baseType(), type.listSize) + type.isVariableSizeList -> this.getTargetVariableSizeListType(type.baseType()) + else -> type.toText() + } + + + val StateVar.targetType: String get() = getTargetType(ASTUtils.getInferredType(this)) + val Action.targetType: String get() = getTargetType(ASTUtils.getInferredType(this)) + val Port.targetType: String get() = getTargetType(ASTUtils.getInferredType(this)) + val Type.targetType: String get() = getTargetType(ASTUtils.getInferredType(this)) + val Parameter.targetType: String get() = getTargetType(ASTUtils.getInferredType(this)) +} + + +class Foo { + +} diff --git a/org.lflang/src/org/lflang/generator/SomeKotlin.kt b/org.lflang/src/org/lflang/generator/SomeKotlin.kt new file mode 100644 index 0000000000..568381fa7d --- /dev/null +++ b/org.lflang/src/org/lflang/generator/SomeKotlin.kt @@ -0,0 +1,2244 @@ +/** + * Generator base class for shared code between code generators. + */ +package org.lflang.generator + +import com.google.common.collect.Iterables +import org.eclipse.core.resources.IMarker +import org.eclipse.core.resources.IResource +import org.eclipse.core.resources.ResourcesPlugin +import org.eclipse.emf.ecore.EObject +import org.eclipse.emf.ecore.resource.Resource +import org.eclipse.xtend2.lib.StringConcatenation +import org.eclipse.xtext.generator.IFileSystemAccess2 +import org.eclipse.xtext.generator.IGeneratorContext +import org.eclipse.xtext.nodemodel.util.NodeModelUtils +import org.eclipse.xtext.resource.XtextResource +import org.eclipse.xtext.validation.CheckMode +import org.eclipse.xtext.xbase.lib.* +import org.lflang.* +import org.lflang.Target +import org.lflang.graph.InstantiationGraph +import org.lflang.lf.* +import org.lflang.validation.AbstractLFValidator +import java.io.* +import java.net.URI +import java.nio.file.Files +import java.nio.file.Path +import java.nio.file.Paths +import java.nio.file.StandardCopyOption +import java.util.* +import java.util.regex.Pattern +import kotlin.collections.LinkedHashMap +import kotlin.collections.LinkedHashSet +import kotlin.math.max + +/** + * Generator base class for shared code between code generators. + * This extends AbstractLinguaFrancaValidator so that errors can be highlighted + * in the XText-based IDE. + * + * @author{Edward A. Lee @berkeley.edu>} + * @author{Marten Lohstroh @berkeley.edu>} + * @author{Christian Menard @tu-dresden.de} + * @author{Matt Weber @berkeley.edu>} + */ +abstract class GeneratorBase(val target: Target) : AbstractLFValidator() { + /** + * Defines the execution environment that is used to execute binaries. + * + * A given command may be directly executable on the host (NATIVE) + * or it may need to be executed within a bash shell (BASH). + * On Unix-like machines, this is typically determined by the PATH variable + * which could be different in these two environments. + */ + enum class ExecutionEnvironment { + NATIVE, BASH + } + + /** + * Parsed error message from a compiler is returned here. + */ + protected class ErrorFileAndLine { + var filepath = null as String? + var line = "1" + var character = "0" + var message = "" + var isError = true + } + + /** + * All code goes into this string buffer. + */ + protected var code = StringBuilder() + + /** + * The current target configuration. + */ + protected var targetConfig = TargetConfig() + + /** + * The current file configuration. NOTE: not initialized until the + * invocation of doGenerate, which calls setFileConfig. + */ + protected var fileConfig: FileConfig? = null + + /** + * [Mode.STANDALONE][.Mode.STANDALONE] if the code generator is being + * called from the command line, [Mode.INTEGRATED][.Mode.INTEGRATED] + * if it is being called from the Eclipse IDE, and + * [Mode.UNDEFINED][.Mode.UNDEFINED] otherwise. + */ + var mode = Mode.UNDEFINED + + /** + * Collection of generated delay classes. + */ + private val delayClasses = LinkedHashSet() + + /** + * Set the fileConfig field to point to the specified resource using the specified + * file-system access and context. + * @param resource The resource (Eclipse-speak for a file). + * @param fsa The Xtext abstraction for the file system. + * @param context The generator context (whatever that is). + */ + open fun setFileConfig(resource: Resource, fsa: IFileSystemAccess2, context: IGeneratorContext) { + fileConfig = FileConfig(resource, fsa, context) + topLevelName = fileConfig!!.name + } + + /** + * Indicator of whether generator errors occurred. + * This is set to true by the report() method and returned by the + * errorsOccurred() method. + */ + protected var generatorErrorsOccurred = false + + /** + * If running in an Eclipse IDE, the iResource refers to the + * IFile representing the Lingua Franca program. + * This is the XText view of the file, which is distinct + * from the Eclipse eCore view of the file and the OS view of the file. + */ + protected var iResource = null as IResource? + + /** + * The main (top-level) reactor instance. + */ + protected var main: ReactorInstance? = null + + /** + * Definition of the main (top-level) reactor. + * This is an automatically generated AST node for the top-level + * reactor. + */ + protected var mainDef: Instantiation? = null + + /** + * A list of Reactor definitions in the main resource, including non-main + * reactors defined in imported resources. These are ordered in the list in + * such a way that each reactor is preceded by any reactor that it instantiates + * using a command like `foo = new Foo();` + */ + protected var reactors: MutableList = mutableListOf() + + /** + * The set of resources referenced reactor classes reside in. + */ + protected var resources: MutableSet = CollectionLiterals.newLinkedHashSet() + + /** + * Graph that tracks dependencies between instantiations. + * This is a graph where each node is a Reactor (not a ReactorInstance) + * and an arc from Reactor A to Reactor B means that B contains an instance of A, constructed with a statement + * like `a = new A();` After creating the graph, + * sort the reactors in topological order and assign them to the reactors class variable. + * Hence, after this method returns, `this.reactors` will be a list of Reactors such that any + * reactor is preceded in the list by reactors that it instantiates. + */ + protected var instantiationGraph: InstantiationGraph? = null + + /** + * The set of unordered reactions. An unordered reaction is one that does + * not have any dependency on other reactions in the containing reactor, + * and where no other reaction in the containing reactor depends on it. + * There is currently no way in the syntax of LF to make a reaction + * unordered, deliberately, because it can introduce unexpected + * nondeterminacy. However, certain automatically generated reactions are + * known to be safe to be unordered because they do not interact with the + * state of the containing reactor. To make a reaction unordered, when + * the Reaction instance is created, add that instance to this set. + */ + protected var unorderedReactions: MutableSet? = null + + /** + * Indicates whether or not the current Lingua Franca program + * contains a federation. + */ + protected var isFederated = false + + /** + * A list of federate instances or a list with a single empty string + * if there are no federates specified. FIXME: Why put a single empty string there? It should be just empty... + */ + protected var federates: MutableList = LinkedList() + + /** + * A map from federate IDs to federate instances. + */ + protected var federateByID: MutableMap = LinkedHashMap() + + /** + * A map from instantiations to the federate instances for that instantiation. + * If the instantiation has a width, there may be more than one federate instance. + */ + protected var federatesByInstantiation: MutableMap>? = null + + /** + * The federation RTI properties, which defaults to 'localhost: 15045'. + */ + protected val federationRTIProperties = mutableMapOf( + "host" to "localhost", + "port" to 0 + ) + + /** + * Contents of $LF_CLASSPATH, if it was set. + */ + protected var classpathLF: String? = null + + /** + * The index available to user-generated reaction that delineates the index + * of the reactor in a bank of reactors. The value must be set to zero + * in generated code for reactors that are not in a bank + */ + protected var targetBankIndex = "bank_index" + + /** + * The type of the bank index, which must be an integer in the target language + */ + protected var targetBankIndexType = "int" + + /** + * The name of the top-level reactor. + */ + protected var topLevelName: String? = null + + /** + * Map from builder to its current indentation. + */ + private val indentation = LinkedHashMap() + + /** + * Store the given reactor in the collection of generated delay classes + * and insert it in the AST under the top-level reactors node. + */ + fun addDelayClass(generatedDelay: Reactor) { + delayClasses.add(generatedDelay) + val model = fileConfig!!.resource.allContents.asSequence().mapNotNull { it as? Model }.firstOrNull() + model?.reactors?.add(generatedDelay) + } + + /** + * Return the generated delay reactor that corresponds to the given class + * name if it had been created already, `null` otherwise. + */ + fun findDelayClass(className: String): Reactor? = + delayClasses.firstOrNull { it.name == className } + + + fun setTargetConfig(context: IGeneratorContext) { + // If there are any physical actions, ensure the threaded engine is used. + for (action in fileConfig.resource.allContents.toIterable.filter(Action)) { + if (action.origin == ActionOrigin.PHYSICAL) { + targetConfig.threads = 1 + } + } + + val target = fileConfig.resource.findTarget + if (target.config !== null) { + // Update the configuration according to the set target properties. + TargetProperty.update(this.targetConfig, target.config.pairs ?: emptyList) + } + + // Override target properties if specified as command line arguments. + if (context is StandaloneContext) { + if (context.args.containsKey("no-compile")) { + targetConfig.noCompile = true + } + if (context.args.containsKey("threads")) { + targetConfig.threads = Integer.parseInt(context.args.getProperty("threads")) + } + if (context.args.containsKey("target-compiler")) { + targetConfig.compiler = context.args.getProperty("target-compiler") + } + if (context.args.containsKey("target-flags")) { + targetConfig.compilerFlags.clear() + if (context.args.getProperty("target-flags").isNotEmpty()) { + targetConfig.compilerFlags.addAll(context.args.getProperty("target-flags").split(' ')) + } + } + } + } + + /** + * If there is a main or federated reactor, then create a synthetic Instantiation + * for that top-level reactor and set the field mainDef to refer to it. + */ + fun createMainInstance() { + // Find the main reactor and create an AST node for its instantiation. + for (reactor in fileConfig!!.resource.allContents.asSequence().filterIsInstance()) { + if (reactor.isMain || reactor.isFederated) { + // Creating an definition for the main reactor because there isn't one. + this.mainDef = LfFactory.eINSTANCE.createInstantiation().apply { + name = reactor.name + reactorClass = reactor + } + } + } + } + + /** + * Generate code from the Lingua Franca model contained by the specified resource. + * + * This is the main entry point for code generation. This base class finds all + * reactor class definitions, including any reactors defined in imported .lf files + * (except any main reactors in those imported files), and adds them to the + * [reactors][.GeneratorBase.reactors] list. If errors occur during + * generation, then a subsequent call to errorsOccurred() will return true. + * @param resource The resource containing the source code. + * @param fsa The file system access (used to write the result). + * @param context Context relating to invocation of the code generator. + * In stand alone mode, this object is also used to relay CLI arguments. + */ + open fun doGenerate(resource: Resource, fsa: IFileSystemAccess2, context: IGeneratorContext) { + + setFileConfig(resource, fsa, context) + + setMode() + + printInfo() + + // Clear any markers that may have been created by a previous build. + // Markers mark problems in the Eclipse IDE when running in integrated mode. + clearMarkers() + + val fileConfig = fileConfig!! + ASTUtils.setMainName(fileConfig.resource, fileConfig.name) + + createMainInstance() + + // Check if there are any conflicting main reactors elsewhere in the package. + if (mainDef !== null) { + for (conflict in MainConflictChecker(fileConfig).conflicts) { + reportError(this.mainDef!!.reactorClass, "Conflicting main reactor in $conflict") + } + } + + setTargetConfig(context) + + // If federates are specified in the target, create a mapping + // from Instantiations in the main reactor to federate names. + // Also create a list of federate names or a list with a single + // empty name if there are no federates specified. + // This must be done before desugaring delays below. + analyzeFederates() + + // Process target files. Copy each of them into the src-gen dir. + copyUserFiles() + + // Collect reactors and create an instantiation graph. These are needed to figure out which resources we need + // to validate, which happens in setResources(). + setReactorsAndInstantiationGraph() + + // Collect the reactors defined in this resource (i.e., file in Eclipse speak) and (non-main) + // reactors defined in imported resources. + setResources(context) + + // Reroute connections that have delays associated with them via generated delay reactors. + transformDelays() + + // Invoke this function a second time because transformations may have introduced new reactors! + setReactorsAndInstantiationGraph() + + // First, produce any preamble code that the code generator needs + // to produce before anything else goes into the code generated files. + generatePreamble() // FIXME: Move this elsewhere. See awkwardness with CppGenerator because it will not even + // use the result. + } + + /** + * Create a new instantiation graph. This is a graph where each node is a Reactor (not a ReactorInstance) + * and an arc from Reactor A to Reactor B means that B contains an instance of A, constructed with a statement + * like `a = new A();` After creating the graph, + * sort the reactors in topological order and assign them to the reactors class variable. + * Hence, after this method returns, `this.reactors` will be a list of Reactors such that any + * reactor is preceded in the list by reactors that it instantiates. + */ + protected fun setReactorsAndInstantiationGraph() { + // Build the instantiation graph . + val fileConfig = fileConfig!! + val instantiationGraph = InstantiationGraph(fileConfig.resource, false) + this.instantiationGraph = instantiationGraph + + // Topologically sort the reactors such that all of a reactor's instantiation dependencies occur earlier in + // the sorted list of reactors. This helps the code generator output code in the correct order. + // For example if `reactor Foo {bar = new Bar()}` then the definition of `Bar` has to be generated before + // the definition of `Foo`. + this.reactors = instantiationGraph.nodesInTopologicalOrder() + + // If there is no main reactor, then make sure the reactors list includes + // even reactors that are not instantiated anywhere. + if (mainDef === null) { + for (r in fileConfig.resource.allContents.asSequence().filterIsInstance()) { + if (r !in this.reactors) { + this.reactors.add(r) + } + } + } + } + + /** + * For each involved resource, replace connections with delays with generated delay reactors. + */ + protected fun transformDelays() { + for (r in resources) { + ASTUtils.insertGeneratedDelays(r, this) + } + } + + /** + * Update the class variable that lists all the involved resources. Also report validation problems of imported + * resources at the import statements through those failing resources are reached. + * + * @param context The context providing the cancel indicator used by the validator. + */ + protected fun setResources(context: IGeneratorContext) { + val fileConfig = this.fileConfig!! + val validator = (fileConfig.resource as XtextResource).resourceServiceProvider.resourceValidator + val mainDef = mainDef + if (mainDef != null) { + reactors.add(mainDef.reactorClass as Reactor) + } + // Iterate over reactors and mark their resources as tainted if they import resources that are either marked + // as tainted or fail to validate. + val tainted = mutableSetOf() + for (r in this.reactors) { + val res = r.eResource() + if (!this.resources.contains(res)) { + if (res !== fileConfig.resource) { + if (tainted.contains(res) + || validator.validate(res, CheckMode.ALL, context.cancelIndicator).isNotEmpty() + ) { + + for (inst in this.instantiationGraph!!.getDownstreamAdjacentNodes(r)) { + for (imp in (inst.eContainer() as Model).imports) { + for (decl in imp.reactorClasses) { + if (decl.reactorClass.eResource() === res) { + reportError(imp, """Unresolved compilation issues in "${imp.importURI}".""") + tainted.add(decl.eResource()) + } + } + } + } + } + } + this.resources.add(res) + } + } + } + + /** + * Copy all files listed in the target property `files` into the + * specified directory. + */ + protected open fun copyUserFiles() { +// Make sure the target directory exists. + val fileConfig = this.fileConfig!! + val targetDir = fileConfig.srcGenPath!! + Files.createDirectories(targetDir) + + for (filename in targetConfig.fileNames) { + val file: File? = FileConfig.findFile(filename, fileConfig.srcFile.parent) + if (file != null) { + val target = targetDir.resolve(file.name) + Files.deleteIfExists(target) + Files.copy(file.toPath(), target) + targetConfig.filesNamesWithoutPath.add(file.name) + } else { + // Try to copy the file as a resource. + // If this is missing, it should have been previously reported as an error. + try { + val filenameWithoutPath = filename.substringAfterLast(File.separatorChar) + copyFileFromClassPath(filename, targetDir.resolve(filenameWithoutPath).toString()) + targetConfig.filesNamesWithoutPath.add(filenameWithoutPath) + } catch (ex: IOException) { + // Ignore. Previously reported as a warning. + System.err.println("WARNING: Failed to find file $filename.") + } + } + } + } + + /** + * Return true if errors occurred in the last call to doGenerate(). + * This will return true if any of the reportError methods was called. + * @return True if errors occurred. + */ + fun errorsOccurred(): Boolean { + return generatorErrorsOccurred + } + + /** + * Generate code for the body of a reaction that takes an input and + * schedules an action with the value of that input. + * @param action the action to schedule + * @param port the port to read from + */ + abstract fun generateDelayBody(action: Action, port: VarRef): String? + + /** + * Generate code for the body of a reaction that is triggered by the + * given action and writes its value to the given port. + * @param action the action that triggers the reaction + * @param port the port to write to + */ + abstract fun generateForwardBody(action: Action, port: VarRef): String? + + /** + * Generate code for the generic type to be used in the class definition + * of a generated delay reactor. + */ + abstract fun generateDelayGeneric(): String? + + /** + * Generate code for referencing a port, action, or timer. + * @param reference The referenced variable. + */ + fun generateVarRef(reference: VarRef): String { + var prefix = "" + if (reference.container !== null) { + prefix = reference.container.name + "." + } + return prefix + reference.variable.name + } + + /** + * Return true if the reaction is unordered. An unordered reaction is one + * that does not have any dependency on other reactions in the containing + * reactor, and where no other reaction in the containing reactor depends + * on it. There is currently no way in the syntax of LF to make a reaction + * unordered, deliberately, because it can introduce unexpected + * nondeterminacy. However, certain automatically generated reactions are + * known to be safe to be unordered because they do not interact with the + * state of the containing reactor. To make a reaction unordered, when + * the Reaction instance is created, add that instance to this set. + * @return True if the reaction has been marked unordered. + */ + fun isUnordered(reaction: Reaction): Boolean = + unorderedReactions?.contains(reaction) == true + + /** + * Mark the reaction unordered. An unordered reaction is one that does not + * have any dependency on other reactions in the containing reactor, and + * where no other reaction in the containing reactor depends on it. There + * is currently no way in the syntax of LF to make a reaction unordered, + * deliberately, because it can introduce unexpected nondeterminacy. + * However, certain automatically generated reactions are known to be safe + * to be unordered because they do not interact with the state of the + * containing reactor. To make a reaction unordered, when the Reaction + * instance is created, add that instance to this set. + * @param reaction The reaction to make unordered. + */ + fun makeUnordered(reaction: Reaction): Boolean = + unorderedReactions?.add(reaction) ?: let { + unorderedReactions = mutableSetOf(reaction) + true + } + + /** + * Given a representation of time that may possibly include units, return + * a string that the target language can recognize as a value. In this base + * class, if units are given, e.g. "msec", then we convert the units to upper + * case and return an expression of the form "MSEC(value)". Particular target + * generators will need to either define functions or macros for each possible + * time unit or override this method to return something acceptable to the + * target language. + * @param time A TimeValue that represents a time. + * @return A string, such as "MSEC(100)" for 100 milliseconds. + */ + open fun timeInTargetLanguage(time: TimeValue?): String = + if (time !== null) { + if (time.unit != TimeUnit.NONE) { + time.unit.name + '(' + time.time + ')' + } else { + time.time.toString() + } + } else + "0" // FIXME: do this or throw exception? + + /** + * Create the runtime infrastructure (RTI) source file. + */ + open fun createFederateRTI() { + val fileConfig = fileConfig!! + + // Derive target filename from the .lf filename. + val cFilename = fileConfig.name + "_RTI.c" + + // Delete source previously produced by the LF compiler. + var file = fileConfig.rtiSrcPath.resolve(cFilename) + Files.deleteIfExists(file) + // Also make sure the directory exists. + Files.createDirectories(file.parent) + + // Delete binary previously produced by the C compiler. + file = fileConfig.rtiBinPath.resolve(fileConfig.name) + Files.deleteIfExists(file) + + val rtiCode = StringBuilder() + pr( + rtiCode, """ + #ifdef NUMBER_OF_FEDERATES + #undefine NUMBER_OF_FEDERATES + #endif + #define NUMBER_OF_FEDERATES ${federates.size} + #include "rti.c" + int main(int argc, char* argv[]) { + """ + ) + indent(rtiCode) + + // Initialize the array of information that the RTI has about the + // federates. + // FIXME: No support below for some federates to be FAST and some REALTIME. + pr( + rtiCode, """ + for (int i = 0; i < NUMBER_OF_FEDERATES; i++) { + initialize_federate(i); + ${ + if (targetConfig.fastMode) + "federates[i].mode = FAST;" + else "" + } + } + """ + ) + // Initialize the arrays indicating connectivity to upstream and downstream federates. + for (federate in federates) { + if (federate.dependsOn.isNotEmpty()) { + // Federate receives non-physical messages from other federates. + // Initialize the upstream and upstream_delay arrays. + val numUpstream = federate.dependsOn.size + // Allocate memory for the arrays storing the connectivity information. + pr( + rtiCode, """ + federates[${federate.id}].upstream = (int*)malloc(sizeof(federate_t*) * ${numUpstream}); + federates[${federate.id}].upstream_delay = (interval_t*)malloc(sizeof(interval_t*) * ${numUpstream}); + federates[${federate.id}].num_upstream = ${numUpstream}; + """ + ) + // Next, populate these arrays. + // Find the minimum delay in the process. + // FIXME: Zero delay is not really the same as a microstep delay. + var count = 0 + for (upstreamFederate: federate.dependsOn.keySet) { + pr( + rtiCode, """ + federates[${federate.id}].upstream[${count}] = ${upstreamFederate.id}; + federates[${federate.id}].upstream_delay[${count}] = 0LL; + """ + ) + // The minimum delay calculation needs to be made in the C code because it + // may depend on parameter values. + // FIXME: These would have to be top-level parameters, which don't really + // have any support yet. Ideally, they could be overridden on the command line. + // When that is done, they will need to be in scope here. + val delays = federate.dependsOn.get(upstreamFederate) + if (delays !== null) { + for (delay in delays) { + pr( + rtiCode, """ + if (federates[${federate.id}].upstream_delay[${count}] < ${delay.getRTITime}) { + federates[${federate.id}].upstream_delay[${count}] = ${delay.getRTITime}; + } + """ + ) + } + } + count++ + } + } + // Next, set up the downstream array. + if (federate.sendsTo.isNotEmpty()) { + // Federate sends non-physical messages to other federates. + // Initialize the downstream array. + val numDownstream = federate.sendsTo.size + // Allocate memory for the array. + pr( + rtiCode, """ + federates[${federate.id}].downstream = (int*)malloc(sizeof(federate_t*) * ${numDownstream}); + federates[${federate.id}].num_downstream = ${numDownstream}; + """ + ) + // Next, populate the array. + // Find the minimum delay in the process. + // FIXME: Zero delay is not really the same as a microstep delay. + for ((count, downstreamFederate) in federate.sendsTo.keys.withIndex()) { + pr( + rtiCode, """ + federates[${federate.id}].downstream[${count}] = ${downstreamFederate.id}; + """ + ) + } + } + } + + // Start the RTI server before launching the federates because if it + // fails, e.g. because the port is not available, then we don't want to + // launch the federates. + // Also generate code that blocks until the federates resign. + pr( + rtiCode, """ + int socket_descriptor = start_rti_server(${federationRTIProperties["port"]}); + wait_for_federates(socket_descriptor); + """ + ) + + unindent(rtiCode) + pr(rtiCode, "}") + + Files.write( + fileConfig.rtiSrcPath.resolve(cFilename), + rtiCode.toString().toByteArray() + ) + } + + /** + * Invoke the C compiler on the generated RTI + * The C RTI is used across targets. Thus we need to be able to compile + * it from GeneratorBase. + */ + fun compileRTI(): Boolean { + val fileToCompile = fileConfig!!.name + "_RTI" + return runCCompiler(fileToCompile, false) + } + + /** + * Run the C compiler. + * + * This is required here in order to allow any target to compile the RTI. + * + * @param file The source file to compile without the .c extension. + * @param doNotLinkIfNoMain If true, the compile command will have a + * `-c` flag when there is no main reactor. If false, the compile command + * will never have a `-c` flag. + * + * @return true if compilation succeeds, false otherwise. + */ + open fun runCCompiler(file: String, doNotLinkIfNoMain: Boolean): Boolean { + val compile = compileCCommand(file, doNotLinkIfNoMain) ?: return false + + val stderr = ByteArrayOutputStream() + val returnCode = compile.executeCommand(stderr) + + if (returnCode != 0 && mode !== Mode.INTEGRATED) { + reportError("""${targetConfig.compiler} returns error code $returnCode""") + } + // For warnings (vs. errors), the return code is 0. + // But we still want to mark the IDE. + if (stderr.size() > 0 && mode === Mode.INTEGRATED) { + reportCommandErrors(stderr.toString()) + } + return (returnCode == 0) + } + + /** + * Run the custom build command specified with the "build" parameter. + * This command is executed in the same directory as the source file. + */ + protected fun runBuildCommand() { + val commands = mutableListOf() + for (cmd in targetConfig.buildCommands) { + val tokens = cmd.split("\\s+") + if (tokens.size > 1) { + val buildCommand = createCommand(tokens.first(), tokens.tail(), this.fileConfig!!.srcPath) + ?: return + // If the build command could not be found, abort. + // An error has already been reported in createCommand. + commands.add(buildCommand) + } + } + + for (cmd in commands) { + val stderr = ByteArrayOutputStream() + val returnCode = cmd.executeCommand(stderr) + + if (returnCode != 0 && mode !== Mode.INTEGRATED) { + reportError("""Build command "${targetConfig.buildCommands}" returns error code $returnCode""") + return + } + // For warnings (vs. errors), the return code is 0. + // But we still want to mark the IDE. + if (stderr.size() > 0 && mode == Mode.INTEGRATED) { + reportCommandErrors(stderr.toString()) + return + } + } + } + + /** + * Return a command to compile the specified C file. + * This produces a C specific compile command. Since this command is + * used across targets to build the RTI, it needs to be available in + * GeneratorBase. + * + * @param fileToCompile The C filename without the .c extension. + * @param doNotLinkIfNoMain If true, the compile command will have a + * `-c` flag when there is no main reactor. If false, the compile command + * will never have a `-c` flag. + */ + protected fun compileCCommand(fileToCompile: String, doNotLinkIfNoMain: Boolean): ProcessBuilder? { + val env = findCommandEnv(targetConfig.compiler) + + val cFilename = getTargetFileName(fileToCompile) + val fileConfig = fileConfig!! + + val relativeSrcPath = fileConfig.outPath.relativize(fileConfig.srcGenPath.resolve(cFilename)) + val relativeBinPath = fileConfig.outPath.relativize(fileConfig.binPath.resolve(fileToCompile)) + + // NOTE: we assume that any C compiler takes Unix paths as arguments. + val relSrcPathString = FileConfig.toUnixString(relativeSrcPath) + var relBinPathString = FileConfig.toUnixString(relativeBinPath) + + // If there is no main reactor, then generate a .o file not an executable. + if (mainDef === null) { + relBinPathString += ".o" + } + + val compileArgs = mutableListOf() + compileArgs.add(relSrcPathString) + compileArgs.addAll(targetConfig.compileAdditionalSources) + compileArgs.addAll(targetConfig.compileLibraries) + + // Only set the output file name if it hasn't already been set + // using a target property or Args line flag. + if (compileArgs.all { it.trim() != "-o" }) { + compileArgs.addAll(listOf("-o", relBinPathString)) + } + + // If threaded computation is requested, add a -pthread option. + + if (targetConfig.threads != 0 || targetConfig.tracing !== null) { + compileArgs.add("-pthread") + // If the LF program itself is threaded or if tracing is enabled, we need to define + // NUMBER_OF_WORKERS so that platform-specific C files will contain the appropriate functions + compileArgs.add("-DNUMBER_OF_WORKERS=${targetConfig.threads}") + } + // Finally add the compiler flags in target parameters (if any) + if (targetConfig.compilerFlags.isNotEmpty()) { + compileArgs.addAll(targetConfig.compilerFlags) + } + // If there is no main reactor, then use the -c flag to prevent linking from occurring. + // FIXME: we could add a `-c` flag to `lfc` to make this explicit in stand-alone mode. + // Then again, I think this only makes sense when we can do linking. + // In any case, a warning is helpful to draw attention to the fact that no binary was produced. + if (doNotLinkIfNoMain && main == null) { + compileArgs.add("-c") // FIXME: revisit + if (mode == Mode.STANDALONE) { + reportError("ERROR: Did not output executable; no main reactor found.") + } + } + return createCommand(targetConfig.compiler, compileArgs, fileConfig.outPath, env) + } + + /** + * Produces the filename including the target-specific extension + */ + protected open fun getTargetFileName(fileName: String): String = "$fileName.c" + + /** + * Clear the buffer of generated code. + */ + protected fun clearCode(): StringBuilder = StringBuilder().also { this.code = it } + + /** + * Get the specified file as an Eclipse IResource or, if it is not found, then + * return the iResource for the main file. + * For some inexplicable reason, Eclipse uses a mysterious parallel to the file + * system, and when running in INTEGRATED mode, for some things, you cannot access + * files by referring to their file system location. Instead, you have to refer + * to them relative the workspace root. This is required, for example, when marking + * the file with errors or warnings or when deleting those marks. + * + * @param uri A java.net.uri of the form "file://path". + */ + protected fun getEclipseResource(uri: URI?): IResource? { + var resource = iResource // Default resource. + // For some peculiar reason known only to Eclipse developers, + // the resource cannot be used directly but has to be converted + // a resource relative to the workspace root. + val workspaceRoot = ResourcesPlugin.getWorkspace().root + // The following uses a java.net.URI, which, + // pathetically, cannot be distinguished in xtend from a org.eclipse.emf.common.util.URI. + if (uri !== null) { + // Pathetically, Eclipse requires a java.net.uri, not a org.eclipse.emf.common.util.URI. + val files = workspaceRoot.findFilesForLocationURI(uri) + if (files !== null && files.isNotEmpty() && files[0] !== null) { + resource = files[0] + } + } + return resource + } + + /** + * Clear markers in the IDE if running in integrated mode. + * This has the side effect of setting the iResource variable to point to + * the IFile for the Lingua Franca program. + * Also reset the flag indicating that generator errors occurred. + */ + protected fun clearMarkers(): Boolean { + if (mode == Mode.INTEGRATED) { + try { + val resource = getEclipseResource(fileConfig!!.srcFile.toURI()) + // First argument can be null to delete all markers. + // But will that delete xtext markers too? + resource?.deleteMarkers(IMarker.PROBLEM, true, IResource.DEPTH_INFINITE) + } catch (e: Exception) { + // Ignore, but print a warning. + println("Warning: Deleting markers in the IDE failed: $e") + } + } + generatorErrorsOccurred = false + return false + } + + /** + * Run a given command and record its output. + * + * @param cmd the command to be executed + * @param errStream a stream object to forward the commands error messages to + * @param outStream a stream object to forward the commands output messages to + * @return the commands return code + */ + protected fun executeCommand(cmd: ProcessBuilder, errStream: OutputStream? = null, outStream: OutputStream? = null): Int { + println("--- Current working directory: \${cmd.directory.toString()}") + println("--- Executing command: ${cmd.command().joinToString(" ")}") + + val outStreams = mutableListOf() + val errStreams = mutableListOf() + outStreams.add(System.out) + errStreams.add(System.err) + if (outStream != null) { + outStreams.add(outStream) + } + if (errStream != null) { + errStreams.add(errStream) + } + + // Execute the command. Write output to the System output, + // but also keep copies in outStream and errStream + return cmd.runSubprocess(outStreams, errStreams) + + } + + /** + * It tries to find the command with 'which ' (or 'where ' on Windows). + * If that fails, it tries again with bash. + * In case this fails again, raise an error. + * + * Return ExecutionEnvironment.NATIVE + * if the specified command is directly executable on the current host + * Returns ExecutionEnvironment.BASH + * if the command must be executed within a bash shell. + * + * The latter occurs, for example, if the specified command + * is not in the native path but is in the path + * specified by the user's bash configuration file. + * If the specified command is not found in either the native environment + * nor the bash environment, + * then this reports and error and returns null. + * + * @param cmd The command to be find. + * @return Returns an ExecutionEnvironment. + */ + protected fun findCommandEnv(cmd: String): ExecutionEnvironment? { + // Make sure the command is found in the PATH. + print("--- Looking for command $cmd ...") + // Use 'where' on Windows, 'which' on other systems + val which = if (System.getProperty("os.name").startsWith("Windows")) "where" else "which" + val whichBuilder = ProcessBuilder(which, cmd) + val whichReturn = whichBuilder.start().waitFor() + if (whichReturn == 0) { + println("SUCCESS") + + return ExecutionEnvironment.NATIVE + } + println("FAILED") + // Try running with bash. + // The --login option forces bash to look for and load the first of + // ~/.bash_profile, ~/.bash_login, and ~/.bashrc that it finds. + print("--- Trying again with bash ... ") + val bashCommand = listOf("bash", "--login", "-c", "which $cmd") + val bashBuilder = ProcessBuilder(bashCommand) + val bashOut = ByteArrayOutputStream() + val bashReturn = bashBuilder.runSubprocess(#[bashOut], #[]) + if (bashReturn == 0) { + println("SUCCESS") + return ExecutionEnvironment.BASH + } + reportError( + """The command $cmd could not be found. +Make sure that your PATH variable includes the directory where $cmd is installed. +You can set PATH in ~/.bash_profile on Linux or Mac.""" + ) + return null + + } + + /** + * Create a ProcessBuilder for a given command. + * + * This method makes sure that the given command is executable, + * It first tries to find the command with 'which cmake'. If that + * fails, it tries again with bash. In case this fails again, + * it returns null. Otherwise, a correctly constructed ProcessBuilder + * object is returned. + * + * A bit more context: + * If the command cannot be found directly, then a second attempt is made using a + * Bash shell with the --login option, which sources the user's + * ~/.bash_profile, ~/.bash_login, or ~/.bashrc (whichever + * is first found) before running the command. This helps to ensure that + * the user's PATH variable is set according to their usual environment, + * assuming that they use a bash shell. + * + * More information: Unfortunately, at least on a Mac if you are running + * within Eclipse, the PATH variable is extremely limited; supposedly, it + * is given by the default provided in /etc/paths, but at least on my machine, + * it does not even include directories in that file for some reason. + * One way to add a directory like + * /usr/local/bin to the path once-and-for-all is this: + * + * sudo launchctl config user path /usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin + * + * But asking users to do that is not ideal. Hence, we try a more hack-y + * approach of just trying to execute using a bash shell. + * Also note that while ProcessBuilder can configured to use custom + * environment variables, these variables do not affect the command that is + * to be executed but merely the environment in which the command executes. + * + * @param cmd The command to be executed + * @param args A list of arguments for the given command + * @param dir the directory to change into before executing the command. + * @param env is the type of the Execution Environment. + * @return A ProcessBuilder object if the command was found or null otherwise. + */ + protected fun createCommand( + cmd: String, + args: List = emptyList(), + dir: Path = fileConfig!!.outPath, + env: ExecutionEnvironment? = findCommandEnv(cmd) + ): ProcessBuilder? { + if (env == ExecutionEnvironment.NATIVE) { + val builder = ProcessBuilder(cmd, *args.toTypedArray()) + builder.directory(dir.toFile()) + return builder + } else if (env == ExecutionEnvironment.BASH) { + val bashArg = args.joinToString(separator = " ", prefix = "$cmd ") + // use that command to build the process + val builder = ProcessBuilder("bash", "--login", "-c", bashArg) + builder.directory(dir.toFile()) + return builder + } + println("FAILED") + reportError( + """The command $cmd could not be found. +Make sure that your PATH variable includes the directory where $cmd is installed. +You can set PATH in ~/.bash_profile on Linux or Mac.""" + ) + return null + } + + /** + * Creates a ProcessBuilder for a given command and its arguments. + * + * This method returns correctly constructed ProcessBuilder object + * according to the Execution environment. It finds the execution environment using findCommandEnv(). + * Raise an error if the env is null. + * + * @param cmd The command to be executed + * @param args A list of arguments for the given command + * @return A ProcessBuilder object if the command was found or null otherwise. + */ + protected fun createCommand(cmd: String, args: List, dir: Path): ProcessBuilder? { + val env = findCommandEnv(cmd) + return this.createCommand(cmd, args, dir, env) + } + + /** + * Return the target. + */ + fun findTarget(resource: Resource): TargetDecl? { + val targets = resource.allContents.asSequence().filterIsInstance().toList() + when { + targets.isEmpty() -> throw RuntimeException("No target found!") + targets.size > 1 -> throw RuntimeException("There is more than one target!") // FIXME: check this in validator + else -> return targets[0] + } + } + + /** + * Generate code for the body of a reaction that handles input from the network + * that is handled by the specified action. This base class throws an exception. + * @param action The action that has been created to handle incoming messages. + * @param sendingPort The output port providing the data to send. + * @param receivingPort The ID of the destination port. + * @param receivingPortID The ID of the destination port. + * @param sendingFed The sending federate. + * @param receivingFed The destination federate. + * @param receivingBankIndex The receiving federate's bank index, if it is in a bank. + * @param receivingChannelIndex The receiving federate's channel index, if it is a multiport. + * @param type The type. + * @throws UnsupportedOperationException If the target does not support this operation. + */ + open fun generateNetworkReceiverBody( + action: Action?, + sendingPort: VarRef?, + receivingPort: VarRef?, + receivingPortID: Int, + sendingFed: FederateInstance?, + receivingFed: FederateInstance?, + receivingBankIndex: Int, + receivingChannelIndex: Int, + type: InferredType? + ): String? { + throw UnsupportedOperationException("This target does not support direct connections between federates.") + } + + // ---ported until HERE--- + + /** + * Generate code for the body of a reaction that handles an output + * that is to be sent over the network. This base class throws an exception. + * @param sendingPort The output port providing the data to send. + * @param receivingPort The ID of the destination port. + * @param receivingPortID The ID of the destination port. + * @param sendingFed The sending federate. + * @param sendingBankIndex The bank index of the sending federate, if it is a bank. + * @param sendingChannelIndex The channel index of the sending port, if it is a multiport. + * @param receivingFed The destination federate. + * @param type The type. + * @param isPhysical Indicates whether the connection is physical or not + * @param delay The delay value imposed on the connection using after + * @throws UnsupportedOperationException If the target does not support this operation. + */ + open fun generateNetworkSenderBody( + sendingPort: VarRef?, + receivingPort: VarRef?, + receivingPortID: Int, + sendingFed: FederateInstance?, + sendingBankIndex: Int, + sendingChannelIndex: Int, + receivingFed: FederateInstance?, + type: InferredType?, + isPhysical: Boolean, + delay: Delay? + ): String? { + throw UnsupportedOperationException("This target does not support direct connections between federates.") + } + + /** + * Generate any preamble code that appears in the code generated + * file before anything else. + */ + protected open fun generatePreamble() { + prComment("Code generated by the Lingua Franca compiler from:") + val _unixString = FileConfig.toUnixString(fileConfig!!.srcFile.toPath()) + val _plus = ("file:/$_unixString") + prComment(_plus) + val models = LinkedHashSet() + var _elvis: List? = null + if (reactors != null) { + _elvis = reactors + } else { + val _emptyList = CollectionLiterals.emptyList() + _elvis = _emptyList + } + for (r: Reactor? in _elvis!!) { + val _eContainer = ASTUtils.toDefinition(r).eContainer() + models.add((_eContainer as Model)) + } + if ((mainDef != null)) { + val _eContainer_1 = ASTUtils.toDefinition(mainDef!!.reactorClass).eContainer() + models.add((_eContainer_1 as Model)) + } + for (m: Model in models) { + val _preambles = m.preambles + for (p: Preamble in _preambles) { + this.pr(ASTUtils.toText(p.code)) + } + } + } + + /** + * Get the code produced so far. + * @return The code produced so far as a String. + */ + protected fun getCode(): String { + return this.code.toString() + } + /** + * Increase the indentation of the output code produced + * on the specified builder. + * @param The builder to indent. + */ + /** + * Increase the indentation of the output code produced. + */ + protected fun indent(builder: StringBuilder = this.code): String? { + var _xblockexpression: String? = null + run { + var prefix: String? = this.indentation[builder] + if ((prefix == null)) { + prefix = "" + } + val _prefix: String = prefix + prefix = (_prefix + " ") + _xblockexpression = this.indentation.put(builder, prefix) + } + return _xblockexpression + } + + /** + * Append the specified text plus a final newline to the current + * code buffer. + * @param format A format string to be used by String.format or + * the text to append if no further arguments are given. + * @param args Additional arguments to pass to the formatter. + */ + protected fun pr(format: String?, vararg args: Any?): StringBuilder? { + var _xifexpression: String? = null + if (((args != null) && (args.size > 0))) { + _xifexpression = String.format((format)!!, *args) + } else { + _xifexpression = format + } + return this.pr(this.code, _xifexpression) + } + + /** + * Append the specified text plus a final newline to the specified + * code buffer. + * @param builder The code buffer. + * @param text The text to append. + */ + protected fun pr(builder: StringBuilder, text: Any?): StringBuilder? { + var _xblockexpression: StringBuilder? = null + run { + var string: String = text.toString() + var indent: String? = this.indentation[builder] + if ((indent == null)) { + indent = "" + } + var _xifexpression: StringBuilder? = null + val _contains: Boolean = string.contains("\n") + if (_contains) { + string = string.replace("\t".toRegex(), " ") + val split: Array = string.split("\n").toTypedArray() + var offset: Int = Int.MAX_VALUE + var firstLine: Boolean = true + for (line: String in split) { + if (firstLine) { + firstLine = false + } else { + val numLeadingSpaces: Int = line.indexOf(line.trim { it <= ' ' }) + if ((numLeadingSpaces < offset)) { + offset = numLeadingSpaces + } + } + } + firstLine = true + for (line_1: String? in split) { + { + builder.append(indent) + if (firstLine) { + builder.append(line_1) + firstLine = false + } else { + builder.append(line_1.substring(offset)) + } + builder.append("\n") + } + } + } else { + var _xblockexpression_1: StringBuilder? = null + { + builder.append(indent) + builder.append(text) + _xblockexpression_1 = builder.append("\n") + } + _xifexpression = _xblockexpression_1 + } + _xblockexpression = _xifexpression + } + return _xblockexpression + } + + /** + * Prints an indented block of text with the given begin and end markers, + * but only if the actions print any text at all. + * This is helpful to avoid the production of empty blocks. + * @param begin The prologue of the block. + * @param end The epilogue of the block. + * @param actions Actions that print the interior of the block. + */ + protected fun prBlock(begin: String?, end: String?, vararg actions: Runnable): StringBuilder? { + var _xblockexpression: StringBuilder? = null + run { + val i: Int = this.code.length + this.indent() + for (action: Runnable in actions) { + action.run() + } + this.unindent() + var _xifexpression: StringBuilder? = null + val _length: Int = this.code.length + val _lessThan: Boolean = (i < _length) + if (_lessThan) { + var _xblockexpression_1: StringBuilder? = null + { + val inserted: String = this.code.substring(i, this.code.length) + this.code.delete(i, this.code.length) + this.pr(begin) + this.code.append(inserted) + _xblockexpression_1 = this.pr(end) + } + _xifexpression = _xblockexpression_1 + } + _xblockexpression = _xifexpression + } + return _xblockexpression + } + + /** + * Leave a marker in the generated code that indicates the original line + * number in the LF source. + * @param eObject The node. + */ + protected open fun prSourceLineNumber(eObject: EObject?): StringBuilder? { + var _xifexpression: StringBuilder? = null + if ((eObject is Code)) { + val _builder = StringConcatenation() + _builder.append("// ") + val _startLine = NodeModelUtils.getNode(eObject).startLine + val _plus = (_startLine + 1) + _builder.append(_plus) + _xifexpression = this.pr(this.code, _builder) + } else { + val _builder_1 = StringConcatenation() + _builder_1.append("// ") + val _startLine_1 = NodeModelUtils.getNode(eObject).startLine + _builder_1.append(_startLine_1) + _xifexpression = this.pr(this.code, _builder_1) + } + return _xifexpression + } + + /** + * Print a comment to the generated file. + * Particular targets will need to override this if comments + * start with something other than '//'. + * @param comment The comment. + */ + protected fun prComment(comment: String): StringBuilder? { + return this.pr(this.code, ("// $comment")) + } + + /** + * Given a line of text from the output of a compiler, return + * an instance of ErrorFileAndLine if the line is recognized as + * the first line of an error message. Otherwise, return null. + * This base class simply returns null. + * @param line A line of output from a compiler or other external + * tool that might generate errors. + * @return If the line is recognized as the start of an error message, + * then return a class containing the path to the file on which the + * error occurred (or null if there is none), the line number (or the + * string "1" if there is none), the character position (or the string + * "0" if there is none), and the message (or an empty string if there + * is none). + */ + protected open fun parseCommandOutput(line: String?): ErrorFileAndLine? { + return null + } + + /** + * Parse the specified string for command errors that can be reported + * using marks in the Eclipse IDE. In this class, we attempt to parse + * the messages to look for file and line information, thereby generating + * marks on the appropriate lines. This should only be called if + * mode == INTEGRATED. + * + * @param stderr The output on standard error of executing a command. + */ + protected fun reportCommandErrors(stderr: String): String? { + val message = StringBuilder() + var lineNumber: Int? = null + var resource: IResource? = this.getEclipseResource(this.fileConfig!!.srcFile.toURI()) + val originalResource: IResource? = resource + var severity: Int = IMarker.SEVERITY_ERROR + + for (line in stderr.lines()) { + val parsed = parseCommandOutput(line) + if (parsed != null) { + // Found a new line number designator. + // If there is a previously accumulated message, report it. + + if (message.isNotEmpty()) { + this.report(message.toString(), severity, lineNumber, resource) + if (originalResource != resource) { + // Report an error also in the top-level resource. + // FIXME: It should be possible to descend through the import + // statements to find which one matches and mark all the + // import statements down the chain. But what a pain! + this.report( + "Error in imported file: " + resource?.fullPath, + IMarker.SEVERITY_ERROR, + null, originalResource + ) + } + } + severity = if (parsed.isError) { + IMarker.SEVERITY_ERROR + } else { + IMarker.SEVERITY_WARNING + } + + // Start accumulating a new message. + message.setLength(0) + // Append the message on the line number designator line. + message.append(parsed.message) + + // Set the new line number. + lineNumber = try { + Integer.decode(parsed.line) + } catch (_t: Exception) { + null + } + + // FIXME: Ignoring the position within the line. + // Determine the resource within which the error occurred. + // Sadly, Eclipse defines an interface called "URI" that conflicts with the + // Java one, so we have to give the full class name here. + resource = this.getEclipseResource(URI(parsed.filepath)) + } else { + // No line designator. + if (message.isNotEmpty()) { + message.append("\n") + } else { + if ("warning:" in line.toLowerCase()) { + severity = IMarker.SEVERITY_WARNING + } + } + message.append(line) + } + } + + if (message.isNotEmpty()) { + report(message.toString(), severity, lineNumber, resource) + if (originalResource != resource) { + // Report an error also in the top-level resource. + // FIXME: It should be possible to descend through the import + // statements to find which one matches and mark all the + // import statements down the chain. But what a pain! + report( + "Error in imported file: " + resource.fullPath, + IMarker.SEVERITY_ERROR, + null, + originalResource + ) + } + } + } + + /** + * Lookup a file in the classpath and copy its contents to a destination path + * in the filesystem. + * + * This also creates new directories for any directories on the destination + * path that do not yet exist. + * + * @param source The source file as a path relative to the classpath. + * @param destination The file system path that the source file is copied to. + */ + protected fun copyFileFromClassPath(source: String, destination: String): Long { + val sourceStream = this::class.java.getResourceAsStream(source) + + if (sourceStream == null) { + throw IOException( + "A required target resource could not be found: " + source + "\n" + + "Perhaps a git submodule is missing or not up to date.\n" + + "See https://github.com/icyphy/lingua-franca/wiki/downloading-and-building#clone-the-lingua-franca-repository.\n" + + "Also try to refresh and clean the project explorer if working from eclipse." + ) + } + + // Copy the file. + try { + // Make sure the directory exists + val destFile = File(destination) + destFile.parentFile.mkdirs() + + Files.copy(sourceStream, Paths.get(destination), StandardCopyOption.REPLACE_EXISTING) + } catch (ex: IOException) { + throw IOException( + "A required target resource could not be copied: " + source + "\n" + + "Perhaps a git submodule is missing or not up to date.\n" + + "See https://github.com/icyphy/lingua-franca/wiki/downloading-and-building#clone-the-lingua-franca-repository.", + ex + ) + } finally { + sourceStream.close() + } + } + + /** + * Copy a list of files from a given source directory to a given destination directory. + * @param srcDir The directory to copy files from. + * @param dstDir The directory to copy files to. + * @param files The files to copy. + */ + protected fun copyFilesFromClassPath(srcDir: String, dstDir: String, files: List) { + for (file: String in files) { + copyFileFromClassPath("$srcDir/$file", dstDir + File.separator + file) + } + } + + /** + * If the mode is INTEGRATED (the code generator is running in an + * an Eclipse IDE), then refresh the project. This will ensure that + * any generated files become visible in the project. + */ + protected fun refreshProject(): String? { + if (mode == Mode.INTEGRATED) { + // Find name of current project + val id = "((:?[a-z]|[A-Z]|_\\w)*)" + val pattern: Pattern = if (File.separator.equals("/")) { // Linux/Mac file separator + Pattern.compile("platform:" + File.separator + "resource" + File.separator + id + File.separator) + } else { // Windows file separator + Pattern.compile( + "platform:" + File.separator + File.separator + "resource" + File.separator + File.separator + + id + File.separator + File.separator + ) + } + val matcher = pattern.matcher(code) + var projName = "" + if (matcher.find()) { + projName = matcher.group(1) + } + try { + val members = ResourcesPlugin.getWorkspace().root.members + for (member in members) { + // Refresh current project, or simply entire workspace if project name was not found + if (projName == "" || projName.equals(member.fullPath.toString().substring(1))) { + member.refreshLocal(IResource.DEPTH_INFINITE, null) + println("Refreshed " + member.fullPath) + } + } + } catch (e: IllegalStateException) { + println("Unable to refresh workspace: $e") + } + } + } + + /** + * Report a warning or error on the specified line of the specified resource. + * The caller should not throw an exception so execution can continue. + * This will print the error message to stderr. + * If running in INTEGRATED mode (within the Eclipse IDE), then this also + * adds a marker to the editor. + * @param message The error message. + * @param severity One of IMarker.SEVERITY_ERROR or IMarker.SEVERITY_WARNING + * @param line The line number or null if it is not known. + * @param object The Ecore object, or null if it is not known. + * @param resource The resource, or null if it is not known. + */ + protected fun report(message: String, severity: Int, line: Int?, `object`: EObject?, resource: IResource?): String { + if (severity == IMarker.SEVERITY_ERROR) { + generatorErrorsOccurred = true + } + val header = if (severity == IMarker.SEVERITY_ERROR) "ERROR: " else "WARNING: " + val lineAsString = if (line === null) "" else "Line $line" + + val fullPath: String = let { + var p = resource?.fullPath?.toString() + if (p == null) { + if (`object` != null && `object`.eResource() !== null) + p = FileConfig.toPath(`object`.eResource()).toString() + if (p == null) { + p = if (line == null) "" else "path unknown" + } + } + p + } + + + System.err.println("$header$fullPath $lineAsString\n$message") + + // If running in INTEGRATED mode, create a marker in the IDE for the error. + // See: https://help.eclipse.org/2020-03/index.jsp?topic=%2Forg.eclipse.platform.doc.isv%2Fguide%2FresAdv_markers.htm + if (mode === Mode.INTEGRATED) { + var myResource = resource + if (myResource === null && `object` != null) { + // Attempt to identify the IResource from the object. + val eResource = `object`.eResource() + if (eResource !== null) { + val uri = FileConfig.toPath(eResource).toUri() + myResource = getEclipseResource(uri) + } + } + // If the resource is still null, use the resource associated with + // the top-level file. + if (myResource === null) { + myResource = iResource + } + if (myResource !== null) { + val marker = myResource.createMarker(IMarker.PROBLEM) + marker.setAttribute(IMarker.MESSAGE, message) + if (line !== null) { + marker.setAttribute(IMarker.LINE_NUMBER, line) + } else { + marker.setAttribute(IMarker.LINE_NUMBER, 1) + } + // Human-readable line number information. + marker.setAttribute(IMarker.LOCATION, lineAsString) + // Mark as an error or warning. + marker.setAttribute(IMarker.SEVERITY, severity) + marker.setAttribute(IMarker.PRIORITY, IMarker.PRIORITY_HIGH) + + marker.setAttribute(IMarker.USER_EDITABLE, false) + + // NOTE: It might be useful to set a start and end. + // marker.setAttribute(IMarker.CHAR_START, 0); + // marker.setAttribute(IMarker.CHAR_END, 5); + } + } + + // Return a string that can be inserted into the generated code. + if (severity == IMarker.SEVERITY_ERROR) { + return "[[ERROR: $message]]" + } + return "" + } + + /** + * Report a warning or error on the specified parse tree object in the + * current resource. + * The caller should not throw an exception so execution can continue. + * If running in INTEGRATED mode (within the Eclipse IDE), then this also + * adds a marker to the editor. + * @param message The error message. + * @param severity One of IMarker.SEVERITY_ERROR or IMarker.SEVERITY_WARNING + * @param `object` The parse tree object or null if not known. + */ + protected fun report(message: String, severity: Int, obj: EObject?): String { + var line: Int? = null + if (obj != null) { + val node = NodeModelUtils.getNode(obj) + if ((node != null)) { + line = Integer.valueOf(node.startLine) + } + } + return this.report(message, severity, line, obj, null) + } + + /** + * Report a warning or error on the specified parse tree object in the + * current resource. + * The caller should not throw an exception so execution can continue. + * If running in INTEGRATED mode (within the Eclipse IDE), then this also + * adds a marker to the editor. + * @param message The error message. + * @param severity One of IMarker.SEVERITY_ERROR or IMarker.SEVERITY_WARNING + * @param resource The resource. + */ + protected fun report(message: String, severity: Int, line: Int?, resource: IResource?): String { + return this.report(message, severity, line, null, resource) + } + + /** + * Report an error. + * @param message The error message. + */ + protected fun reportError(message: String): String { + return this.report(message, IMarker.SEVERITY_ERROR, null) + } + + /** + * Report an error on the specified parse tree object. + * @param object The parse tree object. + * @param message The error message. + */ + protected fun reportError(`object`: EObject?, message: String): String { + return this.report(message, IMarker.SEVERITY_ERROR, `object`) + } + + /** + * Report a warning on the specified parse tree object. + * @param object The parse tree object. + * @param message The error message. + */ + protected fun reportWarning(`object`: EObject?, message: String): String { + return this.report(message, IMarker.SEVERITY_WARNING, `object`) + } + + /** + * Reduce the indentation by one level for generated code + * in the default code buffer. + */ + protected fun unindent(builder: StringBuilder = this.code) { + var indent = indentation[builder] ?: return + val end = indent.length - 4 + indent = indent.substring(0, max(0, end)) + indentation[builder] = indent + } + + /** + * Create a list of default parameter initializers in target code. + * + * @param param The parameter to create initializers for + * @return A list of initializers in target code + */ + protected fun getInitializerList(param: Parameter?): LinkedList { + val list = LinkedList() + for (i in param?.init.orEmpty()) { + if (ASTUtils.isOfTimeType(param)) { + list.add(this.getTargetTime(i)) + } else { + list.add(getTargetValue(i)) + } + } + return list + } + + /** + * Create a list of state initializers in target code. + * + * @param this@getInitializerList The state variable to create initializers for + * @return A list of initializers in target code + */ + protected val StateVar?.initializerList: List? + get() = if (ASTUtils.isInitialized(this)) { + this?.init.orEmpty().map { + when { + it.parameter != null -> (getTargetReference(it.parameter)) + ASTUtils.isOfTimeType(this) -> (this@GeneratorBase.getTargetTime(it)) + else -> (getTargetValue(it)) + } + } + } else { + null + } + + /** + * Create a list of parameter initializers in target code in the context + * of an reactor instantiation. + * + * This respects the parameter assignments given in the reactor + * instantiation and falls back to the reactors default initializers + * if no value is assigned to it. + * + * @param param The parameter to create initializers for + * @return A list of initializers in target code + */ + protected fun getInitializerList(param: Parameter?, i: Instantiation?): List? { + if (i === null || param === null) { + return null + } + + val assignments = i.parameters.filter { it.lhs === param } + + return if (assignments.isEmpty()) { + // the parameter was not overwritten in the instantiation + param.initializerList() + } else { + // the parameter was overwritten in the instantiation + val ofTimeType = param.isOfTimeType + assignments.firstOrNull()?.rhs.orEmpty().map { + if (ofTimeType) init.targetTime + else init.targetValue + } + } + } + + /** + * Generate target code for a parameter reference. + * + * @param param The parameter to generate code for + * @return Parameter reference in target code + */ + protected open fun getTargetReference(param: Parameter): String { + return param.name + } + + /** + * If the argument is a multiport, return a list of strings + * describing the width of the port, and otherwise, return null. + * If the list is empty, then the width is variable (specified + * as '[]'). Otherwise, it is a list of integers and/or parameter + * references obtained by getTargetReference(). + * @param variable The port. + * @return The width specification for a multiport or null if it is + * not a multiport. + */ + protected fun multiportWidthSpec(variable: Variable?): List? { + if (variable !is Port || variable.widthSpec == null) return null + val result = LinkedList() + if (!variable.widthSpec.isOfVariableLength) { + for (term in variable.widthSpec.terms) { + if (term.parameter !== null) { + result.add(getTargetReference(term.parameter)) + } else { + result.add(term.width.toString()) + } + } + } + return result + + } + + /** + * If the argument is a multiport, then return a string that + * gives the width as an expression, and otherwise, return null. + * The string will be empty if the width is variable (specified + * as '[]'). Otherwise, if is a single term or a sum of terms + * (separated by '+'), where each term is either an integer + * or a parameter reference in the target language. + */ + protected fun multiportWidthExpression(variable: Variable?): String? = + multiportWidthSpec(variable)?.joinToString(separator = " + ") + + + /** + * Return true if the specified port is a multiport. + * @param port The port. + * @return True if the port is a multiport. + */ + protected fun isMultiport(port: Port): Boolean = port.widthSpec != null + + /** + * Get textual representation of a time in the target language. + * This is a separate function from + * getTargetTime to avoid producing invalid RTI + * code for targets that override timeInTargetLanguage + * to return a C-incompatible time type. + * + * @param d A time AST node + * @return An RTI-compatible (ie. C target) time string + */ + protected fun getRTITime(d: Delay): String { + if (d.parameter !== null) { + return d.toText + } + + val time = TimeValue(d.interval.toLong(), d.unit) + + return if (time.unit != TimeUnit.NONE) { + time.unit.name + '(' + time.time + ')' + } else { + time.time.toString() + } + } + + /** + * Analyze the resource (the .lf file) that is being parsed + * to determine whether code is being mapped to single or to + * multiple target machines. If it is being mapped to multiple + * machines, then set the 'federates' list, the 'federateIDs' + * map, and the 'federationRTIHost' and 'federationRTIPort' + * variables. + * + * In addition, analyze the connections between federates. + * Ensure that every cycle has a non-zero delay (microstep + * delays will not be sufficient). Construct the dependency + * graph between federates. And replace connections between + * federates with a pair of reactions, one triggered by + * the sender's output port, and the other triggered by + * an action. + * + * This class is target independent, so the target code + * generator still has quite a bit of work to do. + * It needs to provide the body of the sending and + * receiving reactions. It also needs to provide the + * runtime infrastructure that uses the dependency + * information between federates. See the C target + * for a reference implementation. + */ + private fun analyzeFederates(): FederateInstance? { + // Next, if there actually are federates, analyze the topology + // interconnecting them and replace the connections between them + // with an action and two reactions. + val mainDefn = this.mainDef?.reactorClass.toDefinition() + + if (this.mainDef === null || !mainDefn.isFederated) { + // Ensure federates is never empty. + val federateInstance = FederateInstance(null, 0, 0, this) + federates.add(federateInstance) + federateByID[0] = federateInstance + } else { + // The Lingua Franca program is federated + isFederated = true + if (mainDefn?.host != null) { + // Get the host information, if specified. + // If not specified, this defaults to 'localhost' + if (mainDefn.host.addr != null) { + federationRTIProperties["host"] = mainDefn.host.addr + } + // Get the port information, if specified. + // If not specified, this defaults to 14045 + if (mainDefn.host.port != 0) { + federationRTIProperties["port"] = mainDefn.host.port + } + // Get the user information, if specified. + if (mainDefn.host.user !== null) { + federationRTIProperties["user"] = mainDefn.host.user + } + // Get the directory information, if specified. + /* FIXME + * if (mainDef.reactorClass.host.dir !== null) { + * federationRTIProperties.put('dir', mainDef.reactorClass.host.dir) + * } + */ + } + + // Create a FederateInstance for each top-level reactor. + for (instantiation in mainDefn.allInstantiations) { + var bankWidth = ASTUtils.width(instantiation.widthSpec) + if (bankWidth < 0) { + reportError(instantiation, "Cannot determine bank width!") + // Continue with a bank width of 1. + bankWidth = 1 + } + // Create one federate instance for each reactor instance in the bank of reactors. + val federateInstances = LinkedList() + for (i in 0..bankWidth) { + // Assign an integer ID to the federate. + val federateID = federates.size + val federateInstance = FederateInstance(instantiation, federateID, i, this) + federateInstance.bankIndex = i + federates.add(federateInstance) + federateInstances.add(federateInstance) + federateByID[federateID] = federateInstance + + if (instantiation.host !== null) { + federateInstance.host = instantiation.host.addr + // The following could be 0. + federateInstance.port = instantiation.host.port + // The following could be null. + federateInstance.user = instantiation.host.user + /* FIXME: The at keyword should support a directory component. + * federateInstance.dir = instantiation.host.dir + */ + } + } + if (federatesByInstantiation === null) { + federatesByInstantiation = LinkedHashMap() + } + federatesByInstantiation!![instantiation] = federateInstances + } + + // In a federated execution, we need keepalive to be true, + // otherwise a federate could exit simply because it hasn't received + // any messages. + if (federates.size > 1) { + targetConfig.keepalive = true + } + + // Analyze the connection topology of federates. + // First, find all the connections between federates. + // For each connection between federates, replace it in the + // AST with an action (which inherits the delay) and two reactions. + // The action will be physical for physical connections and logical + // for logical connections. + val connectionsToRemove = LinkedList() + for (connection in mainDefn.connections) { + // Each connection object may represent more than one physical connection between + // federates because of banks and multiports. We need to generate communciation + // for each of these. This iteration assumes the balance of the connection has been + // checked. + var rightIndex = 0 + var rightPort = connection.rightPorts[rightIndex++] + var rightBankIndex = 0 + var rightChannelIndex = 0 + var rightPortWidth = ASTUtils.width((rightPort.variable as Port).widthSpec) + for (leftPort in connection.leftPorts) { + val leftPortWidth = ASTUtils.width((leftPort.variable as Port).widthSpec) + for (leftBankIndex in 0..ASTUtils.width(leftPort.container.widthSpec)) { + var leftChannelIndex = 0 + while (rightPort !== null) { + val minWidth = + if (leftPortWidth - leftChannelIndex < rightPortWidth - rightChannelIndex) + leftPortWidth - leftChannelIndex + else rightPortWidth - rightChannelIndex + for (j in 0..minWidth) { + + // Finally, we have a specific connection. + // Replace the connection in the AST with an action + // (which inherits the delay) and two reactions. + // The action will be physical if the connection physical and + // otherwise will be logical. + val leftFederate = federatesByInstantiation!!.get(leftPort.container)!!.get(leftBankIndex) + val rightFederate = federatesByInstantiation!!.get(rightPort.container)!!.get(rightBankIndex) + + // Set up dependency information. + // FIXME: Maybe we don't need this any more? + if ( + leftFederate !== rightFederate + && !connection.isPhysical + && targetConfig.coordination !== TargetProperty.CoordinationType.DECENTRALIZED + ) { + var dependsOn = rightFederate.dependsOn[leftFederate] + if (dependsOn === null) { + dependsOn = LinkedHashSet() + rightFederate.dependsOn[leftFederate] = dependsOn + } + if (connection.delay !== null) { + dependsOn.add(connection.delay) + } + var sendsTo = leftFederate.sendsTo[rightFederate] + if (sendsTo === null) { + sendsTo = LinkedHashSet() + leftFederate.sendsTo[rightFederate] = sendsTo + } + if (connection.delay !== null) { + sendsTo.add(connection.delay) + } + // Check for causality loops between federates. + // FIXME: This does not detect cycles involving more than one federate. + val reverseDependency = leftFederate.dependsOn[rightFederate] + if (reverseDependency !== null) { + // Check that at least one direction has a delay. + if (reverseDependency.size == 0 && dependsOn.size == 0) { + // Found a causality loop. + val message = "Causality loop found between federates " + + leftFederate.name + " and " + rightFederate.name + reportError(connection, message) + // This is a fatal error, so throw an exception. + throw AssertionError(message) + } + } + } + + ASTUtils.makeCommunication( + connection, + leftFederate, leftBankIndex, leftChannelIndex, + rightFederate, rightBankIndex, rightChannelIndex, + this, targetConfig.coordination + ) + + leftChannelIndex++ + rightChannelIndex++ + if (rightChannelIndex >= rightPortWidth) { + // Ran out of channels on the right. + // First, check whether there is another bank reactor. + when { + rightBankIndex < ASTUtils.width(rightPort.container.widthSpec) - 1 -> { + rightBankIndex++ + rightChannelIndex = 0 + } + rightIndex >= connection.rightPorts.size() -> { + // We are done. + rightPort = null + rightBankIndex = 0 + rightChannelIndex = 0 + } + else -> { + rightBankIndex = 0 + rightPort = connection.rightPorts[rightIndex++] + rightChannelIndex = 0 + rightPortWidth = ASTUtils.width((rightPort.variable as Port).widthSpec) + } + } + } + } + } + } + } + // To avoid concurrent modification exception, collect a list + // of connections to remove. + connectionsToRemove.add(connection) + } + for (connection in connectionsToRemove) { + // Remove the original connection for the parent. + mainDefn?.connections?.remove(connection) + } + } + } + + /** + * Determine which mode the compiler is running in. + * Integrated mode means that it is running within an Eclipse IDE. + * Standalone mode means that it is running on the command line. + */ + private fun setMode(): Mode? { + val resource = fileConfig?.resource + mode = when { + resource?.uri?.isPlatform == true -> Mode.INTEGRATED + resource?.uri?.isFile == true -> Mode.STANDALONE + else -> Mode.UNDEFINED.also { + System.err.println("ERROR: Source file protocol is not recognized: " + resource.uri) + } + } + return mode + } + + /** + * Print to stdout information about what source file is being generated, + * what mode the generator is in, and where the generated sources are to be put. + */ + open fun printInfo(): String? { + println("Generating code for: " + fileConfig!!.resource.uri) + println("******** mode: $mode") + println("******** source file: " + fileConfig!!.srcFile) // FIXME: redundant + println("******** generated sources: " + fileConfig!!.srcGenPath) + } + + /** + * Execute a process while forwarding output and error streams. + * + * Executing a process directly with `processBuiler.start()` could + * lead to a deadlock as the subprocess blocks when output or error + * buffers are full. This method ensures that output and error messages + * are continuously read and forwards them to the given streams. + * + * @param processBuilder The process to be executed. + * @param outStream The stream to forward the process' output to. + * @param errStream The stream to forward the process' error messages to. + * @author{Christian Menard @tu-dresden.de} + */ + private fun runSubprocess(processBuilder: ProcessBuilder, outStream: List, errStream: List): Int { + val process = processBuilder.start() + + val outThread = Thread { + val buffer = ByteArray(64) + var len = process.inputStream.read(buffer) + while (len != -1) { + for (os in outStream) { + os.write(buffer, 0, len) + } + len = process.inputStream.read(buffer) + } + } + outThread.start() + + val errThread = Thread { + val buffer = ByteArray(64) + var len = process.errorStream.read(buffer) + while (len != -1) { + for (es in errStream) { + es.write(buffer, 0, len) + } + len = process.errorStream.read(buffer) + } + } + errThread.start() + + val returnCode = process.waitFor() + outThread.join() + errThread.join() + + return returnCode + } + + /** + * Return true if the target supports generics (i.e., parametric + * polymorphism), false otherwise. + */ + abstract fun supportsGenerics(): Boolean + abstract val targetTimeType: String + abstract val targetTagType: String + abstract val targetTagIntervalType: String + abstract val targetUndefinedType: String + + abstract fun getTargetFixedSizeListType(baseType: String?, size: Int?): String + abstract fun getTargetVariableSizeListType(baseType: String?): String + + /** Return a string representing the specified type in the target language. */ + protected fun getTargetType(type: InferredType): String = when { + type.isUndefined -> this.targetUndefinedType + type.isTime -> when { + type.isFixedSizeList -> this.getTargetFixedSizeListType(this.targetTimeType, type.listSize) + type.isVariableSizeList -> this.getTargetVariableSizeListType(this.targetTimeType) + else -> this.targetTimeType + } + type.isFixedSizeList -> this.getTargetFixedSizeListType(type.baseType(), type.listSize) + type.isVariableSizeList -> this.getTargetVariableSizeListType(type.baseType()) + else -> type.toText() + } + + val StateVar.targetType: String get() = getTargetType(ASTUtils.getInferredType(this)) + val Action.targetType: String get() = getTargetType(ASTUtils.getInferredType(this)) + val Port.targetType: String get() = getTargetType(ASTUtils.getInferredType(this)) + val Type.targetType: String get() = getTargetType(InferredType.fromAST(this)) + val Parameter.targetType: String get() = getTargetType(ASTUtils.getInferredType(this)) + + /** + * Get textual representation of a time in the target language. + * + * @param t A time AST node + * @return A time string in the target language + */ + protected fun getTargetTime(t: Time): String = timeInTargetLanguage(TimeValue(t.interval.toLong(), t.unit)) + + /** + * Get textual representation of a value in the target language. + * + * If the value evaluates to 0, it is interpreted as a normal value. + * + * @param v A time AST node + * @return A time string in the target language + */ + protected fun getTargetValue(v: Value): String = + if ((v.time != null)) { + this.getTargetTime(v.time) + } else ASTUtils.toText(v) + + /** + * Get textual representation of a value in the target language. + * + * If the value evaluates to 0, it is interpreted as a time. + * + * @param v A time AST node + * @return A time string in the target language + */ + protected fun getTargetTime(v: Value): String = when { + v.time != null -> this.getTargetTime(v.time) + ASTUtils.isZero(v) -> timeInTargetLanguage(TimeValue(0, TimeUnit.NONE)) + else -> ASTUtils.toText(v) + } + + protected fun getTargetTime(d: Delay): String = + if (d.parameter != null) { + ASTUtils.toText(d) + } else { + timeInTargetLanguage(TimeValue(d.interval.toLong(), d.unit)) + } + + /** + * Write the source code to file. + * @param code The code to be written. + * @param path The file to write the code to. + */ + protected fun writeSourceCodeToFile(code: ByteArray, path: String) { + Files.write(Paths.get(path), code) + } + + companion object { + /** + * Constant that specifies how to name generated delay reactors. + */ + val GEN_DELAY_CLASS_NAME = "__GenDelay" + } +} From 5920166ebb4a85cfc475ee0c8b267aebca4e5b27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Thu, 22 Apr 2021 18:58:03 +0200 Subject: [PATCH 23/88] Finish porting KtGeneratorBase --- org.lflang/src/org/lflang/Extensions.kt | 48 ++- .../src/org/lflang/generator/CppGenerator2.kt | 93 ++--- .../org/lflang/generator/KtGeneratorBase.kt | 326 +++++++----------- ...copeProvider.kt => LFScopeProviderImpl.kt} | 9 +- .../org/lflang/validation/LFValidator.java | 6 + ...FValidator.xtend => LFValidatorImpl.xtend} | 134 +++---- 6 files changed, 260 insertions(+), 356 deletions(-) rename org.lflang/src/org/lflang/scoping/{LFScopeProvider.kt => LFScopeProviderImpl.kt} (97%) create mode 100644 org.lflang/src/org/lflang/validation/LFValidator.java rename org.lflang/src/org/lflang/validation/{LFValidator.xtend => LFValidatorImpl.xtend} (97%) diff --git a/org.lflang/src/org/lflang/Extensions.kt b/org.lflang/src/org/lflang/Extensions.kt index fae1b4d68a..93a15fd501 100644 --- a/org.lflang/src/org/lflang/Extensions.kt +++ b/org.lflang/src/org/lflang/Extensions.kt @@ -24,13 +24,11 @@ package org.lflang +import org.eclipse.xtext.nodemodel.util.NodeModelUtils import org.lflang.lf.* -import java.lang.Exception -import kotlin.reflect.KClass -fun ReactorDecl?.toDefinition(): Reactor? = when (this) { - null -> null +fun ReactorDecl.toDefinition(): Reactor = when (this) { is Reactor -> this is ImportedReactor -> this.reactorClass else -> throw AssertionError("unreachable") @@ -93,5 +91,47 @@ val Reactor.allTimers: List get() = superClassRecursor { timers } private fun Reactor.superClassRecursor(collector: Reactor.() -> List): List = superClasses.orEmpty().mapNotNull { it.toDefinition()?.collector() }.flatten() + this.collector() +val Parameter.isOfTimeType: Boolean + get() { + // Either the type has to be declared as a time. + if (type?.isTime == true) { + return true + } + // Or it has to be initialized as a proper time with units. + init?.singleOrNull() + ?.time + ?.takeIf { it.unit != TimeUnit.NONE } + ?.let { + return true + } + // In other words, one can write: + // - `x:time(0)` -OR- + // - `x:(0 msec)`, `x:(0 sec)`, etc. + return false + } fun List.tail() = subList(1, size) +fun List.headAndTail() = Pair(first(), tail()) + + +fun Code?.toText(): String { + this ?: return "" + val node = NodeModelUtils.getNode(this) + return if (node != null) { + val str = node.leafNodes + .joinToString { it.text }.trim() + .removeSurrounding("{=", "=}") + + if ('\n' in str) str.trimIndent() else str.trim() + } else if (body != null) { + // Code must have been added as a simple string. + body.toString() + } else { + "" + } +} + +fun TypeParm.toText(): String = + if (!literal.isNullOrEmpty()) literal + else code.toText() + diff --git a/org.lflang/src/org/lflang/generator/CppGenerator2.kt b/org.lflang/src/org/lflang/generator/CppGenerator2.kt index b5bf056870..49a88607eb 100644 --- a/org.lflang/src/org/lflang/generator/CppGenerator2.kt +++ b/org.lflang/src/org/lflang/generator/CppGenerator2.kt @@ -24,55 +24,18 @@ package org.lflang.generator -import org.lflang.ASTUtils -import org.lflang.InferredType import org.lflang.Target -import org.lflang.lf.* +import org.lflang.lf.Action +import org.lflang.lf.Reactor +import org.lflang.lf.VarRef /** * */ -class CppGenerator2 : GeneratorBase() { - - - /** - * Return a string representing the specified type in the target language. - * @param type The type. - */ - private fun getTargetType(type: InferredType, undefinedType ): String { - val _isUndefined = type.isUndefined - if (_isUndefined) { - return this.getTargetUndefinedType() - } else { - if (type.isTime.toBoolean()) { - return if (type.isFixedSizeList.toBoolean()) { - this.getTargetFixedSizeListType(this.getTargetTimeType(), type.listSize) - } else { - if (type.isVariableSizeList.toBoolean()) { - this.getTargetVariableSizeListType(this.getTargetTimeType()) - } else { - this.getTargetTimeType() - } - } - } else { - if (type.isFixedSizeList.toBoolean()) { - return this.getTargetFixedSizeListType(type.baseType(), type.listSize) - } else { - if (type.isVariableSizeList.toBoolean()) { - return this.getTargetVariableSizeListType(type.baseType()) - } - } - } - } - return type.toText() - } - - fun StateVar.getTargetType(): String = getTargetType(ASTUtils.getInferredType(this)) - fun Action.getTargetType(): String = getTargetType(ASTUtils.getInferredType(this)) - fun Port.getTargetType(): String = getTargetType(ASTUtils.getInferredType(this)) - fun Type.getTargetType(): String = getTargetType(ASTUtils.getInferredType(this)) - fun Parameter.getTargetType(): String = getTargetType(ASTUtils.getInferredType(this)) - +class CppGenerator2 : KtGeneratorBase( + Target.CPP, + supportsGenerics = true +) { /* @@ -89,48 +52,32 @@ class CppGenerator2 : GeneratorBase() { "std::add_const<${it.targetType}>::type ${it.name};" } - - 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") - } - - override fun supportsGenerics(): Boolean { - TODO("Not yet implemented") - } - - override fun getTargetTimeType(): String { - TODO("Not yet implemented") - } - - override fun getTargetTagType(): String { + override fun generateDelayBody(action: Action, port: VarRef): String? { TODO("Not yet implemented") } - override fun getTargetTagIntervalType(): String { + override fun generateForwardBody(action: Action, port: VarRef): String? { TODO("Not yet implemented") } - override fun getTargetUndefinedType(): String { + override fun generateDelayGeneric(): String? { TODO("Not yet implemented") } - override fun getTargetFixedSizeListType(baseType: String?, size: Int?): String { - TODO("Not yet implemented") - } + override val targetTimeType: String + get() = TODO("Not yet implemented") + override val targetTagType: String + get() = TODO("Not yet implemented") + override val targetTagIntervalType: String + get() = TODO("Not yet implemented") + override val targetUndefinedType: String + get() = TODO("Not yet implemented") - override fun getTargetVariableSizeListType(baseType: String?): String { + override fun getTargetFixedSizeListType(baseType: String, size: Int): String { TODO("Not yet implemented") } - override fun getTarget(): Target { + override fun getTargetVariableSizeListType(baseType: String): String { TODO("Not yet implemented") } diff --git a/org.lflang/src/org/lflang/generator/KtGeneratorBase.kt b/org.lflang/src/org/lflang/generator/KtGeneratorBase.kt index 6f5081cdfd..7e495c5c7f 100644 --- a/org.lflang/src/org/lflang/generator/KtGeneratorBase.kt +++ b/org.lflang/src/org/lflang/generator/KtGeneratorBase.kt @@ -3,13 +3,11 @@ */ package org.lflang.generator -import com.google.common.collect.Iterables import org.eclipse.core.resources.IMarker import org.eclipse.core.resources.IResource import org.eclipse.core.resources.ResourcesPlugin import org.eclipse.emf.ecore.EObject import org.eclipse.emf.ecore.resource.Resource -import org.eclipse.xtend2.lib.StringConcatenation import org.eclipse.xtext.generator.IFileSystemAccess2 import org.eclipse.xtext.generator.IGeneratorContext import org.eclipse.xtext.nodemodel.util.NodeModelUtils @@ -32,18 +30,25 @@ import java.util.regex.Pattern import kotlin.collections.LinkedHashMap import kotlin.collections.LinkedHashSet import kotlin.math.max +import kotlin.math.min /** * Generator base class for shared code between code generators. * This extends AbstractLinguaFrancaValidator so that errors can be highlighted * in the XText-based IDE. * + * @property target The target which this generator handles + * @property supportsGenerics True if the target supports generics (i.e., parametric polymorphism), false otherwise. + * * @author {Edward A. Lee @berkeley.edu>} * @author {Marten Lohstroh @berkeley.edu>} * @author {Christian Menard @tu-dresden.de} * @author {Matt Weber @berkeley.edu>} */ -abstract class KtGeneratorBase(val target: Target) : AbstractLFValidator() { +abstract class KtGeneratorBase( + val target: Target, + val supportsGenerics: Boolean +) : AbstractLFValidator() { /** * Defines the execution environment that is used to execute binaries. @@ -644,7 +649,7 @@ abstract class KtGeneratorBase(val target: Target) : AbstractLFValidator() { // Find the minimum delay in the process. // FIXME: Zero delay is not really the same as a microstep delay. var count = 0 - for (upstreamFederate: federate.dependsOn.keySet) { + for (upstreamFederate in federate.dependsOn.keys) { pr( rtiCode, """ federates[${federate.id}].upstream[${count}] = ${upstreamFederate.id}; @@ -1156,29 +1161,22 @@ You can set PATH in ~/.bash_profile on Linux or Mac.""" */ protected open fun generatePreamble() { prComment("Code generated by the Lingua Franca compiler from:") - val _unixString = FileConfig.toUnixString(fileConfig!!.srcFile.toPath()) - val _plus = ("file:/$_unixString") - prComment(_plus) - val models = LinkedHashSet() - var _elvis: List? = null - if (reactors != null) { - _elvis = reactors - } else { - val _emptyList = CollectionLiterals.emptyList() - _elvis = _emptyList - } - for (r: Reactor? in _elvis!!) { - val _eContainer = ASTUtils.toDefinition(r).eContainer() - models.add((_eContainer as Model)) - } - if ((mainDef != null)) { - val _eContainer_1 = ASTUtils.toDefinition(mainDef!!.reactorClass).eContainer() - models.add((_eContainer_1 as Model)) + prComment("file:/" + FileConfig.toUnixString(fileConfig!!.srcFile.toPath())) + val models = this.reactors.map { + // This assumes all reactors have a container. + // This means that generated reactors **have** to be + // added to a resource; not doing so will result in a NPE. + it.toDefinition().eContainer() as Model + }.toMutableSet() + + // Add the main reactor if it is defined + val mainDef = this.mainDef + if (mainDef != null) { + models.add(mainDef.reactorClass.toDefinition().eContainer() as Model) } - for (m: Model in models) { - val _preambles = m.preambles - for (p: Preamble in _preambles) { - this.pr(ASTUtils.toText(p.code)) + for (m in models) { + for (p in m.preambles) { + pr(p.code.toText()) } } } @@ -1187,9 +1185,8 @@ You can set PATH in ~/.bash_profile on Linux or Mac.""" * Get the code produced so far. * @return The code produced so far as a String. */ - protected fun getCode(): String { - return this.code.toString() - } + protected fun getCode(): String = code.toString() + /** * Increase the indentation of the output code produced * on the specified builder. @@ -1198,19 +1195,10 @@ You can set PATH in ~/.bash_profile on Linux or Mac.""" /** * Increase the indentation of the output code produced. */ - protected fun indent(builder: StringBuilder = this.code): String? { - var _xblockexpression: String? = null - run { - var prefix: String? = this.indentation[builder] - if ((prefix == null)) { - prefix = "" - } - val _prefix: String = prefix - prefix = (_prefix + " ") - _xblockexpression = this.indentation.put(builder, prefix) + protected fun indent(builder: StringBuilder = this.code): String = + (indentation.getOrDefault(builder, "") + " ").also { + indentation[builder] = it } - return _xblockexpression - } /** * Append the specified text plus a final newline to the current @@ -1219,14 +1207,11 @@ You can set PATH in ~/.bash_profile on Linux or Mac.""" * the text to append if no further arguments are given. * @param args Additional arguments to pass to the formatter. */ - protected fun pr(format: String?, vararg args: Any?): StringBuilder? { - var _xifexpression: String? = null - if (((args != null) && (args.size > 0))) { - _xifexpression = String.format((format)!!, *args) - } else { - _xifexpression = format - } - return this.pr(this.code, _xifexpression) + protected fun pr(format: String, vararg args: Any?): StringBuilder? { + val text = + if (args.isNotEmpty()) String.format(format, args) + else format + return pr(code, text) } /** @@ -1235,56 +1220,33 @@ You can set PATH in ~/.bash_profile on Linux or Mac.""" * @param builder The code buffer. * @param text The text to append. */ - protected fun pr(builder: StringBuilder, text: Any?): StringBuilder? { - var _xblockexpression: StringBuilder? = null - run { - var string: String = text.toString() - var indent: String? = this.indentation[builder] - if ((indent == null)) { - indent = "" + protected fun pr(builder: StringBuilder, text: Any?): StringBuilder { + // Handle multi-line text. + var string = text.toString() + val indent = indentation[builder] ?: "" + if ('\n' in string) { + // Replace all tabs with four spaces. + string = string.replace("\t", " ") + // Use two passes, first to find the minimum leading white space + // in each line of the source text. + var offset = Integer.MAX_VALUE + // Skip the first line, which has white space stripped. + val (firstLine, rest) = string.lines().headAndTail() + for (line in rest) { + val numLeadingSpaces = line.indexOf(line.trim()) + offset = min(offset, numLeadingSpaces) } - var _xifexpression: StringBuilder? = null - val _contains: Boolean = string.contains("\n") - if (_contains) { - string = string.replace("\t".toRegex(), " ") - val split: Array = string.split("\n").toTypedArray() - var offset: Int = Int.MAX_VALUE - var firstLine: Boolean = true - for (line: String in split) { - if (firstLine) { - firstLine = false - } else { - val numLeadingSpaces: Int = line.indexOf(line.trim { it <= ' ' }) - if ((numLeadingSpaces < offset)) { - offset = numLeadingSpaces - } - } - } - firstLine = true - for (line_1: String? in split) { - { - builder.append(indent) - if (firstLine) { - builder.append(line_1) - firstLine = false - } else { - builder.append(line_1.substring(offset)) - } - builder.append("\n") - } - } - } else { - var _xblockexpression_1: StringBuilder? = null - { - builder.append(indent) - builder.append(text) - _xblockexpression_1 = builder.append("\n") - } - _xifexpression = _xblockexpression_1 + + // Now make a pass for each line, replacing the offset leading + // spaces with the current indentation. + builder.append(indent).append(firstLine) + for (line in rest) { + builder.append(indent).append(line.substring(offset)).appendLine() } - _xblockexpression = _xifexpression + } else { + builder.append(indent).append(text).appendLine() } - return _xblockexpression + return builder } /** @@ -1295,32 +1257,21 @@ You can set PATH in ~/.bash_profile on Linux or Mac.""" * @param end The epilogue of the block. * @param actions Actions that print the interior of the block. */ - protected fun prBlock(begin: String?, end: String?, vararg actions: Runnable): StringBuilder? { - var _xblockexpression: StringBuilder? = null - run { - val i: Int = this.code.length - this.indent() - for (action: Runnable in actions) { - action.run() - } - this.unindent() - var _xifexpression: StringBuilder? = null - val _length: Int = this.code.length - val _lessThan: Boolean = (i < _length) - if (_lessThan) { - var _xblockexpression_1: StringBuilder? = null - { - val inserted: String = this.code.substring(i, this.code.length) - this.code.delete(i, this.code.length) - this.pr(begin) - this.code.append(inserted) - _xblockexpression_1 = this.pr(end) - } - _xifexpression = _xblockexpression_1 - } - _xblockexpression = _xifexpression - } - return _xblockexpression + protected fun prBlock(begin: String = "", end: String = "", vararg actions: () -> Unit): StringBuilder { + val i = code.length + indent() + for (action in actions) { + action() + } + unindent() + if (i < code.length) { + val inserted = code.substring(i, code.length) + code.delete(i, code.length) + pr(begin) + code.append(inserted) + pr(end) + } + return code } /** @@ -1328,23 +1279,10 @@ You can set PATH in ~/.bash_profile on Linux or Mac.""" * number in the LF source. * @param eObject The node. */ - protected open fun prSourceLineNumber(eObject: EObject?): StringBuilder? { - var _xifexpression: StringBuilder? = null - if ((eObject is Code)) { - val _builder = StringConcatenation() - _builder.append("// ") - val _startLine = NodeModelUtils.getNode(eObject).startLine - val _plus = (_startLine + 1) - _builder.append(_plus) - _xifexpression = this.pr(this.code, _builder) - } else { - val _builder_1 = StringConcatenation() - _builder_1.append("// ") - val _startLine_1 = NodeModelUtils.getNode(eObject).startLine - _builder_1.append(_startLine_1) - _xifexpression = this.pr(this.code, _builder_1) - } - return _xifexpression + protected open fun prSourceLineNumber(eObject: EObject): StringBuilder { + val startLine = NodeModelUtils.getNode(eObject).startLine + val numToPrint = if (eObject is Code) startLine + 1 else startLine + return pr(code, "// $numToPrint") } /** @@ -1353,9 +1291,8 @@ You can set PATH in ~/.bash_profile on Linux or Mac.""" * start with something other than '//'. * @param comment The comment. */ - protected fun prComment(comment: String): StringBuilder? { - return this.pr(this.code, ("// $comment")) - } + protected fun prComment(comment: String): StringBuilder = + pr(this.code, ("// $comment")) /** * Given a line of text from the output of a compiler, return @@ -1476,15 +1413,12 @@ You can set PATH in ~/.bash_profile on Linux or Mac.""" */ protected fun copyFileFromClassPath(source: String, destination: String): Long { val sourceStream = this::class.java.getResourceAsStream(source) - - if (sourceStream == null) { - throw IOException( + ?: throw IOException( "A required target resource could not be found: " + source + "\n" + "Perhaps a git submodule is missing or not up to date.\n" + "See https://github.com/icyphy/lingua-franca/wiki/downloading-and-building#clone-the-lingua-franca-repository.\n" + "Also try to refresh and clean the project explorer if working from eclipse." ) - } // Copy the file. try { @@ -1645,14 +1579,8 @@ You can set PATH in ~/.bash_profile on Linux or Mac.""" * @param `object` The parse tree object or null if not known. */ protected fun report(message: String, severity: Int, obj: EObject?): String { - var line: Int? = null - if (obj != null) { - val node = NodeModelUtils.getNode(obj) - if ((node != null)) { - line = Integer.valueOf(node.startLine) - } - } - return this.report(message, severity, line, obj, null) + val line = NodeModelUtils.getNode(obj)?.startLine + return report(message, severity, line, obj, null) } /** @@ -1708,35 +1636,31 @@ You can set PATH in ~/.bash_profile on Linux or Mac.""" /** * Create a list of default parameter initializers in target code. - * - * @param param The parameter to create initializers for * @return A list of initializers in target code */ - protected fun getInitializerList(param: Parameter?): LinkedList { - val list = LinkedList() - for (i in param?.init.orEmpty()) { - if (ASTUtils.isOfTimeType(param)) { - list.add(this.getTargetTime(i)) - } else { - list.add(getTargetValue(i)) + protected val Parameter?.initializerList: List + get() { + val ofTimeType = this?.isOfTimeType ?: false + + return this?.init.orEmpty().map { + if (ofTimeType) getTargetTime(it) + else getTargetValue(it) } } - return list - } /** * Create a list of state initializers in target code. * - * @param this@getInitializerList The state variable to create initializers for + * @receiver The state variable to create initializers for * @return A list of initializers in target code */ - protected val StateVar?.initializerList: List? + protected val StateVar.initializerList: List? get() = if (ASTUtils.isInitialized(this)) { - this?.init.orEmpty().map { + this.init.orEmpty().map { when { - it.parameter != null -> (getTargetReference(it.parameter)) - ASTUtils.isOfTimeType(this) -> (this@GeneratorBase.getTargetTime(it)) - else -> (getTargetValue(it)) + it.parameter != null -> getTargetReference(it.parameter) + ASTUtils.isOfTimeType(this) -> getTargetTime(it) + else -> getTargetValue(it) } } } else { @@ -1755,21 +1679,22 @@ You can set PATH in ~/.bash_profile on Linux or Mac.""" * @return A list of initializers in target code */ protected fun getInitializerList(param: Parameter?, i: Instantiation?): List? { - if (i === null || param === null) { + if (i == null || param == null) { return null } - val assignments = i.parameters.filter { it.lhs === param } + val ofTimeType = param.isOfTimeType + + val assignments = i.parameters.filter { p.lhs === param } return if (assignments.isEmpty()) { // the parameter was not overwritten in the instantiation - param.initializerList() + param.initializerList } else { // the parameter was overwritten in the instantiation - val ofTimeType = param.isOfTimeType - assignments.firstOrNull()?.rhs.orEmpty().map { - if (ofTimeType) init.targetTime - else init.targetValue + assignments[0]?.rhs.orEmpty().map { + if (ofTimeType) getTargetTime(it) + else getTargetValue(it) } } } @@ -1785,49 +1710,45 @@ You can set PATH in ~/.bash_profile on Linux or Mac.""" } /** - * If the argument is a multiport, return a list of strings + * If the receiver is a multiport, return a list of strings * describing the width of the port, and otherwise, return null. * If the list is empty, then the width is variable (specified * as '[]'). Otherwise, it is a list of integers and/or parameter * references obtained by getTargetReference(). - * @param variable The port. + * @receiver The port. * @return The width specification for a multiport or null if it is * not a multiport. */ - protected fun multiportWidthSpec(variable: Variable?): List? { - if (variable !is Port || variable.widthSpec == null) return null - val result = LinkedList() - if (!variable.widthSpec.isOfVariableLength) { - for (term in variable.widthSpec.terms) { - if (term.parameter !== null) { - result.add(getTargetReference(term.parameter)) - } else { - result.add(term.width.toString()) - } - } - } - return result + protected fun Variable?.multiportWidthSpec(): List? { + val widthSpec = (this as? Port)?.widthSpec ?: return null + if (widthSpec.isOfVariableLength) return emptyList() + return widthSpec.terms.map { term -> + val param = term.parameter + if (param !== null) getTargetReference(param) + else term.width.toString() + } } /** - * If the argument is a multiport, then return a string that + * If the receiver is a multiport, then return a string that * gives the width as an expression, and otherwise, return null. * The string will be empty if the width is variable (specified * as '[]'). Otherwise, if is a single term or a sum of terms * (separated by '+'), where each term is either an integer * or a parameter reference in the target language. */ - protected fun multiportWidthExpression(variable: Variable?): String? = - multiportWidthSpec(variable)?.joinToString(separator = " + ") + protected fun Variable?.multiportWidthExpression(): String? = + this.multiportWidthSpec()?.joinToString(separator = " + ") /** * Return true if the specified port is a multiport. - * @param port The port. + * @receiver The port. * @return True if the port is a multiport. */ - protected fun isMultiport(port: Port): Boolean = port.widthSpec != null + protected val Port.isMultiport: Boolean + get() = widthSpec != null /** * Get textual representation of a time in the target language. @@ -2153,18 +2074,13 @@ You can set PATH in ~/.bash_profile on Linux or Mac.""" return returnCode } - /** - * Return true if the target supports generics (i.e., parametric - * polymorphism), false otherwise. - */ - abstract fun supportsGenerics(): Boolean abstract val targetTimeType: String abstract val targetTagType: String abstract val targetTagIntervalType: String abstract val targetUndefinedType: String - abstract fun getTargetFixedSizeListType(baseType: String?, size: Int?): String - abstract fun getTargetVariableSizeListType(baseType: String?): String + abstract fun getTargetFixedSizeListType(baseType: String, size: Int): String + abstract fun getTargetVariableSizeListType(baseType: String): String /** Return a string representing the specified type in the target language. */ protected fun getTargetType(type: InferredType): String = when { diff --git a/org.lflang/src/org/lflang/scoping/LFScopeProvider.kt b/org.lflang/src/org/lflang/scoping/LFScopeProviderImpl.kt similarity index 97% rename from org.lflang/src/org/lflang/scoping/LFScopeProvider.kt rename to org.lflang/src/org/lflang/scoping/LFScopeProviderImpl.kt index 034e2a831a..50c88507fc 100644 --- a/org.lflang/src/org/lflang/scoping/LFScopeProvider.kt +++ b/org.lflang/src/org/lflang/scoping/LFScopeProviderImpl.kt @@ -47,7 +47,8 @@ import java.util.Collections.emptyList * * @author Marten Lohstroh */ -class LFScopeProvider : DelegatingScopeProvider() { +class LFScopeProviderImpl(val nameProvider: SimpleNameProvider, + val scopeProvider: LFGlobalScopeProvider) : DelegatingScopeProvider() { /** * Enumerate of the kinds of references. */ @@ -55,12 +56,6 @@ class LFScopeProvider : DelegatingScopeProvider() { NULL, TRIGGER, SOURCE, EFFECT, DEADLINE, CLEFT, CRIGHT } - @Inject - private val nameProvider: SimpleNameProvider? = null - - @Inject - private val scopeProvider: LFGlobalScopeProvider? = null - /** * Depending on the provided context, construct the appropriate scope * for the given reference. diff --git a/org.lflang/src/org/lflang/validation/LFValidator.java b/org.lflang/src/org/lflang/validation/LFValidator.java new file mode 100644 index 0000000000..e3e3936a92 --- /dev/null +++ b/org.lflang/src/org/lflang/validation/LFValidator.java @@ -0,0 +1,6 @@ +package org.lflang.validation; + +public class LFValidator extends AbstractLFValidator { + + // todo port xtend into new kotlin file +} diff --git a/org.lflang/src/org/lflang/validation/LFValidator.xtend b/org.lflang/src/org/lflang/validation/LFValidatorImpl.xtend similarity index 97% rename from org.lflang/src/org/lflang/validation/LFValidator.xtend rename to org.lflang/src/org/lflang/validation/LFValidatorImpl.xtend index 4754e18294..533af8fe9a 100644 --- a/org.lflang/src/org/lflang/validation/LFValidator.xtend +++ b/org.lflang/src/org/lflang/validation/LFValidatorImpl.xtend @@ -13,15 +13,15 @@ * 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 + * 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 + * 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.validation @@ -82,16 +82,16 @@ import org.lflang.lf.LfPackage.Literals /** * Custom validation checks for Lingua Franca programs. - * + * * Also see: https://www.eclipse.org/Xtext/documentation/303_runtime_concepts.html#validation - * + * * @author{Edward A. Lee } * @author{Marten Lohstroh } * @author{Matt Weber } * @author(Christian Menard } - * + * */ -class LFValidator extends AbstractLFValidator { +class LFValidatorImpl extends LFValidator { var Target target public var info = new ModelInfo() @@ -105,22 +105,22 @@ class LFValidator extends AbstractLFValidator { /** * Regular expression to check the validity of IPV6 addresses (due to David M. Syzdek), * with minor adjustment to allow up to six IPV6 segments (without truncation) in front - * of an embedded IPv4-address. + * of an embedded IPv4-address. **/ - static val ipv6Regex = + static val ipv6Regex = "(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|" + - "([0-9a-fA-F]{1,4}:){1,7}:|" + + "([0-9a-fA-F]{1,4}:){1,7}:|" + "([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|" + - "([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|" + - "([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|" + - "([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|" + - "([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|" + - "[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|" + + "([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|" + + "([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|" + + "([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|" + + "([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|" + + "[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|" + ":((:[0-9a-fA-F]{1,4}){1,7}|:)|" + - "fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|" + - "::(ffff(:0{1,4}){0,1}:){0,1}" + ipv4Regex + "|" + + "fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|" + + "::(ffff(:0{1,4}){0,1}:){0,1}" + ipv4Regex + "|" + "([0-9a-fA-F]{1,4}:){1,4}:" + ipv4Regex + "|" + - "([0-9a-fA-F]{1,4}:){1,6}" + ipv4Regex + ")" + "([0-9a-fA-F]{1,4}:){1,6}" + ipv4Regex + ")" static val usernameRegex = "^[a-z_]([a-z0-9_-]{0,31}|[a-z0-9_-]{0,30}\\$)$" @@ -131,7 +131,7 @@ class LFValidator extends AbstractLFValidator { static val spacingViolationPolicies = #['defer', 'drop', 'replace'] public val List targetPropertyErrors = newLinkedList - + public val List targetPropertyWarnings = newLinkedList @Check @@ -158,9 +158,9 @@ class LFValidator extends AbstractLFValidator { error("Error loading resource.", Literals.IMPORT__IMPORT_URI) // FIXME: print specifics. return } - + // FIXME: report error if resource cannot be resolved. - + for (reactor : imp.reactorClasses) { if (!reactor.unused) { return @@ -195,7 +195,7 @@ class LFValidator extends AbstractLFValidator { /** * Report whether a given reactor has dependencies on a cyclic * instantiation pattern. This means the reactor has an instantiation - * in it -- directly or in one of its contained reactors -- that is + * in it -- directly or in one of its contained reactors -- that is * self-referential. * @param reactor The reactor definition to find out whether it has any * dependencies on cyclic instantiations. @@ -219,7 +219,7 @@ class LFValidator extends AbstractLFValidator { } return false } - + /** * Report whether a given imported reactor is used in this resource or not. * @param reactor The imported reactor to check whether it is used. @@ -238,12 +238,12 @@ class LFValidator extends AbstractLFValidator { } return false } - + // ////////////////////////////////////////////////// // // Functions to set up data structures for performing checks. // FAST ensures that these checks run whenever a file is modified. - // Alternatives are NORMAL (when saving) and EXPENSIVE (only when right-click, validate). + // Alternatives are NORMAL (when saving) and EXPENSIVE (only when right-click, validate). // ////////////////////////////////////////////////// // // The following checks are in alphabetical order. @@ -308,7 +308,7 @@ class LFValidator extends AbstractLFValidator { // FIXME": similar checks for decl/init // Specifically for C: list can only be literal or time lists } - + @Check(FAST) def checkWidthSpec(WidthSpec widthSpec) { if (this.target != Target.C && this.target != Target.CPP && this.target != Target.Python) { @@ -322,7 +322,7 @@ class LFValidator extends AbstractLFValidator { } } else { if (this.target != Target.C && this.target != Target.Python) { - error("Parameterized widths are currently only supported by the C target.", + error("Parameterized widths are currently only supported by the C target.", Literals.WIDTH_SPEC__TERMS) } } @@ -339,7 +339,7 @@ class LFValidator extends AbstractLFValidator { for (rp : connection.rightPorts) { var leftInCycle = false val reactorName = (connection.eContainer as Reactor).name - + if ((lp.container === null && cycle.exists [ it.node === lp.variable ]) || cycle.exists [ @@ -355,7 +355,7 @@ class LFValidator extends AbstractLFValidator { ]) { if (leftInCycle) { // Only report of _both_ referenced ports are in the cycle. - error('''Connection in reactor «reactorName» creates ''' + + error('''Connection in reactor «reactorName» creates ''' + '''a cyclic dependency between «lp.toText» and ''' + '''«rp.toText».''', Literals.CONNECTION__DELAY ) @@ -364,7 +364,7 @@ class LFValidator extends AbstractLFValidator { } } } - + // For the C target, since C has such a weak type system, check that // the types on both sides of every connection match. For other languages, // we leave type compatibility that language's compiler or interpreter. @@ -399,7 +399,7 @@ class LFValidator extends AbstractLFValidator { } } } - + // Check whether the total width of the left side of the connection // matches the total width of the right side. This cannot be determined // here if the width is not given as a constant. In that case, it is up @@ -424,7 +424,7 @@ class LFValidator extends AbstractLFValidator { rightWidth += width } } - + if (leftWidth !== -1 && rightWidth !== -1 && leftWidth != rightWidth) { if (connection.isIterated) { if (rightWidth % leftWidth != 0) { @@ -444,9 +444,9 @@ class LFValidator extends AbstractLFValidator { ) } } - + val reactor = connection.eContainer as Reactor - + // Make sure the right port is not already an effect of a reaction. for (reaction : reactor.reactions) { for (effect : reaction.effects) { @@ -480,7 +480,7 @@ class LFValidator extends AbstractLFValidator { } } } - + /** * Return true if the two types match. Unfortunately, xtext does not * seem to create a suitable equals() method for Type, so we have to @@ -521,7 +521,7 @@ class LFValidator extends AbstractLFValidator { Literals.DEADLINE__DELAY) } } - + @Check(NORMAL) def checkBuild(Model model) { val uri = model.eResource?.URI @@ -553,7 +553,7 @@ class LFValidator extends AbstractLFValidator { error("Input must have a type.", Literals.TYPED_VARIABLE__TYPE) } } - + // mutable has no meaning in C++ if (input.mutable && this.target == Target.CPP) { warning( @@ -562,7 +562,7 @@ class LFValidator extends AbstractLFValidator { Literals.INPUT__MUTABLE ) } - + // Variable width multiports are not supported (yet?). if (input.widthSpec !== null && input.widthSpec.ofVariableLength) { error("Variable-width multiports are not supported.", Literals.PORT__WIDTH_SPEC) @@ -580,7 +580,7 @@ class LFValidator extends AbstractLFValidator { Literals.INSTANTIATION__REACTOR_CLASS ) } - + // Report error if this instantiation is part of a cycle. // FIXME: improve error message. // FIXME: Also report if there exists a cycle within. @@ -600,7 +600,7 @@ class LFValidator extends AbstractLFValidator { } } // Variable width multiports are not supported (yet?). - if (instantiation.widthSpec !== null + if (instantiation.widthSpec !== null && instantiation.widthSpec.ofVariableLength ) { if (this.target == Target.C) { @@ -662,7 +662,7 @@ class LFValidator extends AbstractLFValidator { error("Output must have a type.", Literals.TYPED_VARIABLE__TYPE) } } - + // Variable width multiports are not supported (yet?). if (output.widthSpec !== null && output.widthSpec.ofVariableLength) { error("Variable-width multiports are not supported.", Literals.PORT__WIDTH_SPEC) @@ -675,7 +675,7 @@ class LFValidator extends AbstractLFValidator { info.update(model) } } - + @Check(NORMAL) def updateModelInfo(Model model) { info.update(model) @@ -690,14 +690,14 @@ class LFValidator extends AbstractLFValidator { error("Parameter cannot be initialized using parameter.", Literals.PARAMETER__INIT) } - + if (param.init === null || param.init.size == 0) { // All parameters must be initialized. error("Uninitialized parameter.", Literals.PARAMETER__INIT) } else if (param.isOfTimeType) { // We do additional checks on types because we can make stronger // assumptions about them. - + // If the parameter is not a list, cannot be initialized // using a one. if (param.init.size > 1 && param.type.arraySpec === null) { @@ -718,7 +718,7 @@ class LFValidator extends AbstractLFValidator { Literals.PARAMETER__INIT) } } - } // If time is not null, we know that a unit is also specified. + } // If time is not null, we know that a unit is also specified. } } else if (this.target.requiresTypes) { // Report missing target type. @@ -874,7 +874,7 @@ class LFValidator extends AbstractLFValidator { '''Cyclic dependency due to preceding reaction. Consider reordering reactions within reactor «reactor.name» to avoid causality loop.''', reaction.eContainer, Literals.REACTOR__REACTIONS, - reactor.reactions.indexOf(reaction)) + reactor.reactions.indexOf(reaction)) } else if (effects.size == 0) { error( '''Cyclic dependency due to succeeding reaction. Consider reordering reactions within reactor «reactor.name» to avoid causality loop.''', @@ -886,7 +886,7 @@ class LFValidator extends AbstractLFValidator { // Moving them won't help solve the problem. } } - // FIXME: improve error message. + // FIXME: improve error message. } @Check(FAST) @@ -902,7 +902,7 @@ class LFValidator extends AbstractLFValidator { // Prevent NPE in tests below. return } else { - if (reactor.isFederated || reactor.isMain) { + if (reactor.isFederated || reactor.isMain) { if(!reactor.name.equals(name)) { // Make sure that if the name is omitted, the reactor is indeed main. error( @@ -932,12 +932,12 @@ class LFValidator extends AbstractLFValidator { ) } } - + // If there is a main reactor (with no name) then disallow other (non-main) reactors // matching the file name. - + checkName(reactor.name, Literals.REACTOR_DECL__NAME) - + // C++ reactors may not be called 'preamble' if (this.target == Target.CPP && reactor.name.equalsIgnoreCase("preamble")) { error( @@ -945,11 +945,11 @@ class LFValidator extends AbstractLFValidator { Literals.REACTOR_DECL__NAME ) } - + if (reactor.host !== null) { if (!reactor.isFederated) { error( - "Cannot assign a host to reactor '" + reactor.name + + "Cannot assign a host to reactor '" + reactor.name + "' because it is not federated.", Literals.REACTOR__HOST ) @@ -961,11 +961,11 @@ class LFValidator extends AbstractLFValidator { variables.addAll(reactor.outputs) variables.addAll(reactor.actions) variables.addAll(reactor.timers) - + // Perform checks on super classes. for (superClass : reactor.superClasses ?: emptyList) { var conflicts = new HashSet() - + // Detect input conflicts checkConflict(superClass.toDefinition.inputs, reactor.inputs, variables, conflicts) // Detect output conflicts @@ -980,7 +980,7 @@ class LFValidator extends AbstractLFValidator { variables.add(timer) } } - + // Report conflicts. if (conflicts.size > 0) { val names = new ArrayList(); @@ -988,11 +988,11 @@ class LFValidator extends AbstractLFValidator { error( '''Cannot extend «superClass.name» due to the following conflicts: «names.join(',')».''', Literals.REACTOR__SUPER_CLASSES - ) + ) } } } - /** + /** * For each input, report a conflict if: * 1) the input exists and the type doesn't match; or * 2) the input has a name clash with variable that is not an input. @@ -1217,12 +1217,12 @@ class LFValidator extends AbstractLFValidator { } } } - + @Check(FAST) def checkTimer(Timer timer) { checkName(timer.name, Literals.VARIABLE__NAME) } - + @Check(FAST) def checkType(Type type) { // FIXME: disallow the use of generics in C @@ -1239,7 +1239,7 @@ class LFValidator extends AbstractLFValidator { } } else if (this.target == Target.Python) { - if (type !== null) { + if (type !== null) { error( "Types are not allowed in the Python target", Literals.TYPE__ID @@ -1247,7 +1247,7 @@ class LFValidator extends AbstractLFValidator { } } } - + static val UNDERSCORE_MESSAGE = "Names of objects (inputs, outputs, actions, timers, parameters, state, reactor definitions, and reactor instantiation) may not start with \"__\": " static val ACTIONS_MESSAGE = "\"actions\" is a reserved word for the TypeScript target for objects (inputs, outputs, actions, timers, parameters, state, reactor definitions, and reactor instantiation): " static val RESERVED_MESSAGE = "Reserved words in the target language are not allowed for objects (inputs, outputs, actions, timers, parameters, state, reactor definitions, and reactor instantiation): " From a55bcbc81c455cc48a3975d8c129da7a3a077655 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Thu, 22 Apr 2021 19:34:18 +0200 Subject: [PATCH 24/88] More things from ASTUtils --- org.lflang/src/org/lflang/Extensions.kt | 343 ++++++++++++++++++ .../org/lflang/generator/KtGeneratorBase.kt | 6 +- 2 files changed, 346 insertions(+), 3 deletions(-) diff --git a/org.lflang/src/org/lflang/Extensions.kt b/org.lflang/src/org/lflang/Extensions.kt index 93a15fd501..3e82750b5e 100644 --- a/org.lflang/src/org/lflang/Extensions.kt +++ b/org.lflang/src/org/lflang/Extensions.kt @@ -24,7 +24,10 @@ package org.lflang +import org.eclipse.emf.ecore.resource.Resource import org.eclipse.xtext.nodemodel.util.NodeModelUtils +import org.lflang.ASTUtils.factory +import org.lflang.generator.KtGeneratorBase import org.lflang.lf.* @@ -135,3 +138,343 @@ fun TypeParm.toText(): String = if (!literal.isNullOrEmpty()) literal else code.toText() + +/** + * Find connections in the given resource that have a delay associated with them, + * and reroute them via a generated delay reactor. + * @param resource The AST. + * @param generator A code generator. + */ +fun insertGeneratedDelays(resource: Resource, generator: KtGeneratorBase) { + // The resulting changes to the AST are performed _after_ iterating + // in order to avoid concurrent modification problems. + val oldConnections = mutableListOf() + val newConnections = mutableMapOf>() + val delayInstances = mutableMapOf>() + + // Iterate over the connections in the tree. + for (container in resource.allContents.asSequence().filterIsInstance()) { + for (connection in container.connections) { + if (connection.delay !== null) { + val parent = connection.eContainer() as Reactor + // Assume all the types are the same, so just use the first on the right. + val type = (connection.rightPorts[0].variable as Port).type + val delayClass = getDelayClass(type, generator) + val generic = + if (generator.supportsGenerics) + generator.getTargetType(InferredType.fromAST(type)) + else "" + + // If the left or right has a multiport or bank, then create a bank + // of delays with an inferred width. + // FIXME: If the connection already uses an inferred width on + // the left or right, then this will fail because you cannot + // have an inferred width on both sides. + val isWide = connection.isWide + val delayInstance = getDelayInstance(delayClass, connection.delay, generic, isWide) + + // Stage the new connections for insertion into the tree. + newConnections.computeIfAbsent(parent) { mutableListOf() } + .addAll(connection.rerouteViaDelay(delayInstance)) + + // Stage the original connection for deletion from the tree. + oldConnections.add(connection) + + // Stage the newly created delay reactor instance for insertion + delayInstances.computeIfAbsent(parent) { mutableListOf() } + .add(delayInstance) + } + } + } + // Remove old connections; insert new ones. + for (connection in oldConnections) { + (connection.eContainer() as Reactor).connections.remove(connection) + } + for ((reactor, connections) in newConnections) { + reactor.connections.addAll(connections) + } + // Finally, insert the instances and, before doing so, assign them a unique name. + for ((reactor, instantiations) in delayInstances) { + for (instantiation in instantiations) { + instantiation.name = reactor.getUniqueIdentifier("delay") + reactor.instantiations.add(instantiation) + } + } +} + + +/** + * Return true if any port on the left or right of this connection involves + * a bank of reactors or a multiport. + */ +private val Connection.isWide: Boolean + get() { + val allPorts = leftPorts + rightPorts + return allPorts.any { port -> + (port.variable as? Port)?.widthSpec != null + || port.container?.widthSpec != null + } + } + + +/** + * Take a connection and reroute it via an instance of a generated delay + * reactor. This method returns a list to new connections to substitute + * the original one. + * @receiver The connection to reroute. + * @param delayInstance The delay instance to route the connection through. + */ +private fun Connection.rerouteViaDelay(delayInstance: Instantiation): List { + val connections = mutableListOf() + + val upstream = factory.createConnection() + val downstream = factory.createConnection() + val input = factory.createVarRef() + val output = factory.createVarRef() + + val delayClass = delayInstance.reactorClass.toDefinition() + + // Establish references to the involved ports. + input.container = delayInstance + input.variable = delayClass.inputs[0] + output.container = delayInstance + output.variable = delayClass.outputs[0] + upstream.leftPorts.addAll(leftPorts) + upstream.rightPorts.add(input) + downstream.leftPorts.add(output) + downstream.rightPorts.addAll(rightPorts) + + connections.add(upstream) + connections.add(downstream) + return connections +} + +/** + * Produce a unique identifier within a reactor based on a + * given based name. If the name does not exists, it is returned; + * if does exist, an index is appended that makes the name unique. + * @receiver The reactor to find a unique identifier within. + * @param name The name to base the returned identifier on. + */ +fun Reactor.getUniqueIdentifier(name: String): String { + val vars = mutableSetOf().apply { + addAll(allActions.map { it.name }) + addAll(allTimers.map { it.name }) + addAll(allParameters.map { it.name }) + addAll(allInputs.map { it.name }) + addAll(allOutputs.map { it.name }) + addAll(allStateVars.map { it.name }) + addAll(allInstantiations.map { it.name }) + } + + var index = 0 + var suffix = "" + while (true) { + val id = name + suffix + if (id in vars) { + // already exists + suffix = "_$index" + index++ + } else { + break + } + } + return name + suffix +} + +/** + * Create a new instance delay instances using the given reactor class. + * The supplied time value is used to override the default interval (which + * is zero). + * If the target supports parametric polymorphism, then a single class may + * be used for each instantiation, in which case a non-empty string must + * be supplied to parameterize the instance. + * A default name ("delay") is assigned to the instantiation, but this + * name must be overridden at the call site, where checks can be done to + * avoid name collisions in the container in which the instantiation is + * to be placed. Such checks (or modifications of the AST) are not + * performed in this method in order to avoid causing concurrent + * modification exceptions. + * @param delayClass The class to create an instantiation for + * @param value A time interval corresponding to the desired delay + * @param generic A string that denotes the appropriate type parameter, + * which should be null or empty if the target does not support generics. + * @param isWide True to create a variable-width width specification. + */ +private fun getDelayInstance(delayClass: Reactor, delay: Delay, generic: String, isWide: Boolean): Instantiation { + val delayInstance = factory.createInstantiation().apply { + reactorClass = delayClass + } + if (generic.isNotEmpty()) { + val typeParm = factory.createTypeParm().apply { literal = generic } + delayInstance.typeParms.add(typeParm) + } + if (isWide) { + val widthSpec = factory.createWidthSpec() + delayInstance.widthSpec = widthSpec + widthSpec.isOfVariableLength = true + } + val assignment = factory.createAssignment() + assignment.lhs = delayClass.parameters[0] + val value = factory.createValue().apply { + if (delay.parameter !== null) { + parameter = delay.parameter + } else { + time = factory.createTime() + time.interval = delay.interval + time.unit = delay.unit + } + } + assignment.rhs.add(value) + delayInstance.parameters.add(assignment) + delayInstance.name = "delay" // This has to be overridden. + + return delayInstance + +} + +/** + * Return a synthesized AST node that represents the definition of a delay + * reactor. Depending on whether the target supports generics, either this + * method will synthesize a generic definition and keep returning it upon + * subsequent calls, or otherwise, it will synthesize a new definition for + * each new type it hasn't yet created a compatible delay reactor for. + * @param aType The type the delay class must be compatible with. + * @param generator A code generator. + */ +private fun getDelayClass(aType: Type, generator: KtGeneratorBase): Reactor { + val className = + if (generator.supportsGenerics) KtGeneratorBase.GEN_DELAY_CLASS_NAME + else run { + val id = Integer.toHexString(InferredType.fromAST(aType).toText().hashCode()) + "${KtGeneratorBase.GEN_DELAY_CLASS_NAME}_$id" + } + + // Only add class definition if it is not already there. + val classDef = generator.findDelayClass(className) + if (classDef !== null) { + return classDef + } + + val defaultValue = factory.createValue().apply { + literal = generator.timeInTargetLanguage(TimeValue(0, TimeUnit.NONE)) + } + + val delayParameter = factory.createParameter().apply { + name = "delay" + type = factory.createType() + aType.id = generator.targetTimeType + init.add(defaultValue) + } + val action = factory.createAction().apply { + name = "act" + minDelay = factory.createValue() + minDelay.parameter = delayParameter + origin = ActionOrigin.LOGICAL + } + + // Establish references to the action. + val triggerRef = factory.createVarRef().apply { variable = action } + val effectRef = factory.createVarRef().apply { variable = action } + val input = factory.createInput().apply { + name = "inp" + type = action.type.getCopy() + } + val output = factory.createOutput().apply { + name = "out" + type = action.type.getCopy() + } + + // Establish references to the involved ports. + val inRef = factory.createVarRef().apply { + variable = input + } + val outRef = factory.createVarRef().apply { + variable = output + } + + + // Name the newly created action; set its delay and type. + + if (generator.supportsGenerics) { + action.type = factory.createType() + action.type.id = "T" + } else { + action.type = aType.getCopy() + } + + val r1 = factory.createReaction().apply { + // Configure the second reaction, which reads the input. + triggers.add(inRef) + effects.add(effectRef) + code = factory.createCode() + code.body = generator.generateDelayBody(action, inRef) + } + + val r2 = factory.createReaction().apply { + // Configure the first reaction, which produces the output. + triggers.add(triggerRef) + effects.add(outRef) + code = factory.createCode() + code.body = generator.generateForwardBody(action, outRef) + } + + val delayClass = factory.createReactor().apply { + name = className + // Add the action to the reactor. + actions += action + + // These need to go in the opposite order in case + // a new input arrives at the same time the delayed + // output is delivered! + reactions += r2 + reactions += r1 + + inputs += input + outputs += output + parameters += delayParameter + + // Add a type parameter if the target supports it. + if (generator.supportsGenerics) { + typeParms += factory.createTypeParm().apply { + literal = generator.generateDelayGeneric() + } + } + } + + generator.addDelayClass(delayClass) + + return delayClass +} + +private fun TypeParm.getCopy(): TypeParm { + val original = this + return factory.createTypeParm().apply { + literal = original.literal + code = factory.createCode().apply { body = original.code.body } + } +} + +private fun Type.getCopy(): Type { + val original = this + return factory.createType().apply { + id = original.id + isTime = original.isTime + stars.addAll(original.stars.orEmpty()) + + if (original.code !== null) { + code = factory.createCode().apply { + body = original.code.body + } + } + if (original.arraySpec !== null) { + arraySpec = factory.createArraySpec().apply { + this.isOfVariableLength = original.arraySpec.isOfVariableLength + length = original.arraySpec.length + } + } + + typeParms.addAll(original.typeParms.orEmpty().map { it.getCopy() }) + } + +} diff --git a/org.lflang/src/org/lflang/generator/KtGeneratorBase.kt b/org.lflang/src/org/lflang/generator/KtGeneratorBase.kt index 7e495c5c7f..dff347cc19 100644 --- a/org.lflang/src/org/lflang/generator/KtGeneratorBase.kt +++ b/org.lflang/src/org/lflang/generator/KtGeneratorBase.kt @@ -410,7 +410,7 @@ abstract class KtGeneratorBase( */ protected fun transformDelays() { for (r in resources) { - ASTUtils.insertGeneratedDelays(r, this) + insertGeneratedDelays(r, this) } } @@ -1321,7 +1321,7 @@ You can set PATH in ~/.bash_profile on Linux or Mac.""" * * @param stderr The output on standard error of executing a command. */ - protected fun reportCommandErrors(stderr: String): String? { + protected fun reportCommandErrors(stderr: String) { val message = StringBuilder() var lineNumber: Int? = null var resource: IResource? = this.getEclipseResource(this.fileConfig!!.srcFile.toURI()) @@ -2083,7 +2083,7 @@ You can set PATH in ~/.bash_profile on Linux or Mac.""" abstract fun getTargetVariableSizeListType(baseType: String): String /** Return a string representing the specified type in the target language. */ - protected fun getTargetType(type: InferredType): String = when { + fun getTargetType(type: InferredType): String = when { type.isUndefined -> this.targetUndefinedType type.isTime -> when { type.isFixedSizeList -> this.getTargetFixedSizeListType(this.targetTimeType, type.listSize) From 48f912750b568b22a77ba92b185796ed99f07375 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Thu, 22 Apr 2021 19:36:03 +0200 Subject: [PATCH 25/88] Commit new files Where do they come from? why do I need to do this? --- .../src/org/lflang/ide/LFIdeModule.java | 11 +++++++ .../src/org/lflang/ide/LFIdeModule.xtend | 11 ------- .../src/org/lflang/ide/LFIdeSetup.java | 22 +++++++++++++ .../src/org/lflang/ide/LFIdeSetup.xtend | 20 ------------ .../src/org/lflang/tests/LFParsingTest.java | 31 ++++++++++++++++++ .../src/org/lflang/ui/LFUiModule.java | 16 ++++++++++ .../src/org/lflang/ui/LFUiModule.xtend | 2 +- .../ui/contentassist/LFProposalProvider.java | 12 +++++++ .../ui/contentassist/LFProposalProvider.xtend | 12 ------- ....xtend => LFDescriptionLabelProvider.java} | 19 +++++------ .../lflang/ui/labeling/LFLabelProvider.java | 31 ++++++++++++++++++ .../lflang/ui/labeling/LFLabelProvider.xtend | 31 ------------------ ...vider.xtend => LFOutlineTreeProvider.java} | 6 ++-- .../ui/quickfix/LFQuickfixProvider.java | 26 +++++++++++++++ .../ui/quickfix/LFQuickfixProvider.xtend | 24 -------------- .../org/lflang/scoping/LFScopeProvider.java | 32 +++++++++++++++++++ 16 files changed, 195 insertions(+), 111 deletions(-) create mode 100644 org.lflang.ide/src/org/lflang/ide/LFIdeModule.java delete mode 100644 org.lflang.ide/src/org/lflang/ide/LFIdeModule.xtend create mode 100644 org.lflang.ide/src/org/lflang/ide/LFIdeSetup.java delete mode 100644 org.lflang.ide/src/org/lflang/ide/LFIdeSetup.xtend create mode 100644 org.lflang.tests/src/org/lflang/tests/LFParsingTest.java create mode 100644 org.lflang.ui/src/org/lflang/ui/LFUiModule.java create mode 100644 org.lflang.ui/src/org/lflang/ui/contentassist/LFProposalProvider.java delete mode 100644 org.lflang.ui/src/org/lflang/ui/contentassist/LFProposalProvider.xtend rename org.lflang.ui/src/org/lflang/ui/labeling/{LFDescriptionLabelProvider.xtend => LFDescriptionLabelProvider.java} (50%) create mode 100644 org.lflang.ui/src/org/lflang/ui/labeling/LFLabelProvider.java delete mode 100644 org.lflang.ui/src/org/lflang/ui/labeling/LFLabelProvider.xtend rename org.lflang.ui/src/org/lflang/ui/outline/{LFOutlineTreeProvider.xtend => LFOutlineTreeProvider.java} (68%) create mode 100644 org.lflang.ui/src/org/lflang/ui/quickfix/LFQuickfixProvider.java delete mode 100644 org.lflang.ui/src/org/lflang/ui/quickfix/LFQuickfixProvider.xtend create mode 100644 org.lflang/src/org/lflang/scoping/LFScopeProvider.java diff --git a/org.lflang.ide/src/org/lflang/ide/LFIdeModule.java b/org.lflang.ide/src/org/lflang/ide/LFIdeModule.java new file mode 100644 index 0000000000..6c63d9c6e0 --- /dev/null +++ b/org.lflang.ide/src/org/lflang/ide/LFIdeModule.java @@ -0,0 +1,11 @@ +/* + * generated by Xtext 2.23.0 + */ +package org.lflang.ide; + + +/** + * Use this class to register ide components. + */ +public class LFIdeModule extends AbstractLFIdeModule { +} diff --git a/org.lflang.ide/src/org/lflang/ide/LFIdeModule.xtend b/org.lflang.ide/src/org/lflang/ide/LFIdeModule.xtend deleted file mode 100644 index 15294b401d..0000000000 --- a/org.lflang.ide/src/org/lflang/ide/LFIdeModule.xtend +++ /dev/null @@ -1,11 +0,0 @@ -/* - * generated by Xtext 2.17.0 - */ -package org.lflang.ide - - -/** - * Use this class to register ide components. - */ -class LFIdeModule extends AbstractLFIdeModule { -} diff --git a/org.lflang.ide/src/org/lflang/ide/LFIdeSetup.java b/org.lflang.ide/src/org/lflang/ide/LFIdeSetup.java new file mode 100644 index 0000000000..034154d4f8 --- /dev/null +++ b/org.lflang.ide/src/org/lflang/ide/LFIdeSetup.java @@ -0,0 +1,22 @@ +/* + * generated by Xtext 2.23.0 + */ +package org.lflang.ide; + +import com.google.inject.Guice; +import com.google.inject.Injector; +import org.eclipse.xtext.util.Modules2; +import org.lflang.LFRuntimeModule; +import org.lflang.LFStandaloneSetup; + +/** + * Initialization support for running Xtext languages as language servers. + */ +public class LFIdeSetup extends LFStandaloneSetup { + + @Override + public Injector createInjector() { + return Guice.createInjector(Modules2.mixin(new LFRuntimeModule(), new LFIdeModule())); + } + +} diff --git a/org.lflang.ide/src/org/lflang/ide/LFIdeSetup.xtend b/org.lflang.ide/src/org/lflang/ide/LFIdeSetup.xtend deleted file mode 100644 index 2dd67890f5..0000000000 --- a/org.lflang.ide/src/org/lflang/ide/LFIdeSetup.xtend +++ /dev/null @@ -1,20 +0,0 @@ -/* - * generated by Xtext 2.17.0 - */ -package org.lflang.ide - -import com.google.inject.Guice -import org.eclipse.xtext.util.Modules2 -import org.lflang.LFRuntimeModule -import org.lflang.LFStandaloneSetup - -/** - * Initialization support for running Xtext languages as language servers. - */ -class LFIdeSetup extends LFStandaloneSetup { - - override createInjector() { - Guice.createInjector(Modules2.mixin(new LFRuntimeModule, new LFIdeModule)) - } - -} diff --git a/org.lflang.tests/src/org/lflang/tests/LFParsingTest.java b/org.lflang.tests/src/org/lflang/tests/LFParsingTest.java new file mode 100644 index 0000000000..4b8b2340d7 --- /dev/null +++ b/org.lflang.tests/src/org/lflang/tests/LFParsingTest.java @@ -0,0 +1,31 @@ +/* + * generated by Xtext 2.23.0 + */ +package org.lflang.tests; + +import com.google.inject.Inject; +import java.util.List; +import org.eclipse.emf.ecore.resource.Resource.Diagnostic; +import org.eclipse.xtext.testing.InjectWith; +import org.eclipse.xtext.testing.extensions.InjectionExtension; +import org.eclipse.xtext.testing.util.ParseHelper; +import org.eclipse.xtext.xbase.lib.IterableExtensions; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.lflang.lf.Model; + +@ExtendWith(InjectionExtension.class) +@InjectWith(LFInjectorProvider.class) +public class LFParsingTest { + @Inject + private ParseHelper parseHelper; + + @Test + public void loadModel() throws Exception { + Model result = parseHelper.parse("Hello Xtext!"); + Assertions.assertNotNull(result); + List errors = result.eResource().getErrors(); + Assertions.assertTrue(errors.isEmpty(), "Unexpected errors: " + IterableExtensions.join(errors, ", ")); + } +} diff --git a/org.lflang.ui/src/org/lflang/ui/LFUiModule.java b/org.lflang.ui/src/org/lflang/ui/LFUiModule.java new file mode 100644 index 0000000000..e651a9e147 --- /dev/null +++ b/org.lflang.ui/src/org/lflang/ui/LFUiModule.java @@ -0,0 +1,16 @@ +/* + * generated by Xtext 2.23.0 + */ +package org.lflang.ui; + +import org.eclipse.ui.plugin.AbstractUIPlugin; + +/** + * Use this class to register components to be used within the Eclipse IDE. + */ +public class LFUiModule extends AbstractLFUiModule { + + public LFUiModule(AbstractUIPlugin plugin) { + super(plugin); + } +} diff --git a/org.lflang.ui/src/org/lflang/ui/LFUiModule.xtend b/org.lflang.ui/src/org/lflang/ui/LFUiModule.xtend index 8559e7f04b..e90b6f8b2d 100644 --- a/org.lflang.ui/src/org/lflang/ui/LFUiModule.xtend +++ b/org.lflang.ui/src/org/lflang/ui/LFUiModule.xtend @@ -30,7 +30,7 @@ import org.eclipse.xtext.resource.containers.IAllContainersState * subclassing, and the code has no comments in it at all. */ @FinalFieldsConstructor -class LFUiModule extends AbstractLFUiModule { +class LFUiModuleImpl extends AbstractLFUiModule { // Instead of classpath, use Properties -> Project Reference override Provider provideIAllContainersState() { diff --git a/org.lflang.ui/src/org/lflang/ui/contentassist/LFProposalProvider.java b/org.lflang.ui/src/org/lflang/ui/contentassist/LFProposalProvider.java new file mode 100644 index 0000000000..9e10038905 --- /dev/null +++ b/org.lflang.ui/src/org/lflang/ui/contentassist/LFProposalProvider.java @@ -0,0 +1,12 @@ +/* + * generated by Xtext 2.23.0 + */ +package org.lflang.ui.contentassist; + + +/** + * See https://www.eclipse.org/Xtext/documentation/310_eclipse_support.html#content-assist + * on how to customize the content assistant. + */ +public class LFProposalProvider extends AbstractLFProposalProvider { +} diff --git a/org.lflang.ui/src/org/lflang/ui/contentassist/LFProposalProvider.xtend b/org.lflang.ui/src/org/lflang/ui/contentassist/LFProposalProvider.xtend deleted file mode 100644 index 0076cea5ef..0000000000 --- a/org.lflang.ui/src/org/lflang/ui/contentassist/LFProposalProvider.xtend +++ /dev/null @@ -1,12 +0,0 @@ -/* - * generated by Xtext 2.17.0 - */ -package org.lflang.ui.contentassist - - -/** - * See https://www.eclipse.org/Xtext/documentation/304_ide_concepts.html#content-assist - * on how to customize the content assistant. - */ -class LFProposalProvider extends AbstractLFProposalProvider { -} diff --git a/org.lflang.ui/src/org/lflang/ui/labeling/LFDescriptionLabelProvider.xtend b/org.lflang.ui/src/org/lflang/ui/labeling/LFDescriptionLabelProvider.java similarity index 50% rename from org.lflang.ui/src/org/lflang/ui/labeling/LFDescriptionLabelProvider.xtend rename to org.lflang.ui/src/org/lflang/ui/labeling/LFDescriptionLabelProvider.java index 047124fff4..cbb042511a 100644 --- a/org.lflang.ui/src/org/lflang/ui/labeling/LFDescriptionLabelProvider.xtend +++ b/org.lflang.ui/src/org/lflang/ui/labeling/LFDescriptionLabelProvider.java @@ -1,24 +1,25 @@ /* * generated by Xtext 2.23.0 */ -package org.lflang.ui.labeling +package org.lflang.ui.labeling; -import org.eclipse.xtext.ui.label.DefaultDescriptionLabelProvider +import org.eclipse.xtext.ui.label.DefaultDescriptionLabelProvider; /** * Provides labels for IEObjectDescriptions and IResourceDescriptions. * * See https://www.eclipse.org/Xtext/documentation/310_eclipse_support.html#label-provider */ -class LFDescriptionLabelProvider extends DefaultDescriptionLabelProvider { +public class LFDescriptionLabelProvider extends DefaultDescriptionLabelProvider { // Labels and icons can be computed like this: - -// override text(IEObjectDescription ele) { -// ele.name.toString +// @Override +// public String text(IEObjectDescription ele) { +// return ele.getName().toString(); // } -// -// override image(IEObjectDescription ele) { -// ele.EClass.name + '.gif' +// +// @Override +// public String image(IEObjectDescription ele) { +// return ele.getEClass().getName() + ".gif"; // } } diff --git a/org.lflang.ui/src/org/lflang/ui/labeling/LFLabelProvider.java b/org.lflang.ui/src/org/lflang/ui/labeling/LFLabelProvider.java new file mode 100644 index 0000000000..568b19120d --- /dev/null +++ b/org.lflang.ui/src/org/lflang/ui/labeling/LFLabelProvider.java @@ -0,0 +1,31 @@ +/* + * generated by Xtext 2.23.0 + */ +package org.lflang.ui.labeling; + +import com.google.inject.Inject; +import org.eclipse.emf.edit.ui.provider.AdapterFactoryLabelProvider; +import org.eclipse.xtext.ui.label.DefaultEObjectLabelProvider; + +/** + * Provides labels for EObjects. + * + * See https://www.eclipse.org/Xtext/documentation/310_eclipse_support.html#label-provider + */ +public class LFLabelProvider extends DefaultEObjectLabelProvider { + + @Inject + public LFLabelProvider(AdapterFactoryLabelProvider delegate) { + super(delegate); + } + + // Labels and icons can be computed like this: + +// String text(Greeting ele) { +// return "A greeting to " + ele.getName(); +// } +// +// String image(Greeting ele) { +// return "Greeting.gif"; +// } +} diff --git a/org.lflang.ui/src/org/lflang/ui/labeling/LFLabelProvider.xtend b/org.lflang.ui/src/org/lflang/ui/labeling/LFLabelProvider.xtend deleted file mode 100644 index 75c75822e6..0000000000 --- a/org.lflang.ui/src/org/lflang/ui/labeling/LFLabelProvider.xtend +++ /dev/null @@ -1,31 +0,0 @@ -/* - * generated by Xtext 2.23.0 - */ -package org.lflang.ui.labeling - -import com.google.inject.Inject -import org.eclipse.emf.edit.ui.provider.AdapterFactoryLabelProvider -import org.eclipse.xtext.ui.label.DefaultEObjectLabelProvider - -/** - * Provides labels for EObjects. - * - * See https://www.eclipse.org/Xtext/documentation/310_eclipse_support.html#label-provider - */ -class LFLabelProvider extends DefaultEObjectLabelProvider { - - @Inject - new(AdapterFactoryLabelProvider delegate) { - super(delegate); - } - - // Labels and icons can be computed like this: - -// def text(Greeting ele) { -// 'A greeting to ' + ele.name -// } -// -// def image(Greeting ele) { -// 'Greeting.gif' -// } -} diff --git a/org.lflang.ui/src/org/lflang/ui/outline/LFOutlineTreeProvider.xtend b/org.lflang.ui/src/org/lflang/ui/outline/LFOutlineTreeProvider.java similarity index 68% rename from org.lflang.ui/src/org/lflang/ui/outline/LFOutlineTreeProvider.xtend rename to org.lflang.ui/src/org/lflang/ui/outline/LFOutlineTreeProvider.java index 2f81586eef..5a141e7a8e 100644 --- a/org.lflang.ui/src/org/lflang/ui/outline/LFOutlineTreeProvider.xtend +++ b/org.lflang.ui/src/org/lflang/ui/outline/LFOutlineTreeProvider.java @@ -1,15 +1,15 @@ /* * generated by Xtext 2.23.0 */ -package org.lflang.ui.outline +package org.lflang.ui.outline; -import org.eclipse.xtext.ui.editor.outline.impl.DefaultOutlineTreeProvider +import org.eclipse.xtext.ui.editor.outline.impl.DefaultOutlineTreeProvider; /** * Customization of the default outline structure. * * See https://www.eclipse.org/Xtext/documentation/310_eclipse_support.html#outline */ -class LFOutlineTreeProvider extends DefaultOutlineTreeProvider { +public class LFOutlineTreeProvider extends DefaultOutlineTreeProvider { } diff --git a/org.lflang.ui/src/org/lflang/ui/quickfix/LFQuickfixProvider.java b/org.lflang.ui/src/org/lflang/ui/quickfix/LFQuickfixProvider.java new file mode 100644 index 0000000000..a9dd0ae481 --- /dev/null +++ b/org.lflang.ui/src/org/lflang/ui/quickfix/LFQuickfixProvider.java @@ -0,0 +1,26 @@ +/* + * generated by Xtext 2.23.0 + */ +package org.lflang.ui.quickfix; + +import org.eclipse.xtext.ui.editor.quickfix.DefaultQuickfixProvider; + +/** + * Custom quickfixes. + * + * See https://www.eclipse.org/Xtext/documentation/310_eclipse_support.html#quick-fixes + */ +public class LFQuickfixProvider extends DefaultQuickfixProvider { + +// @Fix(LFValidator.INVALID_NAME) +// public void capitalizeName(final Issue issue, IssueResolutionAcceptor acceptor) { +// acceptor.accept(issue, "Capitalize name", "Capitalize the name.", "upcase.png", new IModification() { +// public void apply(IModificationContext context) throws BadLocationException { +// IXtextDocument xtextDocument = context.getXtextDocument(); +// String firstLetter = xtextDocument.get(issue.getOffset(), 1); +// xtextDocument.replace(issue.getOffset(), 1, firstLetter.toUpperCase()); +// } +// }); +// } + +} diff --git a/org.lflang.ui/src/org/lflang/ui/quickfix/LFQuickfixProvider.xtend b/org.lflang.ui/src/org/lflang/ui/quickfix/LFQuickfixProvider.xtend deleted file mode 100644 index 5473c6fcef..0000000000 --- a/org.lflang.ui/src/org/lflang/ui/quickfix/LFQuickfixProvider.xtend +++ /dev/null @@ -1,24 +0,0 @@ -/* - * generated by Xtext 2.23.0 - */ -package org.lflang.ui.quickfix - -import org.eclipse.xtext.ui.editor.quickfix.DefaultQuickfixProvider - -/** - * Custom quickfixes. - * - * See https://www.eclipse.org/Xtext/documentation/310_eclipse_support.html#quick-fixes - */ -class LFQuickfixProvider extends DefaultQuickfixProvider { - -// @Fix(LFValidator.INVALID_NAME) -// def capitalizeName(Issue issue, IssueResolutionAcceptor acceptor) { -// acceptor.accept(issue, 'Capitalize name', 'Capitalize the name.', 'upcase.png') [ -// context | -// val xtextDocument = context.xtextDocument -// val firstLetter = xtextDocument.get(issue.offset, 1) -// xtextDocument.replace(issue.offset, 1, firstLetter.toUpperCase) -// ] -// } -} diff --git a/org.lflang/src/org/lflang/scoping/LFScopeProvider.java b/org.lflang/src/org/lflang/scoping/LFScopeProvider.java new file mode 100644 index 0000000000..875dc6a02a --- /dev/null +++ b/org.lflang/src/org/lflang/scoping/LFScopeProvider.java @@ -0,0 +1,32 @@ +/* + * generated by Xtext 2.23.0 + */ + +package org.lflang.scoping; + + +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.EReference; +import org.eclipse.xtext.naming.SimpleNameProvider; +import org.eclipse.xtext.scoping.IScope; + +import com.google.inject.Inject; + +/** + * This class contains custom scoping description. + *

+ * See https://www.eclipse.org/Xtext/documentation/303_runtime_concepts.html#scoping + * on how and when to use it. + */ +public class LFScopeProvider extends AbstractLFScopeProvider { + + @Inject + private SimpleNameProvider nameProvider; + @Inject + private LFGlobalScopeProvider scopeProvider; + + @Override + public IScope getScope(EObject context, EReference reference) { + return new LFScopeProviderImpl(nameProvider, scopeProvider).getScope(context, reference); + } +} From b299a3b661ee14a08202eb192aa563840b9c0873 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Thu, 22 Apr 2021 16:38:28 -0700 Subject: [PATCH 26/88] Updated generated stubs in ide package. --- org.lflang.ide/.classpath | 290 +----------------- org.lflang.ide/.project | 32 +- .../org.eclipse.wst.common.component | 1 + org.lflang/.classpath | 2 +- org.lflang/.project | 13 + .../.settings/org.eclipse.jdt.core.prefs | 1 + 6 files changed, 39 insertions(+), 300 deletions(-) diff --git a/org.lflang.ide/.classpath b/org.lflang.ide/.classpath index 5aedde908f..b86a833339 100644 --- a/org.lflang.ide/.classpath +++ b/org.lflang.ide/.classpath @@ -1,305 +1,25 @@ - + - + - + - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + diff --git a/org.lflang.ide/.project b/org.lflang.ide/.project index 92f51d3431..dd41def898 100644 --- a/org.lflang.ide/.project +++ b/org.lflang.ide/.project @@ -2,35 +2,39 @@ org.lflang.ide - - - org.eclipse.xtext.ui.shared.xtextNature - org.eclipse.jdt.core.javanature - org.eclipse.pde.PluginNature - org.eclipse.buildship.core.gradleprojectnature - + + 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 + diff --git a/org.lflang.web/.settings/org.eclipse.wst.common.component b/org.lflang.web/.settings/org.eclipse.wst.common.component index cdf8a7cee1..e93ed3ca81 100644 --- a/org.lflang.web/.settings/org.eclipse.wst.common.component +++ b/org.lflang.web/.settings/org.eclipse.wst.common.component @@ -4,6 +4,7 @@ + uses diff --git a/org.lflang/.classpath b/org.lflang/.classpath index b37b281235..1b604e5af8 100644 --- a/org.lflang/.classpath +++ b/org.lflang/.classpath @@ -20,6 +20,6 @@ - + diff --git a/org.lflang/.project b/org.lflang/.project index 947290c99e..910d63860a 100644 --- a/org.lflang/.project +++ b/org.lflang/.project @@ -5,6 +5,11 @@ + + org.jetbrains.kotlin.ui.kotlinBuilder + + + org.eclipse.jdt.core.javabuilder @@ -36,5 +41,13 @@ org.eclipse.jdt.core.javanature org.eclipse.pde.PluginNature org.eclipse.buildship.core.gradleprojectnature + org.jetbrains.kotlin.core.kotlinNature + + + kotlin_bin + 2 + 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 519596a625..9d92e3c736 100644 --- a/org.lflang/.settings/org.eclipse.jdt.core.prefs +++ b/org.lflang/.settings/org.eclipse.jdt.core.prefs @@ -1,4 +1,5 @@ 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 From cd67cedba33dfcb9cb82b66a911e03c39dd13d7a Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Thu, 22 Apr 2021 17:07:55 -0700 Subject: [PATCH 27/88] Addressed warning. --- .../src/org/lflang/ui/{LFUiModule.xtend => LFUiModuleImpl.xtend} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename org.lflang.ui/src/org/lflang/ui/{LFUiModule.xtend => LFUiModuleImpl.xtend} (100%) diff --git a/org.lflang.ui/src/org/lflang/ui/LFUiModule.xtend b/org.lflang.ui/src/org/lflang/ui/LFUiModuleImpl.xtend similarity index 100% rename from org.lflang.ui/src/org/lflang/ui/LFUiModule.xtend rename to org.lflang.ui/src/org/lflang/ui/LFUiModuleImpl.xtend From 502c229fff36c0d3cdfbfc9f3a7de5c7eef9109f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Fri, 23 Apr 2021 11:18:00 +0200 Subject: [PATCH 28/88] Add kotlin and ajdt plugins to oomph --- oomph/LinguaFranca.setup | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/oomph/LinguaFranca.setup b/oomph/LinguaFranca.setup index 76405930d8..1d91ff0b27 100644 --- a/oomph/LinguaFranca.setup +++ b/oomph/LinguaFranca.setup @@ -166,6 +166,24 @@ url="http://download.eclipse.org/modeling/tmf/xtext/updates/composite/releases/"/> Install the tools needed in the IDE to work with the source code for ${scope.project.label} + + + + + + + + + + Date: Fri, 23 Apr 2021 11:19:57 +0200 Subject: [PATCH 29/88] Cleanup target --- org.lflang/src/org/lflang/Target.java | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/org.lflang/src/org/lflang/Target.java b/org.lflang/src/org/lflang/Target.java index 72c27bd061..4c16bffe67 100644 --- a/org.lflang/src/org/lflang/Target.java +++ b/org.lflang/src/org/lflang/Target.java @@ -1,5 +1,5 @@ /* Static information about targets. */ -/** +/** * Copyright (c) 2019, The University of California at Berkeley. * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: @@ -339,41 +339,41 @@ public enum Target { "_Static_assert", // (since C11) "_Thread_local" // (since C11) ) - ); - + ); + /** * String representation of this target. */ private final String description; - + /** * Whether or not this target requires types. */ public final boolean requiresTypes; - + /** * Reserved words in the target language. */ public final List keywords; - + /** * Return an array of all known targets. */ public final static Target[] ALL = Target.values(); - + /** * Private constructor for targets. - * + * * @param name String representation of this target. * @param requires Types Whether this target requires type annotations or not. * @param keywords List of reserved strings in the target language. */ - private Target(String description, boolean requiresTypes, List keywords) { + Target(String description, boolean requiresTypes, List keywords) { this.description = description; this.requiresTypes = requiresTypes; this.keywords = keywords; } - + /** * Check whether a given string corresponds with the name of a valid target. * @param name The string for which to determine whether there is a match. @@ -388,7 +388,7 @@ public final static boolean hasForName(String name) { /** * Return the target that matches the given string. - * + * * @param name The string to match against. * @return The matching target (or null if there is none). */ @@ -401,7 +401,7 @@ public static Target forName(String name) { */ @Override public String toString() { - return this.description; + return description; } /** @@ -411,7 +411,6 @@ public String toString() { * @param string The string to match against candidates. * @param candidates The candidates to match the string against. */ - @Nullable public static T match(final String string, final Iterable candidates) { // kotlin: candidates.firstOrNull { it.toString().equalsIgnoreCase(string) } for (T candidate : candidates) { @@ -429,7 +428,6 @@ public static T match(final String string, final Iterable candidates) { * @param string The string to match against candidates. * @param candidates The candidates to match the string against. */ - @Nullable public static T match(final String string, final T[] candidates) { return match(string, Arrays.asList(candidates)); } From 380061db639b90538f9c787d9e92ae6d7fcf07ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Fri, 23 Apr 2021 11:45:32 +0200 Subject: [PATCH 30/88] Finish updating eclipse files Kotlin should normally be editable in IDE --- .classpath | 6 + .project | 23 ++ build.gradle | 11 +- org.lflang.ide/.classpath | 290 +----------------- org.lflang.ide/.project | 32 +- .../org.eclipse.wst.common.component | 1 + org.lflang/.classpath | 1 - org.lflang/.project | 13 + .../.settings/org.eclipse.jdt.core.prefs | 1 + .../org/lflang/generator/KtGeneratorBase.kt | 14 +- 10 files changed, 80 insertions(+), 312 deletions(-) create mode 100644 .classpath create mode 100644 .project diff --git a/.classpath b/.classpath new file mode 100644 index 0000000000..4a04201ca2 --- /dev/null +++ b/.classpath @@ -0,0 +1,6 @@ + + + + + + diff --git a/.project b/.project new file mode 100644 index 0000000000..f300cafd5a --- /dev/null +++ b/.project @@ -0,0 +1,23 @@ + + + lingua-franca + Project lingua-franca created by Buildship. + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.buildship.core.gradleprojectbuilder + + + + + + org.eclipse.jdt.core.javanature + org.eclipse.buildship.core.gradleprojectnature + + diff --git a/build.gradle b/build.gradle index 04c923c4d3..cdb1562927 100644 --- a/build.gradle +++ b/build.gradle @@ -37,11 +37,12 @@ subprojects { implementation group: 'com.google.inject', name: 'guice', version: '5.0.0-BETA-1' // https://mvnrepository.com/artifact/commons-cli/commons-cli implementation group: 'commons-cli', name: 'commons-cli', version: '1.4' - // https://mvnrepository.com/artifact/org.jetbrains.kotlin/kotlin-stdlib - implementation group: 'org.jetbrains.kotlin', name: 'kotlin-stdlib', version: "$kotlinVersion" - // https://mvnrepository.com/artifact/org.jetbrains.kotlin/kotlin-stdlib-jdk8 - implementation group: 'org.jetbrains.kotlin', name: 'kotlin-stdlib-jdk8', version: "$kotlinVersion" - } + } + dependencies { + implementation group: 'org.jetbrains.kotlin', name: 'kotlin-stdlib', version: kotlinVersion + implementation group: 'org.jetbrains.kotlin', name: 'kotlin-reflect', version: kotlinVersion + } + apply plugin: 'org.xtext.xtend' apply from: "${rootDir}/gradle/source-layout.gradle" diff --git a/org.lflang.ide/.classpath b/org.lflang.ide/.classpath index 5aedde908f..b86a833339 100644 --- a/org.lflang.ide/.classpath +++ b/org.lflang.ide/.classpath @@ -1,305 +1,25 @@ - + - + - + - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + diff --git a/org.lflang.ide/.project b/org.lflang.ide/.project index 92f51d3431..dd41def898 100644 --- a/org.lflang.ide/.project +++ b/org.lflang.ide/.project @@ -2,35 +2,39 @@ org.lflang.ide - - - org.eclipse.xtext.ui.shared.xtextNature - org.eclipse.jdt.core.javanature - org.eclipse.pde.PluginNature - org.eclipse.buildship.core.gradleprojectnature - + + 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 + diff --git a/org.lflang.web/.settings/org.eclipse.wst.common.component b/org.lflang.web/.settings/org.eclipse.wst.common.component index cdf8a7cee1..e93ed3ca81 100644 --- a/org.lflang.web/.settings/org.eclipse.wst.common.component +++ b/org.lflang.web/.settings/org.eclipse.wst.common.component @@ -4,6 +4,7 @@ + uses diff --git a/org.lflang/.classpath b/org.lflang/.classpath index b37b281235..1aa5319633 100644 --- a/org.lflang/.classpath +++ b/org.lflang/.classpath @@ -20,6 +20,5 @@ - diff --git a/org.lflang/.project b/org.lflang/.project index 947290c99e..3b22ebf011 100644 --- a/org.lflang/.project +++ b/org.lflang/.project @@ -20,6 +20,11 @@ + + org.jetbrains.kotlin.ui.kotlinBuilder + + + org.eclipse.pde.ManifestBuilder @@ -36,5 +41,13 @@ org.eclipse.jdt.core.javanature org.eclipse.pde.PluginNature org.eclipse.buildship.core.gradleprojectnature + org.jetbrains.kotlin.core.kotlinNature + + + kotlin_bin + 2 + 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 519596a625..9d92e3c736 100644 --- a/org.lflang/.settings/org.eclipse.jdt.core.prefs +++ b/org.lflang/.settings/org.eclipse.jdt.core.prefs @@ -1,4 +1,5 @@ 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 diff --git a/org.lflang/src/org/lflang/generator/KtGeneratorBase.kt b/org.lflang/src/org/lflang/generator/KtGeneratorBase.kt index dff347cc19..bdebad1ebb 100644 --- a/org.lflang/src/org/lflang/generator/KtGeneratorBase.kt +++ b/org.lflang/src/org/lflang/generator/KtGeneratorBase.kt @@ -256,16 +256,16 @@ abstract class KtGeneratorBase( fun setTargetConfig(context: IGeneratorContext) { // If there are any physical actions, ensure the threaded engine is used. - for (action in fileConfig.resource.allContents.toIterable.filter(Action)) { + for (action in fileConfig!!.resource.allContents.asSequence().filterIsInstance()) { if (action.origin == ActionOrigin.PHYSICAL) { targetConfig.threads = 1 } } - val target = fileConfig.resource.findTarget + val target = fileConfig!!.resource.findTarget() if (target.config !== null) { // Update the configuration according to the set target properties. - TargetProperty.update(this.targetConfig, target.config.pairs ?: emptyList) + TargetProperty.update(this.targetConfig, target.config.pairs ?: emptyList()) } // Override target properties if specified as command line arguments. @@ -1411,7 +1411,7 @@ You can set PATH in ~/.bash_profile on Linux or Mac.""" * @param source The source file as a path relative to the classpath. * @param destination The file system path that the source file is copied to. */ - protected fun copyFileFromClassPath(source: String, destination: String): Long { + protected fun copyFileFromClassPath(source: String, destination: String) { val sourceStream = this::class.java.getResourceAsStream(source) ?: throw IOException( "A required target resource could not be found: " + source + "\n" + @@ -1456,7 +1456,7 @@ You can set PATH in ~/.bash_profile on Linux or Mac.""" * an Eclipse IDE), then refresh the project. This will ensure that * any generated files become visible in the project. */ - protected fun refreshProject(): String? { + protected fun refreshProject() { if (mode == Mode.INTEGRATED) { // Find name of current project val id = "((:?[a-z]|[A-Z]|_\\w)*)" @@ -1798,7 +1798,7 @@ You can set PATH in ~/.bash_profile on Linux or Mac.""" * information between federates. See the C target * for a reference implementation. */ - private fun analyzeFederates(): FederateInstance? { + private fun analyzeFederates() { // Next, if there actually are federates, analyze the topology // interconnecting them and replace the connections between them // with an action and two reactions. @@ -2020,7 +2020,7 @@ You can set PATH in ~/.bash_profile on Linux or Mac.""" * Print to stdout information about what source file is being generated, * what mode the generator is in, and where the generated sources are to be put. */ - open fun printInfo(): String? { + open fun printInfo() { println("Generating code for: " + fileConfig!!.resource.uri) println("******** mode: $mode") println("******** source file: " + fileConfig!!.srcFile) // FIXME: redundant From c98471ffebe55088f642449dabfa7e59c3b678db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Fri, 23 Apr 2021 12:32:04 +0200 Subject: [PATCH 31/88] Continue porting KtGeneratorBase --- org.lflang.ide/.classpath | 1 + org.lflang.ide/.project | 13 + .../.settings/org.eclipse.jdt.core.prefs | 11 +- org.lflang.tests/.classpath | 1 + org.lflang.tests/.project | 13 + .../.settings/org.eclipse.jdt.core.prefs | 1 + org.lflang.web/.classpath | 1 + org.lflang.web/.project | 13 + .../.settings/org.eclipse.jdt.core.prefs | 1 + org.lflang/.classpath | 1 + org.lflang/.project | 5 - org.lflang/src/org/lflang/Extensions.kt | 111 ++++++++- .../org/lflang/generator/KtGeneratorBase.kt | 222 ++++++++---------- 13 files changed, 253 insertions(+), 141 deletions(-) diff --git a/org.lflang.ide/.classpath b/org.lflang.ide/.classpath index b86a833339..91283994da 100644 --- a/org.lflang.ide/.classpath +++ b/org.lflang.ide/.classpath @@ -21,5 +21,6 @@ + diff --git a/org.lflang.ide/.project b/org.lflang.ide/.project index dd41def898..d0c289aac8 100644 --- a/org.lflang.ide/.project +++ b/org.lflang.ide/.project @@ -5,6 +5,11 @@ + + org.jetbrains.kotlin.ui.kotlinBuilder + + + org.eclipse.jdt.core.javabuilder @@ -36,5 +41,13 @@ org.eclipse.jdt.core.javanature org.eclipse.pde.PluginNature org.eclipse.buildship.core.gradleprojectnature + org.jetbrains.kotlin.core.kotlinNature + + + kotlin_bin + 2 + 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 8f46b80aa0..3056f74d3b 100644 --- a/org.lflang.ide/.settings/org.eclipse.jdt.core.prefs +++ b/org.lflang.ide/.settings/org.eclipse.jdt.core.prefs @@ -1,9 +1,8 @@ -# -#Wed Apr 21 21:15:03 CEST 2021 +eclipse.preferences.version=1 +org.eclipse.jdt.core.builder.resourceCopyExclusionFilter=*.kt org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled -org.eclipse.jdt.core.compiler.problem.assertIdentifier=error org.eclipse.jdt.core.compiler.codegen.targetPlatform=11 -org.eclipse.jdt.core.compiler.source=11 -eclipse.preferences.version=1 -org.eclipse.jdt.core.compiler.problem.enumIdentifier=error 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.source=11 diff --git a/org.lflang.tests/.classpath b/org.lflang.tests/.classpath index 9c7e040c0a..90e203fa3a 100644 --- a/org.lflang.tests/.classpath +++ b/org.lflang.tests/.classpath @@ -23,5 +23,6 @@ + diff --git a/org.lflang.tests/.project b/org.lflang.tests/.project index b17de320d9..76b0dc0dd0 100644 --- a/org.lflang.tests/.project +++ b/org.lflang.tests/.project @@ -5,6 +5,11 @@ + + org.jetbrains.kotlin.ui.kotlinBuilder + + + org.eclipse.jdt.core.javabuilder @@ -36,5 +41,13 @@ org.eclipse.jdt.core.javanature org.eclipse.pde.PluginNature org.eclipse.buildship.core.gradleprojectnature + org.jetbrains.kotlin.core.kotlinNature + + + kotlin_bin + 2 + 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 f4d933e4eb..3056f74d3b 100644 --- a/org.lflang.tests/.settings/org.eclipse.jdt.core.prefs +++ b/org.lflang.tests/.settings/org.eclipse.jdt.core.prefs @@ -1,4 +1,5 @@ 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 diff --git a/org.lflang.web/.classpath b/org.lflang.web/.classpath index 36bc8839a7..4609f05ef3 100644 --- a/org.lflang.web/.classpath +++ b/org.lflang.web/.classpath @@ -25,5 +25,6 @@ + diff --git a/org.lflang.web/.project b/org.lflang.web/.project index 023d4957f4..8d94631494 100644 --- a/org.lflang.web/.project +++ b/org.lflang.web/.project @@ -5,6 +5,11 @@ + + org.jetbrains.kotlin.ui.kotlinBuilder + + + org.eclipse.jdt.core.javabuilder @@ -37,5 +42,13 @@ 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 + 2 + 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 f4d933e4eb..3056f74d3b 100644 --- a/org.lflang.web/.settings/org.eclipse.jdt.core.prefs +++ b/org.lflang.web/.settings/org.eclipse.jdt.core.prefs @@ -1,4 +1,5 @@ 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 diff --git a/org.lflang/.classpath b/org.lflang/.classpath index 1aa5319633..1b604e5af8 100644 --- a/org.lflang/.classpath +++ b/org.lflang/.classpath @@ -20,5 +20,6 @@ + diff --git a/org.lflang/.project b/org.lflang/.project index 31321b422d..3b22ebf011 100644 --- a/org.lflang/.project +++ b/org.lflang/.project @@ -5,11 +5,6 @@ - - org.jetbrains.kotlin.ui.kotlinBuilder - - - org.eclipse.jdt.core.javabuilder diff --git a/org.lflang/src/org/lflang/Extensions.kt b/org.lflang/src/org/lflang/Extensions.kt index 3e82750b5e..a60258bba8 100644 --- a/org.lflang/src/org/lflang/Extensions.kt +++ b/org.lflang/src/org/lflang/Extensions.kt @@ -92,7 +92,7 @@ val Reactor.allStateVars: List get() = superClassRecursor { stateVars val Reactor.allTimers: List get() = superClassRecursor { timers } private fun Reactor.superClassRecursor(collector: Reactor.() -> List): List = - superClasses.orEmpty().mapNotNull { it.toDefinition()?.collector() }.flatten() + this.collector() + superClasses.orEmpty().mapNotNull { it.toDefinition().collector() }.flatten() + this.collector() val Parameter.isOfTimeType: Boolean get() { @@ -139,6 +139,74 @@ fun TypeParm.toText(): String = else code.toText() +/** + * Return a textual representation of this element, + * without quotes if there are any. Leading or trailing + * whitespace is removed. + * + * @receiver The element to be rendered as a string. + */ +fun Element.toText(): String { + if (literal != null) { + return literal.withoutQuotes().trim() + } + if (id != null) { + return id + } + return "" +} + + +fun Delay.toText(): String { + if (parameter !== null) { + return parameter.name + } + return interval.toString() + " " + 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. + * @param this@toText The variable reference. + */ +fun VarRef.toText(): String = + if (container !== null) { + "${container.name}.${variable.name}" + } else { + variable.name + } + +/** + * Convert an array specification to its textual representation as it would + * appear in LF code. + * + * @param this@toText The array spec to be converted + * @return A textual representation + */ +fun ArraySpec.toText(): String = + if (isOfVariableLength) "[]" + else "[$length]" + + +/** + * Translate the given type into its textual representation, including + * any array specifications. + * @param type AST node to render as string. + * @return Textual representation of the given argument. + */ +fun toText(type: Type): String { + return type.baseType + type.arraySpec?.toText().orEmpty() +} + /** * Find connections in the given resource that have a delay associated with them, * and reroute them via a generated delay reactor. @@ -350,11 +418,8 @@ private fun getDelayClass(aType: Type, generator: KtGeneratorBase): Reactor { "${KtGeneratorBase.GEN_DELAY_CLASS_NAME}_$id" } - // Only add class definition if it is not already there. - val classDef = generator.findDelayClass(className) - if (classDef !== null) { - return classDef - } + // If it is there, return it + generator.findDelayClass(className)?.let { return it } val defaultValue = factory.createValue().apply { literal = generator.timeInTargetLanguage(TimeValue(0, TimeUnit.NONE)) @@ -478,3 +543,37 @@ private fun Type.getCopy(): Type { } } + +/** + * Translate the given type into its textual representation, but + * do not append any array specifications. + * @receiver AST node to render as string. + * @return Textual representation of the given argument. + */ +val Type.baseType: String + get() = when { + code != null -> code.toText() + isTime -> "time" + else -> id + stars.orEmpty().joinToString() + } + +/** + * Report whether the given literal is zero or not. + * @receiver AST node to inspect. + * @return True if the given literal denotes the constant `0`, false + * otherwise. + */ +val String.isZero: Boolean get() = this.toIntOrNull() == 0 + +val Code.isZero: Boolean get() = this.toText().isZero + +/** + * Report whether the given value is zero or not. + * @param value AST node to inspect. + * @return True if the given value denotes the constant `0`, false otherwise. + */ +fun isZero(value: Value): Boolean = + value.literal?.isZero + ?: value.code?.isZero + ?: false + diff --git a/org.lflang/src/org/lflang/generator/KtGeneratorBase.kt b/org.lflang/src/org/lflang/generator/KtGeneratorBase.kt index bdebad1ebb..07cf2cdb94 100644 --- a/org.lflang/src/org/lflang/generator/KtGeneratorBase.kt +++ b/org.lflang/src/org/lflang/generator/KtGeneratorBase.kt @@ -263,7 +263,7 @@ abstract class KtGeneratorBase( } val target = fileConfig!!.resource.findTarget() - if (target.config !== null) { + if (target.config != null) { // Update the configuration according to the set target properties. TargetProperty.update(this.targetConfig, target.config.pairs ?: emptyList()) } @@ -336,7 +336,7 @@ abstract class KtGeneratorBase( createMainInstance() // Check if there are any conflicting main reactors elsewhere in the package. - if (mainDef !== null) { + if (mainDef != null) { for (conflict in MainConflictChecker(fileConfig).conflicts) { reportError(this.mainDef!!.reactorClass, "Conflicting main reactor in $conflict") } @@ -524,7 +524,7 @@ abstract class KtGeneratorBase( */ fun generateVarRef(reference: VarRef): String { var prefix = "" - if (reference.container !== null) { + if (reference.container != null) { prefix = reference.container.name + "." } return prefix + reference.variable.name @@ -575,7 +575,7 @@ abstract class KtGeneratorBase( * @return A string, such as "MSEC(100)" for 100 milliseconds. */ open fun timeInTargetLanguage(time: TimeValue?): String = - if (time !== null) { + if (time != null) { if (time.unit != TimeUnit.NONE) { time.unit.name + '(' + time.time + ')' } else { @@ -661,17 +661,15 @@ abstract class KtGeneratorBase( // FIXME: These would have to be top-level parameters, which don't really // have any support yet. Ideally, they could be overridden on the command line. // When that is done, they will need to be in scope here. - val delays = federate.dependsOn.get(upstreamFederate) - if (delays !== null) { - for (delay in delays) { - pr( - rtiCode, """ - if (federates[${federate.id}].upstream_delay[${count}] < ${delay.getRTITime}) { - federates[${federate.id}].upstream_delay[${count}] = ${delay.getRTITime}; - } - """ - ) - } + val delays = federate.dependsOn[upstreamFederate].orEmpty() + for (delay in delays) { + pr( + rtiCode, """ + if (federates[${federate.id}].upstream_delay[${count}] < ${delay.rtiTime}) { + federates[${federate.id}].upstream_delay[${count}] = ${delay.rtiTime}; + } + """ + ) } count++ } @@ -747,7 +745,7 @@ abstract class KtGeneratorBase( val compile = compileCCommand(file, doNotLinkIfNoMain) ?: return false val stderr = ByteArrayOutputStream() - val returnCode = compile.executeCommand(stderr) + val returnCode = compile.executeCommand(errStream = stderr) if (returnCode != 0 && mode !== Mode.INTEGRATED) { reportError("""${targetConfig.compiler} returns error code $returnCode""") @@ -779,7 +777,7 @@ abstract class KtGeneratorBase( for (cmd in commands) { val stderr = ByteArrayOutputStream() - val returnCode = cmd.executeCommand(stderr) + val returnCode = cmd.executeCommand(errStream = stderr) if (returnCode != 0 && mode !== Mode.INTEGRATED) { reportError("""Build command "${targetConfig.buildCommands}" returns error code $returnCode""") @@ -836,7 +834,7 @@ abstract class KtGeneratorBase( // If threaded computation is requested, add a -pthread option. - if (targetConfig.threads != 0 || targetConfig.tracing !== null) { + if (targetConfig.threads != 0 || targetConfig.tracing != null) { compileArgs.add("-pthread") // If the LF program itself is threaded or if tracing is enabled, we need to define // NUMBER_OF_WORKERS so that platform-specific C files will contain the appropriate functions @@ -888,10 +886,10 @@ abstract class KtGeneratorBase( val workspaceRoot = ResourcesPlugin.getWorkspace().root // The following uses a java.net.URI, which, // pathetically, cannot be distinguished in xtend from a org.eclipse.emf.common.util.URI. - if (uri !== null) { + if (uri != null) { // Pathetically, Eclipse requires a java.net.uri, not a org.eclipse.emf.common.util.URI. val files = workspaceRoot.findFilesForLocationURI(uri) - if (files !== null && files.isNotEmpty() && files[0] !== null) { + if (files != null && files.isNotEmpty() && files[0] != null) { resource = files[0] } } @@ -923,14 +921,14 @@ abstract class KtGeneratorBase( /** * Run a given command and record its output. * - * @param cmd the command to be executed + * @receiver the command to be executed * @param errStream a stream object to forward the commands error messages to * @param outStream a stream object to forward the commands output messages to * @return the commands return code */ - protected fun executeCommand(cmd: ProcessBuilder, errStream: OutputStream? = null, outStream: OutputStream? = null): Int { + protected fun ProcessBuilder.executeCommand(errStream: OutputStream? = null, outStream: OutputStream? = null): Int { println("--- Current working directory: \${cmd.directory.toString()}") - println("--- Executing command: ${cmd.command().joinToString(" ")}") + println("--- Executing command: ${command().joinToString(" ")}") val outStreams = mutableListOf() val errStreams = mutableListOf() @@ -945,7 +943,7 @@ abstract class KtGeneratorBase( // Execute the command. Write output to the System output, // but also keep copies in outStream and errStream - return cmd.runSubprocess(outStreams, errStreams) + return runSubprocess(outStreams, errStreams) } @@ -989,7 +987,7 @@ abstract class KtGeneratorBase( val bashCommand = listOf("bash", "--login", "-c", "which $cmd") val bashBuilder = ProcessBuilder(bashCommand) val bashOut = ByteArrayOutputStream() - val bashReturn = bashBuilder.runSubprocess(#[bashOut], #[]) + val bashReturn = bashBuilder.runSubprocess(listOf(bashOut), listOf()) if (bashReturn == 0) { println("SUCCESS") return ExecutionEnvironment.BASH @@ -1083,18 +1081,6 @@ You can set PATH in ~/.bash_profile on Linux or Mac.""" return this.createCommand(cmd, args, dir, env) } - /** - * Return the target. - */ - fun findTarget(resource: Resource): TargetDecl? { - val targets = resource.allContents.asSequence().filterIsInstance().toList() - when { - targets.isEmpty() -> throw RuntimeException("No target found!") - targets.size > 1 -> throw RuntimeException("There is more than one target!") // FIXME: check this in validator - else -> return targets[0] - } - } - /** * Generate code for the body of a reaction that handles input from the network * that is handled by the specified action. This base class throws an exception. @@ -1181,19 +1167,12 @@ You can set PATH in ~/.bash_profile on Linux or Mac.""" } } - /** - * Get the code produced so far. - * @return The code produced so far as a String. - */ + /** Returns the code produced so far. */ protected fun getCode(): String = code.toString() /** * Increase the indentation of the output code produced * on the specified builder. - * @param The builder to indent. - */ - /** - * Increase the indentation of the output code produced. */ protected fun indent(builder: StringBuilder = this.code): String = (indentation.getOrDefault(builder, "") + " ").also { @@ -1392,7 +1371,7 @@ You can set PATH in ~/.bash_profile on Linux or Mac.""" // statements to find which one matches and mark all the // import statements down the chain. But what a pain! report( - "Error in imported file: " + resource.fullPath, + "Error in imported file: " + resource!!.fullPath, IMarker.SEVERITY_ERROR, null, originalResource @@ -1469,15 +1448,13 @@ You can set PATH in ~/.bash_profile on Linux or Mac.""" ) } val matcher = pattern.matcher(code) - var projName = "" - if (matcher.find()) { - projName = matcher.group(1) - } + val projName = if (matcher.find()) matcher.group(1) else "" + try { - val members = ResourcesPlugin.getWorkspace().root.members + val members = ResourcesPlugin.getWorkspace().root.members() for (member in members) { // Refresh current project, or simply entire workspace if project name was not found - if (projName == "" || projName.equals(member.fullPath.toString().substring(1))) { + if (projName.isEmpty() || projName == member.fullPath.toString().substring(1)) { member.refreshLocal(IResource.DEPTH_INFINITE, null) println("Refreshed " + member.fullPath) } @@ -1510,7 +1487,7 @@ You can set PATH in ~/.bash_profile on Linux or Mac.""" val fullPath: String = let { var p = resource?.fullPath?.toString() if (p == null) { - if (`object` != null && `object`.eResource() !== null) + if (`object` != null && `object`.eResource() != null) p = FileConfig.toPath(`object`.eResource()).toString() if (p == null) { p = if (line == null) "" else "path unknown" @@ -1529,7 +1506,7 @@ You can set PATH in ~/.bash_profile on Linux or Mac.""" if (myResource === null && `object` != null) { // Attempt to identify the IResource from the object. val eResource = `object`.eResource() - if (eResource !== null) { + if (eResource != null) { val uri = FileConfig.toPath(eResource).toUri() myResource = getEclipseResource(uri) } @@ -1539,10 +1516,10 @@ You can set PATH in ~/.bash_profile on Linux or Mac.""" if (myResource === null) { myResource = iResource } - if (myResource !== null) { + if (myResource != null) { val marker = myResource.createMarker(IMarker.PROBLEM) marker.setAttribute(IMarker.MESSAGE, message) - if (line !== null) { + if (line != null) { marker.setAttribute(IMarker.LINE_NUMBER, line) } else { marker.setAttribute(IMarker.LINE_NUMBER, 1) @@ -1685,7 +1662,7 @@ You can set PATH in ~/.bash_profile on Linux or Mac.""" val ofTimeType = param.isOfTimeType - val assignments = i.parameters.filter { p.lhs === param } + val assignments = i.parameters.filter { it.lhs === param } return if (assignments.isEmpty()) { // the parameter was not overwritten in the instantiation @@ -1725,7 +1702,7 @@ You can set PATH in ~/.bash_profile on Linux or Mac.""" if (widthSpec.isOfVariableLength) return emptyList() return widthSpec.terms.map { term -> val param = term.parameter - if (param !== null) getTargetReference(param) + if (param != null) getTargetReference(param) else term.width.toString() } } @@ -1757,22 +1734,23 @@ You can set PATH in ~/.bash_profile on Linux or Mac.""" * code for targets that override timeInTargetLanguage * to return a C-incompatible time type. * - * @param d A time AST node + * @param this@getRTITime A time AST node * @return An RTI-compatible (ie. C target) time string */ - protected fun getRTITime(d: Delay): String { - if (d.parameter !== null) { - return d.toText - } + protected val Delay.rtiTime: String + get() { + if (parameter != null) { + return this.toText() + } - val time = TimeValue(d.interval.toLong(), d.unit) + val time = TimeValue(interval.toLong(), unit) - return if (time.unit != TimeUnit.NONE) { - time.unit.name + '(' + time.time + ')' - } else { - time.time.toString() + return if (time.unit != TimeUnit.NONE) { + time.unit.name + '(' + time.time + ')' + } else { + time.time.toString() + } } - } /** * Analyze the resource (the .lf file) that is being parsed @@ -1802,9 +1780,9 @@ You can set PATH in ~/.bash_profile on Linux or Mac.""" // Next, if there actually are federates, analyze the topology // interconnecting them and replace the connections between them // with an action and two reactions. - val mainDefn = this.mainDef?.reactorClass.toDefinition() + val mainDefn = this.mainDef?.reactorClass?.toDefinition() - if (this.mainDef === null || !mainDefn.isFederated) { + if (mainDefn?.isFederated != true) { // Ensure federates is never empty. val federateInstance = FederateInstance(null, 0, 0, this) federates.add(federateInstance) @@ -1812,7 +1790,7 @@ You can set PATH in ~/.bash_profile on Linux or Mac.""" } else { // The Lingua Franca program is federated isFederated = true - if (mainDefn?.host != null) { + if (mainDefn.host != null) { // Get the host information, if specified. // If not specified, this defaults to 'localhost' if (mainDefn.host.addr != null) { @@ -1824,12 +1802,12 @@ You can set PATH in ~/.bash_profile on Linux or Mac.""" federationRTIProperties["port"] = mainDefn.host.port } // Get the user information, if specified. - if (mainDefn.host.user !== null) { + if (mainDefn.host.user != null) { federationRTIProperties["user"] = mainDefn.host.user } // Get the directory information, if specified. /* FIXME - * if (mainDef.reactorClass.host.dir !== null) { + * if (mainDef.reactorClass.host.dir != null) { * federationRTIProperties.put('dir', mainDef.reactorClass.host.dir) * } */ @@ -1854,7 +1832,7 @@ You can set PATH in ~/.bash_profile on Linux or Mac.""" federateInstances.add(federateInstance) federateByID[federateID] = federateInstance - if (instantiation.host !== null) { + if (instantiation.host != null) { federateInstance.host = instantiation.host.addr // The following could be 0. federateInstance.port = instantiation.host.port @@ -1899,7 +1877,7 @@ You can set PATH in ~/.bash_profile on Linux or Mac.""" val leftPortWidth = ASTUtils.width((leftPort.variable as Port).widthSpec) for (leftBankIndex in 0..ASTUtils.width(leftPort.container.widthSpec)) { var leftChannelIndex = 0 - while (rightPort !== null) { + while (rightPort != null) { val minWidth = if (leftPortWidth - leftChannelIndex < rightPortWidth - rightChannelIndex) leftPortWidth - leftChannelIndex @@ -1921,26 +1899,18 @@ You can set PATH in ~/.bash_profile on Linux or Mac.""" && !connection.isPhysical && targetConfig.coordination !== TargetProperty.CoordinationType.DECENTRALIZED ) { - var dependsOn = rightFederate.dependsOn[leftFederate] - if (dependsOn === null) { - dependsOn = LinkedHashSet() - rightFederate.dependsOn[leftFederate] = dependsOn - } - if (connection.delay !== null) { + val dependsOn = rightFederate.dependsOn.computeIfAbsent(leftFederate) { mutableSetOf() } + if (connection.delay != null) { dependsOn.add(connection.delay) } - var sendsTo = leftFederate.sendsTo[rightFederate] - if (sendsTo === null) { - sendsTo = LinkedHashSet() - leftFederate.sendsTo[rightFederate] = sendsTo - } - if (connection.delay !== null) { + val sendsTo = leftFederate.dependsOn.computeIfAbsent(rightFederate) { mutableSetOf() } + if (connection.delay != null) { sendsTo.add(connection.delay) } // Check for causality loops between federates. // FIXME: This does not detect cycles involving more than one federate. val reverseDependency = leftFederate.dependsOn[rightFederate] - if (reverseDependency !== null) { + if (reverseDependency != null) { // Check that at least one direction has a delay. if (reverseDependency.size == 0 && dependsOn.size == 0) { // Found a causality loop. @@ -1957,7 +1927,8 @@ You can set PATH in ~/.bash_profile on Linux or Mac.""" connection, leftFederate, leftBankIndex, leftChannelIndex, rightFederate, rightBankIndex, rightChannelIndex, - this, targetConfig.coordination + this, + targetConfig.coordination ) leftChannelIndex++ @@ -1970,7 +1941,7 @@ You can set PATH in ~/.bash_profile on Linux or Mac.""" rightBankIndex++ rightChannelIndex = 0 } - rightIndex >= connection.rightPorts.size() -> { + rightIndex >= connection.rightPorts.size -> { // We are done. rightPort = null rightBankIndex = 0 @@ -2004,16 +1975,15 @@ You can set PATH in ~/.bash_profile on Linux or Mac.""" * Integrated mode means that it is running within an Eclipse IDE. * Standalone mode means that it is running on the command line. */ - private fun setMode(): Mode? { + private fun setMode() { val resource = fileConfig?.resource mode = when { resource?.uri?.isPlatform == true -> Mode.INTEGRATED resource?.uri?.isFile == true -> Mode.STANDALONE else -> Mode.UNDEFINED.also { - System.err.println("ERROR: Source file protocol is not recognized: " + resource.uri) + System.err.println("ERROR: Source file protocol is not recognized: " + resource!!.uri) } } - return mode } /** @@ -2035,37 +2005,33 @@ You can set PATH in ~/.bash_profile on Linux or Mac.""" * buffers are full. This method ensures that output and error messages * are continuously read and forwards them to the given streams. * - * @param processBuilder The process to be executed. - * @param outStream The stream to forward the process' output to. - * @param errStream The stream to forward the process' error messages to. + * @param this@runSubprocess The process to be executed. + * @param outStreams The stream to forward the process' output to. + * @param errStreams The stream to forward the process' error messages to. * @author{Christian Menard @tu-dresden.de} */ - private fun runSubprocess(processBuilder: ProcessBuilder, outStream: List, errStream: List): Int { - val process = processBuilder.start() + private fun ProcessBuilder.runSubprocess(outStreams: List, + errStreams: List): Int { - val outThread = Thread { - val buffer = ByteArray(64) - var len = process.inputStream.read(buffer) - while (len != -1) { - for (os in outStream) { - os.write(buffer, 0, len) - } - len = process.inputStream.read(buffer) - } - } - outThread.start() - - val errThread = Thread { - val buffer = ByteArray(64) - var len = process.errorStream.read(buffer) - while (len != -1) { - for (es in errStream) { - es.write(buffer, 0, len) + fun startThread(inputStream: InputStream, outputs:List) = + Thread { + val buffer = ByteArray(64) + var len = inputStream.read(buffer) + while (len != -1) { + for (os in outputs) { + os.write(buffer, 0, len) + } + len = inputStream.read(buffer) } - len = process.errorStream.read(buffer) + }.also { + it.start() } - } - errThread.start() + + + val process = start() + + val outThread = startThread(process.inputStream, outStreams) + val errThread = startThread(process.errorStream, errStreams) val returnCode = process.waitFor() outThread.join() @@ -2153,9 +2119,17 @@ You can set PATH in ~/.bash_profile on Linux or Mac.""" } companion object { - /** - * Constant that specifies how to name generated delay reactors. - */ - val GEN_DELAY_CLASS_NAME = "__GenDelay" + /** Constant that specifies how to name generated delay reactors. */ + const val GEN_DELAY_CLASS_NAME = "__GenDelay" + + /** Return the target. Throws if there is not exactly one. */ + fun Resource.findTarget(): TargetDecl { + val targets = allContents.asSequence().filterIsInstance().toList() + when { + targets.isEmpty() -> throw RuntimeException("No target found!") + targets.size > 1 -> throw RuntimeException("There is more than one target!") // FIXME: check this in validator + else -> return targets[0] + } + } } } From d835e011f3a8a32fa0e0c6cc8fca9922f1b9c82c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Fri, 23 Apr 2021 13:17:13 +0200 Subject: [PATCH 32/88] Some more progress Nearly all of ASTUtils has been converted now. The remaining compilation errors are caused by federation-related code, which expects a GeneratorBase and not a KtGeneratorBase --- org.lflang/src/org/lflang/Extensions.kt | 433 +++++++++++++++++- .../org/lflang/generator/KtGeneratorBase.kt | 30 +- 2 files changed, 439 insertions(+), 24 deletions(-) diff --git a/org.lflang/src/org/lflang/Extensions.kt b/org.lflang/src/org/lflang/Extensions.kt index a60258bba8..d6edbfd40e 100644 --- a/org.lflang/src/org/lflang/Extensions.kt +++ b/org.lflang/src/org/lflang/Extensions.kt @@ -29,6 +29,7 @@ import org.eclipse.xtext.nodemodel.util.NodeModelUtils import org.lflang.ASTUtils.factory import org.lflang.generator.KtGeneratorBase import org.lflang.lf.* +import java.lang.NumberFormatException fun ReactorDecl.toDefinition(): Reactor = when (this) { @@ -176,20 +177,41 @@ fun String.withoutQuotes(): String { /** * Return a string of the form either "name" or "container.name" depending * on in which form the variable reference was given. - * @param this@toText The variable reference. + * @receiver The variable reference. */ fun VarRef.toText(): String = - if (container !== null) { - "${container.name}.${variable.name}" - } else { - variable.name - } + if (container !== null) "${container.name}.${variable.name}" + else variable.name + + +/** + * Convert a value to its textual representation as it would + * appear in LF code. + * + * @receiver The value to be converted + * @return A textual representation + */ +fun Value.toText(): String = + parameter?.name + ?: time?.toText() + ?: literal + ?: code?.toText() + ?: "" + + +/** + * Convert a time to its textual representation as it would + * appear in LF code. + * @receiver The time to be converted + */ +fun Time.toText(): String = "$interval $unit" + /** * Convert an array specification to its textual representation as it would * appear in LF code. * - * @param this@toText The array spec to be converted + * @receiver The array spec to be converted * @return A textual representation */ fun ArraySpec.toText(): String = @@ -200,11 +222,11 @@ fun ArraySpec.toText(): String = /** * Translate the given type into its textual representation, including * any array specifications. - * @param type AST node to render as string. + * @receiver AST node to render as string. * @return Textual representation of the given argument. */ -fun toText(type: Type): String { - return type.baseType + type.arraySpec?.toText().orEmpty() +fun Type.toText(): String { + return baseType + arraySpec?.toText().orEmpty() } /** @@ -577,3 +599,394 @@ fun isZero(value: Value): Boolean = ?: value.code?.isZero ?: false + +/** + * Given the width specification of port or instantiation + * and an (optional) list of nested intantiations, return + * the width if it can be determined and -1 if not. + * It will not be able to be determined if either the + * width is variable (in which case you should use + * {@link inferPortWidth(VarRef, Connection, List}) + * or the list of instantiations is incomplete or missing. + * If there are parameter references in the width, they are + * evaluated to the extent possible given the instantiations list. + * + * The instantiations list is as in + * {@link initialValue(Parameter, List}. + * If the spec belongs to an instantiation (for a bank of reactors), + * then the first element on this list should be the instantiation + * that contains this instantiation. If the spec belongs to a port, + * then the first element on the list should be the instantiation + * of the reactor that contains the port. + * + * @param spec The width specification or null (to return 1). + * @param instantiations The (optional) list of instantiations. + * + * @return The width, or null if the width could not be determined. + * + * @throws IllegalArgumentException If an instantiation provided is not as + * given above or if the chain of instantiations is not nested. + */ +fun width(spec: WidthSpec, instantiations: List = emptyList()): Int? { + if (spec.isOfVariableLength && spec.eContainer() is Instantiation) { + // We may be able to infer the width by examining the connections of + // the enclosing reactor definition. This works, for example, with + // delays between multiports or banks of reactors. + // Attempt to infer the width. + for (c in (spec.eContainer().eContainer() as Reactor).connections) { + var leftWidth = 0 + var rightWidth = 0 + var isOnLeft: Boolean? = null + for (leftPort in c.leftPorts) { + if (leftPort.container === spec.eContainer()) { + if (isOnLeft != null) { + throw Exception("Multiple ports with variable width on a connection.") + } + isOnLeft = true + } else { + leftWidth += inferPortWidth(leftPort, c) ?: return null + } + } + for (rightPort in c.rightPorts) { + if (rightPort.container === spec.eContainer()) { + if (isOnLeft != null) { + throw Exception("Multiple ports with variable width on a connection.") + } + isOnLeft = false + } else { + rightWidth += inferPortWidth(rightPort, c) ?: return null + } + } + + if (isOnLeft != null) { + return if (isOnLeft) rightWidth - leftWidth else leftWidth - rightWidth + } + } + // A connection was not found with the instantiation. + return null + } + var result = 0 + for (term in spec.terms) { + if (term.parameter !== null) { + val termWidth = initialValueInt(term.parameter, instantiations) + if (termWidth !== null) { + result += termWidth + } else { + return -1 + } + } else { + result += term.width + } + } + return result +} + +/** + * Infer the width of a port reference in a connection. + * The port reference one or two parts, a port and an (optional) container + * which is an Instantiation that may refer to a bank of reactors. + * The width will be the product of the bank width and the port width. + * The returned value will be 1 if the port is not in a bank and is not a multiport. + * + * If the width cannot be determined, this will return -1. + * The width cannot be determined if the list of instantiations is + * missing or incomplete. + * + * The instantiations list is as in + * {@link initialValue(Parameter, List}. + * The first element on this list should be the instantiation + * that contains the specified connection. + * + * @param reference A port reference. + * @param connection A connection, or null if not in the context of a connection. + * @param instantiations The (optional) list of instantiations. + * + * @return The width or null if it could not be determined. + * + * @throws IllegalArgumentException If an instantiation provided is not as + * given above or if the chain of instantiations is not nested. + */ +fun inferPortWidth(reference: VarRef, connection: Connection?, instantiations: List = emptyList()): Int? { + if (reference.variable is Port) { + // If the port is given as a.b, then we want to prepend a to + // the list of instantiations to determine the width of this port. + var extended = instantiations + if (reference.container !== null) { + extended = mutableListOf() + extended.add(reference.container) + extended.addAll(instantiations) + } + + val portWidth = width((reference.variable as Port).widthSpec, extended) ?: return null + + // Next determine the bank width. This may be unspecified, in which + // case it has to be inferred using the connection. + val bankWidth: Int = + if (reference.container == null || instantiations == null) { + 1 + } else { + // Could not determine the bank width.// This is an error.// This port is on the right. + // Check that portWidth divides the discrepancy. + // This port is on the left.// Indicate that this port is on the right.// The left port is not the same as this reference.// Indicate that this port is on the left.// This occurs for a bank of delays.// width returned null + // Try to infer the bank width from the connection. + width(reference.container.widthSpec, instantiations) + ?: if (connection == null) return null + else { // width returned null, no connection + + // Try to infer the bank width from the connection. + if (reference.container.widthSpec.isOfVariableLength) { + // This occurs for a bank of delays. + var leftWidth = 0 + var rightWidth = 0 + var leftOrRight = 0 + for (leftPort in connection.leftPorts) { + if (leftPort === reference) { + if (leftOrRight != 0) { + throw Exception("Multiple ports with variable width on a connection.") + } + // Indicate that this port is on the left. + leftOrRight = -1 + } else { + // The left port is not the same as this reference. + val otherWidth = inferPortWidth(leftPort, connection, instantiations) ?: return null + leftWidth += otherWidth + } + } + for (rightPort in connection.rightPorts) { + if (rightPort === reference) { + if (leftOrRight != 0) { + throw Exception("Multiple ports with variable width on a connection.") + } + // Indicate that this port is on the right. + leftOrRight = 1 + } else { + val otherWidth = inferPortWidth(rightPort, connection, instantiations) ?: return null + rightWidth += otherWidth + } + } + var discrepancy = 0 + if (leftOrRight < 0) { + // This port is on the left. + discrepancy = rightWidth - leftWidth + } else if (leftOrRight > 0) { + // This port is on the right. + discrepancy = leftWidth - rightWidth + } + // Check that portWidth divides the discrepancy. + if (discrepancy % portWidth != 0) { + return null // This is an error. + } + discrepancy / portWidth + } else { + return null // Could not determine the bank width. + } + } + } + return portWidth * bankWidth + } + // Argument is not a port. + return null +} + +/** + * Return the width of the port reference if it can be determined + * and otherwise return -1. The width can be determined if the + * port is not a multiport in a bank of reactors (the width will 1) + * or if the width of the multiport and/or the bank is given by a + * literal constant. + * + * IMPORTANT: This method should not be used you really need to + * determine the width! It will not evaluate parameter values. + * @see width(WidthSpec, List instantiations) + * @see inferPortWidth(VarRef, Connection, List) + * + * @param reference A reference to a port. + * @return The width of a port or null if it cannot be determined. + * @deprecated + */ +fun multiportWidthIfLiteral(reference: VarRef): Int? = inferPortWidth(reference, null, instantiations = emptyList()) + +/** + * Given the specification of the width of either a bank of reactors + * or a multiport, return the width if it can be determined and otherwise + * return -1. The width can be determined if it is given by one or more + * literal constants or if the widthSpec is null (it is not a multiport + * or reactor bank). + * + * IMPORTANT: This method should not be used you really need to + * determine the width! It will not evaluate parameter values. + * + * @receiver The width specification. + * + * @return The width or null if it cannot be determined. + * @deprecated + */ +val WidthSpec.width: Int? + get() = width(this) + +inline fun WidthSpec.width(default: T): T = width(this) as? T ?: default + + +/** + * Given an instantiation of a reactor or bank of reactors, return + * the width. This will be 1 if this is not a reactor bank. Otherwise, + * this will attempt to determine the width. If the width is declared + * as a literal constant, it will return that constant. If the width + * is specified as a reference to a parameter, this will throw an + * exception. If the width is variable, this will find + * connections in the enclosing reactor and attempt to infer the + * width. If the width cannot be determined, it will throw an exception. + * + * IMPORTANT: This method should not be used you really need to + * determine the width! It will not evaluate parameter values. + * @see width(WidthSpec, List instantiations) + * + * @receiver A reactor instantiation. + * + * @return The width, if it can be determined. + * @throws RuntimeException If the width cannot be determined + */ +fun Instantiation.widthSpecification(): Int = + width(widthSpec) ?: throw Exception("Cannot determine width for the instance $name") + + +/** + * Given a parameter, return its initial value. + * The initial value is a list of instances of Value, where each + * Value is either an instance of Time, Literal, or Code. + * + * If the instantiations argument is null or an empty list, then the + * value returned is simply the default value given when the parameter + * is defined. + * + * If a list of instantiations is given, then the first instantiation + * is required to be an instantiation of the reactor class that is + * parameterized by the parameter. I.e., + * ``` + * parameter.eContainer == instantiations.get(0).reactorClass + * ``` + * If a second instantiation is given, then it is required to be an instantiation of a + * reactor class that contains the first instantiation. That is, + * ``` + * instantiations.get(0).eContainer == instantiations.get(1).reactorClass + * ``` + * More generally, for all 0 <= i < instantiations.size - 1, + * ``` + * instantiations.get(i).eContainer == instantiations.get(i + 1).reactorClass + * ``` + * If any of these conditions is not satisfied, then an IllegalArgumentException + * will be thrown. + * + * Note that this chain of reactions cannot be inferred from the parameter because + * in each of the predicates above, there may be more than one instantiation that + * can appear on the right hand side of the predicate. + * + * For example, consider the following program: + * ``` + * reactor A(x:int(1)) {} + * reactor B(y:int(2)) { + * a1 = new A(x = y); + * a2 = new A(x = -1); + * } + * reactor C(z:int(3)) { + * b1 = new B(y = z); + * b2 = new B(y = -2); + * } + * ``` + * Notice that there are a total of four instances of reactor class A. + * Then + * ``` + * initialValue(x, null) returns 1 + * initialValue(x, [a1]) returns 2 + * initialValue(x, [a2]) returns -1 + * initialValue(x, [a1, b1]) returns 3 + * initialValue(x, [a2, b1]) returns -1 + * initialValue(x, [a1, b2]) returns -2 + * initialValue(x, [a2, b2]) returns -1 + * ``` + * (Actually, in each of the above cases, the returned value is a list with + * one entry, a Literal, e.g. ["1"]). + * + * There are two instances of reactor class B. + * ``` + * initialValue(y, null) returns 2 + * initialValue(y, [a1]) throws an IllegalArgumentException + * initialValue(y, [b1]) returns 3 + * initialValue(y, [b2]) returns -2 + * ``` + * + * @param parameter The parameter. + * @param instantiations The (optional) instantiations. + * + * @return The value of the parameter. + * + * @throws IllegalArgumentException If an instantiation provided is not an + * instantiation of the reactor class that is parameterized by the + * respective parameter or if the chain of instantiations is not nested. + */ +fun initialValue(parameter: Parameter, instantiations: List = emptyList()): List { + // If instantiations are given, then check to see whether this parameter gets overridden in + // the first of those instantiations. + if (instantiations.isNotEmpty()) { + // Check to be sure that the instantiation is in fact an instantiation + // of the reactor class for which this is a parameter. + val instantiation = instantiations[0] + if (parameter.eContainer() !== instantiation.reactorClass) { + throw IllegalArgumentException("Parameter ${parameter.name} is not a parameter of reactor instance ${instantiation.name}.") + } + // In case there is more than one assignment to this parameter, we need to + // find the last one. + val lastAssignment = instantiation.parameters.lastOrNull { it.lhs === parameter } + if (lastAssignment != null) { + // Right hand side can be a list. Collect the entries. + val result = mutableListOf() + for (value in lastAssignment.rhs) { + if (value.parameter !== null) { + if (instantiations.size > 1 + && instantiation.eContainer() !== instantiations[1].reactorClass + ) { + throw IllegalArgumentException("Reactor instance ${instantiation.name} is not contained by instance ${instantiations[1].name}.") + } + val elements = initialValue(value.parameter, instantiations.subList(1, instantiations.size)) + result.addAll(elements) + } else { + result.add(value) + } + } + return result + } + } + // If we reach here, then either no instantiation was supplied or + // there was no assignment in the instantiation. So just use the + // parameter's initial value. + return parameter.init +} + +/** + * Given a parameter return its integer value or null + * if it does not have an integer value. + * If the value of the parameter is a list of integers, + * return the sum of value in the list. + * The instantiations parameter is as in + * {@link initialValue(Parameter, List}. + * + * @param parameter The parameter. + * @param instantiations The (optional) list of instantiations. + * + * @return The integer value of the parameter, or null if does not have an integer value. + * + * @throws IllegalArgumentException If an instantiation provided is not an + * instantiation of the reactor class that is parameterized by the + * respective parameter or if the chain of instantiations is not nested. + */ +fun initialValueInt(parameter: Parameter, instantiations: List = emptyList()): Int? = + initialValue(parameter, instantiations) + .sumBy { it.literal.toIntOrNullAnyRadix() ?: return null } + + +fun String.toIntOrNullAnyRadix(): Int? = + try { + Integer.decode(this) + } catch (e: NumberFormatException) { + null + } diff --git a/org.lflang/src/org/lflang/generator/KtGeneratorBase.kt b/org.lflang/src/org/lflang/generator/KtGeneratorBase.kt index 07cf2cdb94..d30a4f9519 100644 --- a/org.lflang/src/org/lflang/generator/KtGeneratorBase.kt +++ b/org.lflang/src/org/lflang/generator/KtGeneratorBase.kt @@ -16,6 +16,7 @@ import org.eclipse.xtext.validation.CheckMode import org.eclipse.xtext.xbase.lib.* import org.lflang.* import org.lflang.Target +import org.lflang.federated.FedASTUtils import org.lflang.graph.InstantiationGraph import org.lflang.lf.* import org.lflang.validation.AbstractLFValidator @@ -1349,7 +1350,7 @@ You can set PATH in ~/.bash_profile on Linux or Mac.""" // Determine the resource within which the error occurred. // Sadly, Eclipse defines an interface called "URI" that conflicts with the // Java one, so we have to give the full class name here. - resource = this.getEclipseResource(URI(parsed.filepath)) + resource = this.getEclipseResource(URI(parsed.filepath!!)) } else { // No line designator. if (message.isNotEmpty()) { @@ -1815,11 +1816,10 @@ You can set PATH in ~/.bash_profile on Linux or Mac.""" // Create a FederateInstance for each top-level reactor. for (instantiation in mainDefn.allInstantiations) { - var bankWidth = ASTUtils.width(instantiation.widthSpec) - if (bankWidth < 0) { + val bankWidth = instantiation.widthSpec.width ?: run { reportError(instantiation, "Cannot determine bank width!") // Continue with a bank width of 1. - bankWidth = 1 + 1 } // Create one federate instance for each reactor instance in the bank of reactors. val federateInstances = LinkedList() @@ -1872,10 +1872,10 @@ You can set PATH in ~/.bash_profile on Linux or Mac.""" var rightPort = connection.rightPorts[rightIndex++] var rightBankIndex = 0 var rightChannelIndex = 0 - var rightPortWidth = ASTUtils.width((rightPort.variable as Port).widthSpec) + var rightPortWidth = (rightPort.variable as Port).widthSpec.width(default = 1) for (leftPort in connection.leftPorts) { - val leftPortWidth = ASTUtils.width((leftPort.variable as Port).widthSpec) - for (leftBankIndex in 0..ASTUtils.width(leftPort.container.widthSpec)) { + val leftPortWidth = (leftPort.variable as Port).widthSpec.width(default = 1) + for (leftBankIndex in 0..leftPort.container.widthSpec.width(default = 1)) { var leftChannelIndex = 0 while (rightPort != null) { val minWidth = @@ -1923,7 +1923,7 @@ You can set PATH in ~/.bash_profile on Linux or Mac.""" } } - ASTUtils.makeCommunication( + FedASTUtils.makeCommunication( connection, leftFederate, leftBankIndex, leftChannelIndex, rightFederate, rightBankIndex, rightChannelIndex, @@ -1937,21 +1937,21 @@ You can set PATH in ~/.bash_profile on Linux or Mac.""" // Ran out of channels on the right. // First, check whether there is another bank reactor. when { - rightBankIndex < ASTUtils.width(rightPort.container.widthSpec) - 1 -> { + rightBankIndex < rightPort.container.widthSpec.width(default = 1) - 1 -> { rightBankIndex++ rightChannelIndex = 0 } - rightIndex >= connection.rightPorts.size -> { + rightIndex >= connection.rightPorts.size -> { // We are done. rightPort = null rightBankIndex = 0 rightChannelIndex = 0 } - else -> { + else -> { rightBankIndex = 0 rightPort = connection.rightPorts[rightIndex++] rightChannelIndex = 0 - rightPortWidth = ASTUtils.width((rightPort.variable as Port).widthSpec) + rightPortWidth = (rightPort.variable as Port).widthSpec.width(default = 1) } } } @@ -2084,9 +2084,11 @@ You can set PATH in ~/.bash_profile on Linux or Mac.""" * @return A time string in the target language */ protected fun getTargetValue(v: Value): String = - if ((v.time != null)) { + if (v.time != null) { this.getTargetTime(v.time) - } else ASTUtils.toText(v) + } else { + v.toText() + } /** * Get textual representation of a value in the target language. From eae35229b0d2f975129336e30e946e2f7fd672dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Fri, 23 Apr 2021 13:53:38 +0200 Subject: [PATCH 33/88] Introduce supertype to both generators This is to make the federated code compile The entire project builds now --- org.lflang/src/org/lflang/TargetProperty.java | 2 +- .../src/org/lflang/federated/FedASTUtils.java | 9 +- .../federated/FederatedGenerationHelper.java | 123 +++++++++++++++++ .../src/org/lflang/generator/CGenerator.xtend | 1 - .../src/org/lflang/generator/CppGenerator2.kt | 5 +- .../lflang/generator/FederateInstance.xtend | 6 +- .../org/lflang/generator/GeneratorApi.java | 41 ++++++ .../org/lflang/generator/GeneratorBase.xtend | 112 ++------------- .../lflang/generator/KotlinGeneratorBase.kt | 73 ---------- .../org/lflang/generator/KtGeneratorBase.kt | 130 ++++++++---------- .../org/lflang/validation/LFValidator.java | 5 +- .../lflang/validation/LFValidatorImpl.xtend | 8 +- 12 files changed, 251 insertions(+), 264 deletions(-) create mode 100644 org.lflang/src/org/lflang/federated/FederatedGenerationHelper.java create mode 100644 org.lflang/src/org/lflang/generator/GeneratorApi.java delete mode 100644 org.lflang/src/org/lflang/generator/KotlinGeneratorBase.kt diff --git a/org.lflang/src/org/lflang/TargetProperty.java b/org.lflang/src/org/lflang/TargetProperty.java index 6aec72b4db..ef505463ef 100644 --- a/org.lflang/src/org/lflang/TargetProperty.java +++ b/org.lflang/src/org/lflang/TargetProperty.java @@ -759,7 +759,7 @@ public interface TargetPropertyType { */ public static void produceError(String name, String description, LFValidator v) { - v.targetPropertyErrors.add("Target property '" + name + v.getTargetPropertyErrors().add("Target property '" + name + "' is required to be " + description + "."); } } diff --git a/org.lflang/src/org/lflang/federated/FedASTUtils.java b/org.lflang/src/org/lflang/federated/FedASTUtils.java index c8286a2d2e..ce5ba7a176 100644 --- a/org.lflang/src/org/lflang/federated/FedASTUtils.java +++ b/org.lflang/src/org/lflang/federated/FedASTUtils.java @@ -37,6 +37,7 @@ import org.lflang.TargetProperty.CoordinationType; import org.lflang.TimeValue; import org.lflang.generator.FederateInstance; +import org.lflang.generator.GeneratorApi; import org.lflang.generator.GeneratorBase; import org.lflang.lf.Action; import org.lflang.lf.ActionOrigin; @@ -95,7 +96,7 @@ public static void addNetworkInputControlReaction( int recevingPortID, FederateInstance instance, Reactor parent, - GeneratorBase generator + GeneratorApi generator ) { LfFactory factory = LfFactory.eINSTANCE; Reaction reaction = factory.createReaction(); @@ -160,7 +161,7 @@ public static void addNetworkInputControlReaction( */ private static TimeValue findMaxSTP(Variable port, FederateInstance instance, - GeneratorBase generator, Reactor reactor) { + GeneratorApi generator, Reactor reactor) { // Find a list of STP offsets (if any exists) List STPList = new LinkedList(); @@ -290,7 +291,7 @@ public static void addNetworkOutputControlReaction( int channelIndex, int bankIndex, int receivingFedID, - GeneratorBase generator + GeneratorApi generator ) { LfFactory factory = LfFactory.eINSTANCE; Reaction reaction = factory.createReaction(); @@ -380,7 +381,7 @@ public static void makeCommunication( FederateInstance rightFederate, int rightBankIndex, int rightChannelIndex, - GeneratorBase generator, + GeneratorApi generator, CoordinationType coordination ) { LfFactory factory = LfFactory.eINSTANCE; diff --git a/org.lflang/src/org/lflang/federated/FederatedGenerationHelper.java b/org.lflang/src/org/lflang/federated/FederatedGenerationHelper.java new file mode 100644 index 0000000000..f0b9876c38 --- /dev/null +++ b/org.lflang/src/org/lflang/federated/FederatedGenerationHelper.java @@ -0,0 +1,123 @@ +package org.lflang.federated; + +import org.lflang.InferredType; +import org.lflang.TimeValue; +import org.lflang.generator.FederateInstance; +import org.lflang.lf.Action; +import org.lflang.lf.Delay; +import org.lflang.lf.Reaction; +import org.lflang.lf.VarRef; + +/** + * API needed by {@link org.lflang.federated.FedASTUtils}, implemented by generators. + */ +public interface FederatedGenerationHelper { + // fixme extract those from GeneratorBase? It's too large! + // fixme this is transitional until we have a single GeneratorBase + + + boolean makeUnordered(Reaction reaction); + + + int getFederationSize(); + + + boolean isFederatedAndDecentralized(); + + + /** + * Generate code for the body of a reaction that waits long enough so that the status + * of the trigger for the given port becomes known for the current logical time. + * + * @param receivingPortID The port to generate the control reaction for + * @param maxSTP The maximum value of STP is assigned to reactions (if any) + * that have port as their trigger or source + */ + default String generateNetworkInputControlReactionBody(int receivingPortID, TimeValue maxSTP) { + throw new UnsupportedOperationException("This target does not support direct connections between federates."); + } + + + /** + * Generate code for the body of a reaction that handles the + * action that is triggered by receiving a message from a remote + * federate. + * + * @param action The action. + * @param sendingPort The output port providing the data to send. + * @param receivingPort The ID of the destination port. + * @param receivingPortID The ID of the destination port. + * @param sendingFed The sending federate. + * @param receivingFed The destination federate. + * @param receivingBankIndex The receiving federate's bank index, if it is in a bank. + * @param receivingChannelIndex The receiving federate's channel index, if it is a multiport. + * @param type The type. + * @param isPhysical Indicates whether or not the connection is physical + */ + default String generateNetworkReceiverBody( + Action action, + VarRef sendingPort, + VarRef receivingPort, + int receivingPortID, + FederateInstance sendingFed, + FederateInstance receivingFed, + int receivingBankIndex, + int receivingChannelIndex, + InferredType type, + boolean isPhysical + ) { + throw new UnsupportedOperationException("This target does not support direct connections between federates."); + } + + + /** + * Generate code for the body of a reaction that handles an output + * that is to be sent over the network. This base class throws an exception. + * + * @param sendingPort The output port providing the data to send. + * @param receivingPort The ID of the destination port. + * @param receivingPortID The ID of the destination port. + * @param sendingFed The sending federate. + * @param sendingBankIndex The bank index of the sending federate, if it is a bank. + * @param sendingChannelIndex The channel index of the sending port, if it is a multiport. + * @param receivingFed The destination federate. + * @param type The type. + * @param isPhysical Indicates whether the connection is physical or not + * @param delay The delay value imposed on the connection using after + * @throws UnsupportedOperationException If the target does not support this operation. + */ + default String generateNetworkSenderBody( + VarRef sendingPort, + VarRef receivingPort, + int receivingPortID, + FederateInstance sendingFed, + int sendingBankIndex, + int sendingChannelIndex, + FederateInstance receivingFed, + InferredType type, + boolean isPhysical, + Delay delay + ) { + throw new UnsupportedOperationException("This target does not support direct connections between federates."); + } + + /** + * Generate code for the body of a reaction that sends a port status message for the given + * port if it is absent. + * + * @param port The port to generate the control reaction for + * @param portID The ID assigned to the port in the AST transformation + * @param receivingFederateID The ID of the receiving federate + * @param sendingBankIndex The bank index of the sending federate, if it is a bank. + * @param sendingChannelIndex The channel if a multiport + */ + default String generateNetworkOutputControlReactionBody( + VarRef port, + int portID, + int receivingFederateID, + int sendingBankIndex, + int sendingChannelIndex + ) { + throw new UnsupportedOperationException("This target does not support direct connections between federates."); + } +} diff --git a/org.lflang/src/org/lflang/generator/CGenerator.xtend b/org.lflang/src/org/lflang/generator/CGenerator.xtend index c39d59faea..9830b9c86f 100644 --- a/org.lflang/src/org/lflang/generator/CGenerator.xtend +++ b/org.lflang/src/org/lflang/generator/CGenerator.xtend @@ -65,7 +65,6 @@ import org.lflang.lf.StateVar import org.lflang.lf.Timer import org.lflang.lf.TriggerRef import org.lflang.lf.TypedVariable -import org.lflang.lf.Value import org.lflang.lf.VarRef import org.lflang.lf.Variable diff --git a/org.lflang/src/org/lflang/generator/CppGenerator2.kt b/org.lflang/src/org/lflang/generator/CppGenerator2.kt index 49a88607eb..03232624c3 100644 --- a/org.lflang/src/org/lflang/generator/CppGenerator2.kt +++ b/org.lflang/src/org/lflang/generator/CppGenerator2.kt @@ -64,8 +64,9 @@ class CppGenerator2 : KtGeneratorBase( TODO("Not yet implemented") } - override val targetTimeType: String - get() = TODO("Not yet implemented") + override fun getTargetTimeType(): String { + TODO("Not yet implemented") + } override val targetTagType: String get() = TODO("Not yet implemented") override val targetTagIntervalType: String diff --git a/org.lflang/src/org/lflang/generator/FederateInstance.xtend b/org.lflang/src/org/lflang/generator/FederateInstance.xtend index 337a556903..8a72ef0f23 100644 --- a/org.lflang/src/org/lflang/generator/FederateInstance.xtend +++ b/org.lflang/src/org/lflang/generator/FederateInstance.xtend @@ -69,7 +69,7 @@ class FederateInstance { Instantiation instantiation, int id, int bankIndex, - GeneratorBase generator + GeneratorApi generator ) { this.instantiation = instantiation; this.id = id; @@ -313,7 +313,7 @@ class FederateInstance { * @return True if no federation has been defined. */ def isSingleton() { - return ((instantiation === null) || (generator.federates.size <= 1)) + return ((instantiation === null) || (generator.getFederationSize <= 1)) } /** @@ -344,7 +344,7 @@ class FederateInstance { var excludeReactions = null as Set /** The generator using this. */ - var generator = null as GeneratorBase + var GeneratorApi generator = null /** * Find the nearest (shortest) path to a physical action trigger from this diff --git a/org.lflang/src/org/lflang/generator/GeneratorApi.java b/org.lflang/src/org/lflang/generator/GeneratorApi.java new file mode 100644 index 0000000000..dba2ed00ed --- /dev/null +++ b/org.lflang/src/org/lflang/generator/GeneratorApi.java @@ -0,0 +1,41 @@ +package org.lflang.generator; + +import org.eclipse.emf.ecore.EObject; +import org.lflang.federated.FederatedGenerationHelper; + +/** + * Common supertype of {@link GeneratorBase} and {@link KtGeneratorBase}. + */ +public interface GeneratorApi extends FederatedGenerationHelper { + // fixme this is transitional until we have a single GeneratorBase + + + String getTargetTimeType(); + + + /** + * Report an error. + * + * @param message The error message. + */ + String reportError(final String message); + + + /** + * Report an error on the specified parse tree object. + * + * @param object The parse tree object. + * @param message The error message. + */ + String reportError(final EObject object, final String message); + + + /** + * Report a warning on the specified parse tree object. + * + * @param object The parse tree object. + * @param message The error message. + */ + String reportWarning(final EObject object, final String message); + +} diff --git a/org.lflang/src/org/lflang/generator/GeneratorBase.xtend b/org.lflang/src/org/lflang/generator/GeneratorBase.xtend index 8d6c5e6125..b5d325f4c8 100644 --- a/org.lflang/src/org/lflang/generator/GeneratorBase.xtend +++ b/org.lflang/src/org/lflang/generator/GeneratorBase.xtend @@ -99,7 +99,7 @@ import org.lflang.federated.FedASTUtils * @author{Christian Menard } */ -abstract class GeneratorBase extends AbstractLFValidator { +abstract class GeneratorBase extends AbstractLFValidator implements GeneratorApi { //////////////////////////////////////////// //// Public fields. @@ -652,7 +652,7 @@ abstract class GeneratorBase extends AbstractLFValidator { * instance is created, add that instance to this set. * @param reaction The reaction to make unordered. */ - def makeUnordered(Reaction reaction) { + override makeUnordered(Reaction reaction) { if (unorderedReactions === null) { unorderedReactions = new LinkedHashSet() } @@ -1232,106 +1232,12 @@ abstract class GeneratorBase extends AbstractLFValidator { targetDecl } - /** - * Generate code for the body of a reaction that handles the - * action that is triggered by receiving a message from a remote - * federate. - * @param action The action. - * @param sendingPort The output port providing the data to send. - * @param receivingPort The ID of the destination port. - * @param receivingPortID The ID of the destination port. - * @param sendingFed The sending federate. - * @param receivingFed The destination federate. - * @param receivingBankIndex The receiving federate's bank index, if it is in a bank. - * @param receivingChannelIndex The receiving federate's channel index, if it is a multiport. - * @param type The type. - * @param isPhysical Indicates whether or not the connection is physical - */ - def String generateNetworkReceiverBody( - Action action, - VarRef sendingPort, - VarRef receivingPort, - int receivingPortID, - FederateInstance sendingFed, - FederateInstance receivingFed, - int receivingBankIndex, - int receivingChannelIndex, - InferredType type, - boolean isPhysical - ) { - throw new UnsupportedOperationException("This target does not support direct connections between federates.") - } - - /** - * Generate code for the body of a reaction that handles an output - * that is to be sent over the network. This base class throws an exception. - * @param sendingPort The output port providing the data to send. - * @param receivingPort The ID of the destination port. - * @param receivingPortID The ID of the destination port. - * @param sendingFed The sending federate. - * @param sendingBankIndex The bank index of the sending federate, if it is a bank. - * @param sendingChannelIndex The channel index of the sending port, if it is a multiport. - * @param receivingFed The destination federate. - * @param type The type. - * @param isPhysical Indicates whether the connection is physical or not - * @param delay The delay value imposed on the connection using after - * @throws UnsupportedOperationException If the target does not support this operation. - */ - def String generateNetworkSenderBody( - VarRef sendingPort, - VarRef receivingPort, - int receivingPortID, - FederateInstance sendingFed, - int sendingBankIndex, - int sendingChannelIndex, - FederateInstance receivingFed, - InferredType type, - boolean isPhysical, - Delay delay - ) { - throw new UnsupportedOperationException("This target does not support direct connections between federates.") - } - - /** - * Generate code for the body of a reaction that waits long enough so that the status - * of the trigger for the given port becomes known for the current logical time. - * - * @param port The port to generate the control reaction for - * @param maxSTP The maximum value of STP is assigned to reactions (if any) - * that have port as their trigger or source - */ - def String generateNetworkInputControlReactionBody( - int receivingPortID, - TimeValue maxSTP - ) { - throw new UnsupportedOperationException("This target does not support direct connections between federates.") - } - - /** - * Generate code for the body of a reaction that sends a port status message for the given - * port if it is absent. - * - * @param port The port to generate the control reaction for - * @param portID The ID assigned to the port in the AST transformation - * @param receivingFederateID The ID of the receiving federate - * @param sendingBankIndex The bank index of the sending federate, if it is a bank. - * @param sendingChannelIndex The channel if a multiport - */ - def String generateNetworkOutputControlReactionBody( - VarRef port, - int portID, - int receivingFederateID, - int sendingBankIndex, - int sendingChannelIndex - ) { - throw new UnsupportedOperationException("This target does not support direct connections between federates.") - } /** * Returns true if the program is federated and uses the decentralized * coordination mechanism. */ - def isFederatedAndDecentralized() { + override isFederatedAndDecentralized() { if (isFederated && targetConfig.coordination === CoordinationType.DECENTRALIZED) { return true @@ -1842,7 +1748,7 @@ abstract class GeneratorBase extends AbstractLFValidator { /** Report an error. * @param message The error message. */ - protected def reportError(String message) { + override reportError(String message) { return report(message, IMarker.SEVERITY_ERROR, null) } @@ -1850,7 +1756,7 @@ abstract class GeneratorBase extends AbstractLFValidator { * @param object The parse tree object. * @param message The error message. */ - protected def reportError(EObject object, String message) { + override reportError(EObject object, String message) { return report(message, IMarker.SEVERITY_ERROR, object) } @@ -1858,7 +1764,7 @@ abstract class GeneratorBase extends AbstractLFValidator { * @param object The parse tree object. * @param message The error message. */ - protected def reportWarning(EObject object, String message) { + override reportWarning(EObject object, String message) { return report(message, IMarker.SEVERITY_WARNING, object) } @@ -2342,7 +2248,7 @@ abstract class GeneratorBase extends AbstractLFValidator { */ abstract def boolean supportsGenerics() - abstract def String getTargetTimeType() + abstract override String getTargetTimeType() abstract def String getTargetTagType() @@ -2465,5 +2371,9 @@ abstract class GeneratorBase extends AbstractLFValidator { fOut.write(code) fOut.close() } + + override getFederationSize() { + federates.size + } } diff --git a/org.lflang/src/org/lflang/generator/KotlinGeneratorBase.kt b/org.lflang/src/org/lflang/generator/KotlinGeneratorBase.kt deleted file mode 100644 index 2997296fe2..0000000000 --- a/org.lflang/src/org/lflang/generator/KotlinGeneratorBase.kt +++ /dev/null @@ -1,73 +0,0 @@ -/* - * 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.generator - -import org.lflang.ASTUtils -import org.lflang.InferredType -import org.lflang.Target -import org.lflang.lf.* - -/** - * - */ -abstract class KotlinGeneratorBase(val target: Target) { - - abstract fun generateDelayBody(action: Action, port: VarRef): String - abstract fun generateForwardBody(action: Action, port: VarRef): String - abstract fun generateDelayGeneric(): String - abstract fun supportsGenerics(): Boolean - abstract fun getTargetTimeType(): String - abstract fun getTargetTagType(): String - abstract fun getTargetTagIntervalType(): String - abstract fun getTargetUndefinedType(): String - abstract fun getTargetFixedSizeListType(baseType: String, size: Int): String - abstract fun getTargetVariableSizeListType(baseType: String): String - - - /** Return a string representing the specified type in the target language. */ - protected fun getTargetType(type: InferredType): String = when { - type.isUndefined -> this.getTargetUndefinedType() - type.isTime -> when { - type.isFixedSizeList -> this.getTargetFixedSizeListType(this.getTargetTimeType(), type.listSize) - type.isVariableSizeList -> this.getTargetVariableSizeListType(this.getTargetTimeType()) - else -> this.getTargetTimeType() - } - type.isFixedSizeList -> this.getTargetFixedSizeListType(type.baseType(), type.listSize) - type.isVariableSizeList -> this.getTargetVariableSizeListType(type.baseType()) - else -> type.toText() - } - - - val StateVar.targetType: String get() = getTargetType(ASTUtils.getInferredType(this)) - val Action.targetType: String get() = getTargetType(ASTUtils.getInferredType(this)) - val Port.targetType: String get() = getTargetType(ASTUtils.getInferredType(this)) - val Type.targetType: String get() = getTargetType(ASTUtils.getInferredType(this)) - val Parameter.targetType: String get() = getTargetType(ASTUtils.getInferredType(this)) -} - - -class Foo { - -} diff --git a/org.lflang/src/org/lflang/generator/KtGeneratorBase.kt b/org.lflang/src/org/lflang/generator/KtGeneratorBase.kt index d30a4f9519..8a01b642d5 100644 --- a/org.lflang/src/org/lflang/generator/KtGeneratorBase.kt +++ b/org.lflang/src/org/lflang/generator/KtGeneratorBase.kt @@ -49,7 +49,7 @@ import kotlin.math.min abstract class KtGeneratorBase( val target: Target, val supportsGenerics: Boolean -) : AbstractLFValidator() { +) : AbstractLFValidator(), GeneratorApi { /** * Defines the execution environment that is used to execute binaries. @@ -531,6 +531,37 @@ abstract class KtGeneratorBase( return prefix + reference.variable.name } + + /** + * Generate code for referencing a port possibly indexed by + * a bank index and/or a multiport index. This assumes the target language uses + * the usual array indexing [n] for both cases. If not, this needs to be overridden + * by the target code generator. If the provided reference is not a port, then + * this return the string "ERROR: not a port.". + * @param reference The reference to the port. + * @param bankIndex A bank index or null or negative if not in a bank. + * @param multiportIndex A multiport index or null if not in a multiport. + */ + fun generatePortRef( reference:VarRef, bankIndex:Int?, multiportIndex:Int?):String { + if (reference.variable !is Port) { + return "ERROR: not a port." + } + var prefix = "" + if (reference.container != null) { + var bank = "" + if (reference.container.widthSpec != null && bankIndex != null) { + bank = "[$bankIndex]" + } + prefix = reference.container.name + bank + "." + } + var multiport = "" + if ((reference.variable as Port).widthSpec != null && multiportIndex != null && multiportIndex >= 0) { + multiport = "[$multiportIndex]" + } + return prefix + reference.variable.name + multiport + } + + /** * Return true if the reaction is unordered. An unordered reaction is one * that does not have any dependency on other reactions in the containing @@ -558,7 +589,7 @@ abstract class KtGeneratorBase( * instance is created, add that instance to this set. * @param reaction The reaction to make unordered. */ - fun makeUnordered(reaction: Reaction): Boolean = + override fun makeUnordered(reaction: Reaction): Boolean = unorderedReactions?.add(reaction) ?: let { unorderedReactions = mutableSetOf(reaction) true @@ -1082,66 +1113,6 @@ You can set PATH in ~/.bash_profile on Linux or Mac.""" return this.createCommand(cmd, args, dir, env) } - /** - * Generate code for the body of a reaction that handles input from the network - * that is handled by the specified action. This base class throws an exception. - * @param action The action that has been created to handle incoming messages. - * @param sendingPort The output port providing the data to send. - * @param receivingPort The ID of the destination port. - * @param receivingPortID The ID of the destination port. - * @param sendingFed The sending federate. - * @param receivingFed The destination federate. - * @param receivingBankIndex The receiving federate's bank index, if it is in a bank. - * @param receivingChannelIndex The receiving federate's channel index, if it is a multiport. - * @param type The type. - * @throws UnsupportedOperationException If the target does not support this operation. - */ - open fun generateNetworkReceiverBody( - action: Action?, - sendingPort: VarRef?, - receivingPort: VarRef?, - receivingPortID: Int, - sendingFed: FederateInstance?, - receivingFed: FederateInstance?, - receivingBankIndex: Int, - receivingChannelIndex: Int, - type: InferredType? - ): String? { - throw UnsupportedOperationException("This target does not support direct connections between federates.") - } - - // ---ported until HERE--- - - /** - * Generate code for the body of a reaction that handles an output - * that is to be sent over the network. This base class throws an exception. - * @param sendingPort The output port providing the data to send. - * @param receivingPort The ID of the destination port. - * @param receivingPortID The ID of the destination port. - * @param sendingFed The sending federate. - * @param sendingBankIndex The bank index of the sending federate, if it is a bank. - * @param sendingChannelIndex The channel index of the sending port, if it is a multiport. - * @param receivingFed The destination federate. - * @param type The type. - * @param isPhysical Indicates whether the connection is physical or not - * @param delay The delay value imposed on the connection using after - * @throws UnsupportedOperationException If the target does not support this operation. - */ - open fun generateNetworkSenderBody( - sendingPort: VarRef?, - receivingPort: VarRef?, - receivingPortID: Int, - sendingFed: FederateInstance?, - sendingBankIndex: Int, - sendingChannelIndex: Int, - receivingFed: FederateInstance?, - type: InferredType?, - isPhysical: Boolean, - delay: Delay? - ): String? { - throw UnsupportedOperationException("This target does not support direct connections between federates.") - } - /** * Generate any preamble code that appears in the code generated * file before anything else. @@ -1472,13 +1443,14 @@ You can set PATH in ~/.bash_profile on Linux or Mac.""" * This will print the error message to stderr. * If running in INTEGRATED mode (within the Eclipse IDE), then this also * adds a marker to the editor. + * * @param message The error message. * @param severity One of IMarker.SEVERITY_ERROR or IMarker.SEVERITY_WARNING * @param line The line number or null if it is not known. - * @param object The Ecore object, or null if it is not known. + * @param eObject The Ecore object, or null if it is not known. * @param resource The resource, or null if it is not known. */ - protected fun report(message: String, severity: Int, line: Int?, `object`: EObject?, resource: IResource?): String { + protected fun report(message: String, severity: Int, line: Int?, eObject: EObject?, resource: IResource?): String { if (severity == IMarker.SEVERITY_ERROR) { generatorErrorsOccurred = true } @@ -1488,8 +1460,8 @@ You can set PATH in ~/.bash_profile on Linux or Mac.""" val fullPath: String = let { var p = resource?.fullPath?.toString() if (p == null) { - if (`object` != null && `object`.eResource() != null) - p = FileConfig.toPath(`object`.eResource()).toString() + if (eObject != null && eObject.eResource() != null) + p = FileConfig.toPath(eObject.eResource()).toString() if (p == null) { p = if (line == null) "" else "path unknown" } @@ -1504,9 +1476,9 @@ You can set PATH in ~/.bash_profile on Linux or Mac.""" // See: https://help.eclipse.org/2020-03/index.jsp?topic=%2Forg.eclipse.platform.doc.isv%2Fguide%2FresAdv_markers.htm if (mode === Mode.INTEGRATED) { var myResource = resource - if (myResource === null && `object` != null) { + if (myResource === null && eObject != null) { // Attempt to identify the IResource from the object. - val eResource = `object`.eResource() + val eResource = eObject.eResource() if (eResource != null) { val uri = FileConfig.toPath(eResource).toUri() myResource = getEclipseResource(uri) @@ -1579,26 +1551,26 @@ You can set PATH in ~/.bash_profile on Linux or Mac.""" * Report an error. * @param message The error message. */ - protected fun reportError(message: String): String { + override fun reportError(message: String): String { return this.report(message, IMarker.SEVERITY_ERROR, null) } /** * Report an error on the specified parse tree object. - * @param object The parse tree object. + * @param eObject The parse tree object. * @param message The error message. */ - protected fun reportError(`object`: EObject?, message: String): String { - return this.report(message, IMarker.SEVERITY_ERROR, `object`) + override fun reportError(eObject: EObject?, message: String): String { + return this.report(message, IMarker.SEVERITY_ERROR, eObject) } /** * Report a warning on the specified parse tree object. - * @param object The parse tree object. + * @param eObject The parse tree object. * @param message The error message. */ - protected fun reportWarning(`object`: EObject?, message: String): String { - return this.report(message, IMarker.SEVERITY_WARNING, `object`) + override fun reportWarning(eObject: EObject?, message: String): String { + return this.report(message, IMarker.SEVERITY_WARNING, eObject) } /** @@ -2040,7 +2012,7 @@ You can set PATH in ~/.bash_profile on Linux or Mac.""" return returnCode } - abstract val targetTimeType: String + abstract override fun getTargetTimeType(): String abstract val targetTagType: String abstract val targetTagIntervalType: String abstract val targetUndefinedType: String @@ -2134,4 +2106,10 @@ You can set PATH in ~/.bash_profile on Linux or Mac.""" } } } + + override fun getFederationSize(): Int = federates.size + + override fun isFederatedAndDecentralized() = + isFederated && targetConfig.coordination === TargetProperty.CoordinationType.DECENTRALIZED + } diff --git a/org.lflang/src/org/lflang/validation/LFValidator.java b/org.lflang/src/org/lflang/validation/LFValidator.java index e3e3936a92..032ec921f1 100644 --- a/org.lflang/src/org/lflang/validation/LFValidator.java +++ b/org.lflang/src/org/lflang/validation/LFValidator.java @@ -1,6 +1,9 @@ package org.lflang.validation; -public class LFValidator extends AbstractLFValidator { +import java.util.List; +public abstract class LFValidator extends AbstractLFValidator { + + public abstract List getTargetPropertyErrors(); // todo port xtend into new kotlin file } diff --git a/org.lflang/src/org/lflang/validation/LFValidatorImpl.xtend b/org.lflang/src/org/lflang/validation/LFValidatorImpl.xtend index 871bcd0ef9..a59cbdd50c 100644 --- a/org.lflang/src/org/lflang/validation/LFValidatorImpl.xtend +++ b/org.lflang/src/org/lflang/validation/LFValidatorImpl.xtend @@ -131,9 +131,13 @@ class LFValidatorImpl extends LFValidator { static val spacingViolationPolicies = #['defer', 'drop', 'replace'] - public val List targetPropertyErrors = newLinkedList + private val List targetPropertyErrors = newLinkedList - public val List targetPropertyWarnings = newLinkedList + private val List targetPropertyWarnings = newLinkedList + + override List getTargetPropertyErrors() { + this.targetPropertyErrors + } @Check def checkImportedReactor(ImportedReactor reactor) { From 4ba2bfce25ea02c7f239643615454a4d9a7145f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Wed, 28 Apr 2021 16:04:58 +0200 Subject: [PATCH 34/88] Add gradle task to remove files forced on us by Xtext --- build.gradle | 2 - org.lflang/build.gradle | 29 +++++++ .../src/org/lflang/LFRuntimeModule.java | 27 ------ org.lflang/src/org/lflang/LFRuntimeModule.kt | 26 ++++++ .../src/org/lflang/generator/LFGenerator.java | 27 ------ .../src/org/lflang/generator/LFGenerator.kt | 84 +++++++++++++++++++ .../org/lflang/generator/LFGeneratorImpl.kt | 66 --------------- .../org/lflang/validation/LFValidator.java | 9 -- ...FValidatorImpl.xtend => LFValidator.xtend} | 4 +- 9 files changed, 141 insertions(+), 133 deletions(-) delete mode 100644 org.lflang/src/org/lflang/LFRuntimeModule.java create mode 100644 org.lflang/src/org/lflang/LFRuntimeModule.kt delete mode 100644 org.lflang/src/org/lflang/generator/LFGenerator.java create mode 100644 org.lflang/src/org/lflang/generator/LFGenerator.kt delete mode 100644 org.lflang/src/org/lflang/generator/LFGeneratorImpl.kt delete mode 100644 org.lflang/src/org/lflang/validation/LFValidator.java rename org.lflang/src/org/lflang/validation/{LFValidatorImpl.xtend => LFValidator.xtend} (99%) diff --git a/build.gradle b/build.gradle index cdb1562927..65dd58d63f 100644 --- a/build.gradle +++ b/build.gradle @@ -22,8 +22,6 @@ subprojects { } apply plugin: 'kotlin' - apply plugin: 'java' - compileJava.dependsOn(compileKotlin) compileKotlin { destinationDir = compileJava.destinationDir kotlinOptions { diff --git a/org.lflang/build.gradle b/org.lflang/build.gradle index 94852fde57..177ec1ae6f 100644 --- a/org.lflang/build.gradle +++ b/org.lflang/build.gradle @@ -31,6 +31,35 @@ task generateXtextLanguage(type: JavaExec) { args += "rootPath=/${projectDir}/.." } +task cleanupXtextFilesThatWeWriteOurselves(type: Delete) { + dependsOn(generateXtextLanguage) + def filesToDelete = [ + "org.lflang.validation.LFValidator", + "org.lflang.LFRuntimeModule", + "org.lflang.LFStandaloneSetup", + "org.lflang.generator.LFGenerator", + ] + + doLast { + filesToDelete.each { qname -> + def path = qname.replace('.', '/') + def ktFile = file("src/${path}.kt") + def javaFile = file("src/${path}.java") + def xtendFile = file("src/${path}.xtend") + + if (ktFile.exists() || xtendFile.exists()) { + def chosenLang = ktFile.exists() ? "Kotlin" : "Xtend" + project.logger.info("deleting ${projectDir.relativePath(javaFile)}, the ${chosenLang} file prevails") + delete(javaFile) // generated by Xtend + } else { + project.logger.info("no ${projectDir.relativePath(ktFile)}, leaving the Java implementation in") + } + } + } +} + +compileKotlin.dependsOn(cleanupXtextFilesThatWeWriteOurselves) + generateXtext.dependsOn(generateXtextLanguage) clean.dependsOn(cleanGenerateXtextLanguage) eclipse.classpath.plusConfigurations += [configurations.mwe2] diff --git a/org.lflang/src/org/lflang/LFRuntimeModule.java b/org.lflang/src/org/lflang/LFRuntimeModule.java deleted file mode 100644 index 4d7d7fee34..0000000000 --- a/org.lflang/src/org/lflang/LFRuntimeModule.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * generated by Xtext 2.23.0 - */ -package org.lflang; - -import org.lflang.scoping.LFGlobalScopeProvider; -import org.lflang.validation.LFNamesAreUniqueValidationHelper; - -/** - * Use this class to register components to be used at runtime / without the Equinox extension registry. - */ -public class LFRuntimeModule extends AbstractLFRuntimeModule { - /** Establish a binding to our custom global scope provider. */ - @Override - public Class bindIGlobalScopeProvider() { - return LFGlobalScopeProvider.class; - } - - /** Establish a binding to a helper that checks that names are unique. */ - public Class bindNamesAreUniqueValidationHelper() { - return LFNamesAreUniqueValidationHelper.class; - } - /** Establish a binding to our custom resource description strategy. */ -// fun bindIDefaultResourceDescriptionStrategy(): Class = LFResourceDescriptionStrategy::class.java - - -} diff --git a/org.lflang/src/org/lflang/LFRuntimeModule.kt b/org.lflang/src/org/lflang/LFRuntimeModule.kt new file mode 100644 index 0000000000..2ce7ae80ce --- /dev/null +++ b/org.lflang/src/org/lflang/LFRuntimeModule.kt @@ -0,0 +1,26 @@ +/* + * generated by Xtext 2.23.0 + */ +package org.lflang + +import org.lflang.scoping.LFGlobalScopeProvider +import org.lflang.validation.LFNamesAreUniqueValidationHelper + +/** + * Use this class to register components to be used at runtime / without the Equinox extension registry. + */ +open class LFRuntimeModule : AbstractLFRuntimeModule() { + + /** Establish a binding to our custom global scope provider. */ + override fun bindIGlobalScopeProvider(): Class { + return LFGlobalScopeProvider::class.java + } + + /** Establish a binding to a helper that checks that names are unique. */ + fun bindNamesAreUniqueValidationHelper(): Class { + return LFNamesAreUniqueValidationHelper::class.java + } + + /** Establish a binding to our custom resource description strategy. */ + // fun bindIDefaultResourceDescriptionStrategy(): Class = LFResourceDescriptionStrategy::class.java +} diff --git a/org.lflang/src/org/lflang/generator/LFGenerator.java b/org.lflang/src/org/lflang/generator/LFGenerator.java deleted file mode 100644 index 367d826a36..0000000000 --- a/org.lflang/src/org/lflang/generator/LFGenerator.java +++ /dev/null @@ -1,27 +0,0 @@ -package org.lflang.generator; - -import org.eclipse.emf.ecore.resource.Resource; -import org.eclipse.xtext.generator.AbstractGenerator; -import org.eclipse.xtext.generator.IFileSystemAccess2; -import org.eclipse.xtext.generator.IGeneratorContext; - -/** - * Generates code from your model files on save. - * - * See https://www.eclipse.org/Xtext/documentation/303_runtime_concepts.html#code-generation - */ -public class LFGenerator extends AbstractGenerator { - - // Indicator of whether generator errors occurred. - protected boolean generatorErrorsOccurred = false; - - public void doGenerate(Resource resource, IFileSystemAccess2 fsa, IGeneratorContext context) { - generatorErrorsOccurred = LFGeneratorImpl.INSTANCE.doGenerate(resource, fsa, context); - } - - /** Return true if errors occurred in the last call to doGenerate(). */ - public boolean errorsOccurred() { - return generatorErrorsOccurred; - } - -} diff --git a/org.lflang/src/org/lflang/generator/LFGenerator.kt b/org.lflang/src/org/lflang/generator/LFGenerator.kt new file mode 100644 index 0000000000..75dd9557ed --- /dev/null +++ b/org.lflang/src/org/lflang/generator/LFGenerator.kt @@ -0,0 +1,84 @@ +/* Generated by Xtext 2.17.0 and then modified to support specific targets. */ +/************* + * Copyright (c) 2019-2020, 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.generator + +import org.eclipse.emf.ecore.resource.Resource +import org.eclipse.xtext.generator.AbstractGenerator +import org.eclipse.xtext.generator.IFileSystemAccess2 +import org.eclipse.xtext.generator.IGeneratorContext +import org.lflang.Target +import org.lflang.lf.TargetDecl + +/** + * Generates code from your model files on save. + * + * See https://www.eclipse.org/Xtext/documentation/303_runtime_concepts.html#code-generation + */ +class LFGenerator : AbstractGenerator() { + + /** + * Is set if errors occurred in the last call to doGenerate(). + */ + var generatorErrorsOccurred = false + private set + + override fun doGenerate(resource: Resource, fsa: IFileSystemAccess2, context: IGeneratorContext) { + this.generatorErrorsOccurred = generateImpl(resource, fsa, context) + } + + companion object { + + private val TARGET_MAP: Map> = mapOf( + Target.C to CGenerator::class.java, + Target.CCPP to CCppGenerator::class.java, + Target.CPP to CppGenerator::class.java, + Target.TS to TypeScriptGenerator::class.java, + Target.Python to PythonGenerator::class.java + ) + + private fun getGenerator(target: Target): GeneratorBase { + val generatorClass = TARGET_MAP[target]!! + return try { + generatorClass.getConstructor().newInstance() + } catch (e: Exception) { + throw AssertionError("Missing constructor in $generatorClass", e) + } + } + + /** Returns true if some errors occurred. */ + private fun generateImpl(resource: Resource, fsa: IFileSystemAccess2, context: IGeneratorContext): Boolean { + // Determine which target is desired. + val targetName = findTargetNameOrThrow(resource) + val target = Target.forName(targetName) ?: throw AssertionError("Not a target '$targetName'") + return getGenerator(target).also { + it.doGenerate(resource, fsa, context) + }.errorsOccurred() + } + + private fun findTargetNameOrThrow(resource: Resource): String = + resource.allContents.asSequence() + .mapNotNull { it as? TargetDecl } + .firstOrNull() + ?.name + ?: throw AssertionError("No target declaration") + + } +} diff --git a/org.lflang/src/org/lflang/generator/LFGeneratorImpl.kt b/org.lflang/src/org/lflang/generator/LFGeneratorImpl.kt deleted file mode 100644 index 0c0036b205..0000000000 --- a/org.lflang/src/org/lflang/generator/LFGeneratorImpl.kt +++ /dev/null @@ -1,66 +0,0 @@ -/* Generated by Xtext 2.17.0 and then modified to support specific targets. */ -/************* - * Copyright (c) 2019-2020, 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.generator - -import org.eclipse.emf.ecore.resource.Resource -import org.eclipse.xtext.generator.IFileSystemAccess2 -import org.eclipse.xtext.generator.IGeneratorContext -import org.lflang.Target -import org.lflang.lf.TargetDecl - -/** Implementation of [LFGenerator]. */ -internal object LFGeneratorImpl { - - private val TARGET_MAP: Map> = mapOf( - Target.C to CGenerator::class.java, - Target.CCPP to CCppGenerator::class.java, - Target.CPP to CppGenerator::class.java, - Target.TS to TypeScriptGenerator::class.java, - Target.Python to PythonGenerator::class.java - ) - - private fun getGenerator(target: Target): GeneratorBase { - val generatorClass = TARGET_MAP[target]!! - return try { - generatorClass.getConstructor().newInstance() - } catch (e: Exception) { - throw AssertionError("Missing constructor in $generatorClass", e) - } - - } - - /** Returns true if some errors occurred. */ - fun doGenerate(resource: Resource, fsa: IFileSystemAccess2, context: IGeneratorContext): Boolean { - // Determine which target is desired. - val targetName = findTargetNameOrThrow(resource) - val target = Target.forName(targetName) ?: throw AssertionError("Not a target '$targetName'") - val generator = getGenerator(target) - generator.doGenerate(resource, fsa, context) - return generator.errorsOccurred() - } - - private fun findTargetNameOrThrow(resource: Resource): String = - resource.allContents.asSequence() - .mapNotNull { it as? TargetDecl } - .firstOrNull() - ?.name - ?: throw AssertionError("No target declaration") -} diff --git a/org.lflang/src/org/lflang/validation/LFValidator.java b/org.lflang/src/org/lflang/validation/LFValidator.java deleted file mode 100644 index 032ec921f1..0000000000 --- a/org.lflang/src/org/lflang/validation/LFValidator.java +++ /dev/null @@ -1,9 +0,0 @@ -package org.lflang.validation; - -import java.util.List; - -public abstract class LFValidator extends AbstractLFValidator { - - public abstract List getTargetPropertyErrors(); - // todo port xtend into new kotlin file -} diff --git a/org.lflang/src/org/lflang/validation/LFValidatorImpl.xtend b/org.lflang/src/org/lflang/validation/LFValidator.xtend similarity index 99% rename from org.lflang/src/org/lflang/validation/LFValidatorImpl.xtend rename to org.lflang/src/org/lflang/validation/LFValidator.xtend index a59cbdd50c..f4ecf43ed7 100644 --- a/org.lflang/src/org/lflang/validation/LFValidatorImpl.xtend +++ b/org.lflang/src/org/lflang/validation/LFValidator.xtend @@ -92,7 +92,7 @@ import org.lflang.lf.STP * @author(Christian Menard } * */ -class LFValidatorImpl extends LFValidator { +class LFValidator extends AbstractLFValidator { var Target target public var info = new ModelInfo() @@ -135,7 +135,7 @@ class LFValidatorImpl extends LFValidator { private val List targetPropertyWarnings = newLinkedList - override List getTargetPropertyErrors() { + def List getTargetPropertyErrors() { this.targetPropertyErrors } From 43e9a4146fabc3477cf67ef6e7bfeed480ca0b49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Wed, 28 Apr 2021 16:27:58 +0200 Subject: [PATCH 35/88] Remove some kotlin files (KtGeneratorBase) --- org.lflang/build.gradle | 6 +- .../{Extensions.kt => AstExtensions.kt} | 0 .../src/org/lflang/federated/FedASTUtils.java | 9 +- .../federated/FederatedGenerationHelper.java | 123 - .../src/org/lflang/generator/CppGenerator2.kt | 85 - .../lflang/generator/FederateInstance.xtend | 8 +- .../org/lflang/generator/GeneratorApi.java | 41 - .../org/lflang/generator/GeneratorBase.xtend | 247 +- .../org/lflang/generator/KtGeneratorBase.kt | 2115 ----------------- .../org/lflang/scoping/LFScopeProvider.java | 32 - ...copeProviderImpl.kt => LFScopeProvider.kt} | 20 +- 11 files changed, 197 insertions(+), 2489 deletions(-) rename org.lflang/src/org/lflang/{Extensions.kt => AstExtensions.kt} (100%) delete mode 100644 org.lflang/src/org/lflang/federated/FederatedGenerationHelper.java delete mode 100644 org.lflang/src/org/lflang/generator/CppGenerator2.kt delete mode 100644 org.lflang/src/org/lflang/generator/GeneratorApi.java delete mode 100644 org.lflang/src/org/lflang/generator/KtGeneratorBase.kt delete mode 100644 org.lflang/src/org/lflang/scoping/LFScopeProvider.java rename org.lflang/src/org/lflang/scoping/{LFScopeProviderImpl.kt => LFScopeProvider.kt} (94%) diff --git a/org.lflang/build.gradle b/org.lflang/build.gradle index 177ec1ae6f..f50102af82 100644 --- a/org.lflang/build.gradle +++ b/org.lflang/build.gradle @@ -38,6 +38,7 @@ task cleanupXtextFilesThatWeWriteOurselves(type: Delete) { "org.lflang.LFRuntimeModule", "org.lflang.LFStandaloneSetup", "org.lflang.generator.LFGenerator", + "org.lflang.scoping.LFScopeProvider" ] doLast { @@ -65,7 +66,6 @@ clean.dependsOn(cleanGenerateXtextLanguage) eclipse.classpath.plusConfigurations += [configurations.mwe2] task generateStandaloneCompiler() { - apply plugin: 'java' apply plugin: 'application' apply plugin: 'com.github.johnrengelman.shadow' mainClassName = 'org.lflang.generator.Main' @@ -80,10 +80,6 @@ task generateStandaloneCompiler() { resource = 'plugin.properties' } } - - compileJava { - options.compilerArgs << '-Xlint:unchecked' - } } generateStandaloneCompiler.finalizedBy shadowJar diff --git a/org.lflang/src/org/lflang/Extensions.kt b/org.lflang/src/org/lflang/AstExtensions.kt similarity index 100% rename from org.lflang/src/org/lflang/Extensions.kt rename to org.lflang/src/org/lflang/AstExtensions.kt diff --git a/org.lflang/src/org/lflang/federated/FedASTUtils.java b/org.lflang/src/org/lflang/federated/FedASTUtils.java index ce5ba7a176..c8286a2d2e 100644 --- a/org.lflang/src/org/lflang/federated/FedASTUtils.java +++ b/org.lflang/src/org/lflang/federated/FedASTUtils.java @@ -37,7 +37,6 @@ import org.lflang.TargetProperty.CoordinationType; import org.lflang.TimeValue; import org.lflang.generator.FederateInstance; -import org.lflang.generator.GeneratorApi; import org.lflang.generator.GeneratorBase; import org.lflang.lf.Action; import org.lflang.lf.ActionOrigin; @@ -96,7 +95,7 @@ public static void addNetworkInputControlReaction( int recevingPortID, FederateInstance instance, Reactor parent, - GeneratorApi generator + GeneratorBase generator ) { LfFactory factory = LfFactory.eINSTANCE; Reaction reaction = factory.createReaction(); @@ -161,7 +160,7 @@ public static void addNetworkInputControlReaction( */ private static TimeValue findMaxSTP(Variable port, FederateInstance instance, - GeneratorApi generator, Reactor reactor) { + GeneratorBase generator, Reactor reactor) { // Find a list of STP offsets (if any exists) List STPList = new LinkedList(); @@ -291,7 +290,7 @@ public static void addNetworkOutputControlReaction( int channelIndex, int bankIndex, int receivingFedID, - GeneratorApi generator + GeneratorBase generator ) { LfFactory factory = LfFactory.eINSTANCE; Reaction reaction = factory.createReaction(); @@ -381,7 +380,7 @@ public static void makeCommunication( FederateInstance rightFederate, int rightBankIndex, int rightChannelIndex, - GeneratorApi generator, + GeneratorBase generator, CoordinationType coordination ) { LfFactory factory = LfFactory.eINSTANCE; diff --git a/org.lflang/src/org/lflang/federated/FederatedGenerationHelper.java b/org.lflang/src/org/lflang/federated/FederatedGenerationHelper.java deleted file mode 100644 index f0b9876c38..0000000000 --- a/org.lflang/src/org/lflang/federated/FederatedGenerationHelper.java +++ /dev/null @@ -1,123 +0,0 @@ -package org.lflang.federated; - -import org.lflang.InferredType; -import org.lflang.TimeValue; -import org.lflang.generator.FederateInstance; -import org.lflang.lf.Action; -import org.lflang.lf.Delay; -import org.lflang.lf.Reaction; -import org.lflang.lf.VarRef; - -/** - * API needed by {@link org.lflang.federated.FedASTUtils}, implemented by generators. - */ -public interface FederatedGenerationHelper { - // fixme extract those from GeneratorBase? It's too large! - // fixme this is transitional until we have a single GeneratorBase - - - boolean makeUnordered(Reaction reaction); - - - int getFederationSize(); - - - boolean isFederatedAndDecentralized(); - - - /** - * Generate code for the body of a reaction that waits long enough so that the status - * of the trigger for the given port becomes known for the current logical time. - * - * @param receivingPortID The port to generate the control reaction for - * @param maxSTP The maximum value of STP is assigned to reactions (if any) - * that have port as their trigger or source - */ - default String generateNetworkInputControlReactionBody(int receivingPortID, TimeValue maxSTP) { - throw new UnsupportedOperationException("This target does not support direct connections between federates."); - } - - - /** - * Generate code for the body of a reaction that handles the - * action that is triggered by receiving a message from a remote - * federate. - * - * @param action The action. - * @param sendingPort The output port providing the data to send. - * @param receivingPort The ID of the destination port. - * @param receivingPortID The ID of the destination port. - * @param sendingFed The sending federate. - * @param receivingFed The destination federate. - * @param receivingBankIndex The receiving federate's bank index, if it is in a bank. - * @param receivingChannelIndex The receiving federate's channel index, if it is a multiport. - * @param type The type. - * @param isPhysical Indicates whether or not the connection is physical - */ - default String generateNetworkReceiverBody( - Action action, - VarRef sendingPort, - VarRef receivingPort, - int receivingPortID, - FederateInstance sendingFed, - FederateInstance receivingFed, - int receivingBankIndex, - int receivingChannelIndex, - InferredType type, - boolean isPhysical - ) { - throw new UnsupportedOperationException("This target does not support direct connections between federates."); - } - - - /** - * Generate code for the body of a reaction that handles an output - * that is to be sent over the network. This base class throws an exception. - * - * @param sendingPort The output port providing the data to send. - * @param receivingPort The ID of the destination port. - * @param receivingPortID The ID of the destination port. - * @param sendingFed The sending federate. - * @param sendingBankIndex The bank index of the sending federate, if it is a bank. - * @param sendingChannelIndex The channel index of the sending port, if it is a multiport. - * @param receivingFed The destination federate. - * @param type The type. - * @param isPhysical Indicates whether the connection is physical or not - * @param delay The delay value imposed on the connection using after - * @throws UnsupportedOperationException If the target does not support this operation. - */ - default String generateNetworkSenderBody( - VarRef sendingPort, - VarRef receivingPort, - int receivingPortID, - FederateInstance sendingFed, - int sendingBankIndex, - int sendingChannelIndex, - FederateInstance receivingFed, - InferredType type, - boolean isPhysical, - Delay delay - ) { - throw new UnsupportedOperationException("This target does not support direct connections between federates."); - } - - /** - * Generate code for the body of a reaction that sends a port status message for the given - * port if it is absent. - * - * @param port The port to generate the control reaction for - * @param portID The ID assigned to the port in the AST transformation - * @param receivingFederateID The ID of the receiving federate - * @param sendingBankIndex The bank index of the sending federate, if it is a bank. - * @param sendingChannelIndex The channel if a multiport - */ - default String generateNetworkOutputControlReactionBody( - VarRef port, - int portID, - int receivingFederateID, - int sendingBankIndex, - int sendingChannelIndex - ) { - throw new UnsupportedOperationException("This target does not support direct connections between federates."); - } -} diff --git a/org.lflang/src/org/lflang/generator/CppGenerator2.kt b/org.lflang/src/org/lflang/generator/CppGenerator2.kt deleted file mode 100644 index 03232624c3..0000000000 --- a/org.lflang/src/org/lflang/generator/CppGenerator2.kt +++ /dev/null @@ -1,85 +0,0 @@ -/* - * 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.generator - -import org.lflang.Target -import org.lflang.lf.Action -import org.lflang.lf.Reactor -import org.lflang.lf.VarRef - -/** - * - */ -class CppGenerator2 : KtGeneratorBase( - Target.CPP, - supportsGenerics = true -) { - - -/* - - def declareParameters(Reactor r) ''' - «FOR p : r.parameters BEFORE '// parameters\n' AFTER '\n'» - std::add_const<«p.targetType»>::type «p.name»; - «ENDFOR» - ''' - */ - - fun Reactor.declareParameters() = - parameters.joinToString(prefix = "// parameters\n", postfix = "\n") { - "std::add_const<${it.targetType}>::type ${it.name};" - } - - 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") - } - - override fun getTargetTimeType(): String { - TODO("Not yet implemented") - } - override val targetTagType: String - get() = TODO("Not yet implemented") - override val targetTagIntervalType: String - get() = TODO("Not yet implemented") - override val targetUndefinedType: String - get() = TODO("Not yet implemented") - - override fun getTargetFixedSizeListType(baseType: String, size: Int): String { - TODO("Not yet implemented") - } - - override fun getTargetVariableSizeListType(baseType: String): String { - TODO("Not yet implemented") - } - -} diff --git a/org.lflang/src/org/lflang/generator/FederateInstance.xtend b/org.lflang/src/org/lflang/generator/FederateInstance.xtend index 8a72ef0f23..8c77903174 100644 --- a/org.lflang/src/org/lflang/generator/FederateInstance.xtend +++ b/org.lflang/src/org/lflang/generator/FederateInstance.xtend @@ -69,7 +69,7 @@ class FederateInstance { Instantiation instantiation, int id, int bankIndex, - GeneratorApi generator + GeneratorBase generator ) { this.instantiation = instantiation; this.id = id; @@ -310,10 +310,10 @@ class FederateInstance { /** * Return true if this is singleton, meaning either that no federation * has been defined or that there is only one federate. - * @return True if no federation has been defined. + * @return True if no federation has been defined or there is only one federate. */ def isSingleton() { - return ((instantiation === null) || (generator.getFederationSize <= 1)) + return ((instantiation === null) || (generator.federates.size <= 1)) } /** @@ -344,7 +344,7 @@ class FederateInstance { var excludeReactions = null as Set /** The generator using this. */ - var GeneratorApi generator = null + var generator = null as GeneratorBase /** * Find the nearest (shortest) path to a physical action trigger from this diff --git a/org.lflang/src/org/lflang/generator/GeneratorApi.java b/org.lflang/src/org/lflang/generator/GeneratorApi.java deleted file mode 100644 index dba2ed00ed..0000000000 --- a/org.lflang/src/org/lflang/generator/GeneratorApi.java +++ /dev/null @@ -1,41 +0,0 @@ -package org.lflang.generator; - -import org.eclipse.emf.ecore.EObject; -import org.lflang.federated.FederatedGenerationHelper; - -/** - * Common supertype of {@link GeneratorBase} and {@link KtGeneratorBase}. - */ -public interface GeneratorApi extends FederatedGenerationHelper { - // fixme this is transitional until we have a single GeneratorBase - - - String getTargetTimeType(); - - - /** - * Report an error. - * - * @param message The error message. - */ - String reportError(final String message); - - - /** - * Report an error on the specified parse tree object. - * - * @param object The parse tree object. - * @param message The error message. - */ - String reportError(final EObject object, final String message); - - - /** - * Report a warning on the specified parse tree object. - * - * @param object The parse tree object. - * @param message The error message. - */ - String reportWarning(final EObject object, final String message); - -} diff --git a/org.lflang/src/org/lflang/generator/GeneratorBase.xtend b/org.lflang/src/org/lflang/generator/GeneratorBase.xtend index b5d325f4c8..fa89f9ab75 100644 --- a/org.lflang/src/org/lflang/generator/GeneratorBase.xtend +++ b/org.lflang/src/org/lflang/generator/GeneratorBase.xtend @@ -99,7 +99,7 @@ import org.lflang.federated.FedASTUtils * @author{Christian Menard } */ -abstract class GeneratorBase extends AbstractLFValidator implements GeneratorApi { +abstract class GeneratorBase extends AbstractLFValidator { //////////////////////////////////////////// //// Public fields. @@ -349,6 +349,9 @@ abstract class GeneratorBase extends AbstractLFValidator implements GeneratorApi targetConfig.compilerFlags.addAll(context.args.getProperty("target-flags").split(' ')) } } + if (context.args.containsKey("runtime-version")) { + targetConfig.runtimeVersion = context.args.getProperty("runtime-version") + } } } @@ -652,7 +655,7 @@ abstract class GeneratorBase extends AbstractLFValidator implements GeneratorApi * instance is created, add that instance to this set. * @param reaction The reaction to make unordered. */ - override makeUnordered(Reaction reaction) { + def makeUnordered(Reaction reaction) { if (unorderedReactions === null) { unorderedReactions = new LinkedHashSet() } @@ -715,7 +718,7 @@ abstract class GeneratorBase extends AbstractLFValidator implements GeneratorApi #ifdef NUMBER_OF_FEDERATES #undefine NUMBER_OF_FEDERATES #endif - #define NUMBER_OF_FEDERATES «federates.length» + #define NUMBER_OF_FEDERATES «federates.size» #include "rti.c" int main(int argc, char* argv[]) { ''') @@ -1232,12 +1235,106 @@ abstract class GeneratorBase extends AbstractLFValidator implements GeneratorApi targetDecl } + /** + * Generate code for the body of a reaction that handles the + * action that is triggered by receiving a message from a remote + * federate. + * @param action The action. + * @param sendingPort The output port providing the data to send. + * @param receivingPort The ID of the destination port. + * @param receivingPortID The ID of the destination port. + * @param sendingFed The sending federate. + * @param receivingFed The destination federate. + * @param receivingBankIndex The receiving federate's bank index, if it is in a bank. + * @param receivingChannelIndex The receiving federate's channel index, if it is a multiport. + * @param type The type. + * @param isPhysical Indicates whether or not the connection is physical + */ + def String generateNetworkReceiverBody( + Action action, + VarRef sendingPort, + VarRef receivingPort, + int receivingPortID, + FederateInstance sendingFed, + FederateInstance receivingFed, + int receivingBankIndex, + int receivingChannelIndex, + InferredType type, + boolean isPhysical + ) { + throw new UnsupportedOperationException("This target does not support direct connections between federates.") + } + + /** + * Generate code for the body of a reaction that handles an output + * that is to be sent over the network. This base class throws an exception. + * @param sendingPort The output port providing the data to send. + * @param receivingPort The ID of the destination port. + * @param receivingPortID The ID of the destination port. + * @param sendingFed The sending federate. + * @param sendingBankIndex The bank index of the sending federate, if it is a bank. + * @param sendingChannelIndex The channel index of the sending port, if it is a multiport. + * @param receivingFed The destination federate. + * @param type The type. + * @param isPhysical Indicates whether the connection is physical or not + * @param delay The delay value imposed on the connection using after + * @throws UnsupportedOperationException If the target does not support this operation. + */ + def String generateNetworkSenderBody( + VarRef sendingPort, + VarRef receivingPort, + int receivingPortID, + FederateInstance sendingFed, + int sendingBankIndex, + int sendingChannelIndex, + FederateInstance receivingFed, + InferredType type, + boolean isPhysical, + Delay delay + ) { + throw new UnsupportedOperationException("This target does not support direct connections between federates.") + } + + /** + * Generate code for the body of a reaction that waits long enough so that the status + * of the trigger for the given port becomes known for the current logical time. + * + * @param port The port to generate the control reaction for + * @param maxSTP The maximum value of STP is assigned to reactions (if any) + * that have port as their trigger or source + */ + def String generateNetworkInputControlReactionBody( + int receivingPortID, + TimeValue maxSTP + ) { + throw new UnsupportedOperationException("This target does not support direct connections between federates.") + } + + /** + * Generate code for the body of a reaction that sends a port status message for the given + * port if it is absent. + * + * @param port The port to generate the control reaction for + * @param portID The ID assigned to the port in the AST transformation + * @param receivingFederateID The ID of the receiving federate + * @param sendingBankIndex The bank index of the sending federate, if it is a bank. + * @param sendingChannelIndex The channel if a multiport + */ + def String generateNetworkOutputControlReactionBody( + VarRef port, + int portID, + int receivingFederateID, + int sendingBankIndex, + int sendingChannelIndex + ) { + throw new UnsupportedOperationException("This target does not support direct connections between federates.") + } /** * Returns true if the program is federated and uses the decentralized * coordination mechanism. */ - override isFederatedAndDecentralized() { + def isFederatedAndDecentralized() { if (isFederated && targetConfig.coordination === CoordinationType.DECENTRALIZED) { return true @@ -1748,7 +1845,7 @@ abstract class GeneratorBase extends AbstractLFValidator implements GeneratorApi /** Report an error. * @param message The error message. */ - override reportError(String message) { + protected def reportError(String message) { return report(message, IMarker.SEVERITY_ERROR, null) } @@ -1756,7 +1853,7 @@ abstract class GeneratorBase extends AbstractLFValidator implements GeneratorApi * @param object The parse tree object. * @param message The error message. */ - override reportError(EObject object, String message) { + protected def reportError(EObject object, String message) { return report(message, IMarker.SEVERITY_ERROR, object) } @@ -1764,7 +1861,7 @@ abstract class GeneratorBase extends AbstractLFValidator implements GeneratorApi * @param object The parse tree object. * @param message The error message. */ - override reportWarning(EObject object, String message) { + protected def reportWarning(EObject object, String message) { return report(message, IMarker.SEVERITY_WARNING, object) } @@ -2034,7 +2131,7 @@ abstract class GeneratorBase extends AbstractLFValidator implements GeneratorApi val federateInstances = new LinkedList(); for (var i = 0; i < bankWidth; i++) { // Assign an integer ID to the federate. - var federateID = federates.length + var federateID = federates.size var federateInstance = new FederateInstance(instantiation, federateID, i, this) federateInstance.bankIndex = i; federates.add(federateInstance) @@ -2061,7 +2158,7 @@ abstract class GeneratorBase extends AbstractLFValidator implements GeneratorApi // In a federated execution, we need keepalive to be true, // otherwise a federate could exit simply because it hasn't received // any messages. - if (federates.size > 1) { + if (isFederated) { targetConfig.keepalive = true } @@ -2090,65 +2187,75 @@ abstract class GeneratorBase extends AbstractLFValidator implements GeneratorApi var minWidth = (leftPortWidth - leftChannelIndex < rightPortWidth - rightChannelIndex) ? leftPortWidth - leftChannelIndex : rightPortWidth - rightChannelIndex; - for (var j = 0; j < minWidth; j++) { - - // Finally, we have a specific connection. - // Replace the connection in the AST with an action - // (which inherits the delay) and two reactions. - // The action will be physical if the connection physical and - // otherwise will be logical. - val leftFederate = federatesByInstantiation.get(leftPort.container).get(leftBankIndex); - val rightFederate = federatesByInstantiation.get(rightPort.container).get(rightBankIndex); - - // Set up dependency information. - if ( - leftFederate !== rightFederate - && !connection.physical - && targetConfig.coordination !== CoordinationType.DECENTRALIZED - ) { - var dependsOn = rightFederate.dependsOn.get(leftFederate) - if (dependsOn === null) { - dependsOn = new LinkedHashSet() - rightFederate.dependsOn.put(leftFederate, dependsOn) - } - if (connection.delay !== null) { - dependsOn.add(connection.delay) - } - var sendsTo = leftFederate.sendsTo.get(rightFederate) - if (sendsTo === null) { - sendsTo = new LinkedHashSet() - leftFederate.sendsTo.put(rightFederate, sendsTo) - } - if (connection.delay !== null) { - sendsTo.add(connection.delay) + if (minWidth <= 0) { + // FIXME: Not sure what to do here. + reportError(connection, "Unexpected error: mismatched widths."); + rightPort = null; + } else { + for (var j = 0; j < minWidth; j++) { + + // Finally, we have a specific connection. + // Replace the connection in the AST with an action + // (which inherits the delay) and two reactions. + // The action will be physical if the connection physical and + // otherwise will be logical. + val leftFederate = federatesByInstantiation.get(leftPort.container).get( + leftBankIndex); + val rightFederate = federatesByInstantiation.get(rightPort.container).get( + rightBankIndex); + + // Set up dependency information. + if (leftFederate !== rightFederate && !connection.physical && + targetConfig.coordination !== CoordinationType.DECENTRALIZED) { + var dependsOn = rightFederate.dependsOn.get(leftFederate) + if (dependsOn === null) { + dependsOn = new LinkedHashSet() + rightFederate.dependsOn.put(leftFederate, dependsOn) + } + if (connection.delay !== null) { + dependsOn.add(connection.delay) + } + var sendsTo = leftFederate.sendsTo.get(rightFederate) + if (sendsTo === null) { + sendsTo = new LinkedHashSet() + leftFederate.sendsTo.put(rightFederate, sendsTo) + } + if (connection.delay !== null) { + sendsTo.add(connection.delay) + } } - } - - FedASTUtils.makeCommunication( - connection, - leftFederate, leftBankIndex, leftChannelIndex, - rightFederate, rightBankIndex, rightChannelIndex, - this, targetConfig.coordination - ) - - leftChannelIndex++; - rightChannelIndex++; - if (rightChannelIndex >= rightPortWidth) { - // Ran out of channels on the right. - // First, check whether there is another bank reactor. - if (rightBankIndex < width(rightPort.container.widthSpec) - 1) { - rightBankIndex++; - rightChannelIndex = 0; - } else if (rightIndex >= connection.rightPorts.size()) { - // We are done. - rightPort = null; - rightBankIndex = 0; - rightChannelIndex = 0; - } else { - rightBankIndex = 0; - rightPort = connection.rightPorts.get(rightIndex++); - rightChannelIndex = 0; - rightPortWidth = width((rightPort.variable as Port).widthSpec); + + FedASTUtils.makeCommunication( + connection, + leftFederate, + leftBankIndex, + leftChannelIndex, + rightFederate, + rightBankIndex, + rightChannelIndex, + this, + targetConfig.coordination + ) + + leftChannelIndex++; + rightChannelIndex++; + if (rightChannelIndex >= rightPortWidth) { + // Ran out of channels on the right. + // First, check whether there is another bank reactor. + if (rightBankIndex < width(rightPort.container.widthSpec) - 1) { + rightBankIndex++; + rightChannelIndex = 0; + } else if (rightIndex >= connection.rightPorts.size()) { + // We are done. + rightPort = null; + rightBankIndex = 0; + rightChannelIndex = 0; + } else { + rightBankIndex = 0; + rightPort = connection.rightPorts.get(rightIndex++); + rightChannelIndex = 0; + rightPortWidth = width((rightPort.variable as Port).widthSpec); + } } } } @@ -2248,7 +2355,7 @@ abstract class GeneratorBase extends AbstractLFValidator implements GeneratorApi */ abstract def boolean supportsGenerics() - abstract override String getTargetTimeType() + abstract def String getTargetTimeType() abstract def String getTargetTagType() @@ -2371,9 +2478,5 @@ abstract class GeneratorBase extends AbstractLFValidator implements GeneratorApi fOut.write(code) fOut.close() } - - override getFederationSize() { - federates.size - } } diff --git a/org.lflang/src/org/lflang/generator/KtGeneratorBase.kt b/org.lflang/src/org/lflang/generator/KtGeneratorBase.kt deleted file mode 100644 index 8a01b642d5..0000000000 --- a/org.lflang/src/org/lflang/generator/KtGeneratorBase.kt +++ /dev/null @@ -1,2115 +0,0 @@ -/** - * Generator base class for shared code between code generators. - */ -package org.lflang.generator - -import org.eclipse.core.resources.IMarker -import org.eclipse.core.resources.IResource -import org.eclipse.core.resources.ResourcesPlugin -import org.eclipse.emf.ecore.EObject -import org.eclipse.emf.ecore.resource.Resource -import org.eclipse.xtext.generator.IFileSystemAccess2 -import org.eclipse.xtext.generator.IGeneratorContext -import org.eclipse.xtext.nodemodel.util.NodeModelUtils -import org.eclipse.xtext.resource.XtextResource -import org.eclipse.xtext.validation.CheckMode -import org.eclipse.xtext.xbase.lib.* -import org.lflang.* -import org.lflang.Target -import org.lflang.federated.FedASTUtils -import org.lflang.graph.InstantiationGraph -import org.lflang.lf.* -import org.lflang.validation.AbstractLFValidator -import java.io.* -import java.net.URI -import java.nio.file.Files -import java.nio.file.Path -import java.nio.file.Paths -import java.nio.file.StandardCopyOption -import java.util.* -import java.util.regex.Pattern -import kotlin.collections.LinkedHashMap -import kotlin.collections.LinkedHashSet -import kotlin.math.max -import kotlin.math.min - -/** - * Generator base class for shared code between code generators. - * This extends AbstractLinguaFrancaValidator so that errors can be highlighted - * in the XText-based IDE. - * - * @property target The target which this generator handles - * @property supportsGenerics True if the target supports generics (i.e., parametric polymorphism), false otherwise. - * - * @author {Edward A. Lee @berkeley.edu>} - * @author {Marten Lohstroh @berkeley.edu>} - * @author {Christian Menard @tu-dresden.de} - * @author {Matt Weber @berkeley.edu>} - */ -abstract class KtGeneratorBase( - val target: Target, - val supportsGenerics: Boolean -) : AbstractLFValidator(), GeneratorApi { - - /** - * Defines the execution environment that is used to execute binaries. - * - * A given command may be directly executable on the host (NATIVE) - * or it may need to be executed within a bash shell (BASH). - * On Unix-like machines, this is typically determined by the PATH variable - * which could be different in these two environments. - */ - enum class ExecutionEnvironment { - NATIVE, BASH - } - - /** - * Parsed error message from a compiler is returned here. - */ - protected class ErrorFileAndLine { - var filepath = null as String? - var line = "1" - var character = "0" - var message = "" - var isError = true - } - - /** - * All code goes into this string buffer. - */ - protected var code = StringBuilder() - - /** - * The current target configuration. - */ - protected var targetConfig = TargetConfig() - - /** - * The current file configuration. NOTE: not initialized until the - * invocation of doGenerate, which calls setFileConfig. - */ - protected var fileConfig: FileConfig? = null - - /** - * [Mode.STANDALONE][.Mode.STANDALONE] if the code generator is being - * called from the command line, [Mode.INTEGRATED][.Mode.INTEGRATED] - * if it is being called from the Eclipse IDE, and - * [Mode.UNDEFINED][.Mode.UNDEFINED] otherwise. - */ - var mode = Mode.UNDEFINED - - /** - * Collection of generated delay classes. - */ - private val delayClasses = LinkedHashSet() - - /** - * Set the fileConfig field to point to the specified resource using the specified - * file-system access and context. - * @param resource The resource (Eclipse-speak for a file). - * @param fsa The Xtext abstraction for the file system. - * @param context The generator context (whatever that is). - */ - open fun setFileConfig(resource: Resource, fsa: IFileSystemAccess2, context: IGeneratorContext) { - fileConfig = FileConfig(resource, fsa, context) - topLevelName = fileConfig!!.name - } - - /** - * Indicator of whether generator errors occurred. - * This is set to true by the report() method and returned by the - * errorsOccurred() method. - */ - protected var generatorErrorsOccurred = false - - /** - * If running in an Eclipse IDE, the iResource refers to the - * IFile representing the Lingua Franca program. - * This is the XText view of the file, which is distinct - * from the Eclipse eCore view of the file and the OS view of the file. - */ - protected var iResource = null as IResource? - - /** - * The main (top-level) reactor instance. - */ - protected var main: ReactorInstance? = null - - /** - * Definition of the main (top-level) reactor. - * This is an automatically generated AST node for the top-level - * reactor. - */ - protected var mainDef: Instantiation? = null - - /** - * A list of Reactor definitions in the main resource, including non-main - * reactors defined in imported resources. These are ordered in the list in - * such a way that each reactor is preceded by any reactor that it instantiates - * using a command like `foo = new Foo();` - */ - protected var reactors: MutableList = mutableListOf() - - /** - * The set of resources referenced reactor classes reside in. - */ - protected var resources: MutableSet = CollectionLiterals.newLinkedHashSet() - - /** - * Graph that tracks dependencies between instantiations. - * This is a graph where each node is a Reactor (not a ReactorInstance) - * and an arc from Reactor A to Reactor B means that B contains an instance of A, constructed with a statement - * like `a = new A();` After creating the graph, - * sort the reactors in topological order and assign them to the reactors class variable. - * Hence, after this method returns, `this.reactors` will be a list of Reactors such that any - * reactor is preceded in the list by reactors that it instantiates. - */ - protected var instantiationGraph: InstantiationGraph? = null - - /** - * The set of unordered reactions. An unordered reaction is one that does - * not have any dependency on other reactions in the containing reactor, - * and where no other reaction in the containing reactor depends on it. - * There is currently no way in the syntax of LF to make a reaction - * unordered, deliberately, because it can introduce unexpected - * nondeterminacy. However, certain automatically generated reactions are - * known to be safe to be unordered because they do not interact with the - * state of the containing reactor. To make a reaction unordered, when - * the Reaction instance is created, add that instance to this set. - */ - protected var unorderedReactions: MutableSet? = null - - /** - * Indicates whether or not the current Lingua Franca program - * contains a federation. - */ - protected var isFederated = false - - /** - * A list of federate instances or a list with a single empty string - * if there are no federates specified. FIXME: Why put a single empty string there? It should be just empty... - */ - protected var federates: MutableList = LinkedList() - - /** - * A map from federate IDs to federate instances. - */ - protected var federateByID: MutableMap = LinkedHashMap() - - /** - * A map from instantiations to the federate instances for that instantiation. - * If the instantiation has a width, there may be more than one federate instance. - */ - protected var federatesByInstantiation: MutableMap>? = null - - /** - * The federation RTI properties, which defaults to 'localhost: 15045'. - */ - protected val federationRTIProperties = mutableMapOf( - "host" to "localhost", - "port" to 0 - ) - - /** - * Contents of $LF_CLASSPATH, if it was set. - */ - protected var classpathLF: String? = null - - /** - * The index available to user-generated reaction that delineates the index - * of the reactor in a bank of reactors. The value must be set to zero - * in generated code for reactors that are not in a bank - */ - protected var targetBankIndex = "bank_index" - - /** - * The type of the bank index, which must be an integer in the target language - */ - protected var targetBankIndexType = "int" - - /** - * The name of the top-level reactor. - */ - protected var topLevelName: String? = null - - /** - * Map from builder to its current indentation. - */ - private val indentation = LinkedHashMap() - - /** - * Store the given reactor in the collection of generated delay classes - * and insert it in the AST under the top-level reactors node. - */ - fun addDelayClass(generatedDelay: Reactor) { - delayClasses.add(generatedDelay) - val model = fileConfig!!.resource.allContents.asSequence().mapNotNull { it as? Model }.firstOrNull() - model?.reactors?.add(generatedDelay) - } - - /** - * Return the generated delay reactor that corresponds to the given class - * name if it had been created already, `null` otherwise. - */ - fun findDelayClass(className: String): Reactor? = - delayClasses.firstOrNull { it.name == className } - - - fun setTargetConfig(context: IGeneratorContext) { - // If there are any physical actions, ensure the threaded engine is used. - for (action in fileConfig!!.resource.allContents.asSequence().filterIsInstance()) { - if (action.origin == ActionOrigin.PHYSICAL) { - targetConfig.threads = 1 - } - } - - val target = fileConfig!!.resource.findTarget() - if (target.config != null) { - // Update the configuration according to the set target properties. - TargetProperty.update(this.targetConfig, target.config.pairs ?: emptyList()) - } - - // Override target properties if specified as command line arguments. - if (context is StandaloneContext) { - if (context.args.containsKey("no-compile")) { - targetConfig.noCompile = true - } - if (context.args.containsKey("threads")) { - targetConfig.threads = Integer.parseInt(context.args.getProperty("threads")) - } - if (context.args.containsKey("target-compiler")) { - targetConfig.compiler = context.args.getProperty("target-compiler") - } - if (context.args.containsKey("target-flags")) { - targetConfig.compilerFlags.clear() - if (context.args.getProperty("target-flags").isNotEmpty()) { - targetConfig.compilerFlags.addAll(context.args.getProperty("target-flags").split(' ')) - } - } - } - } - - /** - * If there is a main or federated reactor, then create a synthetic Instantiation - * for that top-level reactor and set the field mainDef to refer to it. - */ - fun createMainInstance() { - // Find the main reactor and create an AST node for its instantiation. - for (reactor in fileConfig!!.resource.allContents.asSequence().filterIsInstance()) { - if (reactor.isMain || reactor.isFederated) { - // Creating an definition for the main reactor because there isn't one. - this.mainDef = LfFactory.eINSTANCE.createInstantiation().apply { - name = reactor.name - reactorClass = reactor - } - } - } - } - - /** - * Generate code from the Lingua Franca model contained by the specified resource. - * - * This is the main entry point for code generation. This base class finds all - * reactor class definitions, including any reactors defined in imported .lf files - * (except any main reactors in those imported files), and adds them to the - * [reactors][.GeneratorBase.reactors] list. If errors occur during - * generation, then a subsequent call to errorsOccurred() will return true. - * @param resource The resource containing the source code. - * @param fsa The file system access (used to write the result). - * @param context Context relating to invocation of the code generator. - * In stand alone mode, this object is also used to relay CLI arguments. - */ - open fun doGenerate(resource: Resource, fsa: IFileSystemAccess2, context: IGeneratorContext) { - - setFileConfig(resource, fsa, context) - - setMode() - - printInfo() - - // Clear any markers that may have been created by a previous build. - // Markers mark problems in the Eclipse IDE when running in integrated mode. - clearMarkers() - - val fileConfig = fileConfig!! - ASTUtils.setMainName(fileConfig.resource, fileConfig.name) - - createMainInstance() - - // Check if there are any conflicting main reactors elsewhere in the package. - if (mainDef != null) { - for (conflict in MainConflictChecker(fileConfig).conflicts) { - reportError(this.mainDef!!.reactorClass, "Conflicting main reactor in $conflict") - } - } - - setTargetConfig(context) - - // If federates are specified in the target, create a mapping - // from Instantiations in the main reactor to federate names. - // Also create a list of federate names or a list with a single - // empty name if there are no federates specified. - // This must be done before desugaring delays below. - analyzeFederates() - - // Process target files. Copy each of them into the src-gen dir. - copyUserFiles() - - // Collect reactors and create an instantiation graph. These are needed to figure out which resources we need - // to validate, which happens in setResources(). - setReactorsAndInstantiationGraph() - - // Collect the reactors defined in this resource (i.e., file in Eclipse speak) and (non-main) - // reactors defined in imported resources. - setResources(context) - - // Reroute connections that have delays associated with them via generated delay reactors. - transformDelays() - - // Invoke this function a second time because transformations may have introduced new reactors! - setReactorsAndInstantiationGraph() - - // First, produce any preamble code that the code generator needs - // to produce before anything else goes into the code generated files. - generatePreamble() // FIXME: Move this elsewhere. See awkwardness with CppGenerator because it will not even - // use the result. - } - - /** - * Create a new instantiation graph. This is a graph where each node is a Reactor (not a ReactorInstance) - * and an arc from Reactor A to Reactor B means that B contains an instance of A, constructed with a statement - * like `a = new A();` After creating the graph, - * sort the reactors in topological order and assign them to the reactors class variable. - * Hence, after this method returns, `this.reactors` will be a list of Reactors such that any - * reactor is preceded in the list by reactors that it instantiates. - */ - protected fun setReactorsAndInstantiationGraph() { - // Build the instantiation graph . - val fileConfig = fileConfig!! - val instantiationGraph = InstantiationGraph(fileConfig.resource, false) - this.instantiationGraph = instantiationGraph - - // Topologically sort the reactors such that all of a reactor's instantiation dependencies occur earlier in - // the sorted list of reactors. This helps the code generator output code in the correct order. - // For example if `reactor Foo {bar = new Bar()}` then the definition of `Bar` has to be generated before - // the definition of `Foo`. - this.reactors = instantiationGraph.nodesInTopologicalOrder() - - // If there is no main reactor, then make sure the reactors list includes - // even reactors that are not instantiated anywhere. - if (mainDef === null) { - for (r in fileConfig.resource.allContents.asSequence().filterIsInstance()) { - if (r !in this.reactors) { - this.reactors.add(r) - } - } - } - } - - /** - * For each involved resource, replace connections with delays with generated delay reactors. - */ - protected fun transformDelays() { - for (r in resources) { - insertGeneratedDelays(r, this) - } - } - - /** - * Update the class variable that lists all the involved resources. Also report validation problems of imported - * resources at the import statements through those failing resources are reached. - * - * @param context The context providing the cancel indicator used by the validator. - */ - protected fun setResources(context: IGeneratorContext) { - val fileConfig = this.fileConfig!! - val validator = (fileConfig.resource as XtextResource).resourceServiceProvider.resourceValidator - val mainDef = mainDef - if (mainDef != null) { - reactors.add(mainDef.reactorClass as Reactor) - } - // Iterate over reactors and mark their resources as tainted if they import resources that are either marked - // as tainted or fail to validate. - val tainted = mutableSetOf() - for (r in this.reactors) { - val res = r.eResource() - if (!this.resources.contains(res)) { - if (res !== fileConfig.resource) { - if (tainted.contains(res) - || validator.validate(res, CheckMode.ALL, context.cancelIndicator).isNotEmpty() - ) { - - for (inst in this.instantiationGraph!!.getDownstreamAdjacentNodes(r)) { - for (imp in (inst.eContainer() as Model).imports) { - for (decl in imp.reactorClasses) { - if (decl.reactorClass.eResource() === res) { - reportError(imp, """Unresolved compilation issues in "${imp.importURI}".""") - tainted.add(decl.eResource()) - } - } - } - } - } - } - this.resources.add(res) - } - } - } - - /** - * Copy all files listed in the target property `files` into the - * specified directory. - */ - protected open fun copyUserFiles() { -// Make sure the target directory exists. - val fileConfig = this.fileConfig!! - val targetDir = fileConfig.srcGenPath!! - Files.createDirectories(targetDir) - - for (filename in targetConfig.fileNames) { - val file: File? = FileConfig.findFile(filename, fileConfig.srcFile.parent) - if (file != null) { - val target = targetDir.resolve(file.name) - Files.deleteIfExists(target) - Files.copy(file.toPath(), target) - targetConfig.filesNamesWithoutPath.add(file.name) - } else { - // Try to copy the file as a resource. - // If this is missing, it should have been previously reported as an error. - try { - val filenameWithoutPath = filename.substringAfterLast(File.separatorChar) - copyFileFromClassPath(filename, targetDir.resolve(filenameWithoutPath).toString()) - targetConfig.filesNamesWithoutPath.add(filenameWithoutPath) - } catch (ex: IOException) { - // Ignore. Previously reported as a warning. - System.err.println("WARNING: Failed to find file $filename.") - } - } - } - } - - /** - * Return true if errors occurred in the last call to doGenerate(). - * This will return true if any of the reportError methods was called. - * @return True if errors occurred. - */ - fun errorsOccurred(): Boolean { - return generatorErrorsOccurred - } - - /** - * Generate code for the body of a reaction that takes an input and - * schedules an action with the value of that input. - * @param action the action to schedule - * @param port the port to read from - */ - abstract fun generateDelayBody(action: Action, port: VarRef): String? - - /** - * Generate code for the body of a reaction that is triggered by the - * given action and writes its value to the given port. - * @param action the action that triggers the reaction - * @param port the port to write to - */ - abstract fun generateForwardBody(action: Action, port: VarRef): String? - - /** - * Generate code for the generic type to be used in the class definition - * of a generated delay reactor. - */ - abstract fun generateDelayGeneric(): String? - - /** - * Generate code for referencing a port, action, or timer. - * @param reference The referenced variable. - */ - fun generateVarRef(reference: VarRef): String { - var prefix = "" - if (reference.container != null) { - prefix = reference.container.name + "." - } - return prefix + reference.variable.name - } - - - /** - * Generate code for referencing a port possibly indexed by - * a bank index and/or a multiport index. This assumes the target language uses - * the usual array indexing [n] for both cases. If not, this needs to be overridden - * by the target code generator. If the provided reference is not a port, then - * this return the string "ERROR: not a port.". - * @param reference The reference to the port. - * @param bankIndex A bank index or null or negative if not in a bank. - * @param multiportIndex A multiport index or null if not in a multiport. - */ - fun generatePortRef( reference:VarRef, bankIndex:Int?, multiportIndex:Int?):String { - if (reference.variable !is Port) { - return "ERROR: not a port." - } - var prefix = "" - if (reference.container != null) { - var bank = "" - if (reference.container.widthSpec != null && bankIndex != null) { - bank = "[$bankIndex]" - } - prefix = reference.container.name + bank + "." - } - var multiport = "" - if ((reference.variable as Port).widthSpec != null && multiportIndex != null && multiportIndex >= 0) { - multiport = "[$multiportIndex]" - } - return prefix + reference.variable.name + multiport - } - - - /** - * Return true if the reaction is unordered. An unordered reaction is one - * that does not have any dependency on other reactions in the containing - * reactor, and where no other reaction in the containing reactor depends - * on it. There is currently no way in the syntax of LF to make a reaction - * unordered, deliberately, because it can introduce unexpected - * nondeterminacy. However, certain automatically generated reactions are - * known to be safe to be unordered because they do not interact with the - * state of the containing reactor. To make a reaction unordered, when - * the Reaction instance is created, add that instance to this set. - * @return True if the reaction has been marked unordered. - */ - fun isUnordered(reaction: Reaction): Boolean = - unorderedReactions?.contains(reaction) == true - - /** - * Mark the reaction unordered. An unordered reaction is one that does not - * have any dependency on other reactions in the containing reactor, and - * where no other reaction in the containing reactor depends on it. There - * is currently no way in the syntax of LF to make a reaction unordered, - * deliberately, because it can introduce unexpected nondeterminacy. - * However, certain automatically generated reactions are known to be safe - * to be unordered because they do not interact with the state of the - * containing reactor. To make a reaction unordered, when the Reaction - * instance is created, add that instance to this set. - * @param reaction The reaction to make unordered. - */ - override fun makeUnordered(reaction: Reaction): Boolean = - unorderedReactions?.add(reaction) ?: let { - unorderedReactions = mutableSetOf(reaction) - true - } - - /** - * Given a representation of time that may possibly include units, return - * a string that the target language can recognize as a value. In this base - * class, if units are given, e.g. "msec", then we convert the units to upper - * case and return an expression of the form "MSEC(value)". Particular target - * generators will need to either define functions or macros for each possible - * time unit or override this method to return something acceptable to the - * target language. - * @param time A TimeValue that represents a time. - * @return A string, such as "MSEC(100)" for 100 milliseconds. - */ - open fun timeInTargetLanguage(time: TimeValue?): String = - if (time != null) { - if (time.unit != TimeUnit.NONE) { - time.unit.name + '(' + time.time + ')' - } else { - time.time.toString() - } - } else - "0" // FIXME: do this or throw exception? - - /** - * Create the runtime infrastructure (RTI) source file. - */ - open fun createFederateRTI() { - val fileConfig = fileConfig!! - - // Derive target filename from the .lf filename. - val cFilename = fileConfig.name + "_RTI.c" - - // Delete source previously produced by the LF compiler. - var file = fileConfig.rtiSrcPath.resolve(cFilename) - Files.deleteIfExists(file) - // Also make sure the directory exists. - Files.createDirectories(file.parent) - - // Delete binary previously produced by the C compiler. - file = fileConfig.rtiBinPath.resolve(fileConfig.name) - Files.deleteIfExists(file) - - val rtiCode = StringBuilder() - pr( - rtiCode, """ - #ifdef NUMBER_OF_FEDERATES - #undefine NUMBER_OF_FEDERATES - #endif - #define NUMBER_OF_FEDERATES ${federates.size} - #include "rti.c" - int main(int argc, char* argv[]) { - """ - ) - indent(rtiCode) - - // Initialize the array of information that the RTI has about the - // federates. - // FIXME: No support below for some federates to be FAST and some REALTIME. - pr( - rtiCode, """ - for (int i = 0; i < NUMBER_OF_FEDERATES; i++) { - initialize_federate(i); - ${ - if (targetConfig.fastMode) - "federates[i].mode = FAST;" - else "" - } - } - """ - ) - // Initialize the arrays indicating connectivity to upstream and downstream federates. - for (federate in federates) { - if (federate.dependsOn.isNotEmpty()) { - // Federate receives non-physical messages from other federates. - // Initialize the upstream and upstream_delay arrays. - val numUpstream = federate.dependsOn.size - // Allocate memory for the arrays storing the connectivity information. - pr( - rtiCode, """ - federates[${federate.id}].upstream = (int*)malloc(sizeof(federate_t*) * ${numUpstream}); - federates[${federate.id}].upstream_delay = (interval_t*)malloc(sizeof(interval_t*) * ${numUpstream}); - federates[${federate.id}].num_upstream = ${numUpstream}; - """ - ) - // Next, populate these arrays. - // Find the minimum delay in the process. - // FIXME: Zero delay is not really the same as a microstep delay. - var count = 0 - for (upstreamFederate in federate.dependsOn.keys) { - pr( - rtiCode, """ - federates[${federate.id}].upstream[${count}] = ${upstreamFederate.id}; - federates[${federate.id}].upstream_delay[${count}] = 0LL; - """ - ) - // The minimum delay calculation needs to be made in the C code because it - // may depend on parameter values. - // FIXME: These would have to be top-level parameters, which don't really - // have any support yet. Ideally, they could be overridden on the command line. - // When that is done, they will need to be in scope here. - val delays = federate.dependsOn[upstreamFederate].orEmpty() - for (delay in delays) { - pr( - rtiCode, """ - if (federates[${federate.id}].upstream_delay[${count}] < ${delay.rtiTime}) { - federates[${federate.id}].upstream_delay[${count}] = ${delay.rtiTime}; - } - """ - ) - } - count++ - } - } - // Next, set up the downstream array. - if (federate.sendsTo.isNotEmpty()) { - // Federate sends non-physical messages to other federates. - // Initialize the downstream array. - val numDownstream = federate.sendsTo.size - // Allocate memory for the array. - pr( - rtiCode, """ - federates[${federate.id}].downstream = (int*)malloc(sizeof(federate_t*) * ${numDownstream}); - federates[${federate.id}].num_downstream = ${numDownstream}; - """ - ) - // Next, populate the array. - // Find the minimum delay in the process. - // FIXME: Zero delay is not really the same as a microstep delay. - for ((count, downstreamFederate) in federate.sendsTo.keys.withIndex()) { - pr( - rtiCode, """ - federates[${federate.id}].downstream[${count}] = ${downstreamFederate.id}; - """ - ) - } - } - } - - // Start the RTI server before launching the federates because if it - // fails, e.g. because the port is not available, then we don't want to - // launch the federates. - // Also generate code that blocks until the federates resign. - pr( - rtiCode, """ - int socket_descriptor = start_rti_server(${federationRTIProperties["port"]}); - wait_for_federates(socket_descriptor); - """ - ) - - unindent(rtiCode) - pr(rtiCode, "}") - - Files.write( - fileConfig.rtiSrcPath.resolve(cFilename), - rtiCode.toString().toByteArray() - ) - } - - /** - * Invoke the C compiler on the generated RTI - * The C RTI is used across targets. Thus we need to be able to compile - * it from GeneratorBase. - */ - fun compileRTI(): Boolean { - val fileToCompile = fileConfig!!.name + "_RTI" - return runCCompiler(fileToCompile, false) - } - - /** - * Run the C compiler. - * - * This is required here in order to allow any target to compile the RTI. - * - * @param file The source file to compile without the .c extension. - * @param doNotLinkIfNoMain If true, the compile command will have a - * `-c` flag when there is no main reactor. If false, the compile command - * will never have a `-c` flag. - * - * @return true if compilation succeeds, false otherwise. - */ - open fun runCCompiler(file: String, doNotLinkIfNoMain: Boolean): Boolean { - val compile = compileCCommand(file, doNotLinkIfNoMain) ?: return false - - val stderr = ByteArrayOutputStream() - val returnCode = compile.executeCommand(errStream = stderr) - - if (returnCode != 0 && mode !== Mode.INTEGRATED) { - reportError("""${targetConfig.compiler} returns error code $returnCode""") - } - // For warnings (vs. errors), the return code is 0. - // But we still want to mark the IDE. - if (stderr.size() > 0 && mode === Mode.INTEGRATED) { - reportCommandErrors(stderr.toString()) - } - return (returnCode == 0) - } - - /** - * Run the custom build command specified with the "build" parameter. - * This command is executed in the same directory as the source file. - */ - protected fun runBuildCommand() { - val commands = mutableListOf() - for (cmd in targetConfig.buildCommands) { - val tokens = cmd.split("\\s+") - if (tokens.size > 1) { - val buildCommand = createCommand(tokens.first(), tokens.tail(), this.fileConfig!!.srcPath) - ?: return - // If the build command could not be found, abort. - // An error has already been reported in createCommand. - commands.add(buildCommand) - } - } - - for (cmd in commands) { - val stderr = ByteArrayOutputStream() - val returnCode = cmd.executeCommand(errStream = stderr) - - if (returnCode != 0 && mode !== Mode.INTEGRATED) { - reportError("""Build command "${targetConfig.buildCommands}" returns error code $returnCode""") - return - } - // For warnings (vs. errors), the return code is 0. - // But we still want to mark the IDE. - if (stderr.size() > 0 && mode == Mode.INTEGRATED) { - reportCommandErrors(stderr.toString()) - return - } - } - } - - /** - * Return a command to compile the specified C file. - * This produces a C specific compile command. Since this command is - * used across targets to build the RTI, it needs to be available in - * GeneratorBase. - * - * @param fileToCompile The C filename without the .c extension. - * @param doNotLinkIfNoMain If true, the compile command will have a - * `-c` flag when there is no main reactor. If false, the compile command - * will never have a `-c` flag. - */ - protected fun compileCCommand(fileToCompile: String, doNotLinkIfNoMain: Boolean): ProcessBuilder? { - val env = findCommandEnv(targetConfig.compiler) - - val cFilename = getTargetFileName(fileToCompile) - val fileConfig = fileConfig!! - - val relativeSrcPath = fileConfig.outPath.relativize(fileConfig.srcGenPath.resolve(cFilename)) - val relativeBinPath = fileConfig.outPath.relativize(fileConfig.binPath.resolve(fileToCompile)) - - // NOTE: we assume that any C compiler takes Unix paths as arguments. - val relSrcPathString = FileConfig.toUnixString(relativeSrcPath) - var relBinPathString = FileConfig.toUnixString(relativeBinPath) - - // If there is no main reactor, then generate a .o file not an executable. - if (mainDef === null) { - relBinPathString += ".o" - } - - val compileArgs = mutableListOf() - compileArgs.add(relSrcPathString) - compileArgs.addAll(targetConfig.compileAdditionalSources) - compileArgs.addAll(targetConfig.compileLibraries) - - // Only set the output file name if it hasn't already been set - // using a target property or Args line flag. - if (compileArgs.all { it.trim() != "-o" }) { - compileArgs.addAll(listOf("-o", relBinPathString)) - } - - // If threaded computation is requested, add a -pthread option. - - if (targetConfig.threads != 0 || targetConfig.tracing != null) { - compileArgs.add("-pthread") - // If the LF program itself is threaded or if tracing is enabled, we need to define - // NUMBER_OF_WORKERS so that platform-specific C files will contain the appropriate functions - compileArgs.add("-DNUMBER_OF_WORKERS=${targetConfig.threads}") - } - // Finally add the compiler flags in target parameters (if any) - if (targetConfig.compilerFlags.isNotEmpty()) { - compileArgs.addAll(targetConfig.compilerFlags) - } - // If there is no main reactor, then use the -c flag to prevent linking from occurring. - // FIXME: we could add a `-c` flag to `lfc` to make this explicit in stand-alone mode. - // Then again, I think this only makes sense when we can do linking. - // In any case, a warning is helpful to draw attention to the fact that no binary was produced. - if (doNotLinkIfNoMain && main == null) { - compileArgs.add("-c") // FIXME: revisit - if (mode == Mode.STANDALONE) { - reportError("ERROR: Did not output executable; no main reactor found.") - } - } - return createCommand(targetConfig.compiler, compileArgs, fileConfig.outPath, env) - } - - /** - * Produces the filename including the target-specific extension - */ - protected open fun getTargetFileName(fileName: String): String = "$fileName.c" - - /** - * Clear the buffer of generated code. - */ - protected fun clearCode(): StringBuilder = StringBuilder().also { this.code = it } - - /** - * Get the specified file as an Eclipse IResource or, if it is not found, then - * return the iResource for the main file. - * For some inexplicable reason, Eclipse uses a mysterious parallel to the file - * system, and when running in INTEGRATED mode, for some things, you cannot access - * files by referring to their file system location. Instead, you have to refer - * to them relative the workspace root. This is required, for example, when marking - * the file with errors or warnings or when deleting those marks. - * - * @param uri A java.net.uri of the form "file://path". - */ - protected fun getEclipseResource(uri: URI?): IResource? { - var resource = iResource // Default resource. - // For some peculiar reason known only to Eclipse developers, - // the resource cannot be used directly but has to be converted - // a resource relative to the workspace root. - val workspaceRoot = ResourcesPlugin.getWorkspace().root - // The following uses a java.net.URI, which, - // pathetically, cannot be distinguished in xtend from a org.eclipse.emf.common.util.URI. - if (uri != null) { - // Pathetically, Eclipse requires a java.net.uri, not a org.eclipse.emf.common.util.URI. - val files = workspaceRoot.findFilesForLocationURI(uri) - if (files != null && files.isNotEmpty() && files[0] != null) { - resource = files[0] - } - } - return resource - } - - /** - * Clear markers in the IDE if running in integrated mode. - * This has the side effect of setting the iResource variable to point to - * the IFile for the Lingua Franca program. - * Also reset the flag indicating that generator errors occurred. - */ - protected fun clearMarkers(): Boolean { - if (mode == Mode.INTEGRATED) { - try { - val resource = getEclipseResource(fileConfig!!.srcFile.toURI()) - // First argument can be null to delete all markers. - // But will that delete xtext markers too? - resource?.deleteMarkers(IMarker.PROBLEM, true, IResource.DEPTH_INFINITE) - } catch (e: Exception) { - // Ignore, but print a warning. - println("Warning: Deleting markers in the IDE failed: $e") - } - } - generatorErrorsOccurred = false - return false - } - - /** - * Run a given command and record its output. - * - * @receiver the command to be executed - * @param errStream a stream object to forward the commands error messages to - * @param outStream a stream object to forward the commands output messages to - * @return the commands return code - */ - protected fun ProcessBuilder.executeCommand(errStream: OutputStream? = null, outStream: OutputStream? = null): Int { - println("--- Current working directory: \${cmd.directory.toString()}") - println("--- Executing command: ${command().joinToString(" ")}") - - val outStreams = mutableListOf() - val errStreams = mutableListOf() - outStreams.add(System.out) - errStreams.add(System.err) - if (outStream != null) { - outStreams.add(outStream) - } - if (errStream != null) { - errStreams.add(errStream) - } - - // Execute the command. Write output to the System output, - // but also keep copies in outStream and errStream - return runSubprocess(outStreams, errStreams) - - } - - /** - * It tries to find the command with 'which ' (or 'where ' on Windows). - * If that fails, it tries again with bash. - * In case this fails again, raise an error. - * - * Return ExecutionEnvironment.NATIVE - * if the specified command is directly executable on the current host - * Returns ExecutionEnvironment.BASH - * if the command must be executed within a bash shell. - * - * The latter occurs, for example, if the specified command - * is not in the native path but is in the path - * specified by the user's bash configuration file. - * If the specified command is not found in either the native environment - * nor the bash environment, - * then this reports and error and returns null. - * - * @param cmd The command to be find. - * @return Returns an ExecutionEnvironment. - */ - protected fun findCommandEnv(cmd: String): ExecutionEnvironment? { - // Make sure the command is found in the PATH. - print("--- Looking for command $cmd ...") - // Use 'where' on Windows, 'which' on other systems - val which = if (System.getProperty("os.name").startsWith("Windows")) "where" else "which" - val whichBuilder = ProcessBuilder(which, cmd) - val whichReturn = whichBuilder.start().waitFor() - if (whichReturn == 0) { - println("SUCCESS") - - return ExecutionEnvironment.NATIVE - } - println("FAILED") - // Try running with bash. - // The --login option forces bash to look for and load the first of - // ~/.bash_profile, ~/.bash_login, and ~/.bashrc that it finds. - print("--- Trying again with bash ... ") - val bashCommand = listOf("bash", "--login", "-c", "which $cmd") - val bashBuilder = ProcessBuilder(bashCommand) - val bashOut = ByteArrayOutputStream() - val bashReturn = bashBuilder.runSubprocess(listOf(bashOut), listOf()) - if (bashReturn == 0) { - println("SUCCESS") - return ExecutionEnvironment.BASH - } - reportError( - """The command $cmd could not be found. -Make sure that your PATH variable includes the directory where $cmd is installed. -You can set PATH in ~/.bash_profile on Linux or Mac.""" - ) - return null - - } - - /** - * Create a ProcessBuilder for a given command. - * - * This method makes sure that the given command is executable, - * It first tries to find the command with 'which cmake'. If that - * fails, it tries again with bash. In case this fails again, - * it returns null. Otherwise, a correctly constructed ProcessBuilder - * object is returned. - * - * A bit more context: - * If the command cannot be found directly, then a second attempt is made using a - * Bash shell with the --login option, which sources the user's - * ~/.bash_profile, ~/.bash_login, or ~/.bashrc (whichever - * is first found) before running the command. This helps to ensure that - * the user's PATH variable is set according to their usual environment, - * assuming that they use a bash shell. - * - * More information: Unfortunately, at least on a Mac if you are running - * within Eclipse, the PATH variable is extremely limited; supposedly, it - * is given by the default provided in /etc/paths, but at least on my machine, - * it does not even include directories in that file for some reason. - * One way to add a directory like - * /usr/local/bin to the path once-and-for-all is this: - * - * sudo launchctl config user path /usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin - * - * But asking users to do that is not ideal. Hence, we try a more hack-y - * approach of just trying to execute using a bash shell. - * Also note that while ProcessBuilder can configured to use custom - * environment variables, these variables do not affect the command that is - * to be executed but merely the environment in which the command executes. - * - * @param cmd The command to be executed - * @param args A list of arguments for the given command - * @param dir the directory to change into before executing the command. - * @param env is the type of the Execution Environment. - * @return A ProcessBuilder object if the command was found or null otherwise. - */ - protected fun createCommand( - cmd: String, - args: List = emptyList(), - dir: Path = fileConfig!!.outPath, - env: ExecutionEnvironment? = findCommandEnv(cmd) - ): ProcessBuilder? { - if (env == ExecutionEnvironment.NATIVE) { - val builder = ProcessBuilder(cmd, *args.toTypedArray()) - builder.directory(dir.toFile()) - return builder - } else if (env == ExecutionEnvironment.BASH) { - val bashArg = args.joinToString(separator = " ", prefix = "$cmd ") - // use that command to build the process - val builder = ProcessBuilder("bash", "--login", "-c", bashArg) - builder.directory(dir.toFile()) - return builder - } - println("FAILED") - reportError( - """The command $cmd could not be found. -Make sure that your PATH variable includes the directory where $cmd is installed. -You can set PATH in ~/.bash_profile on Linux or Mac.""" - ) - return null - } - - /** - * Creates a ProcessBuilder for a given command and its arguments. - * - * This method returns correctly constructed ProcessBuilder object - * according to the Execution environment. It finds the execution environment using findCommandEnv(). - * Raise an error if the env is null. - * - * @param cmd The command to be executed - * @param args A list of arguments for the given command - * @return A ProcessBuilder object if the command was found or null otherwise. - */ - protected fun createCommand(cmd: String, args: List, dir: Path): ProcessBuilder? { - val env = findCommandEnv(cmd) - return this.createCommand(cmd, args, dir, env) - } - - /** - * Generate any preamble code that appears in the code generated - * file before anything else. - */ - protected open fun generatePreamble() { - prComment("Code generated by the Lingua Franca compiler from:") - prComment("file:/" + FileConfig.toUnixString(fileConfig!!.srcFile.toPath())) - val models = this.reactors.map { - // This assumes all reactors have a container. - // This means that generated reactors **have** to be - // added to a resource; not doing so will result in a NPE. - it.toDefinition().eContainer() as Model - }.toMutableSet() - - // Add the main reactor if it is defined - val mainDef = this.mainDef - if (mainDef != null) { - models.add(mainDef.reactorClass.toDefinition().eContainer() as Model) - } - for (m in models) { - for (p in m.preambles) { - pr(p.code.toText()) - } - } - } - - /** Returns the code produced so far. */ - protected fun getCode(): String = code.toString() - - /** - * Increase the indentation of the output code produced - * on the specified builder. - */ - protected fun indent(builder: StringBuilder = this.code): String = - (indentation.getOrDefault(builder, "") + " ").also { - indentation[builder] = it - } - - /** - * Append the specified text plus a final newline to the current - * code buffer. - * @param format A format string to be used by String.format or - * the text to append if no further arguments are given. - * @param args Additional arguments to pass to the formatter. - */ - protected fun pr(format: String, vararg args: Any?): StringBuilder? { - val text = - if (args.isNotEmpty()) String.format(format, args) - else format - return pr(code, text) - } - - /** - * Append the specified text plus a final newline to the specified - * code buffer. - * @param builder The code buffer. - * @param text The text to append. - */ - protected fun pr(builder: StringBuilder, text: Any?): StringBuilder { - // Handle multi-line text. - var string = text.toString() - val indent = indentation[builder] ?: "" - if ('\n' in string) { - // Replace all tabs with four spaces. - string = string.replace("\t", " ") - // Use two passes, first to find the minimum leading white space - // in each line of the source text. - var offset = Integer.MAX_VALUE - // Skip the first line, which has white space stripped. - val (firstLine, rest) = string.lines().headAndTail() - for (line in rest) { - val numLeadingSpaces = line.indexOf(line.trim()) - offset = min(offset, numLeadingSpaces) - } - - // Now make a pass for each line, replacing the offset leading - // spaces with the current indentation. - builder.append(indent).append(firstLine) - for (line in rest) { - builder.append(indent).append(line.substring(offset)).appendLine() - } - } else { - builder.append(indent).append(text).appendLine() - } - return builder - } - - /** - * Prints an indented block of text with the given begin and end markers, - * but only if the actions print any text at all. - * This is helpful to avoid the production of empty blocks. - * @param begin The prologue of the block. - * @param end The epilogue of the block. - * @param actions Actions that print the interior of the block. - */ - protected fun prBlock(begin: String = "", end: String = "", vararg actions: () -> Unit): StringBuilder { - val i = code.length - indent() - for (action in actions) { - action() - } - unindent() - if (i < code.length) { - val inserted = code.substring(i, code.length) - code.delete(i, code.length) - pr(begin) - code.append(inserted) - pr(end) - } - return code - } - - /** - * Leave a marker in the generated code that indicates the original line - * number in the LF source. - * @param eObject The node. - */ - protected open fun prSourceLineNumber(eObject: EObject): StringBuilder { - val startLine = NodeModelUtils.getNode(eObject).startLine - val numToPrint = if (eObject is Code) startLine + 1 else startLine - return pr(code, "// $numToPrint") - } - - /** - * Print a comment to the generated file. - * Particular targets will need to override this if comments - * start with something other than '//'. - * @param comment The comment. - */ - protected fun prComment(comment: String): StringBuilder = - pr(this.code, ("// $comment")) - - /** - * Given a line of text from the output of a compiler, return - * an instance of ErrorFileAndLine if the line is recognized as - * the first line of an error message. Otherwise, return null. - * This base class simply returns null. - * @param line A line of output from a compiler or other external - * tool that might generate errors. - * @return If the line is recognized as the start of an error message, - * then return a class containing the path to the file on which the - * error occurred (or null if there is none), the line number (or the - * string "1" if there is none), the character position (or the string - * "0" if there is none), and the message (or an empty string if there - * is none). - */ - protected open fun parseCommandOutput(line: String?): ErrorFileAndLine? { - return null - } - - /** - * Parse the specified string for command errors that can be reported - * using marks in the Eclipse IDE. In this class, we attempt to parse - * the messages to look for file and line information, thereby generating - * marks on the appropriate lines. This should only be called if - * mode == INTEGRATED. - * - * @param stderr The output on standard error of executing a command. - */ - protected fun reportCommandErrors(stderr: String) { - val message = StringBuilder() - var lineNumber: Int? = null - var resource: IResource? = this.getEclipseResource(this.fileConfig!!.srcFile.toURI()) - val originalResource: IResource? = resource - var severity: Int = IMarker.SEVERITY_ERROR - - for (line in stderr.lines()) { - val parsed = parseCommandOutput(line) - if (parsed != null) { - // Found a new line number designator. - // If there is a previously accumulated message, report it. - - if (message.isNotEmpty()) { - this.report(message.toString(), severity, lineNumber, resource) - if (originalResource != resource) { - // Report an error also in the top-level resource. - // FIXME: It should be possible to descend through the import - // statements to find which one matches and mark all the - // import statements down the chain. But what a pain! - this.report( - "Error in imported file: " + resource?.fullPath, - IMarker.SEVERITY_ERROR, - null, originalResource - ) - } - } - severity = if (parsed.isError) { - IMarker.SEVERITY_ERROR - } else { - IMarker.SEVERITY_WARNING - } - - // Start accumulating a new message. - message.setLength(0) - // Append the message on the line number designator line. - message.append(parsed.message) - - // Set the new line number. - lineNumber = try { - Integer.decode(parsed.line) - } catch (_t: Exception) { - null - } - - // FIXME: Ignoring the position within the line. - // Determine the resource within which the error occurred. - // Sadly, Eclipse defines an interface called "URI" that conflicts with the - // Java one, so we have to give the full class name here. - resource = this.getEclipseResource(URI(parsed.filepath!!)) - } else { - // No line designator. - if (message.isNotEmpty()) { - message.append("\n") - } else { - if ("warning:" in line.toLowerCase()) { - severity = IMarker.SEVERITY_WARNING - } - } - message.append(line) - } - } - - if (message.isNotEmpty()) { - report(message.toString(), severity, lineNumber, resource) - if (originalResource != resource) { - // Report an error also in the top-level resource. - // FIXME: It should be possible to descend through the import - // statements to find which one matches and mark all the - // import statements down the chain. But what a pain! - report( - "Error in imported file: " + resource!!.fullPath, - IMarker.SEVERITY_ERROR, - null, - originalResource - ) - } - } - } - - /** - * Lookup a file in the classpath and copy its contents to a destination path - * in the filesystem. - * - * This also creates new directories for any directories on the destination - * path that do not yet exist. - * - * @param source The source file as a path relative to the classpath. - * @param destination The file system path that the source file is copied to. - */ - protected fun copyFileFromClassPath(source: String, destination: String) { - val sourceStream = this::class.java.getResourceAsStream(source) - ?: throw IOException( - "A required target resource could not be found: " + source + "\n" + - "Perhaps a git submodule is missing or not up to date.\n" + - "See https://github.com/icyphy/lingua-franca/wiki/downloading-and-building#clone-the-lingua-franca-repository.\n" + - "Also try to refresh and clean the project explorer if working from eclipse." - ) - - // Copy the file. - try { - // Make sure the directory exists - val destFile = File(destination) - destFile.parentFile.mkdirs() - - Files.copy(sourceStream, Paths.get(destination), StandardCopyOption.REPLACE_EXISTING) - } catch (ex: IOException) { - throw IOException( - "A required target resource could not be copied: " + source + "\n" + - "Perhaps a git submodule is missing or not up to date.\n" + - "See https://github.com/icyphy/lingua-franca/wiki/downloading-and-building#clone-the-lingua-franca-repository.", - ex - ) - } finally { - sourceStream.close() - } - } - - /** - * Copy a list of files from a given source directory to a given destination directory. - * @param srcDir The directory to copy files from. - * @param dstDir The directory to copy files to. - * @param files The files to copy. - */ - protected fun copyFilesFromClassPath(srcDir: String, dstDir: String, files: List) { - for (file: String in files) { - copyFileFromClassPath("$srcDir/$file", dstDir + File.separator + file) - } - } - - /** - * If the mode is INTEGRATED (the code generator is running in an - * an Eclipse IDE), then refresh the project. This will ensure that - * any generated files become visible in the project. - */ - protected fun refreshProject() { - if (mode == Mode.INTEGRATED) { - // Find name of current project - val id = "((:?[a-z]|[A-Z]|_\\w)*)" - val pattern: Pattern = if (File.separator.equals("/")) { // Linux/Mac file separator - Pattern.compile("platform:" + File.separator + "resource" + File.separator + id + File.separator) - } else { // Windows file separator - Pattern.compile( - "platform:" + File.separator + File.separator + "resource" + File.separator + File.separator + - id + File.separator + File.separator - ) - } - val matcher = pattern.matcher(code) - val projName = if (matcher.find()) matcher.group(1) else "" - - try { - val members = ResourcesPlugin.getWorkspace().root.members() - for (member in members) { - // Refresh current project, or simply entire workspace if project name was not found - if (projName.isEmpty() || projName == member.fullPath.toString().substring(1)) { - member.refreshLocal(IResource.DEPTH_INFINITE, null) - println("Refreshed " + member.fullPath) - } - } - } catch (e: IllegalStateException) { - println("Unable to refresh workspace: $e") - } - } - } - - /** - * Report a warning or error on the specified line of the specified resource. - * The caller should not throw an exception so execution can continue. - * This will print the error message to stderr. - * If running in INTEGRATED mode (within the Eclipse IDE), then this also - * adds a marker to the editor. - * - * @param message The error message. - * @param severity One of IMarker.SEVERITY_ERROR or IMarker.SEVERITY_WARNING - * @param line The line number or null if it is not known. - * @param eObject The Ecore object, or null if it is not known. - * @param resource The resource, or null if it is not known. - */ - protected fun report(message: String, severity: Int, line: Int?, eObject: EObject?, resource: IResource?): String { - if (severity == IMarker.SEVERITY_ERROR) { - generatorErrorsOccurred = true - } - val header = if (severity == IMarker.SEVERITY_ERROR) "ERROR: " else "WARNING: " - val lineAsString = if (line === null) "" else "Line $line" - - val fullPath: String = let { - var p = resource?.fullPath?.toString() - if (p == null) { - if (eObject != null && eObject.eResource() != null) - p = FileConfig.toPath(eObject.eResource()).toString() - if (p == null) { - p = if (line == null) "" else "path unknown" - } - } - p - } - - - System.err.println("$header$fullPath $lineAsString\n$message") - - // If running in INTEGRATED mode, create a marker in the IDE for the error. - // See: https://help.eclipse.org/2020-03/index.jsp?topic=%2Forg.eclipse.platform.doc.isv%2Fguide%2FresAdv_markers.htm - if (mode === Mode.INTEGRATED) { - var myResource = resource - if (myResource === null && eObject != null) { - // Attempt to identify the IResource from the object. - val eResource = eObject.eResource() - if (eResource != null) { - val uri = FileConfig.toPath(eResource).toUri() - myResource = getEclipseResource(uri) - } - } - // If the resource is still null, use the resource associated with - // the top-level file. - if (myResource === null) { - myResource = iResource - } - if (myResource != null) { - val marker = myResource.createMarker(IMarker.PROBLEM) - marker.setAttribute(IMarker.MESSAGE, message) - if (line != null) { - marker.setAttribute(IMarker.LINE_NUMBER, line) - } else { - marker.setAttribute(IMarker.LINE_NUMBER, 1) - } - // Human-readable line number information. - marker.setAttribute(IMarker.LOCATION, lineAsString) - // Mark as an error or warning. - marker.setAttribute(IMarker.SEVERITY, severity) - marker.setAttribute(IMarker.PRIORITY, IMarker.PRIORITY_HIGH) - - marker.setAttribute(IMarker.USER_EDITABLE, false) - - // NOTE: It might be useful to set a start and end. - // marker.setAttribute(IMarker.CHAR_START, 0); - // marker.setAttribute(IMarker.CHAR_END, 5); - } - } - - // Return a string that can be inserted into the generated code. - if (severity == IMarker.SEVERITY_ERROR) { - return "[[ERROR: $message]]" - } - return "" - } - - /** - * Report a warning or error on the specified parse tree object in the - * current resource. - * The caller should not throw an exception so execution can continue. - * If running in INTEGRATED mode (within the Eclipse IDE), then this also - * adds a marker to the editor. - * @param message The error message. - * @param severity One of IMarker.SEVERITY_ERROR or IMarker.SEVERITY_WARNING - * @param `object` The parse tree object or null if not known. - */ - protected fun report(message: String, severity: Int, obj: EObject?): String { - val line = NodeModelUtils.getNode(obj)?.startLine - return report(message, severity, line, obj, null) - } - - /** - * Report a warning or error on the specified parse tree object in the - * current resource. - * The caller should not throw an exception so execution can continue. - * If running in INTEGRATED mode (within the Eclipse IDE), then this also - * adds a marker to the editor. - * @param message The error message. - * @param severity One of IMarker.SEVERITY_ERROR or IMarker.SEVERITY_WARNING - * @param resource The resource. - */ - protected fun report(message: String, severity: Int, line: Int?, resource: IResource?): String { - return this.report(message, severity, line, null, resource) - } - - /** - * Report an error. - * @param message The error message. - */ - override fun reportError(message: String): String { - return this.report(message, IMarker.SEVERITY_ERROR, null) - } - - /** - * Report an error on the specified parse tree object. - * @param eObject The parse tree object. - * @param message The error message. - */ - override fun reportError(eObject: EObject?, message: String): String { - return this.report(message, IMarker.SEVERITY_ERROR, eObject) - } - - /** - * Report a warning on the specified parse tree object. - * @param eObject The parse tree object. - * @param message The error message. - */ - override fun reportWarning(eObject: EObject?, message: String): String { - return this.report(message, IMarker.SEVERITY_WARNING, eObject) - } - - /** - * Reduce the indentation by one level for generated code - * in the default code buffer. - */ - protected fun unindent(builder: StringBuilder = this.code) { - var indent = indentation[builder] ?: return - val end = indent.length - 4 - indent = indent.substring(0, max(0, end)) - indentation[builder] = indent - } - - /** - * Create a list of default parameter initializers in target code. - * @return A list of initializers in target code - */ - protected val Parameter?.initializerList: List - get() { - val ofTimeType = this?.isOfTimeType ?: false - - return this?.init.orEmpty().map { - if (ofTimeType) getTargetTime(it) - else getTargetValue(it) - } - } - - /** - * Create a list of state initializers in target code. - * - * @receiver The state variable to create initializers for - * @return A list of initializers in target code - */ - protected val StateVar.initializerList: List? - get() = if (ASTUtils.isInitialized(this)) { - this.init.orEmpty().map { - when { - it.parameter != null -> getTargetReference(it.parameter) - ASTUtils.isOfTimeType(this) -> getTargetTime(it) - else -> getTargetValue(it) - } - } - } else { - null - } - - /** - * Create a list of parameter initializers in target code in the context - * of an reactor instantiation. - * - * This respects the parameter assignments given in the reactor - * instantiation and falls back to the reactors default initializers - * if no value is assigned to it. - * - * @param param The parameter to create initializers for - * @return A list of initializers in target code - */ - protected fun getInitializerList(param: Parameter?, i: Instantiation?): List? { - if (i == null || param == null) { - return null - } - - val ofTimeType = param.isOfTimeType - - val assignments = i.parameters.filter { it.lhs === param } - - return if (assignments.isEmpty()) { - // the parameter was not overwritten in the instantiation - param.initializerList - } else { - // the parameter was overwritten in the instantiation - assignments[0]?.rhs.orEmpty().map { - if (ofTimeType) getTargetTime(it) - else getTargetValue(it) - } - } - } - - /** - * Generate target code for a parameter reference. - * - * @param param The parameter to generate code for - * @return Parameter reference in target code - */ - protected open fun getTargetReference(param: Parameter): String { - return param.name - } - - /** - * If the receiver is a multiport, return a list of strings - * describing the width of the port, and otherwise, return null. - * If the list is empty, then the width is variable (specified - * as '[]'). Otherwise, it is a list of integers and/or parameter - * references obtained by getTargetReference(). - * @receiver The port. - * @return The width specification for a multiport or null if it is - * not a multiport. - */ - protected fun Variable?.multiportWidthSpec(): List? { - val widthSpec = (this as? Port)?.widthSpec ?: return null - - if (widthSpec.isOfVariableLength) return emptyList() - return widthSpec.terms.map { term -> - val param = term.parameter - if (param != null) getTargetReference(param) - else term.width.toString() - } - } - - /** - * If the receiver is a multiport, then return a string that - * gives the width as an expression, and otherwise, return null. - * The string will be empty if the width is variable (specified - * as '[]'). Otherwise, if is a single term or a sum of terms - * (separated by '+'), where each term is either an integer - * or a parameter reference in the target language. - */ - protected fun Variable?.multiportWidthExpression(): String? = - this.multiportWidthSpec()?.joinToString(separator = " + ") - - - /** - * Return true if the specified port is a multiport. - * @receiver The port. - * @return True if the port is a multiport. - */ - protected val Port.isMultiport: Boolean - get() = widthSpec != null - - /** - * Get textual representation of a time in the target language. - * This is a separate function from - * getTargetTime to avoid producing invalid RTI - * code for targets that override timeInTargetLanguage - * to return a C-incompatible time type. - * - * @param this@getRTITime A time AST node - * @return An RTI-compatible (ie. C target) time string - */ - protected val Delay.rtiTime: String - get() { - if (parameter != null) { - return this.toText() - } - - val time = TimeValue(interval.toLong(), unit) - - return if (time.unit != TimeUnit.NONE) { - time.unit.name + '(' + time.time + ')' - } else { - time.time.toString() - } - } - - /** - * Analyze the resource (the .lf file) that is being parsed - * to determine whether code is being mapped to single or to - * multiple target machines. If it is being mapped to multiple - * machines, then set the 'federates' list, the 'federateIDs' - * map, and the 'federationRTIHost' and 'federationRTIPort' - * variables. - * - * In addition, analyze the connections between federates. - * Ensure that every cycle has a non-zero delay (microstep - * delays will not be sufficient). Construct the dependency - * graph between federates. And replace connections between - * federates with a pair of reactions, one triggered by - * the sender's output port, and the other triggered by - * an action. - * - * This class is target independent, so the target code - * generator still has quite a bit of work to do. - * It needs to provide the body of the sending and - * receiving reactions. It also needs to provide the - * runtime infrastructure that uses the dependency - * information between federates. See the C target - * for a reference implementation. - */ - private fun analyzeFederates() { - // Next, if there actually are federates, analyze the topology - // interconnecting them and replace the connections between them - // with an action and two reactions. - val mainDefn = this.mainDef?.reactorClass?.toDefinition() - - if (mainDefn?.isFederated != true) { - // Ensure federates is never empty. - val federateInstance = FederateInstance(null, 0, 0, this) - federates.add(federateInstance) - federateByID[0] = federateInstance - } else { - // The Lingua Franca program is federated - isFederated = true - if (mainDefn.host != null) { - // Get the host information, if specified. - // If not specified, this defaults to 'localhost' - if (mainDefn.host.addr != null) { - federationRTIProperties["host"] = mainDefn.host.addr - } - // Get the port information, if specified. - // If not specified, this defaults to 14045 - if (mainDefn.host.port != 0) { - federationRTIProperties["port"] = mainDefn.host.port - } - // Get the user information, if specified. - if (mainDefn.host.user != null) { - federationRTIProperties["user"] = mainDefn.host.user - } - // Get the directory information, if specified. - /* FIXME - * if (mainDef.reactorClass.host.dir != null) { - * federationRTIProperties.put('dir', mainDef.reactorClass.host.dir) - * } - */ - } - - // Create a FederateInstance for each top-level reactor. - for (instantiation in mainDefn.allInstantiations) { - val bankWidth = instantiation.widthSpec.width ?: run { - reportError(instantiation, "Cannot determine bank width!") - // Continue with a bank width of 1. - 1 - } - // Create one federate instance for each reactor instance in the bank of reactors. - val federateInstances = LinkedList() - for (i in 0..bankWidth) { - // Assign an integer ID to the federate. - val federateID = federates.size - val federateInstance = FederateInstance(instantiation, federateID, i, this) - federateInstance.bankIndex = i - federates.add(federateInstance) - federateInstances.add(federateInstance) - federateByID[federateID] = federateInstance - - if (instantiation.host != null) { - federateInstance.host = instantiation.host.addr - // The following could be 0. - federateInstance.port = instantiation.host.port - // The following could be null. - federateInstance.user = instantiation.host.user - /* FIXME: The at keyword should support a directory component. - * federateInstance.dir = instantiation.host.dir - */ - } - } - if (federatesByInstantiation === null) { - federatesByInstantiation = LinkedHashMap() - } - federatesByInstantiation!![instantiation] = federateInstances - } - - // In a federated execution, we need keepalive to be true, - // otherwise a federate could exit simply because it hasn't received - // any messages. - if (federates.size > 1) { - targetConfig.keepalive = true - } - - // Analyze the connection topology of federates. - // First, find all the connections between federates. - // For each connection between federates, replace it in the - // AST with an action (which inherits the delay) and two reactions. - // The action will be physical for physical connections and logical - // for logical connections. - val connectionsToRemove = LinkedList() - for (connection in mainDefn.connections) { - // Each connection object may represent more than one physical connection between - // federates because of banks and multiports. We need to generate communciation - // for each of these. This iteration assumes the balance of the connection has been - // checked. - var rightIndex = 0 - var rightPort = connection.rightPorts[rightIndex++] - var rightBankIndex = 0 - var rightChannelIndex = 0 - var rightPortWidth = (rightPort.variable as Port).widthSpec.width(default = 1) - for (leftPort in connection.leftPorts) { - val leftPortWidth = (leftPort.variable as Port).widthSpec.width(default = 1) - for (leftBankIndex in 0..leftPort.container.widthSpec.width(default = 1)) { - var leftChannelIndex = 0 - while (rightPort != null) { - val minWidth = - if (leftPortWidth - leftChannelIndex < rightPortWidth - rightChannelIndex) - leftPortWidth - leftChannelIndex - else rightPortWidth - rightChannelIndex - for (j in 0..minWidth) { - - // Finally, we have a specific connection. - // Replace the connection in the AST with an action - // (which inherits the delay) and two reactions. - // The action will be physical if the connection physical and - // otherwise will be logical. - val leftFederate = federatesByInstantiation!!.get(leftPort.container)!!.get(leftBankIndex) - val rightFederate = federatesByInstantiation!!.get(rightPort.container)!!.get(rightBankIndex) - - // Set up dependency information. - // FIXME: Maybe we don't need this any more? - if ( - leftFederate !== rightFederate - && !connection.isPhysical - && targetConfig.coordination !== TargetProperty.CoordinationType.DECENTRALIZED - ) { - val dependsOn = rightFederate.dependsOn.computeIfAbsent(leftFederate) { mutableSetOf() } - if (connection.delay != null) { - dependsOn.add(connection.delay) - } - val sendsTo = leftFederate.dependsOn.computeIfAbsent(rightFederate) { mutableSetOf() } - if (connection.delay != null) { - sendsTo.add(connection.delay) - } - // Check for causality loops between federates. - // FIXME: This does not detect cycles involving more than one federate. - val reverseDependency = leftFederate.dependsOn[rightFederate] - if (reverseDependency != null) { - // Check that at least one direction has a delay. - if (reverseDependency.size == 0 && dependsOn.size == 0) { - // Found a causality loop. - val message = "Causality loop found between federates " + - leftFederate.name + " and " + rightFederate.name - reportError(connection, message) - // This is a fatal error, so throw an exception. - throw AssertionError(message) - } - } - } - - FedASTUtils.makeCommunication( - connection, - leftFederate, leftBankIndex, leftChannelIndex, - rightFederate, rightBankIndex, rightChannelIndex, - this, - targetConfig.coordination - ) - - leftChannelIndex++ - rightChannelIndex++ - if (rightChannelIndex >= rightPortWidth) { - // Ran out of channels on the right. - // First, check whether there is another bank reactor. - when { - rightBankIndex < rightPort.container.widthSpec.width(default = 1) - 1 -> { - rightBankIndex++ - rightChannelIndex = 0 - } - rightIndex >= connection.rightPorts.size -> { - // We are done. - rightPort = null - rightBankIndex = 0 - rightChannelIndex = 0 - } - else -> { - rightBankIndex = 0 - rightPort = connection.rightPorts[rightIndex++] - rightChannelIndex = 0 - rightPortWidth = (rightPort.variable as Port).widthSpec.width(default = 1) - } - } - } - } - } - } - } - // To avoid concurrent modification exception, collect a list - // of connections to remove. - connectionsToRemove.add(connection) - } - for (connection in connectionsToRemove) { - // Remove the original connection for the parent. - mainDefn?.connections?.remove(connection) - } - } - } - - /** - * Determine which mode the compiler is running in. - * Integrated mode means that it is running within an Eclipse IDE. - * Standalone mode means that it is running on the command line. - */ - private fun setMode() { - val resource = fileConfig?.resource - mode = when { - resource?.uri?.isPlatform == true -> Mode.INTEGRATED - resource?.uri?.isFile == true -> Mode.STANDALONE - else -> Mode.UNDEFINED.also { - System.err.println("ERROR: Source file protocol is not recognized: " + resource!!.uri) - } - } - } - - /** - * Print to stdout information about what source file is being generated, - * what mode the generator is in, and where the generated sources are to be put. - */ - open fun printInfo() { - println("Generating code for: " + fileConfig!!.resource.uri) - println("******** mode: $mode") - println("******** source file: " + fileConfig!!.srcFile) // FIXME: redundant - println("******** generated sources: " + fileConfig!!.srcGenPath) - } - - /** - * Execute a process while forwarding output and error streams. - * - * Executing a process directly with `processBuiler.start()` could - * lead to a deadlock as the subprocess blocks when output or error - * buffers are full. This method ensures that output and error messages - * are continuously read and forwards them to the given streams. - * - * @param this@runSubprocess The process to be executed. - * @param outStreams The stream to forward the process' output to. - * @param errStreams The stream to forward the process' error messages to. - * @author{Christian Menard @tu-dresden.de} - */ - private fun ProcessBuilder.runSubprocess(outStreams: List, - errStreams: List): Int { - - fun startThread(inputStream: InputStream, outputs:List) = - Thread { - val buffer = ByteArray(64) - var len = inputStream.read(buffer) - while (len != -1) { - for (os in outputs) { - os.write(buffer, 0, len) - } - len = inputStream.read(buffer) - } - }.also { - it.start() - } - - - val process = start() - - val outThread = startThread(process.inputStream, outStreams) - val errThread = startThread(process.errorStream, errStreams) - - val returnCode = process.waitFor() - outThread.join() - errThread.join() - - return returnCode - } - - abstract override fun getTargetTimeType(): String - abstract val targetTagType: String - abstract val targetTagIntervalType: String - abstract val targetUndefinedType: String - - abstract fun getTargetFixedSizeListType(baseType: String, size: Int): String - abstract fun getTargetVariableSizeListType(baseType: String): String - - /** Return a string representing the specified type in the target language. */ - fun getTargetType(type: InferredType): String = when { - type.isUndefined -> this.targetUndefinedType - type.isTime -> when { - type.isFixedSizeList -> this.getTargetFixedSizeListType(this.targetTimeType, type.listSize) - type.isVariableSizeList -> this.getTargetVariableSizeListType(this.targetTimeType) - else -> this.targetTimeType - } - type.isFixedSizeList -> this.getTargetFixedSizeListType(type.baseType(), type.listSize) - type.isVariableSizeList -> this.getTargetVariableSizeListType(type.baseType()) - else -> type.toText() - } - - val StateVar.targetType: String get() = getTargetType(ASTUtils.getInferredType(this)) - val Action.targetType: String get() = getTargetType(ASTUtils.getInferredType(this)) - val Port.targetType: String get() = getTargetType(ASTUtils.getInferredType(this)) - val Type.targetType: String get() = getTargetType(InferredType.fromAST(this)) - val Parameter.targetType: String get() = getTargetType(ASTUtils.getInferredType(this)) - - /** - * Get textual representation of a time in the target language. - * - * @param t A time AST node - * @return A time string in the target language - */ - protected fun getTargetTime(t: Time): String = timeInTargetLanguage(TimeValue(t.interval.toLong(), t.unit)) - - /** - * Get textual representation of a value in the target language. - * - * If the value evaluates to 0, it is interpreted as a normal value. - * - * @param v A time AST node - * @return A time string in the target language - */ - protected fun getTargetValue(v: Value): String = - if (v.time != null) { - this.getTargetTime(v.time) - } else { - v.toText() - } - - /** - * Get textual representation of a value in the target language. - * - * If the value evaluates to 0, it is interpreted as a time. - * - * @param v A time AST node - * @return A time string in the target language - */ - protected fun getTargetTime(v: Value): String = when { - v.time != null -> this.getTargetTime(v.time) - ASTUtils.isZero(v) -> timeInTargetLanguage(TimeValue(0, TimeUnit.NONE)) - else -> ASTUtils.toText(v) - } - - protected fun getTargetTime(d: Delay): String = - if (d.parameter != null) { - ASTUtils.toText(d) - } else { - timeInTargetLanguage(TimeValue(d.interval.toLong(), d.unit)) - } - - /** - * Write the source code to file. - * @param code The code to be written. - * @param path The file to write the code to. - */ - protected fun writeSourceCodeToFile(code: ByteArray, path: String) { - Files.write(Paths.get(path), code) - } - - companion object { - /** Constant that specifies how to name generated delay reactors. */ - const val GEN_DELAY_CLASS_NAME = "__GenDelay" - - /** Return the target. Throws if there is not exactly one. */ - fun Resource.findTarget(): TargetDecl { - val targets = allContents.asSequence().filterIsInstance().toList() - when { - targets.isEmpty() -> throw RuntimeException("No target found!") - targets.size > 1 -> throw RuntimeException("There is more than one target!") // FIXME: check this in validator - else -> return targets[0] - } - } - } - - override fun getFederationSize(): Int = federates.size - - override fun isFederatedAndDecentralized() = - isFederated && targetConfig.coordination === TargetProperty.CoordinationType.DECENTRALIZED - -} diff --git a/org.lflang/src/org/lflang/scoping/LFScopeProvider.java b/org.lflang/src/org/lflang/scoping/LFScopeProvider.java deleted file mode 100644 index 875dc6a02a..0000000000 --- a/org.lflang/src/org/lflang/scoping/LFScopeProvider.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * generated by Xtext 2.23.0 - */ - -package org.lflang.scoping; - - -import org.eclipse.emf.ecore.EObject; -import org.eclipse.emf.ecore.EReference; -import org.eclipse.xtext.naming.SimpleNameProvider; -import org.eclipse.xtext.scoping.IScope; - -import com.google.inject.Inject; - -/** - * This class contains custom scoping description. - *

- * See https://www.eclipse.org/Xtext/documentation/303_runtime_concepts.html#scoping - * on how and when to use it. - */ -public class LFScopeProvider extends AbstractLFScopeProvider { - - @Inject - private SimpleNameProvider nameProvider; - @Inject - private LFGlobalScopeProvider scopeProvider; - - @Override - public IScope getScope(EObject context, EReference reference) { - return new LFScopeProviderImpl(nameProvider, scopeProvider).getScope(context, reference); - } -} diff --git a/org.lflang/src/org/lflang/scoping/LFScopeProviderImpl.kt b/org.lflang/src/org/lflang/scoping/LFScopeProvider.kt similarity index 94% rename from org.lflang/src/org/lflang/scoping/LFScopeProviderImpl.kt rename to org.lflang/src/org/lflang/scoping/LFScopeProvider.kt index 50c88507fc..43f479283b 100644 --- a/org.lflang/src/org/lflang/scoping/LFScopeProviderImpl.kt +++ b/org.lflang/src/org/lflang/scoping/LFScopeProvider.kt @@ -30,7 +30,6 @@ import org.eclipse.emf.ecore.EReference import org.eclipse.xtext.naming.SimpleNameProvider import org.eclipse.xtext.scoping.IScope import org.eclipse.xtext.scoping.Scopes -import org.eclipse.xtext.scoping.impl.DelegatingScopeProvider import org.eclipse.xtext.scoping.impl.SelectableBasedScope import org.eclipse.xtext.xbase.lib.CollectionLiterals import org.lflang.* @@ -47,8 +46,15 @@ import java.util.Collections.emptyList * * @author Marten Lohstroh */ -class LFScopeProviderImpl(val nameProvider: SimpleNameProvider, - val scopeProvider: LFGlobalScopeProvider) : DelegatingScopeProvider() { +class LFScopeProvider : AbstractLFScopeProvider() { + + @Inject + lateinit var nameProvider: SimpleNameProvider + + @Inject + lateinit var scopeProvider: LFGlobalScopeProvider + + /** * Enumerate of the kinds of references. */ @@ -79,7 +85,7 @@ class LFScopeProviderImpl(val nameProvider: SimpleNameProvider, */ private fun getScopeForImportedReactor(context: ImportedReactor, reference: EReference): IScope { val importURI = (context.eContainer() as Import).importURI ?: "" - val importedURI = scopeProvider!!.resolve(importURI, context.eResource()) + val importedURI = scopeProvider.resolve(importURI, context.eResource()) if (importedURI != null) { val uniqueImportURIs: Set = scopeProvider.getImportedUris(context.eResource()) val uri = uniqueImportURIs.first { it == importedURI } @@ -118,7 +124,7 @@ class LFScopeProviderImpl(val nameProvider: SimpleNameProvider, private fun getScopeForAssignment(assignment: Assignment, reference: EReference?): IScope { if (reference == LfPackage.Literals.ASSIGNMENT__LHS) { - val defn = ((assignment.eContainer() as Instantiation).reactorClass).toDefinition() + val defn = ((assignment.eContainer() as Instantiation).reactorClass)?.toDefinition() if (defn != null) { return Scopes.scopeFor(defn.allParameters) } @@ -155,11 +161,11 @@ class LFScopeProviderImpl(val nameProvider: SimpleNameProvider, } if (variable.container != null) { // Resolve hierarchical port reference - val instanceName = nameProvider?.getFullyQualifiedName(variable.container) + val instanceName = nameProvider.getFullyQualifiedName(variable.container) val instances = reactor.instantiations for (instance in instances) { - val defn = instance.reactorClass.toDefinition() + val defn = instance.reactorClass?.toDefinition() if (defn != null && instanceName != null && instance.name == instanceName.toString()) { return when (type) { RefType.TRIGGER, RefType.SOURCE, RefType.CLEFT -> Scopes.scopeFor(defn.allOutputs) From 3f61992da93871b7c80598011b7e3eed2c59e76f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Wed, 28 Apr 2021 16:33:06 +0200 Subject: [PATCH 36/88] Remove parts of AstExtensions.kt --- org.lflang/src/org/lflang/AstExtensions.kt | 779 +-------------------- 1 file changed, 26 insertions(+), 753 deletions(-) diff --git a/org.lflang/src/org/lflang/AstExtensions.kt b/org.lflang/src/org/lflang/AstExtensions.kt index d6edbfd40e..c92214a0bc 100644 --- a/org.lflang/src/org/lflang/AstExtensions.kt +++ b/org.lflang/src/org/lflang/AstExtensions.kt @@ -24,14 +24,13 @@ package org.lflang -import org.eclipse.emf.ecore.resource.Resource -import org.eclipse.xtext.nodemodel.util.NodeModelUtils -import org.lflang.ASTUtils.factory -import org.lflang.generator.KtGeneratorBase import org.lflang.lf.* -import java.lang.NumberFormatException - +/** + * If this reactor declaration is an import, then + * return the imported reactor class definition. + * Otherwise, just return the argument. + */ fun ReactorDecl.toDefinition(): Reactor = when (this) { is Reactor -> this is ImportedReactor -> this.reactorClass @@ -95,46 +94,18 @@ val Reactor.allTimers: List get() = superClassRecursor { timers } private fun Reactor.superClassRecursor(collector: Reactor.() -> List): List = superClasses.orEmpty().mapNotNull { it.toDefinition().collector() }.flatten() + this.collector() -val Parameter.isOfTimeType: Boolean - get() { - // Either the type has to be declared as a time. - if (type?.isTime == true) { - return true - } - // Or it has to be initialized as a proper time with units. - init?.singleOrNull() - ?.time - ?.takeIf { it.unit != TimeUnit.NONE } - ?.let { - return true - } - // In other words, one can write: - // - `x:time(0)` -OR- - // - `x:(0 msec)`, `x:(0 sec)`, etc. - return false - } +val Parameter.isOfTimeType: Boolean get() = ASTUtils.isOfTimeType(this) -fun List.tail() = subList(1, size) -fun List.headAndTail() = Pair(first(), tail()) - - -fun Code?.toText(): String { - this ?: return "" - val node = NodeModelUtils.getNode(this) - return if (node != null) { - val str = node.leafNodes - .joinToString { it.text }.trim() - .removeSurrounding("{=", "=}") - - if ('\n' in str) str.trimIndent() else str.trim() - } else if (body != null) { - // Code must have been added as a simple string. - body.toString() - } else { - "" - } -} +/** + * Translate this code element into its textual representation. + * @see ASTUtils.toText + */ +fun Code.toText(): String = ASTUtils.toText(this) +/** + * Translate this code element into its textual representation. + * @see ASTUtils.toText + */ fun TypeParm.toText(): String = if (!literal.isNullOrEmpty()) literal else code.toText() @@ -147,22 +118,15 @@ fun TypeParm.toText(): String = * * @receiver The element to be rendered as a string. */ -fun Element.toText(): String { - if (literal != null) { - return literal.withoutQuotes().trim() - } - if (id != null) { - return id - } - return "" -} +fun Element.toText(): String = + literal?.withoutQuotes()?.trim() ?: id ?: "" fun Delay.toText(): String { if (parameter !== null) { return parameter.name } - return interval.toString() + " " + unit + return "$interval $unit" } /** @@ -225,119 +189,7 @@ fun ArraySpec.toText(): String = * @receiver AST node to render as string. * @return Textual representation of the given argument. */ -fun Type.toText(): String { - return baseType + arraySpec?.toText().orEmpty() -} - -/** - * Find connections in the given resource that have a delay associated with them, - * and reroute them via a generated delay reactor. - * @param resource The AST. - * @param generator A code generator. - */ -fun insertGeneratedDelays(resource: Resource, generator: KtGeneratorBase) { - // The resulting changes to the AST are performed _after_ iterating - // in order to avoid concurrent modification problems. - val oldConnections = mutableListOf() - val newConnections = mutableMapOf>() - val delayInstances = mutableMapOf>() - - // Iterate over the connections in the tree. - for (container in resource.allContents.asSequence().filterIsInstance()) { - for (connection in container.connections) { - if (connection.delay !== null) { - val parent = connection.eContainer() as Reactor - // Assume all the types are the same, so just use the first on the right. - val type = (connection.rightPorts[0].variable as Port).type - val delayClass = getDelayClass(type, generator) - val generic = - if (generator.supportsGenerics) - generator.getTargetType(InferredType.fromAST(type)) - else "" - - // If the left or right has a multiport or bank, then create a bank - // of delays with an inferred width. - // FIXME: If the connection already uses an inferred width on - // the left or right, then this will fail because you cannot - // have an inferred width on both sides. - val isWide = connection.isWide - val delayInstance = getDelayInstance(delayClass, connection.delay, generic, isWide) - - // Stage the new connections for insertion into the tree. - newConnections.computeIfAbsent(parent) { mutableListOf() } - .addAll(connection.rerouteViaDelay(delayInstance)) - - // Stage the original connection for deletion from the tree. - oldConnections.add(connection) - - // Stage the newly created delay reactor instance for insertion - delayInstances.computeIfAbsent(parent) { mutableListOf() } - .add(delayInstance) - } - } - } - // Remove old connections; insert new ones. - for (connection in oldConnections) { - (connection.eContainer() as Reactor).connections.remove(connection) - } - for ((reactor, connections) in newConnections) { - reactor.connections.addAll(connections) - } - // Finally, insert the instances and, before doing so, assign them a unique name. - for ((reactor, instantiations) in delayInstances) { - for (instantiation in instantiations) { - instantiation.name = reactor.getUniqueIdentifier("delay") - reactor.instantiations.add(instantiation) - } - } -} - - -/** - * Return true if any port on the left or right of this connection involves - * a bank of reactors or a multiport. - */ -private val Connection.isWide: Boolean - get() { - val allPorts = leftPorts + rightPorts - return allPorts.any { port -> - (port.variable as? Port)?.widthSpec != null - || port.container?.widthSpec != null - } - } - - -/** - * Take a connection and reroute it via an instance of a generated delay - * reactor. This method returns a list to new connections to substitute - * the original one. - * @receiver The connection to reroute. - * @param delayInstance The delay instance to route the connection through. - */ -private fun Connection.rerouteViaDelay(delayInstance: Instantiation): List { - val connections = mutableListOf() - - val upstream = factory.createConnection() - val downstream = factory.createConnection() - val input = factory.createVarRef() - val output = factory.createVarRef() - - val delayClass = delayInstance.reactorClass.toDefinition() - - // Establish references to the involved ports. - input.container = delayInstance - input.variable = delayClass.inputs[0] - output.container = delayInstance - output.variable = delayClass.outputs[0] - upstream.leftPorts.addAll(leftPorts) - upstream.rightPorts.add(input) - downstream.leftPorts.add(output) - downstream.rightPorts.addAll(rightPorts) - - connections.add(upstream) - connections.add(downstream) - return connections -} +fun Type.toText(): String = baseType + arraySpec?.toText().orEmpty() /** * Produce a unique identifier within a reactor based on a @@ -346,225 +198,8 @@ private fun Connection.rerouteViaDelay(delayInstance: Instantiation): List().apply { - addAll(allActions.map { it.name }) - addAll(allTimers.map { it.name }) - addAll(allParameters.map { it.name }) - addAll(allInputs.map { it.name }) - addAll(allOutputs.map { it.name }) - addAll(allStateVars.map { it.name }) - addAll(allInstantiations.map { it.name }) - } - - var index = 0 - var suffix = "" - while (true) { - val id = name + suffix - if (id in vars) { - // already exists - suffix = "_$index" - index++ - } else { - break - } - } - return name + suffix -} - -/** - * Create a new instance delay instances using the given reactor class. - * The supplied time value is used to override the default interval (which - * is zero). - * If the target supports parametric polymorphism, then a single class may - * be used for each instantiation, in which case a non-empty string must - * be supplied to parameterize the instance. - * A default name ("delay") is assigned to the instantiation, but this - * name must be overridden at the call site, where checks can be done to - * avoid name collisions in the container in which the instantiation is - * to be placed. Such checks (or modifications of the AST) are not - * performed in this method in order to avoid causing concurrent - * modification exceptions. - * @param delayClass The class to create an instantiation for - * @param value A time interval corresponding to the desired delay - * @param generic A string that denotes the appropriate type parameter, - * which should be null or empty if the target does not support generics. - * @param isWide True to create a variable-width width specification. - */ -private fun getDelayInstance(delayClass: Reactor, delay: Delay, generic: String, isWide: Boolean): Instantiation { - val delayInstance = factory.createInstantiation().apply { - reactorClass = delayClass - } - if (generic.isNotEmpty()) { - val typeParm = factory.createTypeParm().apply { literal = generic } - delayInstance.typeParms.add(typeParm) - } - if (isWide) { - val widthSpec = factory.createWidthSpec() - delayInstance.widthSpec = widthSpec - widthSpec.isOfVariableLength = true - } - val assignment = factory.createAssignment() - assignment.lhs = delayClass.parameters[0] - val value = factory.createValue().apply { - if (delay.parameter !== null) { - parameter = delay.parameter - } else { - time = factory.createTime() - time.interval = delay.interval - time.unit = delay.unit - } - } - assignment.rhs.add(value) - delayInstance.parameters.add(assignment) - delayInstance.name = "delay" // This has to be overridden. - - return delayInstance - -} - -/** - * Return a synthesized AST node that represents the definition of a delay - * reactor. Depending on whether the target supports generics, either this - * method will synthesize a generic definition and keep returning it upon - * subsequent calls, or otherwise, it will synthesize a new definition for - * each new type it hasn't yet created a compatible delay reactor for. - * @param aType The type the delay class must be compatible with. - * @param generator A code generator. - */ -private fun getDelayClass(aType: Type, generator: KtGeneratorBase): Reactor { - val className = - if (generator.supportsGenerics) KtGeneratorBase.GEN_DELAY_CLASS_NAME - else run { - val id = Integer.toHexString(InferredType.fromAST(aType).toText().hashCode()) - "${KtGeneratorBase.GEN_DELAY_CLASS_NAME}_$id" - } - - // If it is there, return it - generator.findDelayClass(className)?.let { return it } - - val defaultValue = factory.createValue().apply { - literal = generator.timeInTargetLanguage(TimeValue(0, TimeUnit.NONE)) - } - - val delayParameter = factory.createParameter().apply { - name = "delay" - type = factory.createType() - aType.id = generator.targetTimeType - init.add(defaultValue) - } - val action = factory.createAction().apply { - name = "act" - minDelay = factory.createValue() - minDelay.parameter = delayParameter - origin = ActionOrigin.LOGICAL - } - - // Establish references to the action. - val triggerRef = factory.createVarRef().apply { variable = action } - val effectRef = factory.createVarRef().apply { variable = action } - val input = factory.createInput().apply { - name = "inp" - type = action.type.getCopy() - } - val output = factory.createOutput().apply { - name = "out" - type = action.type.getCopy() - } - - // Establish references to the involved ports. - val inRef = factory.createVarRef().apply { - variable = input - } - val outRef = factory.createVarRef().apply { - variable = output - } - - - // Name the newly created action; set its delay and type. - - if (generator.supportsGenerics) { - action.type = factory.createType() - action.type.id = "T" - } else { - action.type = aType.getCopy() - } - - val r1 = factory.createReaction().apply { - // Configure the second reaction, which reads the input. - triggers.add(inRef) - effects.add(effectRef) - code = factory.createCode() - code.body = generator.generateDelayBody(action, inRef) - } - - val r2 = factory.createReaction().apply { - // Configure the first reaction, which produces the output. - triggers.add(triggerRef) - effects.add(outRef) - code = factory.createCode() - code.body = generator.generateForwardBody(action, outRef) - } - - val delayClass = factory.createReactor().apply { - name = className - // Add the action to the reactor. - actions += action - - // These need to go in the opposite order in case - // a new input arrives at the same time the delayed - // output is delivered! - reactions += r2 - reactions += r1 - - inputs += input - outputs += output - parameters += delayParameter - - // Add a type parameter if the target supports it. - if (generator.supportsGenerics) { - typeParms += factory.createTypeParm().apply { - literal = generator.generateDelayGeneric() - } - } - } - - generator.addDelayClass(delayClass) - - return delayClass -} - -private fun TypeParm.getCopy(): TypeParm { - val original = this - return factory.createTypeParm().apply { - literal = original.literal - code = factory.createCode().apply { body = original.code.body } - } -} - -private fun Type.getCopy(): Type { - val original = this - return factory.createType().apply { - id = original.id - isTime = original.isTime - stars.addAll(original.stars.orEmpty()) - - if (original.code !== null) { - code = factory.createCode().apply { - body = original.code.body - } - } - if (original.arraySpec !== null) { - arraySpec = factory.createArraySpec().apply { - this.isOfVariableLength = original.arraySpec.isOfVariableLength - length = original.arraySpec.length - } - } - - typeParms.addAll(original.typeParms.orEmpty().map { it.getCopy() }) - } - -} +fun Reactor.getUniqueIdentifier(name: String): String = + ASTUtils.getUniqueIdentifier(this, name) /** * Translate the given type into its textual representation, but @@ -599,213 +234,6 @@ fun isZero(value: Value): Boolean = ?: value.code?.isZero ?: false - -/** - * Given the width specification of port or instantiation - * and an (optional) list of nested intantiations, return - * the width if it can be determined and -1 if not. - * It will not be able to be determined if either the - * width is variable (in which case you should use - * {@link inferPortWidth(VarRef, Connection, List}) - * or the list of instantiations is incomplete or missing. - * If there are parameter references in the width, they are - * evaluated to the extent possible given the instantiations list. - * - * The instantiations list is as in - * {@link initialValue(Parameter, List}. - * If the spec belongs to an instantiation (for a bank of reactors), - * then the first element on this list should be the instantiation - * that contains this instantiation. If the spec belongs to a port, - * then the first element on the list should be the instantiation - * of the reactor that contains the port. - * - * @param spec The width specification or null (to return 1). - * @param instantiations The (optional) list of instantiations. - * - * @return The width, or null if the width could not be determined. - * - * @throws IllegalArgumentException If an instantiation provided is not as - * given above or if the chain of instantiations is not nested. - */ -fun width(spec: WidthSpec, instantiations: List = emptyList()): Int? { - if (spec.isOfVariableLength && spec.eContainer() is Instantiation) { - // We may be able to infer the width by examining the connections of - // the enclosing reactor definition. This works, for example, with - // delays between multiports or banks of reactors. - // Attempt to infer the width. - for (c in (spec.eContainer().eContainer() as Reactor).connections) { - var leftWidth = 0 - var rightWidth = 0 - var isOnLeft: Boolean? = null - for (leftPort in c.leftPorts) { - if (leftPort.container === spec.eContainer()) { - if (isOnLeft != null) { - throw Exception("Multiple ports with variable width on a connection.") - } - isOnLeft = true - } else { - leftWidth += inferPortWidth(leftPort, c) ?: return null - } - } - for (rightPort in c.rightPorts) { - if (rightPort.container === spec.eContainer()) { - if (isOnLeft != null) { - throw Exception("Multiple ports with variable width on a connection.") - } - isOnLeft = false - } else { - rightWidth += inferPortWidth(rightPort, c) ?: return null - } - } - - if (isOnLeft != null) { - return if (isOnLeft) rightWidth - leftWidth else leftWidth - rightWidth - } - } - // A connection was not found with the instantiation. - return null - } - var result = 0 - for (term in spec.terms) { - if (term.parameter !== null) { - val termWidth = initialValueInt(term.parameter, instantiations) - if (termWidth !== null) { - result += termWidth - } else { - return -1 - } - } else { - result += term.width - } - } - return result -} - -/** - * Infer the width of a port reference in a connection. - * The port reference one or two parts, a port and an (optional) container - * which is an Instantiation that may refer to a bank of reactors. - * The width will be the product of the bank width and the port width. - * The returned value will be 1 if the port is not in a bank and is not a multiport. - * - * If the width cannot be determined, this will return -1. - * The width cannot be determined if the list of instantiations is - * missing or incomplete. - * - * The instantiations list is as in - * {@link initialValue(Parameter, List}. - * The first element on this list should be the instantiation - * that contains the specified connection. - * - * @param reference A port reference. - * @param connection A connection, or null if not in the context of a connection. - * @param instantiations The (optional) list of instantiations. - * - * @return The width or null if it could not be determined. - * - * @throws IllegalArgumentException If an instantiation provided is not as - * given above or if the chain of instantiations is not nested. - */ -fun inferPortWidth(reference: VarRef, connection: Connection?, instantiations: List = emptyList()): Int? { - if (reference.variable is Port) { - // If the port is given as a.b, then we want to prepend a to - // the list of instantiations to determine the width of this port. - var extended = instantiations - if (reference.container !== null) { - extended = mutableListOf() - extended.add(reference.container) - extended.addAll(instantiations) - } - - val portWidth = width((reference.variable as Port).widthSpec, extended) ?: return null - - // Next determine the bank width. This may be unspecified, in which - // case it has to be inferred using the connection. - val bankWidth: Int = - if (reference.container == null || instantiations == null) { - 1 - } else { - // Could not determine the bank width.// This is an error.// This port is on the right. - // Check that portWidth divides the discrepancy. - // This port is on the left.// Indicate that this port is on the right.// The left port is not the same as this reference.// Indicate that this port is on the left.// This occurs for a bank of delays.// width returned null - // Try to infer the bank width from the connection. - width(reference.container.widthSpec, instantiations) - ?: if (connection == null) return null - else { // width returned null, no connection - - // Try to infer the bank width from the connection. - if (reference.container.widthSpec.isOfVariableLength) { - // This occurs for a bank of delays. - var leftWidth = 0 - var rightWidth = 0 - var leftOrRight = 0 - for (leftPort in connection.leftPorts) { - if (leftPort === reference) { - if (leftOrRight != 0) { - throw Exception("Multiple ports with variable width on a connection.") - } - // Indicate that this port is on the left. - leftOrRight = -1 - } else { - // The left port is not the same as this reference. - val otherWidth = inferPortWidth(leftPort, connection, instantiations) ?: return null - leftWidth += otherWidth - } - } - for (rightPort in connection.rightPorts) { - if (rightPort === reference) { - if (leftOrRight != 0) { - throw Exception("Multiple ports with variable width on a connection.") - } - // Indicate that this port is on the right. - leftOrRight = 1 - } else { - val otherWidth = inferPortWidth(rightPort, connection, instantiations) ?: return null - rightWidth += otherWidth - } - } - var discrepancy = 0 - if (leftOrRight < 0) { - // This port is on the left. - discrepancy = rightWidth - leftWidth - } else if (leftOrRight > 0) { - // This port is on the right. - discrepancy = leftWidth - rightWidth - } - // Check that portWidth divides the discrepancy. - if (discrepancy % portWidth != 0) { - return null // This is an error. - } - discrepancy / portWidth - } else { - return null // Could not determine the bank width. - } - } - } - return portWidth * bankWidth - } - // Argument is not a port. - return null -} - -/** - * Return the width of the port reference if it can be determined - * and otherwise return -1. The width can be determined if the - * port is not a multiport in a bank of reactors (the width will 1) - * or if the width of the multiport and/or the bank is given by a - * literal constant. - * - * IMPORTANT: This method should not be used you really need to - * determine the width! It will not evaluate parameter values. - * @see width(WidthSpec, List instantiations) - * @see inferPortWidth(VarRef, Connection, List) - * - * @param reference A reference to a port. - * @return The width of a port or null if it cannot be determined. - * @deprecated - */ -fun multiportWidthIfLiteral(reference: VarRef): Int? = inferPortWidth(reference, null, instantiations = emptyList()) - /** * Given the specification of the width of either a bank of reactors * or a multiport, return the width if it can be determined and otherwise @@ -819,170 +247,12 @@ fun multiportWidthIfLiteral(reference: VarRef): Int? = inferPortWidth(reference, * @receiver The width specification. * * @return The width or null if it cannot be determined. - * @deprecated */ val WidthSpec.width: Int? - get() = width(this) - -inline fun WidthSpec.width(default: T): T = width(this) as? T ?: default - + get() = ASTUtils.width(this, null).takeIf { it >= 0 } -/** - * Given an instantiation of a reactor or bank of reactors, return - * the width. This will be 1 if this is not a reactor bank. Otherwise, - * this will attempt to determine the width. If the width is declared - * as a literal constant, it will return that constant. If the width - * is specified as a reference to a parameter, this will throw an - * exception. If the width is variable, this will find - * connections in the enclosing reactor and attempt to infer the - * width. If the width cannot be determined, it will throw an exception. - * - * IMPORTANT: This method should not be used you really need to - * determine the width! It will not evaluate parameter values. - * @see width(WidthSpec, List instantiations) - * - * @receiver A reactor instantiation. - * - * @return The width, if it can be determined. - * @throws RuntimeException If the width cannot be determined - */ -fun Instantiation.widthSpecification(): Int = - width(widthSpec) ?: throw Exception("Cannot determine width for the instance $name") - - -/** - * Given a parameter, return its initial value. - * The initial value is a list of instances of Value, where each - * Value is either an instance of Time, Literal, or Code. - * - * If the instantiations argument is null or an empty list, then the - * value returned is simply the default value given when the parameter - * is defined. - * - * If a list of instantiations is given, then the first instantiation - * is required to be an instantiation of the reactor class that is - * parameterized by the parameter. I.e., - * ``` - * parameter.eContainer == instantiations.get(0).reactorClass - * ``` - * If a second instantiation is given, then it is required to be an instantiation of a - * reactor class that contains the first instantiation. That is, - * ``` - * instantiations.get(0).eContainer == instantiations.get(1).reactorClass - * ``` - * More generally, for all 0 <= i < instantiations.size - 1, - * ``` - * instantiations.get(i).eContainer == instantiations.get(i + 1).reactorClass - * ``` - * If any of these conditions is not satisfied, then an IllegalArgumentException - * will be thrown. - * - * Note that this chain of reactions cannot be inferred from the parameter because - * in each of the predicates above, there may be more than one instantiation that - * can appear on the right hand side of the predicate. - * - * For example, consider the following program: - * ``` - * reactor A(x:int(1)) {} - * reactor B(y:int(2)) { - * a1 = new A(x = y); - * a2 = new A(x = -1); - * } - * reactor C(z:int(3)) { - * b1 = new B(y = z); - * b2 = new B(y = -2); - * } - * ``` - * Notice that there are a total of four instances of reactor class A. - * Then - * ``` - * initialValue(x, null) returns 1 - * initialValue(x, [a1]) returns 2 - * initialValue(x, [a2]) returns -1 - * initialValue(x, [a1, b1]) returns 3 - * initialValue(x, [a2, b1]) returns -1 - * initialValue(x, [a1, b2]) returns -2 - * initialValue(x, [a2, b2]) returns -1 - * ``` - * (Actually, in each of the above cases, the returned value is a list with - * one entry, a Literal, e.g. ["1"]). - * - * There are two instances of reactor class B. - * ``` - * initialValue(y, null) returns 2 - * initialValue(y, [a1]) throws an IllegalArgumentException - * initialValue(y, [b1]) returns 3 - * initialValue(y, [b2]) returns -2 - * ``` - * - * @param parameter The parameter. - * @param instantiations The (optional) instantiations. - * - * @return The value of the parameter. - * - * @throws IllegalArgumentException If an instantiation provided is not an - * instantiation of the reactor class that is parameterized by the - * respective parameter or if the chain of instantiations is not nested. - */ -fun initialValue(parameter: Parameter, instantiations: List = emptyList()): List { - // If instantiations are given, then check to see whether this parameter gets overridden in - // the first of those instantiations. - if (instantiations.isNotEmpty()) { - // Check to be sure that the instantiation is in fact an instantiation - // of the reactor class for which this is a parameter. - val instantiation = instantiations[0] - if (parameter.eContainer() !== instantiation.reactorClass) { - throw IllegalArgumentException("Parameter ${parameter.name} is not a parameter of reactor instance ${instantiation.name}.") - } - // In case there is more than one assignment to this parameter, we need to - // find the last one. - val lastAssignment = instantiation.parameters.lastOrNull { it.lhs === parameter } - if (lastAssignment != null) { - // Right hand side can be a list. Collect the entries. - val result = mutableListOf() - for (value in lastAssignment.rhs) { - if (value.parameter !== null) { - if (instantiations.size > 1 - && instantiation.eContainer() !== instantiations[1].reactorClass - ) { - throw IllegalArgumentException("Reactor instance ${instantiation.name} is not contained by instance ${instantiations[1].name}.") - } - val elements = initialValue(value.parameter, instantiations.subList(1, instantiations.size)) - result.addAll(elements) - } else { - result.add(value) - } - } - return result - } - } - // If we reach here, then either no instantiation was supplied or - // there was no assignment in the instantiation. So just use the - // parameter's initial value. - return parameter.init -} - -/** - * Given a parameter return its integer value or null - * if it does not have an integer value. - * If the value of the parameter is a list of integers, - * return the sum of value in the list. - * The instantiations parameter is as in - * {@link initialValue(Parameter, List}. - * - * @param parameter The parameter. - * @param instantiations The (optional) list of instantiations. - * - * @return The integer value of the parameter, or null if does not have an integer value. - * - * @throws IllegalArgumentException If an instantiation provided is not an - * instantiation of the reactor class that is parameterized by the - * respective parameter or if the chain of instantiations is not nested. - */ -fun initialValueInt(parameter: Parameter, instantiations: List = emptyList()): Int? = - initialValue(parameter, instantiations) - .sumBy { it.literal.toIntOrNullAnyRadix() ?: return null } +// more general extensions fun String.toIntOrNullAnyRadix(): Int? = try { @@ -990,3 +260,6 @@ fun String.toIntOrNullAnyRadix(): Int? = } catch (e: NumberFormatException) { null } + +fun List.tail() = subList(1, size) +fun List.headAndTail() = Pair(first(), tail()) From 24b630ad68edab60d524527df69fbabcc3eb943e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Wed, 28 Apr 2021 19:24:56 +0200 Subject: [PATCH 37/88] Cleanups --- org.lflang/src/org/lflang/AstExtensions.kt | 31 ++++++++++++++++--- .../src/org/lflang/scoping/LFScopeProvider.kt | 9 ++---- 2 files changed, 29 insertions(+), 11 deletions(-) diff --git a/org.lflang/src/org/lflang/AstExtensions.kt b/org.lflang/src/org/lflang/AstExtensions.kt index c92214a0bc..2be4bcc98d 100644 --- a/org.lflang/src/org/lflang/AstExtensions.kt +++ b/org.lflang/src/org/lflang/AstExtensions.kt @@ -34,7 +34,7 @@ import org.lflang.lf.* fun ReactorDecl.toDefinition(): Reactor = when (this) { is Reactor -> this is ImportedReactor -> this.reactorClass - else -> throw AssertionError("unreachable") + else -> throw AssertionError("Unknown reactor type: $this") } /** @@ -83,7 +83,7 @@ val Reactor.allReactions: List get() = superClassRecursor { reactions * Given a reactor class, return a list of all its state variables, * which includes state variables of base classes that it extends. */ -val Reactor.allStateVars: List get() = superClassRecursor { stateVars } +val Reactor.allStateVars: List get() = this.superClassRecursor { this.stateVars } /** * Given a reactor class, return a list of all its timers, @@ -92,6 +92,8 @@ val Reactor.allStateVars: List get() = superClassRecursor { stateVars val Reactor.allTimers: List get() = superClassRecursor { timers } private fun Reactor.superClassRecursor(collector: Reactor.() -> List): List = + + superClasses.orEmpty().mapNotNull { it.toDefinition().collector() }.flatten() + this.collector() val Parameter.isOfTimeType: Boolean get() = ASTUtils.isOfTimeType(this) @@ -225,9 +227,7 @@ val String.isZero: Boolean get() = this.toIntOrNull() == 0 val Code.isZero: Boolean get() = this.toText().isZero /** - * Report whether the given value is zero or not. - * @param value AST node to inspect. - * @return True if the given value denotes the constant `0`, false otherwise. + * Return whether the given [value] is zero or not. */ fun isZero(value: Value): Boolean = value.literal?.isZero @@ -254,6 +254,12 @@ val WidthSpec.width: Int? // 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) @@ -261,5 +267,20 @@ fun String.toIntOrNullAnyRadix(): Int? = 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()) diff --git a/org.lflang/src/org/lflang/scoping/LFScopeProvider.kt b/org.lflang/src/org/lflang/scoping/LFScopeProvider.kt index 43f479283b..1abbb05f74 100644 --- a/org.lflang/src/org/lflang/scoping/LFScopeProvider.kt +++ b/org.lflang/src/org/lflang/scoping/LFScopeProvider.kt @@ -55,9 +55,7 @@ class LFScopeProvider : AbstractLFScopeProvider() { lateinit var scopeProvider: LFGlobalScopeProvider - /** - * Enumerate of the kinds of references. - */ + /** Enumerate of the kinds of references. */ private enum class RefType { NULL, TRIGGER, SOURCE, EFFECT, DEADLINE, CLEFT, CRIGHT } @@ -68,8 +66,8 @@ class LFScopeProvider : AbstractLFScopeProvider() { * @param context The AST node in which a to-be-resolved reference occurs. * @param reference The reference to resolve. */ - override fun getScope(context: EObject, reference: EReference): IScope { - return when (context) { + override fun getScope(context: EObject, reference: EReference): IScope = + when (context) { is VarRef -> getScopeForVarRef(context, reference) is Assignment -> getScopeForAssignment(context, reference) is Instantiation -> getScopeForReactorDecl(context, reference) @@ -77,7 +75,6 @@ class LFScopeProvider : AbstractLFScopeProvider() { is ImportedReactor -> getScopeForImportedReactor(context, reference) else -> super.getScope(context, reference) } - } /** * Filter out candidates that do not originate from the file listed in From 96ac7835153f687f8c7b92135c105d7e2329e713 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Wed, 28 Apr 2021 21:43:33 +0200 Subject: [PATCH 38/88] Fix guice bug --- org.lflang/src/org/lflang/LFRuntimeModule.kt | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/org.lflang/src/org/lflang/LFRuntimeModule.kt b/org.lflang/src/org/lflang/LFRuntimeModule.kt index 2ce7ae80ce..13dcaa6017 100644 --- a/org.lflang/src/org/lflang/LFRuntimeModule.kt +++ b/org.lflang/src/org/lflang/LFRuntimeModule.kt @@ -3,6 +3,9 @@ */ package org.lflang +import org.eclipse.xtext.resource.IDefaultResourceDescriptionStrategy +import org.eclipse.xtext.scoping.IGlobalScopeProvider +import org.eclipse.xtext.validation.NamesAreUniqueValidationHelper import org.lflang.scoping.LFGlobalScopeProvider import org.lflang.validation.LFNamesAreUniqueValidationHelper @@ -10,17 +13,19 @@ import org.lflang.validation.LFNamesAreUniqueValidationHelper * Use this class to register components to be used at runtime / without the Equinox extension registry. */ open class LFRuntimeModule : AbstractLFRuntimeModule() { + // note: don't use covariant return types here. The return type of each method must be + // Class, even though with covariance you could write Class + // Guice parses the return type apparently. /** Establish a binding to our custom global scope provider. */ - override fun bindIGlobalScopeProvider(): Class { - return LFGlobalScopeProvider::class.java - } + override fun bindIGlobalScopeProvider(): Class = + LFGlobalScopeProvider::class.java /** Establish a binding to a helper that checks that names are unique. */ - fun bindNamesAreUniqueValidationHelper(): Class { - return LFNamesAreUniqueValidationHelper::class.java - } + fun bindNamesAreUniqueValidationHelper(): Class = + LFNamesAreUniqueValidationHelper::class.java /** Establish a binding to our custom resource description strategy. */ - // fun bindIDefaultResourceDescriptionStrategy(): Class = LFResourceDescriptionStrategy::class.java + fun bindIDefaultResourceDescriptionStrategy(): Class = + LFResourceDescriptionStrategy::class.java } From 7e20f14e04c98bbbd396d5b602f5c9555ef824a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Tue, 18 May 2021 23:11:48 +0200 Subject: [PATCH 39/88] Fix clean task AFAICS when cleaned correctly, `gradle build` succeeds, including tests cc @lhstrh --- build.gradle | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/build.gradle b/build.gradle index 7c0379a30a..549d937b46 100644 --- a/build.gradle +++ b/build.gradle @@ -58,4 +58,9 @@ subprojects { configurations.all { exclude group: 'asm' } + + // Delete generated sources on `gradle clean` + clean.doLast { + delete "${projectDir}/xtend-gen" + } } From a628c5bce5ec49d7698c422360b8887bfa6dec00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Thu, 20 May 2021 16:59:06 +0200 Subject: [PATCH 40/88] Fix merge conflict in eclipse file --- org.lflang/.classpath | 3 --- 1 file changed, 3 deletions(-) diff --git a/org.lflang/.classpath b/org.lflang/.classpath index a49d07bc07..1b604e5af8 100644 --- a/org.lflang/.classpath +++ b/org.lflang/.classpath @@ -20,9 +20,6 @@ -<<<<<<< HEAD -======= ->>>>>>> master From 537bd1c36024311b4e05c297dbaa8bbde0f42d1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Fri, 21 May 2021 13:27:11 +0200 Subject: [PATCH 41/88] Minor cleanup --- org.lflang/src/org/lflang/AstExtensions.kt | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/org.lflang/src/org/lflang/AstExtensions.kt b/org.lflang/src/org/lflang/AstExtensions.kt index 2be4bcc98d..953ac6c4a1 100644 --- a/org.lflang/src/org/lflang/AstExtensions.kt +++ b/org.lflang/src/org/lflang/AstExtensions.kt @@ -124,12 +124,9 @@ fun Element.toText(): String = literal?.withoutQuotes()?.trim() ?: id ?: "" -fun Delay.toText(): String { - if (parameter !== null) { - return parameter.name - } - return "$interval $unit" -} +fun Delay.toText(): String = + parameter?.name ?: "$interval $unit" + /** * Remove quotation marks surrounding the specified string. @@ -146,7 +143,7 @@ fun String.withoutQuotes(): String { * @receiver The variable reference. */ fun VarRef.toText(): String = - if (container !== null) "${container.name}.${variable.name}" + if (container != null) "${container.name}.${variable.name}" else variable.name From 8fbf35f4b8d04f25bbce7d8e1d3a903c19889e6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Sun, 23 May 2021 12:56:26 +0200 Subject: [PATCH 42/88] Fix bug with Jacoco and kotlin 1.5.0 https://github.com/jacoco/jacoco/issues/1155 Was fixed in Jacoco 0.8.7. Wrong syntax in gradle file made the jacoco version be defaulted. --- org.lflang.tests/build.gradle | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/org.lflang.tests/build.gradle b/org.lflang.tests/build.gradle index a82522097e..002439568c 100644 --- a/org.lflang.tests/build.gradle +++ b/org.lflang.tests/build.gradle @@ -9,13 +9,14 @@ dependencies { testImplementation "org.eclipse.xtext:org.eclipse.xtext.xbase.testing:${xtextVersion}" } +apply plugin: 'java' +apply plugin: 'jacoco' + jacoco { toolVersion = "0.8.7" reportsDir = file("$buildDir/reports/jacoco") //default directory where jacoco generates test reports } -apply plugin: 'java' -apply plugin: 'jacoco' jacocoTestReport { reports { From 9ff6764ff56f5451592dd0efaa539c1dd4c3fc4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Thu, 27 May 2021 12:23:03 +0200 Subject: [PATCH 43/88] build: Make maven support kotlin Still WIP, refs #337 https://kotlinlang.org/docs/kotlin-osgi.html\#faq --- build.gradle | 2 +- org.lflang.diagram/pom.xml | 4 + org.lflang.ide/pom.xml | 4 + org.lflang.tests/pom.xml | 91 +++++++++---------- org.lflang.ui.tests/pom.xml | 16 +--- org.lflang.ui/pom.xml | 6 +- org.lflang/pom.xml | 41 +++++++++ .../src/org/lflang/LFStandaloneSetup.java | 15 --- org.lflang/src/org/lflang/Target.java | 3 - pom.xml | 47 ++++++++++ 10 files changed, 147 insertions(+), 82 deletions(-) delete mode 100644 org.lflang/src/org/lflang/LFStandaloneSetup.java diff --git a/build.gradle b/build.gradle index 549d937b46..6c2e37c942 100644 --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,5 @@ buildscript { - ext.kotlinVersion = "1.5.0-RC" + ext.kotlinVersion = "1.5.0-RC" // sync with pom.xml repositories { mavenCentral() } diff --git a/org.lflang.diagram/pom.xml b/org.lflang.diagram/pom.xml index f5aa16a127..9296996d05 100644 --- a/org.lflang.diagram/pom.xml +++ b/org.lflang.diagram/pom.xml @@ -32,6 +32,10 @@ org.eclipse.xtend xtend-maven-plugin + + org.jetbrains.kotlin + kotlin-maven-plugin + diff --git a/org.lflang.ide/pom.xml b/org.lflang.ide/pom.xml index 15a7235744..4a36a678e6 100644 --- a/org.lflang.ide/pom.xml +++ b/org.lflang.ide/pom.xml @@ -31,6 +31,10 @@ org.eclipse.xtend xtend-maven-plugin + + org.jetbrains.kotlin + kotlin-maven-plugin + diff --git a/org.lflang.tests/pom.xml b/org.lflang.tests/pom.xml index 82a97024f4..7e532d812a 100644 --- a/org.lflang.tests/pom.xml +++ b/org.lflang.tests/pom.xml @@ -35,6 +35,40 @@ + + org.eclipse.xtend + xtend-maven-plugin + + + maven-antrun-plugin + 3.0.0 + + + cleanup-xtend + generate-sources + + run + + + + + + + + + + + + + + + + + org.jetbrains.kotlin + kotlin-maven-plugin + + org.eclipse.tycho @@ -47,56 +81,6 @@ - - - - - - - - org.eclipse.xtend - xtend-maven-plugin - - org.eclipse.tycho tycho-surefire-plugin @@ -147,4 +131,11 @@ + + + + org.jetbrains.kotlin + kotlin-osgi-bundle + + diff --git a/org.lflang.ui.tests/pom.xml b/org.lflang.ui.tests/pom.xml index 0dcdb286f1..1869ad1438 100644 --- a/org.lflang.ui.tests/pom.xml +++ b/org.lflang.ui.tests/pom.xml @@ -27,22 +27,14 @@ - - - org.eclipse.tycho - tycho-compiler-plugin - ${tycho-version} - - -err:-forbidden - false - - - - org.eclipse.xtend xtend-maven-plugin + + org.jetbrains.kotlin + kotlin-maven-plugin + org.eclipse.tycho tycho-surefire-plugin diff --git a/org.lflang.ui/pom.xml b/org.lflang.ui/pom.xml index e5e83d4f9d..f51c5d4df6 100644 --- a/org.lflang.ui/pom.xml +++ b/org.lflang.ui/pom.xml @@ -1,6 +1,6 @@ - + 4.0.0 @@ -31,6 +31,10 @@ org.eclipse.xtend xtend-maven-plugin + + org.jetbrains.kotlin + kotlin-maven-plugin + diff --git a/org.lflang/pom.xml b/org.lflang/pom.xml index e782be5a07..6f2fd431ee 100644 --- a/org.lflang/pom.xml +++ b/org.lflang/pom.xml @@ -86,6 +86,40 @@ org.eclipse.xtend xtend-maven-plugin + + maven-antrun-plugin + 3.0.0 + + + cleanup-xtend + generate-sources + + run + + + + + + + + + + + + + + + + + + + org.jetbrains.kotlin + kotlin-maven-plugin + + + org.eclipse.tycho + tycho-compiler-plugin + org.apache.maven.plugins @@ -165,5 +199,12 @@ + + + org.jetbrains.kotlin + kotlin-osgi-bundle + + + diff --git a/org.lflang/src/org/lflang/LFStandaloneSetup.java b/org.lflang/src/org/lflang/LFStandaloneSetup.java deleted file mode 100644 index 5c7d5ddb56..0000000000 --- a/org.lflang/src/org/lflang/LFStandaloneSetup.java +++ /dev/null @@ -1,15 +0,0 @@ -/* - * generated by Xtext 2.23.0 - */ -package org.lflang; - - -/** - * Initialization support for running Xtext languages without Equinox extension registry. - */ -public class LFStandaloneSetup extends LFStandaloneSetupGenerated { - - public static void doSetup() { - new LFStandaloneSetup().createInjectorAndDoEMFRegistration(); - } -} diff --git a/org.lflang/src/org/lflang/Target.java b/org.lflang/src/org/lflang/Target.java index 4c16bffe67..d47d5c5d9f 100644 --- a/org.lflang/src/org/lflang/Target.java +++ b/org.lflang/src/org/lflang/Target.java @@ -22,9 +22,6 @@ import java.util.Arrays; import java.util.List; -import java.util.stream.Stream; - -import org.jetbrains.annotations.Nullable; /** * Enumeration of targets and their associated properties. These classes are diff --git a/pom.xml b/pom.xml index bd36934d9f..2519f8bf90 100644 --- a/pom.xml +++ b/pom.xml @@ -30,6 +30,7 @@ + 1.5.0-RC 11 11 2.3.0 @@ -73,6 +74,8 @@ ${xtext.version} + generate-xtend + generate-sources compile xtend-install-debug-info @@ -86,6 +89,40 @@ + + org.jetbrains.kotlin + kotlin-maven-plugin + ${kotlin.version} + + + kotlin-compile + process-sources + + compile + + + + ${project.basedir}/src + ${project.basedir}/src-gen + ${project.basedir}/xtend-gen + + + + + + + + org.eclipse.tycho + tycho-compiler-plugin + ${tycho-version} + + + default-compile + compile + + + + - - - - - - - - - - - org.jetbrains.kotlin kotlin-maven-plugin 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 2dcbd77068..3ce30badf6 100644 --- a/org.lflang.tests/src/org/lflang/tests/runtime/TestBase.xtend +++ b/org.lflang.tests/src/org/lflang/tests/runtime/TestBase.xtend @@ -30,7 +30,7 @@ import org.lflang.tests.TestRegistry.TestCategory import org.junit.jupiter.api.Test import org.junit.jupiter.api.^extension.ExtendWith -import static extension org.junit.Assert.assertTrue +import static extension org.junit.jupiter.api.Assertions.assertTrue @ExtendWith(InjectionExtension) @InjectWith(LFInjectorProvider) From b03a8b26f8b74bb26f1d5c991a96237b93562299 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Thu, 27 May 2021 20:44:17 +0200 Subject: [PATCH 45/88] build: Fix another wrong usage of junit 4 still, kotlin is missing from the test classpath... how to make the tycho surefire plugin pick up on it? --- .../lflang/tests/compiler/LinguaFrancaValidationTest.xtend | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/org.lflang.tests/src/org/lflang/tests/compiler/LinguaFrancaValidationTest.xtend b/org.lflang.tests/src/org/lflang/tests/compiler/LinguaFrancaValidationTest.xtend index 81f482d921..bb8fe0d144 100644 --- a/org.lflang.tests/src/org/lflang/tests/compiler/LinguaFrancaValidationTest.xtend +++ b/org.lflang.tests/src/org/lflang/tests/compiler/LinguaFrancaValidationTest.xtend @@ -46,8 +46,8 @@ import org.junit.jupiter.api.Assertions import org.junit.jupiter.api.Test import org.junit.jupiter.api.^extension.ExtendWith -import static org.junit.Assert.assertNotNull -import static org.junit.Assert.assertTrue +import static org.junit.jupiter.api.Assertions.assertNotNull +import static org.junit.jupiter.api.Assertions.assertTrue import static extension org.lflang.ASTUtils.* import org.lflang.TargetProperty.UnionType From 8d7ee032e047eb6f273ed37fef0bd5420d8b00b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Wed, 2 Jun 2021 16:21:53 +0200 Subject: [PATCH 46/88] [gradle] Fixup clean task once more --- build.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/build.gradle b/build.gradle index 6c2e37c942..716d678b4d 100644 --- a/build.gradle +++ b/build.gradle @@ -62,5 +62,6 @@ subprojects { // Delete generated sources on `gradle clean` clean.doLast { delete "${projectDir}/xtend-gen" + delete "${projectDir}/src-gen" } } From cca6fdc6dfb4ecd5fa419ddac64de3d4dcccc1f9 Mon Sep 17 00:00:00 2001 From: Alexander Schulz-Rosengarten Date: Wed, 2 Jun 2021 19:08:07 +0200 Subject: [PATCH 47/88] oomph: Adjusted target platform to include kotlin plugin --- oomph/LinguaFranca.setup | 6 +++++- .../org.lflang.targetplatform.target | 8 +++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/oomph/LinguaFranca.setup b/oomph/LinguaFranca.setup index 6daa34662f..68c4d280b0 100644 --- a/oomph/LinguaFranca.setup +++ b/oomph/LinguaFranca.setup @@ -182,7 +182,7 @@ + url="https://download.jetbrains.com/kotlin/eclipse-plugin/last"/> + + diff --git a/org.lflang.targetplatform/org.lflang.targetplatform.target b/org.lflang.targetplatform/org.lflang.targetplatform.target index 7e3e08461d..18625f0ce5 100644 --- a/org.lflang.targetplatform/org.lflang.targetplatform.target +++ b/org.lflang.targetplatform/org.lflang.targetplatform.target @@ -1,6 +1,6 @@ - + @@ -19,6 +19,8 @@ + + @@ -40,6 +42,10 @@ + + + + From 7eb9d408463b30b3b233ec0120aae744d4e1752e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Thu, 3 Jun 2021 12:06:14 +0200 Subject: [PATCH 48/88] Commit LFStandaloneSetup --- org.lflang/pom.xml | 2 +- org.lflang/src/org/lflang/LFStandaloneSetup.java | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 org.lflang/src/org/lflang/LFStandaloneSetup.java diff --git a/org.lflang/pom.xml b/org.lflang/pom.xml index 6f2fd431ee..d48bbf30fd 100644 --- a/org.lflang/pom.xml +++ b/org.lflang/pom.xml @@ -102,7 +102,7 @@ - + diff --git a/org.lflang/src/org/lflang/LFStandaloneSetup.java b/org.lflang/src/org/lflang/LFStandaloneSetup.java new file mode 100644 index 0000000000..d163b73fff --- /dev/null +++ b/org.lflang/src/org/lflang/LFStandaloneSetup.java @@ -0,0 +1,15 @@ +/* + * generated by Xtext 2.25.0 + */ +package org.lflang; + + +/** + * Initialization support for running Xtext languages without Equinox extension registry. + */ +public class LFStandaloneSetup extends LFStandaloneSetupGenerated { + + public static void doSetup() { + new LFStandaloneSetup().createInjectorAndDoEMFRegistration(); + } +} From 1665f76c69791435b0c86f3dc0c7e5241491e819 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Thu, 3 Jun 2021 14:15:37 +0200 Subject: [PATCH 49/88] Add kotlin osgi bundle to manifest The bundle version seems unrelated to the kotlin version we use. For now this doesn't cause problems in the build apparently... The bundled-compiler bundle is distributed by the kotlin-eclipse plugin: https://github.com/JetBrains/kotlin-eclipse --- org.lflang/META-INF/MANIFEST.MF | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/org.lflang/META-INF/MANIFEST.MF b/org.lflang/META-INF/MANIFEST.MF index 781becbe42..4725e9f337 100644 --- a/org.lflang/META-INF/MANIFEST.MF +++ b/org.lflang/META-INF/MANIFEST.MF @@ -17,7 +17,8 @@ Require-Bundle: org.eclipse.xtext, org.antlr.runtime;bundle-version="[3.2.0,3.2.1)", com.google.guava, org.eclipse.xtend.lib.macro, - org.apache.commons.cli;bundle-version="1.4" + org.apache.commons.cli;bundle-version="1.4", + org.jetbrains.kotlin.bundled-compiler Bundle-RequiredExecutionEnvironment: JavaSE-11 Export-Package: org.lflang, org.lflang.generator, From 81965278e3b181ef284296fbe0514d89d8aa56e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Fri, 4 Jun 2021 12:33:14 +0200 Subject: [PATCH 50/88] Add src-gen, xtend-gen to clean task --- build.gradle | 7 ++++--- .../lflang/web/AbstractLinguaFrancaWebModule.java | 14 -------------- 2 files changed, 4 insertions(+), 17 deletions(-) delete mode 100644 org.lflang.web/src-gen/org/lflang/web/AbstractLinguaFrancaWebModule.java diff --git a/build.gradle b/build.gradle index 716d678b4d..1a1fd0eb38 100644 --- a/build.gradle +++ b/build.gradle @@ -60,8 +60,9 @@ subprojects { } // Delete generated sources on `gradle clean` - clean.doLast { - delete "${projectDir}/xtend-gen" - delete "${projectDir}/src-gen" + clean.doFirst { + project.logger.info("Deleting ${projectDir}/xtend-gen, src-gen") + delete "${projectDir}/xtend-gen/" + delete "${projectDir}/src-gen/" } } diff --git a/org.lflang.web/src-gen/org/lflang/web/AbstractLinguaFrancaWebModule.java b/org.lflang.web/src-gen/org/lflang/web/AbstractLinguaFrancaWebModule.java deleted file mode 100644 index 54d043579f..0000000000 --- a/org.lflang.web/src-gen/org/lflang/web/AbstractLinguaFrancaWebModule.java +++ /dev/null @@ -1,14 +0,0 @@ -/* - * generated by Xtext 2.18.0 - */ -package org.lflang.web; - -import org.eclipse.xtext.web.server.DefaultWebModule; - -/** - * Manual modifications go to {@link LinguaFrancaWebModule}. - */ -@SuppressWarnings("all") -public abstract class AbstractLinguaFrancaWebModule extends DefaultWebModule { - -} From 027f0dc4a0fefbf5f6e28b59b5a1c36c1474a9b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Fri, 4 Jun 2021 13:33:44 +0200 Subject: [PATCH 51/88] Convert xtend in web module to kotlin/java --- org.lflang.web/build.gradle | 1 + .../org/lflang/web/LinguaFrancaServlet.java | 39 +++++++++++++ .../org/lflang/web/LinguaFrancaServlet.xtend | 32 ----------- .../org/lflang/web/LinguaFrancaWebModule.java | 10 ++++ .../lflang/web/LinguaFrancaWebModule.xtend | 11 ---- .../org/lflang/web/LinguaFrancaWebSetup.java | 20 +++++++ .../org/lflang/web/LinguaFrancaWebSetup.xtend | 22 -------- .../src/org/lflang/web/ServerLauncher.kt | 55 +++++++++++++++++++ .../src/org/lflang/web/ServerLauncher.xtend | 54 ------------------ 9 files changed, 125 insertions(+), 119 deletions(-) create mode 100644 org.lflang.web/src/org/lflang/web/LinguaFrancaServlet.java delete mode 100644 org.lflang.web/src/org/lflang/web/LinguaFrancaServlet.xtend create mode 100644 org.lflang.web/src/org/lflang/web/LinguaFrancaWebModule.java delete mode 100644 org.lflang.web/src/org/lflang/web/LinguaFrancaWebModule.xtend create mode 100644 org.lflang.web/src/org/lflang/web/LinguaFrancaWebSetup.java delete mode 100644 org.lflang.web/src/org/lflang/web/LinguaFrancaWebSetup.xtend create mode 100644 org.lflang.web/src/org/lflang/web/ServerLauncher.kt delete mode 100644 org.lflang.web/src/org/lflang/web/ServerLauncher.xtend diff --git a/org.lflang.web/build.gradle b/org.lflang.web/build.gradle index df451ee459..fdbe8212af 100644 --- a/org.lflang.web/build.gradle +++ b/org.lflang.web/build.gradle @@ -13,6 +13,7 @@ dependencies { providedCompile "org.eclipse.jetty:jetty-annotations:9.4.14.v20181114" providedCompile "org.slf4j:slf4j-simple:1.7.21" } + task jettyRun(type:JavaExec) { dependsOn(sourceSets.main.runtimeClasspath) classpath = sourceSets.main.runtimeClasspath.filter{it.exists()} diff --git a/org.lflang.web/src/org/lflang/web/LinguaFrancaServlet.java b/org.lflang.web/src/org/lflang/web/LinguaFrancaServlet.java new file mode 100644 index 0000000000..a9f7e60623 --- /dev/null +++ b/org.lflang.web/src/org/lflang/web/LinguaFrancaServlet.java @@ -0,0 +1,39 @@ +/* + * generated by Xtext 2.18.0 + */ +package org.lflang.web; + +import javax.servlet.ServletException; +import javax.servlet.annotation.WebServlet; +import org.eclipse.xtext.util.DisposableRegistry; +import org.eclipse.xtext.web.servlet.XtextServlet; + +import com.google.inject.Injector; + +/** + * Deploy this class into a servlet container to enable DSL-specific services. + */ +@WebServlet(name = "XtextServices", urlPatterns = "/xtext-service/*") +class LinguaFrancaServlet extends XtextServlet { + + private DisposableRegistry disposableRegistry; + + + @Override + public void init() throws ServletException { + super.init(); + Injector injector = new LinguaFrancaWebSetup().createInjectorAndDoEMFRegistration(); + disposableRegistry = injector.getInstance(DisposableRegistry.class); + } + + + @Override + public void destroy() { + if (disposableRegistry != null) { + disposableRegistry.dispose(); + disposableRegistry = null; + } + super.destroy(); + } + +} diff --git a/org.lflang.web/src/org/lflang/web/LinguaFrancaServlet.xtend b/org.lflang.web/src/org/lflang/web/LinguaFrancaServlet.xtend deleted file mode 100644 index 01e584d4ea..0000000000 --- a/org.lflang.web/src/org/lflang/web/LinguaFrancaServlet.xtend +++ /dev/null @@ -1,32 +0,0 @@ -/* - * generated by Xtext 2.18.0 - */ -package org.lflang.web - -import javax.servlet.annotation.WebServlet -import org.eclipse.xtext.util.DisposableRegistry -import org.eclipse.xtext.web.servlet.XtextServlet - -/** - * Deploy this class into a servlet container to enable DSL-specific services. - */ -@WebServlet(name = 'XtextServices', urlPatterns = '/xtext-service/*') -class LinguaFrancaServlet extends XtextServlet { - - DisposableRegistry disposableRegistry - - override init() { - super.init() - val injector = new LinguaFrancaWebSetup().createInjectorAndDoEMFRegistration() - disposableRegistry = injector.getInstance(DisposableRegistry) - } - - override destroy() { - if (disposableRegistry !== null) { - disposableRegistry.dispose() - disposableRegistry = null - } - super.destroy() - } - -} diff --git a/org.lflang.web/src/org/lflang/web/LinguaFrancaWebModule.java b/org.lflang.web/src/org/lflang/web/LinguaFrancaWebModule.java new file mode 100644 index 0000000000..5b47934d54 --- /dev/null +++ b/org.lflang.web/src/org/lflang/web/LinguaFrancaWebModule.java @@ -0,0 +1,10 @@ +package org.lflang.web; + +import org.eclipse.xtext.web.server.DefaultWebModule; + + +/** + * Use this class to register additional components to be used within the web application. + */ +class LinguaFrancaWebModule extends DefaultWebModule { +} diff --git a/org.lflang.web/src/org/lflang/web/LinguaFrancaWebModule.xtend b/org.lflang.web/src/org/lflang/web/LinguaFrancaWebModule.xtend deleted file mode 100644 index c866a668df..0000000000 --- a/org.lflang.web/src/org/lflang/web/LinguaFrancaWebModule.xtend +++ /dev/null @@ -1,11 +0,0 @@ -/* - * generated by Xtext 2.18.0 - */ -package org.lflang.web - - -/** - * Use this class to register additional components to be used within the web application. - */ -class LinguaFrancaWebModule extends AbstractLinguaFrancaWebModule { -} diff --git a/org.lflang.web/src/org/lflang/web/LinguaFrancaWebSetup.java b/org.lflang.web/src/org/lflang/web/LinguaFrancaWebSetup.java new file mode 100644 index 0000000000..845a1f0af1 --- /dev/null +++ b/org.lflang.web/src/org/lflang/web/LinguaFrancaWebSetup.java @@ -0,0 +1,20 @@ +package org.lflang.web; + +import com.google.inject.Guice; +import com.google.inject.Injector; +import org.eclipse.xtext.util.Modules2; +import org.lflang.LFRuntimeModule; +import org.lflang.LFStandaloneSetup; +import org.lflang.ide.LFIdeModule; + +/** + * Initialization support for running Xtext languages in web applications. + */ +class LinguaFrancaWebSetup extends LFStandaloneSetup { + + @Override + public Injector createInjector() { + return Guice.createInjector(Modules2.mixin(new LFRuntimeModule(), new LFIdeModule(), new LinguaFrancaWebModule())); + } + +} diff --git a/org.lflang.web/src/org/lflang/web/LinguaFrancaWebSetup.xtend b/org.lflang.web/src/org/lflang/web/LinguaFrancaWebSetup.xtend deleted file mode 100644 index 240c8516bb..0000000000 --- a/org.lflang.web/src/org/lflang/web/LinguaFrancaWebSetup.xtend +++ /dev/null @@ -1,22 +0,0 @@ -/* - * generated by Xtext 2.18.0 - */ -package org.lflang.web - -import com.google.inject.Guice -import com.google.inject.Injector -import org.eclipse.xtext.util.Modules2 -import org.lflang.LFRuntimeModule -import org.lflang.LFStandaloneSetup -import org.lflang.ide.LFIdeModule - -/** - * Initialization support for running Xtext languages in web applications. - */ -class LinguaFrancaWebSetup extends LFStandaloneSetup { - - override Injector createInjector() { - return Guice.createInjector(Modules2.mixin(new LFRuntimeModule, new LFIdeModule, new LinguaFrancaWebModule)) - } - -} diff --git a/org.lflang.web/src/org/lflang/web/ServerLauncher.kt b/org.lflang.web/src/org/lflang/web/ServerLauncher.kt new file mode 100644 index 0000000000..2775ce9bc6 --- /dev/null +++ b/org.lflang.web/src/org/lflang/web/ServerLauncher.kt @@ -0,0 +1,55 @@ +@file:JvmName("ServerLauncher") + +package org.lflang.web + +import java.net.InetSocketAddress +import org.eclipse.jetty.annotations.AnnotationConfiguration +import org.eclipse.jetty.server.Server +import org.eclipse.jetty.util.log.Slf4jLog +import org.eclipse.jetty.webapp.MetaInfConfiguration +import org.eclipse.jetty.webapp.WebAppContext +import org.eclipse.jetty.webapp.WebInfConfiguration +import org.eclipse.jetty.webapp.WebXmlConfiguration +import kotlin.concurrent.thread +import kotlin.system.exitProcess + +/** + * This program starts an HTTP server for testing the web integration of your DSL. + * Just execute it and point a web browser to http://localhost:8080/ + */ +fun main(args: Array) { + val server = Server(InetSocketAddress("localhost", 8080)) + server.handler = WebAppContext().apply { + resourceBase = "WebRoot" + welcomeFiles = arrayOf("index.html") + contextPath = "/" + configurations = arrayOf( + AnnotationConfiguration(), + WebXmlConfiguration(), + WebInfConfiguration(), + MetaInfConfiguration() + ) + setAttribute(WebInfConfiguration.CONTAINER_JAR_PATTERN, ".*/org\\.icyphy\\.linguafranca\\.web/.*,.*\\.jar") + setInitParameter("org.mortbay.jetty.servlet.Default.useFileMappedBuffer", "false") + } + + val log = Slf4jLog("org.lflang.web.ServerLauncher") + try { + server.start() + log.info("Server started ${server.uri}...") + + thread(start = true) { + log.info("Press enter to stop the server...") + val key = System.`in`.read() + if (key != -1) { + server.stop() + } else { + log.warn("Console input is not available. In order to stop the server, you need to cancel process manually.") + } + } + server.join() + } catch (exception: Exception) { + log.warn(exception.message) + exitProcess(1) + } +} diff --git a/org.lflang.web/src/org/lflang/web/ServerLauncher.xtend b/org.lflang.web/src/org/lflang/web/ServerLauncher.xtend deleted file mode 100644 index 7a79795fc0..0000000000 --- a/org.lflang.web/src/org/lflang/web/ServerLauncher.xtend +++ /dev/null @@ -1,54 +0,0 @@ -/* - * generated by Xtext 2.18.0 - */ -package org.lflang.web - -import java.net.InetSocketAddress -import org.eclipse.jetty.annotations.AnnotationConfiguration -import org.eclipse.jetty.server.Server -import org.eclipse.jetty.util.log.Slf4jLog -import org.eclipse.jetty.webapp.MetaInfConfiguration -import org.eclipse.jetty.webapp.WebAppContext -import org.eclipse.jetty.webapp.WebInfConfiguration -import org.eclipse.jetty.webapp.WebXmlConfiguration - -/** - * This program starts an HTTP server for testing the web integration of your DSL. - * Just execute it and point a web browser to http://localhost:8080/ - */ -class ServerLauncher { - def static void main(String[] args) { - val server = new Server(new InetSocketAddress('localhost', 8080)) - server.handler = new WebAppContext => [ - resourceBase = 'WebRoot' - welcomeFiles = #["index.html"] - contextPath = "/" - configurations = #[ - new AnnotationConfiguration, - new WebXmlConfiguration, - new WebInfConfiguration, - new MetaInfConfiguration - ] - setAttribute(WebInfConfiguration.CONTAINER_JAR_PATTERN, '.*/org\\.icyphy\\.linguafranca\\.web/.*,.*\\.jar') - setInitParameter("org.mortbay.jetty.servlet.Default.useFileMappedBuffer", "false") - ] - val log = new Slf4jLog(ServerLauncher.name) - try { - server.start - log.info('Server started ' + server.getURI + '...') - new Thread[ - log.info('Press enter to stop the server...') - val key = System.in.read - if (key != -1) { - server.stop - } else { - log.warn('Console input is not available. In order to stop the server, you need to cancel process manually.') - } - ].start - server.join - } catch (Exception exception) { - log.warn(exception.message) - System.exit(1) - } - } -} From a5d3623a8ed0b500ee2191e0e953f6b704687192 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Fri, 4 Jun 2021 14:12:29 +0200 Subject: [PATCH 52/88] Revert some changes Prep for PR --- .gitignore | 34 +++++++++++++++------------------- org.lflang/pom.xml | 1 + 2 files changed, 16 insertions(+), 19 deletions(-) diff --git a/.gitignore b/.gitignore index cfd52d468c..b25ba96973 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,18 @@ +*.lft +*.out +*.class +*.DS_Store +*.xml_gen +*.xtendbin +*._trace +.project/ +.settings/ +**/bin/ +!./bin/ +**/build/ +**/test-bin/ +**/src-gen/ +**/xtend-gen/ # Created by https://www.toptal.com/developers/gitignore/api/intellij,gradle,eclipse,maven,visualstudiocode # Edit at https://www.toptal.com/developers/gitignore?templates=intellij,gradle,eclipse,maven,visualstudiocode @@ -135,22 +150,3 @@ gradle-app.setting **/build/ # End of https://www.toptal.com/developers/gitignore/api/intellij,gradle,eclipse,maven,visualstudiocode - -# Custom entries -*.lft -*.out -*.class -*.DS_Store -*.xml_gen -*.xtendbin -*._trace -**/bin/ -!./bin/ -**/build/ -**/test-bin/ -**/src-gen/ -**/xtend-gen/ -test/Cpp/include -test/Cpp/share -test/Cpp/lib - diff --git a/org.lflang/pom.xml b/org.lflang/pom.xml index d48bbf30fd..a3f843413c 100644 --- a/org.lflang/pom.xml +++ b/org.lflang/pom.xml @@ -87,6 +87,7 @@ xtend-maven-plugin + maven-antrun-plugin 3.0.0 From 39f08160a840cc39f7709fdf51a39bd34b761bbb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Fri, 4 Jun 2021 14:17:17 +0200 Subject: [PATCH 53/88] Upgrade kotlin to 1.5.0 --- build.gradle | 2 +- pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 1a1fd0eb38..647e41e7d8 100644 --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,5 @@ buildscript { - ext.kotlinVersion = "1.5.0-RC" // sync with pom.xml + ext.kotlinVersion = "1.5.0" // sync with pom.xml repositories { mavenCentral() } diff --git a/pom.xml b/pom.xml index 2519f8bf90..eeb1a67086 100644 --- a/pom.xml +++ b/pom.xml @@ -30,7 +30,7 @@ - 1.5.0-RC + 1.5.0 11 11 2.3.0 From cbd34acf0073fbea3e7d2908f1a88aa5e0ff5049 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Fri, 4 Jun 2021 14:34:30 +0200 Subject: [PATCH 54/88] Test converting standalone setup to kotlin --- org.lflang/pom.xml | 2 +- org.lflang/src/org/lflang/LFStandaloneSetup.java | 15 --------------- org.lflang/src/org/lflang/LFStandaloneSetup.kt | 9 +++++++++ 3 files changed, 10 insertions(+), 16 deletions(-) delete mode 100644 org.lflang/src/org/lflang/LFStandaloneSetup.java create mode 100644 org.lflang/src/org/lflang/LFStandaloneSetup.kt diff --git a/org.lflang/pom.xml b/org.lflang/pom.xml index a3f843413c..ffee11a0a4 100644 --- a/org.lflang/pom.xml +++ b/org.lflang/pom.xml @@ -103,7 +103,7 @@ - + diff --git a/org.lflang/src/org/lflang/LFStandaloneSetup.java b/org.lflang/src/org/lflang/LFStandaloneSetup.java deleted file mode 100644 index d163b73fff..0000000000 --- a/org.lflang/src/org/lflang/LFStandaloneSetup.java +++ /dev/null @@ -1,15 +0,0 @@ -/* - * generated by Xtext 2.25.0 - */ -package org.lflang; - - -/** - * Initialization support for running Xtext languages without Equinox extension registry. - */ -public class LFStandaloneSetup extends LFStandaloneSetupGenerated { - - public static void doSetup() { - new LFStandaloneSetup().createInjectorAndDoEMFRegistration(); - } -} diff --git a/org.lflang/src/org/lflang/LFStandaloneSetup.kt b/org.lflang/src/org/lflang/LFStandaloneSetup.kt new file mode 100644 index 0000000000..1bacff3786 --- /dev/null +++ b/org.lflang/src/org/lflang/LFStandaloneSetup.kt @@ -0,0 +1,9 @@ +/* + * generated by Xtext 2.25.0 + */ +package org.lflang + +/** + * Initialization support for running Xtext languages without Equinox extension registry. + */ +open class LFStandaloneSetup : LFStandaloneSetupGenerated() From 4c0f025eca83fc81c3f0b080cfd9fcd3800d4374 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Fri, 4 Jun 2021 15:42:08 +0200 Subject: [PATCH 55/88] Use kotlin OSGI bundle directly We can't control the version of the bundled-compiler bundle from kotlin-eclipse --- org.lflang/META-INF/MANIFEST.MF | 2 +- pom.xml | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/org.lflang/META-INF/MANIFEST.MF b/org.lflang/META-INF/MANIFEST.MF index 4725e9f337..fd8a3d6dd6 100644 --- a/org.lflang/META-INF/MANIFEST.MF +++ b/org.lflang/META-INF/MANIFEST.MF @@ -18,7 +18,7 @@ Require-Bundle: org.eclipse.xtext, com.google.guava, org.eclipse.xtend.lib.macro, org.apache.commons.cli;bundle-version="1.4", - org.jetbrains.kotlin.bundled-compiler + org.jetbrains.kotlin.osgi-bundle;bundle-version="1.5.0" Bundle-RequiredExecutionEnvironment: JavaSE-11 Export-Package: org.lflang, org.lflang.generator, diff --git a/pom.xml b/pom.xml index eeb1a67086..adba8c076d 100644 --- a/pom.xml +++ b/pom.xml @@ -204,12 +204,14 @@ target-platform-configuration ${tycho-version} - + + + consider org.lflang org.lflang.targetplatform - 0.1.0-SNAPSHOT + ${project.version} From a35bd105977ba021ffc6dc48439f5e4bde91943b Mon Sep 17 00:00:00 2001 From: Christian Menard Date: Tue, 8 Jun 2021 14:33:08 +0200 Subject: [PATCH 56/88] ASTUtils: bugfix, search all reactor superclasses recursively --- org.lflang/src/org/lflang/AstExtensions.kt | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/org.lflang/src/org/lflang/AstExtensions.kt b/org.lflang/src/org/lflang/AstExtensions.kt index 953ac6c4a1..a692376c7e 100644 --- a/org.lflang/src/org/lflang/AstExtensions.kt +++ b/org.lflang/src/org/lflang/AstExtensions.kt @@ -91,10 +91,14 @@ val Reactor.allStateVars: List get() = this.superClassRecursor { this. */ val Reactor.allTimers: List get() = superClassRecursor { timers } +/** + * Apply the [collector] method recursively to the receiving reactor and all its superclasses. + * + * This collects the return values for indivudal reactors in a flat list, creating a collected list + * over all visisted reactors. + */ private fun Reactor.superClassRecursor(collector: Reactor.() -> List): List = - - - superClasses.orEmpty().mapNotNull { it.toDefinition().collector() }.flatten() + this.collector() + superClasses.orEmpty().mapNotNull { it.toDefinition().superClassRecursor(collector) }.flatten() + this.collector() val Parameter.isOfTimeType: Boolean get() = ASTUtils.isOfTimeType(this) From fb5d913cd18ffc722e1dce1bb95d7c6eeaa54b79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Tue, 8 Jun 2021 15:09:35 +0200 Subject: [PATCH 57/88] Also rename function --- org.lflang/src/org/lflang/AstExtensions.kt | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/org.lflang/src/org/lflang/AstExtensions.kt b/org.lflang/src/org/lflang/AstExtensions.kt index a692376c7e..66ed2d643f 100644 --- a/org.lflang/src/org/lflang/AstExtensions.kt +++ b/org.lflang/src/org/lflang/AstExtensions.kt @@ -41,55 +41,55 @@ fun ReactorDecl.toDefinition(): Reactor = when (this) { * Given a reactor class, return a list of all its actions, * which includes actions of base classes that it extends. */ -val Reactor.allActions: List get() = superClassRecursor { actions } +val Reactor.allActions: List get() = collectInSupertypes { actions } /** * Given a reactor class, return a list of all its connections, * which includes connections of base classes that it extends. */ -val Reactor.allConnections: List get() = superClassRecursor { connections } +val Reactor.allConnections: List get() = collectInSupertypes { connections } /** * Given a reactor class, return a list of all its inputs, * which includes inputs of base classes that it extends. */ -val Reactor.allInputs: List get() = superClassRecursor { inputs } +val Reactor.allInputs: List get() = collectInSupertypes { inputs } /** * Given a reactor class, return a list of all its outputs, * which includes outputs of base classes that it extends. */ -val Reactor.allOutputs: List get() = superClassRecursor { outputs } +val Reactor.allOutputs: List get() = collectInSupertypes { outputs } /** * Given a reactor class, return a list of all its instantiations, * which includes instantiations of base classes that it extends. */ -val Reactor.allInstantiations: List get() = superClassRecursor { instantiations } +val Reactor.allInstantiations: List get() = collectInSupertypes { instantiations } /** * Given a reactor class, return a list of all its parameters, * which includes parameters of base classes that it extends. */ -val Reactor.allParameters: List get() = superClassRecursor { parameters } +val Reactor.allParameters: List get() = collectInSupertypes { parameters } /** * Given a reactor class, return a list of all its reactions, * which includes reactions of base classes that it extends. */ -val Reactor.allReactions: List get() = superClassRecursor { reactions } +val Reactor.allReactions: List get() = collectInSupertypes { reactions } /** * Given a reactor class, return a list of all its state variables, * which includes state variables of base classes that it extends. */ -val Reactor.allStateVars: List get() = this.superClassRecursor { this.stateVars } +val Reactor.allStateVars: List get() = collectInSupertypes { stateVars } /** * Given a reactor class, return a list of all its timers, * which includes timers of base classes that it extends. */ -val Reactor.allTimers: List get() = superClassRecursor { timers } +val Reactor.allTimers: List get() = collectInSupertypes { timers } /** * Apply the [collector] method recursively to the receiving reactor and all its superclasses. @@ -97,8 +97,8 @@ val Reactor.allTimers: List get() = superClassRecursor { timers } * This collects the return values for indivudal reactors in a flat list, creating a collected list * over all visisted reactors. */ -private fun Reactor.superClassRecursor(collector: Reactor.() -> List): List = - superClasses.orEmpty().mapNotNull { it.toDefinition().superClassRecursor(collector) }.flatten() + this.collector() +private fun Reactor.collectInSupertypes(collector: Reactor.() -> List): List = + superClasses.orEmpty().mapNotNull { it.toDefinition().collectInSupertypes(collector) }.flatten() + this.collector() val Parameter.isOfTimeType: Boolean get() = ASTUtils.isOfTimeType(this) From caae126c78789315f1af8fac24cf5ee8826e63b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Wed, 9 Jun 2021 12:09:59 +0200 Subject: [PATCH 58/88] Use kotlin 1.5.10 --- 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 48530009993895d93d8efcc2e5e4cbfb18cafcb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Wed, 9 Jun 2021 12:16:39 +0200 Subject: [PATCH 59/88] Remove gitignore for LFParsingTest --- org.lflang.tests/.gitignore | 1 - 1 file changed, 1 deletion(-) delete mode 100644 org.lflang.tests/.gitignore diff --git a/org.lflang.tests/.gitignore b/org.lflang.tests/.gitignore deleted file mode 100644 index 3fcdf48338..0000000000 --- a/org.lflang.tests/.gitignore +++ /dev/null @@ -1 +0,0 @@ -src/org/lflang/tests/LFParsingTest.xtend \ No newline at end of file From 24d73cd11c8b508a20b776fd7f00b6f83e19f1fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Wed, 9 Jun 2021 12:21:24 +0200 Subject: [PATCH 60/88] Put xtext cleanup in a doLast This is better than a separate task because it will necessarily be executed. Otherwise the cleanup is only executed if some other task depends on it, eg `compileKotlin`, but not if you call `gradle generateXtextLanguage` --- org.lflang/build.gradle | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/org.lflang/build.gradle b/org.lflang/build.gradle index f50102af82..4b8b47afba 100644 --- a/org.lflang/build.gradle +++ b/org.lflang/build.gradle @@ -29,19 +29,16 @@ task generateXtextLanguage(type: JavaExec) { args += "src/org/lflang/GenerateLinguaFranca.mwe2" args += "-p" args += "rootPath=/${projectDir}/.." -} - -task cleanupXtextFilesThatWeWriteOurselves(type: Delete) { - dependsOn(generateXtextLanguage) - def filesToDelete = [ - "org.lflang.validation.LFValidator", - "org.lflang.LFRuntimeModule", - "org.lflang.LFStandaloneSetup", - "org.lflang.generator.LFGenerator", - "org.lflang.scoping.LFScopeProvider" - ] doLast { + def filesToDelete = [ + "org.lflang.validation.LFValidator", + "org.lflang.LFRuntimeModule", + "org.lflang.LFStandaloneSetup", + "org.lflang.generator.LFGenerator", + "org.lflang.scoping.LFScopeProvider" + ] + filesToDelete.each { qname -> def path = qname.replace('.', '/') def ktFile = file("src/${path}.kt") @@ -51,7 +48,7 @@ task cleanupXtextFilesThatWeWriteOurselves(type: Delete) { if (ktFile.exists() || xtendFile.exists()) { def chosenLang = ktFile.exists() ? "Kotlin" : "Xtend" project.logger.info("deleting ${projectDir.relativePath(javaFile)}, the ${chosenLang} file prevails") - delete(javaFile) // generated by Xtend + project.delete(javaFile) // generated by Xtend } else { project.logger.info("no ${projectDir.relativePath(ktFile)}, leaving the Java implementation in") } @@ -59,8 +56,6 @@ task cleanupXtextFilesThatWeWriteOurselves(type: Delete) { } } -compileKotlin.dependsOn(cleanupXtextFilesThatWeWriteOurselves) - generateXtext.dependsOn(generateXtextLanguage) clean.dependsOn(cleanGenerateXtextLanguage) eclipse.classpath.plusConfigurations += [configurations.mwe2] From d9699f91340455676fbd1553d95651fc44ca1421 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Wed, 9 Jun 2021 12:22:47 +0200 Subject: [PATCH 61/88] Refresh eclipse files --- org.lflang.ide/.classpath | 285 +++++++- org.lflang.ide/.project | 36 +- .../.settings/org.eclipse.jdt.core.prefs | 12 +- org.lflang.tests/.classpath | 394 ++++++++++- org.lflang.tests/.project | 36 +- .../.settings/org.eclipse.jdt.core.prefs | 12 +- org.lflang.web/.classpath | 474 ++++++++++++- org.lflang.web/.project | 39 +- .../.settings/org.eclipse.jdt.core.prefs | 12 +- org.lflang/.classpath | 313 ++++++++- org.lflang/.project | 36 +- .../.settings/org.eclipse.jdt.core.prefs | 658 +++++++++--------- 12 files changed, 1862 insertions(+), 445 deletions(-) diff --git a/org.lflang.ide/.classpath b/org.lflang.ide/.classpath index 91283994da..96113596ef 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..dea554748e 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 +# +#Wed Jun 09 12:22:29 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..12d33275b5 100644 --- a/org.lflang.tests/.classpath +++ b/org.lflang.tests/.classpath @@ -1,28 +1,414 @@ - + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dea554748e 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 +# +#Wed Jun 09 12:22:29 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.web/.classpath b/org.lflang.web/.classpath index 4609f05ef3..73406051c3 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..dea554748e 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 +# +#Wed Jun 09 12:22:29 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..04a089ca11 100644 --- a/org.lflang/.classpath +++ b/org.lflang/.classpath @@ -1,25 +1,330 @@ - + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..ea3e9fc927 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 +# +#Wed Jun 09 12:22:29 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 From 82bee03f7833539fdd690edee6eedb5ca5f93e37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Wed, 9 Jun 2021 16:49:13 +0200 Subject: [PATCH 62/88] Update osgi bundle version in manifest --- build.gradle | 2 +- org.lflang/META-INF/MANIFEST.MF | 2 +- pom.xml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/build.gradle b/build.gradle index 6a6d27f522..8c71b8350e 100644 --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,5 @@ buildscript { - ext.kotlinVersion = "1.5.10" // sync with pom.xml + ext.kotlinVersion = "1.5.10" // sync with pom.xml and MANIFEST.mf repositories { mavenCentral() } diff --git a/org.lflang/META-INF/MANIFEST.MF b/org.lflang/META-INF/MANIFEST.MF index fd8a3d6dd6..3b5f26604b 100644 --- a/org.lflang/META-INF/MANIFEST.MF +++ b/org.lflang/META-INF/MANIFEST.MF @@ -18,7 +18,7 @@ Require-Bundle: org.eclipse.xtext, com.google.guava, org.eclipse.xtend.lib.macro, org.apache.commons.cli;bundle-version="1.4", - org.jetbrains.kotlin.osgi-bundle;bundle-version="1.5.0" + org.jetbrains.kotlin.osgi-bundle;bundle-version="1.5.10" Bundle-RequiredExecutionEnvironment: JavaSE-11 Export-Package: org.lflang, org.lflang.generator, diff --git a/pom.xml b/pom.xml index 7724f2b45a..bffa8b5da9 100644 --- a/pom.xml +++ b/pom.xml @@ -30,7 +30,7 @@ - 1.5.10 + 1.5.10 11 11 2.3.0 From dbdaf2472ed983fc143c87891aedbc95de06f667 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Thu, 10 Jun 2021 15:02:23 +0200 Subject: [PATCH 63/88] Ignore some files generated by the build Issue is similar to #348 --- example/.gitignore | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/example/.gitignore b/example/.gitignore index 62a9173771..f842b2dff2 100644 --- a/example/.gitignore +++ b/example/.gitignore @@ -6,4 +6,6 @@ /*/test-bin/ /*/src-gen/ my_trace - +include +lib +share From f515c56ce7a4547916ce2c38416eac9a148a7715 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Fri, 11 Jun 2021 12:00:15 +0200 Subject: [PATCH 64/88] Fix the RCA built with mvn (missing kotlin dep) --- org.lflang.rca/pom.xml | 8 ++++++++ pom.xml | 7 +++++++ 2 files changed, 15 insertions(+) diff --git a/org.lflang.rca/pom.xml b/org.lflang.rca/pom.xml index b63bd8639e..1c7d8d65cb 100644 --- a/org.lflang.rca/pom.xml +++ b/org.lflang.rca/pom.xml @@ -18,6 +18,14 @@ + + org.eclipse.tycho + tycho-p2-repository-plugin + ${tycho-version} + + true + + org.eclipse.tycho tycho-p2-director-plugin diff --git a/pom.xml b/pom.xml index bffa8b5da9..7b3df2b420 100644 --- a/pom.xml +++ b/pom.xml @@ -238,6 +238,13 @@ + + + org.jetbrains.kotlin + kotlin-osgi-bundle + + + From b38bfcfc53a1d6782b4d6686fe0b84a5e39e0e24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Wed, 16 Jun 2021 14:03:38 +0200 Subject: [PATCH 65/88] Use bundled-compiler from eclipse project --- build.gradle | 2 +- org.lflang/META-INF/MANIFEST.MF | 2 +- pom.xml | 21 +++------------------ 3 files changed, 5 insertions(+), 20 deletions(-) diff --git a/build.gradle b/build.gradle index 34dfcc18ea..45bdaae265 100644 --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,5 @@ buildscript { - ext.kotlinVersion = "1.5.10" // sync with pom.xml and MANIFEST.mf + ext.kotlinVersion = "1.4.10" // sync with pom.xml repositories { mavenCentral() } diff --git a/org.lflang/META-INF/MANIFEST.MF b/org.lflang/META-INF/MANIFEST.MF index 3b5f26604b..4725e9f337 100644 --- a/org.lflang/META-INF/MANIFEST.MF +++ b/org.lflang/META-INF/MANIFEST.MF @@ -18,7 +18,7 @@ Require-Bundle: org.eclipse.xtext, com.google.guava, org.eclipse.xtend.lib.macro, org.apache.commons.cli;bundle-version="1.4", - org.jetbrains.kotlin.osgi-bundle;bundle-version="1.5.10" + org.jetbrains.kotlin.bundled-compiler Bundle-RequiredExecutionEnvironment: JavaSE-11 Export-Package: org.lflang, org.lflang.generator, diff --git a/pom.xml b/pom.xml index 7b3df2b420..48aa15f1f5 100644 --- a/pom.xml +++ b/pom.xml @@ -30,7 +30,9 @@ - 1.5.10 + + + 1.4.10 11 11 2.3.0 @@ -238,21 +240,4 @@ - - - org.jetbrains.kotlin - kotlin-osgi-bundle - - - - - - - org.jetbrains.kotlin - kotlin-osgi-bundle - ${kotlin.version} - - - - From 2c88bac6fea9585c8fac415c4ad9d3e85cb618b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Wed, 16 Jun 2021 14:15:06 +0200 Subject: [PATCH 66/88] Commit eclipse files (absolute paths...) --- org.lflang.ide/.classpath | 31 +++---- .../.settings/org.eclipse.jdt.core.prefs | 2 +- org.lflang.tests/.classpath | 87 +++++++++---------- .../.settings/org.eclipse.jdt.core.prefs | 2 +- org.lflang.web/.classpath | 48 +++++----- .../.settings/org.eclipse.jdt.core.prefs | 2 +- org.lflang/.classpath | 21 ++--- .../.settings/org.eclipse.jdt.core.prefs | 6 +- 8 files changed, 89 insertions(+), 110 deletions(-) diff --git a/org.lflang.ide/.classpath b/org.lflang.ide/.classpath index 96113596ef..79055456e6 100644 --- a/org.lflang.ide/.classpath +++ b/org.lflang.ide/.classpath @@ -53,7 +53,7 @@ - + @@ -63,12 +63,12 @@ - + - + @@ -193,7 +193,7 @@ - + @@ -203,16 +203,6 @@ - - - - - - - - - - @@ -233,6 +223,11 @@ + + + + + @@ -248,7 +243,7 @@ - + @@ -258,7 +253,7 @@ - + @@ -283,7 +278,7 @@ - + @@ -293,7 +288,7 @@ - + diff --git a/org.lflang.ide/.settings/org.eclipse.jdt.core.prefs b/org.lflang.ide/.settings/org.eclipse.jdt.core.prefs index dea554748e..b22252a4e3 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 @@ # -#Wed Jun 09 12:22:29 CEST 2021 +#Wed Jun 16 14:14:40 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 12d33275b5..7c19b68e20 100644 --- a/org.lflang.tests/.classpath +++ b/org.lflang.tests/.classpath @@ -26,7 +26,7 @@ - + @@ -36,12 +36,27 @@ - + - + + + + + + + + + + + + + + + + @@ -56,7 +71,7 @@ - + @@ -66,72 +81,72 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -166,7 +181,7 @@ - + @@ -176,7 +191,7 @@ - + @@ -201,7 +216,7 @@ - + @@ -211,7 +226,7 @@ - + @@ -241,26 +256,6 @@ - - - - - - - - - - - - - - - - - - - - @@ -279,25 +274,25 @@ - + - + - + - + diff --git a/org.lflang.tests/.settings/org.eclipse.jdt.core.prefs b/org.lflang.tests/.settings/org.eclipse.jdt.core.prefs index dea554748e..b22252a4e3 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 @@ # -#Wed Jun 09 12:22:29 CEST 2021 +#Wed Jun 16 14:14:40 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 73406051c3..025b0b5e23 100644 --- a/org.lflang.web/.classpath +++ b/org.lflang.web/.classpath @@ -91,7 +91,7 @@ - + @@ -103,13 +103,13 @@ - + - + @@ -295,7 +295,7 @@ - + @@ -307,12 +307,6 @@ - - - - - - @@ -337,46 +331,46 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -433,7 +427,7 @@ - + @@ -445,7 +439,7 @@ - + @@ -475,7 +469,7 @@ - + @@ -487,7 +481,7 @@ - + diff --git a/org.lflang.web/.settings/org.eclipse.jdt.core.prefs b/org.lflang.web/.settings/org.eclipse.jdt.core.prefs index dea554748e..4b17d5f141 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 @@ # -#Wed Jun 09 12:22:29 CEST 2021 +#Wed Jun 16 14:14:41 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 04a089ca11..c9cd8072e8 100644 --- a/org.lflang/.classpath +++ b/org.lflang/.classpath @@ -57,7 +57,7 @@ - + @@ -67,17 +67,17 @@ - + - + - + @@ -87,7 +87,7 @@ - + @@ -172,7 +172,7 @@ - + @@ -182,7 +182,7 @@ - + @@ -222,7 +222,7 @@ - + @@ -232,11 +232,6 @@ - - - - - diff --git a/org.lflang/.settings/org.eclipse.jdt.core.prefs b/org.lflang/.settings/org.eclipse.jdt.core.prefs index ea3e9fc927..0e88cf3b8b 100644 --- a/org.lflang/.settings/org.eclipse.jdt.core.prefs +++ b/org.lflang/.settings/org.eclipse.jdt.core.prefs @@ -1,12 +1,12 @@ # -#Wed Jun 09 12:22:29 CEST 2021 +#Wed Jun 16 14:14:40 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 c0cc5e678b540bf69b452eb152eff3eda2b1792c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Wed, 16 Jun 2021 14:36:02 +0200 Subject: [PATCH 67/88] Fix maven build, RCA ok Launch Runtime Eclipse is still bugged for some reason. --- org.lflang.tests/pom.xml | 6 ------ org.lflang/pom.xml | 8 -------- 2 files changed, 14 deletions(-) diff --git a/org.lflang.tests/pom.xml b/org.lflang.tests/pom.xml index 59afa871cc..2a8ae18507 100644 --- a/org.lflang.tests/pom.xml +++ b/org.lflang.tests/pom.xml @@ -107,10 +107,4 @@ - - - org.jetbrains.kotlin - kotlin-osgi-bundle - - diff --git a/org.lflang/pom.xml b/org.lflang/pom.xml index ffee11a0a4..07bd135bf5 100644 --- a/org.lflang/pom.xml +++ b/org.lflang/pom.xml @@ -200,12 +200,4 @@ - - - org.jetbrains.kotlin - kotlin-osgi-bundle - - - - From 589b3b313ec7b9957fdcc27d9c7e316da8b49ac0 Mon Sep 17 00:00:00 2001 From: Christian Menard Date: Thu, 17 Jun 2021 09:07:40 +0200 Subject: [PATCH 68/88] Revert "Commit eclipse files" This reverts commit 2c88bac6fea9585c8fac415c4ad9d3e85cb618b9. --- org.lflang.ide/.classpath | 31 ++++--- .../.settings/org.eclipse.jdt.core.prefs | 2 +- org.lflang.tests/.classpath | 87 ++++++++++--------- .../.settings/org.eclipse.jdt.core.prefs | 2 +- org.lflang.web/.classpath | 48 +++++----- .../.settings/org.eclipse.jdt.core.prefs | 2 +- org.lflang/.classpath | 21 +++-- .../.settings/org.eclipse.jdt.core.prefs | 6 +- 8 files changed, 110 insertions(+), 89 deletions(-) diff --git a/org.lflang.ide/.classpath b/org.lflang.ide/.classpath index 79055456e6..96113596ef 100644 --- a/org.lflang.ide/.classpath +++ b/org.lflang.ide/.classpath @@ -53,7 +53,7 @@ - + @@ -63,12 +63,12 @@ - + - + @@ -193,7 +193,7 @@ - + @@ -203,27 +203,32 @@ - + - + - + - + - + + + + + + @@ -243,7 +248,7 @@ - + @@ -253,7 +258,7 @@ - + @@ -278,7 +283,7 @@ - + @@ -288,7 +293,7 @@ - + diff --git a/org.lflang.ide/.settings/org.eclipse.jdt.core.prefs b/org.lflang.ide/.settings/org.eclipse.jdt.core.prefs index b22252a4e3..dea554748e 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 @@ # -#Wed Jun 16 14:14:40 CEST 2021 +#Wed Jun 09 12:22:29 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 7c19b68e20..12d33275b5 100644 --- a/org.lflang.tests/.classpath +++ b/org.lflang.tests/.classpath @@ -26,7 +26,7 @@ - + @@ -36,27 +36,12 @@ - + - - - - - - - - - - - - - - - - + @@ -71,7 +56,7 @@ - + @@ -81,72 +66,72 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -181,7 +166,7 @@ - + @@ -191,7 +176,7 @@ - + @@ -216,7 +201,7 @@ - + @@ -226,7 +211,7 @@ - + @@ -256,6 +241,26 @@ + + + + + + + + + + + + + + + + + + + + @@ -274,25 +279,25 @@ - + - + - + - + diff --git a/org.lflang.tests/.settings/org.eclipse.jdt.core.prefs b/org.lflang.tests/.settings/org.eclipse.jdt.core.prefs index b22252a4e3..dea554748e 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 @@ # -#Wed Jun 16 14:14:40 CEST 2021 +#Wed Jun 09 12:22:29 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 025b0b5e23..73406051c3 100644 --- a/org.lflang.web/.classpath +++ b/org.lflang.web/.classpath @@ -91,7 +91,7 @@ - + @@ -103,13 +103,13 @@ - + - + @@ -295,7 +295,7 @@ - + @@ -307,6 +307,12 @@ + + + + + + @@ -331,46 +337,46 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -427,7 +433,7 @@ - + @@ -439,7 +445,7 @@ - + @@ -469,7 +475,7 @@ - + @@ -481,7 +487,7 @@ - + diff --git a/org.lflang.web/.settings/org.eclipse.jdt.core.prefs b/org.lflang.web/.settings/org.eclipse.jdt.core.prefs index 4b17d5f141..dea554748e 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 @@ # -#Wed Jun 16 14:14:41 CEST 2021 +#Wed Jun 09 12:22:29 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 c9cd8072e8..04a089ca11 100644 --- a/org.lflang/.classpath +++ b/org.lflang/.classpath @@ -57,7 +57,7 @@ - + @@ -67,17 +67,17 @@ - + - + - + @@ -87,7 +87,7 @@ - + @@ -172,7 +172,7 @@ - + @@ -182,7 +182,7 @@ - + @@ -222,7 +222,7 @@ - + @@ -232,6 +232,11 @@ + + + + + diff --git a/org.lflang/.settings/org.eclipse.jdt.core.prefs b/org.lflang/.settings/org.eclipse.jdt.core.prefs index 0e88cf3b8b..ea3e9fc927 100644 --- a/org.lflang/.settings/org.eclipse.jdt.core.prefs +++ b/org.lflang/.settings/org.eclipse.jdt.core.prefs @@ -1,12 +1,12 @@ # -#Wed Jun 16 14:14:40 CEST 2021 +#Wed Jun 09 12:22:29 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.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_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 @@ -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.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_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 From e5fc5da75c34d29d5e0c0e5aa0b3be5decbb64a6 Mon Sep 17 00:00:00 2001 From: Christian Menard Date: Thu, 17 Jun 2021 09:07:58 +0200 Subject: [PATCH 69/88] Revert "Refresh eclipse files" This reverts commit d9699f91340455676fbd1553d95651fc44ca1421. --- org.lflang.ide/.classpath | 285 +------- org.lflang.ide/.project | 36 +- .../.settings/org.eclipse.jdt.core.prefs | 12 +- org.lflang.tests/.classpath | 394 +---------- org.lflang.tests/.project | 36 +- .../.settings/org.eclipse.jdt.core.prefs | 12 +- org.lflang.web/.classpath | 474 +------------ org.lflang.web/.project | 39 +- .../.settings/org.eclipse.jdt.core.prefs | 12 +- org.lflang/.classpath | 313 +-------- org.lflang/.project | 36 +- .../.settings/org.eclipse.jdt.core.prefs | 660 +++++++++--------- 12 files changed, 446 insertions(+), 1863 deletions(-) diff --git a/org.lflang.ide/.classpath b/org.lflang.ide/.classpath index 96113596ef..91283994da 100644 --- a/org.lflang.ide/.classpath +++ b/org.lflang.ide/.classpath @@ -1,301 +1,26 @@ - + - + - + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/org.lflang.ide/.project b/org.lflang.ide/.project index 15dda3eb9a..d0c289aac8 100644 --- a/org.lflang.ide/.project +++ b/org.lflang.ide/.project @@ -2,40 +2,47 @@ 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 @@ -43,5 +50,4 @@ 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 dea554748e..3056f74d3b 100644 --- a/org.lflang.ide/.settings/org.eclipse.jdt.core.prefs +++ b/org.lflang.ide/.settings/org.eclipse.jdt.core.prefs @@ -1,10 +1,8 @@ -# -#Wed Jun 09 12:22:29 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 -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.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.source=11 diff --git a/org.lflang.tests/.classpath b/org.lflang.tests/.classpath index 12d33275b5..90e203fa3a 100644 --- a/org.lflang.tests/.classpath +++ b/org.lflang.tests/.classpath @@ -1,414 +1,28 @@ - + - + - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/org.lflang.tests/.project b/org.lflang.tests/.project index 03c3b00d39..76b0dc0dd0 100644 --- a/org.lflang.tests/.project +++ b/org.lflang.tests/.project @@ -2,40 +2,47 @@ 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 @@ -43,5 +50,4 @@ 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 dea554748e..3056f74d3b 100644 --- a/org.lflang.tests/.settings/org.eclipse.jdt.core.prefs +++ b/org.lflang.tests/.settings/org.eclipse.jdt.core.prefs @@ -1,10 +1,8 @@ -# -#Wed Jun 09 12:22:29 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 -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.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.source=11 diff --git a/org.lflang.web/.classpath b/org.lflang.web/.classpath index 73406051c3..4609f05ef3 100644 --- a/org.lflang.web/.classpath +++ b/org.lflang.web/.classpath @@ -1,23 +1,24 @@ - + - + - + + @@ -26,471 +27,4 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/org.lflang.web/.project b/org.lflang.web/.project index a798c094fd..8d94631494 100644 --- a/org.lflang.web/.project +++ b/org.lflang.web/.project @@ -2,42 +2,48 @@ 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 @@ -45,5 +51,4 @@ 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 dea554748e..3056f74d3b 100644 --- a/org.lflang.web/.settings/org.eclipse.jdt.core.prefs +++ b/org.lflang.web/.settings/org.eclipse.jdt.core.prefs @@ -1,10 +1,8 @@ -# -#Wed Jun 09 12:22:29 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 -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.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.source=11 diff --git a/org.lflang/.classpath b/org.lflang/.classpath index 04a089ca11..1b604e5af8 100644 --- a/org.lflang/.classpath +++ b/org.lflang/.classpath @@ -1,330 +1,25 @@ - + - + - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/org.lflang/.project b/org.lflang/.project index 8f7f2a25fc..3b22ebf011 100644 --- a/org.lflang/.project +++ b/org.lflang/.project @@ -2,40 +2,47 @@ 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 @@ -43,5 +50,4 @@ 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 ea3e9fc927..9d92e3c736 100644 --- a/org.lflang/.settings/org.eclipse.jdt.core.prefs +++ b/org.lflang/.settings/org.eclipse.jdt.core.prefs @@ -1,365 +1,363 @@ -# -#Wed Jun 09 12:22:29 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 +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 org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled org.eclipse.jdt.core.compiler.problem.enumIdentifier=error -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.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.align_variable_declarations_on_columns=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.align_with_spaces=false org.eclipse.jdt.core.formatter.alignment_for_additive_operator=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_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.alignment_for_arguments_in_explicit_constructor_call=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.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_constructor_declaration=end_of_line -org.eclipse.jdt.core.formatter.brace_position_for_lambda_body=end_of_line -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.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.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_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_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.align_type_members_on_columns=false +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_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.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_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.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_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_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.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_module_statements=16 +org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16 +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.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.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.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_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.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.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.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.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.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.comment.clear_blank_lines_in_block_comment=true +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.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.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.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_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_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_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.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.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_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.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.insert_space_after_unary_operator=do not 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_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_assignment_operator=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_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_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_after_arrow_in_switch_case=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_before_colon_in_assert=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_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_space_before_logical_operator=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_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_angle_bracket_in_type_arguments=do not 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.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.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.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_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_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.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_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.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_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_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_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.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_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.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.insert_space_before_shift_operator=insert 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.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_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.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.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.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.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.tabulation.char=space -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.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.wrap_before_string_concatenation=true -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 +org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true +org.eclipse.jdt.core.javaFormatter=org.eclipse.jdt.core.defaultJavaFormatter From 1ed49cf3d2c2c89ba2422b1314045eb10eec1fa4 Mon Sep 17 00:00:00 2001 From: Christian Menard Date: Thu, 17 Jun 2021 09:38:24 +0200 Subject: [PATCH 70/88] add xtend-gen directories to prevent build errors --- org.lflang.ide/xtend-gen/.gitignore | 5 +++++ org.lflang.ui.tests/xtend-gen/.gitignore | 5 +++++ org.lflang.web/xtend-gen/.gitignore | 5 +++++ 3 files changed, 15 insertions(+) create mode 100644 org.lflang.ide/xtend-gen/.gitignore create mode 100644 org.lflang.ui.tests/xtend-gen/.gitignore create mode 100644 org.lflang.web/xtend-gen/.gitignore diff --git a/org.lflang.ide/xtend-gen/.gitignore b/org.lflang.ide/xtend-gen/.gitignore new file mode 100644 index 0000000000..ed273976ba --- /dev/null +++ b/org.lflang.ide/xtend-gen/.gitignore @@ -0,0 +1,5 @@ +# This file is only here to add the otherwise empty xtend-gen directory to the repo +# Ignore everything in this directory +* +# Except this file +!.gitignore diff --git a/org.lflang.ui.tests/xtend-gen/.gitignore b/org.lflang.ui.tests/xtend-gen/.gitignore new file mode 100644 index 0000000000..ed273976ba --- /dev/null +++ b/org.lflang.ui.tests/xtend-gen/.gitignore @@ -0,0 +1,5 @@ +# This file is only here to add the otherwise empty xtend-gen directory to the repo +# Ignore everything in this directory +* +# Except this file +!.gitignore diff --git a/org.lflang.web/xtend-gen/.gitignore b/org.lflang.web/xtend-gen/.gitignore new file mode 100644 index 0000000000..ed273976ba --- /dev/null +++ b/org.lflang.web/xtend-gen/.gitignore @@ -0,0 +1,5 @@ +# This file is only here to add the otherwise empty xtend-gen directory to the repo +# Ignore everything in this directory +* +# Except this file +!.gitignore From 529918a66812564eceb76e0eb2882d12db69ad89 Mon Sep 17 00:00:00 2001 From: Christian Menard Date: Thu, 17 Jun 2021 10:58:04 +0200 Subject: [PATCH 71/88] remove unused xtend-gen directories --- org.lflang.ide/.classpath | 6 ------ org.lflang.ide/xtend-gen/.gitignore | 5 ----- org.lflang.ui.tests/.classpath | 5 ----- org.lflang.ui.tests/xtend-gen/.gitignore | 5 ----- org.lflang.web/.classpath | 6 ------ org.lflang.web/.settings/org.eclipse.wst.common.component | 1 - org.lflang.web/xtend-gen/.gitignore | 5 ----- 7 files changed, 33 deletions(-) delete mode 100644 org.lflang.ide/xtend-gen/.gitignore delete mode 100644 org.lflang.ui.tests/xtend-gen/.gitignore delete mode 100644 org.lflang.web/xtend-gen/.gitignore diff --git a/org.lflang.ide/.classpath b/org.lflang.ide/.classpath index 91283994da..baba5b6ad0 100644 --- a/org.lflang.ide/.classpath +++ b/org.lflang.ide/.classpath @@ -6,12 +6,6 @@ - - - - - - diff --git a/org.lflang.ide/xtend-gen/.gitignore b/org.lflang.ide/xtend-gen/.gitignore deleted file mode 100644 index ed273976ba..0000000000 --- a/org.lflang.ide/xtend-gen/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -# This file is only here to add the otherwise empty xtend-gen directory to the repo -# Ignore everything in this directory -* -# Except this file -!.gitignore diff --git a/org.lflang.ui.tests/.classpath b/org.lflang.ui.tests/.classpath index 116a47ac18..5c18ede0c1 100644 --- a/org.lflang.ui.tests/.classpath +++ b/org.lflang.ui.tests/.classpath @@ -10,11 +10,6 @@ - - - - - diff --git a/org.lflang.ui.tests/xtend-gen/.gitignore b/org.lflang.ui.tests/xtend-gen/.gitignore deleted file mode 100644 index ed273976ba..0000000000 --- a/org.lflang.ui.tests/xtend-gen/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -# This file is only here to add the otherwise empty xtend-gen directory to the repo -# Ignore everything in this directory -* -# Except this file -!.gitignore diff --git a/org.lflang.web/.classpath b/org.lflang.web/.classpath index 4609f05ef3..9394ab9567 100644 --- a/org.lflang.web/.classpath +++ b/org.lflang.web/.classpath @@ -6,12 +6,6 @@ - - - - - - diff --git a/org.lflang.web/.settings/org.eclipse.wst.common.component b/org.lflang.web/.settings/org.eclipse.wst.common.component index e93ed3ca81..cdf8a7cee1 100644 --- a/org.lflang.web/.settings/org.eclipse.wst.common.component +++ b/org.lflang.web/.settings/org.eclipse.wst.common.component @@ -4,7 +4,6 @@ - uses diff --git a/org.lflang.web/xtend-gen/.gitignore b/org.lflang.web/xtend-gen/.gitignore deleted file mode 100644 index ed273976ba..0000000000 --- a/org.lflang.web/xtend-gen/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -# This file is only here to add the otherwise empty xtend-gen directory to the repo -# Ignore everything in this directory -* -# Except this file -!.gitignore From efa29031ab9b3bc054d2463676cfa8c0d3fb23f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Thu, 17 Jun 2021 15:38:47 +0200 Subject: [PATCH 72/88] Change default target --- oomph/LinguaFranca.setup | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/oomph/LinguaFranca.setup b/oomph/LinguaFranca.setup index 68c4d280b0..468c5cb27c 100644 --- a/oomph/LinguaFranca.setup +++ b/oomph/LinguaFranca.setup @@ -399,7 +399,7 @@ + url="https://dl.bintray.com/jetbrains/kotlin/eclipse-plugin/last/"/> @@ -474,6 +474,8 @@ versionRange="2.25.0"/> + + From 24c2bd3e805eaaa11f69ce872ea29263f3f15a9f Mon Sep 17 00:00:00 2001 From: Christian Menard Date: Thu, 17 Jun 2021 12:13:07 +0200 Subject: [PATCH 73/88] add eclipse files after 'Refresh Gradle Project' --- org.lflang.ide/.classpath | 2 +- org.lflang.ide/.project | 8 ++++---- org.lflang.tests/.project | 8 ++++---- org.lflang.web/.project | 10 +++++----- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/org.lflang.ide/.classpath b/org.lflang.ide/.classpath index baba5b6ad0..f2f202a205 100644 --- a/org.lflang.ide/.classpath +++ b/org.lflang.ide/.classpath @@ -12,9 +12,9 @@ + - diff --git a/org.lflang.ide/.project b/org.lflang.ide/.project index d0c289aac8..00d32931e3 100644 --- a/org.lflang.ide/.project +++ b/org.lflang.ide/.project @@ -6,22 +6,22 @@ - org.jetbrains.kotlin.ui.kotlinBuilder + org.eclipse.jdt.core.javabuilder - org.eclipse.jdt.core.javabuilder + org.eclipse.xtext.ui.shared.xtextBuilder - org.eclipse.xtext.ui.shared.xtextBuilder + org.eclipse.buildship.core.gradleprojectbuilder - org.eclipse.buildship.core.gradleprojectbuilder + org.jetbrains.kotlin.ui.kotlinBuilder diff --git a/org.lflang.tests/.project b/org.lflang.tests/.project index 76b0dc0dd0..ec198a5045 100644 --- a/org.lflang.tests/.project +++ b/org.lflang.tests/.project @@ -6,22 +6,22 @@ - org.jetbrains.kotlin.ui.kotlinBuilder + org.eclipse.jdt.core.javabuilder - org.eclipse.jdt.core.javabuilder + org.eclipse.xtext.ui.shared.xtextBuilder - org.eclipse.xtext.ui.shared.xtextBuilder + org.eclipse.buildship.core.gradleprojectbuilder - org.eclipse.buildship.core.gradleprojectbuilder + org.jetbrains.kotlin.ui.kotlinBuilder diff --git a/org.lflang.web/.project b/org.lflang.web/.project index 8d94631494..ca368bbe6f 100644 --- a/org.lflang.web/.project +++ b/org.lflang.web/.project @@ -5,11 +5,6 @@ - - org.jetbrains.kotlin.ui.kotlinBuilder - - - org.eclipse.jdt.core.javabuilder @@ -35,6 +30,11 @@ + + org.jetbrains.kotlin.ui.kotlinBuilder + + + org.eclipse.jdt.core.javanature From c1fe4be556117119762adfec14a267204c7816db Mon Sep 17 00:00:00 2001 From: Alexander Schulz-Rosengarten Date: Fri, 18 Jun 2021 11:01:25 +0200 Subject: [PATCH 74/88] oomph: Added weaving features to target platform --- oomph/LinguaFranca.setup | 31 +++++++++++++------ .../org.lflang.targetplatform.target | 12 +++++-- 2 files changed, 32 insertions(+), 11 deletions(-) diff --git a/oomph/LinguaFranca.setup b/oomph/LinguaFranca.setup index 468c5cb27c..a83b3eb45e 100644 --- a/oomph/LinguaFranca.setup +++ b/oomph/LinguaFranca.setup @@ -166,23 +166,28 @@ url="http://download.eclipse.org/modeling/tmf/xtext/updates/composite/releases/"/> Install the tools needed in the IDE to work with the source code for ${scope.project.label} - - - - - + + + + + + + + + + + diff --git a/org.lflang.targetplatform/org.lflang.targetplatform.target b/org.lflang.targetplatform/org.lflang.targetplatform.target index 18625f0ce5..fab853511e 100644 --- a/org.lflang.targetplatform/org.lflang.targetplatform.target +++ b/org.lflang.targetplatform/org.lflang.targetplatform.target @@ -1,12 +1,13 @@ - + + @@ -23,6 +24,8 @@ + + @@ -44,7 +47,11 @@ - + + + + + @@ -53,6 +60,7 @@ + From 69c424aea192410de5c4a74d3c759352676b9e61 Mon Sep 17 00:00:00 2001 From: Christian Menard Date: Wed, 23 Jun 2021 14:09:39 +0200 Subject: [PATCH 75/88] partially revert commit 4ba2bfce converts LFGenerator and LFRuntimeModule back to Java --- .../src/org/lflang/LFRuntimeModule.java | 27 ++++++ org.lflang/src/org/lflang/LFRuntimeModule.kt | 31 ------- .../src/org/lflang/generator/LFGenerator.java | 27 ++++++ .../src/org/lflang/generator/LFGenerator.kt | 84 ------------------- 4 files changed, 54 insertions(+), 115 deletions(-) create mode 100644 org.lflang/src/org/lflang/LFRuntimeModule.java delete mode 100644 org.lflang/src/org/lflang/LFRuntimeModule.kt create mode 100644 org.lflang/src/org/lflang/generator/LFGenerator.java delete mode 100644 org.lflang/src/org/lflang/generator/LFGenerator.kt diff --git a/org.lflang/src/org/lflang/LFRuntimeModule.java b/org.lflang/src/org/lflang/LFRuntimeModule.java new file mode 100644 index 0000000000..4d7d7fee34 --- /dev/null +++ b/org.lflang/src/org/lflang/LFRuntimeModule.java @@ -0,0 +1,27 @@ +/* + * generated by Xtext 2.23.0 + */ +package org.lflang; + +import org.lflang.scoping.LFGlobalScopeProvider; +import org.lflang.validation.LFNamesAreUniqueValidationHelper; + +/** + * Use this class to register components to be used at runtime / without the Equinox extension registry. + */ +public class LFRuntimeModule extends AbstractLFRuntimeModule { + /** Establish a binding to our custom global scope provider. */ + @Override + public Class bindIGlobalScopeProvider() { + return LFGlobalScopeProvider.class; + } + + /** Establish a binding to a helper that checks that names are unique. */ + public Class bindNamesAreUniqueValidationHelper() { + return LFNamesAreUniqueValidationHelper.class; + } + /** Establish a binding to our custom resource description strategy. */ +// fun bindIDefaultResourceDescriptionStrategy(): Class = LFResourceDescriptionStrategy::class.java + + +} diff --git a/org.lflang/src/org/lflang/LFRuntimeModule.kt b/org.lflang/src/org/lflang/LFRuntimeModule.kt deleted file mode 100644 index 13dcaa6017..0000000000 --- a/org.lflang/src/org/lflang/LFRuntimeModule.kt +++ /dev/null @@ -1,31 +0,0 @@ -/* - * generated by Xtext 2.23.0 - */ -package org.lflang - -import org.eclipse.xtext.resource.IDefaultResourceDescriptionStrategy -import org.eclipse.xtext.scoping.IGlobalScopeProvider -import org.eclipse.xtext.validation.NamesAreUniqueValidationHelper -import org.lflang.scoping.LFGlobalScopeProvider -import org.lflang.validation.LFNamesAreUniqueValidationHelper - -/** - * Use this class to register components to be used at runtime / without the Equinox extension registry. - */ -open class LFRuntimeModule : AbstractLFRuntimeModule() { - // note: don't use covariant return types here. The return type of each method must be - // Class, even though with covariance you could write Class - // Guice parses the return type apparently. - - /** Establish a binding to our custom global scope provider. */ - override fun bindIGlobalScopeProvider(): Class = - LFGlobalScopeProvider::class.java - - /** Establish a binding to a helper that checks that names are unique. */ - fun bindNamesAreUniqueValidationHelper(): Class = - LFNamesAreUniqueValidationHelper::class.java - - /** Establish a binding to our custom resource description strategy. */ - fun bindIDefaultResourceDescriptionStrategy(): Class = - LFResourceDescriptionStrategy::class.java -} diff --git a/org.lflang/src/org/lflang/generator/LFGenerator.java b/org.lflang/src/org/lflang/generator/LFGenerator.java new file mode 100644 index 0000000000..367d826a36 --- /dev/null +++ b/org.lflang/src/org/lflang/generator/LFGenerator.java @@ -0,0 +1,27 @@ +package org.lflang.generator; + +import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.xtext.generator.AbstractGenerator; +import org.eclipse.xtext.generator.IFileSystemAccess2; +import org.eclipse.xtext.generator.IGeneratorContext; + +/** + * Generates code from your model files on save. + * + * See https://www.eclipse.org/Xtext/documentation/303_runtime_concepts.html#code-generation + */ +public class LFGenerator extends AbstractGenerator { + + // Indicator of whether generator errors occurred. + protected boolean generatorErrorsOccurred = false; + + public void doGenerate(Resource resource, IFileSystemAccess2 fsa, IGeneratorContext context) { + generatorErrorsOccurred = LFGeneratorImpl.INSTANCE.doGenerate(resource, fsa, context); + } + + /** Return true if errors occurred in the last call to doGenerate(). */ + public boolean errorsOccurred() { + return generatorErrorsOccurred; + } + +} diff --git a/org.lflang/src/org/lflang/generator/LFGenerator.kt b/org.lflang/src/org/lflang/generator/LFGenerator.kt deleted file mode 100644 index 75dd9557ed..0000000000 --- a/org.lflang/src/org/lflang/generator/LFGenerator.kt +++ /dev/null @@ -1,84 +0,0 @@ -/* Generated by Xtext 2.17.0 and then modified to support specific targets. */ -/************* - * Copyright (c) 2019-2020, 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.generator - -import org.eclipse.emf.ecore.resource.Resource -import org.eclipse.xtext.generator.AbstractGenerator -import org.eclipse.xtext.generator.IFileSystemAccess2 -import org.eclipse.xtext.generator.IGeneratorContext -import org.lflang.Target -import org.lflang.lf.TargetDecl - -/** - * Generates code from your model files on save. - * - * See https://www.eclipse.org/Xtext/documentation/303_runtime_concepts.html#code-generation - */ -class LFGenerator : AbstractGenerator() { - - /** - * Is set if errors occurred in the last call to doGenerate(). - */ - var generatorErrorsOccurred = false - private set - - override fun doGenerate(resource: Resource, fsa: IFileSystemAccess2, context: IGeneratorContext) { - this.generatorErrorsOccurred = generateImpl(resource, fsa, context) - } - - companion object { - - private val TARGET_MAP: Map> = mapOf( - Target.C to CGenerator::class.java, - Target.CCPP to CCppGenerator::class.java, - Target.CPP to CppGenerator::class.java, - Target.TS to TypeScriptGenerator::class.java, - Target.Python to PythonGenerator::class.java - ) - - private fun getGenerator(target: Target): GeneratorBase { - val generatorClass = TARGET_MAP[target]!! - return try { - generatorClass.getConstructor().newInstance() - } catch (e: Exception) { - throw AssertionError("Missing constructor in $generatorClass", e) - } - } - - /** Returns true if some errors occurred. */ - private fun generateImpl(resource: Resource, fsa: IFileSystemAccess2, context: IGeneratorContext): Boolean { - // Determine which target is desired. - val targetName = findTargetNameOrThrow(resource) - val target = Target.forName(targetName) ?: throw AssertionError("Not a target '$targetName'") - return getGenerator(target).also { - it.doGenerate(resource, fsa, context) - }.errorsOccurred() - } - - private fun findTargetNameOrThrow(resource: Resource): String = - resource.allContents.asSequence() - .mapNotNull { it as? TargetDecl } - .firstOrNull() - ?.name - ?: throw AssertionError("No target declaration") - - } -} From c1ebd324581aae6396cc738c421e159bd387deea Mon Sep 17 00:00:00 2001 From: Christian Menard Date: Wed, 23 Jun 2021 14:35:34 +0200 Subject: [PATCH 76/88] fix LFRuntimeModule and LFGenerator --- .../src/org/lflang/LFRuntimeModule.java | 19 ++++--- .../src/org/lflang/generator/LFGenerator.java | 50 +++++++++++++++++-- 2 files changed, 58 insertions(+), 11 deletions(-) diff --git a/org.lflang/src/org/lflang/LFRuntimeModule.java b/org.lflang/src/org/lflang/LFRuntimeModule.java index 4d7d7fee34..b7da745e19 100644 --- a/org.lflang/src/org/lflang/LFRuntimeModule.java +++ b/org.lflang/src/org/lflang/LFRuntimeModule.java @@ -3,25 +3,32 @@ */ package org.lflang; +import org.eclipse.xtext.resource.IDefaultResourceDescriptionStrategy; +import org.eclipse.xtext.scoping.IGlobalScopeProvider; +import org.eclipse.xtext.validation.INamesAreUniqueValidationHelper; import org.lflang.scoping.LFGlobalScopeProvider; import org.lflang.validation.LFNamesAreUniqueValidationHelper; /** - * Use this class to register components to be used at runtime / without the Equinox extension registry. + * Use this class to register components to be used at runtime / without the + * Equinox extension registry. */ public class LFRuntimeModule extends AbstractLFRuntimeModule { + + /** Establish a binding to our custom resource description strategy. */ + public Class bindIDefaultResourceDescriptionStrategy() { + return LFResourceDescriptionStrategy.class; + } + /** Establish a binding to our custom global scope provider. */ @Override - public Class bindIGlobalScopeProvider() { + public Class bindIGlobalScopeProvider() { return LFGlobalScopeProvider.class; } /** Establish a binding to a helper that checks that names are unique. */ - public Class bindNamesAreUniqueValidationHelper() { + public Class bindNamesAreUniqueValidationHelper() { return LFNamesAreUniqueValidationHelper.class; } - /** Establish a binding to our custom resource description strategy. */ -// fun bindIDefaultResourceDescriptionStrategy(): Class = LFResourceDescriptionStrategy::class.java - } diff --git a/org.lflang/src/org/lflang/generator/LFGenerator.java b/org.lflang/src/org/lflang/generator/LFGenerator.java index 367d826a36..5d9aa31451 100644 --- a/org.lflang/src/org/lflang/generator/LFGenerator.java +++ b/org.lflang/src/org/lflang/generator/LFGenerator.java @@ -1,27 +1,67 @@ package org.lflang.generator; +import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.xtext.generator.AbstractGenerator; import org.eclipse.xtext.generator.IFileSystemAccess2; import org.eclipse.xtext.generator.IGeneratorContext; +import org.eclipse.xtext.xbase.lib.IterableExtensions; +import org.eclipse.xtext.xbase.lib.IteratorExtensions; +import org.lflang.Target; +import org.lflang.lf.TargetDecl; /** * Generates code from your model files on save. * - * See https://www.eclipse.org/Xtext/documentation/303_runtime_concepts.html#code-generation + * See + * https://www.eclipse.org/Xtext/documentation/303_runtime_concepts.html#code-generation */ public class LFGenerator extends AbstractGenerator { // Indicator of whether generator errors occurred. protected boolean generatorErrorsOccurred = false; - - public void doGenerate(Resource resource, IFileSystemAccess2 fsa, IGeneratorContext context) { - generatorErrorsOccurred = LFGeneratorImpl.INSTANCE.doGenerate(resource, fsa, context); + + public void doGenerate(Resource resource, IFileSystemAccess2 fsa, + IGeneratorContext context) { + // Determine which target is desired. + GeneratorBase generator = null; + + // first find the target decleration + // is there a better way to do this in plain Java? + final Iterable contentIterable = IteratorExtensions + .toIterable(resource.getAllContents()); + final Iterable targetDeclIterable = IterableExtensions + .filter(contentIterable, TargetDecl.class); + final String targetName = IterableExtensions.head(targetDeclIterable) + .getName(); + + // Get the actual target object + Target target = Target.forName(targetName); + + switch (target) { + case C: { + generator = new CGenerator(); + } + case CCPP: { + generator = new CCppGenerator(); + } + case CPP: { + generator = new CppGenerator(); + } + case TS: { + generator = new TypeScriptGenerator(); + } + case Python: { + generator = new PythonGenerator(); + } + } + + generator.doGenerate(resource, fsa, context); + generatorErrorsOccurred = generator.errorsOccurred(); } /** Return true if errors occurred in the last call to doGenerate(). */ public boolean errorsOccurred() { return generatorErrorsOccurred; } - } From 89eed91b6855361299a5d36581b3682e2465364d Mon Sep 17 00:00:00 2001 From: Christian Menard Date: Wed, 23 Jun 2021 14:42:21 +0200 Subject: [PATCH 77/88] revert LFScopeProvider to xtend --- .../org/lflang/scoping/LFScopeProvider.xtend | 255 ++++++++++++++++++ 1 file changed, 255 insertions(+) create mode 100644 org.lflang/src/org/lflang/scoping/LFScopeProvider.xtend diff --git a/org.lflang/src/org/lflang/scoping/LFScopeProvider.xtend b/org.lflang/src/org/lflang/scoping/LFScopeProvider.xtend new file mode 100644 index 0000000000..f9c24d87d8 --- /dev/null +++ b/org.lflang/src/org/lflang/scoping/LFScopeProvider.xtend @@ -0,0 +1,255 @@ +/* Scope provider for Lingua Franca. */ + +/************* +Copyright (c) 2020, 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.scoping + +import com.google.inject.Inject +import java.util.ArrayList +import org.eclipse.emf.ecore.EObject +import org.eclipse.emf.ecore.EReference +import org.eclipse.xtext.naming.SimpleNameProvider +import org.eclipse.xtext.scoping.IScope +import org.eclipse.xtext.scoping.Scopes +import org.eclipse.xtext.scoping.impl.SelectableBasedScope +import org.lflang.lf.Assignment +import org.lflang.lf.Connection +import org.lflang.lf.Deadline +import org.lflang.lf.Import +import org.lflang.lf.ImportedReactor +import org.lflang.lf.Instantiation +import org.lflang.lf.Model +import org.lflang.lf.Reaction +import org.lflang.lf.Reactor +import org.lflang.lf.VarRef +import org.lflang.lf.LfPackage + +import static extension org.lflang.ASTUtils.* + +/** + * This class enforces custom rules. In particular, it resolves references to + * parameters, ports, actions, and timers. Ports can be referenced across at + * most one level of hierarchy. Parameters, actions, and timers can be + * referenced locally, within the reactor. + * + * @see https://www.eclipse.org/Xtext/documentation/303_runtime_concepts.html#scoping + * on how and when to use it. + * @author Marten Lohstroh + */ +class LFScopeProvider extends AbstractLFScopeProvider { + + @Inject + SimpleNameProvider nameProvider + + @Inject + LFGlobalScopeProvider scopeProvider; + + /** + * Enumerate of the kinds of references. + */ + protected enum RefType { + NULL, + TRIGGER, + SOURCE, + EFFECT, + DEADLINE, + CLEFT, + CRIGHT + } + + /** + * Depending on the provided context, construct the appropriate scope + * for the given reference. + * @param context The AST node in which a to-be-resolved reference occurs. + * @param reference The reference to resolve. + */ + override getScope(EObject context, EReference reference) { + switch (context) { + VarRef: return getScopeForVarRef(context, reference) + Assignment: return getScopeForAssignment(context, reference) + Instantiation: return getScopeForReactorDecl(context, reference) + Reactor: return getScopeForReactorDecl(context, reference) + ImportedReactor: return getScopeForImportedReactor(context, reference) + } + return super.getScope(context, reference); + } + + /** + * Filter out candidates that do not originate from the file listed in + * this particular import statement. + */ + protected def getScopeForImportedReactor(ImportedReactor context, + EReference reference) { + val importedURI = scopeProvider.resolve( + (context.eContainer as Import).importURI ?: "", context.eResource) + if (importedURI !== null) { + + val uniqueImportURIs = scopeProvider.getImportedUris(context.eResource) + val descriptions = scopeProvider.getResourceDescriptions(context.eResource, uniqueImportURIs); + val uri = uniqueImportURIs.findFirst[it.equals(importedURI)] + val description = descriptions.getResourceDescription(uri); + return SelectableBasedScope.createScope(IScope.NULLSCOPE, description, null, reference.EReferenceType, false); + } + return Scopes.scopeFor(newLinkedList) + } + + /** + * + * @param obj Instantiation or Reactor that has a ReactorDecl to resolve. + * @param reference The reference to link to a ReactorDecl node. + */ + protected def getScopeForReactorDecl(EObject obj, EReference reference) { + var Model model + val locals = newLinkedList + + // Find the local Model + if (obj.eContainer instanceof Model) { + model = obj.eContainer as Model + } else if (obj.eContainer.eContainer instanceof Model) { + model = obj.eContainer.eContainer as Model + } else { + // Empty list + } + + // Collect eligible candidates, all of which are local (i.e., not in other files). + model.reactors?.forEach[locals.add(it)] + model.imports?.forEach [ + // Either point to the import statement (if it is renamed) + // or directly to the reactor definition. + it.reactorClasses?.forEach [ + (it.name !== null) ? locals.add(it) : + (it.reactorClass !== null) ? locals.add(it.reactorClass) + ] + ] + return Scopes.scopeFor(locals) + } + + /** + * + */ + protected def getScopeForAssignment(Assignment assignment, + EReference reference) { + + if (reference == LfPackage.Literals.ASSIGNMENT__LHS) { + val defn = (assignment.eContainer as Instantiation).reactorClass.toDefinition + if (defn !== null) { + return Scopes.scopeFor(defn.allParameters) + } + + } + if (reference == LfPackage.Literals.ASSIGNMENT__RHS) { + return Scopes.scopeFor( + (assignment.eContainer.eContainer as Reactor).parameters) + } + return Scopes.scopeFor(newLinkedList) + } + + /** + * + */ + protected def getScopeForVarRef(VarRef variable, EReference reference) { + if (reference == LfPackage.Literals.VAR_REF__VARIABLE) { + // Resolve hierarchical reference + val candidates = new ArrayList() + var type = RefType.NULL + var Reactor reactor = null + + if (variable.eContainer.eContainer instanceof Reactor) { + reactor = variable.eContainer.eContainer as Reactor + } else { + return Scopes.scopeFor(newLinkedList) + } + + if (variable.eContainer instanceof Deadline) { + type = RefType.DEADLINE + } else if (variable.eContainer instanceof Reaction) { + val reaction = variable.eContainer as Reaction + if (reaction.triggers.contains(variable)) { + type = RefType.TRIGGER + } else if (reaction.sources.contains(variable)) { + type = RefType.SOURCE + } else if (reaction.effects.contains(variable)) { + type = RefType.EFFECT + } + } else if (variable.eContainer instanceof Connection) { + val conn = variable.eContainer as Connection + if (conn.leftPorts.contains(variable)) { + type = RefType.CLEFT + } else if (conn.rightPorts.contains(variable)) { + type = RefType.CRIGHT + } + } + + if (variable.container !== null) { // Resolve hierarchical port reference + val instanceName = nameProvider. + getFullyQualifiedName(variable.container) + val instances = reactor.instantiations + + for (instance : instances) { + val defn = instance.reactorClass.toDefinition + if (defn !== null && instanceName !== null && + instance.name.equals(instanceName.toString)) { + if (type === RefType.TRIGGER || + type === RefType.SOURCE || type === RefType.CLEFT) { + return Scopes.scopeFor( + defn.allOutputs) + } else if (type === RefType.EFFECT || + type === RefType.DEADLINE || + type === RefType.CRIGHT) { + return Scopes.scopeFor(defn.allInputs) + } + } + } + return Scopes.scopeFor(candidates) // Empty list + } else { // Resolve local reference + switch (type) { + case RefType.TRIGGER: { + candidates.addAll(reactor.allInputs) + candidates.addAll(reactor.allActions) + candidates.addAll(reactor.allTimers) + } + case RefType.SOURCE: + return super.getScope(variable, reference) + case RefType.EFFECT: { + candidates.addAll(reactor.allOutputs) + candidates.addAll(reactor.allActions) + } + case RefType.DEADLINE: + return Scopes.scopeFor(reactor.allInputs) + case RefType.CLEFT: + return Scopes.scopeFor(reactor.allInputs) + case RefType.CRIGHT: + return Scopes.scopeFor(reactor.allOutputs) + default: { + } + } + return Scopes.scopeFor(candidates) + } + } else { // Resolve instance + return super.getScope(variable, reference) + } + } +} From dcfa23d8456a1ee0531e9c707eafb3d164d99b52 Mon Sep 17 00:00:00 2001 From: Christian Menard Date: Wed, 23 Jun 2021 14:44:36 +0200 Subject: [PATCH 78/88] Revert "Port one leaf of the dependency graph to kotlin" This reverts commit 1f2cc68e774f6a7a9555088c231c34637ca8f25e. --- .../LFNamesAreUniqueValidationHelper.kt | 50 ------------------- .../LFNamesAreUniqueValidationHelper.xtend | 28 +++++++++++ 2 files changed, 28 insertions(+), 50 deletions(-) delete mode 100644 org.lflang/src/org/lflang/validation/LFNamesAreUniqueValidationHelper.kt create mode 100644 org.lflang/src/org/lflang/validation/LFNamesAreUniqueValidationHelper.xtend diff --git a/org.lflang/src/org/lflang/validation/LFNamesAreUniqueValidationHelper.kt b/org.lflang/src/org/lflang/validation/LFNamesAreUniqueValidationHelper.kt deleted file mode 100644 index c69865c1b6..0000000000 --- a/org.lflang/src/org/lflang/validation/LFNamesAreUniqueValidationHelper.kt +++ /dev/null @@ -1,50 +0,0 @@ -/* - * 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.validation - -import org.eclipse.emf.ecore.EClass -import org.eclipse.xtext.validation.NamesAreUniqueValidationHelper -import org.lflang.lf.LfPackage - -class LFNamesAreUniqueValidationHelper : NamesAreUniqueValidationHelper() { - - /** - * Lump all inputs, outputs, timers, actions, parameters, and - * instantiations in the same cluster type. This ensures that - * names amongst them are checked for uniqueness. - */ - override fun getAssociatedClusterType(eClass: EClass): EClass? { - return when (eClass) { - LfPackage.Literals.INPUT, - LfPackage.Literals.OUTPUT, - LfPackage.Literals.TIMER, - LfPackage.Literals.ACTION, - LfPackage.Literals.PARAMETER, - LfPackage.Literals.INSTANTIATION, - -> LfPackage.Literals.VARIABLE - else -> super.getAssociatedClusterType(eClass) - } - } -} diff --git a/org.lflang/src/org/lflang/validation/LFNamesAreUniqueValidationHelper.xtend b/org.lflang/src/org/lflang/validation/LFNamesAreUniqueValidationHelper.xtend new file mode 100644 index 0000000000..2e7f0b6bd0 --- /dev/null +++ b/org.lflang/src/org/lflang/validation/LFNamesAreUniqueValidationHelper.xtend @@ -0,0 +1,28 @@ +package org.lflang.validation; + +import org.eclipse.emf.ecore.EClass +import org.eclipse.xtext.validation.NamesAreUniqueValidationHelper +import org.lflang.lf.LfPackage + +class LFNamesAreUniqueValidationHelper extends + NamesAreUniqueValidationHelper { + + /** + * Lump all inputs, outputs, timers, actions, parameters, and + * instantiations in the same cluster type. This ensures that + * names amongst them are checked for uniqueness. + */ + override getAssociatedClusterType(EClass eClass) { + if (LfPackage.Literals.INPUT == eClass || + LfPackage.Literals.OUTPUT == eClass || + LfPackage.Literals.TIMER == eClass || + LfPackage.Literals.ACTION == eClass || + LfPackage.Literals.PARAMETER == eClass || + LfPackage.Literals.INSTANTIATION == eClass + ) { + return LfPackage.Literals.VARIABLE; + } + return super.getAssociatedClusterType(eClass); + } + +} \ No newline at end of file From e041bf847d441e48f287e52eff368dc1df942e0b Mon Sep 17 00:00:00 2001 From: Christian Menard Date: Wed, 23 Jun 2021 14:48:22 +0200 Subject: [PATCH 79/88] revert LFStandaloneSetup to java --- .../src/org/lflang/LFStandaloneSetup.java | 15 ++ .../src/org/lflang/LFStandaloneSetup.kt | 9 - .../src/org/lflang/scoping/LFScopeProvider.kt | 193 ------------------ 3 files changed, 15 insertions(+), 202 deletions(-) create mode 100644 org.lflang/src/org/lflang/LFStandaloneSetup.java delete mode 100644 org.lflang/src/org/lflang/LFStandaloneSetup.kt delete mode 100644 org.lflang/src/org/lflang/scoping/LFScopeProvider.kt diff --git a/org.lflang/src/org/lflang/LFStandaloneSetup.java b/org.lflang/src/org/lflang/LFStandaloneSetup.java new file mode 100644 index 0000000000..d163b73fff --- /dev/null +++ b/org.lflang/src/org/lflang/LFStandaloneSetup.java @@ -0,0 +1,15 @@ +/* + * generated by Xtext 2.25.0 + */ +package org.lflang; + + +/** + * Initialization support for running Xtext languages without Equinox extension registry. + */ +public class LFStandaloneSetup extends LFStandaloneSetupGenerated { + + public static void doSetup() { + new LFStandaloneSetup().createInjectorAndDoEMFRegistration(); + } +} diff --git a/org.lflang/src/org/lflang/LFStandaloneSetup.kt b/org.lflang/src/org/lflang/LFStandaloneSetup.kt deleted file mode 100644 index 1bacff3786..0000000000 --- a/org.lflang/src/org/lflang/LFStandaloneSetup.kt +++ /dev/null @@ -1,9 +0,0 @@ -/* - * generated by Xtext 2.25.0 - */ -package org.lflang - -/** - * Initialization support for running Xtext languages without Equinox extension registry. - */ -open class LFStandaloneSetup : LFStandaloneSetupGenerated() diff --git a/org.lflang/src/org/lflang/scoping/LFScopeProvider.kt b/org.lflang/src/org/lflang/scoping/LFScopeProvider.kt deleted file mode 100644 index 1abbb05f74..0000000000 --- a/org.lflang/src/org/lflang/scoping/LFScopeProvider.kt +++ /dev/null @@ -1,193 +0,0 @@ -/* - * 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.scoping - -import com.google.inject.Inject -import org.eclipse.emf.common.util.URI -import org.eclipse.emf.ecore.EObject -import org.eclipse.emf.ecore.EReference -import org.eclipse.xtext.naming.SimpleNameProvider -import org.eclipse.xtext.scoping.IScope -import org.eclipse.xtext.scoping.Scopes -import org.eclipse.xtext.scoping.impl.SelectableBasedScope -import org.eclipse.xtext.xbase.lib.CollectionLiterals -import org.lflang.* -import org.lflang.lf.* -import java.util.Collections.emptyList - -/** - * This class enforces custom rules. In particular, it resolves references to - * parameters, ports, actions, and timers. Ports can be referenced across at - * most one level of hierarchy. Parameters, actions, and timers can be - * referenced locally, within the reactor. - * - * @see "https://www.eclipse.org/Xtext/documentation/303_runtime_concepts.html.scoping on how and when to use it." - * - * @author Marten Lohstroh - */ -class LFScopeProvider : AbstractLFScopeProvider() { - - @Inject - lateinit var nameProvider: SimpleNameProvider - - @Inject - lateinit var scopeProvider: LFGlobalScopeProvider - - - /** Enumerate of the kinds of references. */ - private enum class RefType { - NULL, TRIGGER, SOURCE, EFFECT, DEADLINE, CLEFT, CRIGHT - } - - /** - * Depending on the provided context, construct the appropriate scope - * for the given reference. - * @param context The AST node in which a to-be-resolved reference occurs. - * @param reference The reference to resolve. - */ - override fun getScope(context: EObject, reference: EReference): IScope = - when (context) { - is VarRef -> getScopeForVarRef(context, reference) - is Assignment -> getScopeForAssignment(context, reference) - is Instantiation -> getScopeForReactorDecl(context, reference) - is Reactor -> getScopeForReactorDecl(context, reference) - is ImportedReactor -> getScopeForImportedReactor(context, reference) - else -> super.getScope(context, reference) - } - - /** - * Filter out candidates that do not originate from the file listed in - * this particular import statement. - */ - private fun getScopeForImportedReactor(context: ImportedReactor, reference: EReference): IScope { - val importURI = (context.eContainer() as Import).importURI ?: "" - val importedURI = scopeProvider.resolve(importURI, context.eResource()) - if (importedURI != null) { - val uniqueImportURIs: Set = scopeProvider.getImportedUris(context.eResource()) - val uri = uniqueImportURIs.first { it == importedURI } - val descriptions = scopeProvider.getResourceDescriptions(context.eResource(), uniqueImportURIs) - val description = descriptions.getResourceDescription(uri) - return SelectableBasedScope.createScope(IScope.NULLSCOPE, description, null, reference.eReferenceType, false) - } - return Scopes.scopeFor(CollectionLiterals.newLinkedList()) - } - - /** - * @param obj Instantiation or Reactor that has a ReactorDecl to resolve. - * @param reference The reference to link to a ReactorDecl node. - */ - private fun getScopeForReactorDecl(obj: EObject, reference: EReference?): IScope { - val locals = mutableListOf() - - // Find the local Model - val model = obj.eContainer() as? Model - ?: obj.eContainer().eContainer() as? Model - ?: return Scopes.scopeFor(emptyList()) - - // Collect eligible candidates, all of which are local (i.e., not in other files). - model.reactors?.forEach { locals.add(it) } - model.imports?.forEach { import -> - // Either point to the import statement (if it is renamed) - // or directly to the reactor definition. - import.reactorClasses?.forEach { - if (it.name != null) locals.add(it) - else if (it.reactorClass != null) locals.add(it.reactorClass) - } - } - return Scopes.scopeFor(locals) - } - - private fun getScopeForAssignment(assignment: Assignment, reference: EReference?): IScope { - - if (reference == LfPackage.Literals.ASSIGNMENT__LHS) { - val defn = ((assignment.eContainer() as Instantiation).reactorClass)?.toDefinition() - if (defn != null) { - return Scopes.scopeFor(defn.allParameters) - } - } - if (reference == LfPackage.Literals.ASSIGNMENT__RHS) { - return Scopes.scopeFor((assignment.eContainer().eContainer() as Reactor).parameters) - } - return Scopes.scopeFor(emptyList()) - - } - - private fun getScopeForVarRef(variable: VarRef, reference: EReference?): IScope { - if (reference != LfPackage.Literals.VAR_REF__VARIABLE) { - return super.getScope(variable, reference) - } - - val reactor: Reactor = variable.eContainer().eContainer() as? Reactor - ?: return Scopes.scopeFor(emptyList()) - - val type = when (val eContainer = variable.eContainer()) { - is Deadline -> RefType.DEADLINE - is Reaction -> when (variable) { - in eContainer.triggers -> RefType.TRIGGER - in eContainer.sources -> RefType.SOURCE - in eContainer.effects -> RefType.EFFECT - else -> RefType.NULL - } - is Connection -> when (variable) { - in eContainer.leftPorts -> RefType.CLEFT - in eContainer.rightPorts -> RefType.CRIGHT - else -> RefType.NULL - } - else -> RefType.NULL - } - - if (variable.container != null) { // Resolve hierarchical port reference - val instanceName = nameProvider.getFullyQualifiedName(variable.container) - val instances = reactor.instantiations - - for (instance in instances) { - val defn = instance.reactorClass?.toDefinition() - if (defn != null && instanceName != null && instance.name == instanceName.toString()) { - return when (type) { - RefType.TRIGGER, RefType.SOURCE, RefType.CLEFT -> Scopes.scopeFor(defn.allOutputs) - RefType.EFFECT, RefType.DEADLINE, RefType.CRIGHT -> Scopes.scopeFor(defn.allInputs) - else -> Scopes.scopeFor(emptyList()) - } - } - } - } - if (type == RefType.SOURCE) - return super.getScope(variable, reference) - - val candidates: List = when (type) { - RefType.TRIGGER -> mutableListOf().apply { - this += reactor.allInputs - this += reactor.allActions - this += reactor.allTimers - } - RefType.EFFECT -> reactor.allOutputs + reactor.allActions - RefType.DEADLINE -> reactor.allInputs - RefType.CLEFT -> reactor.allInputs - RefType.CRIGHT -> reactor.allOutputs - else -> emptyList() - } - - return Scopes.scopeFor(candidates) - } -} From 9b86ca5075ed46842aaf437d2e7efaf03a26f0c8 Mon Sep 17 00:00:00 2001 From: Christian Menard Date: Wed, 23 Jun 2021 14:52:25 +0200 Subject: [PATCH 80/88] Revert "Convert xtend in web module to kotlin/java" This reverts commit 027f0dc4a0fefbf5f6e28b59b5a1c36c1474a9b7. --- org.lflang.web/build.gradle | 1 - .../org/lflang/web/LinguaFrancaServlet.java | 39 ------------- .../org/lflang/web/LinguaFrancaServlet.xtend | 32 +++++++++++ .../org/lflang/web/LinguaFrancaWebModule.java | 10 ---- .../lflang/web/LinguaFrancaWebModule.xtend | 11 ++++ .../org/lflang/web/LinguaFrancaWebSetup.java | 20 ------- .../org/lflang/web/LinguaFrancaWebSetup.xtend | 22 ++++++++ .../src/org/lflang/web/ServerLauncher.kt | 55 ------------------- .../src/org/lflang/web/ServerLauncher.xtend | 54 ++++++++++++++++++ 9 files changed, 119 insertions(+), 125 deletions(-) delete mode 100644 org.lflang.web/src/org/lflang/web/LinguaFrancaServlet.java create mode 100644 org.lflang.web/src/org/lflang/web/LinguaFrancaServlet.xtend delete mode 100644 org.lflang.web/src/org/lflang/web/LinguaFrancaWebModule.java create mode 100644 org.lflang.web/src/org/lflang/web/LinguaFrancaWebModule.xtend delete mode 100644 org.lflang.web/src/org/lflang/web/LinguaFrancaWebSetup.java create mode 100644 org.lflang.web/src/org/lflang/web/LinguaFrancaWebSetup.xtend delete mode 100644 org.lflang.web/src/org/lflang/web/ServerLauncher.kt create mode 100644 org.lflang.web/src/org/lflang/web/ServerLauncher.xtend diff --git a/org.lflang.web/build.gradle b/org.lflang.web/build.gradle index fdbe8212af..df451ee459 100644 --- a/org.lflang.web/build.gradle +++ b/org.lflang.web/build.gradle @@ -13,7 +13,6 @@ dependencies { providedCompile "org.eclipse.jetty:jetty-annotations:9.4.14.v20181114" providedCompile "org.slf4j:slf4j-simple:1.7.21" } - task jettyRun(type:JavaExec) { dependsOn(sourceSets.main.runtimeClasspath) classpath = sourceSets.main.runtimeClasspath.filter{it.exists()} diff --git a/org.lflang.web/src/org/lflang/web/LinguaFrancaServlet.java b/org.lflang.web/src/org/lflang/web/LinguaFrancaServlet.java deleted file mode 100644 index a9f7e60623..0000000000 --- a/org.lflang.web/src/org/lflang/web/LinguaFrancaServlet.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * generated by Xtext 2.18.0 - */ -package org.lflang.web; - -import javax.servlet.ServletException; -import javax.servlet.annotation.WebServlet; -import org.eclipse.xtext.util.DisposableRegistry; -import org.eclipse.xtext.web.servlet.XtextServlet; - -import com.google.inject.Injector; - -/** - * Deploy this class into a servlet container to enable DSL-specific services. - */ -@WebServlet(name = "XtextServices", urlPatterns = "/xtext-service/*") -class LinguaFrancaServlet extends XtextServlet { - - private DisposableRegistry disposableRegistry; - - - @Override - public void init() throws ServletException { - super.init(); - Injector injector = new LinguaFrancaWebSetup().createInjectorAndDoEMFRegistration(); - disposableRegistry = injector.getInstance(DisposableRegistry.class); - } - - - @Override - public void destroy() { - if (disposableRegistry != null) { - disposableRegistry.dispose(); - disposableRegistry = null; - } - super.destroy(); - } - -} diff --git a/org.lflang.web/src/org/lflang/web/LinguaFrancaServlet.xtend b/org.lflang.web/src/org/lflang/web/LinguaFrancaServlet.xtend new file mode 100644 index 0000000000..01e584d4ea --- /dev/null +++ b/org.lflang.web/src/org/lflang/web/LinguaFrancaServlet.xtend @@ -0,0 +1,32 @@ +/* + * generated by Xtext 2.18.0 + */ +package org.lflang.web + +import javax.servlet.annotation.WebServlet +import org.eclipse.xtext.util.DisposableRegistry +import org.eclipse.xtext.web.servlet.XtextServlet + +/** + * Deploy this class into a servlet container to enable DSL-specific services. + */ +@WebServlet(name = 'XtextServices', urlPatterns = '/xtext-service/*') +class LinguaFrancaServlet extends XtextServlet { + + DisposableRegistry disposableRegistry + + override init() { + super.init() + val injector = new LinguaFrancaWebSetup().createInjectorAndDoEMFRegistration() + disposableRegistry = injector.getInstance(DisposableRegistry) + } + + override destroy() { + if (disposableRegistry !== null) { + disposableRegistry.dispose() + disposableRegistry = null + } + super.destroy() + } + +} diff --git a/org.lflang.web/src/org/lflang/web/LinguaFrancaWebModule.java b/org.lflang.web/src/org/lflang/web/LinguaFrancaWebModule.java deleted file mode 100644 index 5b47934d54..0000000000 --- a/org.lflang.web/src/org/lflang/web/LinguaFrancaWebModule.java +++ /dev/null @@ -1,10 +0,0 @@ -package org.lflang.web; - -import org.eclipse.xtext.web.server.DefaultWebModule; - - -/** - * Use this class to register additional components to be used within the web application. - */ -class LinguaFrancaWebModule extends DefaultWebModule { -} diff --git a/org.lflang.web/src/org/lflang/web/LinguaFrancaWebModule.xtend b/org.lflang.web/src/org/lflang/web/LinguaFrancaWebModule.xtend new file mode 100644 index 0000000000..c866a668df --- /dev/null +++ b/org.lflang.web/src/org/lflang/web/LinguaFrancaWebModule.xtend @@ -0,0 +1,11 @@ +/* + * generated by Xtext 2.18.0 + */ +package org.lflang.web + + +/** + * Use this class to register additional components to be used within the web application. + */ +class LinguaFrancaWebModule extends AbstractLinguaFrancaWebModule { +} diff --git a/org.lflang.web/src/org/lflang/web/LinguaFrancaWebSetup.java b/org.lflang.web/src/org/lflang/web/LinguaFrancaWebSetup.java deleted file mode 100644 index 845a1f0af1..0000000000 --- a/org.lflang.web/src/org/lflang/web/LinguaFrancaWebSetup.java +++ /dev/null @@ -1,20 +0,0 @@ -package org.lflang.web; - -import com.google.inject.Guice; -import com.google.inject.Injector; -import org.eclipse.xtext.util.Modules2; -import org.lflang.LFRuntimeModule; -import org.lflang.LFStandaloneSetup; -import org.lflang.ide.LFIdeModule; - -/** - * Initialization support for running Xtext languages in web applications. - */ -class LinguaFrancaWebSetup extends LFStandaloneSetup { - - @Override - public Injector createInjector() { - return Guice.createInjector(Modules2.mixin(new LFRuntimeModule(), new LFIdeModule(), new LinguaFrancaWebModule())); - } - -} diff --git a/org.lflang.web/src/org/lflang/web/LinguaFrancaWebSetup.xtend b/org.lflang.web/src/org/lflang/web/LinguaFrancaWebSetup.xtend new file mode 100644 index 0000000000..240c8516bb --- /dev/null +++ b/org.lflang.web/src/org/lflang/web/LinguaFrancaWebSetup.xtend @@ -0,0 +1,22 @@ +/* + * generated by Xtext 2.18.0 + */ +package org.lflang.web + +import com.google.inject.Guice +import com.google.inject.Injector +import org.eclipse.xtext.util.Modules2 +import org.lflang.LFRuntimeModule +import org.lflang.LFStandaloneSetup +import org.lflang.ide.LFIdeModule + +/** + * Initialization support for running Xtext languages in web applications. + */ +class LinguaFrancaWebSetup extends LFStandaloneSetup { + + override Injector createInjector() { + return Guice.createInjector(Modules2.mixin(new LFRuntimeModule, new LFIdeModule, new LinguaFrancaWebModule)) + } + +} diff --git a/org.lflang.web/src/org/lflang/web/ServerLauncher.kt b/org.lflang.web/src/org/lflang/web/ServerLauncher.kt deleted file mode 100644 index 2775ce9bc6..0000000000 --- a/org.lflang.web/src/org/lflang/web/ServerLauncher.kt +++ /dev/null @@ -1,55 +0,0 @@ -@file:JvmName("ServerLauncher") - -package org.lflang.web - -import java.net.InetSocketAddress -import org.eclipse.jetty.annotations.AnnotationConfiguration -import org.eclipse.jetty.server.Server -import org.eclipse.jetty.util.log.Slf4jLog -import org.eclipse.jetty.webapp.MetaInfConfiguration -import org.eclipse.jetty.webapp.WebAppContext -import org.eclipse.jetty.webapp.WebInfConfiguration -import org.eclipse.jetty.webapp.WebXmlConfiguration -import kotlin.concurrent.thread -import kotlin.system.exitProcess - -/** - * This program starts an HTTP server for testing the web integration of your DSL. - * Just execute it and point a web browser to http://localhost:8080/ - */ -fun main(args: Array) { - val server = Server(InetSocketAddress("localhost", 8080)) - server.handler = WebAppContext().apply { - resourceBase = "WebRoot" - welcomeFiles = arrayOf("index.html") - contextPath = "/" - configurations = arrayOf( - AnnotationConfiguration(), - WebXmlConfiguration(), - WebInfConfiguration(), - MetaInfConfiguration() - ) - setAttribute(WebInfConfiguration.CONTAINER_JAR_PATTERN, ".*/org\\.icyphy\\.linguafranca\\.web/.*,.*\\.jar") - setInitParameter("org.mortbay.jetty.servlet.Default.useFileMappedBuffer", "false") - } - - val log = Slf4jLog("org.lflang.web.ServerLauncher") - try { - server.start() - log.info("Server started ${server.uri}...") - - thread(start = true) { - log.info("Press enter to stop the server...") - val key = System.`in`.read() - if (key != -1) { - server.stop() - } else { - log.warn("Console input is not available. In order to stop the server, you need to cancel process manually.") - } - } - server.join() - } catch (exception: Exception) { - log.warn(exception.message) - exitProcess(1) - } -} diff --git a/org.lflang.web/src/org/lflang/web/ServerLauncher.xtend b/org.lflang.web/src/org/lflang/web/ServerLauncher.xtend new file mode 100644 index 0000000000..7a79795fc0 --- /dev/null +++ b/org.lflang.web/src/org/lflang/web/ServerLauncher.xtend @@ -0,0 +1,54 @@ +/* + * generated by Xtext 2.18.0 + */ +package org.lflang.web + +import java.net.InetSocketAddress +import org.eclipse.jetty.annotations.AnnotationConfiguration +import org.eclipse.jetty.server.Server +import org.eclipse.jetty.util.log.Slf4jLog +import org.eclipse.jetty.webapp.MetaInfConfiguration +import org.eclipse.jetty.webapp.WebAppContext +import org.eclipse.jetty.webapp.WebInfConfiguration +import org.eclipse.jetty.webapp.WebXmlConfiguration + +/** + * This program starts an HTTP server for testing the web integration of your DSL. + * Just execute it and point a web browser to http://localhost:8080/ + */ +class ServerLauncher { + def static void main(String[] args) { + val server = new Server(new InetSocketAddress('localhost', 8080)) + server.handler = new WebAppContext => [ + resourceBase = 'WebRoot' + welcomeFiles = #["index.html"] + contextPath = "/" + configurations = #[ + new AnnotationConfiguration, + new WebXmlConfiguration, + new WebInfConfiguration, + new MetaInfConfiguration + ] + setAttribute(WebInfConfiguration.CONTAINER_JAR_PATTERN, '.*/org\\.icyphy\\.linguafranca\\.web/.*,.*\\.jar') + setInitParameter("org.mortbay.jetty.servlet.Default.useFileMappedBuffer", "false") + ] + val log = new Slf4jLog(ServerLauncher.name) + try { + server.start + log.info('Server started ' + server.getURI + '...') + new Thread[ + log.info('Press enter to stop the server...') + val key = System.in.read + if (key != -1) { + server.stop + } else { + log.warn('Console input is not available. In order to stop the server, you need to cancel process manually.') + } + ].start + server.join + } catch (Exception exception) { + log.warn(exception.message) + System.exit(1) + } + } +} From 944f8fb0f6ce76e37ace6727c406b8142fe597c9 Mon Sep 17 00:00:00 2001 From: Christian Menard Date: Wed, 23 Jun 2021 15:55:35 +0200 Subject: [PATCH 81/88] add AbstractLinguaFrancaWebModule --- org.lflang.web/.classpath | 6 ++++++ .../.settings/org.eclipse.wst.common.component | 1 + .../lflang/web/AbstractLinguaFrancaWebModule.java | 14 ++++++++++++++ 3 files changed, 21 insertions(+) create mode 100644 org.lflang.web/src/org/lflang/web/AbstractLinguaFrancaWebModule.java diff --git a/org.lflang.web/.classpath b/org.lflang.web/.classpath index 9394ab9567..4609f05ef3 100644 --- a/org.lflang.web/.classpath +++ b/org.lflang.web/.classpath @@ -6,6 +6,12 @@ + + + + + + diff --git a/org.lflang.web/.settings/org.eclipse.wst.common.component b/org.lflang.web/.settings/org.eclipse.wst.common.component index cdf8a7cee1..e93ed3ca81 100644 --- a/org.lflang.web/.settings/org.eclipse.wst.common.component +++ b/org.lflang.web/.settings/org.eclipse.wst.common.component @@ -4,6 +4,7 @@ + uses diff --git a/org.lflang.web/src/org/lflang/web/AbstractLinguaFrancaWebModule.java b/org.lflang.web/src/org/lflang/web/AbstractLinguaFrancaWebModule.java new file mode 100644 index 0000000000..54d043579f --- /dev/null +++ b/org.lflang.web/src/org/lflang/web/AbstractLinguaFrancaWebModule.java @@ -0,0 +1,14 @@ +/* + * generated by Xtext 2.18.0 + */ +package org.lflang.web; + +import org.eclipse.xtext.web.server.DefaultWebModule; + +/** + * Manual modifications go to {@link LinguaFrancaWebModule}. + */ +@SuppressWarnings("all") +public abstract class AbstractLinguaFrancaWebModule extends DefaultWebModule { + +} From cc5c2e4432eb08fa0dee40ba31e8d8c09625a51c Mon Sep 17 00:00:00 2001 From: Christian Menard Date: Thu, 24 Jun 2021 09:37:28 +0200 Subject: [PATCH 82/88] add missing breaks... --- org.lflang/src/org/lflang/generator/LFGenerator.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/org.lflang/src/org/lflang/generator/LFGenerator.java b/org.lflang/src/org/lflang/generator/LFGenerator.java index 5d9aa31451..7c30c8c7a3 100644 --- a/org.lflang/src/org/lflang/generator/LFGenerator.java +++ b/org.lflang/src/org/lflang/generator/LFGenerator.java @@ -41,18 +41,23 @@ public void doGenerate(Resource resource, IFileSystemAccess2 fsa, switch (target) { case C: { generator = new CGenerator(); + break; } case CCPP: { generator = new CCppGenerator(); + break; } case CPP: { generator = new CppGenerator(); + break; } case TS: { generator = new TypeScriptGenerator(); + break; } case Python: { generator = new PythonGenerator(); + break; } } From 461758f4e5da4063d091ea06b5b3386a358becc1 Mon Sep 17 00:00:00 2001 From: Christian Menard Date: Thu, 24 Jun 2021 09:48:26 +0200 Subject: [PATCH 83/88] oomph: remove weaving features --- oomph/LinguaFranca.setup | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/oomph/LinguaFranca.setup b/oomph/LinguaFranca.setup index 94ff8f2f83..532ab0d2a7 100644 --- a/oomph/LinguaFranca.setup +++ b/oomph/LinguaFranca.setup @@ -172,22 +172,12 @@ name="org.jetbrains.kotlin.feature.feature.group"/> - - - - - - - - Date: Fri, 25 Jun 2021 09:29:41 +0200 Subject: [PATCH 84/88] don't delete generated files in maven and gradle builds --- org.lflang/build.gradle | 7 +++++-- org.lflang/pom.xml | 10 +++++++--- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/org.lflang/build.gradle b/org.lflang/build.gradle index a14f265f3d..6b7cf4f207 100644 --- a/org.lflang/build.gradle +++ b/org.lflang/build.gradle @@ -30,7 +30,10 @@ task generateXtextLanguage(type: JavaExec) { args += "-p" args += "rootPath=/${projectDir}/.." - doLast { + // Currently we don't need to delete any generated files because we use the + // Java/Xtend implementations. However, if we commit to porting such files + // to Kotlin, we might to reintroduce the deletion mechanism below. + /*doLast { def filesToDelete = [ "org.lflang.validation.LFValidator", "org.lflang.LFRuntimeModule", @@ -53,7 +56,7 @@ task generateXtextLanguage(type: JavaExec) { project.logger.info("no ${projectDir.relativePath(ktFile)}, leaving the Java implementation in") } } - } + }*/ } generateXtext.dependsOn(generateXtextLanguage) diff --git a/org.lflang/pom.xml b/org.lflang/pom.xml index 07bd135bf5..c666a8bde2 100644 --- a/org.lflang/pom.xml +++ b/org.lflang/pom.xml @@ -86,8 +86,12 @@ org.eclipse.xtend xtend-maven-plugin - - + + + org.jetbrains.kotlin kotlin-maven-plugin From 43045bfd66e8f4f26f94e79f6766d967e0befe94 Mon Sep 17 00:00:00 2001 From: Christian Menard Date: Fri, 25 Jun 2021 14:54:21 +0200 Subject: [PATCH 85/88] provide java stubs so that they are not generated from xtext --- .../src/org/lflang/ui/LFUiModule.java | 2 +- org.lflang/src/org/lflang/TargetProperty.java | 14 +++++------ .../org/lflang/scoping/LFScopeProvider.java | 15 +++++++++++ ...ovider.xtend => LFScopeProviderImpl.xtend} | 2 +- .../org/lflang/validation/LFValidator.java | 25 +++++++++++++++++++ ...FValidator.xtend => LFValidatorImpl.xtend} | 6 ++--- 6 files changed, 52 insertions(+), 12 deletions(-) create mode 100644 org.lflang/src/org/lflang/scoping/LFScopeProvider.java rename org.lflang/src/org/lflang/scoping/{LFScopeProvider.xtend => LFScopeProviderImpl.xtend} (99%) create mode 100644 org.lflang/src/org/lflang/validation/LFValidator.java rename org.lflang/src/org/lflang/validation/{LFValidator.xtend => LFValidatorImpl.xtend} (99%) diff --git a/org.lflang.ui/src/org/lflang/ui/LFUiModule.java b/org.lflang.ui/src/org/lflang/ui/LFUiModule.java index e651a9e147..4c94e74f2d 100644 --- a/org.lflang.ui/src/org/lflang/ui/LFUiModule.java +++ b/org.lflang.ui/src/org/lflang/ui/LFUiModule.java @@ -8,7 +8,7 @@ /** * Use this class to register components to be used within the Eclipse IDE. */ -public class LFUiModule extends AbstractLFUiModule { +public class LFUiModule extends LFUiModuleImpl { public LFUiModule(AbstractUIPlugin plugin) { super(plugin); diff --git a/org.lflang/src/org/lflang/TargetProperty.java b/org.lflang/src/org/lflang/TargetProperty.java index 15169ff360..8f50e1a8cd 100644 --- a/org.lflang/src/org/lflang/TargetProperty.java +++ b/org.lflang/src/org/lflang/TargetProperty.java @@ -12,7 +12,7 @@ import org.lflang.lf.KeyValuePair; import org.lflang.lf.KeyValuePairs; import org.lflang.lf.TimeUnit; -import org.lflang.validation.LFValidator; +import org.lflang.validation.LFValidatorImpl; /** * A target properties along with a type and a list of supporting targets @@ -435,7 +435,7 @@ public DictionaryElement forName(String name) { * this dictionary. */ @Override - public void check(Element e, String name, LFValidator v) { + public void check(Element e, String name, LFValidatorImpl v) { KeyValuePairs kv = e.getKeyvalue(); if (kv == null) { TargetPropertyType.produceError(name, this.toString(), v); @@ -540,7 +540,7 @@ public Enum forName(String name) { * this union. */ @Override - public void check(Element e, String name, LFValidator v) { + public void check(Element e, String name, LFValidatorImpl v) { Optional> match = this.match(e); if (match.isPresent()) { // Go deeper if the element is an array or dictionary. @@ -637,7 +637,7 @@ private ArrayType(TargetPropertyType type) { * its elements are all of the correct type. */ @Override - public void check(Element e, String name, LFValidator v) { + public void check(Element e, String name, LFValidatorImpl v) { Array array = e.getArray(); if (array == null) { TargetPropertyType.produceError(name, this.toString(), v); @@ -765,7 +765,7 @@ public interface TargetPropertyType { * @param name The name of the target property. * @param v A reference to the validator to report errors to. */ - public void check(Element e, String name, LFValidator v); + public void check(Element e, String name, LFValidatorImpl v); /** * Helper function to produce an error during type checking. @@ -775,7 +775,7 @@ public interface TargetPropertyType { * @param v A reference to the validator to report errors to. */ public static void produceError(String name, String description, - LFValidator v) { + LFValidatorImpl v) { v.getTargetPropertyErrors().add("Target property '" + name + "' is required to be " + description + "."); } @@ -867,7 +867,7 @@ public boolean validate(Element e) { * @param name The name of the target property. * @param errors A list of errors to append to if problems are found. */ - public void check(Element e, String name, LFValidator v) { + public void check(Element e, String name, LFValidatorImpl v) { if (!this.validate(e)) { TargetPropertyType.produceError(name, this.description, v); } diff --git a/org.lflang/src/org/lflang/scoping/LFScopeProvider.java b/org.lflang/src/org/lflang/scoping/LFScopeProvider.java new file mode 100644 index 0000000000..9967ddaabe --- /dev/null +++ b/org.lflang/src/org/lflang/scoping/LFScopeProvider.java @@ -0,0 +1,15 @@ +/* + * generated by Xtext 2.25.0 + */ +package org.lflang.scoping; + + +/** + * This class contains custom scoping description. + * + * See https://www.eclipse.org/Xtext/documentation/303_runtime_concepts.html#scoping + * on how and when to use it. + */ +public class LFScopeProvider extends LFScopeProviderImpl { + +} diff --git a/org.lflang/src/org/lflang/scoping/LFScopeProvider.xtend b/org.lflang/src/org/lflang/scoping/LFScopeProviderImpl.xtend similarity index 99% rename from org.lflang/src/org/lflang/scoping/LFScopeProvider.xtend rename to org.lflang/src/org/lflang/scoping/LFScopeProviderImpl.xtend index f9c24d87d8..ea8298dd34 100644 --- a/org.lflang/src/org/lflang/scoping/LFScopeProvider.xtend +++ b/org.lflang/src/org/lflang/scoping/LFScopeProviderImpl.xtend @@ -59,7 +59,7 @@ import static extension org.lflang.ASTUtils.* * on how and when to use it. * @author Marten Lohstroh */ -class LFScopeProvider extends AbstractLFScopeProvider { +class LFScopeProviderImpl extends AbstractLFScopeProvider { @Inject SimpleNameProvider nameProvider diff --git a/org.lflang/src/org/lflang/validation/LFValidator.java b/org.lflang/src/org/lflang/validation/LFValidator.java new file mode 100644 index 0000000000..436708e7f7 --- /dev/null +++ b/org.lflang/src/org/lflang/validation/LFValidator.java @@ -0,0 +1,25 @@ +/* + * generated by Xtext 2.25.0 + */ +package org.lflang.validation; + + +/** + * This class contains custom validation rules. + * + * See https://www.eclipse.org/Xtext/documentation/303_runtime_concepts.html#validation + */ +public class LFValidator extends LFValidatorImpl { + +// public static final String INVALID_NAME = "invalidName"; +// +// @Check +// public void checkGreetingStartsWithCapital(Greeting greeting) { +// if (!Character.isUpperCase(greeting.getName().charAt(0))) { +// warning("Name should start with a capital", +// LFPackage.Literals.GREETING__NAME, +// INVALID_NAME); +// } +// } + +} diff --git a/org.lflang/src/org/lflang/validation/LFValidator.xtend b/org.lflang/src/org/lflang/validation/LFValidatorImpl.xtend similarity index 99% rename from org.lflang/src/org/lflang/validation/LFValidator.xtend rename to org.lflang/src/org/lflang/validation/LFValidatorImpl.xtend index 0d05707b9a..37d1086959 100644 --- a/org.lflang/src/org/lflang/validation/LFValidator.xtend +++ b/org.lflang/src/org/lflang/validation/LFValidatorImpl.xtend @@ -93,7 +93,7 @@ import static extension org.lflang.ASTUtils.* * @author(Christian Menard } * */ -class LFValidator extends AbstractLFValidator { +class LFValidatorImpl extends AbstractLFValidator { var Target target @@ -133,9 +133,9 @@ class LFValidator extends AbstractLFValidator { static val spacingViolationPolicies = #['defer', 'drop', 'replace'] - private val List targetPropertyErrors = newLinkedList + val List targetPropertyErrors = newLinkedList - private val List targetPropertyWarnings = newLinkedList + val List targetPropertyWarnings = newLinkedList def List getTargetPropertyErrors() { this.targetPropertyErrors From e1422a24341c78192cb3a3037c86d1b66bf3f8b7 Mon Sep 17 00:00:00 2001 From: Christian Menard Date: Fri, 25 Jun 2021 15:09:14 +0200 Subject: [PATCH 86/88] src-gen seems to be not needed anymore --- org.lflang.web/.classpath | 6 ------ 1 file changed, 6 deletions(-) diff --git a/org.lflang.web/.classpath b/org.lflang.web/.classpath index 4609f05ef3..a082f9a6ec 100644 --- a/org.lflang.web/.classpath +++ b/org.lflang.web/.classpath @@ -12,12 +12,6 @@ - - - - - - From 7134d2cf029e3cff0bfed63cc6904c2a84964172 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Tue, 22 Jun 2021 15:50:06 +0200 Subject: [PATCH 87/88] Add gradle task to run LFC This makes it easier to debug LFC when you build the project with Gradle, including from within Intellij. Use with gradle :org.lflang:runLfc --args '-c example/C/src/Smokers.lf' --- org.lflang/build.gradle | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/org.lflang/build.gradle b/org.lflang/build.gradle index 6b7cf4f207..442fc15984 100644 --- a/org.lflang/build.gradle +++ b/org.lflang/build.gradle @@ -81,3 +81,13 @@ task generateStandaloneCompiler() { } generateStandaloneCompiler.finalizedBy shadowJar + +task runLfc(type: JavaExec) { + // Note: when you use --args, you need to escape cli flags which start with -- + // For instance --args ' --help' + // Otherwise they're parsed as arguments to the Gradle CLI, not LFC. + description = "Build and run LFC, use --args to pass arguments" + group = "application" + classpath = sourceSets.main.runtimeClasspath + mainClass = 'org.lflang.generator.Main' +} From 7662fab47707427c3fc29bbcbe9de7727a2a9004 Mon Sep 17 00:00:00 2001 From: Alexander Schulz-Rosengarten Date: Sat, 26 Jun 2021 15:37:50 +0200 Subject: [PATCH 88/88] Removed eclipse project information of root folder to fix oomph setup --- .classpath | 6 ------ .project | 23 ----------------------- 2 files changed, 29 deletions(-) delete mode 100644 .classpath delete mode 100644 .project diff --git a/.classpath b/.classpath deleted file mode 100644 index 4a04201ca2..0000000000 --- a/.classpath +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/.project b/.project deleted file mode 100644 index f300cafd5a..0000000000 --- a/.project +++ /dev/null @@ -1,23 +0,0 @@ - - - lingua-franca - Project lingua-franca created by Buildship. - - - - - org.eclipse.jdt.core.javabuilder - - - - - org.eclipse.buildship.core.gradleprojectbuilder - - - - - - org.eclipse.jdt.core.javanature - org.eclipse.buildship.core.gradleprojectnature - -