diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index 56e368b..fe30ffe 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -66,6 +66,10 @@ jobs: releng/nl.esi.xplus.standard.site/target/*.zip # Deploy P2 Repository to GitHub Pages for versioned releases + # NOTE: After deployment, use these URLs to add the repository in Eclipse: + # - For releases: https://TNO.github.io/XPlus/releases/TAG_NAME + # - For nightly: https://TNO.github.io/XPlus/nightly + # Do NOT use the github.com/tree/gh-pages URLs as those are web interface URLs, not P2 repository URLs - name: Deploy P2 Repository (Release) if: github.ref_type == 'tag' && success() uses: peaceiris/actions-gh-pages@v4 diff --git a/README.md b/README.md index 6d5f5d2..1f893f4 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # XPlus Base Xtext Languages and Eclipse Plugins -XPlus is a collection of base Xtext languages and Eclipse plugins/libraries that serve as the foundation for projects such as Offline MBT and other model-based tools. +XPlus is a collection of base Xtext languages and Eclipse plugins/libraries that serve as the foundation for projects such as Offline MBT, LSAT and other model-based tools. ### Conventions @@ -52,7 +52,7 @@ To create a development environment: - In the second wizard window: - Use the green '+' icon at the top right to add the Oomph setup. - For **Catalog**, choose **Github Projects**. - - For **Resource URIs**, enter `https://raw.githubusercontent.com/dbera/XPlus/main/XPlus.setup` and make sure there are no spaces before or after the URL. + - For **Resource URIs**, enter `https://raw.githubusercontent.com/TNO/XPlus/develop/XPlus.setup` and make sure there are no spaces before or after the URL. - Click the **OK** button. - Check the checkbox for **XPlus**, from the big list. It is under **Github Projects** / ****. @@ -107,13 +107,13 @@ In your new development environment, consider changing the following settings: ### Building with Maven > [!CAUTION] -> XPlus should be built using [Maven 3.9](https://maven.apache.org/download.cgi) and a _Java 21 VM_. +> XPlus should be built using [Maven 3.9.*](https://maven.apache.org/download.cgi) and a _Java 21 VM_. > The JDK can be downloaded from e.g. [Adoptium](https://adoptium.net/temurin/archive/?variant=openjdk21&jvmVariant=hotspot&version=21). > > To test which Java version is used by Maven, type `mvn -version` in a command shell. To build XPlus with Maven execute the following command in the root: -`mvn clean package -P site` +`mvn install` On a successful build, the built Eclipse P2 repository can be found in the **target** folder of the [releng/nl.esi.xplus.standard.site](releng/nl.esi.xplus.standard.site/) project. diff --git a/XPlus.setup b/XPlus.setup index 13ce9ab..cf41b4c 100644 --- a/XPlus.setup +++ b/XPlus.setup @@ -57,7 +57,7 @@ Set an Oomph redirection system property to redirect the logical location of this setup to its physical location in the Git clone. @@ -116,13 +116,13 @@ value="false"/> - - + xsi:type="setup:CompoundTask" + name="Java Development"> + + @@ -283,7 +283,7 @@ + remoteURI="TNO/XPlus"> - + - XPlus provides cool stuff. + XPlus from TNO diff --git a/bundles/nl.esi.xplus.doc.design/GenerateGrammarsDiagram.launch b/bundles/nl.esi.xplus.doc.design/GenerateGrammarsDiagram.launch new file mode 100644 index 0000000..3d454ea --- /dev/null +++ b/bundles/nl.esi.xplus.doc.design/GenerateGrammarsDiagram.launch @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/bundles/nl.esi.xplus.doc.design/META-INF/MANIFEST.MF b/bundles/nl.esi.xplus.doc.design/META-INF/MANIFEST.MF index 456eb8a..823dc05 100644 --- a/bundles/nl.esi.xplus.doc.design/META-INF/MANIFEST.MF +++ b/bundles/nl.esi.xplus.doc.design/META-INF/MANIFEST.MF @@ -2,8 +2,8 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: Design Documentation Bundle-SymbolicName: nl.esi.xplus.doc.design;singleton:=true -Bundle-Version: 0.1.0.qualifier -Export-Package: nl.esi.xplus.doc.design;x-internal:=true +Bundle-Version: 0.3.0.qualifier +Export-Package: nl.esi.xplus.doc.design Bundle-Vendor: TNO-ESI Automatic-Module-Name: nl.esi.xplus.doc.design Bundle-RequiredExecutionEnvironment: JavaSE-21 diff --git a/bundles/nl.esi.xplus.doc.design/adoc/_section_xtext_languages.adoc b/bundles/nl.esi.xplus.doc.design/adoc/_section_xtext_languages.adoc index 0f66e51..7a59a59 100644 --- a/bundles/nl.esi.xplus.doc.design/adoc/_section_xtext_languages.adoc +++ b/bundles/nl.esi.xplus.doc.design/adoc/_section_xtext_languages.adoc @@ -35,8 +35,6 @@ For more information about the reuse of existing grammars, please read the (i.e. include::{gendocdir}/xtext-grammars.plantuml[] -artifact nl.esi.xtext.types.Types #white/aqua - @enduml .... @@ -46,3 +44,5 @@ include::{extdocdir}/nl.esi.xtext.types.adoc[leveloffset=2] include::{extdocdir}/nl.esi.xtext.expressions.adoc[leveloffset=2] include::{extdocdir}/expression-functions-framework-design.adoc[leveloffset=2] + +include::{extdocdir}/nl.esi.xtext.actions.adoc[leveloffset=2] diff --git a/bundles/nl.esi.xplus.doc.design/pom.xml b/bundles/nl.esi.xplus.doc.design/pom.xml index d25a174..1415e74 100644 --- a/bundles/nl.esi.xplus.doc.design/pom.xml +++ b/bundles/nl.esi.xplus.doc.design/pom.xml @@ -16,7 +16,7 @@ nl.esi.xplus nl.esi.xplus.root - 0.1.0-SNAPSHOT + 0.3.0-SNAPSHOT ../../ @@ -31,95 +31,85 @@ maven-dependency-plugin - unpack-adoc-resources + unpack-ecore-models generate-sources unpack-dependencies - adoc/** - ${project.build.directory}/adoc-ext + true + true + true + true + true + true + META-INF/MANIFEST.MF,model/generated/*.*,**/*.xtext + ${project.build.directory}/meta-models/ - - - - org.codehaus.mojo - exec-maven-plugin - 3.5.0 - - prepare-package + unpack-adoc-resources + generate-sources - java + unpack-dependencies - nl.esi.xplus.doc.design.GenerateGrammarsDiagram - true - - ${project.basedir}/.. - ${project.build.directory}/adoc-gen/xtext-grammars.plantuml - + true + true + adoc/** + ${project.build.directory}/adoc-ext - - - - org.eclipse.xtend - org.eclipse.xtend.lib - ${xtend.version} - - - - - + + + - org.apache.maven.plugins - maven-resources-plugin + maven-antrun-plugin prepare-package - - copy-resources - - - - ${project.basedir}/.. - - */model/generated/*.ecore - - - - ${project.build.directory}/meta-models + + + + + + + run + + - maven-antrun-plugin + org.codehaus.mojo + exec-maven-plugin + 3.5.0 prepare-package - - - - - - - - run + java + + nl.esi.xplus.doc.design.GenerateGrammarsDiagram + true + provided + + ${project.build.directory}/meta-models + ${project.build.directory}/adoc-gen/xtext-grammars.plantuml + nl.esi. + + - com.altran.general.emf.ecoredoc @@ -291,6 +281,30 @@ + + + + org.apache.maven.plugins + maven-clean-plugin + + + remove-meta-models + package + + clean + + + true + + + ${project.build.directory}/meta-models/ + + + + + + \ No newline at end of file diff --git a/bundles/nl.esi.xplus.doc.design/src/nl/esi/xplus/doc/design/GenerateGrammarsDiagram.xtend b/bundles/nl.esi.xplus.doc.design/src/nl/esi/xplus/doc/design/GenerateGrammarsDiagram.xtend index ac87f13..1e8a3b0 100644 --- a/bundles/nl.esi.xplus.doc.design/src/nl/esi/xplus/doc/design/GenerateGrammarsDiagram.xtend +++ b/bundles/nl.esi.xplus.doc.design/src/nl/esi/xplus/doc/design/GenerateGrammarsDiagram.xtend @@ -20,31 +20,41 @@ import java.util.stream.Stream import org.eclipse.xtend.lib.annotations.Accessors class GenerateGrammarsDiagram { - static val TERMINALS_GRAMMAR = new Grammar => [ - bundle = 'org.eclipse.xtext.common' - name = 'org.eclipse.xtext.common.Terminals' - ] + static val TERMINALS_GRAMMAR__BUNDLE = 'org.eclipse.xtext' + static val TERMINALS_GRAMMAR__NAME = 'org.eclipse.xtext.common.Terminals' - static val GRAMMAR_PATTERN = Pattern.compile('''^grammar\s+((\w+\.)*\w+)\s+with\s+((\w+\.)*\w+)''') + static val GRAMMAR_PATTERN = Pattern.compile('''^grammar\s+((\w+\.)*\w+)(\s+with\s+((\w+\.)*\w+))?(\s+hidden\s*\((\w+(,\s*\w+)*)\))?\s*''') static val GENERATE_PATTERN = Pattern.compile('''^generate\s+(\w+)\s+"([^"]+)"''') static val IMPORT_PATTERN = Pattern.compile('''^import\s+"([^"]+)"\s+as\s+(\w+)''') - static val FILE_EXTENSIONS_PATTERN = Pattern.compile('''^\s*fileExtensions\s+=\s+"([^"]+)"''') + static val FILE_EXTENSIONS_PATTERN = Pattern.compile('''^.*fileExtensions\s*=\s*"([^"]+)".*''') def static void main(String[] args) { - if (args.size != 2) { - System.err.println('Expected two arguments: [bundles_directory] [output-file]') + if (args.size < 2 || args.size > 3) { + System.err.println('Usage: []') + System.err.println() + System.err.println('includes\tA comma separated list of bundle prefixes to include') System.exit(1) } val bundlesDir = Path.of(args.get(0)).toRealPath() val outputFile = Path.of(args.get(1)) - println('''Generate diagram: «bundlesDir» => «outputFile»''') - - val xtextFiles = Files.find(bundlesDir, Integer.MAX_VALUE, [$0.toString.endsWith('.xtext')]).toIterable + val includes = args.length > 2 ? args.get(2).split(',').map[trim] + println('''Generate diagram: «bundlesDir» «includes» => «outputFile»''') + + val xtextFiles = Files.find(bundlesDir, Integer.MAX_VALUE, [ path, attrs | + val relativePath = bundlesDir.relativize(path).toString + val included = includes.isNullOrEmpty || includes.exists[include | relativePath.startsWith(include)] + return included && attrs.regularFile && relativePath.endsWith('.xtext') + ]).toIterable val grammars = xtextFiles.map[createGrammar(bundlesDir)].filterNull.toList - grammars += TERMINALS_GRAMMAR + if (grammars.exists[parent == TERMINALS_GRAMMAR__NAME] && !grammars.exists[name == TERMINALS_GRAMMAR__NAME]) { + grammars += new Grammar => [ + bundle = TERMINALS_GRAMMAR__BUNDLE + name = TERMINALS_GRAMMAR__NAME + ] + } // Reduce grammar dependencies grammars.forEach[ - bundleUses.removeAll(getParentGrammar(grammars)?.bundle) + bundleUses.removeAll(getParentGrammars(grammars).map[bundle]) grammarUses.removeAll(getParentGrammars(grammars).map[uri]) ] grammars.sortInplace[a, b | @@ -97,24 +107,28 @@ class GenerateGrammarsDiagram { ''' def static Grammar createGrammar(Path xtextFile, Path bundlesDir) { - if (xtextFile.contains(Path.of('target')) || xtextFile.contains(Path.of('bin'))) { - return null - } val fileName = com.google.common.io.Files.getNameWithoutExtension(xtextFile.fileName.toString) - val xtextLines = Files.lines(xtextFile).toIterable - val mwe2Lines = Files.lines(xtextFile.resolveSibling('''Generate«fileName».mwe2''')).toIterable val bundlePath = xtextFile.getName(bundlesDir.nameCount) + + val xtextLines = Files.lines(xtextFile).toIterable + val genmodel = bundlesDir.resolve(bundlePath).resolve('''model/generated/«fileName».genmodel''') + val fileExtensions = if (Files.isRegularFile(genmodel)) { + val genmodelLines = Files.lines(genmodel).toIterable + genmodelLines.matchAndReturn(FILE_EXTENSIONS_PATTERN, '$1').head + } val manifest = new Manifest(bundlesDir.resolve(bundlePath).resolve('META-INF/MANIFEST.MF').read) val requiredBundles = manifest.mainAttributes.getValue('Require-Bundle') - return new Grammar => [ - bundle = bundlePath.toString - name = xtextLines.matchAndReturn(GRAMMAR_PATTERN, '$1').head - parent = xtextLines.matchAndReturn(GRAMMAR_PATTERN, '$3').head - uri = xtextLines.matchAndReturn(GENERATE_PATTERN, '$2').head - grammarUses += xtextLines.matchAndReturn(IMPORT_PATTERN, '$1') - bundleUses += requiredBundles.split(',').map[split(';').head] - fileExtensions = mwe2Lines.matchAndReturn(FILE_EXTENSIONS_PATTERN, '$1').head + return new Grammar => [ g | + g.bundle = bundlePath.toString + g.name = xtextLines.matchAndReturn(GRAMMAR_PATTERN, '$1').head + g.parent = xtextLines.matchAndReturn(GRAMMAR_PATTERN, '$4').head + g.uri = xtextLines.matchAndReturn(GENERATE_PATTERN, '$2').head + g.grammarUses += xtextLines.matchAndReturn(IMPORT_PATTERN, '$1') + if (!requiredBundles.isNullOrEmpty) { + g.bundleUses += requiredBundles.split(',').map[split(';').head] + } + g.fileExtensions = fileExtensions ] } @@ -137,14 +151,13 @@ class GenerateGrammarsDiagram { def Set getParentGrammars(Iterable grammars) { val parents = newLinkedHashSet var parent = this.getParentGrammar(grammars) - while (parent !== null) { - parents += parent + while (parent !== null && parents.add(parent)) { parent = parent.getParentGrammar(grammars) } return parents } - def Grammar getParentGrammar(Iterable grammars) { + def private Grammar getParentGrammar(Iterable grammars) { return grammars.findFirst[g | g.name == this.parent] } } diff --git a/bundles/nl.esi.xtext.actions.ide/META-INF/MANIFEST.MF b/bundles/nl.esi.xtext.actions.ide/META-INF/MANIFEST.MF index 3ccf5ad..ca2fa39 100644 --- a/bundles/nl.esi.xtext.actions.ide/META-INF/MANIFEST.MF +++ b/bundles/nl.esi.xtext.actions.ide/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: Actions Language IDE Bundle-Vendor: TNO-ESI -Bundle-Version: 0.1.0.qualifier +Bundle-Version: 0.3.0.qualifier Bundle-SymbolicName: nl.esi.xtext.actions.ide; singleton:=true Bundle-ActivationPolicy: lazy Require-Bundle: nl.esi.xtext.actions;visibility:=reexport, diff --git a/bundles/nl.esi.xtext.actions.tests/.classpath b/bundles/nl.esi.xtext.actions.tests/.classpath new file mode 100644 index 0000000..e0cf7ad --- /dev/null +++ b/bundles/nl.esi.xtext.actions.tests/.classpath @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/bundles/nl.esi.xtext.actions.tests/.project b/bundles/nl.esi.xtext.actions.tests/.project new file mode 100644 index 0000000..13ccce8 --- /dev/null +++ b/bundles/nl.esi.xtext.actions.tests/.project @@ -0,0 +1,34 @@ + + + nl.esi.xtext.actions.tests + + + + + + org.eclipse.xtext.ui.shared.xtextBuilder + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.xtext.ui.shared.xtextNature + org.eclipse.jdt.core.javanature + org.eclipse.pde.PluginNature + + diff --git a/bundles/nl.esi.xtext.actions.tests/.settings/org.eclipse.core.resources.prefs b/bundles/nl.esi.xtext.actions.tests/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 0000000..99f26c0 --- /dev/null +++ b/bundles/nl.esi.xtext.actions.tests/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,2 @@ +eclipse.preferences.version=1 +encoding/=UTF-8 diff --git a/bundles/nl.esi.xtext.actions.tests/.settings/org.eclipse.jdt.core.prefs b/bundles/nl.esi.xtext.actions.tests/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..cc4eaa5 --- /dev/null +++ b/bundles/nl.esi.xtext.actions.tests/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,7 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=21 +org.eclipse.jdt.core.compiler.compliance=21 +org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled +org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning +org.eclipse.jdt.core.compiler.release=enabled +org.eclipse.jdt.core.compiler.source=21 diff --git a/bundles/nl.esi.xtext.actions.tests/META-INF/MANIFEST.MF b/bundles/nl.esi.xtext.actions.tests/META-INF/MANIFEST.MF new file mode 100644 index 0000000..3170c8f --- /dev/null +++ b/bundles/nl.esi.xtext.actions.tests/META-INF/MANIFEST.MF @@ -0,0 +1,18 @@ +Manifest-Version: 1.0 +Automatic-Module-Name: nl.esi.xtext.actions.tests +Bundle-ManifestVersion: 2 +Bundle-Name: Actions Lang Tests +Bundle-Vendor: TNO-ESI +Bundle-Version: 0.3.0.qualifier +Bundle-SymbolicName: nl.esi.xtext.actions.tests;singleton:=true +Bundle-ActivationPolicy: lazy +Require-Bundle: nl.esi.xtext.actions, + org.eclipse.xtext.testing, + org.eclipse.xtext.xbase.testing, + org.eclipse.xtext.xbase.lib;bundle-version="2.36.0" +Import-Package: org.junit.jupiter.api;version="[5.1.0,6.0.0)", + org.junit.jupiter.api.extension;version="[5.1.0,6.0.0)", + org.junit.jupiter.api.function;version="[5.1.0,6.0.0)", + org.opentest4j +Bundle-RequiredExecutionEnvironment: JavaSE-21 +Export-Package: nl.esi.xtext.actions.tests;x-internal=true diff --git a/bundles/nl.esi.xtext.actions.tests/build.properties b/bundles/nl.esi.xtext.actions.tests/build.properties new file mode 100644 index 0000000..7d28f0e --- /dev/null +++ b/bundles/nl.esi.xtext.actions.tests/build.properties @@ -0,0 +1,16 @@ +# +# Copyright (c) 2024, 2026 TNO-ESI +# +# This program and the accompanying materials are made +# available under the terms of the Eclipse Public License 2.0 +# which is available at https://www.eclipse.org/legal/epl-2.0/ +# +# SPDX-License-Identifier: EPL-2.0 +# + +source.. = src/,\ + src-gen/,\ + xtend-gen/ +bin.includes = .,\ + META-INF/ +bin.excludes = **/*.xtend diff --git a/bundles/nl.esi.xtext.actions.tests/src-gen/.gitignore b/bundles/nl.esi.xtext.actions.tests/src-gen/.gitignore new file mode 100644 index 0000000..5e7d273 --- /dev/null +++ b/bundles/nl.esi.xtext.actions.tests/src-gen/.gitignore @@ -0,0 +1,4 @@ +# Ignore everything in this directory +* +# Except this file +!.gitignore diff --git a/bundles/nl.esi.xtext.actions.tests/src/nl/esi/xtext/actions/tests/ActionsParsingTest.xtend b/bundles/nl.esi.xtext.actions.tests/src/nl/esi/xtext/actions/tests/ActionsParsingTest.xtend new file mode 100644 index 0000000..8b881c2 --- /dev/null +++ b/bundles/nl.esi.xtext.actions.tests/src/nl/esi/xtext/actions/tests/ActionsParsingTest.xtend @@ -0,0 +1,54 @@ +/** + * Copyright (c) 2024, 2026 TNO-ESI + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ +/* + * generated by Xtext 2.36.0 + */ +package nl.esi.xtext.actions.tests + +import com.google.inject.Inject +import nl.esi.xtext.actions.actions.ActionModel +import nl.esi.xtext.common.lang.utilities.EcoreUtil3 +import org.eclipse.xtext.testing.InjectWith +import org.eclipse.xtext.testing.extensions.InjectionExtension +import org.eclipse.xtext.testing.util.ParseHelper +import org.junit.jupiter.api.Assertions +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.^extension.ExtendWith + +@ExtendWith(InjectionExtension) +@InjectWith(ActionsInjectorProvider) +class ActionsParsingTest { + @Inject + ParseHelper parseHelper + + @Test + def void loadModel() { + val result = parseHelper.parse(''' + bool test = true + if test then test := false fi + ''') + Assertions.assertNotNull(result) + val errors = result.eResource.errors + Assertions.assertTrue(errors.isEmpty, '''Unexpected errors: «errors.join(", ")»''') + } + + @Test + def void saveModel() { + val input = ''' + int test = abs(-1) + for int i in [1,2,3] do test := test + 1 end-for''' + val result = parseHelper.parse(input) + EcoreUtil3.validate(result) + + val txt = EcoreUtil3.serialize(result); + Assertions.assertEquals(input, txt) + } + +} diff --git a/bundles/nl.esi.xtext.actions.tests/src/nl/esi/xtext/actions/tests/ActionsValidationTest.xtend b/bundles/nl.esi.xtext.actions.tests/src/nl/esi/xtext/actions/tests/ActionsValidationTest.xtend new file mode 100644 index 0000000..aa75f08 --- /dev/null +++ b/bundles/nl.esi.xtext.actions.tests/src/nl/esi/xtext/actions/tests/ActionsValidationTest.xtend @@ -0,0 +1,136 @@ +/** + * Copyright (c) 2024, 2026 TNO-ESI + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ +package nl.esi.xtext.actions.tests + +import com.google.inject.Inject +import nl.esi.xtext.actions.actions.ActionModel +import nl.esi.xtext.common.lang.utilities.EcoreUtil3 +import org.eclipse.xtext.testing.InjectWith +import org.eclipse.xtext.testing.extensions.InjectionExtension +import org.eclipse.xtext.testing.util.ParseHelper +import org.junit.jupiter.api.Assertions +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.^extension.ExtendWith + +@ExtendWith(InjectionExtension) +@InjectWith(ActionsInjectorProvider) +class ActionsValidationTest { + @Inject + ParseHelper actionParseHelper + + // === Assignment Action Tests === + + @Test + def void testAssignmentAction() { + validate(''' + int x + x := 5 + ''') + } + + @Test + def void testAssignmentActionIncrement() { + validate(''' + int x + x := x + 1 + ''') + } + + // === For Action Tests === + + @Test + def void testForAction() { + validate(''' + int[] numbers = [1, 2, 3] + int total + for int n in numbers + do + total := total + n + end-for + ''') + } + + // === If Action Tests === + + @Test + def void testIfActionSimple() { + validate(''' + int x + x := 10 + int result + if x > 5 + then + result := 1 + fi + ''') + } + + @Test + def void testIfActionWithElse() { + validate(''' + int x + x := 10 + int result + if x > 5 + then + result := 1 + else + result := 0 + fi + ''') + } + + // === Record Field Assignment Action Tests === + + @Test + def void testRecordFieldAssignment() { + validate(''' + record Point { int x, int y } + Point p = Point{x = 0, y = 0} + p.x := 10 + p.y := 20 + ''') + } + + @Test + def void testNestedRecordFieldAssignment() { + validate(''' + record Inner { int value } + record Outer { Inner inner } + Inner i = Inner{value = 0} + Outer o = Outer{inner = i} + o.inner.value := 42 + ''') + } + + // === Function Call Action Tests === + + @Test + def void testFunctionCallAction() { + validate(''' + function int sum(int[] values) + int[] data = [1, 2, 3] + sum(data) + ''') + } + + private def validate(String text) { + val result = actionParseHelper.parse(text) + + Assertions.assertNotNull(result) + var errors = result.eResource.errors + Assertions.assertTrue(errors.isEmpty, '''Unexpected parsing errors: «errors.join(", ")»''') + EcoreUtil3.validate(result) + errors = result.eResource.errors + Assertions.assertTrue(errors.isEmpty, '''Unexpected validation errors: «errors.join(", ")»''') + // test serialization + EcoreUtil3.serialize(result) + } +} diff --git a/bundles/nl.esi.xtext.actions.tests/xtend-gen/.gitignore b/bundles/nl.esi.xtext.actions.tests/xtend-gen/.gitignore new file mode 100644 index 0000000..5e7d273 --- /dev/null +++ b/bundles/nl.esi.xtext.actions.tests/xtend-gen/.gitignore @@ -0,0 +1,4 @@ +# Ignore everything in this directory +* +# Except this file +!.gitignore diff --git a/bundles/nl.esi.xtext.actions.ui/META-INF/MANIFEST.MF b/bundles/nl.esi.xtext.actions.ui/META-INF/MANIFEST.MF index 6c6c440..da1c095 100644 --- a/bundles/nl.esi.xtext.actions.ui/META-INF/MANIFEST.MF +++ b/bundles/nl.esi.xtext.actions.ui/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: Actions Language UI Bundle-Vendor: TNO-ESI -Bundle-Version: 0.1.0.qualifier +Bundle-Version: 0.3.0.qualifier Bundle-SymbolicName: nl.esi.xtext.actions.ui; singleton:=true Bundle-ActivationPolicy: lazy Require-Bundle: nl.esi.xtext.actions;visibility:=reexport, diff --git a/bundles/nl.esi.xtext.actions/META-INF/MANIFEST.MF b/bundles/nl.esi.xtext.actions/META-INF/MANIFEST.MF index 7f58baa..05e68f8 100644 --- a/bundles/nl.esi.xtext.actions/META-INF/MANIFEST.MF +++ b/bundles/nl.esi.xtext.actions/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: Actions Language Core Bundle-Vendor: TNO-ESI -Bundle-Version: 0.1.0.qualifier +Bundle-Version: 0.3.0.qualifier Bundle-SymbolicName: nl.esi.xtext.actions; singleton:=true Bundle-ActivationPolicy: lazy Require-Bundle: nl.esi.xtext.expressions;visibility:=reexport, diff --git a/bundles/nl.esi.xtext.actions/adoc/nl.esi.xtext.actions.adoc b/bundles/nl.esi.xtext.actions/adoc/nl.esi.xtext.actions.adoc new file mode 100644 index 0000000..e97edbc --- /dev/null +++ b/bundles/nl.esi.xtext.actions/adoc/nl.esi.xtext.actions.adoc @@ -0,0 +1,144 @@ +//// + // Copyright (c) 2024, 2026 TNO-ESI + // + // This program and the accompanying materials are made + // available under the terms of the Eclipse Public License 2.0 + // which is available at https://www.eclipse.org/legal/epl-2.0/ + // + // SPDX-License-Identifier: EPL-2.0 +//// + +[[nl.esi.xtext.actions]] += Actions +:lang: en + +[.normal] + +== Action Language Overview + +Actions are imperative statements used to describe behavior in models. They include assignments, conditional logic, loops, function calls, and record field updates. Actions operate on variables and expressions defined using the <> language. + +*Supported action types:* assignment, for-loop, if-then-else, record field assignment, function call. + + +=== Assignment Action + +An assignment action updates the value of a previously declared variable using the `:=` operator: + +.... +variable := expression +.... + +Examples: + +.... +int x +x := 5 +x := x + 1 +.... + +=== For Action + +A for-loop iterates over the elements of a collection, executing a block of actions for each element: + +.... +for Type name in expression + do + actions +end-for +.... + +Examples: + +.... +int[] numbers = [1, 2, 3] +int total +for int n in numbers + do + total := total + n +end-for +.... + +=== If Action + +A conditional action executes a block of actions when a guard expression evaluates to true. An optional `else` branch is executed when the guard is false: + +.... +if guard +then + actions +fi + +if guard +then + actions +else + actions +fi +.... + +Examples: + +.... +int x +x := 10 +int result +if x > 5 +then + result := 1 +else + result := 0 +fi +.... + +=== Record Field Assignment Action + +A record field assignment updates a specific field of a record stored in a variable. The left-hand side uses dot notation to access the field: + +.... +variable.field := expression +.... + +Nested field access is also supported: + +.... +variable.field1.field2 := expression +.... + +Examples: + +.... +record Point { int x, int y } +Point p = Point{x = 0, y = 0} +p.x := 10 +p.y := 20 +.... + +NOTE: Only fields of records stored in variables can be assigned. Collection element access such as `collection[i].field := value` is not supported. + +=== Function Call Action + +A function call can be used as a standalone action (statement). The function call syntax is the same as in expressions: + +.... +function_name(args) +.... + +Examples: + +.... +function int sum(int[] values) +int[] data = [1, 2, 3] +sum(data) +.... + +NOTE: Function call actions use the same syntax as expression function calls. See <> for details on function calls, named arguments, and template functions. + +=== Notes + +* Actions operate on variables declared using the Expressions language. +* The `:=` operator is used for assignment (not `=`, which is used for initialization in variable declarations). +* For-loops require an iterable expression (e.g., a vector). +* If-actions require a boolean guard expression. +* Record field assignments only work on variables, not on collection elements. +* Function calls can be used both as expressions (returning a value) and as standalone actions. \ No newline at end of file diff --git a/bundles/nl.esi.xtext.actions/build.properties b/bundles/nl.esi.xtext.actions/build.properties index 1d9f886..675fb1d 100644 --- a/bundles/nl.esi.xtext.actions/build.properties +++ b/bundles/nl.esi.xtext.actions/build.properties @@ -14,7 +14,8 @@ source.. = src/,\ bin.includes = model/generated/,\ .,\ META-INF/,\ - plugin.xml + plugin.xml,\ + adoc/ bin.excludes = **/*.mwe2,\ **/*.xtend additional.bundles = org.eclipse.xtext.xbase,\ diff --git a/bundles/nl.esi.xtext.actions/pom.xml b/bundles/nl.esi.xtext.actions/pom.xml index a621316..69dc4d8 100644 --- a/bundles/nl.esi.xtext.actions/pom.xml +++ b/bundles/nl.esi.xtext.actions/pom.xml @@ -16,7 +16,7 @@ nl.esi.xplus nl.esi.xplus.root - 0.1.0-SNAPSHOT + 0.3.0-SNAPSHOT ../../ diff --git a/bundles/nl.esi.xtext.actions/src/nl/esi/xtext/actions/Actions.xtext b/bundles/nl.esi.xtext.actions/src/nl/esi/xtext/actions/Actions.xtext index c27a8b3..3d4bc32 100644 --- a/bundles/nl.esi.xtext.actions/src/nl/esi/xtext/actions/Actions.xtext +++ b/bundles/nl.esi.xtext.actions/src/nl/esi/xtext/actions/Actions.xtext @@ -9,12 +9,24 @@ */ grammar nl.esi.xtext.actions.Actions with nl.esi.xtext.expressions.Expression -generate actions "http://www.esi.nlxtext/actions/Actions" +generate actions "http://www.esi.nl/xtext/actions/Actions" import "http://www.esi.nl/xtext/common/lang/Base" as base import "http://www.esi.nl/xtext/types/Types" as types import "http://www.esi.nl/xtext/expressions/Expression" as expr +/** + * Root container solely used for testing. + */ +ActionModel returns expr::ExpressionModel: {ActionModel} + imports += Import* + ( types += TypeDecl + | variables += VariableDecl + | functions += FunctionDecl + | actions += Action + )* +; + /* * Actions are statements, acts of sending one or more events, or a declaration of * an expectation to observe a number of events that satisfy a pattern. @@ -36,7 +48,7 @@ FunctionCall: ; AssignmentAction: - assignment =[expr::Variable | ID] ':=' exp=Expression (symbolic?='symbolic-ref')? + assignment =[expr::Variable | ID] ':=' exp=Expression ; ForAction: @@ -53,14 +65,15 @@ IfAction: ; RecordFieldAssignmentAction: - fieldAccess = FieldAccessExp ':=' exp=Expression (symbolic?='symbolic-ref')? + fieldAccess = FieldAccessExp ':=' exp=Expression ; /* - * In XPlus we can only change field values of records that are stored in a variable. - * Since we cannot access elements in collections, syntax like collection[i].a := v is not supported + * Restricted variant of ExpressionLevel8 from Expression.xtext, used as an + * assignment target. Only variable-rooted record field paths (e.g., v.a.b) are + * valid l-values. Map element access (e.g., m[k] or m[k].a) is not supported + * because collection elements cannot be assigned to in XPlus. */ - // TODO: Why not just reuse ExpressionRecordAccess here? FieldAccessExp returns expr::Expression: ExpressionVariable ({expr::ExpressionRecordAccess.record = current} '.' field = [types::RecordField | ID])+ ; diff --git a/bundles/nl.esi.xtext.actions/src/nl/esi/xtext/actions/GenerateActions.mwe2 b/bundles/nl.esi.xtext.actions/src/nl/esi/xtext/actions/GenerateActions.mwe2 index ccffa3b..1b10a1f 100644 --- a/bundles/nl.esi.xtext.actions/src/nl/esi/xtext/actions/GenerateActions.mwe2 +++ b/bundles/nl.esi.xtext.actions/src/nl/esi/xtext/actions/GenerateActions.mwe2 @@ -21,6 +21,9 @@ Workflow { project = StandardProjectConfig { baseName = "nl.esi.xtext.actions" rootPath = rootPath + runtimeTest = { + enabled = true + } eclipsePlugin = { enabled = true } diff --git a/bundles/nl.esi.xtext.actions/src/nl/esi/xtext/actions/utilities/ActionsUtilities.xtend b/bundles/nl.esi.xtext.actions/src/nl/esi/xtext/actions/utilities/ActionsUtilities.xtend index f1e110b..81bfd19 100644 --- a/bundles/nl.esi.xtext.actions/src/nl/esi/xtext/actions/utilities/ActionsUtilities.xtend +++ b/bundles/nl.esi.xtext.actions/src/nl/esi/xtext/actions/utilities/ActionsUtilities.xtend @@ -18,6 +18,7 @@ import nl.esi.xtext.actions.actions.PCFragment import nl.esi.xtext.actions.actions.PCFragmentDefinition import nl.esi.xtext.actions.actions.PCFragmentReference import nl.esi.xtext.actions.actions.RecordFieldAssignmentAction +import nl.esi.xtext.expressions.expression.Expression import nl.esi.xtext.expressions.expression.ExpressionRecordAccess import nl.esi.xtext.expressions.expression.ExpressionVariable @@ -57,12 +58,26 @@ class ActionsUtilities { } def static getFields(RecordFieldAssignmentAction action) { + return action.fieldAccess.fields + } + + def static getField(RecordFieldAssignmentAction action) { + return action.fieldAccess.field + } + + def static getFields(Expression expression) { val fields = newLinkedList() - var record = action.fieldAccess + var record = expression while (record instanceof ExpressionRecordAccess) { fields.addFirst(record.field) record = record.record } return fields } + + def static getField(Expression expression) { + if (expression instanceof ExpressionRecordAccess) { + return expression.field + } + } } \ No newline at end of file diff --git a/bundles/nl.esi.xtext.common.lang.ide/META-INF/MANIFEST.MF b/bundles/nl.esi.xtext.common.lang.ide/META-INF/MANIFEST.MF index 42c4977..b90e59e 100644 --- a/bundles/nl.esi.xtext.common.lang.ide/META-INF/MANIFEST.MF +++ b/bundles/nl.esi.xtext.common.lang.ide/META-INF/MANIFEST.MF @@ -3,7 +3,7 @@ Automatic-Module-Name: nl.esi.xtext.common.lang.ide Bundle-ManifestVersion: 2 Bundle-Name: Base Language IDE Bundle-Vendor: TNO-ESI -Bundle-Version: 0.1.0.qualifier +Bundle-Version: 0.3.0.qualifier Bundle-SymbolicName: nl.esi.xtext.common.lang.ide; singleton:=true Bundle-ActivationPolicy: lazy Require-Bundle: nl.esi.xtext.common.lang, diff --git a/bundles/nl.esi.xtext.common.lang.tests/META-INF/MANIFEST.MF b/bundles/nl.esi.xtext.common.lang.tests/META-INF/MANIFEST.MF index d591752..eb8168f 100644 --- a/bundles/nl.esi.xtext.common.lang.tests/META-INF/MANIFEST.MF +++ b/bundles/nl.esi.xtext.common.lang.tests/META-INF/MANIFEST.MF @@ -3,7 +3,7 @@ Automatic-Module-Name: nl.esi.xtext.common.lang.tests Bundle-ManifestVersion: 2 Bundle-Name: Base Language Tests Bundle-Vendor: TNO-ESI -Bundle-Version: 0.1.0.qualifier +Bundle-Version: 0.3.0.qualifier Bundle-SymbolicName: nl.esi.xtext.common.lang.tests; singleton:=true Bundle-ActivationPolicy: lazy Require-Bundle: nl.esi.xtext.common.lang, diff --git a/bundles/nl.esi.xtext.common.lang.ui/META-INF/MANIFEST.MF b/bundles/nl.esi.xtext.common.lang.ui/META-INF/MANIFEST.MF index 234438c..4188e3d 100644 --- a/bundles/nl.esi.xtext.common.lang.ui/META-INF/MANIFEST.MF +++ b/bundles/nl.esi.xtext.common.lang.ui/META-INF/MANIFEST.MF @@ -3,7 +3,7 @@ Automatic-Module-Name: nl.esi.xtext.common.lang.ui Bundle-ManifestVersion: 2 Bundle-Name: Base Language UI Bundle-Vendor: TNO-ESI -Bundle-Version: 0.1.0.qualifier +Bundle-Version: 0.3.0.qualifier Bundle-SymbolicName: nl.esi.xtext.common.lang.ui; singleton:=true Bundle-ActivationPolicy: lazy Require-Bundle: nl.esi.xtext.common.lang, diff --git a/bundles/nl.esi.xtext.common.lang/META-INF/MANIFEST.MF b/bundles/nl.esi.xtext.common.lang/META-INF/MANIFEST.MF index 8b6f714..e7d54df 100644 --- a/bundles/nl.esi.xtext.common.lang/META-INF/MANIFEST.MF +++ b/bundles/nl.esi.xtext.common.lang/META-INF/MANIFEST.MF @@ -3,7 +3,7 @@ Automatic-Module-Name: nl.esi.xtext.common.lang Bundle-ManifestVersion: 2 Bundle-Name: Base Language Core Bundle-Vendor: TNO-ESI -Bundle-Version: 0.1.0.qualifier +Bundle-Version: 0.3.0.qualifier Bundle-SymbolicName: nl.esi.xtext.common.lang; singleton:=true Bundle-ActivationPolicy: lazy Require-Bundle: org.eclipse.xtext, diff --git a/bundles/nl.esi.xtext.common.lang/pom.xml b/bundles/nl.esi.xtext.common.lang/pom.xml index 437919e..04431b8 100644 --- a/bundles/nl.esi.xtext.common.lang/pom.xml +++ b/bundles/nl.esi.xtext.common.lang/pom.xml @@ -15,7 +15,7 @@ nl.esi.xplus nl.esi.xplus.root - 0.1.0-SNAPSHOT + 0.3.0-SNAPSHOT ../../ diff --git a/bundles/nl.esi.xtext.common.lang/src/nl/esi/xtext/common/lang/utilities/EcoreUtil3.java b/bundles/nl.esi.xtext.common.lang/src/nl/esi/xtext/common/lang/utilities/EcoreUtil3.java index b342e54..ed8fa0e 100644 --- a/bundles/nl.esi.xtext.common.lang/src/nl/esi/xtext/common/lang/utilities/EcoreUtil3.java +++ b/bundles/nl.esi.xtext.common.lang/src/nl/esi/xtext/common/lang/utilities/EcoreUtil3.java @@ -43,6 +43,7 @@ import org.eclipse.xtext.serializer.impl.Serializer; import org.eclipse.xtext.util.ITextRegion; +import com.google.common.base.Strings; import com.google.inject.Guice; import com.google.inject.Module; @@ -296,7 +297,7 @@ public static final class ValidationException extends Exception { private static final long serialVersionUID = 4543121779695994392L; public ValidationException(Diagnostic diagnostic) { - super(createMessage(diagnostic), new DiagnosticException(diagnostic)); + super(createMessage(diagnostic, ""), new DiagnosticException(diagnostic)); } @Override @@ -304,10 +305,24 @@ public synchronized DiagnosticException getCause() { return DiagnosticException.class.cast(super.getCause()); } - private static String createMessage(Diagnostic diagnostic) { + private static String createMessage(Diagnostic diagnostic, String indent) { + StringBuilder message = new StringBuilder(indent); + message.append(switch (diagnostic.getSeverity()) { + case Diagnostic.INFO -> "INFO: "; + case Diagnostic.WARNING -> "WARNING: "; + case Diagnostic.ERROR -> "ERROR: "; + default -> ""; + }); + message.append(diagnostic.getMessage()); + + String cIndent = Strings.isNullOrEmpty(indent) ? "- " : " " + indent; String details = diagnostic.getChildren().stream().filter(c -> c.getSeverity() != Diagnostic.OK) - .map(c -> "- " + c.getMessage()).collect(Collectors.joining("\n")); - return diagnostic.getMessage() + (details.isEmpty() ? "" : "\n" + details); + .map(c -> createMessage(c, cIndent)).collect(Collectors.joining("\n")); + if (!details.isEmpty()) { + message.append("\n").append(details); + } + + return message.toString(); } } } diff --git a/bundles/nl.esi.xtext.common.lang/src/nl/esi/xtext/common/lang/validation/BaseValidator.xtend b/bundles/nl.esi.xtext.common.lang/src/nl/esi/xtext/common/lang/validation/BaseValidator.xtend index b5a049e..4180121 100644 --- a/bundles/nl.esi.xtext.common.lang/src/nl/esi/xtext/common/lang/validation/BaseValidator.xtend +++ b/bundles/nl.esi.xtext.common.lang/src/nl/esi/xtext/common/lang/validation/BaseValidator.xtend @@ -96,4 +96,8 @@ class BaseValidator extends AbstractBaseValidator { } } } + + protected static def Iterable getDuplicatesBy(Iterable source, (T)=>Object functor) { + return source.groupBy(functor).values.filter[size > 1].flatten + } } diff --git a/bundles/nl.esi.xtext.expressions.ide/META-INF/MANIFEST.MF b/bundles/nl.esi.xtext.expressions.ide/META-INF/MANIFEST.MF index a09e669..3216339 100644 --- a/bundles/nl.esi.xtext.expressions.ide/META-INF/MANIFEST.MF +++ b/bundles/nl.esi.xtext.expressions.ide/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: Expression Lang IDE Bundle-Vendor: TNO-ESI -Bundle-Version: 0.1.0.qualifier +Bundle-Version: 0.3.0.qualifier Bundle-SymbolicName: nl.esi.xtext.expressions.ide; singleton:=true Bundle-ActivationPolicy: lazy Require-Bundle: nl.esi.xtext.expressions;visibility:=reexport, diff --git a/bundles/nl.esi.xtext.expressions.ide/src/nl/esi/xtext/expressions/ide/contentassist/ExpressionIdeProposalProvider.xtend b/bundles/nl.esi.xtext.expressions.ide/src/nl/esi/xtext/expressions/ide/contentassist/ExpressionIdeProposalProvider.xtend index 28424dc..4492556 100644 --- a/bundles/nl.esi.xtext.expressions.ide/src/nl/esi/xtext/expressions/ide/contentassist/ExpressionIdeProposalProvider.xtend +++ b/bundles/nl.esi.xtext.expressions.ide/src/nl/esi/xtext/expressions/ide/contentassist/ExpressionIdeProposalProvider.xtend @@ -88,7 +88,7 @@ class ExpressionIdeProposalProvider extends AbstractExpressionIdeProposalProvide } try { - val defaultValue = ProposalHelper.defaultValue(typeAnn, targetName) + val defaultValue = createDefaultValueEntry(typeAnn, targetName, context) val proposal = proposalCreator.createProposal(defaultValue, context, [ entry | entry.kind = ContentAssistEntry.KIND_SNIPPET entry.label = ProposalHelper.getTypeName(typeAnn) @@ -103,6 +103,10 @@ class ExpressionIdeProposalProvider extends AbstractExpressionIdeProposalProvide } } + protected def String createDefaultValueEntry(TypeAnnotation typeAnn, String targetName, ContentAssistContext context) { + return ProposalHelper.defaultValue(typeAnn, targetName) + } + protected def createDefaultValue(Type type, String targetName, ContentAssistContext context, IIdeContentProposalAcceptor acceptor) { if (type instanceof TypeReference && type.type instanceof EnumTypeDecl) { createEnumValues(type.type as EnumTypeDecl, context, acceptor) @@ -110,7 +114,7 @@ class ExpressionIdeProposalProvider extends AbstractExpressionIdeProposalProvide } try { - val defaultValue = ProposalHelper.defaultValue(type, targetName) + val defaultValue = createDefaultValueEntry(type, targetName, context) val proposal = proposalCreator.createProposal(defaultValue, context, [ entry | entry.kind = ContentAssistEntry.KIND_SNIPPET entry.label = ProposalHelper.getTypeName(type) @@ -125,6 +129,10 @@ class ExpressionIdeProposalProvider extends AbstractExpressionIdeProposalProvide } } + protected def String createDefaultValueEntry(Type type, String targetName, ContentAssistContext context) { + return ProposalHelper.defaultValue(type, targetName) + } + protected def createEnumValues(EnumTypeDecl type, ContentAssistContext context, IIdeContentProposalAcceptor acceptor) { for (literal : type.literals) { val value = '''«type.name»::«literal.name»''' diff --git a/bundles/nl.esi.xtext.expressions.tests/META-INF/MANIFEST.MF b/bundles/nl.esi.xtext.expressions.tests/META-INF/MANIFEST.MF index be23973..f53652f 100644 --- a/bundles/nl.esi.xtext.expressions.tests/META-INF/MANIFEST.MF +++ b/bundles/nl.esi.xtext.expressions.tests/META-INF/MANIFEST.MF @@ -3,7 +3,7 @@ Automatic-Module-Name: nl.esi.xtext.expressions.tests Bundle-ManifestVersion: 2 Bundle-Name: Expression Lang Tests Bundle-Vendor: TNO-ESI -Bundle-Version: 0.1.0.qualifier +Bundle-Version: 0.3.0.qualifier Bundle-SymbolicName: nl.esi.xtext.expressions.tests; singleton:=true Bundle-ActivationPolicy: lazy Require-Bundle: nl.esi.xtext.expressions, diff --git a/bundles/nl.esi.xtext.expressions.tests/src/nl/esi/xtext/expressions/tests/ExpressionFunctionsValidation.xtend b/bundles/nl.esi.xtext.expressions.tests/src/nl/esi/xtext/expressions/tests/ExpressionFunctionsValidation.xtend index a943aa4..4210bf5 100644 --- a/bundles/nl.esi.xtext.expressions.tests/src/nl/esi/xtext/expressions/tests/ExpressionFunctionsValidation.xtend +++ b/bundles/nl.esi.xtext.expressions.tests/src/nl/esi/xtext/expressions/tests/ExpressionFunctionsValidation.xtend @@ -427,7 +427,86 @@ class ExpressionFunctionsValidation { ''') assertDoesNotThrow [EcoreUtil3.validate(result)] } - + + // ======================================================================== + // Named argument tests + // ======================================================================== + + @Test + def void namedArgs_validCall_noValidationError() { + val result = parse(''' + function int myFn(int a, int b, int c) + int r = myFn(1, b = 2, c = 3) + ''') + assertDoesNotThrow [EcoreUtil3.validate(result)] + } + + @Test + def void namedArgs_sizeMismatch_tooFew_validationError() { + val result = parse(''' + function int myFn(int a, int b, int c) + int r = myFn(1, b = 2) + ''') + val ex = assertThrows(ValidationException) [EcoreUtil3.validate(result)] + assertTrue(ex.message.contains('No Function myFn declared with 2 arguments'), + '''Expected size mismatch error but got: «ex.message»''') + } + + @Test + def void namedArgs_sizeMismatch_tooMany_validationError() { + val result = parse(''' + function int myFn(int a, int b) + int r = myFn(1, 2, c = 3) + ''') + val ex = assertThrows(ValidationException) [EcoreUtil3.validate(result)] + assertTrue(ex.message.contains('No Function myFn declared with 3 arguments'), + '''Expected size mismatch error but got: «ex.message»''') + } + + @Test + def void namedArgs_namedBeforeIndexed_syntaxError() { + var result = parseHelper.parse(''' + function int myFn(int a, int b, int c) + int r = myFn(a = 1, 2, 3) + ''') + assertNotNull(result) + val errors = result.eResource.errors.join(", ") + assertTrue(errors.contains('mismatched input'), + '''Expected mismatch input but got: «errors»''') + } + + @Test + def void namedArgs_duplicateArgAndNamedArg_validationError() { + val result = parse(''' + function int myFn(int a, int b, int c) + int r = myFn(1, 2, b = 3) + ''') + val ex = assertThrows(ValidationException) [EcoreUtil3.validate(result)] + assertTrue(ex.message.contains('already been specified as numbered arg'), + '''Expected duplicate arg error but got: «ex.message»''') + } + + @Test + def void namedArgs_duplicateNamedArg_validationError() { + val result = parse(''' + function int myFn(int a, int b, int c) + int r = myFn(1, b = 2, b = 3) + ''') + val ex = assertThrows(ValidationException) [EcoreUtil3.validate(result)] + assertTrue(ex.message.contains('Duplicate argument with name b'), + '''Expected duplicate named arg error but got: «ex.message»''') + } + + @Test + def void namedArgs_unknownName_validationError() { + val result = parse(''' + function int myFn(int a, int b) + int r = myFn(1, x = 2) + ''') + val ex = assertThrows(ValidationException) [EcoreUtil3.validate(result)] + assertTrue(ex.message.contains('Unknown argument name x'), + '''Expected unknown arg name error but got: «ex.message»''') + } private def ExpressionModel parse(String model) { val result = parseHelper.parse(model) diff --git a/bundles/nl.esi.xtext.expressions.ui/META-INF/MANIFEST.MF b/bundles/nl.esi.xtext.expressions.ui/META-INF/MANIFEST.MF index c49f379..8702465 100644 --- a/bundles/nl.esi.xtext.expressions.ui/META-INF/MANIFEST.MF +++ b/bundles/nl.esi.xtext.expressions.ui/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: Expression Lang UI Bundle-Vendor: TNO-ESI -Bundle-Version: 0.1.0.qualifier +Bundle-Version: 0.3.0.qualifier Bundle-SymbolicName: nl.esi.xtext.expressions.ui; singleton:=true Bundle-ActivationPolicy: lazy Require-Bundle: nl.esi.xtext.expressions;visibility:=reexport, diff --git a/bundles/nl.esi.xtext.expressions/META-INF/MANIFEST.MF b/bundles/nl.esi.xtext.expressions/META-INF/MANIFEST.MF index 3c398c7..bb539f6 100644 --- a/bundles/nl.esi.xtext.expressions/META-INF/MANIFEST.MF +++ b/bundles/nl.esi.xtext.expressions/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: Expression Lang Core Bundle-Vendor: TNO-ESI -Bundle-Version: 0.1.0.qualifier +Bundle-Version: 0.3.0.qualifier Bundle-SymbolicName: nl.esi.xtext.expressions; singleton:=true Bundle-ActivationPolicy: lazy Require-Bundle: nl.esi.xtext.types;visibility:=reexport, diff --git a/bundles/nl.esi.xtext.expressions/adoc/nl.esi.xtext.expressions.adoc b/bundles/nl.esi.xtext.expressions/adoc/nl.esi.xtext.expressions.adoc index 7b9ccec..085e75f 100644 --- a/bundles/nl.esi.xtext.expressions/adoc/nl.esi.xtext.expressions.adoc +++ b/bundles/nl.esi.xtext.expressions/adoc/nl.esi.xtext.expressions.adoc @@ -112,12 +112,32 @@ See <> for details on template functi Declared Functions can be called as follows: * `function_name(args)` +* `function_name(positional_args, name = value, ...)` .... int total = sum(v) // calls function explicitely declared in the model int numbers = range(1, 10, 2) // calls a default function .... +==== Named Arguments + +Function calls support named arguments, which allow specifying arguments by parameter name rather than position. Named arguments must appear after all positional (indexed) arguments: + +.... +function string formatDate(int year, int month, int day) + +string d1 = formatDate(2026, 5, 29) // all positional +string d2 = formatDate(2026, month = 5, day = 29) // mixed positional and named +.... + +Rules for named arguments: + +* Named arguments must come after all positional arguments. +* A parameter cannot be specified both positionally and by name. +* Duplicate named arguments (same name used twice) are not allowed. +* The named argument name must match a declared parameter name. +* The total number of positional plus named arguments must match the function's parameter count. + === Parentheses Parentheses can be used to group expressions and control evaluation order: @@ -203,4 +223,4 @@ Operators are evaluated in the following order (highest to lowest): * Operator associativity: most operators are left-associative; the power operator `^` is right-associative. * Variables can be declared with optional initialization: `Type name = expression` or just `Type name`. -NOTE: When invoking functions with custom Java types, `IExpressionConverter` instances are evaluated in order until one successfully converts the argument. The first successful conversion is used. This allows custom converters to handle specific types while falling back to default converters for built-in types. See <> for details on implementing custom converters. \ No newline at end of file +NOTE: When invoking functions with custom Java types, `IExpressionConverter` instances are evaluated in order until one successfully converts the argument. The first successful conversion is used. This allows custom converters to handle specific types while falling back to default converters for built-in types. See <> for details on implementing custom converters. \ No newline at end of file diff --git a/bundles/nl.esi.xtext.expressions/pom.xml b/bundles/nl.esi.xtext.expressions/pom.xml index 8a6d433..75f933c 100644 --- a/bundles/nl.esi.xtext.expressions/pom.xml +++ b/bundles/nl.esi.xtext.expressions/pom.xml @@ -15,7 +15,7 @@ nl.esi.xplus nl.esi.xplus.root - 0.1.0-SNAPSHOT + 0.3.0-SNAPSHOT ../../ diff --git a/bundles/nl.esi.xtext.expressions/src/nl/esi/xtext/expressions/Expression.xtext b/bundles/nl.esi.xtext.expressions/src/nl/esi/xtext/expressions/Expression.xtext index 0a82571..19aa9c5 100644 --- a/bundles/nl.esi.xtext.expressions/src/nl/esi/xtext/expressions/Expression.xtext +++ b/bundles/nl.esi.xtext.expressions/src/nl/esi/xtext/expressions/Expression.xtext @@ -130,7 +130,11 @@ ExpressionLevel9 returns Expression: ; ExpressionFunctionCall: - function = [FunctionDecl|ID] '(' (args += Expression (',' args += Expression)*)? ')' + function = [FunctionDecl|ID] '(' (args += Expression (',' args += Expression)*)? (',' namedArgs += NamedArgument)* ')' +; + +NamedArgument: + name = ID '=' arg=Expression ; ExpressionBracket: diff --git a/bundles/nl.esi.xtext.expressions/src/nl/esi/xtext/expressions/functions/ExpressionFunctionsRegistry.java b/bundles/nl.esi.xtext.expressions/src/nl/esi/xtext/expressions/functions/ExpressionFunctionsRegistry.java index f437031..63a09c1 100644 --- a/bundles/nl.esi.xtext.expressions/src/nl/esi/xtext/expressions/functions/ExpressionFunctionsRegistry.java +++ b/bundles/nl.esi.xtext.expressions/src/nl/esi/xtext/expressions/functions/ExpressionFunctionsRegistry.java @@ -34,6 +34,7 @@ import nl.esi.xtext.expressions.evaluation.IEvaluationContext; import nl.esi.xtext.expressions.expression.Expression; import nl.esi.xtext.expressions.expression.ExpressionFunctionCall; +import nl.esi.xtext.expressions.utilities.ExpressionsUtilities; import nl.esi.xtext.types.types.Type; /** @@ -193,7 +194,7 @@ private Method findMatchingMethod(ExpressionFunctionCall functionCall, IEvaluati return null; } - var args = functionCall.getArgs(); + var args = ExpressionsUtilities.getFunctionArgs(functionCall); for (var method : candidates) { if (method.getParameterTypes().length == args.size()) { boolean allMatch = true; @@ -215,7 +216,7 @@ private Method findMatchingMethod(ExpressionFunctionCall functionCall, IEvaluati /** Converts function call arguments to their Java object representations. */ private Object[] convertArguments(ExpressionFunctionCall funcCall, Class[] paramTypes, IEvaluationContext context) { var funcName = funcCall.getFunction().getName(); - var argExprs = funcCall.getArgs(); + var argExprs = ExpressionsUtilities.getFunctionArgs(funcCall); if (argExprs.size() != paramTypes.length) { throw new IllegalArgumentException("Argument count mismatch for function '" + funcName + "': expected " + paramTypes.length + " but got " + argExprs.size()); diff --git a/bundles/nl.esi.xtext.expressions/src/nl/esi/xtext/expressions/utilities/ExpressionsUtilities.xtend b/bundles/nl.esi.xtext.expressions/src/nl/esi/xtext/expressions/utilities/ExpressionsUtilities.xtend index 34daf58..84bf985 100644 --- a/bundles/nl.esi.xtext.expressions/src/nl/esi/xtext/expressions/utilities/ExpressionsUtilities.xtend +++ b/bundles/nl.esi.xtext.expressions/src/nl/esi/xtext/expressions/utilities/ExpressionsUtilities.xtend @@ -70,6 +70,7 @@ import static nl.esi.xtext.common.lang.utilities.EcoreUtil3.* import static extension nl.esi.xtext.types.utilities.TypeUtilities.* import static extension org.eclipse.emf.ecore.util.EcoreUtil.* +import java.util.ArrayList class ExpressionsUtilities { static extension val ExpressionFactory EXPRESSION_FACTORY = ExpressionFactory.eINSTANCE @@ -244,6 +245,34 @@ class ExpressionsUtilities { def static boolean isAssignableFrom(TypeObject lhs, Expression rhs) { TypeUtilities.subTypeOf(lhs, rhs.typeOf) || rhs instanceof ExpressionNullLiteral } + + def static List getFunctionArgs(ExpressionFunctionCall efc){ + // don't validate here, that is part of the validator + if (efc.function === null) { + return List.of(); + } + val result = new ArrayList(efc.args) + val params = efc.function.params + // Pad with nulls to match number of params + while(result.size < params.size) { + result.add(null) + } + + // Build parameter name to index map for O(1) lookups + val paramNameIndexMap = newLinkedHashMap + for(var i = 0; i < params.size; i++) { + paramNameIndexMap.put(params.get(i).name, i) + } + + // Fill in named arguments + for (na : efc.namedArgs){ + val ind = paramNameIndexMap.get(na.name) + if (ind !== null){ + result.set(ind, na.arg) + } + } + return result + } def static TypeObject inferTypeBinaryArithmetic(ExpressionBinary e){ val leftType = e.left.typeOf diff --git a/bundles/nl.esi.xtext.expressions/src/nl/esi/xtext/expressions/utilities/ProposalHelper.java b/bundles/nl.esi.xtext.expressions/src/nl/esi/xtext/expressions/utilities/ProposalHelper.java index 3cdc453..75ba2ee 100644 --- a/bundles/nl.esi.xtext.expressions/src/nl/esi/xtext/expressions/utilities/ProposalHelper.java +++ b/bundles/nl.esi.xtext.expressions/src/nl/esi/xtext/expressions/utilities/ProposalHelper.java @@ -13,10 +13,13 @@ import java.util.List; import java.util.function.Function; +import java.util.function.Predicate; import java.util.stream.Collectors; import org.eclipse.emf.ecore.util.EcoreUtil; +import com.google.common.base.Predicates; + import nl.esi.xtext.expressions.expression.Expression; import nl.esi.xtext.expressions.expression.ExpressionAddition; import nl.esi.xtext.expressions.expression.ExpressionAnd; @@ -56,7 +59,6 @@ import nl.esi.xtext.types.types.MapTypeConstructor; import nl.esi.xtext.types.types.MapTypeDecl; import nl.esi.xtext.types.types.RecordField; -import nl.esi.xtext.types.types.RecordFieldKind; import nl.esi.xtext.types.types.RecordTypeDecl; import nl.esi.xtext.types.types.SimpleTypeDecl; import nl.esi.xtext.types.types.Type; @@ -84,16 +86,24 @@ public static String getTypeName(TypeAnnotation typeAnn) { } public static String defaultValue(TypeAnnotation typeAnn, String targetName) throws UnsupportedTypeException { - return createDefaultValueEntry(typeAnn.getType(), targetName, ""); + return createDefaultValueEntry(typeAnn.getType(), targetName, "", Predicates.alwaysTrue()); + } + + public static String defaultValue(TypeAnnotation typeAnn, String targetName, Predicate filter) throws UnsupportedTypeException { + return createDefaultValueEntry(typeAnn.getType(), targetName, "", filter); } public static String defaultValue(Type type, String targetName) throws UnsupportedTypeException { - return createDefaultValue(type, targetName, ""); + return createDefaultValue(type, targetName, "", Predicates.alwaysTrue()); + } + + public static String defaultValue(Type type, String targetName, Predicate filter) throws UnsupportedTypeException { + return createDefaultValue(type, targetName, "", filter); } - private static String createDefaultValue(Type type, String targetName, String indent) throws UnsupportedTypeException { + private static String createDefaultValue(Type type, String targetName, String indent, Predicate filter) throws UnsupportedTypeException { if (type instanceof TypeReference) { - return createDefaultValueEntry(type, targetName, indent); + return createDefaultValueEntry(type, targetName, indent, filter); } else if (type instanceof VectorTypeConstructor) { return "<" + getTypeName(type) + ">[]"; } else if (type instanceof MapTypeConstructor) { @@ -102,17 +112,17 @@ private static String createDefaultValue(Type type, String targetName, String in throw new UnsupportedTypeException(type); } - private static String createDefaultValueEntry(Type type, String targetName, String indent) throws UnsupportedTypeException { + private static String createDefaultValueEntry(Type type, String targetName, String indent, Predicate filter) throws UnsupportedTypeException { if (type instanceof TypeReference) { - return createDefaultValue(type.getType(), targetName, indent); + return createDefaultValue(type.getType(), targetName, indent, filter); } else if (type instanceof VectorTypeConstructor vecType) { if (vecType.getDimensions().size() > 1) { - return createDefaultValue(getOuterDimension(vecType), null, indent); + return createDefaultValue(getOuterDimension(vecType), null, indent, filter); } - return createDefaultValue(type.getType(), targetName, indent); + return createDefaultValue(type.getType(), targetName, indent, filter); } else if (type instanceof MapTypeConstructor mapType) { - String key = createDefaultValue(type.getType(), null, indent); - String value = createDefaultValue(mapType.getValueType(), null, indent); + String key = createDefaultValue(type.getType(), null, indent, filter); + String value = createDefaultValue(mapType.getValueType(), null, indent, filter); return key + " -> " + value; } throw new UnsupportedTypeException(type); @@ -124,9 +134,9 @@ private static Type getOuterDimension(VectorTypeConstructor vectorType) { return outerDimension; } - private static String createDefaultValue(TypeDecl type, String targetName, String indent) throws UnsupportedTypeException { + private static String createDefaultValue(TypeDecl type, String targetName, String indent, Predicate filter) throws UnsupportedTypeException { if (type instanceof SimpleTypeDecl simpleType) { - if (simpleType.getBase() != null) return createDefaultValue(simpleType.getBase(), targetName, indent); + if (simpleType.getBase() != null) return createDefaultValue(simpleType.getBase(), targetName, indent, filter); else if (simpleType.getName().equals("int")) return "0"; else if (simpleType.getName().equals("real")) return "0.0"; else if (simpleType.getName().equals("bool")) return "true"; @@ -139,16 +149,16 @@ private static String createDefaultValue(TypeDecl type, String targetName, Strin } else if (type instanceof MapTypeDecl) { return "{}"; } else if (type instanceof RecordTypeDecl recType) { - List recFields = getAllFields(recType).stream().filter(f -> !RecordFieldKind.SYMBOLIC.equals(f.getKind())).toList(); + List recFields = getAllFields(recType).stream().filter(filter).toList(); if (recFields.size() > 1) { String fieldIndent = indent + "\t"; String value = recFields.stream() - .map(f -> String.format("%s%s = %s", fieldIndent, f.getName(), createDefaultValue(f.getType(), f.getName(), fieldIndent))) + .map(f -> String.format("%s%s = %s", fieldIndent, f.getName(), createDefaultValue(f.getType(), f.getName(), fieldIndent, filter))) .collect(Collectors.joining(",\n")); return String.format("%s {\n%s\n%s}", type.getName(), value, indent); } else { String value = recFields.stream() - .map(f -> String.format("%s = %s", f.getName(), createDefaultValue(f.getType(), f.getName(), indent))) + .map(f -> String.format("%s = %s", f.getName(), createDefaultValue(f.getType(), f.getName(), indent, filter))) .collect(Collectors.joining(",\n")); return String.format("%s { %s }", type.getName(), value); } diff --git a/bundles/nl.esi.xtext.expressions/src/nl/esi/xtext/expressions/validation/ExpressionValidator.xtend b/bundles/nl.esi.xtext.expressions/src/nl/esi/xtext/expressions/validation/ExpressionValidator.xtend index 27ee7ad..196d283 100644 --- a/bundles/nl.esi.xtext.expressions/src/nl/esi/xtext/expressions/validation/ExpressionValidator.xtend +++ b/bundles/nl.esi.xtext.expressions/src/nl/esi/xtext/expressions/validation/ExpressionValidator.xtend @@ -51,8 +51,8 @@ import org.eclipse.emf.ecore.EReference import org.eclipse.xtext.scoping.IScopeProvider import org.eclipse.xtext.validation.Check -import static extension nl.esi.xtext.expressions.utilities.ExpressionsUtilities.* import static extension nl.esi.xtext.types.utilities.TypeUtilities.* +import static extension nl.esi.xtext.expressions.utilities.ExpressionsUtilities.* /* * This class mainly captures the XPlus type system for expressions. Constraints are not formulated @@ -254,29 +254,51 @@ class ExpressionValidator extends AbstractExpressionValidator { } ExpressionFunctionCall: { if (e.function === null || e.function.name === null) { - error('''Function declaration not found. Name or number of args («e.args.size») is wrong''', null) + error('''Function declaration not found. Name or number of args («e.args.size») is wrong''', e, ExpressionPackage.Literals.EXPRESSION_FUNCTION_CALL__FUNCTION) + return + } + val totalArgs = e.args.size + e.namedArgs.size + val duplicates = e.namedArgs.groupBy[name].values.filter[size>1].flatten + if (!duplicates.empty) { + for( it : e.namedArgs.groupBy[name].values.filter[size>1].flatten) { + error('''Duplicate argument with name «name».''', e, ExpressionPackage.Literals.EXPRESSION_FUNCTION_CALL__NAMED_ARGS,e.namedArgs.indexOf(it)) + } + return + } + if (totalArgs != e.function.params.size) { + error('''No Function «e.function.name» declared with «totalArgs» arguments.''', e, ExpressionPackage.Literals.EXPRESSION_FUNCTION_CALL__FUNCTION) return + } + + val paramList = e.function.params.map[name] + for (na : e.namedArgs){ + val paramIndex = paramList.indexOf(na.name) + if(paramIndex === -1) { + error('''Unknown argument name «na.name» for function «e.function.name»''', e, ExpressionPackage.Literals.EXPRESSION_FUNCTION_CALL__NAMED_ARGS, e.namedArgs.indexOf(na)) + return + } + if (paramIndex < e.args.size ) { + error('''Argument name «na.name» with index «paramIndex» has already been specified as numbered arg''', e, ExpressionPackage.Literals.EXPRESSION_FUNCTION_CALL__NAMED_ARGS, e.namedArgs.indexOf(na)) + return + } } - if (e.args.size != e.function.params.size) { - error('''No Function «e.function.name» declared with «e.args.size» arguments.''', null) - } else { - val ambiguousTypes = e.function.typeParams.filter[tp |tp.getActualFunctionTypes(e).size>1].toList - for (var i = 0; i < e.args.size; i++) { - val arg = e.args.get(i) - val param = e.function.params.get(i) - val paramType = param.type.inferActualType(arg)?.typeObject - val argType = arg.typeOf - if (!argType.subTypeOf(paramType) ) { - error('''Function «e.function.name» expects argument «param.name» to be of type «paramType.typeName».''', - e, ExpressionPackage.Literals.EXPRESSION_FUNCTION_CALL__ARGS, i) - } - val containedGenerics = param.type.genericsTypeParams - val isAmbiguous = !containedGenerics.filter[ambiguousTypes.contains(it)].empty - if (isAmbiguous){ - error('''Function «e.function.name» generic type mismatch typeParam «param.name» resolving is ambiguous''', - e, ExpressionPackage.Literals.EXPRESSION_FUNCTION_CALL__ARGS, i) - } + val ambiguousTypes = e.function.typeParams.filter[tp |tp.getActualFunctionTypes(e).size>1].toList + val args = e.functionArgs + for (var i = 0; i < args.size; i++) { + val arg = args.get(i) + val param = e.function.params.get(i) + val paramType = param.type.inferActualType(arg)?.typeObject + val argType = arg.typeOf + if (!argType.subTypeOf(paramType) ) { + error('''Function «e.function.name» expects argument «param.name» to be of type «paramType.typeName».''', + e, ExpressionPackage.Literals.EXPRESSION_FUNCTION_CALL__ARGS, i) + } + val containedGenerics = param.type.genericsTypeParams + val isAmbiguous = !containedGenerics.filter[ambiguousTypes.contains(it)].empty + if (isAmbiguous){ + error('''Function «e.function.name» generic type mismatch typeParam «param.name» resolving is ambiguous''', + e, ExpressionPackage.Literals.EXPRESSION_FUNCTION_CALL__ARGS, i) } } } diff --git a/bundles/nl.esi.xtext.launch/Generate all Language Infrastructures.launch b/bundles/nl.esi.xtext.launch/Generate all Language Infrastructures.launch index 42c07c0..2259433 100644 --- a/bundles/nl.esi.xtext.launch/Generate all Language Infrastructures.launch +++ b/bundles/nl.esi.xtext.launch/Generate all Language Infrastructures.launch @@ -2,22 +2,22 @@ - + - + - + - + diff --git a/bundles/nl.esi.xtext.launch/Maven Build.launch b/bundles/nl.esi.xtext.launch/Maven Build.launch index 0c6782e..89d7d36 100644 --- a/bundles/nl.esi.xtext.launch/Maven Build.launch +++ b/bundles/nl.esi.xtext.launch/Maven Build.launch @@ -10,7 +10,7 @@ - + diff --git a/bundles/nl.esi.xtext.launch/Maven Doc-Build.launch b/bundles/nl.esi.xtext.launch/Maven Doc-Build.launch index 51d65c1..de372ed 100644 --- a/bundles/nl.esi.xtext.launch/Maven Doc-Build.launch +++ b/bundles/nl.esi.xtext.launch/Maven Doc-Build.launch @@ -12,7 +12,7 @@ - + diff --git a/bundles/nl.esi.xtext.launch/License Format.launch b/bundles/nl.esi.xtext.launch/Maven License Format.launch similarity index 96% rename from bundles/nl.esi.xtext.launch/License Format.launch rename to bundles/nl.esi.xtext.launch/Maven License Format.launch index 750253b..0c3ddd2 100644 --- a/bundles/nl.esi.xtext.launch/License Format.launch +++ b/bundles/nl.esi.xtext.launch/Maven License Format.launch @@ -10,7 +10,7 @@ - + diff --git a/bundles/nl.esi.xtext.launch/Maven Re-build.launch b/bundles/nl.esi.xtext.launch/Maven Re-build.launch index 1f6c661..1732623 100644 --- a/bundles/nl.esi.xtext.launch/Maven Re-build.launch +++ b/bundles/nl.esi.xtext.launch/Maven Re-build.launch @@ -2,7 +2,7 @@ - + @@ -12,7 +12,7 @@ - + diff --git a/bundles/nl.esi.xtext.launch/Maven Update Version.launch b/bundles/nl.esi.xtext.launch/Maven Update Version.launch new file mode 100644 index 0000000..e038a6f --- /dev/null +++ b/bundles/nl.esi.xtext.launch/Maven Update Version.launch @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/bundles/nl.esi.xtext.launch/Maven Validate.launch b/bundles/nl.esi.xtext.launch/Maven Validate.launch new file mode 100644 index 0000000..520fede --- /dev/null +++ b/bundles/nl.esi.xtext.launch/Maven Validate.launch @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/bundles/nl.esi.xtext.lsp.generator/META-INF/MANIFEST.MF b/bundles/nl.esi.xtext.lsp.generator/META-INF/MANIFEST.MF index a7e824f..f86de4e 100644 --- a/bundles/nl.esi.xtext.lsp.generator/META-INF/MANIFEST.MF +++ b/bundles/nl.esi.xtext.lsp.generator/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: Xtext LSP Generator Bundle-SymbolicName: nl.esi.xtext.lsp.generator -Bundle-Version: 0.1.0.qualifier +Bundle-Version: 0.3.0.qualifier Export-Package: nl.esi.xtext.lsp.generator.ide.contentassist, nl.esi.xtext.lsp.generator.lezer Require-Bundle: org.eclipse.xtend.lib, diff --git a/bundles/nl.esi.xtext.lsp.server/META-INF/MANIFEST.MF b/bundles/nl.esi.xtext.lsp.server/META-INF/MANIFEST.MF index 40f1310..84838d4 100644 --- a/bundles/nl.esi.xtext.lsp.server/META-INF/MANIFEST.MF +++ b/bundles/nl.esi.xtext.lsp.server/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: Xtext LSP Server Bundle-SymbolicName: nl.esi.xtext.lsp.server -Bundle-Version: 0.1.0.qualifier +Bundle-Version: 0.3.0.qualifier Export-Package: nl.esi.xtext.lsp.client, nl.esi.xtext.lsp.impl;x-internal:=true, nl.esi.xtext.lsp.server diff --git a/bundles/nl.esi.xtext.types.ide/META-INF/MANIFEST.MF b/bundles/nl.esi.xtext.types.ide/META-INF/MANIFEST.MF index b1d84b6..01f1e80 100644 --- a/bundles/nl.esi.xtext.types.ide/META-INF/MANIFEST.MF +++ b/bundles/nl.esi.xtext.types.ide/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: Types Language IDE Bundle-Vendor: TNO-ESI -Bundle-Version: 0.1.0.qualifier +Bundle-Version: 0.3.0.qualifier Bundle-SymbolicName: nl.esi.xtext.types.ide; singleton:=true Bundle-ActivationPolicy: lazy Require-Bundle: nl.esi.xtext.types;visibility:=reexport, diff --git a/bundles/nl.esi.xtext.types.tests/META-INF/MANIFEST.MF b/bundles/nl.esi.xtext.types.tests/META-INF/MANIFEST.MF index 3a7b188..6312aad 100644 --- a/bundles/nl.esi.xtext.types.tests/META-INF/MANIFEST.MF +++ b/bundles/nl.esi.xtext.types.tests/META-INF/MANIFEST.MF @@ -3,7 +3,7 @@ Automatic-Module-Name: nl.esi.xtext.types.tests Bundle-ManifestVersion: 2 Bundle-Name: Types Lang Tests Bundle-Vendor: TNO-ESI -Bundle-Version: 0.1.0.qualifier +Bundle-Version: 0.3.0.qualifier Bundle-SymbolicName: nl.esi.xtext.types.tests;singleton:=true Bundle-ActivationPolicy: lazy Require-Bundle: org.eclipse.xtext.testing, diff --git a/bundles/nl.esi.xtext.types.ui/META-INF/MANIFEST.MF b/bundles/nl.esi.xtext.types.ui/META-INF/MANIFEST.MF index 1077bb2..ea72893 100644 --- a/bundles/nl.esi.xtext.types.ui/META-INF/MANIFEST.MF +++ b/bundles/nl.esi.xtext.types.ui/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: Types Language UI Bundle-Vendor: TNO-ESI -Bundle-Version: 0.1.0.qualifier +Bundle-Version: 0.3.0.qualifier Bundle-SymbolicName: nl.esi.xtext.types.ui; singleton:=true Bundle-ActivationPolicy: lazy Require-Bundle: nl.esi.xtext.types;visibility:=reexport, diff --git a/bundles/nl.esi.xtext.types/META-INF/MANIFEST.MF b/bundles/nl.esi.xtext.types/META-INF/MANIFEST.MF index 85b9559..8d9aae9 100644 --- a/bundles/nl.esi.xtext.types/META-INF/MANIFEST.MF +++ b/bundles/nl.esi.xtext.types/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: Types Language Core Bundle-Vendor: TNO-ESI -Bundle-Version: 0.1.0.qualifier +Bundle-Version: 0.3.0.qualifier Bundle-SymbolicName: nl.esi.xtext.types; singleton:=true Bundle-ActivationPolicy: lazy Require-Bundle: nl.esi.xtext.common.lang;visibility:=reexport, diff --git a/bundles/nl.esi.xtext.types/plugin.xml b/bundles/nl.esi.xtext.types/plugin.xml index 70aa20e..5ccb6de 100644 --- a/bundles/nl.esi.xtext.types/plugin.xml +++ b/bundles/nl.esi.xtext.types/plugin.xml @@ -12,39 +12,11 @@ --> - + - - - - - - - - - - - - - - diff --git a/bundles/nl.esi.xtext.types/pom.xml b/bundles/nl.esi.xtext.types/pom.xml index 1ab40e0..fbd52d0 100644 --- a/bundles/nl.esi.xtext.types/pom.xml +++ b/bundles/nl.esi.xtext.types/pom.xml @@ -16,7 +16,7 @@ nl.esi.xplus nl.esi.xplus.root - 0.1.0-SNAPSHOT + 0.3.0-SNAPSHOT ../../ diff --git a/bundles/nl.esi.xtext.types/schema/xplusValidator.exsd b/bundles/nl.esi.xtext.types/schema/xplusValidator.exsd index e6fd46f..1b7bbfb 100644 --- a/bundles/nl.esi.xtext.types/schema/xplusValidator.exsd +++ b/bundles/nl.esi.xtext.types/schema/xplusValidator.exsd @@ -123,7 +123,7 @@ - <extension point="nl.esi.xtext.types.commaValidator"> + <extension point="nl.esi.xtext.types.xplusValidator"> <customValidator class="nl.esi.xplus.project.dynamics.validation.InterfaceValidator" language="InterfaceDefinition"> diff --git a/bundles/nl.esi.xtext.types/src/nl/esi/xtext/types/generator/XPlusFileSystemAccess.xtend b/bundles/nl.esi.xtext.types/src/nl/esi/xtext/types/generator/XPlusFileSystemAccess.xtend index 1c38a57..9f5d441 100644 --- a/bundles/nl.esi.xtext.types/src/nl/esi/xtext/types/generator/XPlusFileSystemAccess.xtend +++ b/bundles/nl.esi.xtext.types/src/nl/esi/xtext/types/generator/XPlusFileSystemAccess.xtend @@ -25,12 +25,12 @@ class XPlusFileSystemAccess implements IFileSystemAccess { public String outputConfiguration = DEFAULT_OUTPUT String generationFolder - final public static String COMMA_OUTPUT_ID = "outputCommaGen" - final public static String COMMA_OUTPUT_FOLDER = "./xplus-gen" - public static val OutputConfiguration COMMA_OUTPUT_CONF = { - val config = new OutputConfiguration(COMMA_OUTPUT_ID) - config.outputDirectory = COMMA_OUTPUT_FOLDER - config.description = COMMA_OUTPUT_FOLDER + final public static String XPLUS_OUTPUT_ID = "outputXPlusGen" + final public static String XPLUS_OUTPUT_FOLDER = "./xplus-gen" + public static val OutputConfiguration XPLUS_OUTPUT_CONF = { + val config = new OutputConfiguration(XPLUS_OUTPUT_ID) + config.outputDirectory = XPLUS_OUTPUT_FOLDER + config.description = XPLUS_OUTPUT_FOLDER config.createOutputDirectory = true config.canClearOutputDirectory = true config.cleanUpDerivedResources = true @@ -56,7 +56,7 @@ class XPlusFileSystemAccess implements IFileSystemAccess { this.fileSystemAccess = fsa this.generationFolder = generationFolder if(xplusGen) { - setOutPutCommaGen + setOutPutXPlusGen } } @@ -98,17 +98,17 @@ class XPlusFileSystemAccess implements IFileSystemAccess { return sb.toString } - def setOutPutCommaGen() { + def setOutPutXPlusGen() { if (fileSystemAccess instanceof AbstractFileSystemAccess) { - outputConfiguration = COMMA_OUTPUT_ID + outputConfiguration = XPLUS_OUTPUT_ID val configurations = fileSystemAccess.outputConfigurations - if (!configurations.containsKey(COMMA_OUTPUT_ID)) { + if (!configurations.containsKey(XPLUS_OUTPUT_ID)) { val newConfigurations = new HashMap(configurations) - newConfigurations.put(COMMA_OUTPUT_ID, COMMA_OUTPUT_CONF) + newConfigurations.put(XPLUS_OUTPUT_ID, XPLUS_OUTPUT_CONF) fileSystemAccess.outputConfigurations = newConfigurations } } else { - generationFolder = FOLDER_UP + "comma-gen/" + generationFolder + generationFolder = FOLDER_UP + "xplus-gen/" + generationFolder } } diff --git a/bundles/nl.esi.xtext.types/src/nl/esi/xtext/types/generator/XPlusMain.xtend b/bundles/nl.esi.xtext.types/src/nl/esi/xtext/types/generator/XPlusMain.xtend index 7593ca0..c0178d2 100644 --- a/bundles/nl.esi.xtext.types/src/nl/esi/xtext/types/generator/XPlusMain.xtend +++ b/bundles/nl.esi.xtext.types/src/nl/esi/xtext/types/generator/XPlusMain.xtend @@ -41,7 +41,7 @@ class XPlusMain { static final String ERR_LOCATION_WRONG = 'Location could not be found. ' static final String INFO_GENERATION_FINISHED = 'Code generation finished.' - static final String INFO_COMMA_FINISHED = 'All XPlus Tasks are finished.' + static final String INFO_XPLUS_FINISHED = 'All XPlus Tasks are finished.' static final String INFO_SEARCHING = 'Searching for {0} ({1}) files in {2}' static final String INFO_OUTPUT = 'Output set: ' static final String INFO_STOP = 'Errors found, stopping generation.' @@ -219,7 +219,7 @@ class XPlusMain { // Configure and start the generator fileAccess.outputPath = outputdir.toString - setCommaGen(fileAccess, outputdir.toString) + setXPlusGen(fileAccess, outputdir.toString) generator.generate(resource, fileAccess, cliContext) } @@ -335,7 +335,7 @@ class XPlusMain { } System.out.println(INFO_GENERATION_FINISHED) System.out.println("") - System.out.println(INFO_COMMA_FINISHED) + System.out.println(INFO_XPLUS_FINISHED) } def Options createOptions() { @@ -467,7 +467,7 @@ class XPlusMain { // Configure and start the generator fileAccess.outputPath = outputdir - setCommaGen(fileAccess, outputdir) + setXPlusGen(fileAccess, outputdir) generator.generate(resource, fileAccess, cliContext) } @@ -488,7 +488,7 @@ class XPlusMain { var cliContext = new StepsParserContext(stepsPath.toString, contexts, outputdir) // Configure and start the generator fileAccess.outputPath = outputdir - setCommaGen(fileAccess, outputdir) + setXPlusGen(fileAccess, outputdir) generator.generate(resource, fileAccess, cliContext) } @@ -517,7 +517,7 @@ class XPlusMain { } // Configure and start the generator fileAccess.outputPath = outputdir - setCommaGen(fileAccess, outputdir) + setXPlusGen(fileAccess, outputdir) try { generator.generate(resource, fileAccess, new CmdLineContext) @@ -532,16 +532,16 @@ class XPlusMain { def cleanOutput(CommandLine cmdLine, Path outputdir) { if (cmdLine.hasOption(OPT_CLEAN)) { println("Start cleaning output directory.") - val commagendir = outputdir.parent.resolve(nl.esi.xtext.types.generator.XPlusFileSystemAccess.COMMA_OUTPUT_CONF.outputDirectory).normalize + val xplusgendir = outputdir.parent.resolve(nl.esi.xtext.types.generator.XPlusFileSystemAccess.XPLUS_OUTPUT_CONF.outputDirectory).normalize //clean src-gen if(new File(outputdir.toString).exists){ Files.walk(outputdir) .sorted(Comparator.reverseOrder()) .forEach[Files::delete(it)] } - //clean comma-gen - if(new File(commagendir.toString).exists){ - Files.walk(commagendir) + //clean xplus-gen + if(new File(xplusgendir.toString).exists){ + Files.walk(xplusgendir) .sorted(Comparator.reverseOrder()) .forEach[Files::delete(it)] } @@ -549,15 +549,15 @@ class XPlusMain { } } - def setCommaGen(JavaIoFileSystemAccess fileAccess, String outputdir) { - val commaConf = nl.esi.xtext.types.generator.XPlusFileSystemAccess.COMMA_OUTPUT_CONF - commaConf.outputDirectory = Paths.get(outputdir).parent.toString + commaConf.outputDirectory - fileAccess.outputConfigurations.put(nl.esi.xtext.types.generator.XPlusFileSystemAccess.COMMA_OUTPUT_ID, commaConf) + def setXPlusGen(JavaIoFileSystemAccess fileAccess, String outputdir) { + val xplusConf = nl.esi.xtext.types.generator.XPlusFileSystemAccess.XPLUS_OUTPUT_CONF + xplusConf.outputDirectory = Paths.get(outputdir).parent.toString + xplusConf.outputDirectory + fileAccess.outputConfigurations.put(nl.esi.xtext.types.generator.XPlusFileSystemAccess.XPLUS_OUTPUT_ID, xplusConf) } - def getCommaGen() { - val commaGen = fileAccess.outputConfigurations.get(nl.esi.xtext.types.generator.XPlusFileSystemAccess.COMMA_OUTPUT_ID) - commaGen.outputDirectory + def getXPlusGen() { + val xplusGen = fileAccess.outputConfigurations.get(nl.esi.xtext.types.generator.XPlusFileSystemAccess.XPLUS_OUTPUT_ID) + xplusGen.outputDirectory } def getJarDir() { diff --git a/bundles/nl.esi.xtext.types/src/nl/esi/xtext/types/utilities/XPlusUtilities.xtend b/bundles/nl.esi.xtext.types/src/nl/esi/xtext/types/utilities/XPlusUtilities.xtend index fdb13f4..90a6130 100644 --- a/bundles/nl.esi.xtext.types/src/nl/esi/xtext/types/utilities/XPlusUtilities.xtend +++ b/bundles/nl.esi.xtext.types/src/nl/esi/xtext/types/utilities/XPlusUtilities.xtend @@ -27,9 +27,4 @@ class XPlusUtilities { } result } - - static def commaVersion(){ - "4.0.0" - } - } \ No newline at end of file diff --git a/bundles/nl.esi.xtext.types/src/nl/esi/xtext/types/validation/TypesValidator.xtend b/bundles/nl.esi.xtext.types/src/nl/esi/xtext/types/validation/TypesValidator.xtend index 64e1c68..423b501 100644 --- a/bundles/nl.esi.xtext.types/src/nl/esi/xtext/types/validation/TypesValidator.xtend +++ b/bundles/nl.esi.xtext.types/src/nl/esi/xtext/types/validation/TypesValidator.xtend @@ -14,18 +14,18 @@ package nl.esi.xtext.types.validation import com.google.inject.Inject import java.util.Set +import nl.esi.xtext.common.lang.base.BasePackage +import nl.esi.xtext.common.lang.base.ModelContainer import nl.esi.xtext.types.BasicTypes import nl.esi.xtext.types.scoping.TypesImportUriGlobalScopeProvider import nl.esi.xtext.types.types.EnumTypeDecl +import nl.esi.xtext.types.types.GenericsTypeParam import nl.esi.xtext.types.types.MapTypeConstructor -import nl.esi.xtext.types.types.RecordFieldKind import nl.esi.xtext.types.types.RecordTypeDecl import nl.esi.xtext.types.types.SimpleTypeDecl import nl.esi.xtext.types.types.Type import nl.esi.xtext.types.types.TypesModel import nl.esi.xtext.types.types.TypesPackage -import nl.esi.xtext.common.lang.base.BasePackage -import nl.esi.xtext.common.lang.base.ModelContainer import org.eclipse.core.runtime.Platform import org.eclipse.emf.ecore.EClass import org.eclipse.emf.ecore.EValidator @@ -34,7 +34,6 @@ import org.eclipse.xtext.validation.Check import org.eclipse.xtext.validation.EValidatorRegistrar import static extension nl.esi.xtext.types.utilities.TypeUtilities.* -import nl.esi.xtext.types.types.GenericsTypeParam /** * This class contains custom validation rules. @@ -240,12 +239,12 @@ class TypesValidator extends AbstractTypesValidator { * + the chain of dependencies induced by record fields contains no cycles. * Clarification: record R1 with field A of type R2, R2 with field b of type R1 is not allowed. * Fields of vector types with base another record type should also be considered. - * In XPlus, records are treated as values. The structure mentioned above can never be created. + * In ComMA, records are treated as values. The structure mentioned above can never be created. */ /* * This methods implements the mechanism for registering third-party extensions to the - * validators of the XPlus languages. + * validators of the ComMA languages. * All languages that directly or indirectly extend Types language inherit it. */ @@ -266,15 +265,4 @@ class TypesValidator extends AbstractTypesValidator { } } } - - /** - * All fields of a record cannot be marked symbolic. - */ - @Check - def checkSymbolicField(RecordTypeDecl type) { - val allField = type.allFields - if (allField.forall[kind != RecordFieldKind::CONCRETE]) { - error('''At least 1 field must be concrete for record «type.name»''', TypesPackage.Literals.RECORD_TYPE_DECL__FIELDS) - } - } } diff --git a/features/nl.esi.xplus.feature.source/feature.xml b/features/nl.esi.xplus.feature.source/feature.xml index 6be2941..cf1c3f6 100644 --- a/features/nl.esi.xplus.feature.source/feature.xml +++ b/features/nl.esi.xplus.feature.source/feature.xml @@ -12,11 +12,11 @@ --> + license-feature-version="0.3.0.qualifier"> This feature provides reusable set of XPlus Core Domain-Specific diff --git a/features/nl.esi.xplus.feature/feature.xml b/features/nl.esi.xplus.feature/feature.xml index 45aaf34..8084dc3 100644 --- a/features/nl.esi.xplus.feature/feature.xml +++ b/features/nl.esi.xplus.feature/feature.xml @@ -13,10 +13,10 @@ + license-feature-version="0.3.0.qualifier"> This feature provides reusable set of XPlus Core Domain-Specific @@ -32,7 +32,7 @@ Languages. - + + + + + diff --git a/features/nl.esi.xplus.lsp.feature.source/.project b/features/nl.esi.xplus.lsp.feature.source/.project new file mode 100644 index 0000000..b981dab --- /dev/null +++ b/features/nl.esi.xplus.lsp.feature.source/.project @@ -0,0 +1,17 @@ + + + nl.esi.xplus.lsp.feature.source + + + + + + org.eclipse.pde.FeatureBuilder + + + + + + org.eclipse.pde.FeatureNature + + diff --git a/features/nl.esi.xplus.lsp.feature.source/.settings/org.eclipse.core.resources.prefs b/features/nl.esi.xplus.lsp.feature.source/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 0000000..99f26c0 --- /dev/null +++ b/features/nl.esi.xplus.lsp.feature.source/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,2 @@ +eclipse.preferences.version=1 +encoding/=UTF-8 diff --git a/features/nl.esi.xplus.lsp.feature.source/build.properties b/features/nl.esi.xplus.lsp.feature.source/build.properties new file mode 100644 index 0000000..739c7f6 --- /dev/null +++ b/features/nl.esi.xplus.lsp.feature.source/build.properties @@ -0,0 +1,11 @@ +# +# Copyright (c) 2024, 2026 TNO-ESI +# +# This program and the accompanying materials are made +# available under the terms of the Eclipse Public License 2.0 +# which is available at https://www.eclipse.org/legal/epl-2.0/ +# +# SPDX-License-Identifier: EPL-2.0 +# + +bin.includes = feature.xml diff --git a/features/nl.esi.xplus.lsp.feature.source/feature.xml b/features/nl.esi.xplus.lsp.feature.source/feature.xml new file mode 100644 index 0000000..7187fc2 --- /dev/null +++ b/features/nl.esi.xplus.lsp.feature.source/feature.xml @@ -0,0 +1,46 @@ + + + + + + This feature provides reusable set of XPlus Core Domain-Specific +Languages. + + + + %copyright + + + + %license + + + + + + + + + diff --git a/features/nl.esi.xplus.lsp.feature/.project b/features/nl.esi.xplus.lsp.feature/.project new file mode 100644 index 0000000..f6ddf3c --- /dev/null +++ b/features/nl.esi.xplus.lsp.feature/.project @@ -0,0 +1,17 @@ + + + nl.esi.xplus.lsp.feature + + + + + + org.eclipse.pde.FeatureBuilder + + + + + + org.eclipse.pde.FeatureNature + + diff --git a/features/nl.esi.xplus.lsp.feature/.settings/org.eclipse.core.resources.prefs b/features/nl.esi.xplus.lsp.feature/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 0000000..99f26c0 --- /dev/null +++ b/features/nl.esi.xplus.lsp.feature/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,2 @@ +eclipse.preferences.version=1 +encoding/=UTF-8 diff --git a/features/nl.esi.xplus.lsp.feature/build.properties b/features/nl.esi.xplus.lsp.feature/build.properties new file mode 100644 index 0000000..739c7f6 --- /dev/null +++ b/features/nl.esi.xplus.lsp.feature/build.properties @@ -0,0 +1,11 @@ +# +# Copyright (c) 2024, 2026 TNO-ESI +# +# This program and the accompanying materials are made +# available under the terms of the Eclipse Public License 2.0 +# which is available at https://www.eclipse.org/legal/epl-2.0/ +# +# SPDX-License-Identifier: EPL-2.0 +# + +bin.includes = feature.xml diff --git a/features/nl.esi.xplus.lsp.feature/feature.xml b/features/nl.esi.xplus.lsp.feature/feature.xml new file mode 100644 index 0000000..d1e7a13 --- /dev/null +++ b/features/nl.esi.xplus.lsp.feature/feature.xml @@ -0,0 +1,46 @@ + + + + + + This feature provides reusable set of XPlus Core Domain-Specific +Languages. + + + + %copyright + + + + %license + + + + + + + + + + + diff --git a/features/nl.esi.xplus.ui.feature.source/feature.xml b/features/nl.esi.xplus.ui.feature.source/feature.xml index 5d3d9ff..7a4a42c 100644 --- a/features/nl.esi.xplus.ui.feature.source/feature.xml +++ b/features/nl.esi.xplus.ui.feature.source/feature.xml @@ -13,10 +13,10 @@ + license-feature-version="0.3.0.qualifier"> This feature includes XPlus Core languages feature and adds the default XPlus project language and help. @@ -46,6 +46,10 @@ id="nl.esi.xtext.types.ui.source" version="0.0.0"/> + + diff --git a/features/nl.esi.xplus.ui.feature/feature.xml b/features/nl.esi.xplus.ui.feature/feature.xml index 0feba10..e2d22bf 100644 --- a/features/nl.esi.xplus.ui.feature/feature.xml +++ b/features/nl.esi.xplus.ui.feature/feature.xml @@ -13,10 +13,10 @@ + license-feature-version="0.3.0.qualifier"> This feature includes XPlus Core languages feature and adds the default XPlus project language and help. @@ -46,6 +46,10 @@ id="nl.esi.xtext.types.ui" version="0.0.0"/> + + diff --git a/pom.xml b/pom.xml index ba24a12..b0afde1 100644 --- a/pom.xml +++ b/pom.xml @@ -17,7 +17,7 @@ nl.esi.xplus nl.esi.xplus.configuration - 0.1.0-SNAPSHOT + 0.3.0-SNAPSHOT releng/nl.esi.xplus.configuration/pom.xml diff --git a/releng/nl.esi.xplus.configuration/pom.xml b/releng/nl.esi.xplus.configuration/pom.xml index ee70738..cd65434 100644 --- a/releng/nl.esi.xplus.configuration/pom.xml +++ b/releng/nl.esi.xplus.configuration/pom.xml @@ -17,7 +17,7 @@ nl.esi.xplus nl.esi.xplus.configuration - 0.1.0-SNAPSHOT + 0.3.0-SNAPSHOT pom @@ -62,9 +62,9 @@ - scm:git:git@github.com:dbera/OfflineMBT.git - scm:git:git@github.com:dbera/OfflineMBT.git - https://github.com/dbera/OfflineMBT + scm:git:git@github.com:TNO/XPlus.git + scm:git:git@github.com:TNO/XPlus.git + https://github.com/TNO/XPlus HEAD diff --git a/releng/nl.esi.xplus.license/feature.xml b/releng/nl.esi.xplus.license/feature.xml index c828cd0..269b36a 100644 --- a/releng/nl.esi.xplus.license/feature.xml +++ b/releng/nl.esi.xplus.license/feature.xml @@ -13,7 +13,7 @@ diff --git a/releng/nl.esi.xplus.standard.site/category.xml b/releng/nl.esi.xplus.standard.site/category.xml index 323e8d0..1c250cf 100644 --- a/releng/nl.esi.xplus.standard.site/category.xml +++ b/releng/nl.esi.xplus.standard.site/category.xml @@ -18,29 +18,43 @@ - + - + - + - - + + + + + - - - - + + + + + + + + + XPlus Framework - + + + XPlus Framework - LSP Support + + + - XPlus Framework - Source Code + UI Project of XPlus + diff --git a/releng/nl.esi.xplus.standard.site/pom.xml b/releng/nl.esi.xplus.standard.site/pom.xml index 1ca73fc..8263bea 100644 --- a/releng/nl.esi.xplus.standard.site/pom.xml +++ b/releng/nl.esi.xplus.standard.site/pom.xml @@ -18,7 +18,7 @@ nl.esi.xplus nl.esi.xplus.root - 0.1.0-SNAPSHOT + 0.3.0-SNAPSHOT ../../ diff --git a/releng/nl.esi.xplus.target/nl.esi.xplus.maven.target b/releng/nl.esi.xplus.target/nl.esi.xplus.maven.target index 7025d10..f5a014d 100644 --- a/releng/nl.esi.xplus.target/nl.esi.xplus.maven.target +++ b/releng/nl.esi.xplus.target/nl.esi.xplus.maven.target @@ -1,7 +1,7 @@ - + diff --git a/releng/nl.esi.xplus.target/nl.esi.xplus.target.target b/releng/nl.esi.xplus.target/nl.esi.xplus.target.target index 9ec4b93..09739c0 100644 --- a/releng/nl.esi.xplus.target/nl.esi.xplus.target.target +++ b/releng/nl.esi.xplus.target/nl.esi.xplus.target.target @@ -1,7 +1,8 @@ - + + @@ -25,7 +26,6 @@ - @@ -63,6 +63,7 @@ + @@ -71,11 +72,11 @@ - + - + @@ -86,6 +87,5 @@ - - \ No newline at end of file +