diff --git a/build.gradle b/build.gradle index 6b11fcefdd..45bdaae265 100644 --- a/build.gradle +++ b/build.gradle @@ -1,14 +1,16 @@ buildscript { + ext.kotlinVersion = "1.4.10" // sync with pom.xml repositories { mavenCentral() } dependencies { classpath 'org.xtext:xtext-gradle-plugin:2.0.8' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion" } } plugins { - id "com.github.johnrengelman.shadow" version "6.0.0" + id 'com.github.johnrengelman.shadow' version '6.0.0' id 'java' id 'jacoco' } @@ -19,19 +21,34 @@ subprojects { mavenCentral() } - apply plugin: 'java' + apply plugin: 'kotlin' + compileKotlin { + destinationDir = compileJava.destinationDir + kotlinOptions { + jvmTarget = "1.8" + } + } + dependencies { implementation platform("org.eclipse.xtext:xtext-dev-bom:${xtextVersion}") // https://mvnrepository.com/artifact/com.google.inject/guice implementation group: 'com.google.inject', name: 'guice', version: '5.0.1' // https://mvnrepository.com/artifact/commons-cli/commons-cli implementation group: 'commons-cli', name: 'commons-cli', version: '1.4' - } + } + 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" apply plugin: 'eclipse' - + + // generate xtend sources before kotlin compilation + compileKotlin.dependsOn("generateXtext") + group = 'org.lflang' version = '0.1.0-SNAPSHOT' @@ -41,4 +58,11 @@ subprojects { configurations.all { exclude group: 'asm' } + + // Delete generated sources on `gradle clean` + clean.doFirst { + project.logger.info("Deleting ${projectDir}/xtend-gen, src-gen") + delete "${projectDir}/xtend-gen/" + delete "${projectDir}/src-gen/" + } } 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 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' } diff --git a/oomph/LinguaFranca.setup b/oomph/LinguaFranca.setup index 278b62768a..532ab0d2a7 100644 --- a/oomph/LinguaFranca.setup +++ b/oomph/LinguaFranca.setup @@ -166,6 +166,19 @@ 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} + + + + + + + + + + @@ -452,6 +471,8 @@ versionRange="2.25.0"/> + + 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/.classpath b/org.lflang.ide/.classpath index 1aa5319633..f2f202a205 100644 --- a/org.lflang.ide/.classpath +++ b/org.lflang.ide/.classpath @@ -6,19 +6,15 @@ - - - - - - + + diff --git a/org.lflang.ide/.project b/org.lflang.ide/.project index dd41def898..00d32931e3 100644 --- a/org.lflang.ide/.project +++ b/org.lflang.ide/.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.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 f4d933e4eb..3056f74d3b 100644 --- a/org.lflang.ide/.settings/org.eclipse.jdt.core.prefs +++ b/org.lflang.ide/.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.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.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.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/org.lflang.targetplatform/org.lflang.targetplatform.target b/org.lflang.targetplatform/org.lflang.targetplatform.target index 852991b151..99647fad7d 100644 --- a/org.lflang.targetplatform/org.lflang.targetplatform.target +++ b/org.lflang.targetplatform/org.lflang.targetplatform.target @@ -1,6 +1,6 @@ - + @@ -19,6 +19,7 @@ + @@ -46,6 +47,20 @@ + + + + + + + + + + + + + + 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/.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 diff --git a/org.lflang.tests/.project b/org.lflang.tests/.project index b17de320d9..ec198a5045 100644 --- a/org.lflang.tests/.project +++ b/org.lflang.tests/.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.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.tests/build.gradle b/org.lflang.tests/build.gradle index 090f9acef5..0fc1bc0249 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 { diff --git a/org.lflang.tests/pom.xml b/org.lflang.tests/pom.xml index 82a97024f4..2a8ae18507 100644 --- a/org.lflang.tests/pom.xml +++ b/org.lflang.tests/pom.xml @@ -35,6 +35,15 @@ + + org.eclipse.xtend + xtend-maven-plugin + + + org.jetbrains.kotlin + kotlin-maven-plugin + + org.eclipse.tycho @@ -47,56 +56,6 @@ - - - - - - - - org.eclipse.xtend - xtend-maven-plugin - - org.eclipse.tycho tycho-surefire-plugin @@ -147,4 +106,5 @@ + 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.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 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) 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/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.ui/src/org/lflang/ui/LFUiModule.java b/org.lflang.ui/src/org/lflang/ui/LFUiModule.java new file mode 100644 index 0000000000..4c94e74f2d --- /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 LFUiModuleImpl { + + 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/LFUiModuleImpl.xtend similarity index 99% rename from org.lflang.ui/src/org/lflang/ui/LFUiModule.xtend rename to org.lflang.ui/src/org/lflang/ui/LFUiModuleImpl.xtend index 004c1113b3..b0e86994b9 100644 --- a/org.lflang.ui/src/org/lflang/ui/LFUiModule.xtend +++ b/org.lflang.ui/src/org/lflang/ui/LFUiModuleImpl.xtend @@ -34,7 +34,7 @@ import java.io.PrintStream * subclassing, and the code has no comments in it at all. */ @FinalFieldsConstructor -class LFUiModule extends AbstractLFUiModule { +class LFUiModuleImpl extends AbstractLFUiModule { static var consoleInitialized = false 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.web/.classpath b/org.lflang.web/.classpath index 36bc8839a7..a082f9a6ec 100644 --- a/org.lflang.web/.classpath +++ b/org.lflang.web/.classpath @@ -12,12 +12,6 @@ - - - - - - @@ -25,5 +19,6 @@ + diff --git a/org.lflang.web/.project b/org.lflang.web/.project index 023d4957f4..ca368bbe6f 100644 --- a/org.lflang.web/.project +++ b/org.lflang.web/.project @@ -30,6 +30,11 @@ + + org.jetbrains.kotlin.ui.kotlinBuilder + + + org.eclipse.jdt.core.javanature @@ -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.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-gen/org/lflang/web/AbstractLinguaFrancaWebModule.java b/org.lflang.web/src/org/lflang/web/AbstractLinguaFrancaWebModule.java similarity index 100% rename from org.lflang.web/src-gen/org/lflang/web/AbstractLinguaFrancaWebModule.java rename to org.lflang.web/src/org/lflang/web/AbstractLinguaFrancaWebModule.java 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 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/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, diff --git a/org.lflang/build.gradle b/org.lflang/build.gradle index d23b97eeed..442fc15984 100644 --- a/org.lflang/build.gradle +++ b/org.lflang/build.gradle @@ -29,6 +29,34 @@ task generateXtextLanguage(type: JavaExec) { args += "src/org/lflang/GenerateLinguaFranca.mwe2" args += "-p" args += "rootPath=/${projectDir}/.." + + // 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", + "org.lflang.LFStandaloneSetup", + "org.lflang.generator.LFGenerator", + "org.lflang.scoping.LFScopeProvider" + ] + + 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") + project.delete(javaFile) // generated by Xtend + } else { + project.logger.info("no ${projectDir.relativePath(ktFile)}, leaving the Java implementation in") + } + } + }*/ } generateXtext.dependsOn(generateXtextLanguage) @@ -36,7 +64,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' @@ -51,10 +78,16 @@ task generateStandaloneCompiler() { resource = 'plugin.properties' } } - - compileJava { - options.compilerArgs << '-Xlint:unchecked' - } } 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' +} diff --git a/org.lflang/pom.xml b/org.lflang/pom.xml index e782be5a07..c666a8bde2 100644 --- a/org.lflang/pom.xml +++ b/org.lflang/pom.xml @@ -86,6 +86,45 @@ org.eclipse.xtend xtend-maven-plugin + + + + + org.jetbrains.kotlin + kotlin-maven-plugin + + + org.eclipse.tycho + tycho-compiler-plugin + org.apache.maven.plugins @@ -166,4 +205,3 @@ - diff --git a/org.lflang/src/org/lflang/AstExtensions.kt b/org.lflang/src/org/lflang/AstExtensions.kt new file mode 100644 index 0000000000..66ed2d643f --- /dev/null +++ b/org.lflang/src/org/lflang/AstExtensions.kt @@ -0,0 +1,287 @@ +/* + * 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.* + +/** + * 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 + else -> throw AssertionError("Unknown reactor type: $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() = 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() = 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() = 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() = 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() = 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() = 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() = 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() = 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() = collectInSupertypes { 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.collectInSupertypes(collector: Reactor.() -> List): List = + superClasses.orEmpty().mapNotNull { it.toDefinition().collectInSupertypes(collector) }.flatten() + this.collector() + +val Parameter.isOfTimeType: Boolean get() = ASTUtils.isOfTimeType(this) + +/** + * 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() + + +/** + * 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 = + literal?.withoutQuotes()?.trim() ?: id ?: "" + + +fun Delay.toText(): String = + parameter?.name ?: "$interval $unit" + + +/** + * Remove quotation marks surrounding the specified string. + */ +fun String.withoutQuotes(): String { + val r = removeSurrounding("\"") + return if (r !== this) this else removeSurrounding("'") +} + + +/** + * Return a string of the form either "name" or "container.name" depending + * on in which form the variable reference was given. + * @receiver The variable reference. + */ +fun VarRef.toText(): String = + 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. + * + * @receiver 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. + * @receiver AST node to render as string. + * @return Textual representation of the given argument. + */ +fun Type.toText(): String = baseType + arraySpec?.toText().orEmpty() + +/** + * 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 = + ASTUtils.getUniqueIdentifier(this, name) + +/** + * 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 + +/** + * Return whether the given [value] is zero or not. + */ +fun isZero(value: Value): Boolean = + value.literal?.isZero + ?: value.code?.isZero + ?: false + +/** + * 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. + */ +val WidthSpec.width: Int? + get() = ASTUtils.width(this, null).takeIf { it >= 0 } + + +// more general extensions + +/** + * Parse and return an integer from this string, much + * like [String.toIntOrNull], but allows any radix. + * + * @see Integer.decode + */ +fun String.toIntOrNullAnyRadix(): Int? = + try { + Integer.decode(this) + } catch (e: NumberFormatException) { + null + } + +/** + * Return the sublist consisting of the tail elements of this list, + * ie, everything except the first elements. This is a list view, + * and does not copy the backing buffer (if any). + * + * @throws NoSuchElementException if the list is empty + */ +fun List.tail() = subList(1, size) + +/** + * Return a pair consisting of the [List.first] element and the [tail] sublist. + * This may be used to deconstruct a list recursively, as is usual in + * functional languages. + * + * @throws NoSuchElementException if the list is empty + */ +fun List.headAndTail() = Pair(first(), tail()) 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 diff --git a/org.lflang/src/org/lflang/LFRuntimeModule.java b/org.lflang/src/org/lflang/LFRuntimeModule.java new file mode 100644 index 0000000000..b7da745e19 --- /dev/null +++ b/org.lflang/src/org/lflang/LFRuntimeModule.java @@ -0,0 +1,34 @@ +/* + * 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.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. + */ +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() { + return LFGlobalScopeProvider.class; + } + + /** Establish a binding to a helper that checks that names are unique. */ + public Class bindNamesAreUniqueValidationHelper() { + return LFNamesAreUniqueValidationHelper.class; + } + +} 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.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.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/Target.java b/org.lflang/src/org/lflang/Target.java index dbd59434a2..d47d5c5d9f 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: @@ -336,41 +336,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. @@ -385,12 +385,12 @@ 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). */ public static Target forName(String name) { - return (Target)Target.match(name, Target.values()); + return Target.match(name, Target.values()); } /** @@ -398,19 +398,34 @@ public static Target forName(String name) { */ @Override public String toString() { - return this.description; + return 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. + */ + 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); + 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 f0cc9e8880..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 @@ -362,7 +362,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()); } /** @@ -395,7 +395,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 { @@ -427,7 +427,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); } /** @@ -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); @@ -532,7 +532,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); } /** @@ -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,8 +775,8 @@ public interface TargetPropertyType { * @param v A reference to the validator to report errors to. */ public static void produceError(String name, String description, - LFValidator v) { - v.targetPropertyErrors.add("Target property '" + name + 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/generator/LFGenerator.java b/org.lflang/src/org/lflang/generator/LFGenerator.java new file mode 100644 index 0000000000..7c30c8c7a3 --- /dev/null +++ b/org.lflang/src/org/lflang/generator/LFGenerator.java @@ -0,0 +1,72 @@ +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 + */ +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 = 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(); + 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; + } + } + + generator.doGenerate(resource, fsa, context); + generatorErrorsOccurred = generator.errorsOccurred(); + } + + /** 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; - } - -} 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 97% rename from org.lflang/src/org/lflang/validation/LFValidator.xtend rename to org.lflang/src/org/lflang/validation/LFValidatorImpl.xtend index 44b2825e4f..37d1086959 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 @@ -84,19 +84,19 @@ import static extension org.lflang.ASTUtils.* /** * 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 AbstractLFValidator { var Target target - + public var info = new ModelInfo() /** @@ -108,22 +108,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}\\$)$" @@ -133,9 +133,13 @@ class LFValidator extends AbstractLFValidator { static val spacingViolationPolicies = #['defer', 'drop', 'replace'] - public val List targetPropertyErrors = newLinkedList - - public val List targetPropertyWarnings = newLinkedList + val List targetPropertyErrors = newLinkedList + + val List targetPropertyWarnings = newLinkedList + + def List getTargetPropertyErrors() { + this.targetPropertyErrors + } @Check def checkImportedReactor(ImportedReactor reactor) { @@ -161,9 +165,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 @@ -198,7 +202,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. @@ -222,7 +226,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. @@ -241,12 +245,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. @@ -311,7 +315,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) { @@ -325,7 +329,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) } } @@ -342,7 +346,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.definition === lp.variable ]) || cycle.exists [ @@ -358,7 +362,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 ) @@ -367,10 +371,9 @@ class LFValidator extends AbstractLFValidator { } } } - + // FIXME: look up all ReactorInstance objects that have a definition equal to the // container of this connection. For each of those occurrences, the widths have to match. - // 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. @@ -405,7 +408,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 @@ -430,7 +433,7 @@ class LFValidator extends AbstractLFValidator { rightWidth += width } } - + if (leftWidth !== -1 && rightWidth !== -1 && leftWidth != rightWidth) { if (connection.isIterated) { if (rightWidth % leftWidth != 0) { @@ -450,9 +453,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) { @@ -486,7 +489,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 @@ -527,8 +530,7 @@ class LFValidator extends AbstractLFValidator { Literals.DEADLINE__DELAY) } } - - @Check(FAST) +@Check(FAST) def checkSTPOffset(STP stp) { if (this.target == Target.C && this.info.overflowingDeadlines.contains(stp)) { @@ -538,7 +540,7 @@ class LFValidator extends AbstractLFValidator { Literals.DEADLINE__DELAY) } } - + @Check(NORMAL) def checkBuild(Model model) { val uri = model.eResource?.URI @@ -570,7 +572,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( @@ -579,7 +581,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) @@ -597,7 +599,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. @@ -617,7 +619,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) { @@ -679,7 +681,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) @@ -696,7 +698,7 @@ class LFValidator extends AbstractLFValidator { info.update(model, DefaultErrorReporter.DEFAULT) } } - + @Check(NORMAL) def updateModelInfo(Model model) { info.update(model, DefaultErrorReporter.DEFAULT) @@ -711,14 +713,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) { @@ -739,7 +741,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. @@ -895,7 +897,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.''', @@ -907,7 +909,7 @@ class LFValidator extends AbstractLFValidator { // Moving them won't help solve the problem. } } - // FIXME: improve error message. + // FIXME: improve error message. } @Check(FAST) @@ -923,7 +925,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( @@ -953,12 +955,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( @@ -966,11 +968,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 ) @@ -982,11 +984,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 @@ -1001,7 +1003,7 @@ class LFValidator extends AbstractLFValidator { variables.add(timer) } } - + // Report conflicts. if (conflicts.size > 0) { val names = new ArrayList(); @@ -1009,11 +1011,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. @@ -1238,12 +1240,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 @@ -1260,7 +1262,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 @@ -1268,7 +1270,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): " diff --git a/pom.xml b/pom.xml index bd36934d9f..48aa15f1f5 100644 --- a/pom.xml +++ b/pom.xml @@ -30,6 +30,9 @@ + + + 1.4.10 11 11 2.3.0 @@ -73,6 +76,8 @@ ${xtext.version} + generate-xtend + generate-sources compile xtend-install-debug-info @@ -86,6 +91,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 + + + + + + + consider org.lflang org.lflang.targetplatform - 0.1.0-SNAPSHOT + ${project.version}