From f0453da0e554ec8d0c46274a148ac98adecd01b7 Mon Sep 17 00:00:00 2001 From: Andreas Textor Date: Fri, 20 Mar 2026 15:02:40 +0100 Subject: [PATCH 01/41] Add initial version of tree-sitter-turtle --- .../esmf/aspectmodel/resolver/Download.java | 29 +- core/esmf-tree-sitter-turtle/.gitignore | 7 + core/esmf-tree-sitter-turtle/README.md | 22 + core/esmf-tree-sitter-turtle/pom.xml | 236 ++ .../esmf/buildtime/BuildTimeException.java | 24 + .../eclipse/esmf/buildtime/DownloadZig.java | 272 ++ .../eclipse/esmf/buildtime/NativeCompile.java | 115 + .../eclipse/esmf/buildtime/ZigContext.java | 98 + .../src/main/c/include/NOTICE.md | 2 + .../src/main/c/include/jni.h | 2013 +++++++++++++++ .../src/main/c/include/linux/jawt_md.h | 60 + .../src/main/c/include/linux/jni_md.h | 64 + .../src/main/c/include/macos/jawt_md.h | 77 + .../src/main/c/include/macos/jni_md.h | 64 + .../windows/bridge/AccessBridgeCallbacks.h | 92 + .../windows/bridge/AccessBridgeCalls.h | 724 ++++++ .../windows/bridge/AccessBridgePackages.h | 2217 +++++++++++++++++ .../src/main/c/include/windows/jawt_md.h | 59 + .../src/main/c/include/windows/jni_md.h | 38 + ...e_esmf_treesitterturtle_TreeSitterTurtle.c | 24 + .../treesitterturtle/TreeSitterTurtle.java | 38 + .../src/main/js/NOTICE.md | 3 + .../src/main/js/grammar.js | 466 ++++ .../src/main/js/tree-sitter.json | 37 + .../TreeSitterTurtleTest.java | 39 + pom.xml | 1 + 26 files changed, 6812 insertions(+), 9 deletions(-) create mode 100644 core/esmf-tree-sitter-turtle/.gitignore create mode 100644 core/esmf-tree-sitter-turtle/README.md create mode 100644 core/esmf-tree-sitter-turtle/pom.xml create mode 100644 core/esmf-tree-sitter-turtle/src-buildtime/main/java/org/eclipse/esmf/buildtime/BuildTimeException.java create mode 100644 core/esmf-tree-sitter-turtle/src-buildtime/main/java/org/eclipse/esmf/buildtime/DownloadZig.java create mode 100644 core/esmf-tree-sitter-turtle/src-buildtime/main/java/org/eclipse/esmf/buildtime/NativeCompile.java create mode 100644 core/esmf-tree-sitter-turtle/src-buildtime/main/java/org/eclipse/esmf/buildtime/ZigContext.java create mode 100644 core/esmf-tree-sitter-turtle/src/main/c/include/NOTICE.md create mode 100644 core/esmf-tree-sitter-turtle/src/main/c/include/jni.h create mode 100644 core/esmf-tree-sitter-turtle/src/main/c/include/linux/jawt_md.h create mode 100644 core/esmf-tree-sitter-turtle/src/main/c/include/linux/jni_md.h create mode 100644 core/esmf-tree-sitter-turtle/src/main/c/include/macos/jawt_md.h create mode 100644 core/esmf-tree-sitter-turtle/src/main/c/include/macos/jni_md.h create mode 100755 core/esmf-tree-sitter-turtle/src/main/c/include/windows/bridge/AccessBridgeCallbacks.h create mode 100755 core/esmf-tree-sitter-turtle/src/main/c/include/windows/bridge/AccessBridgeCalls.h create mode 100755 core/esmf-tree-sitter-turtle/src/main/c/include/windows/bridge/AccessBridgePackages.h create mode 100755 core/esmf-tree-sitter-turtle/src/main/c/include/windows/jawt_md.h create mode 100755 core/esmf-tree-sitter-turtle/src/main/c/include/windows/jni_md.h create mode 100644 core/esmf-tree-sitter-turtle/src/main/c/org_eclipse_esmf_treesitterturtle_TreeSitterTurtle.c create mode 100644 core/esmf-tree-sitter-turtle/src/main/java/org/eclipse/esmf/treesitterturtle/TreeSitterTurtle.java create mode 100644 core/esmf-tree-sitter-turtle/src/main/js/NOTICE.md create mode 100644 core/esmf-tree-sitter-turtle/src/main/js/grammar.js create mode 100644 core/esmf-tree-sitter-turtle/src/main/js/tree-sitter.json create mode 100644 core/esmf-tree-sitter-turtle/src/test/java/org/eclipse/esmf/treesitterturtle/TreeSitterTurtleTest.java diff --git a/core/esmf-aspect-meta-model-java/src/main/java/org/eclipse/esmf/aspectmodel/resolver/Download.java b/core/esmf-aspect-meta-model-java/src/main/java/org/eclipse/esmf/aspectmodel/resolver/Download.java index 1392b41d7..2cd5ddc02 100644 --- a/core/esmf-aspect-meta-model-java/src/main/java/org/eclipse/esmf/aspectmodel/resolver/Download.java +++ b/core/esmf-aspect-meta-model-java/src/main/java/org/eclipse/esmf/aspectmodel/resolver/Download.java @@ -36,10 +36,19 @@ */ public class Download { private static final Logger LOG = LoggerFactory.getLogger( Download.class ); - private final ProxyConfig proxyConfig; + private final Config config; + + public record Config( + ProxyConfig proxyConfig, + Duration timeout + ) {} public Download( final ProxyConfig proxyConfig ) { - this.proxyConfig = proxyConfig; + this( new Config( proxyConfig, Duration.ofSeconds( 10 ) ) ); + } + + public Download( final Config config ) { + this.config = config; } public Download() { @@ -69,18 +78,20 @@ public HttpResponse downloadFileAsResponse( final URL fileUrl, final Map final HttpClient.Builder clientBuilder = HttpClient.newBuilder() .version( HttpClient.Version.HTTP_1_1 ) .followRedirects( HttpClient.Redirect.ALWAYS ) - .connectTimeout( Duration.ofSeconds( 10 ) ); - proxyConfig.proxy().ifPresent( clientBuilder::proxy ); - proxyConfig.authenticator().ifPresent( clientBuilder::authenticator ); + .connectTimeout( config.timeout() ); + config.proxyConfig().proxy().ifPresent( clientBuilder::proxy ); + config.proxyConfig().authenticator().ifPresent( clientBuilder::authenticator ); final HttpClient client = clientBuilder.build(); final String[] headersArray = headers.entrySet().stream() .flatMap( entry -> Stream.of( entry.getKey(), entry.getValue() ) ) .toList() .toArray( new String[0] ); - final HttpRequest request = HttpRequest.newBuilder() - .uri( fileUrl.toURI() ) - .headers( headersArray ) - .build(); + final HttpRequest.Builder builder = HttpRequest.newBuilder() + .uri( fileUrl.toURI() ); + if ( headersArray.length > 0 ) { + builder.headers( headersArray ); + } + final HttpRequest request = builder.build(); return client.send( request, HttpResponse.BodyHandlers.ofByteArray() ); } catch ( final InterruptedException | URISyntaxException | IOException exception ) { throw new ModelResolutionException( "Could not retrieve " + fileUrl, exception ); diff --git a/core/esmf-tree-sitter-turtle/.gitignore b/core/esmf-tree-sitter-turtle/.gitignore new file mode 100644 index 000000000..6f1a609c2 --- /dev/null +++ b/core/esmf-tree-sitter-turtle/.gitignore @@ -0,0 +1,7 @@ +src/main/c/parser.c +src/main/c/grammar.json +src/main/c/node-types.json +src/main/c/tree_sitter/* +src/main/js/bindings +src/main/js/js +.zig-cache diff --git a/core/esmf-tree-sitter-turtle/README.md b/core/esmf-tree-sitter-turtle/README.md new file mode 100644 index 000000000..9404eacb3 --- /dev/null +++ b/core/esmf-tree-sitter-turtle/README.md @@ -0,0 +1,22 @@ +# ESMF tree-sitter-turtle + +This module provides a parser for RDF/Turtle, to be used with the [tree-sitter Java binding](https://github.com/bonede/tree-sitter-ng). +First, native C code is generated from the grammar defined in src/main/js/grammar.js using the tree-sitter CLI. This C code is then compiled +to native libraries (.so/.dylib/.dll) for Linux/MacOS/Windows using the [Zig compiler](https://ziglang.org/); since it has built-in +cross-platform compilation capabilities. As the last step, a Java class makes the library available to Java code via JNI. +The Java code that performs the download and execution of Zig is compiled and executed during the build, but is not part of the +final module artifact. + +The build works as follows, in chronological order: + +| Maven lifecycle phase | Plugin | Maven Goal | Description | +|-----------------------|-----------------------|------------|-------------| +| initialize | frontend-maven-plugin | install-node-and-npm | Locally install node and npm | +| initialize | fronted-maven-plugin | npm | Use npm to install tree-sitter CLI locally | +| generate-sources | exec-maven-plugin | exec | Execute tree-sitter CLI to generate Turtle parser C code | +| generate-sources | maven-compiler-plugin | compile | Compile DownloadZig and NativeCompile classes (build time code) | +| process-sources | exec-maven-plugin | java | Execute DownloadZig class, to download and extract Zig release | +| compile | maven-compiler-plugin | compile | Compile regular Java binding class (TreeSitterTurtle) | +| compile | exec-maven-plugin | java | Execute NativeCompile class, to use Zig compiler to create native libraries from Turtle parser C code | + +At the end of the build, platform-specific native libs are present in target/classes/libs. diff --git a/core/esmf-tree-sitter-turtle/pom.xml b/core/esmf-tree-sitter-turtle/pom.xml new file mode 100644 index 000000000..db70c78bb --- /dev/null +++ b/core/esmf-tree-sitter-turtle/pom.xml @@ -0,0 +1,236 @@ + + + + + + org.eclipse.esmf + esmf-sdk-parent + DEV-SNAPSHOT + ../../pom.xml + + 4.0.0 + + esmf-tree-sitter-turtle + ESMF Tree Sitter Turtle + jar + + + + 1.12.1 + 0.2.1 + + 11.2.0 + 22.14.0 + 0.15.2 + 0.11 + + + 0.25.10 + tree-sitter-cli + 0.26.6 + + + ${project.build.directory}/node/node + ${project.basedir}/.zig-cache + + c + js + + + + + org.eclipse.esmf + esmf-aspect-meta-model-java + compile + + + io.github.bonede + tree-sitter + ${tree-sitter.version} + + + org.slf4j + slf4j-nop + + + + + org.junit.jupiter + junit-jupiter + test + + + org.assertj + assertj-core + test + + + + + + + + com.github.eirslett + frontend-maven-plugin + ${frontend-maven-plugin.version} + + + + + + + org.codehaus.mojo + build-helper-maven-plugin + + + add-buildtime-sources + initialize + + add-source + + + + ${build-time-sources}/main/java + + + + + + + + org.apache.maven.plugins + maven-jar-plugin + + + **/buildtime/*.class + + + + + + com.github.eirslett + frontend-maven-plugin + + + install-node-and-npm + initialize + + install-node-and-npm + + + v${node.version} + ${npm.version} + ${project.build.directory} + + + + install-tree-sitter-cli + initialize + + npm + + + ${project.build.directory} + install tree-sitter-cli@${tree-sitter-cli.version} + + + + + + + org.codehaus.mojo + exec-maven-plugin + + + tree-sitter-generate + generate-sources + + exec + + + ${node.path} + ${project.basedir}/src/main/js + + ${project.build.directory}/node_modules/tree-sitter-cli/cli.js generate grammar.js --output ../${c.source.directory} + + + + + download-zig + process-sources + + java + + + org.eclipse.esmf.buildtime.DownloadZig + + + ${zig-cache.path} + + ${zig.version} + + ${minisign.version} + + + + + native-compile + compile + + java + + + org.eclipse.esmf.buildtime.NativeCompile + + + ${zig-cache.path} + + ${zig.version} + + ${project.build.outputDirectory}/lib + + ${project.basedir}/src/main/${c.source.directory} + + + + + + + + maven-compiler-plugin + + + -h + ${project.build.directory}/generated-include + + + + + compile-build-time-code + generate-sources + + compile + + + ${build-time-sources} + + + + + + + diff --git a/core/esmf-tree-sitter-turtle/src-buildtime/main/java/org/eclipse/esmf/buildtime/BuildTimeException.java b/core/esmf-tree-sitter-turtle/src-buildtime/main/java/org/eclipse/esmf/buildtime/BuildTimeException.java new file mode 100644 index 000000000..8a05a0e09 --- /dev/null +++ b/core/esmf-tree-sitter-turtle/src-buildtime/main/java/org/eclipse/esmf/buildtime/BuildTimeException.java @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2026 Robert Bosch Manufacturing Solutions GmbH + * + * See the AUTHORS file(s) distributed with this work for additional + * information regarding authorship. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * SPDX-License-Identifier: MPL-2.0 + */ + +package org.eclipse.esmf.buildtime; + +public class BuildTimeException extends RuntimeException { + public BuildTimeException( final String message ) { + super( message ); + } + + public BuildTimeException( final Exception exception ) { + super( exception ); + } +} diff --git a/core/esmf-tree-sitter-turtle/src-buildtime/main/java/org/eclipse/esmf/buildtime/DownloadZig.java b/core/esmf-tree-sitter-turtle/src-buildtime/main/java/org/eclipse/esmf/buildtime/DownloadZig.java new file mode 100644 index 000000000..0853fc048 --- /dev/null +++ b/core/esmf-tree-sitter-turtle/src-buildtime/main/java/org/eclipse/esmf/buildtime/DownloadZig.java @@ -0,0 +1,272 @@ +/* + * Copyright (c) 2026 Robert Bosch Manufacturing Solutions GmbH + * + * See the AUTHORS file(s) distributed with this work for additional + * information regarding authorship. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * SPDX-License-Identifier: MPL-2.0 + */ + +package org.eclipse.esmf.buildtime; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URL; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.time.Duration; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; + +import org.apache.commons.compress.archivers.tar.TarArchiveEntry; +import org.apache.commons.compress.archivers.tar.TarArchiveInputStream; +import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream; +import org.apache.commons.compress.compressors.xz.XZCompressorInputStream; +import org.apache.commons.io.FileUtils; +import org.apache.commons.io.IOUtils; + +import org.eclipse.esmf.aspectmodel.resolver.Download; +import org.eclipse.esmf.aspectmodel.resolver.ProxyConfig; +import org.eclipse.esmf.aspectmodel.resolver.process.BinaryLauncher; +import org.eclipse.esmf.aspectmodel.resolver.process.ProcessLauncher; + +public class DownloadZig extends ZigContext { + private static final String ZIG_PUB_KEY = "RWSGOq2NVecA2UPNdBUZykf1CCb147pkmdtYxgb3Ti+JO/wCYvhbAb/U"; + private static final URL MIRRORS_LIST_URL = url( "https://ziglang.org/download/community-mirrors.txt" ); + + private final ProxyConfig proxyConfig; + private final String minisignVersion; + + public DownloadZig( final Path cacheLocation, final String zigVersion, final String minisignVersion ) { + super( cacheLocation, zigVersion ); + proxyConfig = ProxyConfig.detectProxySettings(); + this.minisignVersion = minisignVersion; + } + + private File getOrDownloadFile( final URL location ) { + final Path filePath = Paths.get( location.getPath() ); + final String filename = filePath.getName( filePath.getNameCount() - 1 ).toString(); + final File targetFile = cacheLocation.resolve( filename ).toFile(); + if ( targetFile.exists() ) { + return targetFile; + } + + final Download.Config config = new Download.Config( proxyConfig, Duration.ofSeconds( 3L ) ); + System.out.println( "Downloading " + location + " to " + targetFile.getName() + "..." ); + return new Download( config ).downloadFile( location, targetFile ); + } + + private String zigReleaseFileName() { + return switch ( currentOs ) { + case WINDOWS -> "zig-x86_64-windows-%s.zip".formatted( zigVersion ); + case MACOS, LINUX -> "zig-%s-%s-%s.tar.xz".formatted( currentArchitecture, currentOs, zigVersion ); + }; + } + + private String minisignReleaseFileName() { + return switch ( currentOs ) { + case WINDOWS -> "minisign-%s-win64.zip".formatted( minisignVersion ); + case MACOS -> "minisign-%s-macos.zip".formatted( minisignVersion ); + case LINUX -> "minisign-%s-linux.tar.gz".formatted( minisignVersion ); + }; + } + + private Path minisignExecutablePath() { + return switch ( currentOs ) { + case WINDOWS -> Path.of( "minisign-win64", "minisign.exe" ); + case MACOS -> Path.of( "minisign" ); + case LINUX -> Path.of( "minisign-linux", currentArchitecture.toString(), "minisign" ); + }; + } + + private List zigMirrorUrls() { + final File mirrors = getOrDownloadFile( MIRRORS_LIST_URL ); + try { + return Files.readAllLines( mirrors.toPath() ).stream().collect( Collectors.collectingAndThen( Collectors.toList(), collected -> { + Collections.shuffle( collected ); + return collected; + } ) ); + } catch ( final IOException exception ) { + throw new BuildTimeException( exception ); + } + } + + private File getOrDownloadFileFromMirror( final List mirrorUrls, final File outputFile ) { + if ( outputFile.exists() ) { + return outputFile; + } + final List triedLocations = new ArrayList<>(); + for ( final Iterator it = mirrorUrls.iterator(); it.hasNext() && !outputFile.exists(); ) { + final String mirrorUrl = it.next(); + try { + final URL url = url( mirrorUrl + "/" + outputFile.getName() ); + triedLocations.add( url.toString() ); + return getOrDownloadFile( url ); + } catch ( final Exception exception ) { + // try the next mirror + } + } + throw new BuildTimeException( "Could not retrieve " + outputFile.getName() + " from any known mirror. Tried:" + + triedLocations.stream().map( url -> " - " + url ) + .collect( Collectors.joining( "\n" ) ) ); + } + + private static URL url( final String url ) { + try { + return URI.create( url ).toURL(); + } catch ( final MalformedURLException exception ) { + throw new BuildTimeException( exception ); + } + } + + private void extractZip( final File zipFile, final Path outputDir ) { + if ( outputDir.toFile().exists() ) { + return; + } else { + mkdir( outputDir ); + } + + try ( final ZipInputStream zipInputStream = new ZipInputStream( new FileInputStream( zipFile ) ) ) { + for ( ZipEntry entry = zipInputStream.getNextEntry(); entry != null; entry = zipInputStream.getNextEntry() ) { + final Path output = outputDir.resolve( entry.getName() ); + if ( entry.isDirectory() ) { + mkdir( output ); + } else { + try ( final FileOutputStream outputStream = new FileOutputStream( output.toFile() ) ) { + IOUtils.copy( zipInputStream, outputStream ); + } + } + } + } catch ( final IOException exception ) { + throw new BuildTimeException( exception ); + } + } + + private void extractTar( final File tarFile, final Path outputDir ) { + if ( outputDir.toFile().exists() ) { + return; + } else { + mkdir( outputDir ); + } + + final String name = tarFile.getName().toLowerCase(); + if ( !name.endsWith( ".tar.gz" ) && !name.endsWith( ".tar.xz" ) && !name.endsWith( ".tgz" ) ) { + throw new BuildTimeException( "Only .tar.gz, .tgz, and .tar.xz files are supported" ); + } + + try ( final FileInputStream fileInputStream = new FileInputStream( tarFile ) ) { + final InputStream compressorInputStream = name.endsWith( ".tar.xz" ) + ? new XZCompressorInputStream( fileInputStream ) + : new GzipCompressorInputStream( fileInputStream ); + try ( final TarArchiveInputStream tarInputStream = new TarArchiveInputStream( compressorInputStream ) ) { + for ( TarArchiveEntry entry = tarInputStream.getNextEntry(); entry != null; entry = tarInputStream.getNextEntry() ) { + final Path output = outputDir.resolve( entry.getName() ); + if ( entry.isDirectory() ) { + mkdir( output ); + } else { + try ( final FileOutputStream outputStream = new FileOutputStream( output.toFile() ) ) { + IOUtils.copy( tarInputStream, outputStream ); + } + } + } + } + + } catch ( final IOException exception ) { + throw new BuildTimeException( exception ); + } + } + + private void extractArchive( final File archiveFile, final Path targetDirectory ) { + if ( archiveFile.getName().endsWith( ".zip" ) ) { + extractZip( archiveFile, targetDirectory ); + } else if ( archiveFile.getName().endsWith( ".tar.xz" ) || archiveFile.getName().endsWith( ".tar.gz" ) + || archiveFile.getName().endsWith( ".tgz" ) ) { + extractTar( archiveFile, targetDirectory ); + } else { + throw new BuildTimeException( "Do not know how to extract archive: " + archiveFile ); + } + } + + private File downloadAndExtractMinisign() { + final Path minisignDir = cacheLocation.resolve( "minisign" ); + final File minisignExe = minisignDir.resolve( minisignExecutablePath() ).toFile(); + if ( minisignExe.exists() ) { + return minisignExe; + } + final File minisignArchive = getOrDownloadFile( url( "https://github.com/jedisct1/minisign/releases/download/" + minisignVersion + + "/" + minisignReleaseFileName() ) ); + extractArchive( minisignArchive, minisignDir ); + if ( currentOs == OperatingSystem.LINUX || currentOs == OperatingSystem.MACOS ) { + minisignExe.setExecutable( true ); + } + try { + FileUtils.delete( minisignArchive ); + } catch ( final IOException exception ) { + // ignore, since it's only the cache + } + return minisignExe; + } + + private File downloadAndExtractZig( final File minisignExe ) { + final File zigExe = zigExe(); + if ( zigExe.exists() ) { + return zigExe; + } + + final List mirrors = zigMirrorUrls(); + final String fileName = zigReleaseFileName(); + final File signatureOutputFile = cacheLocation.resolve( fileName + ".minisig" ).toFile(); + final File zigReleaseArchive = getOrDownloadFileFromMirror( mirrors, cacheLocation.resolve( fileName ).toFile() ); + getOrDownloadFileFromMirror( mirrors, signatureOutputFile ); + validateZigReleaseSignature( minisignExe, zigReleaseArchive ); + + if ( !zigDir().toFile().exists() ) { + extractArchive( zigReleaseArchive, zigDir() ); + if ( currentOs == OperatingSystem.LINUX || currentOs == OperatingSystem.MACOS ) { + zigExe.setExecutable( true ); + } + } + try { + FileUtils.delete( zigReleaseArchive ); + FileUtils.delete( signatureOutputFile ); + } catch ( final IOException exception ) { + // ignore, since it's only the cache + } + return zigExe; + } + + private void validateZigReleaseSignature( final File minisignExe, final File zigReleaseArchive ) { + final ProcessLauncher.ExecutionResult minisignExecutionResult = new BinaryLauncher( minisignExe ).apply( + List.of( "-qVm", zigReleaseArchive.getAbsolutePath(), "-P", ZIG_PUB_KEY ), Optional.empty(), + zigReleaseArchive.getParentFile() ); + if ( minisignExecutionResult.exitStatus() != 0 ) { + throw new BuildTimeException( "Signature of " + zigReleaseArchive + " does not match" ); + } + } + + static void main( final String[] args ) { + final Path cacheLocation = Path.of( args[0] ); + final String zigVersion = args[1]; + final String minisignVersion = args[2]; + + final DownloadZig downloadZig = new DownloadZig( cacheLocation, zigVersion, minisignVersion ); + final File minisignExe = downloadZig.downloadAndExtractMinisign(); + downloadZig.downloadAndExtractZig( minisignExe ); + } +} diff --git a/core/esmf-tree-sitter-turtle/src-buildtime/main/java/org/eclipse/esmf/buildtime/NativeCompile.java b/core/esmf-tree-sitter-turtle/src-buildtime/main/java/org/eclipse/esmf/buildtime/NativeCompile.java new file mode 100644 index 000000000..2ec077de9 --- /dev/null +++ b/core/esmf-tree-sitter-turtle/src-buildtime/main/java/org/eclipse/esmf/buildtime/NativeCompile.java @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2026 Robert Bosch Manufacturing Solutions GmbH + * + * See the AUTHORS file(s) distributed with this work for additional + * information regarding authorship. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * SPDX-License-Identifier: MPL-2.0 + */ + +package org.eclipse.esmf.buildtime; + +import java.io.File; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +import org.eclipse.esmf.aspectmodel.resolver.process.BinaryLauncher; +import org.eclipse.esmf.aspectmodel.resolver.process.ProcessLauncher; + +public class NativeCompile extends ZigContext { + private static final String LIB_NAME = "tree-sitter-turtle"; + + private final Path libOutputDirectory; + private final Path nativeSourcesDirectory; + + public NativeCompile( final Path cacheLocation, final String zigVersion, final Path libOutputDirectory, + final Path nativeSourcesDirectory ) { + super( cacheLocation, zigVersion ); + this.libOutputDirectory = libOutputDirectory; + this.nativeSourcesDirectory = nativeSourcesDirectory; + } + + private record Target( + OperatingSystem operatingSystem, + Architecture architecture + ) { + public String getTargetName() { + return operatingSystem == OperatingSystem.LINUX + ? "%s-linux-gnu".formatted( architecture.toString() ) + : "%s-%s".formatted( architecture().toString(), operatingSystem().toString() ); + } + } + + private List getTargets() { + return List.of( + new Target( OperatingSystem.WINDOWS, Architecture.X86_64 ), + new Target( OperatingSystem.MACOS, Architecture.X86_64 ), + new Target( OperatingSystem.MACOS, Architecture.AARCH64 ), + new Target( OperatingSystem.LINUX, Architecture.X86_64 ), + new Target( OperatingSystem.LINUX, Architecture.AARCH64 ) ); + } + + private String libNameForTarget( final Target target ) { + return switch ( target.operatingSystem() ) { + case WINDOWS -> "%s-%s.dll".formatted( target.getTargetName(), LIB_NAME ); + case LINUX -> "%s-%s.so".formatted( target.getTargetName(), LIB_NAME ); + case MACOS -> "%s-%s.dylib".formatted( target.getTargetName(), LIB_NAME ); + }; + } + + private void runZig() { + final File zigExe = zigExe(); + + for ( final Target target : getTargets() ) { + final List args = new ArrayList<>(); + final File libFilename = libOutputDirectory.resolve( libNameForTarget( target ) ).toFile(); + + if ( libFilename.exists() ) { + continue; + } + args.add( "c++" ); + args.add( "-g0" ); + args.add( "-fno-sanitize=undefined" ); + args.add( "-shared" ); + args.add( "-target" ); + args.add( target.getTargetName() ); + args.add( "-I" ); + args.add( zigDir().resolve( "lib" ).resolve( "include" ).toString() ); + args.add( "-I" ); + args.add( nativeSourcesDirectory.toString() ); + args.add( "-I" ); + args.add( nativeSourcesDirectory.resolve( "include" ).toString() ); + args.add( "-I" ); + args.add( nativeSourcesDirectory.resolve( "include" ).resolve( currentOs.toString() ).toString() ); + args.add( "-o" ); + args.add( libFilename.getAbsolutePath() ); + args.add( nativeSourcesDirectory.resolve( "parser.c" ).toString() ); + args.add( nativeSourcesDirectory.resolve( "org_eclipse_esmf_treesitterturtle_TreeSitterTurtle.c" ).toString() ); + + System.out.println( zigExe().getAbsolutePath() + " " + String.join( " ", args ) ); + mkdir( libOutputDirectory ); + final ProcessLauncher.ExecutionResult zigExecutionResult = + new BinaryLauncher( zigExe ).apply( args, Optional.empty(), libOutputDirectory.toFile() ); + if ( zigExecutionResult.exitStatus() != 0 ) { + System.err.println( zigExecutionResult.stderr() ); + throw new BuildTimeException( "Compilation of native lib failed" ); + } + System.out.println( "Native lib compiled: " + libFilename.getAbsolutePath() ); + } + } + + static void main( final String[] args ) { + final Path cacheLocation = Path.of( args[0] ); + final String zigVersion = args[1]; + final Path libOutputDirectory = Path.of( args[2] ); + final Path nativeSourcesDirectory = Path.of( args[3] ); + final NativeCompile nativeCompile = new NativeCompile( cacheLocation, zigVersion, libOutputDirectory, nativeSourcesDirectory ); + nativeCompile.runZig(); + } +} diff --git a/core/esmf-tree-sitter-turtle/src-buildtime/main/java/org/eclipse/esmf/buildtime/ZigContext.java b/core/esmf-tree-sitter-turtle/src-buildtime/main/java/org/eclipse/esmf/buildtime/ZigContext.java new file mode 100644 index 000000000..381cab29f --- /dev/null +++ b/core/esmf-tree-sitter-turtle/src-buildtime/main/java/org/eclipse/esmf/buildtime/ZigContext.java @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2026 Robert Bosch Manufacturing Solutions GmbH + * + * See the AUTHORS file(s) distributed with this work for additional + * information regarding authorship. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * SPDX-License-Identifier: MPL-2.0 + */ + +package org.eclipse.esmf.buildtime; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; + +import org.apache.commons.lang3.ArchUtils; +import org.apache.commons.lang3.SystemUtils; +import org.apache.commons.lang3.arch.Processor; + +public class ZigContext { + protected final OperatingSystem currentOs; + protected final Architecture currentArchitecture; + protected final Path cacheLocation; + protected final String zigVersion; + + protected enum OperatingSystem { + WINDOWS, MACOS, LINUX; + + @Override + public String toString() { + return super.toString().toLowerCase(); + } + } + + protected enum Architecture { + X86_64, AARCH64; + + @Override + public String toString() { + return super.toString().toLowerCase(); + } + } + + protected void mkdir( final Path path ) { + try { + Files.createDirectories( path ); + } catch ( final IOException exception ) { + throw new BuildTimeException( exception ); + } + } + + + public ZigContext( final Path cacheLocation, final String zigVersion ) { + this.cacheLocation = cacheLocation; + this.zigVersion = zigVersion; + + final Processor processor = ArchUtils.getProcessor(); + if ( processor.isX86() && processor.is64Bit() ) { + currentArchitecture = Architecture.X86_64; + } else if ( processor.isAarch64() && processor.is64Bit() ) { + currentArchitecture = Architecture.AARCH64; + } else { + throw new BuildTimeException( "Unsupported architecture: " + processor.getType().getLabel() + + "/" + processor.getArch().getLabel() ); + } + + if ( SystemUtils.IS_OS_WINDOWS ) { + currentOs = OperatingSystem.WINDOWS; + if ( !processor.isX86() ) { + throw new BuildTimeException( "Unsupported architecture: " + processor.getType().getLabel() + + "/" + processor.getArch().getLabel() ); + } + } else if ( SystemUtils.IS_OS_MAC ) { + currentOs = OperatingSystem.MACOS; + } else if ( SystemUtils.IS_OS_LINUX ) { + currentOs = OperatingSystem.LINUX; + } else { + throw new BuildTimeException( "Unsupported operating system: " + SystemUtils.OS_NAME ); + } + } + + protected Path zigDir() { + return cacheLocation.resolve( "zig" ); + } + + protected File zigExe() { + final Path zigExecutablePath = switch ( currentOs ) { + case WINDOWS -> Path.of( "zig-x86_64-windows-" + zigVersion, "zig.exe" ); + case MACOS, LINUX -> Path.of( "zig-%s-%s-%s".formatted( currentArchitecture, currentOs, zigVersion ), "zig" ); + }; + return zigDir().resolve( zigExecutablePath ).toFile(); + } +} diff --git a/core/esmf-tree-sitter-turtle/src/main/c/include/NOTICE.md b/core/esmf-tree-sitter-turtle/src/main/c/include/NOTICE.md new file mode 100644 index 000000000..4811eceea --- /dev/null +++ b/core/esmf-tree-sitter-turtle/src/main/c/include/NOTICE.md @@ -0,0 +1,2 @@ +Header files that adapted from OpenJDK. +These files are required during JNI compilation but will not be part of the resulting compiled file. diff --git a/core/esmf-tree-sitter-turtle/src/main/c/include/jni.h b/core/esmf-tree-sitter-turtle/src/main/c/include/jni.h new file mode 100644 index 000000000..1a31c38b3 --- /dev/null +++ b/core/esmf-tree-sitter-turtle/src/main/c/include/jni.h @@ -0,0 +1,2013 @@ +/* + * Copyright (c) 1996, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * We used part of Netscape's Java Runtime Interface (JRI) as the starting + * point of our design and implementation. + */ + +/****************************************************************************** + * Java Runtime Interface + * Copyright (c) 1996 Netscape Communications Corporation. All rights reserved. + *****************************************************************************/ + +#ifndef _JAVASOFT_JNI_H_ +#define _JAVASOFT_JNI_H_ + +#include +#include + +/* jni_md.h contains the machine-dependent typedefs for jbyte, jint + and jlong */ + +#include "jni_md.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define JNICALL + +/* + * JNI Types + */ + +#ifndef JNI_TYPES_ALREADY_DEFINED_IN_JNI_MD_H + +typedef unsigned char jboolean; +typedef unsigned short jchar; +typedef short jshort; +typedef float jfloat; +typedef double jdouble; + +typedef jint jsize; + +#ifdef __cplusplus + +class _jobject {}; +class _jclass : public _jobject {}; +class _jthrowable : public _jobject {}; +class _jstring : public _jobject {}; +class _jarray : public _jobject {}; +class _jbooleanArray : public _jarray {}; +class _jbyteArray : public _jarray {}; +class _jcharArray : public _jarray {}; +class _jshortArray : public _jarray {}; +class _jintArray : public _jarray {}; +class _jlongArray : public _jarray {}; +class _jfloatArray : public _jarray {}; +class _jdoubleArray : public _jarray {}; +class _jobjectArray : public _jarray {}; + +typedef _jobject *jobject; +typedef _jclass *jclass; +typedef _jthrowable *jthrowable; +typedef _jstring *jstring; +typedef _jarray *jarray; +typedef _jbooleanArray *jbooleanArray; +typedef _jbyteArray *jbyteArray; +typedef _jcharArray *jcharArray; +typedef _jshortArray *jshortArray; +typedef _jintArray *jintArray; +typedef _jlongArray *jlongArray; +typedef _jfloatArray *jfloatArray; +typedef _jdoubleArray *jdoubleArray; +typedef _jobjectArray *jobjectArray; + +#else + +struct _jobject; + +typedef struct _jobject *jobject; +typedef jobject jclass; +typedef jobject jthrowable; +typedef jobject jstring; +typedef jobject jarray; +typedef jarray jbooleanArray; +typedef jarray jbyteArray; +typedef jarray jcharArray; +typedef jarray jshortArray; +typedef jarray jintArray; +typedef jarray jlongArray; +typedef jarray jfloatArray; +typedef jarray jdoubleArray; +typedef jarray jobjectArray; + +#endif + +typedef jobject jweak; + +typedef union jvalue { + jboolean z; + jbyte b; + jchar c; + jshort s; + jint i; + jlong j; + jfloat f; + jdouble d; + jobject l; +} jvalue; + +struct _jfieldID; +typedef struct _jfieldID *jfieldID; + +struct _jmethodID; +typedef struct _jmethodID *jmethodID; + +/* Return values from jobjectRefType */ +typedef enum _jobjectType { + JNIInvalidRefType = 0, + JNILocalRefType = 1, + JNIGlobalRefType = 2, + JNIWeakGlobalRefType = 3 +} jobjectRefType; + + +#endif /* JNI_TYPES_ALREADY_DEFINED_IN_JNI_MD_H */ + +/* + * jboolean constants + */ + +#define JNI_FALSE 0 +#define JNI_TRUE 1 + +/* + * possible return values for JNI functions. + */ + +#define JNI_OK 0 /* success */ +#define JNI_ERR (-1) /* unknown error */ +#define JNI_EDETACHED (-2) /* thread detached from the VM */ +#define JNI_EVERSION (-3) /* JNI version error */ +#define JNI_ENOMEM (-4) /* not enough memory */ +#define JNI_EEXIST (-5) /* VM already created */ +#define JNI_EINVAL (-6) /* invalid arguments */ + +/* + * used in ReleaseScalarArrayElements + */ + +#define JNI_COMMIT 1 +#define JNI_ABORT 2 + +/* + * used in RegisterNatives to describe native method name, signature, + * and function pointer. + */ + +typedef struct { + char *name; + char *signature; + void *fnPtr; +} JNINativeMethod; + +/* + * JNI Native Method Interface. + */ + +struct JNINativeInterface_; + +struct JNIEnv_; + +#ifdef __cplusplus +typedef JNIEnv_ JNIEnv; +#else +typedef const struct JNINativeInterface_ *JNIEnv; +#endif + +/* + * JNI Invocation Interface. + */ + +struct JNIInvokeInterface_; + +struct JavaVM_; + +#ifdef __cplusplus +typedef JavaVM_ JavaVM; +#else +typedef const struct JNIInvokeInterface_ *JavaVM; +#endif + +struct JNINativeInterface_ { + void *reserved0; + void *reserved1; + void *reserved2; + + void *reserved3; + jint (JNICALL *GetVersion)(JNIEnv *env); + + jclass (JNICALL *DefineClass) + (JNIEnv *env, const char *name, jobject loader, const jbyte *buf, + jsize len); + jclass (JNICALL *FindClass) + (JNIEnv *env, const char *name); + + jmethodID (JNICALL *FromReflectedMethod) + (JNIEnv *env, jobject method); + jfieldID (JNICALL *FromReflectedField) + (JNIEnv *env, jobject field); + + jobject (JNICALL *ToReflectedMethod) + (JNIEnv *env, jclass cls, jmethodID methodID, jboolean isStatic); + + jclass (JNICALL *GetSuperclass) + (JNIEnv *env, jclass sub); + jboolean (JNICALL *IsAssignableFrom) + (JNIEnv *env, jclass sub, jclass sup); + + jobject (JNICALL *ToReflectedField) + (JNIEnv *env, jclass cls, jfieldID fieldID, jboolean isStatic); + + jint (JNICALL *Throw) + (JNIEnv *env, jthrowable obj); + jint (JNICALL *ThrowNew) + (JNIEnv *env, jclass clazz, const char *msg); + jthrowable (JNICALL *ExceptionOccurred) + (JNIEnv *env); + void (JNICALL *ExceptionDescribe) + (JNIEnv *env); + void (JNICALL *ExceptionClear) + (JNIEnv *env); + void (JNICALL *FatalError) + (JNIEnv *env, const char *msg); + + jint (JNICALL *PushLocalFrame) + (JNIEnv *env, jint capacity); + jobject (JNICALL *PopLocalFrame) + (JNIEnv *env, jobject result); + + jobject (JNICALL *NewGlobalRef) + (JNIEnv *env, jobject lobj); + void (JNICALL *DeleteGlobalRef) + (JNIEnv *env, jobject gref); + void (JNICALL *DeleteLocalRef) + (JNIEnv *env, jobject obj); + jboolean (JNICALL *IsSameObject) + (JNIEnv *env, jobject obj1, jobject obj2); + jobject (JNICALL *NewLocalRef) + (JNIEnv *env, jobject ref); + jint (JNICALL *EnsureLocalCapacity) + (JNIEnv *env, jint capacity); + + jobject (JNICALL *AllocObject) + (JNIEnv *env, jclass clazz); + jobject (JNICALL *NewObject) + (JNIEnv *env, jclass clazz, jmethodID methodID, ...); + jobject (JNICALL *NewObjectV) + (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args); + jobject (JNICALL *NewObjectA) + (JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args); + + jclass (JNICALL *GetObjectClass) + (JNIEnv *env, jobject obj); + jboolean (JNICALL *IsInstanceOf) + (JNIEnv *env, jobject obj, jclass clazz); + + jmethodID (JNICALL *GetMethodID) + (JNIEnv *env, jclass clazz, const char *name, const char *sig); + + jobject (JNICALL *CallObjectMethod) + (JNIEnv *env, jobject obj, jmethodID methodID, ...); + jobject (JNICALL *CallObjectMethodV) + (JNIEnv *env, jobject obj, jmethodID methodID, va_list args); + jobject (JNICALL *CallObjectMethodA) + (JNIEnv *env, jobject obj, jmethodID methodID, const jvalue * args); + + jboolean (JNICALL *CallBooleanMethod) + (JNIEnv *env, jobject obj, jmethodID methodID, ...); + jboolean (JNICALL *CallBooleanMethodV) + (JNIEnv *env, jobject obj, jmethodID methodID, va_list args); + jboolean (JNICALL *CallBooleanMethodA) + (JNIEnv *env, jobject obj, jmethodID methodID, const jvalue * args); + + jbyte (JNICALL *CallByteMethod) + (JNIEnv *env, jobject obj, jmethodID methodID, ...); + jbyte (JNICALL *CallByteMethodV) + (JNIEnv *env, jobject obj, jmethodID methodID, va_list args); + jbyte (JNICALL *CallByteMethodA) + (JNIEnv *env, jobject obj, jmethodID methodID, const jvalue *args); + + jchar (JNICALL *CallCharMethod) + (JNIEnv *env, jobject obj, jmethodID methodID, ...); + jchar (JNICALL *CallCharMethodV) + (JNIEnv *env, jobject obj, jmethodID methodID, va_list args); + jchar (JNICALL *CallCharMethodA) + (JNIEnv *env, jobject obj, jmethodID methodID, const jvalue *args); + + jshort (JNICALL *CallShortMethod) + (JNIEnv *env, jobject obj, jmethodID methodID, ...); + jshort (JNICALL *CallShortMethodV) + (JNIEnv *env, jobject obj, jmethodID methodID, va_list args); + jshort (JNICALL *CallShortMethodA) + (JNIEnv *env, jobject obj, jmethodID methodID, const jvalue *args); + + jint (JNICALL *CallIntMethod) + (JNIEnv *env, jobject obj, jmethodID methodID, ...); + jint (JNICALL *CallIntMethodV) + (JNIEnv *env, jobject obj, jmethodID methodID, va_list args); + jint (JNICALL *CallIntMethodA) + (JNIEnv *env, jobject obj, jmethodID methodID, const jvalue *args); + + jlong (JNICALL *CallLongMethod) + (JNIEnv *env, jobject obj, jmethodID methodID, ...); + jlong (JNICALL *CallLongMethodV) + (JNIEnv *env, jobject obj, jmethodID methodID, va_list args); + jlong (JNICALL *CallLongMethodA) + (JNIEnv *env, jobject obj, jmethodID methodID, const jvalue *args); + + jfloat (JNICALL *CallFloatMethod) + (JNIEnv *env, jobject obj, jmethodID methodID, ...); + jfloat (JNICALL *CallFloatMethodV) + (JNIEnv *env, jobject obj, jmethodID methodID, va_list args); + jfloat (JNICALL *CallFloatMethodA) + (JNIEnv *env, jobject obj, jmethodID methodID, const jvalue *args); + + jdouble (JNICALL *CallDoubleMethod) + (JNIEnv *env, jobject obj, jmethodID methodID, ...); + jdouble (JNICALL *CallDoubleMethodV) + (JNIEnv *env, jobject obj, jmethodID methodID, va_list args); + jdouble (JNICALL *CallDoubleMethodA) + (JNIEnv *env, jobject obj, jmethodID methodID, const jvalue *args); + + void (JNICALL *CallVoidMethod) + (JNIEnv *env, jobject obj, jmethodID methodID, ...); + void (JNICALL *CallVoidMethodV) + (JNIEnv *env, jobject obj, jmethodID methodID, va_list args); + void (JNICALL *CallVoidMethodA) + (JNIEnv *env, jobject obj, jmethodID methodID, const jvalue * args); + + jobject (JNICALL *CallNonvirtualObjectMethod) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...); + jobject (JNICALL *CallNonvirtualObjectMethodV) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, + va_list args); + jobject (JNICALL *CallNonvirtualObjectMethodA) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, + const jvalue * args); + + jboolean (JNICALL *CallNonvirtualBooleanMethod) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...); + jboolean (JNICALL *CallNonvirtualBooleanMethodV) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, + va_list args); + jboolean (JNICALL *CallNonvirtualBooleanMethodA) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, + const jvalue * args); + + jbyte (JNICALL *CallNonvirtualByteMethod) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...); + jbyte (JNICALL *CallNonvirtualByteMethodV) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, + va_list args); + jbyte (JNICALL *CallNonvirtualByteMethodA) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, + const jvalue *args); + + jchar (JNICALL *CallNonvirtualCharMethod) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...); + jchar (JNICALL *CallNonvirtualCharMethodV) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, + va_list args); + jchar (JNICALL *CallNonvirtualCharMethodA) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, + const jvalue *args); + + jshort (JNICALL *CallNonvirtualShortMethod) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...); + jshort (JNICALL *CallNonvirtualShortMethodV) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, + va_list args); + jshort (JNICALL *CallNonvirtualShortMethodA) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, + const jvalue *args); + + jint (JNICALL *CallNonvirtualIntMethod) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...); + jint (JNICALL *CallNonvirtualIntMethodV) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, + va_list args); + jint (JNICALL *CallNonvirtualIntMethodA) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, + const jvalue *args); + + jlong (JNICALL *CallNonvirtualLongMethod) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...); + jlong (JNICALL *CallNonvirtualLongMethodV) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, + va_list args); + jlong (JNICALL *CallNonvirtualLongMethodA) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, + const jvalue *args); + + jfloat (JNICALL *CallNonvirtualFloatMethod) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...); + jfloat (JNICALL *CallNonvirtualFloatMethodV) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, + va_list args); + jfloat (JNICALL *CallNonvirtualFloatMethodA) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, + const jvalue *args); + + jdouble (JNICALL *CallNonvirtualDoubleMethod) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...); + jdouble (JNICALL *CallNonvirtualDoubleMethodV) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, + va_list args); + jdouble (JNICALL *CallNonvirtualDoubleMethodA) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, + const jvalue *args); + + void (JNICALL *CallNonvirtualVoidMethod) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...); + void (JNICALL *CallNonvirtualVoidMethodV) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, + va_list args); + void (JNICALL *CallNonvirtualVoidMethodA) + (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, + const jvalue * args); + + jfieldID (JNICALL *GetFieldID) + (JNIEnv *env, jclass clazz, const char *name, const char *sig); + + jobject (JNICALL *GetObjectField) + (JNIEnv *env, jobject obj, jfieldID fieldID); + jboolean (JNICALL *GetBooleanField) + (JNIEnv *env, jobject obj, jfieldID fieldID); + jbyte (JNICALL *GetByteField) + (JNIEnv *env, jobject obj, jfieldID fieldID); + jchar (JNICALL *GetCharField) + (JNIEnv *env, jobject obj, jfieldID fieldID); + jshort (JNICALL *GetShortField) + (JNIEnv *env, jobject obj, jfieldID fieldID); + jint (JNICALL *GetIntField) + (JNIEnv *env, jobject obj, jfieldID fieldID); + jlong (JNICALL *GetLongField) + (JNIEnv *env, jobject obj, jfieldID fieldID); + jfloat (JNICALL *GetFloatField) + (JNIEnv *env, jobject obj, jfieldID fieldID); + jdouble (JNICALL *GetDoubleField) + (JNIEnv *env, jobject obj, jfieldID fieldID); + + void (JNICALL *SetObjectField) + (JNIEnv *env, jobject obj, jfieldID fieldID, jobject val); + void (JNICALL *SetBooleanField) + (JNIEnv *env, jobject obj, jfieldID fieldID, jboolean val); + void (JNICALL *SetByteField) + (JNIEnv *env, jobject obj, jfieldID fieldID, jbyte val); + void (JNICALL *SetCharField) + (JNIEnv *env, jobject obj, jfieldID fieldID, jchar val); + void (JNICALL *SetShortField) + (JNIEnv *env, jobject obj, jfieldID fieldID, jshort val); + void (JNICALL *SetIntField) + (JNIEnv *env, jobject obj, jfieldID fieldID, jint val); + void (JNICALL *SetLongField) + (JNIEnv *env, jobject obj, jfieldID fieldID, jlong val); + void (JNICALL *SetFloatField) + (JNIEnv *env, jobject obj, jfieldID fieldID, jfloat val); + void (JNICALL *SetDoubleField) + (JNIEnv *env, jobject obj, jfieldID fieldID, jdouble val); + + jmethodID (JNICALL *GetStaticMethodID) + (JNIEnv *env, jclass clazz, const char *name, const char *sig); + + jobject (JNICALL *CallStaticObjectMethod) + (JNIEnv *env, jclass clazz, jmethodID methodID, ...); + jobject (JNICALL *CallStaticObjectMethodV) + (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args); + jobject (JNICALL *CallStaticObjectMethodA) + (JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args); + + jboolean (JNICALL *CallStaticBooleanMethod) + (JNIEnv *env, jclass clazz, jmethodID methodID, ...); + jboolean (JNICALL *CallStaticBooleanMethodV) + (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args); + jboolean (JNICALL *CallStaticBooleanMethodA) + (JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args); + + jbyte (JNICALL *CallStaticByteMethod) + (JNIEnv *env, jclass clazz, jmethodID methodID, ...); + jbyte (JNICALL *CallStaticByteMethodV) + (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args); + jbyte (JNICALL *CallStaticByteMethodA) + (JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args); + + jchar (JNICALL *CallStaticCharMethod) + (JNIEnv *env, jclass clazz, jmethodID methodID, ...); + jchar (JNICALL *CallStaticCharMethodV) + (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args); + jchar (JNICALL *CallStaticCharMethodA) + (JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args); + + jshort (JNICALL *CallStaticShortMethod) + (JNIEnv *env, jclass clazz, jmethodID methodID, ...); + jshort (JNICALL *CallStaticShortMethodV) + (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args); + jshort (JNICALL *CallStaticShortMethodA) + (JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args); + + jint (JNICALL *CallStaticIntMethod) + (JNIEnv *env, jclass clazz, jmethodID methodID, ...); + jint (JNICALL *CallStaticIntMethodV) + (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args); + jint (JNICALL *CallStaticIntMethodA) + (JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args); + + jlong (JNICALL *CallStaticLongMethod) + (JNIEnv *env, jclass clazz, jmethodID methodID, ...); + jlong (JNICALL *CallStaticLongMethodV) + (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args); + jlong (JNICALL *CallStaticLongMethodA) + (JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args); + + jfloat (JNICALL *CallStaticFloatMethod) + (JNIEnv *env, jclass clazz, jmethodID methodID, ...); + jfloat (JNICALL *CallStaticFloatMethodV) + (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args); + jfloat (JNICALL *CallStaticFloatMethodA) + (JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args); + + jdouble (JNICALL *CallStaticDoubleMethod) + (JNIEnv *env, jclass clazz, jmethodID methodID, ...); + jdouble (JNICALL *CallStaticDoubleMethodV) + (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args); + jdouble (JNICALL *CallStaticDoubleMethodA) + (JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args); + + void (JNICALL *CallStaticVoidMethod) + (JNIEnv *env, jclass cls, jmethodID methodID, ...); + void (JNICALL *CallStaticVoidMethodV) + (JNIEnv *env, jclass cls, jmethodID methodID, va_list args); + void (JNICALL *CallStaticVoidMethodA) + (JNIEnv *env, jclass cls, jmethodID methodID, const jvalue * args); + + jfieldID (JNICALL *GetStaticFieldID) + (JNIEnv *env, jclass clazz, const char *name, const char *sig); + jobject (JNICALL *GetStaticObjectField) + (JNIEnv *env, jclass clazz, jfieldID fieldID); + jboolean (JNICALL *GetStaticBooleanField) + (JNIEnv *env, jclass clazz, jfieldID fieldID); + jbyte (JNICALL *GetStaticByteField) + (JNIEnv *env, jclass clazz, jfieldID fieldID); + jchar (JNICALL *GetStaticCharField) + (JNIEnv *env, jclass clazz, jfieldID fieldID); + jshort (JNICALL *GetStaticShortField) + (JNIEnv *env, jclass clazz, jfieldID fieldID); + jint (JNICALL *GetStaticIntField) + (JNIEnv *env, jclass clazz, jfieldID fieldID); + jlong (JNICALL *GetStaticLongField) + (JNIEnv *env, jclass clazz, jfieldID fieldID); + jfloat (JNICALL *GetStaticFloatField) + (JNIEnv *env, jclass clazz, jfieldID fieldID); + jdouble (JNICALL *GetStaticDoubleField) + (JNIEnv *env, jclass clazz, jfieldID fieldID); + + void (JNICALL *SetStaticObjectField) + (JNIEnv *env, jclass clazz, jfieldID fieldID, jobject value); + void (JNICALL *SetStaticBooleanField) + (JNIEnv *env, jclass clazz, jfieldID fieldID, jboolean value); + void (JNICALL *SetStaticByteField) + (JNIEnv *env, jclass clazz, jfieldID fieldID, jbyte value); + void (JNICALL *SetStaticCharField) + (JNIEnv *env, jclass clazz, jfieldID fieldID, jchar value); + void (JNICALL *SetStaticShortField) + (JNIEnv *env, jclass clazz, jfieldID fieldID, jshort value); + void (JNICALL *SetStaticIntField) + (JNIEnv *env, jclass clazz, jfieldID fieldID, jint value); + void (JNICALL *SetStaticLongField) + (JNIEnv *env, jclass clazz, jfieldID fieldID, jlong value); + void (JNICALL *SetStaticFloatField) + (JNIEnv *env, jclass clazz, jfieldID fieldID, jfloat value); + void (JNICALL *SetStaticDoubleField) + (JNIEnv *env, jclass clazz, jfieldID fieldID, jdouble value); + + jstring (JNICALL *NewString) + (JNIEnv *env, const jchar *unicode, jsize len); + jsize (JNICALL *GetStringLength) + (JNIEnv *env, jstring str); + const jchar *(JNICALL *GetStringChars) + (JNIEnv *env, jstring str, jboolean *isCopy); + void (JNICALL *ReleaseStringChars) + (JNIEnv *env, jstring str, const jchar *chars); + + jstring (JNICALL *NewStringUTF) + (JNIEnv *env, const char *utf); + jsize (JNICALL *GetStringUTFLength) + (JNIEnv *env, jstring str); + const char* (JNICALL *GetStringUTFChars) + (JNIEnv *env, jstring str, jboolean *isCopy); + void (JNICALL *ReleaseStringUTFChars) + (JNIEnv *env, jstring str, const char* chars); + + + jsize (JNICALL *GetArrayLength) + (JNIEnv *env, jarray array); + + jobjectArray (JNICALL *NewObjectArray) + (JNIEnv *env, jsize len, jclass clazz, jobject init); + jobject (JNICALL *GetObjectArrayElement) + (JNIEnv *env, jobjectArray array, jsize index); + void (JNICALL *SetObjectArrayElement) + (JNIEnv *env, jobjectArray array, jsize index, jobject val); + + jbooleanArray (JNICALL *NewBooleanArray) + (JNIEnv *env, jsize len); + jbyteArray (JNICALL *NewByteArray) + (JNIEnv *env, jsize len); + jcharArray (JNICALL *NewCharArray) + (JNIEnv *env, jsize len); + jshortArray (JNICALL *NewShortArray) + (JNIEnv *env, jsize len); + jintArray (JNICALL *NewIntArray) + (JNIEnv *env, jsize len); + jlongArray (JNICALL *NewLongArray) + (JNIEnv *env, jsize len); + jfloatArray (JNICALL *NewFloatArray) + (JNIEnv *env, jsize len); + jdoubleArray (JNICALL *NewDoubleArray) + (JNIEnv *env, jsize len); + + jboolean * (JNICALL *GetBooleanArrayElements) + (JNIEnv *env, jbooleanArray array, jboolean *isCopy); + jbyte * (JNICALL *GetByteArrayElements) + (JNIEnv *env, jbyteArray array, jboolean *isCopy); + jchar * (JNICALL *GetCharArrayElements) + (JNIEnv *env, jcharArray array, jboolean *isCopy); + jshort * (JNICALL *GetShortArrayElements) + (JNIEnv *env, jshortArray array, jboolean *isCopy); + jint * (JNICALL *GetIntArrayElements) + (JNIEnv *env, jintArray array, jboolean *isCopy); + jlong * (JNICALL *GetLongArrayElements) + (JNIEnv *env, jlongArray array, jboolean *isCopy); + jfloat * (JNICALL *GetFloatArrayElements) + (JNIEnv *env, jfloatArray array, jboolean *isCopy); + jdouble * (JNICALL *GetDoubleArrayElements) + (JNIEnv *env, jdoubleArray array, jboolean *isCopy); + + void (JNICALL *ReleaseBooleanArrayElements) + (JNIEnv *env, jbooleanArray array, jboolean *elems, jint mode); + void (JNICALL *ReleaseByteArrayElements) + (JNIEnv *env, jbyteArray array, jbyte *elems, jint mode); + void (JNICALL *ReleaseCharArrayElements) + (JNIEnv *env, jcharArray array, jchar *elems, jint mode); + void (JNICALL *ReleaseShortArrayElements) + (JNIEnv *env, jshortArray array, jshort *elems, jint mode); + void (JNICALL *ReleaseIntArrayElements) + (JNIEnv *env, jintArray array, jint *elems, jint mode); + void (JNICALL *ReleaseLongArrayElements) + (JNIEnv *env, jlongArray array, jlong *elems, jint mode); + void (JNICALL *ReleaseFloatArrayElements) + (JNIEnv *env, jfloatArray array, jfloat *elems, jint mode); + void (JNICALL *ReleaseDoubleArrayElements) + (JNIEnv *env, jdoubleArray array, jdouble *elems, jint mode); + + void (JNICALL *GetBooleanArrayRegion) + (JNIEnv *env, jbooleanArray array, jsize start, jsize l, jboolean *buf); + void (JNICALL *GetByteArrayRegion) + (JNIEnv *env, jbyteArray array, jsize start, jsize len, jbyte *buf); + void (JNICALL *GetCharArrayRegion) + (JNIEnv *env, jcharArray array, jsize start, jsize len, jchar *buf); + void (JNICALL *GetShortArrayRegion) + (JNIEnv *env, jshortArray array, jsize start, jsize len, jshort *buf); + void (JNICALL *GetIntArrayRegion) + (JNIEnv *env, jintArray array, jsize start, jsize len, jint *buf); + void (JNICALL *GetLongArrayRegion) + (JNIEnv *env, jlongArray array, jsize start, jsize len, jlong *buf); + void (JNICALL *GetFloatArrayRegion) + (JNIEnv *env, jfloatArray array, jsize start, jsize len, jfloat *buf); + void (JNICALL *GetDoubleArrayRegion) + (JNIEnv *env, jdoubleArray array, jsize start, jsize len, jdouble *buf); + + void (JNICALL *SetBooleanArrayRegion) + (JNIEnv *env, jbooleanArray array, jsize start, jsize l, const jboolean *buf); + void (JNICALL *SetByteArrayRegion) + (JNIEnv *env, jbyteArray array, jsize start, jsize len, const jbyte *buf); + void (JNICALL *SetCharArrayRegion) + (JNIEnv *env, jcharArray array, jsize start, jsize len, const jchar *buf); + void (JNICALL *SetShortArrayRegion) + (JNIEnv *env, jshortArray array, jsize start, jsize len, const jshort *buf); + void (JNICALL *SetIntArrayRegion) + (JNIEnv *env, jintArray array, jsize start, jsize len, const jint *buf); + void (JNICALL *SetLongArrayRegion) + (JNIEnv *env, jlongArray array, jsize start, jsize len, const jlong *buf); + void (JNICALL *SetFloatArrayRegion) + (JNIEnv *env, jfloatArray array, jsize start, jsize len, const jfloat *buf); + void (JNICALL *SetDoubleArrayRegion) + (JNIEnv *env, jdoubleArray array, jsize start, jsize len, const jdouble *buf); + + jint (JNICALL *RegisterNatives) + (JNIEnv *env, jclass clazz, const JNINativeMethod *methods, + jint nMethods); + jint (JNICALL *UnregisterNatives) + (JNIEnv *env, jclass clazz); + + jint (JNICALL *MonitorEnter) + (JNIEnv *env, jobject obj); + jint (JNICALL *MonitorExit) + (JNIEnv *env, jobject obj); + + jint (JNICALL *GetJavaVM) + (JNIEnv *env, JavaVM **vm); + + void (JNICALL *GetStringRegion) + (JNIEnv *env, jstring str, jsize start, jsize len, jchar *buf); + void (JNICALL *GetStringUTFRegion) + (JNIEnv *env, jstring str, jsize start, jsize len, char *buf); + + void * (JNICALL *GetPrimitiveArrayCritical) + (JNIEnv *env, jarray array, jboolean *isCopy); + void (JNICALL *ReleasePrimitiveArrayCritical) + (JNIEnv *env, jarray array, void *carray, jint mode); + + const jchar * (JNICALL *GetStringCritical) + (JNIEnv *env, jstring string, jboolean *isCopy); + void (JNICALL *ReleaseStringCritical) + (JNIEnv *env, jstring string, const jchar *cstring); + + jweak (JNICALL *NewWeakGlobalRef) + (JNIEnv *env, jobject obj); + void (JNICALL *DeleteWeakGlobalRef) + (JNIEnv *env, jweak ref); + + jboolean (JNICALL *ExceptionCheck) + (JNIEnv *env); + + jobject (JNICALL *NewDirectByteBuffer) + (JNIEnv* env, void* address, jlong capacity); + void* (JNICALL *GetDirectBufferAddress) + (JNIEnv* env, jobject buf); + jlong (JNICALL *GetDirectBufferCapacity) + (JNIEnv* env, jobject buf); + + /* New JNI 1.6 Features */ + + jobjectRefType (JNICALL *GetObjectRefType) + (JNIEnv* env, jobject obj); + + /* Module Features */ + + jobject (JNICALL *GetModule) + (JNIEnv* env, jclass clazz); + + /* Virtual threads */ + + jboolean (JNICALL *IsVirtualThread) + (JNIEnv* env, jobject obj); + + /* Large UTF8 Support */ + + jlong (JNICALL *GetStringUTFLengthAsLong) + (JNIEnv *env, jstring str); + +}; + +/* + * We use inlined functions for C++ so that programmers can write: + * + * env->FindClass("java/lang/String") + * + * in C++ rather than: + * + * (*env)->FindClass(env, "java/lang/String") + * + * in C. + */ + +struct JNIEnv_ { + const struct JNINativeInterface_ *functions; +#ifdef __cplusplus + + jint GetVersion() { + return functions->GetVersion(this); + } + jclass DefineClass(const char *name, jobject loader, const jbyte *buf, + jsize len) { + return functions->DefineClass(this, name, loader, buf, len); + } + jclass FindClass(const char *name) { + return functions->FindClass(this, name); + } + jmethodID FromReflectedMethod(jobject method) { + return functions->FromReflectedMethod(this,method); + } + jfieldID FromReflectedField(jobject field) { + return functions->FromReflectedField(this,field); + } + + jobject ToReflectedMethod(jclass cls, jmethodID methodID, jboolean isStatic) { + return functions->ToReflectedMethod(this, cls, methodID, isStatic); + } + + jclass GetSuperclass(jclass sub) { + return functions->GetSuperclass(this, sub); + } + jboolean IsAssignableFrom(jclass sub, jclass sup) { + return functions->IsAssignableFrom(this, sub, sup); + } + + jobject ToReflectedField(jclass cls, jfieldID fieldID, jboolean isStatic) { + return functions->ToReflectedField(this,cls,fieldID,isStatic); + } + + jint Throw(jthrowable obj) { + return functions->Throw(this, obj); + } + jint ThrowNew(jclass clazz, const char *msg) { + return functions->ThrowNew(this, clazz, msg); + } + jthrowable ExceptionOccurred() { + return functions->ExceptionOccurred(this); + } + void ExceptionDescribe() { + functions->ExceptionDescribe(this); + } + void ExceptionClear() { + functions->ExceptionClear(this); + } + void FatalError(const char *msg) { + functions->FatalError(this, msg); + } + + jint PushLocalFrame(jint capacity) { + return functions->PushLocalFrame(this,capacity); + } + jobject PopLocalFrame(jobject result) { + return functions->PopLocalFrame(this,result); + } + + jobject NewGlobalRef(jobject lobj) { + return functions->NewGlobalRef(this,lobj); + } + void DeleteGlobalRef(jobject gref) { + functions->DeleteGlobalRef(this,gref); + } + void DeleteLocalRef(jobject obj) { + functions->DeleteLocalRef(this, obj); + } + + jboolean IsSameObject(jobject obj1, jobject obj2) { + return functions->IsSameObject(this,obj1,obj2); + } + + jobject NewLocalRef(jobject ref) { + return functions->NewLocalRef(this,ref); + } + jint EnsureLocalCapacity(jint capacity) { + return functions->EnsureLocalCapacity(this,capacity); + } + + jobject AllocObject(jclass clazz) { + return functions->AllocObject(this,clazz); + } + jobject NewObject(jclass clazz, jmethodID methodID, ...) { + va_list args; + jobject result; + va_start(args, methodID); + result = functions->NewObjectV(this,clazz,methodID,args); + va_end(args); + return result; + } + jobject NewObjectV(jclass clazz, jmethodID methodID, + va_list args) { + return functions->NewObjectV(this,clazz,methodID,args); + } + jobject NewObjectA(jclass clazz, jmethodID methodID, + const jvalue *args) { + return functions->NewObjectA(this,clazz,methodID,args); + } + + jclass GetObjectClass(jobject obj) { + return functions->GetObjectClass(this,obj); + } + jboolean IsInstanceOf(jobject obj, jclass clazz) { + return functions->IsInstanceOf(this,obj,clazz); + } + + jmethodID GetMethodID(jclass clazz, const char *name, + const char *sig) { + return functions->GetMethodID(this,clazz,name,sig); + } + + jobject CallObjectMethod(jobject obj, jmethodID methodID, ...) { + va_list args; + jobject result; + va_start(args,methodID); + result = functions->CallObjectMethodV(this,obj,methodID,args); + va_end(args); + return result; + } + jobject CallObjectMethodV(jobject obj, jmethodID methodID, + va_list args) { + return functions->CallObjectMethodV(this,obj,methodID,args); + } + jobject CallObjectMethodA(jobject obj, jmethodID methodID, + const jvalue * args) { + return functions->CallObjectMethodA(this,obj,methodID,args); + } + + jboolean CallBooleanMethod(jobject obj, + jmethodID methodID, ...) { + va_list args; + jboolean result; + va_start(args,methodID); + result = functions->CallBooleanMethodV(this,obj,methodID,args); + va_end(args); + return result; + } + jboolean CallBooleanMethodV(jobject obj, jmethodID methodID, + va_list args) { + return functions->CallBooleanMethodV(this,obj,methodID,args); + } + jboolean CallBooleanMethodA(jobject obj, jmethodID methodID, + const jvalue * args) { + return functions->CallBooleanMethodA(this,obj,methodID, args); + } + + jbyte CallByteMethod(jobject obj, jmethodID methodID, ...) { + va_list args; + jbyte result; + va_start(args,methodID); + result = functions->CallByteMethodV(this,obj,methodID,args); + va_end(args); + return result; + } + jbyte CallByteMethodV(jobject obj, jmethodID methodID, + va_list args) { + return functions->CallByteMethodV(this,obj,methodID,args); + } + jbyte CallByteMethodA(jobject obj, jmethodID methodID, + const jvalue * args) { + return functions->CallByteMethodA(this,obj,methodID,args); + } + + jchar CallCharMethod(jobject obj, jmethodID methodID, ...) { + va_list args; + jchar result; + va_start(args,methodID); + result = functions->CallCharMethodV(this,obj,methodID,args); + va_end(args); + return result; + } + jchar CallCharMethodV(jobject obj, jmethodID methodID, + va_list args) { + return functions->CallCharMethodV(this,obj,methodID,args); + } + jchar CallCharMethodA(jobject obj, jmethodID methodID, + const jvalue * args) { + return functions->CallCharMethodA(this,obj,methodID,args); + } + + jshort CallShortMethod(jobject obj, jmethodID methodID, ...) { + va_list args; + jshort result; + va_start(args,methodID); + result = functions->CallShortMethodV(this,obj,methodID,args); + va_end(args); + return result; + } + jshort CallShortMethodV(jobject obj, jmethodID methodID, + va_list args) { + return functions->CallShortMethodV(this,obj,methodID,args); + } + jshort CallShortMethodA(jobject obj, jmethodID methodID, + const jvalue * args) { + return functions->CallShortMethodA(this,obj,methodID,args); + } + + jint CallIntMethod(jobject obj, jmethodID methodID, ...) { + va_list args; + jint result; + va_start(args,methodID); + result = functions->CallIntMethodV(this,obj,methodID,args); + va_end(args); + return result; + } + jint CallIntMethodV(jobject obj, jmethodID methodID, + va_list args) { + return functions->CallIntMethodV(this,obj,methodID,args); + } + jint CallIntMethodA(jobject obj, jmethodID methodID, + const jvalue * args) { + return functions->CallIntMethodA(this,obj,methodID,args); + } + + jlong CallLongMethod(jobject obj, jmethodID methodID, ...) { + va_list args; + jlong result; + va_start(args,methodID); + result = functions->CallLongMethodV(this,obj,methodID,args); + va_end(args); + return result; + } + jlong CallLongMethodV(jobject obj, jmethodID methodID, + va_list args) { + return functions->CallLongMethodV(this,obj,methodID,args); + } + jlong CallLongMethodA(jobject obj, jmethodID methodID, + const jvalue * args) { + return functions->CallLongMethodA(this,obj,methodID,args); + } + + jfloat CallFloatMethod(jobject obj, jmethodID methodID, ...) { + va_list args; + jfloat result; + va_start(args,methodID); + result = functions->CallFloatMethodV(this,obj,methodID,args); + va_end(args); + return result; + } + jfloat CallFloatMethodV(jobject obj, jmethodID methodID, + va_list args) { + return functions->CallFloatMethodV(this,obj,methodID,args); + } + jfloat CallFloatMethodA(jobject obj, jmethodID methodID, + const jvalue * args) { + return functions->CallFloatMethodA(this,obj,methodID,args); + } + + jdouble CallDoubleMethod(jobject obj, jmethodID methodID, ...) { + va_list args; + jdouble result; + va_start(args,methodID); + result = functions->CallDoubleMethodV(this,obj,methodID,args); + va_end(args); + return result; + } + jdouble CallDoubleMethodV(jobject obj, jmethodID methodID, + va_list args) { + return functions->CallDoubleMethodV(this,obj,methodID,args); + } + jdouble CallDoubleMethodA(jobject obj, jmethodID methodID, + const jvalue * args) { + return functions->CallDoubleMethodA(this,obj,methodID,args); + } + + void CallVoidMethod(jobject obj, jmethodID methodID, ...) { + va_list args; + va_start(args,methodID); + functions->CallVoidMethodV(this,obj,methodID,args); + va_end(args); + } + void CallVoidMethodV(jobject obj, jmethodID methodID, + va_list args) { + functions->CallVoidMethodV(this,obj,methodID,args); + } + void CallVoidMethodA(jobject obj, jmethodID methodID, + const jvalue * args) { + functions->CallVoidMethodA(this,obj,methodID,args); + } + + jobject CallNonvirtualObjectMethod(jobject obj, jclass clazz, + jmethodID methodID, ...) { + va_list args; + jobject result; + va_start(args,methodID); + result = functions->CallNonvirtualObjectMethodV(this,obj,clazz, + methodID,args); + va_end(args); + return result; + } + jobject CallNonvirtualObjectMethodV(jobject obj, jclass clazz, + jmethodID methodID, va_list args) { + return functions->CallNonvirtualObjectMethodV(this,obj,clazz, + methodID,args); + } + jobject CallNonvirtualObjectMethodA(jobject obj, jclass clazz, + jmethodID methodID, const jvalue * args) { + return functions->CallNonvirtualObjectMethodA(this,obj,clazz, + methodID,args); + } + + jboolean CallNonvirtualBooleanMethod(jobject obj, jclass clazz, + jmethodID methodID, ...) { + va_list args; + jboolean result; + va_start(args,methodID); + result = functions->CallNonvirtualBooleanMethodV(this,obj,clazz, + methodID,args); + va_end(args); + return result; + } + jboolean CallNonvirtualBooleanMethodV(jobject obj, jclass clazz, + jmethodID methodID, va_list args) { + return functions->CallNonvirtualBooleanMethodV(this,obj,clazz, + methodID,args); + } + jboolean CallNonvirtualBooleanMethodA(jobject obj, jclass clazz, + jmethodID methodID, const jvalue * args) { + return functions->CallNonvirtualBooleanMethodA(this,obj,clazz, + methodID, args); + } + + jbyte CallNonvirtualByteMethod(jobject obj, jclass clazz, + jmethodID methodID, ...) { + va_list args; + jbyte result; + va_start(args,methodID); + result = functions->CallNonvirtualByteMethodV(this,obj,clazz, + methodID,args); + va_end(args); + return result; + } + jbyte CallNonvirtualByteMethodV(jobject obj, jclass clazz, + jmethodID methodID, va_list args) { + return functions->CallNonvirtualByteMethodV(this,obj,clazz, + methodID,args); + } + jbyte CallNonvirtualByteMethodA(jobject obj, jclass clazz, + jmethodID methodID, const jvalue * args) { + return functions->CallNonvirtualByteMethodA(this,obj,clazz, + methodID,args); + } + + jchar CallNonvirtualCharMethod(jobject obj, jclass clazz, + jmethodID methodID, ...) { + va_list args; + jchar result; + va_start(args,methodID); + result = functions->CallNonvirtualCharMethodV(this,obj,clazz, + methodID,args); + va_end(args); + return result; + } + jchar CallNonvirtualCharMethodV(jobject obj, jclass clazz, + jmethodID methodID, va_list args) { + return functions->CallNonvirtualCharMethodV(this,obj,clazz, + methodID,args); + } + jchar CallNonvirtualCharMethodA(jobject obj, jclass clazz, + jmethodID methodID, const jvalue * args) { + return functions->CallNonvirtualCharMethodA(this,obj,clazz, + methodID,args); + } + + jshort CallNonvirtualShortMethod(jobject obj, jclass clazz, + jmethodID methodID, ...) { + va_list args; + jshort result; + va_start(args,methodID); + result = functions->CallNonvirtualShortMethodV(this,obj,clazz, + methodID,args); + va_end(args); + return result; + } + jshort CallNonvirtualShortMethodV(jobject obj, jclass clazz, + jmethodID methodID, va_list args) { + return functions->CallNonvirtualShortMethodV(this,obj,clazz, + methodID,args); + } + jshort CallNonvirtualShortMethodA(jobject obj, jclass clazz, + jmethodID methodID, const jvalue * args) { + return functions->CallNonvirtualShortMethodA(this,obj,clazz, + methodID,args); + } + + jint CallNonvirtualIntMethod(jobject obj, jclass clazz, + jmethodID methodID, ...) { + va_list args; + jint result; + va_start(args,methodID); + result = functions->CallNonvirtualIntMethodV(this,obj,clazz, + methodID,args); + va_end(args); + return result; + } + jint CallNonvirtualIntMethodV(jobject obj, jclass clazz, + jmethodID methodID, va_list args) { + return functions->CallNonvirtualIntMethodV(this,obj,clazz, + methodID,args); + } + jint CallNonvirtualIntMethodA(jobject obj, jclass clazz, + jmethodID methodID, const jvalue * args) { + return functions->CallNonvirtualIntMethodA(this,obj,clazz, + methodID,args); + } + + jlong CallNonvirtualLongMethod(jobject obj, jclass clazz, + jmethodID methodID, ...) { + va_list args; + jlong result; + va_start(args,methodID); + result = functions->CallNonvirtualLongMethodV(this,obj,clazz, + methodID,args); + va_end(args); + return result; + } + jlong CallNonvirtualLongMethodV(jobject obj, jclass clazz, + jmethodID methodID, va_list args) { + return functions->CallNonvirtualLongMethodV(this,obj,clazz, + methodID,args); + } + jlong CallNonvirtualLongMethodA(jobject obj, jclass clazz, + jmethodID methodID, const jvalue * args) { + return functions->CallNonvirtualLongMethodA(this,obj,clazz, + methodID,args); + } + + jfloat CallNonvirtualFloatMethod(jobject obj, jclass clazz, + jmethodID methodID, ...) { + va_list args; + jfloat result; + va_start(args,methodID); + result = functions->CallNonvirtualFloatMethodV(this,obj,clazz, + methodID,args); + va_end(args); + return result; + } + jfloat CallNonvirtualFloatMethodV(jobject obj, jclass clazz, + jmethodID methodID, + va_list args) { + return functions->CallNonvirtualFloatMethodV(this,obj,clazz, + methodID,args); + } + jfloat CallNonvirtualFloatMethodA(jobject obj, jclass clazz, + jmethodID methodID, + const jvalue * args) { + return functions->CallNonvirtualFloatMethodA(this,obj,clazz, + methodID,args); + } + + jdouble CallNonvirtualDoubleMethod(jobject obj, jclass clazz, + jmethodID methodID, ...) { + va_list args; + jdouble result; + va_start(args,methodID); + result = functions->CallNonvirtualDoubleMethodV(this,obj,clazz, + methodID,args); + va_end(args); + return result; + } + jdouble CallNonvirtualDoubleMethodV(jobject obj, jclass clazz, + jmethodID methodID, + va_list args) { + return functions->CallNonvirtualDoubleMethodV(this,obj,clazz, + methodID,args); + } + jdouble CallNonvirtualDoubleMethodA(jobject obj, jclass clazz, + jmethodID methodID, + const jvalue * args) { + return functions->CallNonvirtualDoubleMethodA(this,obj,clazz, + methodID,args); + } + + void CallNonvirtualVoidMethod(jobject obj, jclass clazz, + jmethodID methodID, ...) { + va_list args; + va_start(args,methodID); + functions->CallNonvirtualVoidMethodV(this,obj,clazz,methodID,args); + va_end(args); + } + void CallNonvirtualVoidMethodV(jobject obj, jclass clazz, + jmethodID methodID, + va_list args) { + functions->CallNonvirtualVoidMethodV(this,obj,clazz,methodID,args); + } + void CallNonvirtualVoidMethodA(jobject obj, jclass clazz, + jmethodID methodID, + const jvalue * args) { + functions->CallNonvirtualVoidMethodA(this,obj,clazz,methodID,args); + } + + jfieldID GetFieldID(jclass clazz, const char *name, + const char *sig) { + return functions->GetFieldID(this,clazz,name,sig); + } + + jobject GetObjectField(jobject obj, jfieldID fieldID) { + return functions->GetObjectField(this,obj,fieldID); + } + jboolean GetBooleanField(jobject obj, jfieldID fieldID) { + return functions->GetBooleanField(this,obj,fieldID); + } + jbyte GetByteField(jobject obj, jfieldID fieldID) { + return functions->GetByteField(this,obj,fieldID); + } + jchar GetCharField(jobject obj, jfieldID fieldID) { + return functions->GetCharField(this,obj,fieldID); + } + jshort GetShortField(jobject obj, jfieldID fieldID) { + return functions->GetShortField(this,obj,fieldID); + } + jint GetIntField(jobject obj, jfieldID fieldID) { + return functions->GetIntField(this,obj,fieldID); + } + jlong GetLongField(jobject obj, jfieldID fieldID) { + return functions->GetLongField(this,obj,fieldID); + } + jfloat GetFloatField(jobject obj, jfieldID fieldID) { + return functions->GetFloatField(this,obj,fieldID); + } + jdouble GetDoubleField(jobject obj, jfieldID fieldID) { + return functions->GetDoubleField(this,obj,fieldID); + } + + void SetObjectField(jobject obj, jfieldID fieldID, jobject val) { + functions->SetObjectField(this,obj,fieldID,val); + } + void SetBooleanField(jobject obj, jfieldID fieldID, + jboolean val) { + functions->SetBooleanField(this,obj,fieldID,val); + } + void SetByteField(jobject obj, jfieldID fieldID, + jbyte val) { + functions->SetByteField(this,obj,fieldID,val); + } + void SetCharField(jobject obj, jfieldID fieldID, + jchar val) { + functions->SetCharField(this,obj,fieldID,val); + } + void SetShortField(jobject obj, jfieldID fieldID, + jshort val) { + functions->SetShortField(this,obj,fieldID,val); + } + void SetIntField(jobject obj, jfieldID fieldID, + jint val) { + functions->SetIntField(this,obj,fieldID,val); + } + void SetLongField(jobject obj, jfieldID fieldID, + jlong val) { + functions->SetLongField(this,obj,fieldID,val); + } + void SetFloatField(jobject obj, jfieldID fieldID, + jfloat val) { + functions->SetFloatField(this,obj,fieldID,val); + } + void SetDoubleField(jobject obj, jfieldID fieldID, + jdouble val) { + functions->SetDoubleField(this,obj,fieldID,val); + } + + jmethodID GetStaticMethodID(jclass clazz, const char *name, + const char *sig) { + return functions->GetStaticMethodID(this,clazz,name,sig); + } + + jobject CallStaticObjectMethod(jclass clazz, jmethodID methodID, + ...) { + va_list args; + jobject result; + va_start(args,methodID); + result = functions->CallStaticObjectMethodV(this,clazz,methodID,args); + va_end(args); + return result; + } + jobject CallStaticObjectMethodV(jclass clazz, jmethodID methodID, + va_list args) { + return functions->CallStaticObjectMethodV(this,clazz,methodID,args); + } + jobject CallStaticObjectMethodA(jclass clazz, jmethodID methodID, + const jvalue *args) { + return functions->CallStaticObjectMethodA(this,clazz,methodID,args); + } + + jboolean CallStaticBooleanMethod(jclass clazz, + jmethodID methodID, ...) { + va_list args; + jboolean result; + va_start(args,methodID); + result = functions->CallStaticBooleanMethodV(this,clazz,methodID,args); + va_end(args); + return result; + } + jboolean CallStaticBooleanMethodV(jclass clazz, + jmethodID methodID, va_list args) { + return functions->CallStaticBooleanMethodV(this,clazz,methodID,args); + } + jboolean CallStaticBooleanMethodA(jclass clazz, + jmethodID methodID, const jvalue *args) { + return functions->CallStaticBooleanMethodA(this,clazz,methodID,args); + } + + jbyte CallStaticByteMethod(jclass clazz, + jmethodID methodID, ...) { + va_list args; + jbyte result; + va_start(args,methodID); + result = functions->CallStaticByteMethodV(this,clazz,methodID,args); + va_end(args); + return result; + } + jbyte CallStaticByteMethodV(jclass clazz, + jmethodID methodID, va_list args) { + return functions->CallStaticByteMethodV(this,clazz,methodID,args); + } + jbyte CallStaticByteMethodA(jclass clazz, + jmethodID methodID, const jvalue *args) { + return functions->CallStaticByteMethodA(this,clazz,methodID,args); + } + + jchar CallStaticCharMethod(jclass clazz, + jmethodID methodID, ...) { + va_list args; + jchar result; + va_start(args,methodID); + result = functions->CallStaticCharMethodV(this,clazz,methodID,args); + va_end(args); + return result; + } + jchar CallStaticCharMethodV(jclass clazz, + jmethodID methodID, va_list args) { + return functions->CallStaticCharMethodV(this,clazz,methodID,args); + } + jchar CallStaticCharMethodA(jclass clazz, + jmethodID methodID, const jvalue *args) { + return functions->CallStaticCharMethodA(this,clazz,methodID,args); + } + + jshort CallStaticShortMethod(jclass clazz, + jmethodID methodID, ...) { + va_list args; + jshort result; + va_start(args,methodID); + result = functions->CallStaticShortMethodV(this,clazz,methodID,args); + va_end(args); + return result; + } + jshort CallStaticShortMethodV(jclass clazz, + jmethodID methodID, va_list args) { + return functions->CallStaticShortMethodV(this,clazz,methodID,args); + } + jshort CallStaticShortMethodA(jclass clazz, + jmethodID methodID, const jvalue *args) { + return functions->CallStaticShortMethodA(this,clazz,methodID,args); + } + + jint CallStaticIntMethod(jclass clazz, + jmethodID methodID, ...) { + va_list args; + jint result; + va_start(args,methodID); + result = functions->CallStaticIntMethodV(this,clazz,methodID,args); + va_end(args); + return result; + } + jint CallStaticIntMethodV(jclass clazz, + jmethodID methodID, va_list args) { + return functions->CallStaticIntMethodV(this,clazz,methodID,args); + } + jint CallStaticIntMethodA(jclass clazz, + jmethodID methodID, const jvalue *args) { + return functions->CallStaticIntMethodA(this,clazz,methodID,args); + } + + jlong CallStaticLongMethod(jclass clazz, + jmethodID methodID, ...) { + va_list args; + jlong result; + va_start(args,methodID); + result = functions->CallStaticLongMethodV(this,clazz,methodID,args); + va_end(args); + return result; + } + jlong CallStaticLongMethodV(jclass clazz, + jmethodID methodID, va_list args) { + return functions->CallStaticLongMethodV(this,clazz,methodID,args); + } + jlong CallStaticLongMethodA(jclass clazz, + jmethodID methodID, const jvalue *args) { + return functions->CallStaticLongMethodA(this,clazz,methodID,args); + } + + jfloat CallStaticFloatMethod(jclass clazz, + jmethodID methodID, ...) { + va_list args; + jfloat result; + va_start(args,methodID); + result = functions->CallStaticFloatMethodV(this,clazz,methodID,args); + va_end(args); + return result; + } + jfloat CallStaticFloatMethodV(jclass clazz, + jmethodID methodID, va_list args) { + return functions->CallStaticFloatMethodV(this,clazz,methodID,args); + } + jfloat CallStaticFloatMethodA(jclass clazz, + jmethodID methodID, const jvalue *args) { + return functions->CallStaticFloatMethodA(this,clazz,methodID,args); + } + + jdouble CallStaticDoubleMethod(jclass clazz, + jmethodID methodID, ...) { + va_list args; + jdouble result; + va_start(args,methodID); + result = functions->CallStaticDoubleMethodV(this,clazz,methodID,args); + va_end(args); + return result; + } + jdouble CallStaticDoubleMethodV(jclass clazz, + jmethodID methodID, va_list args) { + return functions->CallStaticDoubleMethodV(this,clazz,methodID,args); + } + jdouble CallStaticDoubleMethodA(jclass clazz, + jmethodID methodID, const jvalue *args) { + return functions->CallStaticDoubleMethodA(this,clazz,methodID,args); + } + + void CallStaticVoidMethod(jclass cls, jmethodID methodID, ...) { + va_list args; + va_start(args,methodID); + functions->CallStaticVoidMethodV(this,cls,methodID,args); + va_end(args); + } + void CallStaticVoidMethodV(jclass cls, jmethodID methodID, + va_list args) { + functions->CallStaticVoidMethodV(this,cls,methodID,args); + } + void CallStaticVoidMethodA(jclass cls, jmethodID methodID, + const jvalue * args) { + functions->CallStaticVoidMethodA(this,cls,methodID,args); + } + + jfieldID GetStaticFieldID(jclass clazz, const char *name, + const char *sig) { + return functions->GetStaticFieldID(this,clazz,name,sig); + } + jobject GetStaticObjectField(jclass clazz, jfieldID fieldID) { + return functions->GetStaticObjectField(this,clazz,fieldID); + } + jboolean GetStaticBooleanField(jclass clazz, jfieldID fieldID) { + return functions->GetStaticBooleanField(this,clazz,fieldID); + } + jbyte GetStaticByteField(jclass clazz, jfieldID fieldID) { + return functions->GetStaticByteField(this,clazz,fieldID); + } + jchar GetStaticCharField(jclass clazz, jfieldID fieldID) { + return functions->GetStaticCharField(this,clazz,fieldID); + } + jshort GetStaticShortField(jclass clazz, jfieldID fieldID) { + return functions->GetStaticShortField(this,clazz,fieldID); + } + jint GetStaticIntField(jclass clazz, jfieldID fieldID) { + return functions->GetStaticIntField(this,clazz,fieldID); + } + jlong GetStaticLongField(jclass clazz, jfieldID fieldID) { + return functions->GetStaticLongField(this,clazz,fieldID); + } + jfloat GetStaticFloatField(jclass clazz, jfieldID fieldID) { + return functions->GetStaticFloatField(this,clazz,fieldID); + } + jdouble GetStaticDoubleField(jclass clazz, jfieldID fieldID) { + return functions->GetStaticDoubleField(this,clazz,fieldID); + } + + void SetStaticObjectField(jclass clazz, jfieldID fieldID, + jobject value) { + functions->SetStaticObjectField(this,clazz,fieldID,value); + } + void SetStaticBooleanField(jclass clazz, jfieldID fieldID, + jboolean value) { + functions->SetStaticBooleanField(this,clazz,fieldID,value); + } + void SetStaticByteField(jclass clazz, jfieldID fieldID, + jbyte value) { + functions->SetStaticByteField(this,clazz,fieldID,value); + } + void SetStaticCharField(jclass clazz, jfieldID fieldID, + jchar value) { + functions->SetStaticCharField(this,clazz,fieldID,value); + } + void SetStaticShortField(jclass clazz, jfieldID fieldID, + jshort value) { + functions->SetStaticShortField(this,clazz,fieldID,value); + } + void SetStaticIntField(jclass clazz, jfieldID fieldID, + jint value) { + functions->SetStaticIntField(this,clazz,fieldID,value); + } + void SetStaticLongField(jclass clazz, jfieldID fieldID, + jlong value) { + functions->SetStaticLongField(this,clazz,fieldID,value); + } + void SetStaticFloatField(jclass clazz, jfieldID fieldID, + jfloat value) { + functions->SetStaticFloatField(this,clazz,fieldID,value); + } + void SetStaticDoubleField(jclass clazz, jfieldID fieldID, + jdouble value) { + functions->SetStaticDoubleField(this,clazz,fieldID,value); + } + + jstring NewString(const jchar *unicode, jsize len) { + return functions->NewString(this,unicode,len); + } + jsize GetStringLength(jstring str) { + return functions->GetStringLength(this,str); + } + const jchar *GetStringChars(jstring str, jboolean *isCopy) { + return functions->GetStringChars(this,str,isCopy); + } + void ReleaseStringChars(jstring str, const jchar *chars) { + functions->ReleaseStringChars(this,str,chars); + } + + jstring NewStringUTF(const char *utf) { + return functions->NewStringUTF(this,utf); + } + jsize GetStringUTFLength(jstring str) { + return functions->GetStringUTFLength(this,str); + } + jlong GetStringUTFLengthAsLong(jstring str) { + return functions->GetStringUTFLengthAsLong(this,str); + } + const char* GetStringUTFChars(jstring str, jboolean *isCopy) { + return functions->GetStringUTFChars(this,str,isCopy); + } + void ReleaseStringUTFChars(jstring str, const char* chars) { + functions->ReleaseStringUTFChars(this,str,chars); + } + + jsize GetArrayLength(jarray array) { + return functions->GetArrayLength(this,array); + } + + jobjectArray NewObjectArray(jsize len, jclass clazz, + jobject init) { + return functions->NewObjectArray(this,len,clazz,init); + } + jobject GetObjectArrayElement(jobjectArray array, jsize index) { + return functions->GetObjectArrayElement(this,array,index); + } + void SetObjectArrayElement(jobjectArray array, jsize index, + jobject val) { + functions->SetObjectArrayElement(this,array,index,val); + } + + jbooleanArray NewBooleanArray(jsize len) { + return functions->NewBooleanArray(this,len); + } + jbyteArray NewByteArray(jsize len) { + return functions->NewByteArray(this,len); + } + jcharArray NewCharArray(jsize len) { + return functions->NewCharArray(this,len); + } + jshortArray NewShortArray(jsize len) { + return functions->NewShortArray(this,len); + } + jintArray NewIntArray(jsize len) { + return functions->NewIntArray(this,len); + } + jlongArray NewLongArray(jsize len) { + return functions->NewLongArray(this,len); + } + jfloatArray NewFloatArray(jsize len) { + return functions->NewFloatArray(this,len); + } + jdoubleArray NewDoubleArray(jsize len) { + return functions->NewDoubleArray(this,len); + } + + jboolean * GetBooleanArrayElements(jbooleanArray array, jboolean *isCopy) { + return functions->GetBooleanArrayElements(this,array,isCopy); + } + jbyte * GetByteArrayElements(jbyteArray array, jboolean *isCopy) { + return functions->GetByteArrayElements(this,array,isCopy); + } + jchar * GetCharArrayElements(jcharArray array, jboolean *isCopy) { + return functions->GetCharArrayElements(this,array,isCopy); + } + jshort * GetShortArrayElements(jshortArray array, jboolean *isCopy) { + return functions->GetShortArrayElements(this,array,isCopy); + } + jint * GetIntArrayElements(jintArray array, jboolean *isCopy) { + return functions->GetIntArrayElements(this,array,isCopy); + } + jlong * GetLongArrayElements(jlongArray array, jboolean *isCopy) { + return functions->GetLongArrayElements(this,array,isCopy); + } + jfloat * GetFloatArrayElements(jfloatArray array, jboolean *isCopy) { + return functions->GetFloatArrayElements(this,array,isCopy); + } + jdouble * GetDoubleArrayElements(jdoubleArray array, jboolean *isCopy) { + return functions->GetDoubleArrayElements(this,array,isCopy); + } + + void ReleaseBooleanArrayElements(jbooleanArray array, + jboolean *elems, + jint mode) { + functions->ReleaseBooleanArrayElements(this,array,elems,mode); + } + void ReleaseByteArrayElements(jbyteArray array, + jbyte *elems, + jint mode) { + functions->ReleaseByteArrayElements(this,array,elems,mode); + } + void ReleaseCharArrayElements(jcharArray array, + jchar *elems, + jint mode) { + functions->ReleaseCharArrayElements(this,array,elems,mode); + } + void ReleaseShortArrayElements(jshortArray array, + jshort *elems, + jint mode) { + functions->ReleaseShortArrayElements(this,array,elems,mode); + } + void ReleaseIntArrayElements(jintArray array, + jint *elems, + jint mode) { + functions->ReleaseIntArrayElements(this,array,elems,mode); + } + void ReleaseLongArrayElements(jlongArray array, + jlong *elems, + jint mode) { + functions->ReleaseLongArrayElements(this,array,elems,mode); + } + void ReleaseFloatArrayElements(jfloatArray array, + jfloat *elems, + jint mode) { + functions->ReleaseFloatArrayElements(this,array,elems,mode); + } + void ReleaseDoubleArrayElements(jdoubleArray array, + jdouble *elems, + jint mode) { + functions->ReleaseDoubleArrayElements(this,array,elems,mode); + } + + void GetBooleanArrayRegion(jbooleanArray array, + jsize start, jsize len, jboolean *buf) { + functions->GetBooleanArrayRegion(this,array,start,len,buf); + } + void GetByteArrayRegion(jbyteArray array, + jsize start, jsize len, jbyte *buf) { + functions->GetByteArrayRegion(this,array,start,len,buf); + } + void GetCharArrayRegion(jcharArray array, + jsize start, jsize len, jchar *buf) { + functions->GetCharArrayRegion(this,array,start,len,buf); + } + void GetShortArrayRegion(jshortArray array, + jsize start, jsize len, jshort *buf) { + functions->GetShortArrayRegion(this,array,start,len,buf); + } + void GetIntArrayRegion(jintArray array, + jsize start, jsize len, jint *buf) { + functions->GetIntArrayRegion(this,array,start,len,buf); + } + void GetLongArrayRegion(jlongArray array, + jsize start, jsize len, jlong *buf) { + functions->GetLongArrayRegion(this,array,start,len,buf); + } + void GetFloatArrayRegion(jfloatArray array, + jsize start, jsize len, jfloat *buf) { + functions->GetFloatArrayRegion(this,array,start,len,buf); + } + void GetDoubleArrayRegion(jdoubleArray array, + jsize start, jsize len, jdouble *buf) { + functions->GetDoubleArrayRegion(this,array,start,len,buf); + } + + void SetBooleanArrayRegion(jbooleanArray array, jsize start, jsize len, + const jboolean *buf) { + functions->SetBooleanArrayRegion(this,array,start,len,buf); + } + void SetByteArrayRegion(jbyteArray array, jsize start, jsize len, + const jbyte *buf) { + functions->SetByteArrayRegion(this,array,start,len,buf); + } + void SetCharArrayRegion(jcharArray array, jsize start, jsize len, + const jchar *buf) { + functions->SetCharArrayRegion(this,array,start,len,buf); + } + void SetShortArrayRegion(jshortArray array, jsize start, jsize len, + const jshort *buf) { + functions->SetShortArrayRegion(this,array,start,len,buf); + } + void SetIntArrayRegion(jintArray array, jsize start, jsize len, + const jint *buf) { + functions->SetIntArrayRegion(this,array,start,len,buf); + } + void SetLongArrayRegion(jlongArray array, jsize start, jsize len, + const jlong *buf) { + functions->SetLongArrayRegion(this,array,start,len,buf); + } + void SetFloatArrayRegion(jfloatArray array, jsize start, jsize len, + const jfloat *buf) { + functions->SetFloatArrayRegion(this,array,start,len,buf); + } + void SetDoubleArrayRegion(jdoubleArray array, jsize start, jsize len, + const jdouble *buf) { + functions->SetDoubleArrayRegion(this,array,start,len,buf); + } + + jint RegisterNatives(jclass clazz, const JNINativeMethod *methods, + jint nMethods) { + return functions->RegisterNatives(this,clazz,methods,nMethods); + } + jint UnregisterNatives(jclass clazz) { + return functions->UnregisterNatives(this,clazz); + } + + jint MonitorEnter(jobject obj) { + return functions->MonitorEnter(this,obj); + } + jint MonitorExit(jobject obj) { + return functions->MonitorExit(this,obj); + } + + jint GetJavaVM(JavaVM **vm) { + return functions->GetJavaVM(this,vm); + } + + void GetStringRegion(jstring str, jsize start, jsize len, jchar *buf) { + functions->GetStringRegion(this,str,start,len,buf); + } + void GetStringUTFRegion(jstring str, jsize start, jsize len, char *buf) { + functions->GetStringUTFRegion(this,str,start,len,buf); + } + + void * GetPrimitiveArrayCritical(jarray array, jboolean *isCopy) { + return functions->GetPrimitiveArrayCritical(this,array,isCopy); + } + void ReleasePrimitiveArrayCritical(jarray array, void *carray, jint mode) { + functions->ReleasePrimitiveArrayCritical(this,array,carray,mode); + } + + const jchar * GetStringCritical(jstring string, jboolean *isCopy) { + return functions->GetStringCritical(this,string,isCopy); + } + void ReleaseStringCritical(jstring string, const jchar *cstring) { + functions->ReleaseStringCritical(this,string,cstring); + } + + jweak NewWeakGlobalRef(jobject obj) { + return functions->NewWeakGlobalRef(this,obj); + } + void DeleteWeakGlobalRef(jweak ref) { + functions->DeleteWeakGlobalRef(this,ref); + } + + jboolean ExceptionCheck() { + return functions->ExceptionCheck(this); + } + + jobject NewDirectByteBuffer(void* address, jlong capacity) { + return functions->NewDirectByteBuffer(this, address, capacity); + } + void* GetDirectBufferAddress(jobject buf) { + return functions->GetDirectBufferAddress(this, buf); + } + jlong GetDirectBufferCapacity(jobject buf) { + return functions->GetDirectBufferCapacity(this, buf); + } + jobjectRefType GetObjectRefType(jobject obj) { + return functions->GetObjectRefType(this, obj); + } + + /* Module Features */ + + jobject GetModule(jclass clazz) { + return functions->GetModule(this, clazz); + } + + /* Virtual threads */ + + jboolean IsVirtualThread(jobject obj) { + return functions->IsVirtualThread(this, obj); + } + +#endif /* __cplusplus */ +}; + +/* + * optionString may be any option accepted by the JVM, or one of the + * following: + * + * -D= Set a system property. + * -verbose[:class|gc|jni] Enable verbose output, comma-separated. E.g. + * "-verbose:class" or "-verbose:gc,class" + * Standard names include: gc, class, and jni. + * All nonstandard (VM-specific) names must begin + * with "X". + * vfprintf extraInfo is a pointer to the vfprintf hook. + * exit extraInfo is a pointer to the exit hook. + * abort extraInfo is a pointer to the abort hook. + */ +typedef struct JavaVMOption { + char *optionString; + void *extraInfo; +} JavaVMOption; + +typedef struct JavaVMInitArgs { + jint version; + + jint nOptions; + JavaVMOption *options; + jboolean ignoreUnrecognized; +} JavaVMInitArgs; + +typedef struct JavaVMAttachArgs { + jint version; + + char *name; + jobject group; +} JavaVMAttachArgs; + +/* These will be VM-specific. */ + +#define JDK1_2 +#define JDK1_4 + +/* End VM-specific. */ + +struct JNIInvokeInterface_ { + void *reserved0; + void *reserved1; + void *reserved2; + + jint (JNICALL *DestroyJavaVM)(JavaVM *vm); + + jint (JNICALL *AttachCurrentThread)(JavaVM *vm, void **penv, void *args); + + jint (JNICALL *DetachCurrentThread)(JavaVM *vm); + + jint (JNICALL *GetEnv)(JavaVM *vm, void **penv, jint version); + + jint (JNICALL *AttachCurrentThreadAsDaemon)(JavaVM *vm, void **penv, void *args); +}; + +struct JavaVM_ { + const struct JNIInvokeInterface_ *functions; +#ifdef __cplusplus + + jint DestroyJavaVM() { + return functions->DestroyJavaVM(this); + } + jint AttachCurrentThread(void **penv, void *args) { + return functions->AttachCurrentThread(this, penv, args); + } + jint DetachCurrentThread() { + return functions->DetachCurrentThread(this); + } + + jint GetEnv(void **penv, jint version) { + return functions->GetEnv(this, penv, version); + } + jint AttachCurrentThreadAsDaemon(void **penv, void *args) { + return functions->AttachCurrentThreadAsDaemon(this, penv, args); + } +#endif +}; + +#ifdef _JNI_IMPLEMENTATION_ +#define _JNI_IMPORT_OR_EXPORT_ JNIEXPORT +#else +#define _JNI_IMPORT_OR_EXPORT_ JNIIMPORT +#endif +_JNI_IMPORT_OR_EXPORT_ jint JNICALL +JNI_GetDefaultJavaVMInitArgs(void *args); + +_JNI_IMPORT_OR_EXPORT_ jint JNICALL +JNI_CreateJavaVM(JavaVM **pvm, void **penv, void *args); + +_JNI_IMPORT_OR_EXPORT_ jint JNICALL +JNI_GetCreatedJavaVMs(JavaVM **, jsize, jsize *); + +/* Defined by native libraries. */ +JNIEXPORT jint JNICALL +JNI_OnLoad(JavaVM *vm, void *reserved); + +JNIEXPORT void JNICALL +JNI_OnUnload(JavaVM *vm, void *reserved); + +#define JNI_VERSION_1_1 0x00010001 +#define JNI_VERSION_1_2 0x00010002 +#define JNI_VERSION_1_4 0x00010004 +#define JNI_VERSION_1_6 0x00010006 +#define JNI_VERSION_1_8 0x00010008 +#define JNI_VERSION_9 0x00090000 +#define JNI_VERSION_10 0x000a0000 +#define JNI_VERSION_19 0x00130000 +#define JNI_VERSION_20 0x00140000 +#define JNI_VERSION_21 0x00150000 +#define JNI_VERSION_24 0x00180000 + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ + +#endif /* !_JAVASOFT_JNI_H_ */ diff --git a/core/esmf-tree-sitter-turtle/src/main/c/include/linux/jawt_md.h b/core/esmf-tree-sitter-turtle/src/main/c/include/linux/jawt_md.h new file mode 100644 index 000000000..2ba3a8e83 --- /dev/null +++ b/core/esmf-tree-sitter-turtle/src/main/c/include/linux/jawt_md.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 1999, 2001, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#ifndef _JAVASOFT_JAWT_MD_H_ +#define _JAVASOFT_JAWT_MD_H_ + +#include +#include +#include "jawt.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * X11-specific declarations for AWT native interface. + * See notes in jawt.h for an example of use. + */ +typedef struct jawt_X11DrawingSurfaceInfo { + Drawable drawable; + Display* display; + VisualID visualID; + Colormap colormapID; + int depth; + /* + * Since 1.4 + * Returns a pixel value from a set of RGB values. + * This is useful for paletted color (256 color) modes. + */ + int (JNICALL *GetAWTColor)(JAWT_DrawingSurface* ds, + int r, int g, int b); +} JAWT_X11DrawingSurfaceInfo; + +#ifdef __cplusplus +} +#endif + +#endif /* !_JAVASOFT_JAWT_MD_H_ */ diff --git a/core/esmf-tree-sitter-turtle/src/main/c/include/linux/jni_md.h b/core/esmf-tree-sitter-turtle/src/main/c/include/linux/jni_md.h new file mode 100644 index 000000000..b4ed87e0c --- /dev/null +++ b/core/esmf-tree-sitter-turtle/src/main/c/include/linux/jni_md.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 1996, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#ifndef _JAVASOFT_JNI_MD_H_ +#define _JAVASOFT_JNI_MD_H_ + +#ifndef __has_attribute + #define __has_attribute(x) 0 +#endif + +#ifndef JNIEXPORT + #if (defined(__GNUC__) && ((__GNUC__ > 4) || (__GNUC__ == 4) && (__GNUC_MINOR__ > 2))) || __has_attribute(visibility) + #ifdef ARM + #define JNIEXPORT __attribute__((externally_visible,visibility("default"))) + #else + #define JNIEXPORT __attribute__((visibility("default"))) + #endif + #else + #define JNIEXPORT + #endif +#endif + +#if (defined(__GNUC__) && ((__GNUC__ > 4) || (__GNUC__ == 4) && (__GNUC_MINOR__ > 2))) || __has_attribute(visibility) + #ifdef ARM + #define JNIIMPORT __attribute__((externally_visible,visibility("default"))) + #else + #define JNIIMPORT __attribute__((visibility("default"))) + #endif +#else + #define JNIIMPORT +#endif + +typedef int jint; +#ifdef _LP64 +typedef long jlong; +#else +typedef long long jlong; +#endif + +typedef signed char jbyte; + +#endif /* !_JAVASOFT_JNI_MD_H_ */ diff --git a/core/esmf-tree-sitter-turtle/src/main/c/include/macos/jawt_md.h b/core/esmf-tree-sitter-turtle/src/main/c/include/macos/jawt_md.h new file mode 100644 index 000000000..94a13c9ab --- /dev/null +++ b/core/esmf-tree-sitter-turtle/src/main/c/include/macos/jawt_md.h @@ -0,0 +1,77 @@ +/* + * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#ifndef _JAVASOFT_JAWT_MD_H_ +#define _JAVASOFT_JAWT_MD_H_ + +#include "jawt.h" + +#ifdef __OBJC__ +#import +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * MacOS specific declarations for AWT native interface. + * See notes in jawt.h for an example of use. + */ + +/* + * When calling JAWT_GetAWT with a JAWT version less than 1.7, you must pass this + * flag or you will not be able to get a valid drawing surface and JAWT_GetAWT will + * return false. This is to maintain compatibility with applications that used the + * interface with Java 6 which had multiple rendering models. This flag is not necessary + * when JAWT version 1.7 or greater is used as this is the only supported rendering mode. + * + * Example: + * JAWT awt; + * awt.version = JAWT_VERSION_1_4 | JAWT_MACOSX_USE_CALAYER; + * jboolean success = JAWT_GetAWT(env, &awt); + */ +#define JAWT_MACOSX_USE_CALAYER 0x80000000 + +/* + * When the native Cocoa toolkit is in use, the pointer stored in + * JAWT_DrawingSurfaceInfo->platformInfo points to a NSObject that conforms to the + * JAWT_SurfaceLayers protocol. Setting the layer property of this object will cause the + * specified layer to be overlaid on the Components rectangle. If the window the + * Component belongs to has a CALayer attached to it, this layer will be accessible via + * the windowLayer property. + */ +#ifdef __OBJC__ +@protocol JAWT_SurfaceLayers +@property (readwrite, retain) CALayer *layer; +@property (readonly) CALayer *windowLayer; +@end +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* !_JAVASOFT_JAWT_MD_H_ */ diff --git a/core/esmf-tree-sitter-turtle/src/main/c/include/macos/jni_md.h b/core/esmf-tree-sitter-turtle/src/main/c/include/macos/jni_md.h new file mode 100644 index 000000000..b4ed87e0c --- /dev/null +++ b/core/esmf-tree-sitter-turtle/src/main/c/include/macos/jni_md.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 1996, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#ifndef _JAVASOFT_JNI_MD_H_ +#define _JAVASOFT_JNI_MD_H_ + +#ifndef __has_attribute + #define __has_attribute(x) 0 +#endif + +#ifndef JNIEXPORT + #if (defined(__GNUC__) && ((__GNUC__ > 4) || (__GNUC__ == 4) && (__GNUC_MINOR__ > 2))) || __has_attribute(visibility) + #ifdef ARM + #define JNIEXPORT __attribute__((externally_visible,visibility("default"))) + #else + #define JNIEXPORT __attribute__((visibility("default"))) + #endif + #else + #define JNIEXPORT + #endif +#endif + +#if (defined(__GNUC__) && ((__GNUC__ > 4) || (__GNUC__ == 4) && (__GNUC_MINOR__ > 2))) || __has_attribute(visibility) + #ifdef ARM + #define JNIIMPORT __attribute__((externally_visible,visibility("default"))) + #else + #define JNIIMPORT __attribute__((visibility("default"))) + #endif +#else + #define JNIIMPORT +#endif + +typedef int jint; +#ifdef _LP64 +typedef long jlong; +#else +typedef long long jlong; +#endif + +typedef signed char jbyte; + +#endif /* !_JAVASOFT_JNI_MD_H_ */ diff --git a/core/esmf-tree-sitter-turtle/src/main/c/include/windows/bridge/AccessBridgeCallbacks.h b/core/esmf-tree-sitter-turtle/src/main/c/include/windows/bridge/AccessBridgeCallbacks.h new file mode 100755 index 000000000..3f907d5f9 --- /dev/null +++ b/core/esmf-tree-sitter-turtle/src/main/c/include/windows/bridge/AccessBridgeCallbacks.h @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * Header file defining callback typedefs for Windows routines + * which are called from Java (responding to events, etc.). + */ + +#ifndef __AccessBridgeCallbacks_H__ +#define __AccessBridgeCallbacks_H__ + +#include +#include "AccessBridgePackages.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void (*AccessBridge_PropertyChangeFP) (long vmID, JOBJECT64 event, JOBJECT64 source, + wchar_t *property, wchar_t *oldValue, wchar_t *newValue); + +typedef void (*AccessBridge_JavaShutdownFP) (long vmID); +typedef void (*AccessBridge_JavaShutdownFP) (long vmID); + +typedef void (*AccessBridge_FocusGainedFP) (long vmID, JOBJECT64 event, JOBJECT64 source); +typedef void (*AccessBridge_FocusLostFP) (long vmID, JOBJECT64 event, JOBJECT64 source); + +typedef void (*AccessBridge_CaretUpdateFP) (long vmID, JOBJECT64 event, JOBJECT64 source); + +typedef void (*AccessBridge_MouseClickedFP) (long vmID, JOBJECT64 event, JOBJECT64 source); +typedef void (*AccessBridge_MouseEnteredFP) (long vmID, JOBJECT64 event, JOBJECT64 source); +typedef void (*AccessBridge_MouseExitedFP) (long vmID, JOBJECT64 event, JOBJECT64 source); +typedef void (*AccessBridge_MousePressedFP) (long vmID, JOBJECT64 event, JOBJECT64 source); +typedef void (*AccessBridge_MouseReleasedFP) (long vmID, JOBJECT64 event, JOBJECT64 source); + +typedef void (*AccessBridge_MenuCanceledFP) (long vmID, JOBJECT64 event, JOBJECT64 source); +typedef void (*AccessBridge_MenuDeselectedFP) (long vmID, JOBJECT64 event, JOBJECT64 source); +typedef void (*AccessBridge_MenuSelectedFP) (long vmID, JOBJECT64 event, JOBJECT64 source); +typedef void (*AccessBridge_PopupMenuCanceledFP) (long vmID, JOBJECT64 event, JOBJECT64 source); +typedef void (*AccessBridge_PopupMenuWillBecomeInvisibleFP) (long vmID, JOBJECT64 event, JOBJECT64 source); +typedef void (*AccessBridge_PopupMenuWillBecomeVisibleFP) (long vmID, JOBJECT64 event, JOBJECT64 source); + +typedef void (*AccessBridge_PropertyNameChangeFP) (long vmID, JOBJECT64 event, JOBJECT64 source, + wchar_t *oldName, wchar_t *newName); +typedef void (*AccessBridge_PropertyDescriptionChangeFP) (long vmID, JOBJECT64 event, JOBJECT64 source, + wchar_t *oldDescription, wchar_t *newDescription); +typedef void (*AccessBridge_PropertyStateChangeFP) (long vmID, JOBJECT64 event, JOBJECT64 source, + wchar_t *oldState, wchar_t *newState); +typedef void (*AccessBridge_PropertyValueChangeFP) (long vmID, JOBJECT64 event, JOBJECT64 source, + wchar_t *oldValue, wchar_t *newValue); +typedef void (*AccessBridge_PropertySelectionChangeFP) (long vmID, JOBJECT64 event, JOBJECT64 source); +typedef void (*AccessBridge_PropertyTextChangeFP) (long vmID, JOBJECT64 event, JOBJECT64 source); +typedef void (*AccessBridge_PropertyCaretChangeFP) (long vmID, JOBJECT64 event, JOBJECT64 source, + int oldPosition, int newPosition); +typedef void (*AccessBridge_PropertyVisibleDataChangeFP) (long vmID, JOBJECT64 event, JOBJECT64 source); +typedef void (*AccessBridge_PropertyChildChangeFP) (long vmID, JOBJECT64 event, JOBJECT64 source, + JOBJECT64 oldChild, JOBJECT64 newChild); +typedef void (*AccessBridge_PropertyActiveDescendentChangeFP) (long vmID, JOBJECT64 event, + JOBJECT64 source, + JOBJECT64 oldActiveDescendent, + JOBJECT64 newActiveDescendent); + +typedef void (*AccessBridge_PropertyTableModelChangeFP) (long vmID, JOBJECT64 event, JOBJECT64 src, + wchar_t *oldValue, wchar_t *newValue); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/core/esmf-tree-sitter-turtle/src/main/c/include/windows/bridge/AccessBridgeCalls.h b/core/esmf-tree-sitter-turtle/src/main/c/include/windows/bridge/AccessBridgeCalls.h new file mode 100755 index 000000000..b2d95f643 --- /dev/null +++ b/core/esmf-tree-sitter-turtle/src/main/c/include/windows/bridge/AccessBridgeCalls.h @@ -0,0 +1,724 @@ +/* + * Copyright (c) 2005, 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* Note: In addition to this header file AccessBridgeCalls.c must be compiled and + * linked to your application. AccessBridgeCalls.c implements the Java Access + * Bridge API and also hides the complexities associated with interfacing to the + * associated Java Access Bridge DLL which is installed when Java is installed. + * + * AccessBridgeCalls.c is available for download from the OpenJDK repository using + * the following link: + * + * https://git.openjdk.org/jdk17/blob/master/src/jdk.accessibility/windows/native/bridge/AccessBridgeCalls.c + * + * Also note that the API is used in the jaccessinspector and jaccesswalker tools. + * The source for those tools is available in the OpenJDK repository at these links: + * + * https://git.openjdk.org/jdk17/blob/master/src/jdk.accessibility/windows/native/jaccessinspector/jaccessinspector.cpp + * https://git.openjdk.org/jdk17/blob/master/src/jdk.accessibility/windows/native/jaccesswalker/jaccesswalker.cpp + * + * + */ + +/* + * Wrapper functions around calls to the AccessBridge DLL + */ + +#include +#include +#include "AccessBridgeCallbacks.h" +#include "AccessBridgePackages.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define null NULL + + typedef JOBJECT64 AccessibleContext; + typedef JOBJECT64 AccessibleText; + typedef JOBJECT64 AccessibleValue; + typedef JOBJECT64 AccessibleSelection; + typedef JOBJECT64 Java_Object; + typedef JOBJECT64 PropertyChangeEvent; + typedef JOBJECT64 FocusEvent; + typedef JOBJECT64 CaretEvent; + typedef JOBJECT64 MouseEvent; + typedef JOBJECT64 MenuEvent; + typedef JOBJECT64 AccessibleTable; + typedef JOBJECT64 AccessibleHyperlink; + typedef JOBJECT64 AccessibleHypertext; + + + typedef void (*Windows_runFP) (); + + typedef void (*SetPropertyChangeFP) (AccessBridge_PropertyChangeFP fp); + + typedef void (*SetJavaShutdownFP) (AccessBridge_JavaShutdownFP fp); + typedef void (*SetFocusGainedFP) (AccessBridge_FocusGainedFP fp); + typedef void (*SetFocusLostFP) (AccessBridge_FocusLostFP fp); + + typedef void (*SetCaretUpdateFP) (AccessBridge_CaretUpdateFP fp); + + typedef void (*SetMouseClickedFP) (AccessBridge_MouseClickedFP fp); + typedef void (*SetMouseEnteredFP) (AccessBridge_MouseEnteredFP fp); + typedef void (*SetMouseExitedFP) (AccessBridge_MouseExitedFP fp); + typedef void (*SetMousePressedFP) (AccessBridge_MousePressedFP fp); + typedef void (*SetMouseReleasedFP) (AccessBridge_MouseReleasedFP fp); + + typedef void (*SetMenuCanceledFP) (AccessBridge_MenuCanceledFP fp); + typedef void (*SetMenuDeselectedFP) (AccessBridge_MenuDeselectedFP fp); + typedef void (*SetMenuSelectedFP) (AccessBridge_MenuSelectedFP fp); + typedef void (*SetPopupMenuCanceledFP) (AccessBridge_PopupMenuCanceledFP fp); + typedef void (*SetPopupMenuWillBecomeInvisibleFP) (AccessBridge_PopupMenuWillBecomeInvisibleFP fp); + typedef void (*SetPopupMenuWillBecomeVisibleFP) (AccessBridge_PopupMenuWillBecomeVisibleFP fp); + + typedef void (*SetPropertyNameChangeFP) (AccessBridge_PropertyNameChangeFP fp); + typedef void (*SetPropertyDescriptionChangeFP) (AccessBridge_PropertyDescriptionChangeFP fp); + typedef void (*SetPropertyStateChangeFP) (AccessBridge_PropertyStateChangeFP fp); + typedef void (*SetPropertyValueChangeFP) (AccessBridge_PropertyValueChangeFP fp); + typedef void (*SetPropertySelectionChangeFP) (AccessBridge_PropertySelectionChangeFP fp); + typedef void (*SetPropertyTextChangeFP) (AccessBridge_PropertyTextChangeFP fp); + typedef void (*SetPropertyCaretChangeFP) (AccessBridge_PropertyCaretChangeFP fp); + typedef void (*SetPropertyVisibleDataChangeFP) (AccessBridge_PropertyVisibleDataChangeFP fp); + typedef void (*SetPropertyChildChangeFP) (AccessBridge_PropertyChildChangeFP fp); + typedef void (*SetPropertyActiveDescendentChangeFP) (AccessBridge_PropertyActiveDescendentChangeFP fp); + + typedef void (*SetPropertyTableModelChangeFP) (AccessBridge_PropertyTableModelChangeFP fp); + + typedef void (*ReleaseJavaObjectFP) (long vmID, Java_Object object); + + typedef BOOL (*GetVersionInfoFP) (long vmID, AccessBridgeVersionInfo *info); + + typedef BOOL (*IsJavaWindowFP) (HWND window); + typedef BOOL (*IsSameObjectFP) (long vmID, JOBJECT64 obj1, JOBJECT64 obj2); + typedef BOOL (*GetAccessibleContextFromHWNDFP) (HWND window, long *vmID, AccessibleContext *ac); + typedef HWND (*getHWNDFromAccessibleContextFP) (long vmID, AccessibleContext ac); + + typedef BOOL (*GetAccessibleContextAtFP) (long vmID, AccessibleContext acParent, + jint x, jint y, AccessibleContext *ac); + typedef BOOL (*GetAccessibleContextWithFocusFP) (HWND window, long *vmID, AccessibleContext *ac); + typedef BOOL (*GetAccessibleContextInfoFP) (long vmID, AccessibleContext ac, AccessibleContextInfo *info); + typedef AccessibleContext (*GetAccessibleChildFromContextFP) (long vmID, AccessibleContext ac, jint i); + typedef AccessibleContext (*GetAccessibleParentFromContextFP) (long vmID, AccessibleContext ac); + + /* begin AccessibleTable */ + typedef BOOL (*getAccessibleTableInfoFP) (long vmID, AccessibleContext ac, AccessibleTableInfo *tableInfo); + typedef BOOL (*getAccessibleTableCellInfoFP) (long vmID, AccessibleTable accessibleTable, + jint row, jint column, AccessibleTableCellInfo *tableCellInfo); + + typedef BOOL (*getAccessibleTableRowHeaderFP) (long vmID, AccessibleContext acParent, AccessibleTableInfo *tableInfo); + typedef BOOL (*getAccessibleTableColumnHeaderFP) (long vmID, AccessibleContext acParent, AccessibleTableInfo *tableInfo); + + typedef AccessibleContext (*getAccessibleTableRowDescriptionFP) (long vmID, AccessibleContext acParent, jint row); + typedef AccessibleContext (*getAccessibleTableColumnDescriptionFP) (long vmID, AccessibleContext acParent, jint column); + + typedef jint (*getAccessibleTableRowSelectionCountFP) (long vmID, AccessibleTable table); + typedef BOOL (*isAccessibleTableRowSelectedFP) (long vmID, AccessibleTable table, jint row); + typedef BOOL (*getAccessibleTableRowSelectionsFP) (long vmID, AccessibleTable table, jint count, + jint *selections); + + typedef jint (*getAccessibleTableColumnSelectionCountFP) (long vmID, AccessibleTable table); + typedef BOOL (*isAccessibleTableColumnSelectedFP) (long vmID, AccessibleTable table, jint column); + typedef BOOL (*getAccessibleTableColumnSelectionsFP) (long vmID, AccessibleTable table, jint count, + jint *selections); + + typedef jint (*getAccessibleTableRowFP) (long vmID, AccessibleTable table, jint index); + typedef jint (*getAccessibleTableColumnFP) (long vmID, AccessibleTable table, jint index); + typedef jint (*getAccessibleTableIndexFP) (long vmID, AccessibleTable table, jint row, jint column); + /* end AccessibleTable */ + + /* AccessibleRelationSet */ + typedef BOOL (*getAccessibleRelationSetFP) (long vmID, AccessibleContext accessibleContext, + AccessibleRelationSetInfo *relationSetInfo); + + /* AccessibleHypertext */ + typedef BOOL (*getAccessibleHypertextFP)(long vmID, AccessibleContext accessibleContext, + AccessibleHypertextInfo *hypertextInfo); + + typedef BOOL (*activateAccessibleHyperlinkFP)(long vmID, AccessibleContext accessibleContext, + AccessibleHyperlink accessibleHyperlink); + + typedef jint (*getAccessibleHyperlinkCountFP)(const long vmID, + const AccessibleContext accessibleContext); + + typedef BOOL (*getAccessibleHypertextExtFP) (const long vmID, + const AccessibleContext accessibleContext, + const jint nStartIndex, + AccessibleHypertextInfo *hypertextInfo); + + typedef jint (*getAccessibleHypertextLinkIndexFP)(const long vmID, + const AccessibleHypertext hypertext, + const jint nIndex); + + typedef BOOL (*getAccessibleHyperlinkFP)(const long vmID, + const AccessibleHypertext hypertext, + const jint nIndex, + AccessibleHyperlinkInfo *hyperlinkInfo); + + + /* Accessible KeyBindings, Icons and Actions */ + typedef BOOL (*getAccessibleKeyBindingsFP)(long vmID, AccessibleContext accessibleContext, + AccessibleKeyBindings *keyBindings); + + typedef BOOL (*getAccessibleIconsFP)(long vmID, AccessibleContext accessibleContext, + AccessibleIcons *icons); + + typedef BOOL (*getAccessibleActionsFP)(long vmID, AccessibleContext accessibleContext, + AccessibleActions *actions); + + typedef BOOL (*doAccessibleActionsFP)(long vmID, AccessibleContext accessibleContext, + AccessibleActionsToDo *actionsToDo, jint *failure); + + + /* AccessibleText */ + + typedef BOOL (*GetAccessibleTextInfoFP) (long vmID, AccessibleText at, AccessibleTextInfo *textInfo, jint x, jint y); + typedef BOOL (*GetAccessibleTextItemsFP) (long vmID, AccessibleText at, AccessibleTextItemsInfo *textItems, jint index); + typedef BOOL (*GetAccessibleTextSelectionInfoFP) (long vmID, AccessibleText at, AccessibleTextSelectionInfo *textSelection); + typedef BOOL (*GetAccessibleTextAttributesFP) (long vmID, AccessibleText at, jint index, AccessibleTextAttributesInfo *attributes); + typedef BOOL (*GetAccessibleTextRectFP) (long vmID, AccessibleText at, AccessibleTextRectInfo *rectInfo, jint index); + typedef BOOL (*GetAccessibleTextLineBoundsFP) (long vmID, AccessibleText at, jint index, jint *startIndex, jint *endIndex); + typedef BOOL (*GetAccessibleTextRangeFP) (long vmID, AccessibleText at, jint start, jint end, wchar_t *text, short len); + + typedef BOOL (*GetCurrentAccessibleValueFromContextFP) (long vmID, AccessibleValue av, wchar_t *value, short len); + typedef BOOL (*GetMaximumAccessibleValueFromContextFP) (long vmID, AccessibleValue av, wchar_t *value, short len); + typedef BOOL (*GetMinimumAccessibleValueFromContextFP) (long vmID, AccessibleValue av, wchar_t *value, short len); + + typedef void (*AddAccessibleSelectionFromContextFP) (long vmID, AccessibleSelection as, int i); + typedef void (*ClearAccessibleSelectionFromContextFP) (long vmID, AccessibleSelection as); + typedef JOBJECT64 (*GetAccessibleSelectionFromContextFP) (long vmID, AccessibleSelection as, int i); + typedef int (*GetAccessibleSelectionCountFromContextFP) (long vmID, AccessibleSelection as); + typedef BOOL (*IsAccessibleChildSelectedFromContextFP) (long vmID, AccessibleSelection as, int i); + typedef void (*RemoveAccessibleSelectionFromContextFP) (long vmID, AccessibleSelection as, int i); + typedef void (*SelectAllAccessibleSelectionFromContextFP) (long vmID, AccessibleSelection as); + + /* Utility methods */ + + typedef BOOL (*setTextContentsFP) (const long vmID, const AccessibleContext ac, const wchar_t *text); + typedef AccessibleContext (*getParentWithRoleFP) (const long vmID, const AccessibleContext ac, const wchar_t *role); + typedef AccessibleContext (*getParentWithRoleElseRootFP) (const long vmID, const AccessibleContext ac, const wchar_t *role); + typedef AccessibleContext (*getTopLevelObjectFP) (const long vmID, const AccessibleContext ac); + typedef int (*getObjectDepthFP) (const long vmID, const AccessibleContext ac); + typedef AccessibleContext (*getActiveDescendentFP) (const long vmID, const AccessibleContext ac); + + + typedef BOOL (*getVirtualAccessibleNameFP) (const long vmID, const AccessibleContext accessibleContext, + wchar_t *name, int len); + + typedef BOOL (*requestFocusFP) (const long vmID, const AccessibleContext accessibleContext); + + typedef BOOL (*selectTextRangeFP) (const long vmID, const AccessibleContext accessibleContext, + const int startIndex, const int endIndex); + + typedef BOOL (*getTextAttributesInRangeFP) (const long vmID, const AccessibleContext accessibleContext, + const int startIndex, const int endIndex, + AccessibleTextAttributesInfo *attributes, short *len); + + typedef int (*getVisibleChildrenCountFP) (const long vmID, const AccessibleContext accessibleContext); + + typedef BOOL (*getVisibleChildrenFP) (const long vmID, const AccessibleContext accessibleContext, + const int startIndex, VisibleChildrenInfo *children); + + typedef BOOL (*setCaretPositionFP) (const long vmID, const AccessibleContext accessibleContext, const int position); + + typedef BOOL (*getCaretLocationFP) (long vmID, AccessibleContext ac, AccessibleTextRectInfo *rectInfo, jint index); + + typedef int (*getEventsWaitingFP) (); + + typedef struct AccessBridgeFPsTag { + Windows_runFP Windows_run; + + SetPropertyChangeFP SetPropertyChange; + + SetJavaShutdownFP SetJavaShutdown; + SetFocusGainedFP SetFocusGained; + SetFocusLostFP SetFocusLost; + + SetCaretUpdateFP SetCaretUpdate; + + SetMouseClickedFP SetMouseClicked; + SetMouseEnteredFP SetMouseEntered; + SetMouseExitedFP SetMouseExited; + SetMousePressedFP SetMousePressed; + SetMouseReleasedFP SetMouseReleased; + + SetMenuCanceledFP SetMenuCanceled; + SetMenuDeselectedFP SetMenuDeselected; + SetMenuSelectedFP SetMenuSelected; + SetPopupMenuCanceledFP SetPopupMenuCanceled; + SetPopupMenuWillBecomeInvisibleFP SetPopupMenuWillBecomeInvisible; + SetPopupMenuWillBecomeVisibleFP SetPopupMenuWillBecomeVisible; + + SetPropertyNameChangeFP SetPropertyNameChange; + SetPropertyDescriptionChangeFP SetPropertyDescriptionChange; + SetPropertyStateChangeFP SetPropertyStateChange; + SetPropertyValueChangeFP SetPropertyValueChange; + SetPropertySelectionChangeFP SetPropertySelectionChange; + SetPropertyTextChangeFP SetPropertyTextChange; + SetPropertyCaretChangeFP SetPropertyCaretChange; + SetPropertyVisibleDataChangeFP SetPropertyVisibleDataChange; + SetPropertyChildChangeFP SetPropertyChildChange; + SetPropertyActiveDescendentChangeFP SetPropertyActiveDescendentChange; + + SetPropertyTableModelChangeFP SetPropertyTableModelChange; + + ReleaseJavaObjectFP ReleaseJavaObject; + GetVersionInfoFP GetVersionInfo; + + IsJavaWindowFP IsJavaWindow; + IsSameObjectFP IsSameObject; + GetAccessibleContextFromHWNDFP GetAccessibleContextFromHWND; + getHWNDFromAccessibleContextFP getHWNDFromAccessibleContext; + + GetAccessibleContextAtFP GetAccessibleContextAt; + GetAccessibleContextWithFocusFP GetAccessibleContextWithFocus; + GetAccessibleContextInfoFP GetAccessibleContextInfo; + GetAccessibleChildFromContextFP GetAccessibleChildFromContext; + GetAccessibleParentFromContextFP GetAccessibleParentFromContext; + + getAccessibleTableInfoFP getAccessibleTableInfo; + getAccessibleTableCellInfoFP getAccessibleTableCellInfo; + + getAccessibleTableRowHeaderFP getAccessibleTableRowHeader; + getAccessibleTableColumnHeaderFP getAccessibleTableColumnHeader; + + getAccessibleTableRowDescriptionFP getAccessibleTableRowDescription; + getAccessibleTableColumnDescriptionFP getAccessibleTableColumnDescription; + + getAccessibleTableRowSelectionCountFP getAccessibleTableRowSelectionCount; + isAccessibleTableRowSelectedFP isAccessibleTableRowSelected; + getAccessibleTableRowSelectionsFP getAccessibleTableRowSelections; + + getAccessibleTableColumnSelectionCountFP getAccessibleTableColumnSelectionCount; + isAccessibleTableColumnSelectedFP isAccessibleTableColumnSelected; + getAccessibleTableColumnSelectionsFP getAccessibleTableColumnSelections; + + getAccessibleTableRowFP getAccessibleTableRow; + getAccessibleTableColumnFP getAccessibleTableColumn; + getAccessibleTableIndexFP getAccessibleTableIndex; + + getAccessibleRelationSetFP getAccessibleRelationSet; + + getAccessibleHypertextFP getAccessibleHypertext; + activateAccessibleHyperlinkFP activateAccessibleHyperlink; + getAccessibleHyperlinkCountFP getAccessibleHyperlinkCount; + getAccessibleHypertextExtFP getAccessibleHypertextExt; + getAccessibleHypertextLinkIndexFP getAccessibleHypertextLinkIndex; + getAccessibleHyperlinkFP getAccessibleHyperlink; + + getAccessibleKeyBindingsFP getAccessibleKeyBindings; + getAccessibleIconsFP getAccessibleIcons; + getAccessibleActionsFP getAccessibleActions; + doAccessibleActionsFP doAccessibleActions; + + GetAccessibleTextInfoFP GetAccessibleTextInfo; + GetAccessibleTextItemsFP GetAccessibleTextItems; + GetAccessibleTextSelectionInfoFP GetAccessibleTextSelectionInfo; + GetAccessibleTextAttributesFP GetAccessibleTextAttributes; + GetAccessibleTextRectFP GetAccessibleTextRect; + GetAccessibleTextLineBoundsFP GetAccessibleTextLineBounds; + GetAccessibleTextRangeFP GetAccessibleTextRange; + + GetCurrentAccessibleValueFromContextFP GetCurrentAccessibleValueFromContext; + GetMaximumAccessibleValueFromContextFP GetMaximumAccessibleValueFromContext; + GetMinimumAccessibleValueFromContextFP GetMinimumAccessibleValueFromContext; + + AddAccessibleSelectionFromContextFP AddAccessibleSelectionFromContext; + ClearAccessibleSelectionFromContextFP ClearAccessibleSelectionFromContext; + GetAccessibleSelectionFromContextFP GetAccessibleSelectionFromContext; + GetAccessibleSelectionCountFromContextFP GetAccessibleSelectionCountFromContext; + IsAccessibleChildSelectedFromContextFP IsAccessibleChildSelectedFromContext; + RemoveAccessibleSelectionFromContextFP RemoveAccessibleSelectionFromContext; + SelectAllAccessibleSelectionFromContextFP SelectAllAccessibleSelectionFromContext; + + setTextContentsFP setTextContents; + getParentWithRoleFP getParentWithRole; + getTopLevelObjectFP getTopLevelObject; + getParentWithRoleElseRootFP getParentWithRoleElseRoot; + getObjectDepthFP getObjectDepth; + getActiveDescendentFP getActiveDescendent; + + getVirtualAccessibleNameFP getVirtualAccessibleName; + requestFocusFP requestFocus; + selectTextRangeFP selectTextRange; + getTextAttributesInRangeFP getTextAttributesInRange; + getVisibleChildrenCountFP getVisibleChildrenCount; + getVisibleChildrenFP getVisibleChildren; + setCaretPositionFP setCaretPosition; + getCaretLocationFP getCaretLocation; + + getEventsWaitingFP getEventsWaiting; + + } AccessBridgeFPs; + + + /** + * Initialize the world + */ + BOOL initializeAccessBridge(); + BOOL shutdownAccessBridge(); + + /** + * Window routines + */ + BOOL IsJavaWindow(HWND window); + + // Returns the virtual machine ID and AccessibleContext for a top-level window + BOOL GetAccessibleContextFromHWND(HWND target, long *vmID, AccessibleContext *ac); + + // Returns the HWND from the AccessibleContext of a top-level window + HWND getHWNDFromAccessibleContext(long vmID, AccessibleContext ac); + + + /** + * Event handling routines + */ + void SetJavaShutdown(AccessBridge_JavaShutdownFP fp); + void SetFocusGained(AccessBridge_FocusGainedFP fp); + void SetFocusLost(AccessBridge_FocusLostFP fp); + + void SetCaretUpdate(AccessBridge_CaretUpdateFP fp); + + void SetMouseClicked(AccessBridge_MouseClickedFP fp); + void SetMouseEntered(AccessBridge_MouseEnteredFP fp); + void SetMouseExited(AccessBridge_MouseExitedFP fp); + void SetMousePressed(AccessBridge_MousePressedFP fp); + void SetMouseReleased(AccessBridge_MouseReleasedFP fp); + + void SetMenuCanceled(AccessBridge_MenuCanceledFP fp); + void SetMenuDeselected(AccessBridge_MenuDeselectedFP fp); + void SetMenuSelected(AccessBridge_MenuSelectedFP fp); + void SetPopupMenuCanceled(AccessBridge_PopupMenuCanceledFP fp); + void SetPopupMenuWillBecomeInvisible(AccessBridge_PopupMenuWillBecomeInvisibleFP fp); + void SetPopupMenuWillBecomeVisible(AccessBridge_PopupMenuWillBecomeVisibleFP fp); + + void SetPropertyNameChange(AccessBridge_PropertyNameChangeFP fp); + void SetPropertyDescriptionChange(AccessBridge_PropertyDescriptionChangeFP fp); + void SetPropertyStateChange(AccessBridge_PropertyStateChangeFP fp); + void SetPropertyValueChange(AccessBridge_PropertyValueChangeFP fp); + void SetPropertySelectionChange(AccessBridge_PropertySelectionChangeFP fp); + void SetPropertyTextChange(AccessBridge_PropertyTextChangeFP fp); + void SetPropertyCaretChange(AccessBridge_PropertyCaretChangeFP fp); + void SetPropertyVisibleDataChange(AccessBridge_PropertyVisibleDataChangeFP fp); + void SetPropertyChildChange(AccessBridge_PropertyChildChangeFP fp); + void SetPropertyActiveDescendentChange(AccessBridge_PropertyActiveDescendentChangeFP fp); + + void SetPropertyTableModelChange(AccessBridge_PropertyTableModelChangeFP fp); + + + /** + * General routines + */ + void ReleaseJavaObject(long vmID, Java_Object object); + BOOL GetVersionInfo(long vmID, AccessBridgeVersionInfo *info); + HWND GetHWNDFromAccessibleContext(long vmID, JOBJECT64 accesibleContext); + + /** + * Accessible Context routines + */ + BOOL GetAccessibleContextAt(long vmID, AccessibleContext acParent, + jint x, jint y, AccessibleContext *ac); + BOOL GetAccessibleContextWithFocus(HWND window, long *vmID, AccessibleContext *ac); + BOOL GetAccessibleContextInfo(long vmID, AccessibleContext ac, AccessibleContextInfo *info); + AccessibleContext GetAccessibleChildFromContext(long vmID, AccessibleContext ac, jint index); + AccessibleContext GetAccessibleParentFromContext(long vmID, AccessibleContext ac); + + /** + * Accessible Text routines + */ + BOOL GetAccessibleTextInfo(long vmID, AccessibleText at, AccessibleTextInfo *textInfo, jint x, jint y); + BOOL GetAccessibleTextItems(long vmID, AccessibleText at, AccessibleTextItemsInfo *textItems, jint index); + BOOL GetAccessibleTextSelectionInfo(long vmID, AccessibleText at, AccessibleTextSelectionInfo *textSelection); + BOOL GetAccessibleTextAttributes(long vmID, AccessibleText at, jint index, AccessibleTextAttributesInfo *attributes); + BOOL GetAccessibleTextRect(long vmID, AccessibleText at, AccessibleTextRectInfo *rectInfo, jint index); + BOOL GetAccessibleTextLineBounds(long vmID, AccessibleText at, jint index, jint *startIndex, jint *endIndex); + BOOL GetAccessibleTextRange(long vmID, AccessibleText at, jint start, jint end, wchar_t *text, short len); + + /* begin AccessibleTable routines */ + BOOL getAccessibleTableInfo(long vmID, AccessibleContext acParent, AccessibleTableInfo *tableInfo); + + BOOL getAccessibleTableCellInfo(long vmID, AccessibleTable accessibleTable, jint row, jint column, + AccessibleTableCellInfo *tableCellInfo); + + BOOL getAccessibleTableRowHeader(long vmID, AccessibleContext acParent, AccessibleTableInfo *tableInfo); + BOOL getAccessibleTableColumnHeader(long vmID, AccessibleContext acParent, AccessibleTableInfo *tableInfo); + + AccessibleContext getAccessibleTableRowDescription(long vmID, AccessibleContext acParent, jint row); + AccessibleContext getAccessibleTableColumnDescription(long vmID, AccessibleContext acParent, jint column); + + jint getAccessibleTableRowSelectionCount(long vmID, AccessibleTable table); + BOOL isAccessibleTableRowSelected(long vmID, AccessibleTable table, jint row); + BOOL getAccessibleTableRowSelections(long vmID, AccessibleTable table, jint count, jint *selections); + + jint getAccessibleTableColumnSelectionCount(long vmID, AccessibleTable table); + BOOL isAccessibleTableColumnSelected(long vmID, AccessibleTable table, jint column); + BOOL getAccessibleTableColumnSelections(long vmID, AccessibleTable table, jint count, jint *selections); + + jint getAccessibleTableRow(long vmID, AccessibleTable table, jint index); + jint getAccessibleTableColumn(long vmID, AccessibleTable table, jint index); + jint getAccessibleTableIndex(long vmID, AccessibleTable table, jint row, jint column); + /* end AccessibleTable */ + + /* ----- AccessibleRelationSet routines */ + BOOL getAccessibleRelationSet(long vmID, AccessibleContext accessibleContext, + AccessibleRelationSetInfo *relationSetInfo); + + /* ----- AccessibleHypertext routines */ + + /* + * Returns hypertext information associated with a component. + */ + BOOL getAccessibleHypertext(long vmID, AccessibleContext accessibleContext, + AccessibleHypertextInfo *hypertextInfo); + + /* + * Requests that a hyperlink be activated. + */ + BOOL activateAccessibleHyperlink(long vmID, AccessibleContext accessibleContext, + AccessibleHyperlink accessibleHyperlink); + + /* + * Returns the number of hyperlinks in a component + * Maps to AccessibleHypertext.getLinkCount. + * Returns -1 on error. + */ + jint getAccessibleHyperlinkCount(const long vmID, + const AccessibleHypertext hypertext); + + /* + * This method is used to iterate through the hyperlinks in a component. It + * returns hypertext information for a component starting at hyperlink index + * nStartIndex. No more than MAX_HYPERLINKS AccessibleHypertextInfo objects will + * be returned for each call to this method. + * Returns FALSE on error. + */ + BOOL getAccessibleHypertextExt(const long vmID, + const AccessibleContext accessibleContext, + const jint nStartIndex, + /* OUT */ AccessibleHypertextInfo *hypertextInfo); + + /* + * Returns the index into an array of hyperlinks that is associated with + * a character index in document; maps to AccessibleHypertext.getLinkIndex + * Returns -1 on error. + */ + jint getAccessibleHypertextLinkIndex(const long vmID, + const AccessibleHypertext hypertext, + const jint nIndex); + + /* + * Returns the nth hyperlink in a document + * Maps to AccessibleHypertext.getLink. + * Returns FALSE on error + */ + BOOL getAccessibleHyperlink(const long vmID, + const AccessibleHypertext hypertext, + const jint nIndex, + /* OUT */ AccessibleHyperlinkInfo *hyperlinkInfo); + + /* Accessible KeyBindings, Icons and Actions */ + + /* + * Returns a list of key bindings associated with a component. + */ + BOOL getAccessibleKeyBindings(long vmID, AccessibleContext accessibleContext, + AccessibleKeyBindings *keyBindings); + + /* + * Returns a list of icons associate with a component. + */ + BOOL getAccessibleIcons(long vmID, AccessibleContext accessibleContext, + AccessibleIcons *icons); + + /* + * Returns a list of actions that a component can perform. + */ + BOOL getAccessibleActions(long vmID, AccessibleContext accessibleContext, + AccessibleActions *actions); + + /* + * Request that a list of AccessibleActions be performed by a component. + * Returns TRUE if all actions are performed. Returns FALSE + * when the first requested action fails in which case "failure" + * contains the index of the action that failed. + */ + BOOL doAccessibleActions(long vmID, AccessibleContext accessibleContext, + AccessibleActionsToDo *actionsToDo, jint *failure); + + + + /* Additional utility methods */ + + /* + * Returns whether two object references refer to the same object. + */ + BOOL IsSameObject(long vmID, JOBJECT64 obj1, JOBJECT64 obj2); + + /** + * Sets editable text contents. The AccessibleContext must implement AccessibleEditableText and + * be editable. The maximum text length that can be set is MAX_STRING_SIZE - 1. + * Returns whether successful + */ + BOOL setTextContents (const long vmID, const AccessibleContext accessibleContext, const wchar_t *text); + + /** + * Returns the Accessible Context with the specified role that is the + * ancestor of a given object. The role is one of the role strings + * defined in AccessBridgePackages.h + * If there is no ancestor object that has the specified role, + * returns (AccessibleContext)0. + */ + AccessibleContext getParentWithRole (const long vmID, const AccessibleContext accessibleContext, + const wchar_t *role); + + /** + * Returns the Accessible Context with the specified role that is the + * ancestor of a given object. The role is one of the role strings + * defined in AccessBridgePackages.h. If an object with the specified + * role does not exist, returns the top level object for the Java Window. + * Returns (AccessibleContext)0 on error. + */ + AccessibleContext getParentWithRoleElseRoot (const long vmID, const AccessibleContext accessibleContext, + const wchar_t *role); + + /** + * Returns the Accessible Context for the top level object in + * a Java Window. This is same Accessible Context that is obtained + * from GetAccessibleContextFromHWND for that window. Returns + * (AccessibleContext)0 on error. + */ + AccessibleContext getTopLevelObject (const long vmID, const AccessibleContext accessibleContext); + + /** + * Returns how deep in the object hierarchy a given object is. + * The top most object in the object hierarchy has an object depth of 0. + * Returns -1 on error. + */ + int getObjectDepth (const long vmID, const AccessibleContext accessibleContext); + + /** + * Returns the Accessible Context of the current ActiveDescendent of an object. + * This method assumes the ActiveDescendent is the component that is currently + * selected in a container object. + * Returns (AccessibleContext)0 on error or if there is no selection. + */ + AccessibleContext getActiveDescendent (const long vmID, const AccessibleContext accessibleContext); + + /** + * Accessible Value routines + */ + BOOL GetCurrentAccessibleValueFromContext(long vmID, AccessibleValue av, wchar_t *value, short len); + BOOL GetMaximumAccessibleValueFromContext(long vmID, AccessibleValue av, wchar_t *value, short len); + BOOL GetMinimumAccessibleValueFromContext(long vmID, AccessibleValue av, wchar_t *value, short len); + + /** + * Accessible Selection routines + */ + void AddAccessibleSelectionFromContext(long vmID, AccessibleSelection as, int i); + void ClearAccessibleSelectionFromContext(long vmID, AccessibleSelection as); + JOBJECT64 GetAccessibleSelectionFromContext(long vmID, AccessibleSelection as, int i); + int GetAccessibleSelectionCountFromContext(long vmID, AccessibleSelection as); + BOOL IsAccessibleChildSelectedFromContext(long vmID, AccessibleSelection as, int i); + void RemoveAccessibleSelectionFromContext(long vmID, AccessibleSelection as, int i); + void SelectAllAccessibleSelectionFromContext(long vmID, AccessibleSelection as); + + /** + * Additional methods for Teton + */ + + /** + * Gets the AccessibleName for a component based upon the JAWS algorithm. Returns + * whether successful. + * + * Bug ID 4916682 - Implement JAWS AccessibleName policy + */ + BOOL getVirtualAccessibleName(const long vmID, const AccessibleContext accessibleContext, + wchar_t *name, int len); + + /** + * Request focus for a component. Returns whether successful. + * + * Bug ID 4944757 - requestFocus method needed + */ + BOOL requestFocus(const long vmID, const AccessibleContext accessibleContext); + + /** + * Selects text between two indices. Selection includes the text at the start index + * and the text at the end index. Returns whether successful. + * + * Bug ID 4944758 - selectTextRange method needed + */ + BOOL selectTextRange(const long vmID, const AccessibleContext accessibleContext, const int startIndex, + const int endIndex); + + /** + * Get text attributes between two indices. The attribute list includes the text at the + * start index and the text at the end index. Returns whether successful; + * + * Bug ID 4944761 - getTextAttributes between two indices method needed + */ + BOOL getTextAttributesInRange(const long vmID, const AccessibleContext accessibleContext, + const int startIndex, const int endIndex, + AccessibleTextAttributesInfo *attributes, short *len); + + /** + * Returns the number of visible children of a component. Returns -1 on error. + * + * Bug ID 4944762- getVisibleChildren for list-like components needed + */ + int getVisibleChildrenCount(const long vmID, const AccessibleContext accessibleContext); + + /** + * Gets the visible children of an AccessibleContext. Returns whether successful. + * + * Bug ID 4944762- getVisibleChildren for list-like components needed + */ + BOOL getVisibleChildren(const long vmID, const AccessibleContext accessibleContext, + const int startIndex, + VisibleChildrenInfo *visibleChildrenInfo); + + /** + * Set the caret to a text position. Returns whether successful. + * + * Bug ID 4944770 - setCaretPosition method needed + */ + BOOL setCaretPosition(const long vmID, const AccessibleContext accessibleContext, + const int position); + + /** + * Gets the text caret location + */ + BOOL getCaretLocation(long vmID, AccessibleContext ac, + AccessibleTextRectInfo *rectInfo, jint index); + + /** + * Gets the number of events waiting to fire + */ + int getEventsWaiting(); + +#ifdef __cplusplus +} +#endif diff --git a/core/esmf-tree-sitter-turtle/src/main/c/include/windows/bridge/AccessBridgePackages.h b/core/esmf-tree-sitter-turtle/src/main/c/include/windows/bridge/AccessBridgePackages.h new file mode 100755 index 000000000..232cab4b2 --- /dev/null +++ b/core/esmf-tree-sitter-turtle/src/main/c/include/windows/bridge/AccessBridgePackages.h @@ -0,0 +1,2217 @@ +/* + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * Header file for packages of paramaters passed between Java Accessibility + * and native Assistive Technologies + */ + +#ifndef __AccessBridgePackages_H__ +#define __AccessBridgePackages_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef ACCESSBRIDGE_ARCH_LEGACY +typedef jobject JOBJECT64; +typedef HWND ABHWND64; +#define ABHandleToLong +#define ABLongToHandle +#else +typedef jlong JOBJECT64; +typedef long ABHWND64; +#define ABHandleToLong HandleToLong +#define ABLongToHandle LongToHandle +#endif + +#define MAX_BUFFER_SIZE 10240 +#define MAX_STRING_SIZE 1024 +#define SHORT_STRING_SIZE 256 + + // object types + typedef JOBJECT64 AccessibleContext; + typedef JOBJECT64 AccessibleText; + typedef JOBJECT64 AccessibleValue; + typedef JOBJECT64 AccessibleSelection; + typedef JOBJECT64 Java_Object; + typedef JOBJECT64 PropertyChangeEvent; + typedef JOBJECT64 FocusEvent; + typedef JOBJECT64 CaretEvent; + typedef JOBJECT64 MouseEvent; + typedef JOBJECT64 MenuEvent; + typedef JOBJECT64 AccessibleTable; + typedef JOBJECT64 AccessibleHyperlink; + typedef JOBJECT64 AccessibleHypertext; + + /** + ****************************************************** + * Java event types + ****************************************************** + */ + +#define cPropertyChangeEvent (jlong) 1 // 1 +#define cFocusGainedEvent (jlong) 2 // 2 +#define cFocusLostEvent (jlong) 4 // 4 +#define cCaretUpdateEvent (jlong) 8 // 8 +#define cMouseClickedEvent (jlong) 16 // 10 +#define cMouseEnteredEvent (jlong) 32 // 20 +#define cMouseExitedEvent (jlong) 64 // 40 +#define cMousePressedEvent (jlong) 128 // 80 +#define cMouseReleasedEvent (jlong) 256 // 100 +#define cMenuCanceledEvent (jlong) 512 // 200 +#define cMenuDeselectedEvent (jlong) 1024 // 400 +#define cMenuSelectedEvent (jlong) 2048 // 800 +#define cPopupMenuCanceledEvent (jlong) 4096 // 1000 +#define cPopupMenuWillBecomeInvisibleEvent (jlong) 8192 // 2000 +#define cPopupMenuWillBecomeVisibleEvent (jlong) 16384 // 4000 +#define cJavaShutdownEvent (jlong) 32768 // 8000 + + /** + ****************************************************** + * Accessible Roles + * Defines all AccessibleRoles in Local.US + ****************************************************** + */ + + /** + * Object is used to alert the user about something. + */ +#define ACCESSIBLE_ALERT L"alert" + + /** + * The header for a column of data. + */ +#define ACCESSIBLE_COLUMN_HEADER L"column header" + + /** + * Object that can be drawn into and is used to trap + * events. + * see ACCESSIBLE_FRAME + * see ACCESSIBLE_GLASS_PANE + * see ACCESSIBLE_LAYERED_PANE + */ +#define ACCESSIBLE_CANVAS L"canvas" + + /** + * A list of choices the user can select from. Also optionally + * allows the user to enter a choice of their own. + */ +#define ACCESSIBLE_COMBO_BOX L"combo box" + + /** + * An iconified internal frame in a DESKTOP_PANE. + * see ACCESSIBLE_DESKTOP_PANE + * see ACCESSIBLE_INTERNAL_FRAME + */ +#define ACCESSIBLE_DESKTOP_ICON L"desktop icon" + + /** + * A frame-like object that is clipped by a desktop pane. The + * desktop pane, internal frame, and desktop icon objects are + * often used to create multiple document interfaces within an + * application. + * see ACCESSIBLE_DESKTOP_ICON + * see ACCESSIBLE_DESKTOP_PANE + * see ACCESSIBLE_FRAME + */ +#define ACCESSIBLE_INTERNAL_FRAME L"internal frame" + + /** + * A pane that supports internal frames and + * iconified versions of those internal frames. + * see ACCESSIBLE_DESKTOP_ICON + * see ACCESSIBLE_INTERNAL_FRAME + */ +#define ACCESSIBLE_DESKTOP_PANE L"desktop pane" + + /** + * A specialized pane whose primary use is inside a DIALOG + * see ACCESSIBLE_DIALOG + */ +#define ACCESSIBLE_OPTION_PANE L"option pane" + + /** + * A top level window with no title or border. + * see ACCESSIBLE_FRAME + * see ACCESSIBLE_DIALOG + */ +#define ACCESSIBLE_WINDOW L"window" + + /** + * A top level window with a title bar, border, menu bar, etc. It is + * often used as the primary window for an application. + * see ACCESSIBLE_DIALOG + * see ACCESSIBLE_CANVAS + * see ACCESSIBLE_WINDOW + */ +#define ACCESSIBLE_FRAME L"frame" + + /** + * A top level window with title bar and a border. A dialog is similar + * to a frame, but it has fewer properties and is often used as a + * secondary window for an application. + * see ACCESSIBLE_FRAME + * see ACCESSIBLE_WINDOW + */ +#define ACCESSIBLE_DIALOG L"dialog" + + /** + * A specialized dialog that lets the user choose a color. + */ +#define ACCESSIBLE_COLOR_CHOOSER L"color chooser" + + + /** + * A pane that allows the user to navigate through + * and select the contents of a directory. May be used + * by a file chooser. + * see ACCESSIBLE_FILE_CHOOSER + */ +#define ACCESSIBLE_DIRECTORY_PANE L"directory pane" + + /** + * A specialized dialog that displays the files in the directory + * and lets the user select a file, browse a different directory, + * or specify a filename. May use the directory pane to show the + * contents of a directory. + * see ACCESSIBLE_DIRECTORY_PANE + */ +#define ACCESSIBLE_FILE_CHOOSER L"file chooser" + + /** + * An object that fills up space in a user interface. It is often + * used in interfaces to tweak the spacing between components, + * but serves no other purpose. + */ +#define ACCESSIBLE_FILLER L"filler" + + /** + * A hypertext anchor + */ +#define ACCESSIBLE_HYPERLINK L"hyperlink" + + /** + * A small fixed size picture, typically used to decorate components. + */ +#define ACCESSIBLE_ICON L"icon" + + /** + * An object used to present an icon or short string in an interface. + */ +#define ACCESSIBLE_LABEL L"label" + + /** + * A specialized pane that has a glass pane and a layered pane as its + * children. + * see ACCESSIBLE_GLASS_PANE + * see ACCESSIBLE_LAYERED_PANE + */ +#define ACCESSIBLE_ROOT_PANE L"root pane" + + /** + * A pane that is guaranteed to be painted on top + * of all panes beneath it. + * see ACCESSIBLE_ROOT_PANE + * see ACCESSIBLE_CANVAS + */ +#define ACCESSIBLE_GLASS_PANE L"glass pane" + + /** + * A specialized pane that allows its children to be drawn in layers, + * providing a form of stacking order. This is usually the pane that + * holds the menu bar as well as the pane that contains most of the + * visual components in a window. + * see ACCESSIBLE_GLASS_PANE + * see ACCESSIBLE_ROOT_PANE + */ +#define ACCESSIBLE_LAYERED_PANE L"layered pane" + + /** + * An object that presents a list of objects to the user and allows the + * user to select one or more of them. A list is usually contained + * within a scroll pane. + * see ACCESSIBLE_SCROLL_PANE + * see ACCESSIBLE_LIST_ITEM + */ +#define ACCESSIBLE_LIST L"list" + + /** + * An object that presents an element in a list. A list is usually + * contained within a scroll pane. + * see ACCESSIBLE_SCROLL_PANE + * see ACCESSIBLE_LIST + */ +#define ACCESSIBLE_LIST_ITEM L"list item" + + /** + * An object usually drawn at the top of the primary dialog box of + * an application that contains a list of menus the user can choose + * from. For example, a menu bar might contain menus for "File," + * "Edit," and "Help." + * see ACCESSIBLE_MENU + * see ACCESSIBLE_POPUP_MENU + * see ACCESSIBLE_LAYERED_PANE + */ +#define ACCESSIBLE_MENU_BAR L"menu bar" + + /** + * A temporary window that is usually used to offer the user a + * list of choices, and then hides when the user selects one of + * those choices. + * see ACCESSIBLE_MENU + * see ACCESSIBLE_MENU_ITEM + */ +#define ACCESSIBLE_POPUP_MENU L"popup menu" + + /** + * An object usually found inside a menu bar that contains a list + * of actions the user can choose from. A menu can have any object + * as its children, but most often they are menu items, other menus, + * or rudimentary objects such as radio buttons, check boxes, or + * separators. For example, an application may have an "Edit" menu + * that contains menu items for "Cut" and "Paste." + * see ACCESSIBLE_MENU_BAR + * see ACCESSIBLE_MENU_ITEM + * see ACCESSIBLE_SEPARATOR + * see ACCESSIBLE_RADIO_BUTTON + * see ACCESSIBLE_CHECK_BOX + * see ACCESSIBLE_POPUP_MENU + */ +#define ACCESSIBLE_MENU L"menu" + + /** + * An object usually contained in a menu that presents an action + * the user can choose. For example, the "Cut" menu item in an + * "Edit" menu would be an action the user can select to cut the + * selected area of text in a document. + * see ACCESSIBLE_MENU_BAR + * see ACCESSIBLE_SEPARATOR + * see ACCESSIBLE_POPUP_MENU + */ +#define ACCESSIBLE_MENU_ITEM L"menu item" + + /** + * An object usually contained in a menu to provide a visual + * and logical separation of the contents in a menu. For example, + * the "File" menu of an application might contain menu items for + * "Open," "Close," and "Exit," and will place a separator between + * "Close" and "Exit" menu items. + * see ACCESSIBLE_MENU + * see ACCESSIBLE_MENU_ITEM + */ +#define ACCESSIBLE_SEPARATOR L"separator" + + /** + * An object that presents a series of panels (or page tabs), one at a + * time, through some mechanism provided by the object. The most common + * mechanism is a list of tabs at the top of the panel. The children of + * a page tab list are all page tabs. + * see ACCESSIBLE_PAGE_TAB + */ +#define ACCESSIBLE_PAGE_TAB_LIST L"page tab list" + + /** + * An object that is a child of a page tab list. Its sole child is + * the panel that is to be presented to the user when the user + * selects the page tab from the list of tabs in the page tab list. + * see ACCESSIBLE_PAGE_TAB_LIST + */ +#define ACCESSIBLE_PAGE_TAB L"page tab" + + /** + * A generic container that is often used to group objects. + */ +#define ACCESSIBLE_PANEL L"panel" + + /** + * An object used to indicate how much of a task has been completed. + */ +#define ACCESSIBLE_PROGRESS_BAR L"progress bar" + + /** + * A text object used for passwords, or other places where the + * text contents is not shown visibly to the user + */ +#define ACCESSIBLE_PASSWORD_TEXT L"password text" + + /** + * An object the user can manipulate to tell the application to do + * something. + * see ACCESSIBLE_CHECK_BOX + * see ACCESSIBLE_TOGGLE_BUTTON + * see ACCESSIBLE_RADIO_BUTTON + */ +#define ACCESSIBLE_PUSH_BUTTON L"push button" + + /** + * A specialized push button that can be checked or unchecked, but + * does not provide a separate indicator for the current state. + * see ACCESSIBLE_PUSH_BUTTON + * see ACCESSIBLE_CHECK_BOX + * see ACCESSIBLE_RADIO_BUTTON + */ +#define ACCESSIBLE_TOGGLE_BUTTON L"toggle button" + + /** + * A choice that can be checked or unchecked and provides a + * separate indicator for the current state. + * see ACCESSIBLE_PUSH_BUTTON + * see ACCESSIBLE_TOGGLE_BUTTON + * see ACCESSIBLE_RADIO_BUTTON + */ +#define ACCESSIBLE_CHECK_BOX L"check box" + + /** + * A specialized check box that will cause other radio buttons in the + * same group to become unchecked when this one is checked. + * see ACCESSIBLE_PUSH_BUTTON + * see ACCESSIBLE_TOGGLE_BUTTON + * see ACCESSIBLE_CHECK_BOX + */ +#define ACCESSIBLE_RADIO_BUTTON L"radio button" + + /** + * The header for a row of data. + */ +#define ACCESSIBLE_ROW_HEADER L"row header" + + /** + * An object that allows a user to incrementally view a large amount + * of information. Its children can include scroll bars and a viewport. + * see ACCESSIBLE_SCROLL_BAR + * see ACCESSIBLE_VIEWPORT + */ +#define ACCESSIBLE_SCROLL_PANE L"scroll pane" + + /** + * An object usually used to allow a user to incrementally view a + * large amount of data. Usually used only by a scroll pane. + * see ACCESSIBLE_SCROLL_PANE + */ +#define ACCESSIBLE_SCROLL_BAR L"scroll bar" + + /** + * An object usually used in a scroll pane. It represents the portion + * of the entire data that the user can see. As the user manipulates + * the scroll bars, the contents of the viewport can change. + * see ACCESSIBLE_SCROLL_PANE + */ +#define ACCESSIBLE_VIEWPORT L"viewport" + + /** + * An object that allows the user to select from a bounded range. For + * example, a slider might be used to select a number between 0 and 100. + */ +#define ACCESSIBLE_SLIDER L"slider" + + /** + * A specialized panel that presents two other panels at the same time. + * Between the two panels is a divider the user can manipulate to make + * one panel larger and the other panel smaller. + */ +#define ACCESSIBLE_SPLIT_PANE L"split pane" + + /** + * An object used to present information in terms of rows and columns. + * An example might include a spreadsheet application. + */ +#define ACCESSIBLE_TABLE L"table" + + /** + * An object that presents text to the user. The text is usually + * editable by the user as opposed to a label. + * see ACCESSIBLE_LABEL + */ +#define ACCESSIBLE_TEXT L"text" + + /** + * An object used to present hierarchical information to the user. + * The individual nodes in the tree can be collapsed and expanded + * to provide selective disclosure of the tree's contents. + */ +#define ACCESSIBLE_TREE L"tree" + + /** + * A bar or palette usually composed of push buttons or toggle buttons. + * It is often used to provide the most frequently used functions for an + * application. + */ +#define ACCESSIBLE_TOOL_BAR L"tool bar" + + /** + * An object that provides information about another object. The + * accessibleDescription property of the tool tip is often displayed + * to the user in a small L"help bubble" when the user causes the + * mouse to hover over the object associated with the tool tip. + */ +#define ACCESSIBLE_TOOL_TIP L"tool tip" + + /** + * An AWT component, but nothing else is known about it. + * see ACCESSIBLE_SWING_COMPONENT + * see ACCESSIBLE_UNKNOWN + */ +#define ACCESSIBLE_AWT_COMPONENT L"awt component" + + /** + * A Swing component, but nothing else is known about it. + * see ACCESSIBLE_AWT_COMPONENT + * see ACCESSIBLE_UNKNOWN + */ +#define ACCESSIBLE_SWING_COMPONENT L"swing component" + + /** + * The object contains some Accessible information, but its role is + * not known. + * see ACCESSIBLE_AWT_COMPONENT + * see ACCESSIBLE_SWING_COMPONENT + */ +#define ACCESSIBLE_UNKNOWN L"unknown" + + /** + * A STATUS_BAR is an simple component that can contain + * multiple labels of status information to the user. + */ +#define ACCESSIBLE_STATUS_BAR L"status bar" + + /** + * A DATE_EDITOR is a component that allows users to edit + * java.util.Date and java.util.Time objects + */ +#define ACCESSIBLE_DATE_EDITOR L"date editor" + + /** + * A SPIN_BOX is a simple spinner component and its main use + * is for simple numbers. + */ +#define ACCESSIBLE_SPIN_BOX L"spin box" + + /** + * A FONT_CHOOSER is a component that lets the user pick various + * attributes for fonts. + */ +#define ACCESSIBLE_FONT_CHOOSER L"font chooser" + + /** + * A GROUP_BOX is a simple container that contains a border + * around it and contains components inside it. + */ +#define ACCESSIBLE_GROUP_BOX L"group box" + + /** + * A text header + */ +#define ACCESSIBLE_HEADER L"header" + + /** + * A text footer + */ +#define ACCESSIBLE_FOOTER L"footer" + + /** + * A text paragraph + */ +#define ACCESSIBLE_PARAGRAPH L"paragraph" + + /** + * A ruler is an object used to measure distance + */ +#define ACCESSIBLE_RULER L"ruler" + + /** + * A role indicating the object acts as a formula for + * calculating a value. An example is a formula in + * a spreadsheet cell. + */ +#define ACCESSIBLE_EDITBAR L"editbar" + + /** + * A role indicating the object monitors the progress + * of some operation. + */ +#define PROGRESS_MONITOR L"progress monitor" + + + /** + ****************************************************** + * Accessibility event types + ****************************************************** + */ + +#define cPropertyNameChangeEvent (jlong) 1 // 1 +#define cPropertyDescriptionChangeEvent (jlong) 2 // 2 +#define cPropertyStateChangeEvent (jlong) 4 // 4 +#define cPropertyValueChangeEvent (jlong) 8 // 8 +#define cPropertySelectionChangeEvent (jlong) 16 // 10 +#define cPropertyTextChangeEvent (jlong) 32 // 20 +#define cPropertyCaretChangeEvent (jlong) 64 // 40 +#define cPropertyVisibleDataChangeEvent (jlong) 128 // 80 +#define cPropertyChildChangeEvent (jlong) 256 // 100 +#define cPropertyActiveDescendentChangeEvent (jlong) 512 // 200 +#define cPropertyTableModelChangeEvent (jlong) 1024 // 400 + + /** + ****************************************************** + * optional AccessibleContext interfaces + * + * This version of the bridge reuses the accessibleValue + * field in the AccessibleContextInfo struct to represent + * additional optional interfaces that are supported by + * the Java AccessibleContext. This is backwardly compatable + * because the old accessibleValue was set to the BOOL + * value TRUE (i.e., 1) if the AccessibleValue interface is + * supported. + ****************************************************** + */ + +#define cAccessibleValueInterface (jlong) 1 // 1 << 1 (TRUE) +#define cAccessibleActionInterface (jlong) 2 // 1 << 2 +#define cAccessibleComponentInterface (jlong) 4 // 1 << 3 +#define cAccessibleSelectionInterface (jlong) 8 // 1 << 4 +#define cAccessibleTableInterface (jlong) 16 // 1 << 5 +#define cAccessibleTextInterface (jlong) 32 // 1 << 6 +#define cAccessibleHypertextInterface (jlong) 64 // 1 << 7 + + + /** + ****************************************************** + * Accessibility information bundles + ****************************************************** + */ + + typedef struct AccessBridgeVersionInfoTag { + wchar_t VMversion[SHORT_STRING_SIZE]; // output of "java -version" + wchar_t bridgeJavaClassVersion[SHORT_STRING_SIZE]; // version of the AccessBridge.class + wchar_t bridgeJavaDLLVersion[SHORT_STRING_SIZE]; // version of JavaAccessBridge.dll + wchar_t bridgeWinDLLVersion[SHORT_STRING_SIZE]; // version of WindowsAccessBridge.dll + } AccessBridgeVersionInfo; + + + typedef struct AccessibleContextInfoTag { + wchar_t name[MAX_STRING_SIZE]; // the AccessibleName of the object + wchar_t description[MAX_STRING_SIZE]; // the AccessibleDescription of the object + + wchar_t role[SHORT_STRING_SIZE]; // localized AccesibleRole string + wchar_t role_en_US[SHORT_STRING_SIZE]; // AccesibleRole string in the en_US locale + wchar_t states[SHORT_STRING_SIZE]; // localized AccesibleStateSet string (comma separated) + wchar_t states_en_US[SHORT_STRING_SIZE]; // AccesibleStateSet string in the en_US locale (comma separated) + + jint indexInParent; // index of object in parent + jint childrenCount; // # of children, if any + + jint x; // screen coords in pixels + jint y; // " + jint width; // pixel width of object + jint height; // pixel height of object + + BOOL accessibleComponent; // flags for various additional + BOOL accessibleAction; // Java Accessibility interfaces + BOOL accessibleSelection; // FALSE if this object doesn't + BOOL accessibleText; // implement the additional interface + // in question + + // BOOL accessibleValue; // old BOOL indicating whether AccessibleValue is supported + BOOL accessibleInterfaces; // new bitfield containing additional interface flags + + } AccessibleContextInfo; + + + + // AccessibleText packages + typedef struct AccessibleTextInfoTag { + jint charCount; // # of characters in this text object + jint caretIndex; // index of caret + jint indexAtPoint; // index at the passsed in point + } AccessibleTextInfo; + + typedef struct AccessibleTextItemsInfoTag { + wchar_t letter; + wchar_t word[SHORT_STRING_SIZE]; + wchar_t sentence[MAX_STRING_SIZE]; + } AccessibleTextItemsInfo; + + typedef struct AccessibleTextSelectionInfoTag { + jint selectionStartIndex; + jint selectionEndIndex; + wchar_t selectedText[MAX_STRING_SIZE]; + } AccessibleTextSelectionInfo; + + typedef struct AccessibleTextRectInfoTag { + jint x; // bounding rect of char at index + jint y; // " + jint width; // " + jint height; // " + } AccessibleTextRectInfo; + + // standard attributes for text; note: tabstops are not supported + typedef struct AccessibleTextAttributesInfoTag { + BOOL bold; + BOOL italic; + BOOL underline; + BOOL strikethrough; + BOOL superscript; + BOOL subscript; + + wchar_t backgroundColor[SHORT_STRING_SIZE]; + wchar_t foregroundColor[SHORT_STRING_SIZE]; + wchar_t fontFamily[SHORT_STRING_SIZE]; + jint fontSize; + + jint alignment; + jint bidiLevel; + + jfloat firstLineIndent; + jfloat leftIndent; + jfloat rightIndent; + jfloat lineSpacing; + jfloat spaceAbove; + jfloat spaceBelow; + + wchar_t fullAttributesString[MAX_STRING_SIZE]; + } AccessibleTextAttributesInfo; + + /** + ****************************************************** + * IPC management typedefs + ****************************************************** + */ + +#define cMemoryMappedNameSize 255 + + /** + * sent by the WindowsDLL -> the memory-mapped file is setup + * + */ + typedef struct MemoryMappedFileCreatedPackageTag { +// HWND bridgeWindow; // redundant, but easier to get to here... + ABHWND64 bridgeWindow; // redundant, but easier to get to here... + char filename[cMemoryMappedNameSize]; + } MemoryMappedFileCreatedPackage; + + + + + /** + * sent when a new JavaVM attaches to the Bridge + * + */ + typedef struct JavaVMCreatedPackageTag { + ABHWND64 bridgeWindow; + long vmID; + } JavaVMCreatedPackage; + + /** + * sent when a JavaVM detatches from the Bridge + * + */ + typedef struct JavaVMDestroyedPackageTag { + ABHWND64 bridgeWindow; + } JavaVMDestroyedPackage; + + /** + * sent when a new AT attaches to the Bridge + * + */ + typedef struct WindowsATCreatedPackageTag { + ABHWND64 bridgeWindow; + } WindowsATCreatedPackage; + + /** + * sent when an AT detatches from the Bridge + * + */ + typedef struct WindowsATDestroyedPackageTag { + ABHWND64 bridgeWindow; + } WindowsATDestroyedPackage; + + + /** + * sent by JVM Bridges in response to a WindowsATCreate + * message; saying "howdy, welcome to the neighborhood" + * + */ + typedef struct JavaVMPresentNotificationPackageTag { + ABHWND64 bridgeWindow; + long vmID; + } JavaVMPresentNotificationPackage; + + /** + * sent by AT Bridges in response to a JavaVMCreate + * message; saying "howdy, welcome to the neighborhood" + * + */ + typedef struct WindowsATPresentNotificationPackageTag { + ABHWND64 bridgeWindow; + } WindowsATPresentNotificationPackage; + + + /** + ****************************************************** + * Core packages + ****************************************************** + */ + + typedef struct ReleaseJavaObjectPackageTag { + long vmID; + JOBJECT64 object; + } ReleaseJavaObjectPackage; + + typedef struct GetAccessBridgeVersionPackageTag { + long vmID; // can't get VM info w/out a VM! + AccessBridgeVersionInfo rVersionInfo; + } GetAccessBridgeVersionPackage; + + typedef struct IsSameObjectPackageTag { + long vmID; + JOBJECT64 obj1; + JOBJECT64 obj2; + jboolean rResult; + } IsSameObjectPackage; + + /** + ****************************************************** + * Windows packages + ****************************************************** + */ + + typedef struct IsJavaWindowPackageTag { + jint window; + jboolean rResult; + } IsJavaWindowPackage; + + typedef struct GetAccessibleContextFromHWNDPackageTag { + jint window; + long rVMID; + JOBJECT64 rAccessibleContext; + } GetAccessibleContextFromHWNDPackage; + + typedef struct GetHWNDFromAccessibleContextPackageTag { + JOBJECT64 accessibleContext; + ABHWND64 rHWND; + } GetHWNDFromAccessibleContextPackage; + + /** +****************************************************** +* AccessibleContext packages +****************************************************** +*/ + + typedef struct GetAccessibleContextAtPackageTag { + jint x; + jint y; + long vmID; + JOBJECT64 AccessibleContext; // look within this AC + JOBJECT64 rAccessibleContext; + } GetAccessibleContextAtPackage; + + typedef struct GetAccessibleContextWithFocusPackageTag { + long rVMID; + JOBJECT64 rAccessibleContext; + } GetAccessibleContextWithFocusPackage; + + typedef struct GetAccessibleContextInfoPackageTag { + long vmID; + JOBJECT64 AccessibleContext; + AccessibleContextInfo rAccessibleContextInfo; + } GetAccessibleContextInfoPackage; + + typedef struct GetAccessibleChildFromContextPackageTag { + long vmID; + JOBJECT64 AccessibleContext; + jint childIndex; + JOBJECT64 rAccessibleContext; + } GetAccessibleChildFromContextPackage; + + typedef struct GetAccessibleParentFromContextPackageTag { + long vmID; + JOBJECT64 AccessibleContext; + JOBJECT64 rAccessibleContext; + } GetAccessibleParentFromContextPackage; + + /** +****************************************************** +* AccessibleTable packages +****************************************************** +*/ + +#define MAX_TABLE_SELECTIONS 64 + + // table information + typedef struct AccessibleTableInfoTag { + JOBJECT64 caption; // AccesibleContext + JOBJECT64 summary; // AccessibleContext + jint rowCount; + jint columnCount; + JOBJECT64 accessibleContext; + JOBJECT64 accessibleTable; + } AccessibleTableInfo; + + typedef struct GetAccessibleTableInfoPackageTag { + long vmID; + JOBJECT64 accessibleContext; + AccessibleTableInfo rTableInfo; + } GetAccessibleTableInfoPackage; + + // table cell information + typedef struct AccessibleTableCellInfoTag { + JOBJECT64 accessibleContext; + jint index; + jint row; + jint column; + jint rowExtent; + jint columnExtent; + jboolean isSelected; + } AccessibleTableCellInfo; + + typedef struct GetAccessibleTableCellInfoPackageTag { + long vmID; + JOBJECT64 accessibleTable; + jint row; + jint column; + AccessibleTableCellInfo rTableCellInfo; + } GetAccessibleTableCellInfoPackage; + + typedef struct GetAccessibleTableRowHeaderPackageTag { + long vmID; + JOBJECT64 accessibleContext; + AccessibleTableInfo rTableInfo; + } GetAccessibleTableRowHeaderPackage; + + typedef struct GetAccessibleTableColumnHeaderPackageTag { + long vmID; + JOBJECT64 accessibleContext; + AccessibleTableInfo rTableInfo; + } GetAccessibleTableColumnHeaderPackage; + + typedef struct GetAccessibleTableRowDescriptionPackageTag { + long vmID; + JOBJECT64 accessibleContext; + jint row; + JOBJECT64 rAccessibleContext; + } GetAccessibleTableRowDescriptionPackage; + + typedef struct GetAccessibleTableColumnDescriptionPackageTag { + long vmID; + JOBJECT64 accessibleContext; + jint column; + JOBJECT64 rAccessibleContext; + } GetAccessibleTableColumnDescriptionPackage; + + typedef struct GetAccessibleTableRowSelectionCountPackageTag { + long vmID; + JOBJECT64 accessibleTable; + jint rCount; + } GetAccessibleTableRowSelectionCountPackage; + + typedef struct IsAccessibleTableRowSelectedPackageTag { + long vmID; + JOBJECT64 accessibleTable; + jint row; + jboolean rResult; + } IsAccessibleTableRowSelectedPackage; + + typedef struct GetAccessibleTableRowSelectionsPackageTag { + long vmID; + JOBJECT64 accessibleTable; + jint count; + jint rSelections[MAX_TABLE_SELECTIONS]; + } GetAccessibleTableRowSelectionsPackage; + + typedef struct GetAccessibleTableColumnSelectionCountPackageTag { + long vmID; + JOBJECT64 accessibleTable; + jint rCount; + } GetAccessibleTableColumnSelectionCountPackage; + + typedef struct IsAccessibleTableColumnSelectedPackageTag { + long vmID; + JOBJECT64 accessibleTable; + jint column; + jboolean rResult; + } IsAccessibleTableColumnSelectedPackage; + + typedef struct GetAccessibleTableColumnSelectionsPackageTag { + long vmID; + JOBJECT64 accessibleTable; + jint count; + jint rSelections[MAX_TABLE_SELECTIONS]; + } GetAccessibleTableColumnSelectionsPackage; + + + typedef struct GetAccessibleTableRowPackageTag { + long vmID; + JOBJECT64 accessibleTable; + jint index; + jint rRow; + } GetAccessibleTableRowPackage; + + typedef struct GetAccessibleTableColumnPackageTag { + long vmID; + JOBJECT64 accessibleTable; + jint index; + jint rColumn; + } GetAccessibleTableColumnPackage; + + typedef struct GetAccessibleTableIndexPackageTag { + long vmID; + JOBJECT64 accessibleTable; + jint row; + jint column; + jint rIndex; + } GetAccessibleTableIndexPackage; + + + /** + ****************************************************** + * AccessibleRelationSet packages + ****************************************************** + */ + +#define MAX_RELATION_TARGETS 25 +#define MAX_RELATIONS 5 + + typedef struct AccessibleRelationInfoTag { + wchar_t key[SHORT_STRING_SIZE]; + jint targetCount; + JOBJECT64 targets[MAX_RELATION_TARGETS]; // AccessibleContexts + } AccessibleRelationInfo; + + typedef struct AccessibleRelationSetInfoTag { + jint relationCount; + AccessibleRelationInfo relations[MAX_RELATIONS]; + } AccessibleRelationSetInfo; + + typedef struct GetAccessibleRelationSetPackageTag { + long vmID; + JOBJECT64 accessibleContext; + AccessibleRelationSetInfo rAccessibleRelationSetInfo; + } GetAccessibleRelationSetPackage; + + /** + ****************************************************** + * AccessibleHypertext packagess + ****************************************************** + */ + +#define MAX_HYPERLINKS 64 // maximum number of hyperlinks returned + + // hyperlink information + typedef struct AccessibleHyperlinkInfoTag { + wchar_t text[SHORT_STRING_SIZE]; // the hyperlink text + jint startIndex; //index in the hypertext document where the link begins + jint endIndex; //index in the hypertext document where the link ends + JOBJECT64 accessibleHyperlink; // AccessibleHyperlink object + } AccessibleHyperlinkInfo; + + // hypertext information + typedef struct AccessibleHypertextInfoTag { + jint linkCount; // number of hyperlinks + AccessibleHyperlinkInfo links[MAX_HYPERLINKS]; // the hyperlinks + JOBJECT64 accessibleHypertext; // AccessibleHypertext object + } AccessibleHypertextInfo; + + // struct for sending a message to get the hypertext for an AccessibleContext + typedef struct GetAccessibleHypertextPackageTag { + long vmID; // the virtual machine ID + JOBJECT64 accessibleContext; // AccessibleContext with hypertext + AccessibleHypertextInfo rAccessibleHypertextInfo; // returned hypertext + } GetAccessibleHypertextPackage; + + // struct for sending an message to activate a hyperlink + typedef struct ActivateAccessibleHyperlinkPackageTag { + long vmID; // the virtual machine ID + JOBJECT64 accessibleContext; // AccessibleContext containing the link + JOBJECT64 accessibleHyperlink; // the link to activate + BOOL rResult; // hyperlink activation return value + } ActivateAccessibleHyperlinkPackage; + + // struct for sending a message to get the number of hyperlinks in a component + typedef struct GetAccessibleHyperlinkCountPackageTag { + long vmID; // the virtual machine ID + JOBJECT64 accessibleContext; // AccessibleContext containing AccessibleHypertext + jint rLinkCount; // link count return value + } GetAccessibleHyperlinkCountPackage; + + // struct for sending a message to get the hypertext for an AccessibleContext + // starting at a specified index in the document + typedef struct GetAccessibleHypertextExtPackageTag { + long vmID; // the virtual machine ID + JOBJECT64 accessibleContext; // AccessibleContext with hypertext + jint startIndex; // start index in document + AccessibleHypertextInfo rAccessibleHypertextInfo; // returned hypertext + BOOL rSuccess; // whether call succeeded + } GetAccessibleHypertextExtPackage; + + // struct for sending a message to get the nth hyperlink in a document; + // maps to AccessibleHypertext.getLink + typedef struct GetAccessibleHyperlinkPackageTag { + long vmID; // the virtual machine ID + JOBJECT64 hypertext; // AccessibleHypertext + jint linkIndex; // hyperlink index + AccessibleHyperlinkInfo rAccessibleHyperlinkInfo; // returned hyperlink + } GetAccessibleHyperlinkPackage; + + // struct for sending a message to get the index into an array + // of hyperlinks that is associated with a character index in a + // document; maps to AccessibleHypertext.getLinkIndex + typedef struct GetAccessibleHypertextLinkIndexPackageTag { + long vmID; // the virtual machine ID + JOBJECT64 hypertext; // AccessibleHypertext + jint charIndex; // character index in document + jint rLinkIndex; // returned hyperlink index + } GetAccessibleHypertextLinkIndexPackage; + + /** + ****************************************************** + * Accessible Key Bindings packages + ****************************************************** + */ + +#define MAX_KEY_BINDINGS 10 + + // keyboard character modifiers +#define ACCESSIBLE_SHIFT_KEYSTROKE 1 +#define ACCESSIBLE_CONTROL_KEYSTROKE 2 +#define ACCESSIBLE_META_KEYSTROKE 4 +#define ACCESSIBLE_ALT_KEYSTROKE 8 +#define ACCESSIBLE_ALT_GRAPH_KEYSTROKE 16 +#define ACCESSIBLE_BUTTON1_KEYSTROKE 32 +#define ACCESSIBLE_BUTTON2_KEYSTROKE 64 +#define ACCESSIBLE_BUTTON3_KEYSTROKE 128 +#define ACCESSIBLE_FKEY_KEYSTROKE 256 // F key pressed, character contains 1-24 +#define ACCESSIBLE_CONTROLCODE_KEYSTROKE 512 // Control code key pressed, character contains control code. + +// The supported control code keys are: +#define ACCESSIBLE_VK_TAB 9 +#define ACCESSIBLE_VK_SPACE 32 +#define ACCESSIBLE_VK_BACK_SPACE 8 +#define ACCESSIBLE_VK_DELETE 127 +#define ACCESSIBLE_VK_DOWN 40 +#define ACCESSIBLE_VK_END 35 +#define ACCESSIBLE_VK_HOME 36 +#define ACCESSIBLE_VK_INSERT 155 +#define ACCESSIBLE_VK_KP_DOWN 225 +#define ACCESSIBLE_VK_KP_LEFT 226 +#define ACCESSIBLE_VK_KP_RIGHT 227 +#define ACCESSIBLE_VK_KP_UP 224 +#define ACCESSIBLE_VK_LEFT 37 +#define ACCESSIBLE_VK_PAGE_DOWN 34 +#define ACCESSIBLE_VK_PAGE_UP 33 +#define ACCESSIBLE_VK_RIGHT 39 +#define ACCESSIBLE_VK_UP 38 + + // a key binding associates with a component + typedef struct AccessibleKeyBindingInfoTag { + jchar character; // the key character + jint modifiers; // the key modifiers + } AccessibleKeyBindingInfo; + + // all of the key bindings associated with a component + typedef struct AccessibleKeyBindingsTag { + int keyBindingsCount; // number of key bindings + AccessibleKeyBindingInfo keyBindingInfo[MAX_KEY_BINDINGS]; + } AccessibleKeyBindings; + + // struct to get the key bindings associated with a component + typedef struct GetAccessibleKeyBindingsPackageTag { + long vmID; // the virtual machine id + JOBJECT64 accessibleContext; // the component + AccessibleKeyBindings rAccessibleKeyBindings; // the key bindings + } GetAccessibleKeyBindingsPackage; + + /** +****************************************************** +* AccessibleIcon packages +****************************************************** +*/ +#define MAX_ICON_INFO 8 + + // an icon assocated with a component + typedef struct AccessibleIconInfoTag { + wchar_t description[SHORT_STRING_SIZE]; // icon description + jint height; // icon height + jint width; // icon width + } AccessibleIconInfo; + + // all of the icons associated with a component + typedef struct AccessibleIconsTag { + jint iconsCount; // number of icons + AccessibleIconInfo iconInfo[MAX_ICON_INFO]; // the icons + } AccessibleIcons; + + // struct to get the icons associated with a component + typedef struct GetAccessibleIconsPackageTag { + long vmID; // the virtual machine id + JOBJECT64 accessibleContext; // the component + AccessibleIcons rAccessibleIcons; // the icons + } GetAccessibleIconsPackage; + + + /** +****************************************************** +* AccessibleAction packages +****************************************************** +*/ +#define MAX_ACTION_INFO 256 +#define MAX_ACTIONS_TO_DO 32 + + // an action assocated with a component + typedef struct AccessibleActionInfoTag { + wchar_t name[SHORT_STRING_SIZE]; // action name + } AccessibleActionInfo; + + // all of the actions associated with a component + typedef struct AccessibleActionsTag { + jint actionsCount; // number of actions + AccessibleActionInfo actionInfo[MAX_ACTION_INFO]; // the action information + } AccessibleActions; + + // struct for requesting the actions associated with a component + typedef struct GetAccessibleActionsPackageTag { + long vmID; + JOBJECT64 accessibleContext; // the component + AccessibleActions rAccessibleActions; // the actions + } GetAccessibleActionsPackage; + + // list of AccessibleActions to do + typedef struct AccessibleActionsToDoTag { + jint actionsCount; // number of actions to do + AccessibleActionInfo actions[MAX_ACTIONS_TO_DO];// the accessible actions to do + } AccessibleActionsToDo; + + // struct for sending an message to do one or more actions + typedef struct DoAccessibleActionsPackageTag { + long vmID; // the virtual machine ID + JOBJECT64 accessibleContext; // component to do the action + AccessibleActionsToDo actionsToDo; // the accessible actions to do + BOOL rResult; // action return value + jint failure; // index of action that failed if rResult is FALSE + } DoAccessibleActionsPackage; + + /** +****************************************************** +* AccessibleText packages +****************************************************** +*/ + + typedef struct GetAccessibleTextInfoPackageTag { + long vmID; + JOBJECT64 AccessibleContext; + jint x; + jint y; + AccessibleTextInfo rTextInfo; + } GetAccessibleTextInfoPackage; + + typedef struct GetAccessibleTextItemsPackageTag { + long vmID; + JOBJECT64 AccessibleContext; + jint index; + AccessibleTextItemsInfo rTextItemsInfo; + } GetAccessibleTextItemsPackage; + + typedef struct GetAccessibleTextSelectionInfoPackageTag { + long vmID; + JOBJECT64 AccessibleContext; + AccessibleTextSelectionInfo rTextSelectionItemsInfo; + } GetAccessibleTextSelectionInfoPackage; + + typedef struct GetAccessibleTextAttributeInfoPackageTag { + long vmID; + JOBJECT64 AccessibleContext; + jint index; + AccessibleTextAttributesInfo rAttributeInfo; + } GetAccessibleTextAttributeInfoPackage; + + typedef struct GetAccessibleTextRectInfoPackageTag { + long vmID; + JOBJECT64 AccessibleContext; + jint index; + AccessibleTextRectInfo rTextRectInfo; + } GetAccessibleTextRectInfoPackage; + + typedef struct GetCaretLocationPackageTag { + long vmID; + JOBJECT64 AccessibleContext; + jint index; + AccessibleTextRectInfo rTextRectInfo; + } GetCaretLocationPackage; + + typedef struct GetAccessibleTextLineBoundsPackageTag { + long vmID; + JOBJECT64 AccessibleContext; + jint index; + jint rLineStart; + jint rLineEnd; + } GetAccessibleTextLineBoundsPackage; + + typedef struct GetAccessibleTextRangePackageTag { + long vmID; + JOBJECT64 AccessibleContext; + jint start; + jint end; + wchar_t rText[MAX_BUFFER_SIZE]; + } GetAccessibleTextRangePackage; + + /** +****************************************************** +* +* Utility method packages +****************************************************** +*/ + + typedef struct SetTextContentsPackageTag { + long vmID; + JOBJECT64 accessibleContext; // the text field + wchar_t text[MAX_STRING_SIZE]; // the text + BOOL rResult; + } SetTextContentsPackage; + + typedef struct GetParentWithRolePackageTag { + long vmID; + JOBJECT64 accessibleContext; + wchar_t role[SHORT_STRING_SIZE]; // one of Accessible Roles above + JOBJECT64 rAccessibleContext; + } GetParentWithRolePackage; + + typedef struct GetTopLevelObjectPackageTag { + long vmID; + JOBJECT64 accessibleContext; + JOBJECT64 rAccessibleContext; + } GetTopLevelObjectPackage; + + typedef struct GetParentWithRoleElseRootPackageTag { + long vmID; + JOBJECT64 accessibleContext; + wchar_t role[SHORT_STRING_SIZE]; // one of Accessible Roles above + JOBJECT64 rAccessibleContext; + } GetParentWithRoleElseRootPackage; + + typedef struct GetObjectDepthPackageTag { + long vmID; + JOBJECT64 accessibleContext; + jint rResult; + } GetObjectDepthPackage; + + typedef struct GetActiveDescendentPackageTag { + long vmID; + JOBJECT64 accessibleContext; + JOBJECT64 rAccessibleContext; + } GetActiveDescendentPackage; + + /** +****************************************************** +* AccessibleValue packages +****************************************************** +*/ + + typedef struct GetCurrentAccessibleValueFromContextPackageTag { + long vmID; + JOBJECT64 AccessibleContext; + wchar_t rValue[SHORT_STRING_SIZE]; + } GetCurrentAccessibleValueFromContextPackage; + + typedef struct GetMaximumAccessibleValueFromContextPackageTag { + long vmID; + JOBJECT64 AccessibleContext; + wchar_t rValue[SHORT_STRING_SIZE]; + } GetMaximumAccessibleValueFromContextPackage; + + typedef struct GetMinimumAccessibleValueFromContextPackageTag { + long vmID; + JOBJECT64 AccessibleContext; + wchar_t rValue[SHORT_STRING_SIZE]; + } GetMinimumAccessibleValueFromContextPackage; + + + /** +****************************************************** +* AccessibleSelection packages +****************************************************** +*/ + + typedef struct AddAccessibleSelectionFromContextPackageTag { + long vmID; + JOBJECT64 AccessibleContext; + jint index; + } AddAccessibleSelectionFromContextPackage; + + typedef struct ClearAccessibleSelectionFromContextPackageTag { + long vmID; + JOBJECT64 AccessibleContext; + } ClearAccessibleSelectionFromContextPackage; + + typedef struct GetAccessibleSelectionFromContextPackageTag { + long vmID; + JOBJECT64 AccessibleContext; + jint index; + JOBJECT64 rAccessibleContext; + } GetAccessibleSelectionFromContextPackage; + + typedef struct GetAccessibleSelectionCountFromContextPackageTag { + long vmID; + JOBJECT64 AccessibleContext; + jint rCount; + } GetAccessibleSelectionCountFromContextPackage; + + typedef struct IsAccessibleChildSelectedFromContextPackageTag { + long vmID; + JOBJECT64 AccessibleContext; + jint index; + jboolean rResult; + } IsAccessibleChildSelectedFromContextPackage; + + typedef struct RemoveAccessibleSelectionFromContextPackageTag { + long vmID; + JOBJECT64 AccessibleContext; + jint index; + } RemoveAccessibleSelectionFromContextPackage; + + typedef struct SelectAllAccessibleSelectionFromContextPackageTag { + long vmID; + JOBJECT64 AccessibleContext; + } SelectAllAccessibleSelectionFromContextPackage; + + + /** +****************************************************** +* Java Event Notification Registration packages +****************************************************** +*/ + + typedef struct AddJavaEventNotificationPackageTag { + jlong type; + //HWND DLLwindow; + ABHWND64 DLLwindow; + } AddJavaEventNotificationPackage; + + typedef struct RemoveJavaEventNotificationPackageTag { + jlong type; + //HWND DLLwindow; + ABHWND64 DLLwindow; + } RemoveJavaEventNotificationPackage; + + + /** +****************************************************** +* Accessibility Event Notification Registration packages +****************************************************** +*/ + + typedef struct AddAccessibilityEventNotificationPackageTag { + jlong type; + //HWND DLLwindow; + ABHWND64 DLLwindow; + } AddAccessibilityEventNotificationPackage; + + typedef struct RemoveAccessibilityEventNotificationPackageTag { + jlong type; + //HWND DLLwindow; + ABHWND64 DLLwindow; + } RemoveAccessibilityEventNotificationPackage; + + + /** +****************************************************** +* Accessibility Property Change Event packages +****************************************************** +*/ + + typedef struct PropertyCaretChangePackageTag { + long vmID; + JOBJECT64 Event; + JOBJECT64 AccessibleContextSource; + jint oldPosition; + jint newPosition; + } PropertyCaretChangePackage; + + typedef struct PropertyDescriptionChangePackageTag { + long vmID; + JOBJECT64 Event; + JOBJECT64 AccessibleContextSource; + wchar_t oldDescription[SHORT_STRING_SIZE]; + wchar_t newDescription[SHORT_STRING_SIZE]; + } PropertyDescriptionChangePackage; + + typedef struct PropertyNameChangePackageTag { + long vmID; + JOBJECT64 Event; + JOBJECT64 AccessibleContextSource; + wchar_t oldName[SHORT_STRING_SIZE]; + wchar_t newName[SHORT_STRING_SIZE]; + } PropertyNameChangePackage; + + typedef struct PropertySelectionChangePackageTag { + long vmID; + JOBJECT64 Event; + JOBJECT64 AccessibleContextSource; + } PropertySelectionChangePackage; + + typedef struct PropertyStateChangePackageTag { + long vmID; + JOBJECT64 Event; + JOBJECT64 AccessibleContextSource; + wchar_t oldState[SHORT_STRING_SIZE]; + wchar_t newState[SHORT_STRING_SIZE]; + } PropertyStateChangePackage; + + typedef struct PropertyTextChangePackageTag { + long vmID; + JOBJECT64 Event; + JOBJECT64 AccessibleContextSource; + } PropertyTextChangePackage; + + typedef struct PropertyValueChangePackageTag { + long vmID; + JOBJECT64 Event; + JOBJECT64 AccessibleContextSource; + wchar_t oldValue[SHORT_STRING_SIZE]; + wchar_t newValue[SHORT_STRING_SIZE]; + } PropertyValueChangePackage; + + typedef struct PropertyVisibleDataChangePackageTag { + long vmID; + JOBJECT64 Event; + JOBJECT64 AccessibleContextSource; + } PropertyVisibleDataChangePackage; + + typedef struct PropertyChildChangePackageTag { + long vmID; + JOBJECT64 Event; + JOBJECT64 AccessibleContextSource; + JOBJECT64 oldChildAccessibleContext; + JOBJECT64 newChildAccessibleContext; + } PropertyChildChangePackage; + + typedef struct PropertyActiveDescendentChangePackageTag { + long vmID; + JOBJECT64 Event; + JOBJECT64 AccessibleContextSource; + JOBJECT64 oldActiveDescendentAccessibleContext; + JOBJECT64 newActiveDescendentAccessibleContext; + } PropertyActiveDescendentChangePackage; + + + // String format for newValue is: + // "type" one of "INSERT", "UPDATE" or "DELETE" + // "firstRow" + // "lastRow" + // "firstColumn" + // "lastColumn" + // + // oldValue is currently unused + // + typedef struct PropertyTableModelChangePackageTag { + long vmID; + JOBJECT64 Event; + JOBJECT64 AccessibleContextSource; + wchar_t oldValue[SHORT_STRING_SIZE]; + wchar_t newValue[SHORT_STRING_SIZE]; + } PropertyTableModelChangePackage; + + + /** +****************************************************** +* Property Change Event packages +****************************************************** +*/ + + /* + typedef struct PropertyChangePackageTag { + long vmID; + jobject Event; + jobject AccessibleContextSource; + char propertyName[SHORT_STRING_SIZE]; + char oldValue[SHORT_STRING_SIZE]; // PropertyChangeEvent().getOldValue().toString() + char newValue[SHORT_STRING_SIZE]; // PropertyChangeEvent().getNewValue().toString() + } PropertyChangePackage; + */ + + /* + * Java shutdown event package + */ + typedef struct JavaShutdownPackageTag { + long vmID; + } JavaShutdownPackage; + + + /** +****************************************************** +* Focus Event packages +****************************************************** +*/ + + typedef struct FocusGainedPackageTag { + long vmID; + JOBJECT64 Event; + JOBJECT64 AccessibleContextSource; + } FocusGainedPackage; + + typedef struct FocusLostPackageTag { + long vmID; + JOBJECT64 Event; + JOBJECT64 AccessibleContextSource; + } FocusLostPackage; + + + /** +****************************************************** +* Caret Event packages +****************************************************** +*/ + + typedef struct CaretUpdatePackageTag { + long vmID; + JOBJECT64 Event; + JOBJECT64 AccessibleContextSource; + } CaretUpdatePackage; + + + /** +****************************************************** +* Mouse Event packages +****************************************************** +*/ + + typedef struct MouseClickedPackageTag { + long vmID; + JOBJECT64 Event; + JOBJECT64 AccessibleContextSource; + } MouseClickedPackage; + + typedef struct MouseEnteredPackageTag { + long vmID; + JOBJECT64 Event; + JOBJECT64 AccessibleContextSource; + } MouseEnteredPackage; + + typedef struct MouseExitedPackageTag { + long vmID; + JOBJECT64 Event; + JOBJECT64 AccessibleContextSource; + } MouseExitedPackage; + + typedef struct MousePressedPackageTag { + long vmID; + JOBJECT64 Event; + JOBJECT64 AccessibleContextSource; + } MousePressedPackage; + + typedef struct MouseReleasedPackageTag { + long vmID; + JOBJECT64 Event; + JOBJECT64 AccessibleContextSource; + } MouseReleasedPackage; + + + /** +****************************************************** +* Menu/PopupMenu Event packages +****************************************************** +*/ + + typedef struct MenuCanceledPackageTag { + long vmID; + JOBJECT64 Event; + JOBJECT64 AccessibleContextSource; + } MenuCanceledPackage; + + typedef struct MenuDeselectedPackageTag { + long vmID; + JOBJECT64 Event; + JOBJECT64 AccessibleContextSource; + } MenuDeselectedPackage; + + typedef struct MenuSelectedPackageTag { + long vmID; + JOBJECT64 Event; + JOBJECT64 AccessibleContextSource; + } MenuSelectedPackage; + + + typedef struct PopupMenuCanceledPackageTag { + long vmID; + JOBJECT64 Event; + JOBJECT64 AccessibleContextSource; + } PopupMenuCanceledPackage; + + typedef struct PopupMenuWillBecomeInvisiblePackageTag { + long vmID; + JOBJECT64 Event; + JOBJECT64 AccessibleContextSource; + } PopupMenuWillBecomeInvisiblePackage; + + typedef struct PopupMenuWillBecomeVisiblePackageTag { + long vmID; + JOBJECT64 Event; + JOBJECT64 AccessibleContextSource; + } PopupMenuWillBecomeVisiblePackage; + + /** +****************************************************** +* Additional methods for Teton +****************************************************** +*/ + + /** + * Gets the AccessibleName for a component based upon the JAWS algorithm. Returns + * whether successful. + * + * Bug ID 4916682 - Implement JAWS AccessibleName policy + */ + typedef struct GetVirtualAccessibleNamePackageTag { + long vmID; + AccessibleContext accessibleContext; + wchar_t rName[MAX_STRING_SIZE]; + int len; + } GetVirtualAccessibleNamePackage; + + /** + * Request focus for a component. Returns whether successful; + * + * Bug ID 4944757 - requestFocus method needed + */ + typedef struct RequestFocusPackageTag { + long vmID; + AccessibleContext accessibleContext; + } RequestFocusPackage; + + /** + * Selects text between two indices. Selection includes the text at the start index + * and the text at the end index. Returns whether successful; + * + * Bug ID 4944758 - selectTextRange method needed + */ + typedef struct SelectTextRangePackageTag { + long vmID; + AccessibleContext accessibleContext; + jint startIndex; + jint endIndex; + } SelectTextRangePackage; + + /** + * Gets the number of contiguous characters with the same attributes. + * + * Bug ID 4944761 - getTextAttributes between two indices method needed + */ + typedef struct GetTextAttributesInRangePackageTag { + long vmID; + AccessibleContext accessibleContext; + jint startIndex; // start index (inclusive) + jint endIndex; // end index (inclusive) + AccessibleTextAttributesInfo attributes; // character attributes to match + short rLength; // number of contiguous characters with matching attributes + } GetTextAttributesInRangePackage; + +#define MAX_VISIBLE_CHILDREN 256 + + // visible children information + typedef struct VisibleChildenInfoTag { + int returnedChildrenCount; // number of children returned + AccessibleContext children[MAX_VISIBLE_CHILDREN]; // the visible children + } VisibleChildrenInfo; + + // struct for sending a message to get the number of visible children + typedef struct GetVisibleChildrenCountPackageTag { + long vmID; // the virtual machine ID + JOBJECT64 accessibleContext; // AccessibleContext of parent component + jint rChildrenCount; // visible children count return value + } GetVisibleChildrenCountPackage; + + // struct for sending a message to get the hypertext for an AccessibleContext + // starting at a specified index in the document + typedef struct GetVisibleChildrenPackageTag { + long vmID; // the virtual machine ID + JOBJECT64 accessibleContext; // AccessibleContext of parent component + jint startIndex; // start index for retrieving children + VisibleChildrenInfo rVisibleChildrenInfo; // returned info + BOOL rSuccess; // whether call succeeded + } GetVisibleChildrenPackage; + + /** + * Set the caret to a text position. Returns whether successful; + * + * Bug ID 4944770 - setCaretPosition method needed + */ + typedef struct SetCaretPositionPackageTag { + long vmID; + AccessibleContext accessibleContext; + jint position; + } SetCaretPositionPackage; + + + /** + ****************************************************** + * Wrapping up all of the packages + ****************************************************** + */ + + /** + * What is the type of this package + */ + typedef enum PackageType { + + cMemoryMappedFileCreatedPackage = 0x11000, + + // many of these will go away... + cJavaVMCreatedPackage = 0x10000, + cJavaVMDestroyedPackage, + cWindowsATCreatedPackage, + cWindowsATDestroyedPackage, + cJavaVMPresentNotificationPackage, + cWindowsATPresentNotificationPackage, + + cReleaseJavaObjectPackage = 1, + cGetAccessBridgeVersionPackage = 2, + + cGetAccessibleContextFromHWNDPackage = 0x10, + cIsJavaWindowPackage, + cGetHWNDFromAccessibleContextPackage, + + cGetAccessibleContextAtPackage = 0x100, + cGetAccessibleContextWithFocusPackage, + cGetAccessibleContextInfoPackage, + cGetAccessibleChildFromContextPackage, + cGetAccessibleParentFromContextPackage, + cIsSameObjectPackage, + + cGetAccessibleTextInfoPackage = 0x200, + cGetAccessibleTextItemsPackage, + cGetAccessibleTextSelectionInfoPackage, + cGetAccessibleTextAttributeInfoPackage, + cGetAccessibleTextRectInfoPackage, + cGetAccessibleTextLineBoundsPackage, + cGetAccessibleTextRangePackage, + + cGetCurrentAccessibleValueFromContextPackage = 0x300, + cGetMaximumAccessibleValueFromContextPackage, + cGetMinimumAccessibleValueFromContextPackage, + + cAddAccessibleSelectionFromContextPackage = 0x400, + cClearAccessibleSelectionFromContextPackage, + cGetAccessibleSelectionFromContextPackage, + cGetAccessibleSelectionCountFromContextPackage, + cIsAccessibleChildSelectedFromContextPackage, + cRemoveAccessibleSelectionFromContextPackage, + cSelectAllAccessibleSelectionFromContextPackage, + + cAddJavaEventNotificationPackage = 0x900, + cRemoveJavaEventNotificationPackage, + cAddAccessibilityEventNotificationPackage, + cRemoveAccessibilityEventNotificationPackage, + + cPropertyChangePackage = 0x1000, + + cJavaShutdownPackage = 0x1010, + cFocusGainedPackage, + cFocusLostPackage, + + cCaretUpdatePackage = 0x1020, + + cMouseClickedPackage = 0x1030, + cMouseEnteredPackage, + cMouseExitedPackage, + cMousePressedPackage, + cMouseReleasedPackage, + + cMenuCanceledPackage = 0x1040, + cMenuDeselectedPackage, + cMenuSelectedPackage, + cPopupMenuCanceledPackage, + cPopupMenuWillBecomeInvisiblePackage, + cPopupMenuWillBecomeVisiblePackage, + + cPropertyCaretChangePackage = 0x1100, + cPropertyDescriptionChangePackage, + cPropertyNameChangePackage, + cPropertySelectionChangePackage, + cPropertyStateChangePackage, + cPropertyTextChangePackage, + cPropertyValueChangePackage, + cPropertyVisibleDataChangePackage, + cPropertyChildChangePackage, + cPropertyActiveDescendentChangePackage, + + + // AccessibleTable + cGetAccessibleTableInfoPackage = 0x1200, + cGetAccessibleTableCellInfoPackage, + + cGetAccessibleTableRowHeaderPackage, + cGetAccessibleTableColumnHeaderPackage, + + cGetAccessibleTableRowDescriptionPackage, + cGetAccessibleTableColumnDescriptionPackage, + + cGetAccessibleTableRowSelectionCountPackage, + cIsAccessibleTableRowSelectedPackage, + cGetAccessibleTableRowSelectionsPackage, + + cGetAccessibleTableColumnSelectionCountPackage, + cIsAccessibleTableColumnSelectedPackage, + cGetAccessibleTableColumnSelectionsPackage, + + cGetAccessibleTableRowPackage, + cGetAccessibleTableColumnPackage, + cGetAccessibleTableIndexPackage, + + cPropertyTableModelChangePackage, + + + // AccessibleRelationSet + cGetAccessibleRelationSetPackage = 0x1300, + + // AccessibleHypertext + cGetAccessibleHypertextPackage = 0x1400, + cActivateAccessibleHyperlinkPackage, + cGetAccessibleHyperlinkCountPackage, + cGetAccessibleHypertextExtPackage, + cGetAccessibleHypertextLinkIndexPackage, + cGetAccessibleHyperlinkPackage, + + // Accessible KeyBinding, Icon and Action + cGetAccessibleKeyBindingsPackage = 0x1500, + cGetAccessibleIconsPackage, + cGetAccessibleActionsPackage, + cDoAccessibleActionsPackage, + + // Utility methods + cSetTextContentsPackage = 0x1600, + cGetParentWithRolePackage, + cGetTopLevelObjectPackage, + cGetParentWithRoleElseRootPackage, + cGetObjectDepthPackage, + cGetActiveDescendentPackage, + + // Additional methods for Teton + cGetVirtualAccessibleNamePackage = 0x1700, + cRequestFocusPackage, + cSelectTextRangePackage, + cGetTextAttributesInRangePackage, + cGetSameTextAttributesInRangePackage, + cGetVisibleChildrenCountPackage, + cGetVisibleChildrenPackage, + cSetCaretPositionPackage, + cGetCaretLocationPackage + + + } PackageType; + + + /** + * Union of all package contents + */ + typedef union AllPackagesTag { + + // Initial Rendezvous packages + MemoryMappedFileCreatedPackage memoryMappedFileCreatedPackage; + + JavaVMCreatedPackage javaVMCreatedPackage; + JavaVMDestroyedPackage javaVMDestroyedPackage; + WindowsATCreatedPackage windowsATCreatedPackage; + WindowsATDestroyedPackage windowsATDestroyedPackage; + JavaVMPresentNotificationPackage javaVMPresentNotificationPackage; + WindowsATPresentNotificationPackage windowsATPresentNotificationPackage; + + // Core packages + ReleaseJavaObjectPackage releaseJavaObject; + GetAccessBridgeVersionPackage getAccessBridgeVersion; + + // Window packages + GetAccessibleContextFromHWNDPackage getAccessibleContextFromHWND; + GetHWNDFromAccessibleContextPackage getHWNDFromAccessibleContext; + + // AccessibleContext packages + GetAccessibleContextAtPackage getAccessibleContextAt; + GetAccessibleContextWithFocusPackage getAccessibleContextWithFocus; + GetAccessibleContextInfoPackage getAccessibleContextInfo; + GetAccessibleChildFromContextPackage getAccessibleChildFromContext; + GetAccessibleParentFromContextPackage getAccessibleParentFromContext; + + // AccessibleText packages + GetAccessibleTextInfoPackage getAccessibleTextInfo; + GetAccessibleTextItemsPackage getAccessibleTextItems; + GetAccessibleTextSelectionInfoPackage getAccessibleTextSelectionInfo; + GetAccessibleTextAttributeInfoPackage getAccessibleTextAttributeInfo; + GetAccessibleTextRectInfoPackage getAccessibleTextRectInfo; + GetAccessibleTextLineBoundsPackage getAccessibleTextLineBounds; + GetAccessibleTextRangePackage getAccessibleTextRange; + + // AccessibleValue packages + GetCurrentAccessibleValueFromContextPackage getCurrentAccessibleValueFromContext; + GetMaximumAccessibleValueFromContextPackage getMaximumAccessibleValueFromContext; + GetMinimumAccessibleValueFromContextPackage getMinimumAccessibleValueFromContext; + + // AccessibleSelection packages + AddAccessibleSelectionFromContextPackage addAccessibleSelectionFromContext; + ClearAccessibleSelectionFromContextPackage clearAccessibleSelectionFromContext; + GetAccessibleSelectionFromContextPackage getAccessibleSelectionFromContext; + GetAccessibleSelectionCountFromContextPackage getAccessibleSelectionCountFromContext; + IsAccessibleChildSelectedFromContextPackage isAccessibleChildSelectedFromContext; + RemoveAccessibleSelectionFromContextPackage removeAccessibleSelectionFromContext; + SelectAllAccessibleSelectionFromContextPackage selectAllAccessibleSelectionFromContext; + + // Event Notification Registration packages + AddJavaEventNotificationPackage addJavaEventNotification; + RemoveJavaEventNotificationPackage removeJavaEventNotification; + AddAccessibilityEventNotificationPackage addAccessibilityEventNotification; + RemoveAccessibilityEventNotificationPackage removeAccessibilityEventNotification; + + // Event contents packages + // PropertyChangePackage propertyChange; + PropertyCaretChangePackage propertyCaretChangePackage; + PropertyDescriptionChangePackage propertyDescriptionChangePackage; + PropertyNameChangePackage propertyNameChangePackage; + PropertySelectionChangePackage propertySelectionChangePackage; + PropertyStateChangePackage propertyStateChangePackage; + PropertyTextChangePackage propertyTextChangePackage; + PropertyValueChangePackage propertyValueChangePackage; + PropertyVisibleDataChangePackage propertyVisibleDataChangePackage; + PropertyChildChangePackage propertyChildChangePackage; + PropertyActiveDescendentChangePackage propertyActiveDescendentChangePackage; + + PropertyTableModelChangePackage propertyTableModelChangePackage; + + JavaShutdownPackage JavaShutdown; + FocusGainedPackage focusGained; + FocusLostPackage focusLost; + + CaretUpdatePackage caretUpdate; + + MouseClickedPackage mouseClicked; + MouseEnteredPackage mouseEntered; + MouseExitedPackage mouseExited; + MousePressedPackage mousePressed; + MouseReleasedPackage mouseReleased; + + MenuCanceledPackage menuCanceled; + MenuDeselectedPackage menuDeselected; + MenuSelectedPackage menuSelected; + PopupMenuCanceledPackage popupMenuCanceled; + PopupMenuWillBecomeInvisiblePackage popupMenuWillBecomeInvisible; + PopupMenuWillBecomeVisiblePackage popupMenuWillBecomeVisible; + + // AccessibleRelationSet + GetAccessibleRelationSetPackage getAccessibleRelationSet; + + // AccessibleHypertext + GetAccessibleHypertextPackage _getAccessibleHypertext; + ActivateAccessibleHyperlinkPackage _activateAccessibleHyperlink; + GetAccessibleHyperlinkCountPackage _getAccessibleHyperlinkCount; + GetAccessibleHypertextExtPackage _getAccessibleHypertextExt; + GetAccessibleHypertextLinkIndexPackage _getAccessibleHypertextLinkIndex; + GetAccessibleHyperlinkPackage _getAccessibleHyperlink; + + // Accessible KeyBinding, Icon and Action + GetAccessibleKeyBindingsPackage getAccessibleKeyBindings; + GetAccessibleIconsPackage getAccessibleIcons; + GetAccessibleActionsPackage getAccessibleActions; + DoAccessibleActionsPackage doAccessibleActions; + + // utility methods + SetTextContentsPackage _setTextContents; + GetParentWithRolePackage _getParentWithRole; + GetTopLevelObjectPackage _getTopLevelObject; + GetParentWithRoleElseRootPackage _getParentWithRoleElseRoot; + GetObjectDepthPackage _getObjectDepth; + GetActiveDescendentPackage _getActiveDescendent; + + // Additional methods for Teton + GetVirtualAccessibleNamePackage _getVirtualAccessibleName; + RequestFocusPackage _requestFocus; + SelectTextRangePackage _selectTextRange; + GetTextAttributesInRangePackage _getTextAttributesInRange; + GetVisibleChildrenCountPackage _getVisibleChildrenCount; + GetVisibleChildrenPackage _getVisibleChildren; + SetCaretPositionPackage _setCaretPosition; + + } AllPackages; + + + /** + * Union of all Java-initiated package contents + */ + typedef union JavaInitiatedPackagesTag { + + // Initial Rendezvous packages + JavaVMCreatedPackage javaVMCreatedPackage; + JavaVMDestroyedPackage javaVMDestroyedPackage; + JavaVMPresentNotificationPackage javaVMPresentNotificationPackage; + + // Event contents packages + PropertyCaretChangePackage propertyCaretChangePackage; + PropertyDescriptionChangePackage propertyDescriptionChangePackage; + PropertyNameChangePackage propertyNameChangePackage; + PropertySelectionChangePackage propertySelectionChangePackage; + PropertyStateChangePackage propertyStateChangePackage; + PropertyTextChangePackage propertyTextChangePackage; + PropertyValueChangePackage propertyValueChangePackage; + PropertyVisibleDataChangePackage propertyVisibleDataChangePackage; + PropertyChildChangePackage propertyChildChangePackage; + PropertyActiveDescendentChangePackage propertyActiveDescendentChangePackage; + + PropertyTableModelChangePackage propertyTableModelChangePackage; + + JavaShutdownPackage JavaShutdown; + FocusGainedPackage focusGained; + FocusLostPackage focusLost; + + CaretUpdatePackage caretUpdate; + + MouseClickedPackage mouseClicked; + MouseEnteredPackage mouseEntered; + MouseExitedPackage mouseExited; + MousePressedPackage mousePressed; + MouseReleasedPackage mouseReleased; + + MenuCanceledPackage menuCanceled; + MenuDeselectedPackage menuDeselected; + MenuSelectedPackage menuSelected; + PopupMenuCanceledPackage popupMenuCanceled; + PopupMenuWillBecomeInvisiblePackage popupMenuWillBecomeInvisible; + PopupMenuWillBecomeVisiblePackage popupMenuWillBecomeVisible; + + } JavaInitiatedPackages; + + + /** + * Union of all Windows-initiated package contents + */ + typedef union WindowsInitiatedPackagesTag { + + // Initial Rendezvous packages + MemoryMappedFileCreatedPackage memoryMappedFileCreatedPackage; + + WindowsATCreatedPackage windowsATCreatedPackage; + WindowsATDestroyedPackage windowsATDestroyedPackage; + WindowsATPresentNotificationPackage windowsATPresentNotificationPackage; + + // Core packages + ReleaseJavaObjectPackage releaseJavaObject; + GetAccessBridgeVersionPackage getAccessBridgeVersion; + + // Window packages + GetAccessibleContextFromHWNDPackage getAccessibleContextFromHWND; + GetHWNDFromAccessibleContextPackage getHWNDFromAccessibleContext; + + // AccessibleContext packages + GetAccessibleContextAtPackage getAccessibleContextAt; + GetAccessibleContextWithFocusPackage getAccessibleContextWithFocus; + GetAccessibleContextInfoPackage getAccessibleContextInfo; + GetAccessibleChildFromContextPackage getAccessibleChildFromContext; + GetAccessibleParentFromContextPackage getAccessibleParentFromContext; + + // AccessibleText packages + GetAccessibleTextInfoPackage getAccessibleTextInfo; + GetAccessibleTextItemsPackage getAccessibleTextItems; + GetAccessibleTextSelectionInfoPackage getAccessibleTextSelectionInfo; + GetAccessibleTextAttributeInfoPackage getAccessibleTextAttributeInfo; + GetAccessibleTextRectInfoPackage getAccessibleTextRectInfo; + GetAccessibleTextLineBoundsPackage getAccessibleTextLineBounds; + GetAccessibleTextRangePackage getAccessibleTextRange; + + // AccessibleValue packages + GetCurrentAccessibleValueFromContextPackage getCurrentAccessibleValueFromContext; + GetMaximumAccessibleValueFromContextPackage getMaximumAccessibleValueFromContext; + GetMinimumAccessibleValueFromContextPackage getMinimumAccessibleValueFromContext; + + // AccessibleSelection packages + AddAccessibleSelectionFromContextPackage addAccessibleSelectionFromContext; + ClearAccessibleSelectionFromContextPackage clearAccessibleSelectionFromContext; + GetAccessibleSelectionFromContextPackage getAccessibleSelectionFromContext; + GetAccessibleSelectionCountFromContextPackage getAccessibleSelectionCountFromContext; + IsAccessibleChildSelectedFromContextPackage isAccessibleChildSelectedFromContext; + RemoveAccessibleSelectionFromContextPackage removeAccessibleSelectionFromContext; + SelectAllAccessibleSelectionFromContextPackage selectAllAccessibleSelectionFromContext; + + // Event Notification Registration packages + AddJavaEventNotificationPackage addJavaEventNotification; + RemoveJavaEventNotificationPackage removeJavaEventNotification; + AddAccessibilityEventNotificationPackage addAccessibilityEventNotification; + RemoveAccessibilityEventNotificationPackage removeAccessibilityEventNotification; + + // AccessibleTable + GetAccessibleTableInfoPackage _getAccessibleTableInfo; + GetAccessibleTableCellInfoPackage _getAccessibleTableCellInfo; + + GetAccessibleTableRowHeaderPackage _getAccessibleTableRowHeader; + GetAccessibleTableColumnHeaderPackage _getAccessibleTableColumnHeader; + + GetAccessibleTableRowDescriptionPackage _getAccessibleTableRowDescription; + GetAccessibleTableColumnDescriptionPackage _getAccessibleTableColumnDescription; + + GetAccessibleTableRowSelectionCountPackage _getAccessibleTableRowSelectionCount; + IsAccessibleTableRowSelectedPackage _isAccessibleTableRowSelected; + GetAccessibleTableRowSelectionsPackage _getAccessibleTableRowSelections; + + GetAccessibleTableColumnSelectionCountPackage _getAccessibleTableColumnSelectionCount; + IsAccessibleTableColumnSelectedPackage _isAccessibleTableColumnSelected; + GetAccessibleTableColumnSelectionsPackage _getAccessibleTableColumnSelections; + + GetAccessibleTableRowPackage _getAccessibleTableRow; + GetAccessibleTableColumnPackage _getAccessibleTableColumn; + GetAccessibleTableIndexPackage _getAccessibleTableIndex; + + // AccessibleRelationSet + GetAccessibleRelationSetPackage _getAccessibleRelationSet; + + // Accessible KeyBindings, Icons and Actions + GetAccessibleKeyBindingsPackage _getAccessibleKeyBindings; + GetAccessibleIconsPackage _getAccessibleIcons; + GetAccessibleActionsPackage _getAccessibleActions; + DoAccessibleActionsPackage _doAccessibleActions; + + + IsSameObjectPackage _isSameObject; + + // utility methods + SetTextContentsPackage _setTextContents; + GetParentWithRolePackage _getParentWithRole; + GetTopLevelObjectPackage _getTopLevelObject; + GetParentWithRoleElseRootPackage _getParentWithRoleElseRoot; + GetObjectDepthPackage _getObjectDepth; + GetActiveDescendentPackage _getActiveDescendent; + + // Additional methods for Teton + GetVirtualAccessibleNamePackage _getVirtualAccessibleName; + RequestFocusPackage _requestFocus; + SelectTextRangePackage _selectTextRange; + GetTextAttributesInRangePackage _getTextAttributesInRange; + GetVisibleChildrenCountPackage _getVisibleChildrenCount; + GetVisibleChildrenPackage _getVisibleChildren; + SetCaretPositionPackage _setCaretPosition; + + + } WindowsInitiatedPackages; + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/core/esmf-tree-sitter-turtle/src/main/c/include/windows/jawt_md.h b/core/esmf-tree-sitter-turtle/src/main/c/include/windows/jawt_md.h new file mode 100755 index 000000000..7d43ff827 --- /dev/null +++ b/core/esmf-tree-sitter-turtle/src/main/c/include/windows/jawt_md.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 1999, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#ifndef _JAVASOFT_JAWT_MD_H_ +#define _JAVASOFT_JAWT_MD_H_ + +#include +#include "jawt.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Win32-specific declarations for AWT native interface. + * See notes in jawt.h for an example of use. + */ +typedef struct jawt_Win32DrawingSurfaceInfo { + /* Native window, DDB, or DIB handle */ + union { + HWND hwnd; + HBITMAP hbitmap; + void* pbits; + }; + /* + * This HDC should always be used instead of the HDC returned from + * BeginPaint() or any calls to GetDC(). + */ + HDC hdc; + HPALETTE hpalette; +} JAWT_Win32DrawingSurfaceInfo; + +#ifdef __cplusplus +} +#endif + +#endif /* !_JAVASOFT_JAWT_MD_H_ */ diff --git a/core/esmf-tree-sitter-turtle/src/main/c/include/windows/jni_md.h b/core/esmf-tree-sitter-turtle/src/main/c/include/windows/jni_md.h new file mode 100755 index 000000000..6d217733d --- /dev/null +++ b/core/esmf-tree-sitter-turtle/src/main/c/include/windows/jni_md.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 1996, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#ifndef _JAVASOFT_JNI_MD_H_ +#define _JAVASOFT_JNI_MD_H_ + +#ifndef JNIEXPORT + #define JNIEXPORT __declspec(dllexport) +#endif +#define JNIIMPORT __declspec(dllimport) + +typedef int jint; +typedef long long jlong; +typedef signed char jbyte; + +#endif /* !_JAVASOFT_JNI_MD_H_ */ diff --git a/core/esmf-tree-sitter-turtle/src/main/c/org_eclipse_esmf_treesitterturtle_TreeSitterTurtle.c b/core/esmf-tree-sitter-turtle/src/main/c/org_eclipse_esmf_treesitterturtle_TreeSitterTurtle.c new file mode 100644 index 000000000..70ccff3d1 --- /dev/null +++ b/core/esmf-tree-sitter-turtle/src/main/c/org_eclipse_esmf_treesitterturtle_TreeSitterTurtle.c @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2026 Robert Bosch Manufacturing Solutions GmbH + * + * See the AUTHORS file(s) distributed with this work for additional + * information regarding authorship. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * SPDX-License-Identifier: MPL-2.0 + */ + +#include +void *tree_sitter_turtle(); +/* + * Class: org_treesitter_TreeSitterTurtle + * Method: tree_sitter_turtle + * Signature: ()J + */ +JNIEXPORT jlong JNICALL Java_org_eclipse_esmf_treesitterturtle_TreeSitterTurtle_tree_1sitter_1turtle + (JNIEnv *env, jclass clz){ + return (jlong) tree_sitter_turtle(); +} diff --git a/core/esmf-tree-sitter-turtle/src/main/java/org/eclipse/esmf/treesitterturtle/TreeSitterTurtle.java b/core/esmf-tree-sitter-turtle/src/main/java/org/eclipse/esmf/treesitterturtle/TreeSitterTurtle.java new file mode 100644 index 000000000..4e0446f5a --- /dev/null +++ b/core/esmf-tree-sitter-turtle/src/main/java/org/eclipse/esmf/treesitterturtle/TreeSitterTurtle.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2026 Robert Bosch Manufacturing Solutions GmbH + * + * See the AUTHORS file(s) distributed with this work for additional + * information regarding authorship. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * SPDX-License-Identifier: MPL-2.0 + */ + +package org.eclipse.esmf.treesitterturtle; + +import org.treesitter.TSLanguage; +import org.treesitter.utils.NativeUtils; + +public class TreeSitterTurtle extends TSLanguage { + static { + NativeUtils.loadLib( "lib/tree-sitter-turtle" ); + } + + private static native long tree_sitter_turtle(); + + public TreeSitterTurtle() { + super( tree_sitter_turtle() ); + } + + private TreeSitterTurtle( final long ptr ) { + super( ptr ); + } + + @Override + public TSLanguage copy() { + return new TreeSitterTurtle( copyPtr() ); + } +} diff --git a/core/esmf-tree-sitter-turtle/src/main/js/NOTICE.md b/core/esmf-tree-sitter-turtle/src/main/js/NOTICE.md new file mode 100644 index 000000000..c3efbd98b --- /dev/null +++ b/core/esmf-tree-sitter-turtle/src/main/js/NOTICE.md @@ -0,0 +1,3 @@ +The source of grammar.js is https://github.com/GordianDziwis/tree-sitter-turtle/blob/main/grammar.js + +This file is licensed under the terms of the MIT License, see https://github.com/GordianDziwis/tree-sitter-turtle/blob/main/LICENSE diff --git a/core/esmf-tree-sitter-turtle/src/main/js/grammar.js b/core/esmf-tree-sitter-turtle/src/main/js/grammar.js new file mode 100644 index 000000000..402aae1e0 --- /dev/null +++ b/core/esmf-tree-sitter-turtle/src/main/js/grammar.js @@ -0,0 +1,466 @@ +// [X] See section "6.5 Grammar" in https://www.w3.org/TR/turtle/#sec-grammar-grammar for +// corresponding rule x. + +// [26] +const UCHAR = /(\\u[0-9A-Fa-f]{4}|\\U[0-9A-Fa-f]{8})/ + +// [154s] +const EXPONENT = [ + /[eE]/, + /[+-]?/, + /\d+/ +] + +// [161s] +const WS = [ + /\x20/, + /\x09/, + /\x0D/, + /\x0A/ +] + +// [163s] +const PN_CHARS_BASE = [ + /[A-Z]/, + /[a-z]/, + /[\u00C0-\u00D6]/, + /[\u00D8-\u00F6]/, + /[\u00F8-\u02FF]/, + /[\u0370-\u037D]/, + /[\u037F-\u1FFF]/, + /[\u200C-\u200D]/, + /[\u2070-\u218F]/, + /[\u2C00-\u2FEF]/, + /[\u3001-\uD7FF]/, + /[\uF900-\uFDCF]/, + /[\uFDF0-\uFFFD]/, + /[\u{10000}-\u{EFFFF}]/u +] + +// [164s] +const PN_CHARS_U = PN_CHARS_BASE.concat('_') + +// [166s] +const PN_CHARS = PN_CHARS_U.concat([ + '-', + /\d/, + /[\u00B7]/, + /[\u0300-\u036F]/, + /[\u203F-\u2040]/ +]) + +// [171s] +const HEX = [ + /\d/, + /[A-F]/, + /[a-f]/ +] + +// [172s] +const PN_LOCAL_ESC = [ + '_', + '~', + '.', + '-', + '!', + '$', + '&', + "'", + '(', + ')', + '*', + '+', + ',', + ';', + '=', + '/', + '?', + '#', + '@', + '%' +].map(char => '\\' + char) + +String.prototype.toCaseInsensitive = function() { + return alias( + token(new RegExp( + this + .split('') + .map(letter => `[${letter}${letter.toLowerCase()}]`) + .join('') + )), + this + ) +} + +module.exports = grammar({ + name: 'turtle', + + extras: $ => [ + $.comment, + /\s/ + ], + + word: $ => $.pn_prefix, + + rules: { + + // [1g] trigDoc ::= (directive | block)* + document: $ => repeat(choice($.directive, $.triple, $.graph)), + + // wrappedGraph ::= '{' triplesBlock? '}' + // NOTE the last wrappedGraph triple does not have to terminate in a '.' + graph: $ => seq( + optional(field('label', $._label)), + '{', + seq( + repeat($.triple), + optional($._triples), + ), + '}', + ), + + // [7g] labelOrSubject ::= iri | BlankNode + _label: $ => seq(optional('GRAPH'), choice($._iri, $._blank_node)), + + comment: _ => token(prec(-1, /#.*/)), + + // [2] + // Triple Statement vs Graph Statement: + // https://www.w3.org/TR/trig/#sec-triple-statements + triple: $ => seq($._triples, '.'), + + // [3] + directive: $ => choice( + $.prefix_id, + $.base, + $.sparql_prefix, + $.sparql_base + ), + + // [4] + prefix_id: $ => seq( + '@prefix', + $.namespace, + $.iri_reference, + '.' + ), + + // [5] + base: $ => seq( + '@base', + $.iri_reference, + '.' + ), + + // [5s] + sparql_base: $ => seq( + 'BASE'.toCaseInsensitive(), + $.iri_reference, + ), + + // [6s] + sparql_prefix: $ => seq( + 'PREFIX'.toCaseInsensitive(), + $.namespace, + $.iri_reference, + ), + + // [6] + _triples: $ => choice( + seq( + $.subject, + $.property_list + ), + seq( + $.blank_node_property_list, + optional($.property_list) + ) + ), + + // [7] + property_list: $ => seq( + $.property, + repeat(seq( + ';', + optional($.property) + )) + ), + + // Enable incremental selection of properties + property: $ => seq( + $.predicate, + $.object_list, + ), + + // [8] + object_list: $ => seq( + $._object, + repeat(seq( + ',', + $._object + )) + ), + + // [9] + // [11] + predicate: $ => choice( + $._iri, + 'a' + ), + + // [10] + subject: $ => choice( + $._iri, + $._blank_node, + $.collection + ), + + // [12] + _object: $ => choice( + $._iri, + $._blank_node, + $.collection, + $.blank_node_property_list, + $._literal + ), + + // [13] + _literal: $ => choice( + $.rdf_literal, + $._numeric_literal, + $.boolean_literal + ), + + // [14] + blank_node_property_list: $ => seq( + '[', + $.property_list, + ']' + ), + + // [15] + collection: $ => seq( + '(', + optional($.object_collection), + ')' + ), + + // Enable incremental selection analog to blank_node_property_list + object_collection: $ => repeat1( + $._object, + ), + + // [16] + _numeric_literal: $ => choice( + $.integer, + $.decimal, + $.double + ), + + // [17] + string: $ => choice( + $._string_literal_quote, + $._string_literal_single_quote, + $._string_literal_long_quote, + $._string_literal_long_single_quote, + ), + + // [18] + iri_reference: _ => + seq( + '<', + // expose <#leading> anchor for syntax highlighting + optional(token(prec(1, '#'))), + token.immediate( + repeat(choice(/([^<>"{}|^`\\\x00-\x20])/, UCHAR)), + ), + + token.immediate('>'), + ), + + // [19] + integer: _ => token(/[+-]?\d+/), + + // [20] + decimal: _ => token(seq(/[+-]?/, /\d*/, '.', /\d+/)), + + // [21] + double: _ => token(seq( + /[+-]?/, + choice( + seq(/\d+/, '.', /\d*/, seq(...EXPONENT)), + seq('.', /\d+/, seq(...EXPONENT)), + seq(/\d+/, seq(...EXPONENT)) + )) + ), + + // [22] + _string_literal_quote: $ => seq( + '"', + repeat(choice( + /[^\x22\x5C\x0A\x0D]/, + $.echar, + UCHAR + )), + '"', + ), + + // [23] + _string_literal_single_quote: $ => seq( + "'", + repeat(choice( + /[^\x27\x5C\x0A\x0D]/, + $.echar, + UCHAR + )), + "'" + ), + + // [24] + _string_literal_long_single_quote: $ => seq( + "'''", + repeat(seq( + optional(choice( + "'", + "''", + )), + choice( + /[^'\\]/, + $.echar, + UCHAR + ) + )), + "'''", + ), + + // [25] + _string_literal_long_quote: $ => seq( + '"""', + repeat(seq( + optional(choice( + '"', + '""', + )), + choice( + /[^"\\]/, + $.echar, + UCHAR + ) + )), + '"""', + ), + + // [128s] + rdf_literal: $ => seq( + field('value', $.string), + optional(choice( + $.lang_tag, + field('datatype', seq('^^', $._iri)) + )) + ), + + // [133s] + boolean_literal: _ => choice( + 'true', + 'false' + ), + + // [135s] + _iri: $ => choice( + $.iri_reference, + $.prefixed_name + ), + + // [136s] + prefixed_name: $ => seq( + $.namespace, + optional($.pn_local) + ), + + // [137s] + _blank_node: $ => choice( + $.blank_node_label, + $.anon + ), + + // [139s] + namespace: $ => seq( + optional($.pn_prefix), + ':' + ), + + // [141s] + blank_node_label: _ => seq( + '_:', + token.immediate(seq( + choice( + ...PN_CHARS_U, + /\d/ + ), + optional(seq( + repeat(choice( + ...PN_CHARS, + '.' + )), + choice(...PN_CHARS) + )) + )) + ), + + // [144s] + lang_tag: _ => token(seq( + '@', + /[a-zA-Z]+/, + repeat(seq('-', /[a-zA-Z0-9]+/)) + )), + + // [159s] + echar: _ => /\\[tbnrf\\"']/, + + // [162s] + anon: _ => token(seq( + '[', + repeat(choice(...WS)), + ']' + )), + + // [167s] + pn_prefix: _ => token(seq( + choice(...PN_CHARS_BASE), + optional(seq( + repeat(choice( + ...PN_CHARS, + '.' + )), + choice(...PN_CHARS) + )) + )), + + // [168s] + pn_local: _ => token.immediate(seq( + choice( + ...PN_CHARS_U, + ':', + /\d/, + seq('%', choice(...HEX), choice(...HEX)), + ...PN_LOCAL_ESC + ), + optional(seq( + repeat(choice( + ...PN_CHARS, + '.', + ':', + seq('%', choice(...HEX), choice(...HEX)), + ...PN_LOCAL_ESC + )), + choice( + ...PN_CHARS, + ':', + seq('%', choice(...HEX), choice(...HEX)), + ...PN_LOCAL_ESC + ) + )) + )), + + } +}) diff --git a/core/esmf-tree-sitter-turtle/src/main/js/tree-sitter.json b/core/esmf-tree-sitter-turtle/src/main/js/tree-sitter.json new file mode 100644 index 000000000..4b6137bde --- /dev/null +++ b/core/esmf-tree-sitter-turtle/src/main/js/tree-sitter.json @@ -0,0 +1,37 @@ +{ + "$schema": "https://tree-sitter.github.io/tree-sitter/assets/schemas/config.schema.json", + "grammars": [ + { + "name": "turtle", + "camelcase": "Turtle", + "title": "RDF/Turtle Parser", + "scope": "source.turtle", + "file-types": [ + "ttl" + ], + "injection-regex": "^turtle$", + "class-name": "TreeSitterTurtle" + } + ], + "metadata": { + "version": "0.0.0", + "license": "EPL-2.0", + "description": "Turtle grammar for tree-sitter", + "authors": [ + { + "name": "Eclipse Semantic Modeling Framework Team", + "email": "esmf-dev@eclipse.org", + "url": "https://eclipse-esmf.github.io/" + } + ] + }, + "bindings": { + "c": false, + "go": false, + "node": false, + "python": false, + "rust": false, + "swift": false, + "zig": false + } +} diff --git a/core/esmf-tree-sitter-turtle/src/test/java/org/eclipse/esmf/treesitterturtle/TreeSitterTurtleTest.java b/core/esmf-tree-sitter-turtle/src/test/java/org/eclipse/esmf/treesitterturtle/TreeSitterTurtleTest.java new file mode 100644 index 000000000..9ded35f1b --- /dev/null +++ b/core/esmf-tree-sitter-turtle/src/test/java/org/eclipse/esmf/treesitterturtle/TreeSitterTurtleTest.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2026 Robert Bosch Manufacturing Solutions GmbH + * + * See the AUTHORS file(s) distributed with this work for additional + * information regarding authorship. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * SPDX-License-Identifier: MPL-2.0 + */ + +package org.eclipse.esmf.treesitterturtle; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.Test; +import org.treesitter.TSLanguage; +import org.treesitter.TSNode; +import org.treesitter.TSParser; +import org.treesitter.TSTree; + +public class TreeSitterTurtleTest { + @Test + void testParser() { + final TSParser parser = new TSParser(); + final TSLanguage turtle = new TreeSitterTurtle(); + parser.setLanguage( turtle ); + final TSTree tree = parser.parseString( null, """ + @prefix : . + :a a :b . + """ ); + final TSNode rootNode = tree.getRootNode(); + assertThat( rootNode.toString() ).doesNotContain( "ERROR" ); + assertThat( rootNode.getChild( 0 ).getChild( 0 ).getChild( 0 ).getGrammarType() ).isEqualTo( "@prefix" ); + System.out.println( rootNode ); + } +} diff --git a/pom.xml b/pom.xml index 53c7bbe0e..e0bf6e382 100644 --- a/pom.xml +++ b/pom.xml @@ -63,6 +63,7 @@ core/esmf-aspect-model-urn core/esmf-aspect-model-validator core/esmf-aspect-static-meta-model-java + core/esmf-tree-sitter-turtle core/esmf-test-aspect-models core/esmf-test-resources tools/esmf-aspect-model-maven-plugin From 0de08d523407e863b81c7c4f6135845ced5767d8 Mon Sep 17 00:00:00 2001 From: Andreas Textor Date: Mon, 23 Mar 2026 09:59:02 +0100 Subject: [PATCH 02/41] Don't use list of hardcoded source files in Zig NativeCompile --- .../org/eclipse/esmf/buildtime/NativeCompile.java | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/core/esmf-tree-sitter-turtle/src-buildtime/main/java/org/eclipse/esmf/buildtime/NativeCompile.java b/core/esmf-tree-sitter-turtle/src-buildtime/main/java/org/eclipse/esmf/buildtime/NativeCompile.java index 2ec077de9..463657243 100644 --- a/core/esmf-tree-sitter-turtle/src-buildtime/main/java/org/eclipse/esmf/buildtime/NativeCompile.java +++ b/core/esmf-tree-sitter-turtle/src-buildtime/main/java/org/eclipse/esmf/buildtime/NativeCompile.java @@ -14,10 +14,13 @@ package org.eclipse.esmf.buildtime; import java.io.File; +import java.io.IOException; +import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; import java.util.List; import java.util.Optional; +import java.util.stream.Stream; import org.eclipse.esmf.aspectmodel.resolver.process.BinaryLauncher; import org.eclipse.esmf.aspectmodel.resolver.process.ProcessLauncher; @@ -89,8 +92,13 @@ private void runZig() { args.add( nativeSourcesDirectory.resolve( "include" ).resolve( currentOs.toString() ).toString() ); args.add( "-o" ); args.add( libFilename.getAbsolutePath() ); - args.add( nativeSourcesDirectory.resolve( "parser.c" ).toString() ); - args.add( nativeSourcesDirectory.resolve( "org_eclipse_esmf_treesitterturtle_TreeSitterTurtle.c" ).toString() ); + try ( final Stream subpaths = Files.list( nativeSourcesDirectory ) ) { + subpaths.filter( sourceFile -> sourceFile.toFile().isFile() ) + .filter( sourceFile -> sourceFile.getFileName().toString().endsWith( ".c" ) ) + .forEach( sourceFile -> args.add( sourceFile.toString() ) ); + } catch ( final IOException exception ) { + throw new BuildTimeException( exception ); + } System.out.println( zigExe().getAbsolutePath() + " " + String.join( " ", args ) ); mkdir( libOutputDirectory ); From 1bf835aa516e8159e6cc37052ba86e1b2084cad0 Mon Sep 17 00:00:00 2001 From: Andreas Textor Date: Tue, 21 Apr 2026 11:19:11 +0200 Subject: [PATCH 03/41] Add initial structure for Turtle language server Co-authored-by: e-filchenko-bosh --- core/esmf-turtle-language-server/pom.xml | 78 ++++++++++ .../esmf/turtle/languageserver/App.java | 46 ++++++ .../languageserver/TurtleLanguageServer.java | 93 +++++++++++ .../diagnostic/AspectDiagnosticMapper.java | 63 ++++++++ .../aspect/model/AspectValidationError.java | 19 +++ .../model/AspectValidationErrorType.java | 21 +++ .../aspect/model/AspectValidationResult.java | 23 +++ .../aspect/model/AspectViolationInfo.java | 24 +++ .../request/ValidateDocumentParams.java | 19 +++ .../service/AspectModelValidationService.java | 27 ++++ .../service/AspectValidationCoordinator.java | 102 ++++++++++++ .../DefaultAspectModelValidationService.java | 145 ++++++++++++++++++ .../common/uri/DocumentUriResolver.java | 30 ++++ .../lsp/text/AspectDiagnosticsWorkflow.java | 71 +++++++++ .../text/DocumentAspectValidationService.java | 124 +++++++++++++++ .../lsp/text/DocumentDiagnosticsService.java | 60 ++++++++ .../lsp/text/DocumentDiagnosticsStore.java | 50 ++++++ .../lsp/text/DocumentStore.java | 37 +++++ .../lsp/text/TextDocumentClientNotifier.java | 56 +++++++ .../text/TurtleSyntaxValidationService.java | 69 +++++++++ .../lsp/text/TurtleTextDocumentService.java | 143 +++++++++++++++++ .../lsp/workspace/TurtleWorkspaceService.java | 30 ++++ .../TurtlePrefixDefinitionService.java | 108 +++++++++++++ .../src/main/resources/logback.xml | 32 ++++ pom.xml | 10 ++ 25 files changed, 1480 insertions(+) create mode 100644 core/esmf-turtle-language-server/pom.xml create mode 100644 core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/App.java create mode 100644 core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/TurtleLanguageServer.java create mode 100644 core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/aspect/diagnostic/AspectDiagnosticMapper.java create mode 100644 core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/aspect/model/AspectValidationError.java create mode 100644 core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/aspect/model/AspectValidationErrorType.java create mode 100644 core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/aspect/model/AspectValidationResult.java create mode 100644 core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/aspect/model/AspectViolationInfo.java create mode 100644 core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/aspect/request/ValidateDocumentParams.java create mode 100644 core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/aspect/service/AspectModelValidationService.java create mode 100644 core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/aspect/service/AspectValidationCoordinator.java create mode 100644 core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/aspect/service/DefaultAspectModelValidationService.java create mode 100644 core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/common/uri/DocumentUriResolver.java create mode 100644 core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/AspectDiagnosticsWorkflow.java create mode 100644 core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/DocumentAspectValidationService.java create mode 100644 core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/DocumentDiagnosticsService.java create mode 100644 core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/DocumentDiagnosticsStore.java create mode 100644 core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/DocumentStore.java create mode 100644 core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TextDocumentClientNotifier.java create mode 100644 core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TurtleSyntaxValidationService.java create mode 100644 core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TurtleTextDocumentService.java create mode 100644 core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/workspace/TurtleWorkspaceService.java create mode 100644 core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/turtle/navigation/TurtlePrefixDefinitionService.java create mode 100644 core/esmf-turtle-language-server/src/main/resources/logback.xml diff --git a/core/esmf-turtle-language-server/pom.xml b/core/esmf-turtle-language-server/pom.xml new file mode 100644 index 000000000..ebe824a56 --- /dev/null +++ b/core/esmf-turtle-language-server/pom.xml @@ -0,0 +1,78 @@ + + + + + + org.eclipse.esmf + esmf-sdk-parent + DEV-SNAPSHOT + ../../pom.xml + + 4.0.0 + + esmf-turtle-language-server + ESMF RDF/Turtle Language Server + jar + + + 1.0.0 + + + + + org.eclipse.esmf + esmf-aspect-meta-model-java + + + org.eclipse.esmf + esmf-aspect-model-validator + + + org.eclipse.esmf + esmf-tree-sitter-turtle + + + org.slf4j + slf4j-nop + + + + + org.eclipse.lsp4j + org.eclipse.lsp4j + ${lsp4j.version} + + + org.slf4j + slf4j-api + + + ch.qos.logback + logback-classic + + + + org.junit.jupiter + junit-jupiter + test + + + org.assertj + assertj-core + test + + + diff --git a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/App.java b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/App.java new file mode 100644 index 000000000..5398ec1aa --- /dev/null +++ b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/App.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2026 Robert Bosch Manufacturing Solutions GmbH + * + * See the AUTHORS file(s) distributed with this work for additional + * information regarding authorship. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * SPDX-License-Identifier: MPL-2.0 + */ + +package org.eclipse.esmf.turtle.languageserver; + +import org.eclipse.lsp4j.jsonrpc.Launcher; +import org.eclipse.lsp4j.services.LanguageClient; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class App { + private static final Logger LOG = LoggerFactory.getLogger( App.class ); + + static void main( final String[] args ) { + LOG.info( "Starting lsp-server" ); + final TurtleLanguageServer server = new TurtleLanguageServer(); + + try { + final Launcher launcher = Launcher.createLauncher( + server, + LanguageClient.class, + System.in, + System.out + ); + + server.connect( launcher.getRemoteProxy() ); + launcher.startListening().get(); + LOG.info( "Language server listener stopped" ); + } catch ( final InterruptedException ex ) { + Thread.currentThread().interrupt(); + LOG.error( "Language server listener was interrupted", ex ); + } catch ( final Exception ex ) { + LOG.error( "Language server terminated with an error", ex ); + } + } +} diff --git a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/TurtleLanguageServer.java b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/TurtleLanguageServer.java new file mode 100644 index 000000000..4f39596ec --- /dev/null +++ b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/TurtleLanguageServer.java @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2026 Robert Bosch Manufacturing Solutions GmbH + * + * See the AUTHORS file(s) distributed with this work for additional + * information regarding authorship. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * SPDX-License-Identifier: MPL-2.0 + */ + +package org.eclipse.esmf.turtle.languageserver; + +import java.util.concurrent.CompletableFuture; + +import org.eclipse.lsp4j.InitializeParams; +import org.eclipse.lsp4j.InitializeResult; +import org.eclipse.lsp4j.SaveOptions; +import org.eclipse.lsp4j.ServerCapabilities; +import org.eclipse.lsp4j.TextDocumentSyncKind; +import org.eclipse.lsp4j.TextDocumentSyncOptions; +import org.eclipse.lsp4j.jsonrpc.services.JsonRequest; +import org.eclipse.lsp4j.services.LanguageClient; +import org.eclipse.lsp4j.services.LanguageClientAware; +import org.eclipse.lsp4j.services.LanguageServer; +import org.eclipse.lsp4j.services.TextDocumentService; +import org.eclipse.lsp4j.services.WorkspaceService; + +import org.eclipse.esmf.turtle.languageserver.aspect.model.AspectValidationResult; +import org.eclipse.esmf.turtle.languageserver.aspect.request.ValidateDocumentParams; +import org.eclipse.esmf.turtle.languageserver.lsp.text.TurtleTextDocumentService; +import org.eclipse.esmf.turtle.languageserver.lsp.workspace.TurtleWorkspaceService; + +public class TurtleLanguageServer implements LanguageServer, LanguageClientAware { + private final TurtleTextDocumentService textDocumentService; + private final TurtleWorkspaceService workspaceService; + + public TurtleLanguageServer() { + this( new TurtleTextDocumentService() ); + } + + TurtleLanguageServer( final TurtleTextDocumentService textDocumentService ) { + this.textDocumentService = textDocumentService; + workspaceService = new TurtleWorkspaceService( textDocumentService ); + } + + @Override + public CompletableFuture initialize( final InitializeParams params ) { + final ServerCapabilities capabilities = new ServerCapabilities(); + final TextDocumentSyncOptions syncOptions = new TextDocumentSyncOptions(); + syncOptions.setOpenClose( true ); + syncOptions.setChange( TextDocumentSyncKind.Full ); + syncOptions.setSave( new SaveOptions( true ) ); + capabilities.setTextDocumentSync( syncOptions ); + capabilities.setDefinitionProvider( true ); + + return CompletableFuture.completedFuture( new InitializeResult( capabilities ) ); + } + + @Override + public CompletableFuture shutdown() { + textDocumentService.shutdown(); + return CompletableFuture.completedFuture( null ); + } + + @Override + public void exit() { + throw new UnsupportedOperationException(); + } + + @Override + public TextDocumentService getTextDocumentService() { + return textDocumentService; + } + + @Override + public WorkspaceService getWorkspaceService() { + return workspaceService; + } + + @Override + public void connect( final LanguageClient client ) { + textDocumentService.connect( client ); + } + + @JsonRequest( "turtle/aspectValidation/validateDocument" ) + public CompletableFuture validateDocument( final ValidateDocumentParams params ) { + final String uri = params != null ? params.uri() : null; + return CompletableFuture.completedFuture( textDocumentService.validateDocument( uri ) ); + } +} diff --git a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/aspect/diagnostic/AspectDiagnosticMapper.java b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/aspect/diagnostic/AspectDiagnosticMapper.java new file mode 100644 index 000000000..838d94bd9 --- /dev/null +++ b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/aspect/diagnostic/AspectDiagnosticMapper.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2026 Robert Bosch Manufacturing Solutions GmbH + * + * See the AUTHORS file(s) distributed with this work for additional + * information regarding authorship. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * SPDX-License-Identifier: MPL-2.0 + */ + +package org.eclipse.esmf.turtle.languageserver.aspect.diagnostic; + +import java.net.URI; +import java.util.List; + +import org.eclipse.esmf.turtle.languageserver.aspect.model.AspectValidationResult; +import org.eclipse.esmf.turtle.languageserver.aspect.model.AspectViolationInfo; + +import org.eclipse.lsp4j.Diagnostic; +import org.eclipse.lsp4j.DiagnosticSeverity; +import org.eclipse.lsp4j.Position; +import org.eclipse.lsp4j.Range; +import org.eclipse.lsp4j.jsonrpc.messages.Either; + +public final class AspectDiagnosticMapper { + public static final String SOURCE = "lsp-server.aspect"; + + public List toDiagnostics( final String documentUri, final AspectValidationResult result ) { + return result.violations().stream() + .filter( violation -> appliesToDocument( documentUri, violation ) ) + .map( this::toDiagnostic ) + .toList(); + } + + private boolean appliesToDocument( final String documentUri, final AspectViolationInfo violation ) { + if ( violation.sourceLocation() == null ) { + return true; + } + + return URI.create( documentUri ).equals( violation.sourceLocation() ); + } + + private Diagnostic toDiagnostic( final AspectViolationInfo violation ) { + final Diagnostic diagnostic = new Diagnostic(); + diagnostic.setSource( SOURCE ); + diagnostic.setSeverity( DiagnosticSeverity.Error ); + diagnostic.setMessage( violation.message() ); + diagnostic.setCode( Either.forLeft( violation.code() ) ); + diagnostic.setRange( toRange( violation ) ); + return diagnostic; + } + + private Range toRange( final AspectViolationInfo violation ) { + final long line = violation.line() != null ? violation.line() : 1L; + final long column = violation.column() != null ? violation.column() : 1L; + final int safeLine = (int) Math.max( 0, line - 1 ); + final int safeColumn = (int) Math.max( 0, column - 1 ); + return new Range( new Position( safeLine, safeColumn ), new Position( safeLine, safeColumn + 1 ) ); + } +} diff --git a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/aspect/model/AspectValidationError.java b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/aspect/model/AspectValidationError.java new file mode 100644 index 000000000..478924c9a --- /dev/null +++ b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/aspect/model/AspectValidationError.java @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2026 Robert Bosch Manufacturing Solutions GmbH + * + * See the AUTHORS file(s) distributed with this work for additional + * information regarding authorship. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * SPDX-License-Identifier: MPL-2.0 + */ + +package org.eclipse.esmf.turtle.languageserver.aspect.model; + +public record AspectValidationError( + AspectValidationErrorType type, + String message +) {} diff --git a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/aspect/model/AspectValidationErrorType.java b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/aspect/model/AspectValidationErrorType.java new file mode 100644 index 000000000..1ccd3e90d --- /dev/null +++ b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/aspect/model/AspectValidationErrorType.java @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2026 Robert Bosch Manufacturing Solutions GmbH + * + * See the AUTHORS file(s) distributed with this work for additional + * information regarding authorship. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * SPDX-License-Identifier: MPL-2.0 + */ + +package org.eclipse.esmf.turtle.languageserver.aspect.model; + +public enum AspectValidationErrorType { + LOAD, + PARSE, + RESOLVE, + PROCESSING +} diff --git a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/aspect/model/AspectValidationResult.java b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/aspect/model/AspectValidationResult.java new file mode 100644 index 000000000..7d7fbd338 --- /dev/null +++ b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/aspect/model/AspectValidationResult.java @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2026 Robert Bosch Manufacturing Solutions GmbH + * + * See the AUTHORS file(s) distributed with this work for additional + * information regarding authorship. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * SPDX-License-Identifier: MPL-2.0 + */ + +package org.eclipse.esmf.turtle.languageserver.aspect.model; + +import java.util.List; + +public record AspectValidationResult( + boolean valid, + String report, + List violations, + AspectValidationError error +) {} diff --git a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/aspect/model/AspectViolationInfo.java b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/aspect/model/AspectViolationInfo.java new file mode 100644 index 000000000..018393438 --- /dev/null +++ b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/aspect/model/AspectViolationInfo.java @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2026 Robert Bosch Manufacturing Solutions GmbH + * + * See the AUTHORS file(s) distributed with this work for additional + * information regarding authorship. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * SPDX-License-Identifier: MPL-2.0 + */ + +package org.eclipse.esmf.turtle.languageserver.aspect.model; + +import java.net.URI; + +public record AspectViolationInfo( + String code, + String message, + URI sourceLocation, + Long line, + Long column +) {} diff --git a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/aspect/request/ValidateDocumentParams.java b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/aspect/request/ValidateDocumentParams.java new file mode 100644 index 000000000..3317ffedf --- /dev/null +++ b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/aspect/request/ValidateDocumentParams.java @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2026 Robert Bosch Manufacturing Solutions GmbH + * + * See the AUTHORS file(s) distributed with this work for additional + * information regarding authorship. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * SPDX-License-Identifier: MPL-2.0 + */ + +package org.eclipse.esmf.turtle.languageserver.aspect.request; + +public record ValidateDocumentParams( + String uri, + String reason +) {} diff --git a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/aspect/service/AspectModelValidationService.java b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/aspect/service/AspectModelValidationService.java new file mode 100644 index 000000000..2454562da --- /dev/null +++ b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/aspect/service/AspectModelValidationService.java @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2026 Robert Bosch Manufacturing Solutions GmbH + * + * See the AUTHORS file(s) distributed with this work for additional + * information regarding authorship. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * SPDX-License-Identifier: MPL-2.0 + */ + +package org.eclipse.esmf.turtle.languageserver.aspect.service; + +import java.io.File; +import java.nio.file.Path; + +import org.eclipse.esmf.turtle.languageserver.aspect.model.AspectValidationResult; + +public interface AspectModelValidationService { + AspectValidationResult validate( Path path ); + + default AspectValidationResult validate( final File file ) { + return validate( file.toPath() ); + } +} diff --git a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/aspect/service/AspectValidationCoordinator.java b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/aspect/service/AspectValidationCoordinator.java new file mode 100644 index 000000000..78f243031 --- /dev/null +++ b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/aspect/service/AspectValidationCoordinator.java @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2026 Robert Bosch Manufacturing Solutions GmbH + * + * See the AUTHORS file(s) distributed with this work for additional + * information regarding authorship. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * SPDX-License-Identifier: MPL-2.0 + */ + +package org.eclipse.esmf.turtle.languageserver.aspect.service; + +import java.nio.file.Path; +import java.util.Map; +import java.util.concurrent.CancellationException; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.atomic.AtomicLong; +import java.util.function.BiConsumer; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.eclipse.esmf.turtle.languageserver.aspect.model.AspectValidationError; +import org.eclipse.esmf.turtle.languageserver.aspect.model.AspectValidationErrorType; +import org.eclipse.esmf.turtle.languageserver.aspect.model.AspectValidationResult; + +public class AspectValidationCoordinator implements AutoCloseable { + private static final Logger LOG = LoggerFactory.getLogger( AspectValidationCoordinator.class ); + private final AspectModelValidationService validationService; + private final ExecutorService executorService; + private final Map> inFlight = new ConcurrentHashMap<>(); + private final Map generations = new ConcurrentHashMap<>(); + + public AspectValidationCoordinator( final AspectModelValidationService validationService ) { + this( validationService, Executors.newSingleThreadExecutor( Thread.ofPlatform().name( "aspect-validation-", 0 ).factory() ) ); + } + + AspectValidationCoordinator( final AspectModelValidationService validationService, final ExecutorService executorService ) { + this.validationService = validationService; + this.executorService = executorService; + } + + public long nextGeneration( final String uri ) { + return generations.computeIfAbsent( uri, ignored -> new AtomicLong() ).incrementAndGet(); + } + + public long currentGeneration( final String uri ) { + final AtomicLong generation = generations.get( uri ); + return generation != null ? generation.get() : 0L; + } + + public void cancel( final String uri ) { + final CompletableFuture previous = inFlight.remove( uri ); + if ( previous != null ) { + LOG.debug( "[cancel] cancelling previous aspect validation for {}", uri ); + previous.cancel( true ); + } + } + + public void submit( final String uri, final Path path, final long generation, final BiConsumer callback ) { + cancel( uri ); + final CompletableFuture future = CompletableFuture.supplyAsync( + () -> validationService.validate( path ), + executorService + ); + inFlight.put( uri, future ); + future.whenComplete( ( result, throwable ) -> { + inFlight.remove( uri, future ); + if ( throwable instanceof CancellationException || future.isCancelled() ) { + LOG.debug( "[cancel] aspect validation cancelled for {}", uri ); + return; + } + if ( throwable != null ) { + LOG.error( "[publish diagnostics] aspect validation failed for {}", uri, throwable ); + callback.accept( generation, new AspectValidationResult( + false, + throwable.getMessage(), + java.util.List.of(), + new AspectValidationError( AspectValidationErrorType.PROCESSING, throwable.getMessage() ) + ) ); + return; + } + callback.accept( generation, result ); + } ); + } + + public AspectValidationResult validateSync( final Path path ) { + return validationService.validate( path ); + } + + @Override + public void close() { + inFlight.values().forEach( future -> future.cancel( true ) ); + executorService.shutdownNow(); + } +} diff --git a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/aspect/service/DefaultAspectModelValidationService.java b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/aspect/service/DefaultAspectModelValidationService.java new file mode 100644 index 000000000..f95823bce --- /dev/null +++ b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/aspect/service/DefaultAspectModelValidationService.java @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2026 Robert Bosch Manufacturing Solutions GmbH + * + * See the AUTHORS file(s) distributed with this work for additional + * information regarding authorship. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * SPDX-License-Identifier: MPL-2.0 + */ + +package org.eclipse.esmf.turtle.languageserver.aspect.service; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.List; +import java.util.Optional; + +import org.eclipse.esmf.aspectmodel.loader.AspectModelLoader; +import org.eclipse.esmf.aspectmodel.shacl.violation.Violation; +import org.eclipse.esmf.aspectmodel.validation.InvalidLexicalValueViolation; +import org.eclipse.esmf.aspectmodel.validation.InvalidSyntaxViolation; +import org.eclipse.esmf.aspectmodel.validation.ProcessingViolation; +import org.eclipse.esmf.aspectmodel.validation.services.AspectModelValidator; +import org.eclipse.esmf.aspectmodel.validation.services.DetailedViolationFormatter; +import org.eclipse.esmf.metamodel.AspectModel; +import org.eclipse.esmf.turtle.languageserver.aspect.model.AspectValidationError; +import org.eclipse.esmf.turtle.languageserver.aspect.model.AspectValidationErrorType; +import org.eclipse.esmf.turtle.languageserver.aspect.model.AspectValidationResult; +import org.eclipse.esmf.turtle.languageserver.aspect.model.AspectViolationInfo; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class DefaultAspectModelValidationService implements AspectModelValidationService { + private static final Logger LOAD_LOG = LoggerFactory.getLogger( "org.eclipse.esmf.turtle.languageserver.validation.aspect.load" ); + private static final Logger RESOLVE_LOG = LoggerFactory.getLogger( "org.eclipse.esmf.turtle.languageserver.validation.aspect.resolve" ); + private static final Logger VALIDATE_LOG = + LoggerFactory.getLogger( "org.eclipse.esmf.turtle.languageserver.validation.aspect.validate" ); + + private final AspectModelLoader loader; + private final AspectModelValidator validator; + + public DefaultAspectModelValidationService() { + this( new AspectModelLoader(), new AspectModelValidator() ); + } + + DefaultAspectModelValidationService( final AspectModelLoader loader, final AspectModelValidator validator ) { + this.loader = loader; + this.validator = validator; + } + + @Override + public AspectValidationResult validate( final Path path ) { + if ( path == null ) { + return failedResult( AspectValidationErrorType.LOAD, "Path must not be null" ); + } + + if ( !Files.exists( path ) ) { + return failedResult( AspectValidationErrorType.LOAD, "Aspect model file does not exist: " + path ); + } + + if ( !Files.isRegularFile( path ) || !Files.isReadable( path ) ) { + return failedResult( AspectValidationErrorType.LOAD, "Aspect model file is not readable: " + path ); + } + + try { + LOAD_LOG.debug( "[load] loading aspect model from {}", path ); + final List violations = validator.validateModel( () -> loadAspectModel( path ) ); + VALIDATE_LOG.debug( "[validate] validation finished for {} with {} violation(s)", path, violations.size() ); + final String report = new DetailedViolationFormatter().apply( violations ); + final AspectValidationError error = classifyError( violations ); + return new AspectValidationResult( violations.isEmpty(), report, violations.stream().map( this::toViolationInfo ).toList(), + error ); + } catch ( final Exception exception ) { + VALIDATE_LOG.error( "[validate] unexpected runtime failure for {}", path, exception ); + return failedResult( AspectValidationErrorType.PROCESSING, exception.getMessage() ); + } + } + + private AspectModel loadAspectModel( final Path path ) { + RESOLVE_LOG.debug( "[resolve imports] resolving imports for {}", path ); + return loader.load( path.toFile() ); + } + + private AspectValidationResult failedResult( final AspectValidationErrorType type, final String message ) { + return new AspectValidationResult( false, message, List.of(), new AspectValidationError( type, message ) ); + } + + private AspectValidationError classifyError( final List violations ) { + final Optional firstFailure = violations.stream() + .filter( violation -> violation instanceof InvalidSyntaxViolation || violation instanceof InvalidLexicalValueViolation + || violation instanceof ProcessingViolation ) + .findFirst(); + + if ( firstFailure.isEmpty() ) { + return null; + } + + final Violation violation = firstFailure.get(); + if ( violation instanceof final InvalidSyntaxViolation syntaxViolation ) { + return new AspectValidationError( AspectValidationErrorType.PARSE, syntaxViolation.message() ); + } + if ( violation instanceof final InvalidLexicalValueViolation lexicalValueViolation ) { + return new AspectValidationError( AspectValidationErrorType.PARSE, lexicalValueViolation.message() ); + } + + final String message = violation.message(); + final AspectValidationErrorType type = message != null && message.toLowerCase().contains( "resolve" ) + ? AspectValidationErrorType.RESOLVE + : AspectValidationErrorType.PROCESSING; + return new AspectValidationError( type, message ); + } + + private AspectViolationInfo toViolationInfo( final Violation violation ) { + if ( violation instanceof final InvalidSyntaxViolation syntaxViolation ) { + return new AspectViolationInfo( + syntaxViolation.errorCode(), + syntaxViolation.message(), + syntaxViolation.sourceLocation().orElse( null ), + syntaxViolation.line(), + syntaxViolation.column() + ); + } + if ( violation instanceof final InvalidLexicalValueViolation lexicalValueViolation ) { + return new AspectViolationInfo( + lexicalValueViolation.errorCode(), + lexicalValueViolation.message(), + lexicalValueViolation.sourceLocation().orElse( null ), + (long) lexicalValueViolation.line(), + (long) lexicalValueViolation.column() + ); + } + + return new AspectViolationInfo( + violation.errorCode(), + violation.message(), + violation.sourceLocation().orElse( null ), + null, + null + ); + } +} diff --git a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/common/uri/DocumentUriResolver.java b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/common/uri/DocumentUriResolver.java new file mode 100644 index 000000000..84044ae0e --- /dev/null +++ b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/common/uri/DocumentUriResolver.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2026 Robert Bosch Manufacturing Solutions GmbH + * + * See the AUTHORS file(s) distributed with this work for additional + * information regarding authorship. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * SPDX-License-Identifier: MPL-2.0 + */ + +package org.eclipse.esmf.turtle.languageserver.common.uri; + +import java.net.URI; +import java.nio.file.Path; +import java.nio.file.Paths; + +public final class DocumentUriResolver { + private DocumentUriResolver() {} + + public static Path toPath( final String uri ) { + if ( uri == null || !uri.startsWith( "file:" ) ) { + return null; + } + + return Paths.get( URI.create( uri ) ); + } +} diff --git a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/AspectDiagnosticsWorkflow.java b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/AspectDiagnosticsWorkflow.java new file mode 100644 index 000000000..aabf7e71e --- /dev/null +++ b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/AspectDiagnosticsWorkflow.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2026 Robert Bosch Manufacturing Solutions GmbH + * + * See the AUTHORS file(s) distributed with this work for additional + * information regarding authorship. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * SPDX-License-Identifier: MPL-2.0 + */ + +package org.eclipse.esmf.turtle.languageserver.lsp.text; + +import java.nio.file.Path; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.eclipse.esmf.turtle.languageserver.aspect.service.AspectValidationCoordinator; +import org.eclipse.esmf.turtle.languageserver.common.uri.DocumentUriResolver; + +public class AspectDiagnosticsWorkflow { + private static final Logger LOG = LoggerFactory.getLogger( AspectDiagnosticsWorkflow.class ); + private final AspectValidationCoordinator aspectValidationCoordinator; + private final DocumentDiagnosticsService diagnosticsService; + private final TextDocumentClientNotifier clientNotifier; + + public AspectDiagnosticsWorkflow( + final AspectValidationCoordinator aspectValidationCoordinator, + final DocumentDiagnosticsService diagnosticsService, + final TextDocumentClientNotifier clientNotifier ) { + this.aspectValidationCoordinator = aspectValidationCoordinator; + this.diagnosticsService = diagnosticsService; + this.clientNotifier = clientNotifier; + } + + public void onDocumentChanged( final String uri ) { + aspectValidationCoordinator.cancel( uri ); + diagnosticsService.clearAspect( uri ); + } + + public void onDocumentClosed( final String uri ) { + aspectValidationCoordinator.cancel( uri ); + diagnosticsService.clearAll( uri ); + } + + public void onDocumentSaved( final String uri ) { + final Path path = DocumentUriResolver.toPath( uri ); + if ( path == null ) { + LOG.info( "[scheduleAspectValidation] unsupported non-file uri={}, skipping aspect validation", uri ); + diagnosticsService.clearAspect( uri ); + clientNotifier.publishCombinedDiagnostics( uri ); + return; + } + + final long generation = aspectValidationCoordinator.nextGeneration( uri ); + aspectValidationCoordinator.submit( uri, path, generation, ( completedGeneration, result ) -> { + final long currentGeneration = aspectValidationCoordinator.currentGeneration( uri ); + if ( completedGeneration != currentGeneration ) { + LOG.debug( "[publish diagnostics] ignoring stale aspect diagnostics for uri={}, generation={}, current={}", uri, + completedGeneration, currentGeneration ); + return; + } + + diagnosticsService.updateAspect( uri, result ); + clientNotifier.publishCombinedDiagnostics( uri ); + } ); + } +} diff --git a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/DocumentAspectValidationService.java b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/DocumentAspectValidationService.java new file mode 100644 index 000000000..e2589d12b --- /dev/null +++ b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/DocumentAspectValidationService.java @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2026 Robert Bosch Manufacturing Solutions GmbH + * + * See the AUTHORS file(s) distributed with this work for additional + * information regarding authorship. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * SPDX-License-Identifier: MPL-2.0 + */ + +package org.eclipse.esmf.turtle.languageserver.lsp.text; + +import java.io.IOException; +import java.net.URI; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardOpenOption; +import java.util.List; +import java.util.Objects; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.eclipse.esmf.turtle.languageserver.aspect.model.AspectValidationError; +import org.eclipse.esmf.turtle.languageserver.aspect.model.AspectValidationErrorType; +import org.eclipse.esmf.turtle.languageserver.aspect.model.AspectValidationResult; +import org.eclipse.esmf.turtle.languageserver.aspect.model.AspectViolationInfo; +import org.eclipse.esmf.turtle.languageserver.aspect.service.AspectValidationCoordinator; +import org.eclipse.esmf.turtle.languageserver.common.uri.DocumentUriResolver; + +public class DocumentAspectValidationService { + private static final Logger LOG = LoggerFactory.getLogger( DocumentAspectValidationService.class ); + private final AspectValidationCoordinator aspectValidationCoordinator; + + public DocumentAspectValidationService( final AspectValidationCoordinator aspectValidationCoordinator ) { + this.aspectValidationCoordinator = aspectValidationCoordinator; + } + + public AspectValidationResult validateDocument( final String uri, final String content ) { + if ( content == null ) { + return failedValidation( AspectValidationErrorType.LOAD, "Document is not available in memory: " + uri ); + } + + final Path path = DocumentUriResolver.toPath( uri ); + if ( path == null ) { + return failedValidation( AspectValidationErrorType.LOAD, "Aspect validation supports only file URIs: " + uri ); + } + + return validateOpenDocument( uri, path, content ); + } + + private AspectValidationResult validateOpenDocument( final String uri, final Path originalPath, final String content ) { + final Path parent = originalPath.getParent(); + if ( parent == null ) { + return failedValidation( AspectValidationErrorType.LOAD, "Document path has no parent directory: " + originalPath ); + } + + final String originalFileName = originalPath.getFileName() != null ? originalPath.getFileName().toString() : "aspect"; + String tempPrefix = originalFileName.replaceAll( "[^A-Za-z0-9._-]", "_" ) + "-"; + if ( tempPrefix.length() < 3 ) { + tempPrefix = "ttl-"; + } + + Path tempFile = null; + try { + tempFile = Files.createTempFile( parent, tempPrefix, ".ttl" ); + Files.writeString( tempFile, content, StandardOpenOption.TRUNCATE_EXISTING ); + final AspectValidationResult result = aspectValidationCoordinator.validateSync( tempFile ); + return remapValidationResult( result, tempFile, originalPath, uri ); + } catch ( final IOException exception ) { + LOG.error( "[validateDocument] failed to prepare in-memory validation for {}", uri, exception ); + return failedValidation( AspectValidationErrorType.PROCESSING, exception.getMessage() ); + } finally { + if ( tempFile != null ) { + try { + Files.deleteIfExists( tempFile ); + } catch ( final IOException exception ) { + LOG.warn( "[validateDocument] failed to delete temp file {}", tempFile, exception ); + } + } + } + } + + private AspectValidationResult remapValidationResult( final AspectValidationResult result, final Path tempFile, final Path originalPath, + final String originalUri ) { + final URI tempUri = tempFile.toUri(); + final List remappedViolations = result.violations().stream() + .map( violation -> remapViolation( violation, tempUri, originalUri ) ) + .toList(); + final String remappedReport = remapReport( result.report(), tempFile, originalPath, originalUri ); + return new AspectValidationResult( result.valid(), remappedReport, remappedViolations, result.error() ); + } + + private AspectViolationInfo remapViolation( final AspectViolationInfo violation, final URI tempUri, final String originalUri ) { + if ( !Objects.equals( violation.sourceLocation(), tempUri ) ) { + return violation; + } + + return new AspectViolationInfo( + violation.code(), + violation.message(), + URI.create( originalUri ), + violation.line(), + violation.column() + ); + } + + private String remapReport( final String report, final Path tempFile, final Path originalPath, final String originalUri ) { + if ( report == null || report.isBlank() ) { + return report; + } + + return report + .replace( tempFile.toUri().toString(), originalUri ) + .replace( tempFile.toAbsolutePath().toString(), originalPath.toAbsolutePath().toString() ); + } + + private AspectValidationResult failedValidation( final AspectValidationErrorType type, final String message ) { + return new AspectValidationResult( false, message, List.of(), new AspectValidationError( type, message ) ); + } +} diff --git a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/DocumentDiagnosticsService.java b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/DocumentDiagnosticsService.java new file mode 100644 index 000000000..0465acf9a --- /dev/null +++ b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/DocumentDiagnosticsService.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2026 Robert Bosch Manufacturing Solutions GmbH + * + * See the AUTHORS file(s) distributed with this work for additional + * information regarding authorship. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * SPDX-License-Identifier: MPL-2.0 + */ + +package org.eclipse.esmf.turtle.languageserver.lsp.text; + +import java.util.List; + +import org.eclipse.lsp4j.Diagnostic; + +import org.eclipse.esmf.turtle.languageserver.aspect.diagnostic.AspectDiagnosticMapper; +import org.eclipse.esmf.turtle.languageserver.aspect.model.AspectValidationResult; + +public class DocumentDiagnosticsService { + private final TurtleSyntaxValidationService syntaxValidationService; + private final AspectDiagnosticMapper aspectDiagnosticMapper; + private final DocumentDiagnosticsStore diagnosticsStore; + + public DocumentDiagnosticsService() { + this( new TurtleSyntaxValidationService(), new AspectDiagnosticMapper(), new DocumentDiagnosticsStore() ); + } + + DocumentDiagnosticsService( + final TurtleSyntaxValidationService syntaxValidationService, + final AspectDiagnosticMapper aspectDiagnosticMapper, + final DocumentDiagnosticsStore diagnosticsStore ) { + this.syntaxValidationService = syntaxValidationService; + this.aspectDiagnosticMapper = aspectDiagnosticMapper; + this.diagnosticsStore = diagnosticsStore; + } + + public void updateSyntax( final String uri, final String content ) { + diagnosticsStore.putSyntax( uri, syntaxValidationService.validate( content ) ); + } + + public void updateAspect( final String uri, final AspectValidationResult result ) { + diagnosticsStore.putAspect( uri, aspectDiagnosticMapper.toDiagnostics( uri, result ) ); + } + + public void clearAspect( final String uri ) { + diagnosticsStore.clearAspect( uri ); + } + + public void clearAll( final String uri ) { + diagnosticsStore.clear( uri ); + } + + public List getCombined( final String uri ) { + return diagnosticsStore.getCombined( uri ); + } +} diff --git a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/DocumentDiagnosticsStore.java b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/DocumentDiagnosticsStore.java new file mode 100644 index 000000000..ee673441c --- /dev/null +++ b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/DocumentDiagnosticsStore.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2026 Robert Bosch Manufacturing Solutions GmbH + * + * See the AUTHORS file(s) distributed with this work for additional + * information regarding authorship. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * SPDX-License-Identifier: MPL-2.0 + */ + +package org.eclipse.esmf.turtle.languageserver.lsp.text; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import org.eclipse.lsp4j.Diagnostic; + +public class DocumentDiagnosticsStore { + private final Map> syntaxDiagnostics = new ConcurrentHashMap<>(); + private final Map> aspectDiagnostics = new ConcurrentHashMap<>(); + + public void putSyntax( final String uri, final List diagnostics ) { + syntaxDiagnostics.put( uri, List.copyOf( diagnostics ) ); + } + + public void putAspect( final String uri, final List diagnostics ) { + aspectDiagnostics.put( uri, List.copyOf( diagnostics ) ); + } + + public void clearAspect( final String uri ) { + aspectDiagnostics.remove( uri ); + } + + public void clear( final String uri ) { + syntaxDiagnostics.remove( uri ); + aspectDiagnostics.remove( uri ); + } + + public List getCombined( final String uri ) { + final List diagnostics = new ArrayList<>(); + diagnostics.addAll( syntaxDiagnostics.getOrDefault( uri, List.of() ) ); + diagnostics.addAll( aspectDiagnostics.getOrDefault( uri, List.of() ) ); + return diagnostics; + } +} diff --git a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/DocumentStore.java b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/DocumentStore.java new file mode 100644 index 000000000..e5ccb706a --- /dev/null +++ b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/DocumentStore.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2026 Robert Bosch Manufacturing Solutions GmbH + * + * See the AUTHORS file(s) distributed with this work for additional + * information regarding authorship. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * SPDX-License-Identifier: MPL-2.0 + */ + +package org.eclipse.esmf.turtle.languageserver.lsp.text; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +public class DocumentStore { + private final Map documents = new ConcurrentHashMap<>(); + + public void put( final String uri, final String content ) { + documents.put( uri, content ); + } + + public String get( final String uri ) { + return documents.get( uri ); + } + + public String getOrDefault( final String uri, final String fallback ) { + return documents.getOrDefault( uri, fallback ); + } + + public void remove( final String uri ) { + documents.remove( uri ); + } +} diff --git a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TextDocumentClientNotifier.java b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TextDocumentClientNotifier.java new file mode 100644 index 000000000..f63a43c6c --- /dev/null +++ b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TextDocumentClientNotifier.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2026 Robert Bosch Manufacturing Solutions GmbH + * + * See the AUTHORS file(s) distributed with this work for additional + * information regarding authorship. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * SPDX-License-Identifier: MPL-2.0 + */ + +package org.eclipse.esmf.turtle.languageserver.lsp.text; + +import java.util.List; + +import org.eclipse.lsp4j.Diagnostic; +import org.eclipse.lsp4j.PublishDiagnosticsParams; +import org.eclipse.lsp4j.services.LanguageClient; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class TextDocumentClientNotifier { + private static final Logger LOG = LoggerFactory.getLogger( TextDocumentClientNotifier.class ); + + private final DocumentDiagnosticsService diagnosticsService; + private LanguageClient client; + + public TextDocumentClientNotifier( final DocumentDiagnosticsService diagnosticsService ) { + this.diagnosticsService = diagnosticsService; + } + + public void connect( final LanguageClient client ) { + this.client = client; + } + + public void publishCombinedDiagnostics( final String uri ) { + if ( client == null ) { + LOG.warn( "[publishDiagnostics] client is null, skipping for uri={}", uri ); + return; + } + + final List diagnostics = diagnosticsService.getCombined( uri ); + LOG.debug( "[publish diagnostics] publishing {} diagnostic(s) for uri={}", diagnostics.size(), uri ); + client.publishDiagnostics( new PublishDiagnosticsParams( uri, diagnostics ) ); + } + + public void publishEmptyDiagnostics( final String uri ) { + if ( client == null ) { + return; + } + + client.publishDiagnostics( new PublishDiagnosticsParams( uri, List.of() ) ); + } +} diff --git a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TurtleSyntaxValidationService.java b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TurtleSyntaxValidationService.java new file mode 100644 index 000000000..093cf88fd --- /dev/null +++ b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TurtleSyntaxValidationService.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2026 Robert Bosch Manufacturing Solutions GmbH + * + * See the AUTHORS file(s) distributed with this work for additional + * information regarding authorship. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * SPDX-License-Identifier: MPL-2.0 + */ + +package org.eclipse.esmf.turtle.languageserver.lsp.text; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.jena.riot.Lang; +import org.apache.jena.riot.RDFParser; +import org.apache.jena.riot.RiotException; +import org.apache.jena.riot.RiotParseException; +import org.apache.jena.riot.system.ErrorHandlerFactory; +import org.apache.jena.riot.system.StreamRDFLib; +import org.eclipse.lsp4j.Diagnostic; +import org.eclipse.lsp4j.DiagnosticSeverity; +import org.eclipse.lsp4j.Position; +import org.eclipse.lsp4j.Range; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class TurtleSyntaxValidationService { + private static final Logger LOG = LoggerFactory.getLogger( TurtleSyntaxValidationService.class ); + private static final String SYNTAX_SOURCE = "lsp-server.syntax"; + + public List validate( final String content ) { + final List diagnostics = new ArrayList<>(); + + try { + RDFParser.create() + .fromString( content ) + .lang( Lang.TTL ) + .errorHandler( ErrorHandlerFactory.errorHandlerStrictNoLogging ) + .parse( StreamRDFLib.sinkNull() ); + LOG.debug( "[validate] turtle parsing successful" ); + } catch ( final RiotParseException exception ) { + LOG.warn( "[validate] parse error at line={}, col={}: {}", exception.getLine(), exception.getCol(), exception.getMessage() ); + diagnostics.add( toDiagnostic( exception.getMessage(), exception.getLine(), exception.getCol() ) ); + } catch ( final RiotException exception ) { + LOG.warn( "[validate] rdf error: {}", exception.getMessage() ); + diagnostics.add( toDiagnostic( exception.getMessage(), 1, 1 ) ); + } + + LOG.debug( "[validate] found {} diagnostic(s)", diagnostics.size() ); + return diagnostics; + } + + private Diagnostic toDiagnostic( final String message, final long line, final long column ) { + final int safeLine = (int) Math.max( 0, line - 1 ); + final int safeColumn = (int) Math.max( 0, column - 1 ); + + final Diagnostic diagnostic = new Diagnostic(); + diagnostic.setSource( SYNTAX_SOURCE ); + diagnostic.setSeverity( DiagnosticSeverity.Error ); + diagnostic.setMessage( message != null ? message : "Invalid Turtle syntax" ); + diagnostic.setRange( new Range( new Position( safeLine, safeColumn ), new Position( safeLine, safeColumn + 1 ) ) ); + return diagnostic; + } +} diff --git a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TurtleTextDocumentService.java b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TurtleTextDocumentService.java new file mode 100644 index 000000000..6f0c2051c --- /dev/null +++ b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TurtleTextDocumentService.java @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2026 Robert Bosch Manufacturing Solutions GmbH + * + * See the AUTHORS file(s) distributed with this work for additional + * information regarding authorship. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * SPDX-License-Identifier: MPL-2.0 + */ + +package org.eclipse.esmf.turtle.languageserver.lsp.text; + +import java.util.List; +import java.util.concurrent.CompletableFuture; + +import org.eclipse.lsp4j.DefinitionParams; +import org.eclipse.lsp4j.DidChangeTextDocumentParams; +import org.eclipse.lsp4j.DidCloseTextDocumentParams; +import org.eclipse.lsp4j.DidOpenTextDocumentParams; +import org.eclipse.lsp4j.DidSaveTextDocumentParams; +import org.eclipse.lsp4j.Location; +import org.eclipse.lsp4j.jsonrpc.messages.Either; +import org.eclipse.lsp4j.services.LanguageClient; +import org.eclipse.lsp4j.services.TextDocumentService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.eclipse.esmf.turtle.languageserver.aspect.model.AspectValidationResult; +import org.eclipse.esmf.turtle.languageserver.aspect.service.AspectModelValidationService; +import org.eclipse.esmf.turtle.languageserver.aspect.service.AspectValidationCoordinator; +import org.eclipse.esmf.turtle.languageserver.aspect.service.DefaultAspectModelValidationService; +import org.eclipse.esmf.turtle.languageserver.turtle.navigation.TurtlePrefixDefinitionService; + +public class TurtleTextDocumentService implements TextDocumentService { + private static final Logger LOG = LoggerFactory.getLogger( TurtleTextDocumentService.class ); + private final DocumentStore documentStore; + private final DocumentDiagnosticsService diagnosticsService; + private final TextDocumentClientNotifier clientNotifier; + private final TurtlePrefixDefinitionService prefixDefinitionService; + private final DocumentAspectValidationService documentValidationService; + private final AspectDiagnosticsWorkflow aspectDiagnosticsWorkflow; + private final AspectValidationCoordinator aspectValidationCoordinator; + + public TurtleTextDocumentService() { + this( new DefaultAspectModelValidationService() ); + } + + public TurtleTextDocumentService( final AspectModelValidationService aspectValidationService ) { + this( + new DocumentStore(), + new DocumentDiagnosticsService(), + new TurtlePrefixDefinitionService(), + new AspectValidationCoordinator( aspectValidationService ) + ); + } + + TurtleTextDocumentService( + final DocumentStore documentStore, + final DocumentDiagnosticsService diagnosticsService, + final TurtlePrefixDefinitionService prefixDefinitionService, + final AspectValidationCoordinator aspectValidationCoordinator ) { + this.documentStore = documentStore; + this.diagnosticsService = diagnosticsService; + this.prefixDefinitionService = prefixDefinitionService; + this.aspectValidationCoordinator = aspectValidationCoordinator; + clientNotifier = new TextDocumentClientNotifier( diagnosticsService ); + documentValidationService = new DocumentAspectValidationService( aspectValidationCoordinator ); + aspectDiagnosticsWorkflow = new AspectDiagnosticsWorkflow( aspectValidationCoordinator, diagnosticsService, clientNotifier ); + } + + public void connect( final LanguageClient client ) { + clientNotifier.connect( client ); + } + + public void shutdown() { + aspectValidationCoordinator.close(); + } + + public AspectValidationResult validateDocument( final String uri ) { + return documentValidationService.validateDocument( uri, documentStore.get( uri ) ); + } + + @Override + public void didOpen( final DidOpenTextDocumentParams params ) { + final String uri = params.getTextDocument().getUri(); + final String content = params.getTextDocument().getText(); + LOG.info( "[didOpen] uri={}, contentLength={}", uri, content.length() ); + documentStore.put( uri, content ); + diagnosticsService.updateSyntax( uri, content ); + clientNotifier.publishCombinedDiagnostics( uri ); + } + + @Override + public void didChange( final DidChangeTextDocumentParams params ) { + final String uri = params.getTextDocument().getUri(); + final String content = + params.getContentChanges().isEmpty() ? documentStore.getOrDefault( uri, "" ) : params.getContentChanges().getLast().getText(); + LOG.debug( "[didChange] uri={}, contentLength={}, changes={}", uri, content.length(), params.getContentChanges().size() ); + documentStore.put( uri, content ); + diagnosticsService.updateSyntax( uri, content ); + aspectDiagnosticsWorkflow.onDocumentChanged( uri ); + clientNotifier.publishCombinedDiagnostics( uri ); + } + + @Override + public void didClose( final DidCloseTextDocumentParams params ) { + final String uri = params.getTextDocument().getUri(); + LOG.info( "[didClose] uri={}", uri ); + documentStore.remove( uri ); + aspectDiagnosticsWorkflow.onDocumentClosed( uri ); + clientNotifier.publishEmptyDiagnostics( uri ); + } + + @Override + public void didSave( final DidSaveTextDocumentParams params ) { + final String uri = params.getTextDocument().getUri(); + final String content = documentStore.getOrDefault( uri, "" ); + LOG.info( "[didSave] uri={}, contentLength={}", uri, content.length() ); + diagnosticsService.updateSyntax( uri, content ); + clientNotifier.publishCombinedDiagnostics( uri ); + aspectDiagnosticsWorkflow.onDocumentSaved( uri ); + } + + @Override + public CompletableFuture, List>> definition( + final DefinitionParams params ) { + final String uri = params.getTextDocument().getUri(); + final String content = documentStore.get( uri ); + if ( content == null ) { + return CompletableFuture.completedFuture( Either.forLeft( List.of() ) ); + } + + final Location declaration = prefixDefinitionService.findPrefixDeclaration( uri, content, params.getPosition() ); + if ( declaration == null ) { + return CompletableFuture.completedFuture( Either.forLeft( List.of() ) ); + } + + return CompletableFuture.completedFuture( Either.forLeft( List.of( declaration ) ) ); + } +} diff --git a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/workspace/TurtleWorkspaceService.java b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/workspace/TurtleWorkspaceService.java new file mode 100644 index 000000000..b33b751d4 --- /dev/null +++ b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/workspace/TurtleWorkspaceService.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2026 Robert Bosch Manufacturing Solutions GmbH + * + * See the AUTHORS file(s) distributed with this work for additional + * information regarding authorship. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * SPDX-License-Identifier: MPL-2.0 + */ + +package org.eclipse.esmf.turtle.languageserver.lsp.workspace; + +import org.eclipse.lsp4j.DidChangeConfigurationParams; +import org.eclipse.lsp4j.DidChangeWatchedFilesParams; +import org.eclipse.lsp4j.services.WorkspaceService; + +import org.eclipse.esmf.turtle.languageserver.lsp.text.TurtleTextDocumentService; + +public class TurtleWorkspaceService implements WorkspaceService { + public TurtleWorkspaceService( final TurtleTextDocumentService textDocumentService ) {} + + @Override + public void didChangeConfiguration( final DidChangeConfigurationParams params ) {} + + @Override + public void didChangeWatchedFiles( final DidChangeWatchedFilesParams params ) {} +} diff --git a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/turtle/navigation/TurtlePrefixDefinitionService.java b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/turtle/navigation/TurtlePrefixDefinitionService.java new file mode 100644 index 000000000..578b1c744 --- /dev/null +++ b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/turtle/navigation/TurtlePrefixDefinitionService.java @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2026 Robert Bosch Manufacturing Solutions GmbH + * + * See the AUTHORS file(s) distributed with this work for additional + * information regarding authorship. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * SPDX-License-Identifier: MPL-2.0 + */ + +package org.eclipse.esmf.turtle.languageserver.turtle.navigation; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.eclipse.lsp4j.Location; +import org.eclipse.lsp4j.Position; +import org.eclipse.lsp4j.Range; + +public class TurtlePrefixDefinitionService { + private static final Pattern PREFIX_DECLARATION_PATTERN = Pattern.compile( + "^\\s*@prefix\\s+([A-Za-z][A-Za-z0-9_-]*)?:\\s*<[^>]*>\\s*\\.", + Pattern.CASE_INSENSITIVE + ); + + public Location findPrefixDeclaration( final String uri, final String content, final Position position ) { + final String prefix = findPrefixAtPosition( content, position ); + if ( prefix == null ) { + return null; + } + + final String[] lines = content.split( "\\R", -1 ); + for ( int line = 0; line < lines.length; line++ ) { + final Matcher matcher = PREFIX_DECLARATION_PATTERN.matcher( lines[line] ); + if ( !matcher.find() ) { + continue; + } + + final String declaredPrefix = matcher.group( 1 ); + final String normalizedPrefix = declaredPrefix == null ? "" : declaredPrefix; + if ( !normalizedPrefix.equals( prefix ) ) { + continue; + } + + return new Location( uri, new Range( new Position( line, 0 ), new Position( line, lines[line].length() ) ) ); + } + + return null; + } + + public String findPrefixAtPosition( final String content, final Position position ) { + int lineStart = 0; + int currentLine = 0; + while ( currentLine < position.getLine() && lineStart < content.length() ) { + if ( content.charAt( lineStart++ ) == '\n' ) { + currentLine++; + } + } + if ( currentLine != position.getLine() ) { + return null; + } + + int lineEnd = lineStart; + while ( lineEnd < content.length() && content.charAt( lineEnd ) != '\n' ) { + lineEnd++; + } + + final int character = Math.max( 0, Math.min( position.getCharacter(), lineEnd - lineStart ) ); + int offset = lineStart + character; + if ( offset > lineStart && ( offset == lineEnd || !isPrefixedNameChar( content.charAt( offset ) ) ) ) { + offset--; + } + if ( offset < lineStart || offset >= lineEnd || !isPrefixedNameChar( content.charAt( offset ) ) ) { + return null; + } + + int start = offset; + while ( start > lineStart && isPrefixedNameChar( content.charAt( start - 1 ) ) ) { + start--; + } + + int end = offset + 1; + while ( end < lineEnd && isPrefixedNameChar( content.charAt( end ) ) ) { + end++; + } + + final String token = content.substring( start, end ); + final int colonIndex = token.indexOf( ':' ); + if ( colonIndex < 0 || colonIndex == token.length() - 1 ) { + return null; + } + + final String prefix = token.substring( 0, colonIndex ); + final String localPart = token.substring( colonIndex + 1 ); + if ( localPart.isEmpty() ) { + return null; + } + + return prefix; + } + + private boolean isPrefixedNameChar( final char ch ) { + return Character.isLetterOrDigit( ch ) || ch == ':' || ch == '_' || ch == '-'; + } +} diff --git a/core/esmf-turtle-language-server/src/main/resources/logback.xml b/core/esmf-turtle-language-server/src/main/resources/logback.xml new file mode 100644 index 000000000..1d4deae08 --- /dev/null +++ b/core/esmf-turtle-language-server/src/main/resources/logback.xml @@ -0,0 +1,32 @@ + + + + + + System.err + + %cyan(%d{HH:mm:ss.SSS}) %highlight(%-5level) - %msg%n + + + + + + + + + + + + + diff --git a/pom.xml b/pom.xml index 303594a23..e85e56579 100644 --- a/pom.xml +++ b/pom.xml @@ -64,6 +64,7 @@ core/esmf-aspect-model-validator core/esmf-aspect-static-meta-model-java core/esmf-tree-sitter-turtle + core/esmf-turtle-language-server core/esmf-test-aspect-models core/esmf-test-resources tools/esmf-aspect-model-maven-plugin @@ -117,6 +118,10 @@ esmf-aspect-model-github-resolver ${project.version} + + org.eclipse.esmf + esmf-turtle-language-server + org.eclipse.esmf esmf-aspect-model-jackson @@ -157,6 +162,11 @@ esmf-aspect-static-meta-model-java ${project.version} + + org.eclipse.esmf + esmf-tree-sitter-turtle + ${project.version} + org.eclipse.esmf esmf-test-aspect-models From 2f0c6c1dab6d6ffaf25c0d57d8658fa5a7c65eb6 Mon Sep 17 00:00:00 2001 From: Andreas Textor Date: Fri, 24 Apr 2026 13:47:55 +0200 Subject: [PATCH 04/41] Introduce Document abstraction and Treesitter-based parsing --- .../aspectmodel/loader/AspectModelLoader.java | 40 +- .../esmf/treesitterturtle/TreeSitterUtil.java | 45 ++ core/esmf-turtle-language-server/pom.xml | 4 + .../service/AspectModelValidationService.java | 10 +- .../service/AspectValidationCoordinator.java | 26 +- .../DefaultAspectModelValidationService.java | 91 ++-- .../lsp/text/AspectDiagnosticsWorkflow.java | 17 +- .../languageserver/lsp/text/Document.java | 79 +++ .../text/DocumentAspectValidationService.java | 92 +--- .../lsp/text/DocumentDiagnosticsService.java | 4 +- .../lsp/text/DocumentStore.java | 12 +- .../turtle/languageserver/lsp/text/Rope.java | 491 ++++++++++++++++++ .../lsp/text/TurtleParserService.java | 129 +++++ .../text/TurtleSyntaxValidationService.java | 6 +- .../lsp/text/TurtleTextDocumentService.java | 57 +- .../TurtlePrefixDefinitionService.java | 7 +- .../languageserver/lsp/text/RopeTest.java | 317 +++++++++++ .../lsp/text/TurtleParserServiceTest.java | 367 +++++++++++++ 18 files changed, 1573 insertions(+), 221 deletions(-) create mode 100644 core/esmf-tree-sitter-turtle/src/main/java/org/eclipse/esmf/treesitterturtle/TreeSitterUtil.java create mode 100644 core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/Document.java create mode 100644 core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/Rope.java create mode 100644 core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TurtleParserService.java create mode 100644 core/esmf-turtle-language-server/src/test/java/org/eclipse/esmf/turtle/languageserver/lsp/text/RopeTest.java create mode 100644 core/esmf-turtle-language-server/src/test/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TurtleParserServiceTest.java diff --git a/core/esmf-aspect-meta-model-java/src/main/java/org/eclipse/esmf/aspectmodel/loader/AspectModelLoader.java b/core/esmf-aspect-meta-model-java/src/main/java/org/eclipse/esmf/aspectmodel/loader/AspectModelLoader.java index 8f90b07d9..cb1708db1 100644 --- a/core/esmf-aspect-meta-model-java/src/main/java/org/eclipse/esmf/aspectmodel/loader/AspectModelLoader.java +++ b/core/esmf-aspect-meta-model-java/src/main/java/org/eclipse/esmf/aspectmodel/loader/AspectModelLoader.java @@ -38,6 +38,15 @@ import java.util.stream.Collectors; import java.util.stream.Stream; +import org.apache.jena.rdf.model.Model; +import org.apache.jena.rdf.model.ModelFactory; +import org.apache.jena.rdf.model.RDFNode; +import org.apache.jena.rdf.model.Resource; +import org.apache.jena.rdf.model.Statement; +import org.apache.jena.rdf.model.StmtIterator; +import org.apache.jena.vocabulary.RDF; +import org.apache.jena.vocabulary.XSD; + import org.eclipse.esmf.aspectmodel.AspectLoadingException; import org.eclipse.esmf.aspectmodel.AspectModelFile; import org.eclipse.esmf.aspectmodel.RdfUtil; @@ -68,19 +77,13 @@ import org.eclipse.esmf.metamodel.impl.DefaultNamespace; import org.eclipse.esmf.metamodel.vocabulary.SammNs; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.google.common.collect.Streams; + import io.vavr.control.Either; import io.vavr.control.Try; -import org.apache.jena.rdf.model.Model; -import org.apache.jena.rdf.model.ModelFactory; -import org.apache.jena.rdf.model.RDFNode; -import org.apache.jena.rdf.model.Resource; -import org.apache.jena.rdf.model.Statement; -import org.apache.jena.rdf.model.StmtIterator; -import org.apache.jena.vocabulary.RDF; -import org.apache.jena.vocabulary.XSD; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; /** * The core class to load an {@link AspectModel}. The AspectModelLoader is also a @@ -339,6 +342,23 @@ public AspectModel loadUrns( final Collection urns ) { return loadAspectModelFiles( loaderContext.loadedFiles() ); } + /** + * Load an Aspect Model from a String containing the RDF/Turtle represenatation and set the srouce + * location + * for this input + * + * @param turtleRepresentation the document as RDF/Turtle + * @param sourceLocation the source location for the model + * @return the Aspect Model + */ + public AspectModel load( final String turtleRepresentation, final URI sourceLocation ) { + final AspectModelFile rawFile = AspectModelFileLoader.load( turtleRepresentation, sourceLocation ); + final AspectModelFile migratedModel = migrate( rawFile ); + final LoaderContext loaderContext = new LoaderContext(); + resolve( List.of( migratedModel ), loaderContext ); + return loadAspectModelFiles( loaderContext.loadedFiles() ); + } + /** * Load an Aspect Model (.ttl) from an input stream and set the source location for this input. For * loading an Aspect Model Namespace Package (.zip), use diff --git a/core/esmf-tree-sitter-turtle/src/main/java/org/eclipse/esmf/treesitterturtle/TreeSitterUtil.java b/core/esmf-tree-sitter-turtle/src/main/java/org/eclipse/esmf/treesitterturtle/TreeSitterUtil.java new file mode 100644 index 000000000..39ee86d6f --- /dev/null +++ b/core/esmf-tree-sitter-turtle/src/main/java/org/eclipse/esmf/treesitterturtle/TreeSitterUtil.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2026 Robert Bosch Manufacturing Solutions GmbH + * + * See the AUTHORS file(s) distributed with this work for additional + * information regarding authorship. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * SPDX-License-Identifier: MPL-2.0 + */ + +package org.eclipse.esmf.treesitterturtle; + +import org.treesitter.TSNode; +import org.treesitter.TSTree; + +public class TreeSitterUtil { + private TreeSitterUtil() {} + + public static String print( final TSTree tree ) { + return print( tree.getRootNode() ); + } + + public static String print( final TSNode node ) { + final StringBuilder builder = new StringBuilder(); + print( node, builder, 0 ); + return builder.toString(); + } + + private static void print( final TSNode node, final StringBuilder builder, final int indentLevel ) { + builder.append( " ".repeat( indentLevel ) ); + builder.append( "- '" ); + builder.append( node.getType() ); + builder.append( "'" ); + if ( node.hasError() ) { + builder.append( " (ERROR)" ); + } + builder.append( "\n" ); + for ( int i = 0; i < node.getChildCount(); i++ ) { + print( node.getChild( i ), builder, indentLevel + 1 ); + } + } +} diff --git a/core/esmf-turtle-language-server/pom.xml b/core/esmf-turtle-language-server/pom.xml index ebe824a56..2d91f8a30 100644 --- a/core/esmf-turtle-language-server/pom.xml +++ b/core/esmf-turtle-language-server/pom.xml @@ -74,5 +74,9 @@ assertj-core test + + net.jqwik + jqwik + diff --git a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/aspect/service/AspectModelValidationService.java b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/aspect/service/AspectModelValidationService.java index 2454562da..ab425663f 100644 --- a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/aspect/service/AspectModelValidationService.java +++ b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/aspect/service/AspectModelValidationService.java @@ -13,15 +13,9 @@ package org.eclipse.esmf.turtle.languageserver.aspect.service; -import java.io.File; -import java.nio.file.Path; - import org.eclipse.esmf.turtle.languageserver.aspect.model.AspectValidationResult; +import org.eclipse.esmf.turtle.languageserver.lsp.text.Document; public interface AspectModelValidationService { - AspectValidationResult validate( Path path ); - - default AspectValidationResult validate( final File file ) { - return validate( file.toPath() ); - } + AspectValidationResult validate( Document document ); } diff --git a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/aspect/service/AspectValidationCoordinator.java b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/aspect/service/AspectValidationCoordinator.java index 78f243031..5b8712ef6 100644 --- a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/aspect/service/AspectValidationCoordinator.java +++ b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/aspect/service/AspectValidationCoordinator.java @@ -13,7 +13,7 @@ package org.eclipse.esmf.turtle.languageserver.aspect.service; -import java.nio.file.Path; +import java.util.List; import java.util.Map; import java.util.concurrent.CancellationException; import java.util.concurrent.CompletableFuture; @@ -23,12 +23,13 @@ import java.util.concurrent.atomic.AtomicLong; import java.util.function.BiConsumer; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import org.eclipse.esmf.turtle.languageserver.aspect.model.AspectValidationError; import org.eclipse.esmf.turtle.languageserver.aspect.model.AspectValidationErrorType; import org.eclipse.esmf.turtle.languageserver.aspect.model.AspectValidationResult; +import org.eclipse.esmf.turtle.languageserver.lsp.text.Document; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class AspectValidationCoordinator implements AutoCloseable { private static final Logger LOG = LoggerFactory.getLogger( AspectValidationCoordinator.class ); @@ -63,10 +64,11 @@ public void cancel( final String uri ) { } } - public void submit( final String uri, final Path path, final long generation, final BiConsumer callback ) { + public void submit( final Document document, final long generation, final BiConsumer callback ) { + final String uri = document.getUri(); cancel( uri ); final CompletableFuture future = CompletableFuture.supplyAsync( - () -> validationService.validate( path ), + () -> validationService.validate( document ), executorService ); inFlight.put( uri, future ); @@ -78,20 +80,16 @@ public void submit( final String uri, final Path path, final long generation, fi } if ( throwable != null ) { LOG.error( "[publish diagnostics] aspect validation failed for {}", uri, throwable ); - callback.accept( generation, new AspectValidationResult( - false, - throwable.getMessage(), - java.util.List.of(), - new AspectValidationError( AspectValidationErrorType.PROCESSING, throwable.getMessage() ) - ) ); + callback.accept( generation, new AspectValidationResult( false, throwable.getMessage(), List.of(), + new AspectValidationError( AspectValidationErrorType.PROCESSING, throwable.getMessage() ) ) ); return; } callback.accept( generation, result ); } ); } - public AspectValidationResult validateSync( final Path path ) { - return validationService.validate( path ); + public AspectValidationResult validateSync( final Document document ) { + return validationService.validate( document ); } @Override diff --git a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/aspect/service/DefaultAspectModelValidationService.java b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/aspect/service/DefaultAspectModelValidationService.java index f95823bce..5301920a3 100644 --- a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/aspect/service/DefaultAspectModelValidationService.java +++ b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/aspect/service/DefaultAspectModelValidationService.java @@ -13,8 +13,8 @@ package org.eclipse.esmf.turtle.languageserver.aspect.service; -import java.nio.file.Files; -import java.nio.file.Path; +import java.io.InputStream; +import java.net.URI; import java.util.List; import java.util.Optional; @@ -25,20 +25,18 @@ import org.eclipse.esmf.aspectmodel.validation.ProcessingViolation; import org.eclipse.esmf.aspectmodel.validation.services.AspectModelValidator; import org.eclipse.esmf.aspectmodel.validation.services.DetailedViolationFormatter; -import org.eclipse.esmf.metamodel.AspectModel; import org.eclipse.esmf.turtle.languageserver.aspect.model.AspectValidationError; import org.eclipse.esmf.turtle.languageserver.aspect.model.AspectValidationErrorType; import org.eclipse.esmf.turtle.languageserver.aspect.model.AspectValidationResult; import org.eclipse.esmf.turtle.languageserver.aspect.model.AspectViolationInfo; +import org.eclipse.esmf.turtle.languageserver.lsp.text.Document; +import org.jspecify.annotations.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class DefaultAspectModelValidationService implements AspectModelValidationService { - private static final Logger LOAD_LOG = LoggerFactory.getLogger( "org.eclipse.esmf.turtle.languageserver.validation.aspect.load" ); - private static final Logger RESOLVE_LOG = LoggerFactory.getLogger( "org.eclipse.esmf.turtle.languageserver.validation.aspect.resolve" ); - private static final Logger VALIDATE_LOG = - LoggerFactory.getLogger( "org.eclipse.esmf.turtle.languageserver.validation.aspect.validate" ); + private static final Logger LOG = LoggerFactory.getLogger( DefaultAspectModelValidationService.class ); private final AspectModelLoader loader; private final AspectModelValidator validator; @@ -53,43 +51,27 @@ public DefaultAspectModelValidationService() { } @Override - public AspectValidationResult validate( final Path path ) { - if ( path == null ) { - return failedResult( AspectValidationErrorType.LOAD, "Path must not be null" ); - } - - if ( !Files.exists( path ) ) { - return failedResult( AspectValidationErrorType.LOAD, "Aspect model file does not exist: " + path ); - } - - if ( !Files.isRegularFile( path ) || !Files.isReadable( path ) ) { - return failedResult( AspectValidationErrorType.LOAD, "Aspect model file is not readable: " + path ); - } - - try { - LOAD_LOG.debug( "[load] loading aspect model from {}", path ); - final List violations = validator.validateModel( () -> loadAspectModel( path ) ); - VALIDATE_LOG.debug( "[validate] validation finished for {} with {} violation(s)", path, violations.size() ); + public AspectValidationResult validate( final Document document ) { + try ( final InputStream inputStream = document.getInputStream() ) { + LOG.debug( "[load] loading aspect model from {}", document.getUri() ); + final List violations = + validator.validateModel( () -> loader.load( inputStream, URI.create( document.getUri() ) ) ); + LOG.debug( "[validate] validation finished for {} with {} violation(s)", document.getUri(), violations.size() ); final String report = new DetailedViolationFormatter().apply( violations ); final AspectValidationError error = classifyError( violations ); return new AspectValidationResult( violations.isEmpty(), report, violations.stream().map( this::toViolationInfo ).toList(), error ); } catch ( final Exception exception ) { - VALIDATE_LOG.error( "[validate] unexpected runtime failure for {}", path, exception ); + LOG.error( "[validate] unexpected runtime failure for {}", document.getUri(), exception ); return failedResult( AspectValidationErrorType.PROCESSING, exception.getMessage() ); } } - private AspectModel loadAspectModel( final Path path ) { - RESOLVE_LOG.debug( "[resolve imports] resolving imports for {}", path ); - return loader.load( path.toFile() ); - } - private AspectValidationResult failedResult( final AspectValidationErrorType type, final String message ) { return new AspectValidationResult( false, message, List.of(), new AspectValidationError( type, message ) ); } - private AspectValidationError classifyError( final List violations ) { + private @Nullable AspectValidationError classifyError( final List violations ) { final Optional firstFailure = violations.stream() .filter( violation -> violation instanceof InvalidSyntaxViolation || violation instanceof InvalidLexicalValueViolation || violation instanceof ProcessingViolation ) @@ -115,31 +97,28 @@ private AspectValidationError classifyError( final List violations ) } private AspectViolationInfo toViolationInfo( final Violation violation ) { - if ( violation instanceof final InvalidSyntaxViolation syntaxViolation ) { - return new AspectViolationInfo( - syntaxViolation.errorCode(), - syntaxViolation.message(), - syntaxViolation.sourceLocation().orElse( null ), - syntaxViolation.line(), - syntaxViolation.column() + return switch ( violation ) { + case final InvalidSyntaxViolation syntaxViolation -> + new AspectViolationInfo( + syntaxViolation.errorCode(), + syntaxViolation.message(), + syntaxViolation.sourceLocation().orElse( null ), + syntaxViolation.line(), + syntaxViolation.column() ); + case final InvalidLexicalValueViolation lexicalValueViolation -> + new AspectViolationInfo( + lexicalValueViolation.errorCode(), + lexicalValueViolation.message(), + lexicalValueViolation.sourceLocation().orElse( null ), + (long) lexicalValueViolation.line(), + (long) lexicalValueViolation.column() ); + default -> new AspectViolationInfo( + violation.errorCode(), + violation.message(), + violation.sourceLocation().orElse( null ), + null, + null ); - } - if ( violation instanceof final InvalidLexicalValueViolation lexicalValueViolation ) { - return new AspectViolationInfo( - lexicalValueViolation.errorCode(), - lexicalValueViolation.message(), - lexicalValueViolation.sourceLocation().orElse( null ), - (long) lexicalValueViolation.line(), - (long) lexicalValueViolation.column() - ); - } - - return new AspectViolationInfo( - violation.errorCode(), - violation.message(), - violation.sourceLocation().orElse( null ), - null, - null - ); + }; } } diff --git a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/AspectDiagnosticsWorkflow.java b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/AspectDiagnosticsWorkflow.java index aabf7e71e..3dce10d86 100644 --- a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/AspectDiagnosticsWorkflow.java +++ b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/AspectDiagnosticsWorkflow.java @@ -13,27 +13,26 @@ package org.eclipse.esmf.turtle.languageserver.lsp.text; -import java.nio.file.Path; +import org.eclipse.esmf.turtle.languageserver.aspect.service.AspectValidationCoordinator; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.eclipse.esmf.turtle.languageserver.aspect.service.AspectValidationCoordinator; -import org.eclipse.esmf.turtle.languageserver.common.uri.DocumentUriResolver; - public class AspectDiagnosticsWorkflow { private static final Logger LOG = LoggerFactory.getLogger( AspectDiagnosticsWorkflow.class ); private final AspectValidationCoordinator aspectValidationCoordinator; private final DocumentDiagnosticsService diagnosticsService; private final TextDocumentClientNotifier clientNotifier; + private final DocumentStore documentStore; public AspectDiagnosticsWorkflow( final AspectValidationCoordinator aspectValidationCoordinator, final DocumentDiagnosticsService diagnosticsService, - final TextDocumentClientNotifier clientNotifier ) { + final TextDocumentClientNotifier clientNotifier, final DocumentStore documentStore ) { this.aspectValidationCoordinator = aspectValidationCoordinator; this.diagnosticsService = diagnosticsService; this.clientNotifier = clientNotifier; + this.documentStore = documentStore; } public void onDocumentChanged( final String uri ) { @@ -47,16 +46,16 @@ public void onDocumentClosed( final String uri ) { } public void onDocumentSaved( final String uri ) { - final Path path = DocumentUriResolver.toPath( uri ); - if ( path == null ) { - LOG.info( "[scheduleAspectValidation] unsupported non-file uri={}, skipping aspect validation", uri ); + final Document document = documentStore.get( uri ); + if ( document == null ) { + LOG.info( "[scheduleAspectValidation] unsupported uri={}, skipping aspect validation", uri ); diagnosticsService.clearAspect( uri ); clientNotifier.publishCombinedDiagnostics( uri ); return; } final long generation = aspectValidationCoordinator.nextGeneration( uri ); - aspectValidationCoordinator.submit( uri, path, generation, ( completedGeneration, result ) -> { + aspectValidationCoordinator.submit( document, generation, ( completedGeneration, result ) -> { final long currentGeneration = aspectValidationCoordinator.currentGeneration( uri ); if ( completedGeneration != currentGeneration ) { LOG.debug( "[publish diagnostics] ignoring stale aspect diagnostics for uri={}, generation={}, current={}", uri, diff --git a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/Document.java b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/Document.java new file mode 100644 index 000000000..d753da5dd --- /dev/null +++ b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/Document.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2026 Robert Bosch Manufacturing Solutions GmbH + * + * See the AUTHORS file(s) distributed with this work for additional + * information regarding authorship. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * SPDX-License-Identifier: MPL-2.0 + */ + +package org.eclipse.esmf.turtle.languageserver.lsp.text; + +import java.io.InputStream; + +import org.eclipse.lsp4j.Position; +import org.eclipse.lsp4j.Range; + +public class Document { + private final String uri; + private Rope content; + + public Document( final String uri, final String initialContent ) { + this.uri = uri; + content = new Rope( initialContent ); + } + + public String getUri() { + return uri; + } + + public String getContent() { + return content.toString(); + } + + public InputStream getInputStream() { + return content.inputStream(); + } + + public int getIndex( final int targetLine, final int targetColumn ) { + return content.getIndex( targetLine, targetColumn ); + } + + /** + * Reads at most many bytes from the given offset into the buffer array, as the array provides, or + * fewer, if + * not as many are left at the offset. Returns 0 if the end of the source code was reached, + * otherwise the number of bytes read. + * + * @param buffer the buffer to write to + * @param offset offset to read from + * @return the number of bytes read + */ + public int read( final byte[] buffer, final int offset ) { + return content.read( buffer, offset ); + } + + /** + * Reads bytes from a specific position (row, column) in the document into the buffer. + * + * @param buffer the buffer to write to + * @param offset offset in the buffer to write to + * @param row the row/line to read from + * @param column the column in the row to read from + * @return the number of bytes read + */ + public int read( final byte[] buffer, final int offset, final int row, final int column ) { + return content.read( buffer, offset, row, column ); + } + + public void update( final Range range, final String newContent ) { + final Position start = range.getStart(); + final Position end = range.getEnd(); + content = content.update( start.getLine(), start.getCharacter(), + end.getLine(), end.getCharacter(), newContent ); + } +} diff --git a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/DocumentAspectValidationService.java b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/DocumentAspectValidationService.java index e2589d12b..fb06e4a45 100644 --- a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/DocumentAspectValidationService.java +++ b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/DocumentAspectValidationService.java @@ -13,23 +13,15 @@ package org.eclipse.esmf.turtle.languageserver.lsp.text; -import java.io.IOException; -import java.net.URI; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.StandardOpenOption; import java.util.List; -import java.util.Objects; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.eclipse.esmf.turtle.languageserver.aspect.model.AspectValidationError; import org.eclipse.esmf.turtle.languageserver.aspect.model.AspectValidationErrorType; import org.eclipse.esmf.turtle.languageserver.aspect.model.AspectValidationResult; -import org.eclipse.esmf.turtle.languageserver.aspect.model.AspectViolationInfo; import org.eclipse.esmf.turtle.languageserver.aspect.service.AspectValidationCoordinator; -import org.eclipse.esmf.turtle.languageserver.common.uri.DocumentUriResolver; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class DocumentAspectValidationService { private static final Logger LOG = LoggerFactory.getLogger( DocumentAspectValidationService.class ); @@ -39,83 +31,11 @@ public DocumentAspectValidationService( final AspectValidationCoordinator aspect this.aspectValidationCoordinator = aspectValidationCoordinator; } - public AspectValidationResult validateDocument( final String uri, final String content ) { - if ( content == null ) { + public AspectValidationResult validateDocument( final String uri, final Document document ) { + if ( document == null ) { return failedValidation( AspectValidationErrorType.LOAD, "Document is not available in memory: " + uri ); } - - final Path path = DocumentUriResolver.toPath( uri ); - if ( path == null ) { - return failedValidation( AspectValidationErrorType.LOAD, "Aspect validation supports only file URIs: " + uri ); - } - - return validateOpenDocument( uri, path, content ); - } - - private AspectValidationResult validateOpenDocument( final String uri, final Path originalPath, final String content ) { - final Path parent = originalPath.getParent(); - if ( parent == null ) { - return failedValidation( AspectValidationErrorType.LOAD, "Document path has no parent directory: " + originalPath ); - } - - final String originalFileName = originalPath.getFileName() != null ? originalPath.getFileName().toString() : "aspect"; - String tempPrefix = originalFileName.replaceAll( "[^A-Za-z0-9._-]", "_" ) + "-"; - if ( tempPrefix.length() < 3 ) { - tempPrefix = "ttl-"; - } - - Path tempFile = null; - try { - tempFile = Files.createTempFile( parent, tempPrefix, ".ttl" ); - Files.writeString( tempFile, content, StandardOpenOption.TRUNCATE_EXISTING ); - final AspectValidationResult result = aspectValidationCoordinator.validateSync( tempFile ); - return remapValidationResult( result, tempFile, originalPath, uri ); - } catch ( final IOException exception ) { - LOG.error( "[validateDocument] failed to prepare in-memory validation for {}", uri, exception ); - return failedValidation( AspectValidationErrorType.PROCESSING, exception.getMessage() ); - } finally { - if ( tempFile != null ) { - try { - Files.deleteIfExists( tempFile ); - } catch ( final IOException exception ) { - LOG.warn( "[validateDocument] failed to delete temp file {}", tempFile, exception ); - } - } - } - } - - private AspectValidationResult remapValidationResult( final AspectValidationResult result, final Path tempFile, final Path originalPath, - final String originalUri ) { - final URI tempUri = tempFile.toUri(); - final List remappedViolations = result.violations().stream() - .map( violation -> remapViolation( violation, tempUri, originalUri ) ) - .toList(); - final String remappedReport = remapReport( result.report(), tempFile, originalPath, originalUri ); - return new AspectValidationResult( result.valid(), remappedReport, remappedViolations, result.error() ); - } - - private AspectViolationInfo remapViolation( final AspectViolationInfo violation, final URI tempUri, final String originalUri ) { - if ( !Objects.equals( violation.sourceLocation(), tempUri ) ) { - return violation; - } - - return new AspectViolationInfo( - violation.code(), - violation.message(), - URI.create( originalUri ), - violation.line(), - violation.column() - ); - } - - private String remapReport( final String report, final Path tempFile, final Path originalPath, final String originalUri ) { - if ( report == null || report.isBlank() ) { - return report; - } - - return report - .replace( tempFile.toUri().toString(), originalUri ) - .replace( tempFile.toAbsolutePath().toString(), originalPath.toAbsolutePath().toString() ); + return aspectValidationCoordinator.validateSync( document ); } private AspectValidationResult failedValidation( final AspectValidationErrorType type, final String message ) { diff --git a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/DocumentDiagnosticsService.java b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/DocumentDiagnosticsService.java index 0465acf9a..574bf440c 100644 --- a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/DocumentDiagnosticsService.java +++ b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/DocumentDiagnosticsService.java @@ -38,8 +38,8 @@ public DocumentDiagnosticsService() { this.diagnosticsStore = diagnosticsStore; } - public void updateSyntax( final String uri, final String content ) { - diagnosticsStore.putSyntax( uri, syntaxValidationService.validate( content ) ); + public void updateSyntax( final Document document ) { + diagnosticsStore.putSyntax( document.getUri(), syntaxValidationService.validate( document ) ); } public void updateAspect( final String uri, final AspectValidationResult result ) { diff --git a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/DocumentStore.java b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/DocumentStore.java index e5ccb706a..8c32704e8 100644 --- a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/DocumentStore.java +++ b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/DocumentStore.java @@ -17,20 +17,16 @@ import java.util.concurrent.ConcurrentHashMap; public class DocumentStore { - private final Map documents = new ConcurrentHashMap<>(); + private final Map documents = new ConcurrentHashMap<>(); - public void put( final String uri, final String content ) { - documents.put( uri, content ); + public void put( final Document document ) { + documents.put( document.getUri(), document ); } - public String get( final String uri ) { + public Document get( final String uri ) { return documents.get( uri ); } - public String getOrDefault( final String uri, final String fallback ) { - return documents.getOrDefault( uri, fallback ); - } - public void remove( final String uri ) { documents.remove( uri ); } diff --git a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/Rope.java b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/Rope.java new file mode 100644 index 000000000..2771e079f --- /dev/null +++ b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/Rope.java @@ -0,0 +1,491 @@ +/* + * Copyright (c) 2026 Robert Bosch Manufacturing Solutions GmbH + * + * See the AUTHORS file(s) distributed with this work for additional + * information regarding authorship. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * SPDX-License-Identifier: MPL-2.0 + */ + +package org.eclipse.esmf.turtle.languageserver.lsp.text; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.util.ArrayDeque; +import java.util.Arrays; +import java.util.Deque; + +import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.Nullable; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class Rope implements CharSequence { + private static final Logger LOG = LoggerFactory.getLogger( Rope.class ); + public static final Rope EMPTY = new Rope( "" ); + + String value; + Rope left; + Rope right; + int weight; + int linebreaks; + + /** + * Constructs a new rope from a given string value + * + * @param value the value + */ + public Rope( final String value ) { + this.value = value; + weight = value.length(); + linebreaks = linebreaks(); + } + + /** + * Constructs a new rope from left and right children + * + * @param left left children + * @param right right children + */ + private Rope( final Rope left, final Rope right ) { + this.left = left; + this.right = right; + weight = length( left ); + linebreaks = linebreaks(); + } + + public int linebreaks() { + return linebreaks( this ); + } + + private int linebreaks( final Rope rope ) { + if ( rope.left == null ) { + return (int) rope.value.chars().filter( ch -> ch == '\n' ).count(); + } + return linebreaks( rope.left ) + linebreaks( rope.right ); + } + + public int weight() { + return weight; + } + + /** + * Returns the length of the rope in characters + * + * @return the length + */ + @Override + public int length() { + return length( this ); + } + + private int length( final Rope r ) { + int len = 0; + for ( Rope rope = r; rope != null; rope = rope.right ) { + len += rope.weight; + } + return len; + } + + /** + * Concatenates another rope to this one + * + * @param rope the other rope + * @return the new rope representing the concatenated result + */ + public Rope concat( final Rope rope ) { + return rope == null ? this : concat( this, rope ); + } + + private @Nullable Rope concat( final @Nullable Rope rope1, final @Nullable Rope rope2 ) { + if ( rope1 == null && rope2 == null ) { + return EMPTY; + } else if ( rope1 == null ) { + return rope2; + } else if ( rope2 == null ) { + return rope1; + } + return new Rope( rope1, rope2 ); + } + + private char charAt( final Rope node, final int index ) { + if ( node.left == null ) { + return node.value.charAt( index ); + } + return node.weight > index ? charAt( node.left, index ) : charAt( node.right, index - node.weight ); + } + + /** + * Returns the character at given index + * + * @param index the index of the {@code char} value to be returned + * + * @return the character at the index + */ + @Override + public char charAt( final int index ) { + return charAt( this, index ); + } + + /** + * Splits this rope into two parts at the given index + * + * @param index the index + * @return an array with two elements, representing the left and right parts of the index. Both + * elements could be null, + * depending on the current rope value and the index + */ + public Rope[] split( final int index ) { + return split( this, index ); + } + + private Rope[] split( final Rope node, final int index ) { + final Rope node0; + final Rope node1; + if ( node.left == null ) { + if ( index == 0 ) { + node0 = null; + node1 = node; + } else if ( index == node.weight ) { + node0 = node; + node1 = null; + } else { + node0 = new Rope( node.value.substring( 0, index ) ); + node1 = new Rope( node.value.substring( index, node.weight ) ); + } + } else if ( index == node.weight ) { + node0 = node.left; + node1 = node.right; + } else if ( index < node.weight ) { + final Rope[] parts = split( node.left, index ); + node0 = parts[0]; + node1 = concat( parts[1], node.right ); + } else { + final Rope[] parts = split( node.right, index - node.weight ); + node0 = concat( node.left, parts[0] ); + node1 = parts[1]; + } + return new Rope[] { node0, node1 }; + } + + /** + * Returns the subsequence of characters between to indices + * + * @param start the start index, inclusive + * @param end the end index, exclusive + * @return the subsequence of characters + */ + @Override + public @NonNull Rope subSequence( final int start, final int end ) { + return split( start )[1].split( end - start )[0]; + } + + /** + * Inserts another rope at the given index. The index must be inside the rope. + * + * @param rope the other rope + * @param index the index. This must be less or equal than this rope's length + * @return the resulting new rope + */ + public Rope insert( final Rope rope, final int index ) { + final Rope[] parts = split( index ); + return concat( concat( parts[0], rope ), parts[1] ); + } + + /** + * Deletes a section at the given index. The index and index+length must be inside the rope. + * + * @param index the index + * @param length the length to delete + * @return the resulting new rope + */ + public Rope delete( final int index, final int length ) { + final Rope[] parts = split( index ); + final Rope result; + if ( parts[1] == null ) { + result = concat( parts[0], null ); + } else { + result = concat( parts[0], parts[1].split( length )[1] ); + } + return result == null ? EMPTY : result; + } + + /** + * Returns the index of the nth linebreak in a string, or -1 if no nth linebreak exists + * + * @param string the text to search in + * @param n the number of the linebreak + * @return the index or -1 + */ + private static int indexOfNthLinebreak( final String string, final int n ) { + int counter = n; + int pos = string.indexOf( '\n' ); + while ( --counter > 0 && pos != -1 ) { + pos = string.indexOf( '\n', pos + 1 ); + } + return pos; + } + + public Rope update( final int startLine, final int startColumn, final int endLine, final int endColumn, final String newContent ) { + final int startIndex = getIndex( startLine, startColumn ); + final int endIndex = getIndex( endLine, endColumn ); + // final int offset = endIndex == length() ? 0 : 1; + final int offset = 1; + final Rope resultAfterDeletion = startIndex == endIndex + ? this + : delete( startIndex, endIndex - startIndex + offset ); + return newContent.isEmpty() ? resultAfterDeletion : resultAfterDeletion.insert( new Rope( newContent ), startIndex ); + } + + public int getIndex( final int targetLine, final int targetColumn ) { + if ( targetLine == 0 ) { + return targetColumn; + } + if ( targetLine < 0 || targetColumn < 0 ) { + return -1; + } + + int currentIndex = 0; + int currentLine = 0; + final int length = length(); + + // Traverse the rope character by character until we reach the target line + while ( currentIndex < length && currentLine < targetLine ) { + if ( charAt( currentIndex ) == '\n' ) { + currentLine++; + } + currentIndex++; + } + + // Add the column offset + return currentIndex + targetColumn; + } + + /** + * Prints the rope as a tree structure + * + * @return the tree structure as a visual string + */ + public String print() { + return print( this, 0 ); + } + + private String print( final Rope rope, final int indentation ) { + if ( rope == null ) { + return "[]"; + } + final String indentString = new String( new char[indentation] ).replace( "\0", " " ); + return "[%s]\n%s-L:%s\n%s-R:%s".formatted( rope.value, + indentString, print( rope.left, indentation + 2 ), + indentString, print( rope.right, indentation + 2 ) ); + } + + public Rope rebalance() { + final Rope[] leaves = leaves(); + return merge( leaves, 0, leaves.length ); + } + + private Rope[] leaves() { + if ( left == null && right == null ) { + return new Rope[] { this }; + } + final Rope[] leftLeaves = left == null ? new Rope[0] : left.leaves(); + final Rope[] rightLeaves = right == null ? new Rope[0] : right.leaves(); + final Rope[] result = Arrays.copyOf( leftLeaves, leftLeaves.length + rightLeaves.length ); + System.arraycopy( rightLeaves, 0, result, leftLeaves.length, rightLeaves.length ); + return result; + } + + private Rope merge( final Rope[] leaves, final int start, final int end ) { + final int range = end - start; + if ( range == 1 ) { + return leaves[start]; + } + if ( range == 2 ) { + return new Rope( leaves[start], leaves[start + 1] ); + } + final int mid = start + ( range / 2 ); + return new Rope( merge( leaves, start, mid ), merge( leaves, mid, end ) ); + } + + @Override + public @NonNull String toString() { + try ( final InputStream inputStream = inputStream( StandardCharsets.UTF_8 ) ) { + return new String( inputStream.readAllBytes(), StandardCharsets.UTF_8 ); + } catch ( final IOException exception ) { + throw new RuntimeException( exception ); + } + } + + /** + * Equality of two ropes is given when the strings they encode are equal, regardless how their + * internal tree structure looks like + * + * @param object the other object + * @return true when the other object is a rope with the same encoded string + */ + @Override + public boolean equals( final Object object ) { + if ( this == object ) { + return true; + } + if ( object == null || getClass() != object.getClass() ) { + return false; + } + final Rope rope = (Rope) object; + return rope.toString().equals( toString() ); + } + + @Override + public int hashCode() { + return toString().hashCode(); + } + + public InputStream inputStream( final Charset encoding ) { + return new RopeInputStream( encoding ); + } + + public InputStream inputStream() { + return inputStream( StandardCharsets.UTF_8 ); + } + + /** + * Reads at most many bytes from the given offset into the buffer array, as the array provides, or + * fewer, if + * not as many are left at the offset. Returns 0 if the end of the source code was reached, + * otherwise the number of bytes read. + * + * @param buffer the buffer to write to + * @param offset offset to read from + * @return the number of bytes read + */ + public int read( final byte[] buffer, final int offset ) { + if ( buffer == null || offset < 0 || offset >= buffer.length ) { + return 0; + } + + try ( final InputStream stream = inputStream( StandardCharsets.UTF_8 ) ) { + final int bytesRead = stream.read( buffer, offset, buffer.length ); + return bytesRead == -1 ? 0 : bytesRead; + } catch ( final Exception exception ) { + LOG.debug( "Exception while reading document content", exception ); + return 0; + } + } + + /** + * Reads bytes from a specific position (row, column) in the rope into the buffer. + * + * @param buffer the buffer to read into + * @param offset offset in the buffer to write to + * @param row row/line to read from + * @param column column or nth byte in the line to read from + * @return the number of bytes read + */ + public int read( final byte[] buffer, final int offset, final int row, final int column ) { + if ( buffer == null || offset < 0 || offset >= buffer.length ) { + return 0; + } + + try ( final InputStream stream = inputStream( StandardCharsets.UTF_8 ) ) { + final byte[] allBytes = stream.readAllBytes(); + + // Find the byte position of the start of the row + int bytePosition = 0; + int currentLine = 0; + + for ( int i = 0; i < allBytes.length && currentLine < row; i++ ) { + if ( allBytes[i] == '\n' ) { + currentLine++; + bytePosition = i + 1; // Start of next line + } + } + + // Add the column offset + bytePosition += column; + + if ( bytePosition >= allBytes.length ) { + return 0; // Beyond end of content + } + + // Calculate how many bytes to read + final int availableInBuffer = buffer.length - offset; + final int availableInSource = allBytes.length - bytePosition; + final int bytesToRead = Math.min( availableInBuffer, availableInSource ); + + if ( bytesToRead <= 0 ) { + return 0; + } + + // Copy bytes into the buffer + System.arraycopy( allBytes, bytePosition, buffer, offset, bytesToRead ); + + return bytesToRead; + + } catch ( final Exception exception ) { + LOG.debug( "Exception while reading document content at position ({}, {})", row, column, exception ); + return 0; + } + } + + public class RopeInputStream extends InputStream { + private final Deque stack; + private byte @Nullable [] currentBytes; + private int currentPosition; + private final Charset encoding; + + public RopeInputStream( final Charset encoding ) { + this.encoding = encoding; + stack = new ArrayDeque<>(); + currentBytes = null; + currentPosition = 0; + pushLeftmostPath( Rope.this ); + } + + private void pushLeftmostPath( final Rope node ) { + Rope current = node; + while ( current != null ) { + if ( current.left == null ) { + currentBytes = current.value.getBytes( encoding ); + currentPosition = 0; + break; + } else { + stack.push( current ); + current = current.left; + } + } + } + + private boolean moveToNextLeaf() { + while ( !stack.isEmpty() ) { + final Rope parent = stack.pop(); + if ( parent.right != null ) { + pushLeftmostPath( parent.right ); + return true; + } + } + currentBytes = null; + return false; + } + + @Override + public int read() { + while ( currentBytes == null || currentPosition >= currentBytes.length ) { + if ( !moveToNextLeaf() ) { + return -1; + } + } + + // Return byte as unsigned int (0-255) + final int result = currentBytes[currentPosition] & 0xFF; + currentPosition++; + return result; + } + } +} diff --git a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TurtleParserService.java b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TurtleParserService.java new file mode 100644 index 000000000..ff01a7d7c --- /dev/null +++ b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TurtleParserService.java @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2026 Robert Bosch Manufacturing Solutions GmbH + * + * See the AUTHORS file(s) distributed with this work for additional + * information regarding authorship. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * SPDX-License-Identifier: MPL-2.0 + */ + +package org.eclipse.esmf.turtle.languageserver.lsp.text; + +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.esmf.treesitterturtle.TreeSitterTurtle; + +import org.eclipse.lsp4j.Position; +import org.eclipse.lsp4j.Range; +import org.eclipse.lsp4j.TextDocumentContentChangeEvent; +import org.treesitter.TSInputEdit; +import org.treesitter.TSLanguage; +import org.treesitter.TSParser; +import org.treesitter.TSPoint; +import org.treesitter.TSTree; + +/** + * Service for parsing Turtle documents using Tree-sitter and maintaining their syntax trees. + * Supports incremental parsing for efficient updates when documents change. + */ +public class TurtleParserService { + private final TSParser parser; + private final Map syntaxTrees = new HashMap<>(); + + public TurtleParserService() { + parser = new TSParser(); + final TSLanguage turtle = new TreeSitterTurtle(); + parser.setLanguage( turtle ); + } + + public TSTree getAbstractSyntaxTree( final Document document ) { + return syntaxTrees.computeIfAbsent( document, this::parseDocument ); + } + + private TSTree parseDocument( final Document document ) { + return parser.parseString( null, document.getContent() ); + } + + /** + * Converts an LSP text change event into a Tree-sitter input edit. + * + * @param document the document (used to calculate byte offsets) + * @param changeEvent the LSP change event + * @return a TSInputEdit, or null if this is a full document change + */ + private TSInputEdit treeChangeFromLspChange( final Document document, final TextDocumentContentChangeEvent changeEvent ) { + final Range range = changeEvent.getRange(); + if ( range == null ) { + // Full document change - return null to indicate full reparse needed + return null; + } + + final Position startPos = range.getStart(); + final Position endPos = range.getEnd(); + final String newText = changeEvent.getText() != null ? changeEvent.getText() : ""; + + final TSPoint startPoint = new TSPoint( startPos.getLine(), startPos.getCharacter() ); + final TSPoint oldEndPoint = new TSPoint( endPos.getLine(), endPos.getCharacter() ); + final int startByte = document.getIndex( startPos.getLine(), startPos.getCharacter() ); + final int oldEndByte = document.getIndex( endPos.getLine(), endPos.getCharacter() ); + final TSPoint newEndPoint = calculateNewEndPoint( startPoint, newText ); + final int newEndByte = startByte + newText.getBytes( StandardCharsets.UTF_8 ).length; + return new TSInputEdit( startByte, oldEndByte, newEndByte, startPoint, oldEndPoint, newEndPoint ); + } + + /** + * Calculates the new end point after inserting text at the start point. + * + * @param startPoint the starting position + * @param newText the text being inserted + * @return the new end position after insertion + */ + private TSPoint calculateNewEndPoint( final TSPoint startPoint, final String newText ) { + if ( newText.isEmpty() ) { + return startPoint; + } + + // Count newlines in the inserted text + final long newlineCount = newText.chars().filter( ch -> ch == '\n' ).count(); + + if ( newlineCount == 0 ) { + // Single line insertion - same row, column advances by text length + final int newColumn = startPoint.getColumn() + newText.length(); + return new TSPoint( startPoint.getRow(), newColumn ); + } else { + // Multi-line insertion + final int lastNewlineIndex = newText.lastIndexOf( '\n' ); + final int newRow = startPoint.getRow() + (int) newlineCount; + final int newColumn = newText.length() - lastNewlineIndex - 1; + return new TSPoint( newRow, newColumn ); + } + } + + public void onChange( final Document document, final TextDocumentContentChangeEvent changeEvent ) { + final TSTree oldTree = syntaxTrees.get( document ); + + if ( oldTree == null ) { + syntaxTrees.put( document, parseDocument( document ) ); + return; + } + + final TSInputEdit edit = treeChangeFromLspChange( document, changeEvent ); + if ( edit == null ) { + // Full document change - reparse from scratch + syntaxTrees.put( document, parseDocument( document ) ); + return; + } + + oldTree.edit( edit ); + final TSTree newTree = parser.parseString( oldTree, document.getContent() ); + syntaxTrees.put( document, newTree ); + } +} + + diff --git a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TurtleSyntaxValidationService.java b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TurtleSyntaxValidationService.java index 093cf88fd..2b7bfd635 100644 --- a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TurtleSyntaxValidationService.java +++ b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TurtleSyntaxValidationService.java @@ -13,6 +13,8 @@ package org.eclipse.esmf.turtle.languageserver.lsp.text; +import java.io.IOException; +import java.io.StringReader; import java.util.ArrayList; import java.util.List; @@ -33,12 +35,12 @@ public class TurtleSyntaxValidationService { private static final Logger LOG = LoggerFactory.getLogger( TurtleSyntaxValidationService.class ); private static final String SYNTAX_SOURCE = "lsp-server.syntax"; - public List validate( final String content ) { + public List validate( final Document document ) { final List diagnostics = new ArrayList<>(); try { RDFParser.create() - .fromString( content ) + .source( new StringReader( document.getContent() ) ) .lang( Lang.TTL ) .errorHandler( ErrorHandlerFactory.errorHandlerStrictNoLogging ) .parse( StreamRDFLib.sinkNull() ); diff --git a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TurtleTextDocumentService.java b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TurtleTextDocumentService.java index 6f0c2051c..38e76f54a 100644 --- a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TurtleTextDocumentService.java +++ b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TurtleTextDocumentService.java @@ -16,24 +16,26 @@ import java.util.List; import java.util.concurrent.CompletableFuture; +import org.eclipse.esmf.turtle.languageserver.aspect.model.AspectValidationResult; +import org.eclipse.esmf.turtle.languageserver.aspect.service.AspectModelValidationService; +import org.eclipse.esmf.turtle.languageserver.aspect.service.AspectValidationCoordinator; +import org.eclipse.esmf.turtle.languageserver.aspect.service.DefaultAspectModelValidationService; +import org.eclipse.esmf.turtle.languageserver.turtle.navigation.TurtlePrefixDefinitionService; + import org.eclipse.lsp4j.DefinitionParams; import org.eclipse.lsp4j.DidChangeTextDocumentParams; import org.eclipse.lsp4j.DidCloseTextDocumentParams; import org.eclipse.lsp4j.DidOpenTextDocumentParams; import org.eclipse.lsp4j.DidSaveTextDocumentParams; import org.eclipse.lsp4j.Location; +import org.eclipse.lsp4j.LocationLink; +import org.eclipse.lsp4j.TextDocumentContentChangeEvent; import org.eclipse.lsp4j.jsonrpc.messages.Either; import org.eclipse.lsp4j.services.LanguageClient; import org.eclipse.lsp4j.services.TextDocumentService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.eclipse.esmf.turtle.languageserver.aspect.model.AspectValidationResult; -import org.eclipse.esmf.turtle.languageserver.aspect.service.AspectModelValidationService; -import org.eclipse.esmf.turtle.languageserver.aspect.service.AspectValidationCoordinator; -import org.eclipse.esmf.turtle.languageserver.aspect.service.DefaultAspectModelValidationService; -import org.eclipse.esmf.turtle.languageserver.turtle.navigation.TurtlePrefixDefinitionService; - public class TurtleTextDocumentService implements TextDocumentService { private static final Logger LOG = LoggerFactory.getLogger( TurtleTextDocumentService.class ); private final DocumentStore documentStore; @@ -43,6 +45,7 @@ public class TurtleTextDocumentService implements TextDocumentService { private final DocumentAspectValidationService documentValidationService; private final AspectDiagnosticsWorkflow aspectDiagnosticsWorkflow; private final AspectValidationCoordinator aspectValidationCoordinator; + private final TurtleParserService turtleParserService; public TurtleTextDocumentService() { this( new DefaultAspectModelValidationService() ); @@ -53,7 +56,8 @@ public TurtleTextDocumentService( final AspectModelValidationService aspectValid new DocumentStore(), new DocumentDiagnosticsService(), new TurtlePrefixDefinitionService(), - new AspectValidationCoordinator( aspectValidationService ) + new AspectValidationCoordinator( aspectValidationService ), + new TurtleParserService() ); } @@ -61,14 +65,17 @@ public TurtleTextDocumentService( final AspectModelValidationService aspectValid final DocumentStore documentStore, final DocumentDiagnosticsService diagnosticsService, final TurtlePrefixDefinitionService prefixDefinitionService, - final AspectValidationCoordinator aspectValidationCoordinator ) { + final AspectValidationCoordinator aspectValidationCoordinator, + final TurtleParserService turtleParserService ) { this.documentStore = documentStore; this.diagnosticsService = diagnosticsService; this.prefixDefinitionService = prefixDefinitionService; this.aspectValidationCoordinator = aspectValidationCoordinator; clientNotifier = new TextDocumentClientNotifier( diagnosticsService ); documentValidationService = new DocumentAspectValidationService( aspectValidationCoordinator ); - aspectDiagnosticsWorkflow = new AspectDiagnosticsWorkflow( aspectValidationCoordinator, diagnosticsService, clientNotifier ); + aspectDiagnosticsWorkflow = + new AspectDiagnosticsWorkflow( aspectValidationCoordinator, diagnosticsService, clientNotifier, documentStore ); + this.turtleParserService = turtleParserService; } public void connect( final LanguageClient client ) { @@ -88,19 +95,22 @@ public void didOpen( final DidOpenTextDocumentParams params ) { final String uri = params.getTextDocument().getUri(); final String content = params.getTextDocument().getText(); LOG.info( "[didOpen] uri={}, contentLength={}", uri, content.length() ); - documentStore.put( uri, content ); - diagnosticsService.updateSyntax( uri, content ); + final Document document = new Document( uri, content ); + documentStore.put( document ); + diagnosticsService.updateSyntax( document ); clientNotifier.publishCombinedDiagnostics( uri ); } @Override public void didChange( final DidChangeTextDocumentParams params ) { final String uri = params.getTextDocument().getUri(); - final String content = - params.getContentChanges().isEmpty() ? documentStore.getOrDefault( uri, "" ) : params.getContentChanges().getLast().getText(); - LOG.debug( "[didChange] uri={}, contentLength={}, changes={}", uri, content.length(), params.getContentChanges().size() ); - documentStore.put( uri, content ); - diagnosticsService.updateSyntax( uri, content ); + final Document document = documentStore.get( params.getTextDocument().getUri() ); + for ( final TextDocumentContentChangeEvent change : params.getContentChanges() ) { + document.update( change.getRange(), change.getText() ); + turtleParserService.onChange( document, change ); + } + LOG.debug( "[didChange] uri={}, changes={}", uri, params.getContentChanges().size() ); + diagnosticsService.updateSyntax( document ); aspectDiagnosticsWorkflow.onDocumentChanged( uri ); clientNotifier.publishCombinedDiagnostics( uri ); } @@ -117,23 +127,22 @@ public void didClose( final DidCloseTextDocumentParams params ) { @Override public void didSave( final DidSaveTextDocumentParams params ) { final String uri = params.getTextDocument().getUri(); - final String content = documentStore.getOrDefault( uri, "" ); - LOG.info( "[didSave] uri={}, contentLength={}", uri, content.length() ); - diagnosticsService.updateSyntax( uri, content ); + final Document document = documentStore.get( uri ); + LOG.info( "[didSave] uri={}", uri ); + diagnosticsService.updateSyntax( document ); clientNotifier.publishCombinedDiagnostics( uri ); aspectDiagnosticsWorkflow.onDocumentSaved( uri ); } @Override - public CompletableFuture, List>> definition( - final DefinitionParams params ) { + public CompletableFuture, List>> definition( final DefinitionParams params ) { final String uri = params.getTextDocument().getUri(); - final String content = documentStore.get( uri ); - if ( content == null ) { + final Document document = documentStore.get( uri ); + if ( document == null ) { return CompletableFuture.completedFuture( Either.forLeft( List.of() ) ); } - final Location declaration = prefixDefinitionService.findPrefixDeclaration( uri, content, params.getPosition() ); + final Location declaration = prefixDefinitionService.findPrefixDeclaration( document, params.getPosition() ); if ( declaration == null ) { return CompletableFuture.completedFuture( Either.forLeft( List.of() ) ); } diff --git a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/turtle/navigation/TurtlePrefixDefinitionService.java b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/turtle/navigation/TurtlePrefixDefinitionService.java index 578b1c744..d2be336e2 100644 --- a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/turtle/navigation/TurtlePrefixDefinitionService.java +++ b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/turtle/navigation/TurtlePrefixDefinitionService.java @@ -16,6 +16,8 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; +import org.eclipse.esmf.turtle.languageserver.lsp.text.Document; + import org.eclipse.lsp4j.Location; import org.eclipse.lsp4j.Position; import org.eclipse.lsp4j.Range; @@ -26,7 +28,8 @@ public class TurtlePrefixDefinitionService { Pattern.CASE_INSENSITIVE ); - public Location findPrefixDeclaration( final String uri, final String content, final Position position ) { + public Location findPrefixDeclaration( final Document document, final Position position ) { + final String content = document.getContent(); final String prefix = findPrefixAtPosition( content, position ); if ( prefix == null ) { return null; @@ -45,7 +48,7 @@ public Location findPrefixDeclaration( final String uri, final String content, f continue; } - return new Location( uri, new Range( new Position( line, 0 ), new Position( line, lines[line].length() ) ) ); + return new Location( document.getUri(), new Range( new Position( line, 0 ), new Position( line, lines[line].length() ) ) ); } return null; diff --git a/core/esmf-turtle-language-server/src/test/java/org/eclipse/esmf/turtle/languageserver/lsp/text/RopeTest.java b/core/esmf-turtle-language-server/src/test/java/org/eclipse/esmf/turtle/languageserver/lsp/text/RopeTest.java new file mode 100644 index 000000000..7fa82c66d --- /dev/null +++ b/core/esmf-turtle-language-server/src/test/java/org/eclipse/esmf/turtle/languageserver/lsp/text/RopeTest.java @@ -0,0 +1,317 @@ +/* + * Copyright (c) 2026 Robert Bosch Manufacturing Solutions GmbH + * + * See the AUTHORS file(s) distributed with this work for additional + * information regarding authorship. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * SPDX-License-Identifier: MPL-2.0 + */ + +package org.eclipse.esmf.turtle.languageserver.lsp.text; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.util.List; +import java.util.Random; +import java.util.concurrent.ThreadLocalRandom; + +import org.junit.jupiter.api.Test; + +import net.jqwik.api.Arbitraries; +import net.jqwik.api.Arbitrary; +import net.jqwik.api.ForAll; +import net.jqwik.api.Property; +import net.jqwik.api.Provide; + +class RopeTest { + /** + * Controls which input strings should be used for tests. Ropes should work for any string, so we + * let Jqwik choose any kind of string. + * + * @return an arbitrary string + */ + @Provide + Arbitrary inputString() { + return Arbitraries.strings(); + } + + @Provide + Arbitrary basicString() { + return Arbitraries.strings().alpha().numeric().excludeChars( '\n' ); + } + + @Property + void ropesCanBeConcatenated( @ForAll( "inputString" ) final String string1, @ForAll( "inputString" ) final String string2 ) { + final Rope rope1 = new Rope( string1 ); + final Rope rope2 = new Rope( string2 ); + final Rope result = rope1.concat( rope2 ); + final Rope concatted = new Rope( string1 + string2 ); + assertThat( result ).isEqualTo( concatted ); + assertThat( result.toString() ).isEqualTo( string1 + string2 ); + assertThat( concatted.toString() ).isEqualTo( string1 + string2 ); + } + + @Property + void ropesCanBeSplit( @ForAll( "inputString" ) final String string ) { + final Rope rope = new Rope( string ); + for ( int i = 0; i <= rope.length(); i++ ) { + final Rope[] parts = rope.split( i ); + if ( parts[0] == null || parts[1] == null ) { + continue; + } + assertThat( parts[0].length() + parts[1].length() ).isEqualTo( rope.length() ); + assertThat( parts[0].value + parts[1].value ).isEqualTo( rope.toString() ); + } + } + + @Property + void ropesCanReturnSubsequences( @ForAll( "inputString" ) final String string ) { + final Rope rope = new Rope( string ); + for ( int i = 0; i <= rope.length(); i++ ) { + for ( int j = i; j <= rope.length(); j++ ) { + if ( i != j ) { + assertThat( rope.subSequence( i, j ).toString() ).isEqualTo( string.substring( i, j ) ); + } + } + } + } + + @Property + void ropesCanInsertStrings( @ForAll( "inputString" ) final String string1, @ForAll( "inputString" ) final String string2 ) { + final Rope rope1 = new Rope( string1 ); + final Rope rope2 = new Rope( string2 ); + for ( int i = 0; i <= rope1.length(); i++ ) { + final Rope ropeResult = rope1.insert( rope2, i ); + final String stringResult = string1.substring( 0, i ) + string2 + string1.substring( i ); + assertThat( ropeResult.toString() ).isEqualTo( stringResult ); + } + } + + @Property + void ropesCanBeRebalanced( @ForAll( "inputString" ) final String string1, @ForAll( "inputString" ) final String string2 ) { + final Rope rope1 = new Rope( string1 ); + final Rope rope2 = new Rope( string2 ); + + // Insert lots of stuff. This will degenerate the tree + Rope ropeResult = rope1; + for ( int j = 0; j <= 10; j++ ) { + if ( j > ropeResult.length() ) { + break; + } + ropeResult = ropeResult.insert( rope2, j ); + } + final Rope balanced = ropeResult.rebalance(); + assertThat( ropeResult ).isEqualTo( balanced ); + assertThat( ropeResult.toString() ).isEqualTo( balanced.toString() ); + } + + @Property + void ropesCanDeleteStrings( @ForAll( "inputString" ) final String string ) { + final Random random = ThreadLocalRandom.current(); + if ( string != null && string.isEmpty() ) { + return; + } + assertThat( string ).isNotNull(); + final int index = random.nextInt( 0, string.length() ); + final int length = random.nextInt( 0, string.length() - index ); + final Rope rope = new Rope( string ); + + final String stringResult = string.substring( 0, index ) + string.substring( index + length ); + final Rope result = rope.delete( index, length ); + assertThat( result.toString() ).isEqualTo( stringResult ); + } + + @Property + void testInputStreamAndToStringConsistency( @ForAll( "inputString" ) final String string ) throws IOException { + final Rope rope = new Rope( string ); + for ( final Charset encoding : List.of( StandardCharsets.UTF_8, StandardCharsets.UTF_16 ) ) { + final byte[] bytesFromToString = rope.toString().getBytes( encoding ); + try ( final InputStream inputStream = rope.inputStream( encoding ) ) { + final byte[] bytesFromInputStream = inputStream.readAllBytes(); + assertThat( bytesFromToString ) + .as( () -> "Compared string: " + string ) + .hasSameSizeAs( bytesFromInputStream ) + .isEqualTo( bytesFromInputStream ); + } + } + } + + @Test + void testSubSequence() { + final Rope rope = new Rope( "abc\ndef\n" ); + assertThat( rope.subSequence( 0, 3 ).toString() ).isEqualTo( "abc" ); + assertThat( rope.subSequence( 4, 7 ).toString() ).isEqualTo( "def" ); + } + + @Test + void testGetIndex() { + final Rope rope = new Rope( "abc\ndef\nghi\n" ); + assertThat( rope.getIndex( 0, 0 ) ).isEqualTo( 0 ); + assertThat( rope.getIndex( 0, 2 ) ).isEqualTo( 2 ); + assertThat( rope.getIndex( 1, 0 ) ).isEqualTo( 4 ); + assertThat( rope.getIndex( 1, 3 ) ).isEqualTo( 7 ); + assertThat( rope.getIndex( 2, 0 ) ).isEqualTo( 8 ); + assertThat( rope.getIndex( 2, 2 ) ).isEqualTo( 10 ); + + final Rope rope2 = new Rope( "\n\n" ); + assertThat( rope2.getIndex( 0, 0 ) ).isEqualTo( 0 ); + assertThat( rope2.getIndex( 1, 0 ) ).isEqualTo( 1 ); + assertThat( rope2.getIndex( 2, 0 ) ).isEqualTo( 2 ); + } + + @Property + void randomOperationsMatchStringBehavior( @ForAll( "inputString" ) final String initialString ) { + if ( initialString.isEmpty() ) { + return; + } + + final Random random = ThreadLocalRandom.current(); + final int operationCount = random.nextInt( 5, 15 ); + + Rope rope = new Rope( initialString ); + String string = initialString; + + enum Operation { + DELETE, INSERT, UPDATE + } + + for ( int i = 0; i < operationCount; i++ ) { + final Operation operation = Operation.values()[random.nextInt( 3 )]; + + try { + if ( string.isEmpty() ) { + // Can only insert if string is empty + final String toInsert = "test" + i; + rope = rope.insert( new Rope( toInsert ), 0 ); + assertThat( rope ).isNotNull(); + string = toInsert + string; + } else if ( operation == Operation.DELETE ) { + final int start = random.nextInt( string.length() ); + final int maxLength = string.length() - start; + final int length = maxLength > 0 ? random.nextInt( 1, maxLength + 1 ) : 0; + + if ( length > 0 ) { + rope = rope.delete( start, length ); + string = string.substring( 0, start ) + string.substring( start + length ); + } + } else if ( operation == Operation.INSERT ) { + final int index = random.nextInt( string.length() + 1 ); + final String toInsert = "ins" + i; + + rope = rope.insert( new Rope( toInsert ), index ); + string = string.substring( 0, index ) + toInsert + string.substring( index ); + } else { + // Update (replace) operation - delete then insert + final int start = random.nextInt( string.length() ); + final int maxLength = string.length() - start; + final int length = maxLength > 0 ? random.nextInt( 1, maxLength + 1 ) : 0; + final String replacement = "upd" + i; + + if ( length > 0 ) { + rope = rope.delete( start, length ).insert( new Rope( replacement ), start ); + string = string.substring( 0, start ) + replacement + string.substring( start + length ); + } + } + + assertThat( rope.toString() ) + .as( "After operation %d (type=%d)", i, operation ) + .isEqualTo( string ); + + } catch ( final Exception exception ) { + final String ropeLength = rope == null ? "?" : "" + rope.length(); + throw new AssertionError( "Failed at operation " + i + " with rope length " + ropeLength + + " and string length " + string.length() + ": " + exception.getMessage(), exception ); + } + } + + assertThat( rope.toString() ).isEqualTo( string ); + } + + @Test + void testUpdate() { + final Rope rope = new Rope( "\n" ); + final Rope result = rope.update( 0, 1, 0, 1, "X" ); + assertThat( result.toString() ).isEqualTo( "\nX" ); + + final Rope rope2 = new Rope( "abcd\nefgh" ); + final Rope result2 = rope2.update( 1, 1, 1, 3, "X" ); + assertThat( result2.toString() ).isEqualTo( "abcd\neX" ); + + final Rope rope3 = new Rope( "\nabcd" ); + final Rope result3 = rope3.update( 0, 0, 1, 3, "X" ); + assertThat( result3.toString() ).isEqualTo( "X" ); + + final Rope rope4 = new Rope( "\na" ); + final Rope result4 = rope4.update( 0, 0, 1, 0, "X" ); + assertThat( result4.toString() ).isEqualTo( "X" ); + } + + @Test + void testMixedOperationsWithKnownInput() { + // Test with a known input to ensure predictable behavior + String string = "line1\nline2\nline3\n"; + Rope rope = new Rope( string ); + + // Operation 1: Delete "line2\n" + rope = rope.delete( 6, 6 ); + string = string.substring( 0, 6 ) + string.substring( 12 ); + assertThat( rope.toString() ).isEqualTo( string ).isEqualTo( "line1\nline3\n" ); + + // Operation 2: Insert "inserted\n" at position 6 + rope = rope.insert( new Rope( "inserted\n" ), 6 ); + string = string.substring( 0, 6 ) + "inserted\n" + string.substring( 6 ); + assertThat( rope.toString() ).isEqualTo( string ).isEqualTo( "line1\ninserted\nline3\n" ); + + // Operation 3: Update using line/column (replace "inserted" with "modified") + rope = rope.update( 1, 0, 1, 7, "modified" ); + string = "line1\nmodified\nline3\n"; + assertThat( rope.toString() ).isEqualTo( string ); + + // Operation 4: Delete from middle of one line to middle of another + rope = rope.update( 0, 3, 2, 3, "X" ); + string = "linX3\n"; + assertThat( rope.toString() ).isEqualTo( string ); + } + + @Property + void randomDeletionsAndInsertionsPreserveLength( @ForAll( "inputString" ) final String initialString ) { + if ( initialString.length() < 5 ) { + return; + } + + final Random random = ThreadLocalRandom.current(); + Rope rope = new Rope( initialString ); + String string = initialString; + + // Perform 10 delete-insert pairs that should preserve total content + for ( int i = 0; i < 10; i++ ) { + final int index = random.nextInt( string.length() ); + final int deleteLength = Math.min( random.nextInt( 1, 4 ), string.length() - index ); + + // Delete + final String deleted = string.substring( index, index + deleteLength ); + rope = rope.delete( index, deleteLength ); + string = string.substring( 0, index ) + string.substring( index + deleteLength ); + + assertThat( rope.toString() ).isEqualTo( string ); + + // Re-insert at a different position + final int insertIndex = string.isEmpty() ? 0 : random.nextInt( string.length() + 1 ); + rope = rope.insert( new Rope( deleted ), insertIndex ); + string = string.substring( 0, insertIndex ) + deleted + string.substring( insertIndex ); + + assertThat( rope.toString() ).isEqualTo( string ); + } + + // Verify the characters are still all present (may be reordered) + assertThat( rope.length() ).isEqualTo( initialString.length() ); + } +} diff --git a/core/esmf-turtle-language-server/src/test/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TurtleParserServiceTest.java b/core/esmf-turtle-language-server/src/test/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TurtleParserServiceTest.java new file mode 100644 index 000000000..60d9ded14 --- /dev/null +++ b/core/esmf-turtle-language-server/src/test/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TurtleParserServiceTest.java @@ -0,0 +1,367 @@ +/* + * Copyright (c) 2026 Robert Bosch Manufacturing Solutions GmbH + * + * See the AUTHORS file(s) distributed with this work for additional + * information regarding authorship. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * SPDX-License-Identifier: MPL-2.0 + */ + +package org.eclipse.esmf.turtle.languageserver.lsp.text; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.eclipse.esmf.treesitterturtle.TreeSitterUtil; + +import org.eclipse.lsp4j.Position; +import org.eclipse.lsp4j.Range; +import org.eclipse.lsp4j.TextDocumentContentChangeEvent; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.treesitter.TSNode; +import org.treesitter.TSTree; + +@SuppressWarnings( "HttpUrlsUsage" ) +class TurtleParserServiceTest { + private TurtleParserService parserService; + + @BeforeEach + void setUp() { + parserService = new TurtleParserService(); + } + + @Test + void testInitialParsing() { + final String content = """ + @prefix ex: . + + ex:subject ex:predicate ex:object . + """; + + final Document document = new Document( "test.ttl", content ); + final TSTree tree = parserService.getAbstractSyntaxTree( document ); + + assertThat( tree ).isNotNull(); + final TSNode rootNode = tree.getRootNode(); + assertThat( rootNode ).isNotNull(); + assertThat( rootNode.getType() ).isEqualTo( "document" ); + assertThat( rootNode.hasError() ).isFalse(); + + final TSNode prefixDeclaration = rootNode.getChild( 0 ); + assertThat( prefixDeclaration ).isNotNull(); + assertThat( prefixDeclaration.getType() ).isEqualTo( "directive" ); + assertThat( prefixDeclaration.hasError() ).isFalse(); + + final TSNode prefixId = prefixDeclaration.getChild( 0 ); + assertThat( prefixId ).isNotNull(); + assertThat( prefixId.getType() ).isEqualTo( "prefix_id" ); + assertThat( prefixId.hasError() ).isFalse(); + + final TSNode namespace = prefixId.getChild( 0 ); + assertThat( namespace ).isNotNull(); + assertThat( namespace.getType() ).isEqualTo( "@prefix" ); + assertThat( namespace.hasError() ).isFalse(); + } + + @Test + void testEmptyDocument() { + final Document document = new Document( "empty.ttl", "" ); + final TSTree tree = parserService.getAbstractSyntaxTree( document ); + + assertThat( tree ).isNotNull(); + final TSNode rootNode = tree.getRootNode(); + assertThat( rootNode ).isNotNull(); + assertThat( rootNode.getChildCount() ).isEqualTo( 0 ); + } + + @Test + void testSingleLineInsertion() { + final String initialContent = """ + @prefix ex: . + """; + + final Document document = new Document( "test.ttl", initialContent ); + final TSTree initialTree = parserService.getAbstractSyntaxTree( document ); + assertThat( initialTree.getRootNode().hasError() ).isFalse(); + + final String newText = "\nex:subject ex:predicate ex:object ."; + applyChange( document, pos( 1, 0 ), pos( 1, 0 ), newText ); + + final TSTree updatedTree = parserService.getAbstractSyntaxTree( document ); + assertThat( updatedTree ).isNotNull(); + assertThat( updatedTree.getRootNode().hasError() ).isFalse(); + + assertThat( document.getContent() ).contains( "ex:subject ex:predicate ex:object" ); + } + + @Test + void testMultiLineInsertion() { + final String initialContent = "@prefix ex: ."; + final Document document = new Document( "test.ttl", initialContent ); + + final String newText = """ + + ex:subject1 ex:predicate1 ex:object1 . + ex:subject2 ex:predicate2 ex:object2 . + ex:subject3 ex:predicate3 ex:object3 ."""; + + applyChange( document, pos( 0, initialContent.length() ), pos( 0, initialContent.length() ), newText ); + + final TSTree tree = parserService.getAbstractSyntaxTree( document ); + assertThat( tree.getRootNode().hasError() ).isFalse(); + assertThat( document.getContent() ) + .contains( "ex:subject1" ) + .contains( "ex:subject2" ) + .contains( "ex:subject3" ); + } + + @Test + void testDeletion() { + final String initialContent = """ + @prefix ex: . + + ex:subject ex:predicate ex:object . + ex:ToDelete ex:willBeDeleted ex:Value . + """; + + final Document document = new Document( "test.ttl", initialContent ); + parserService.getAbstractSyntaxTree( document ); + + applyChange( document, pos( 3, 0 ), pos( 3, 38 ), "" ); + + final TSTree tree = parserService.getAbstractSyntaxTree( document ); + assertThat( tree.getRootNode().hasError() ).isFalse(); + assertThat( document.getContent() ).doesNotContain( "ex:ToDelete" ); + assertThat( document.getContent() ).contains( "ex:subject ex:predicate ex:object" ); + } + + @Test + void testReplacement() { + final String initialContent = """ + @prefix ex: . + + ex:subject ex:predicate ex:OldObject . + """; + + final Document document = new Document( "test.ttl", initialContent ); + parserService.getAbstractSyntaxTree( document ); + + final String replacement = "NewObject"; + applyChange( document, pos( 2, 27 ), pos( 2, 35 ), replacement ); + + final TSTree tree = parserService.getAbstractSyntaxTree( document ); + if ( tree.getRootNode().hasError() ) { + printDocumentAndTree( document, tree ); + } + assertThat( tree.getRootNode().hasError() ).isFalse(); + assertThat( document.getContent() ).doesNotContain( "OldObject" ); + assertThat( document.getContent() ).contains( "NewObject" ); + } + + @Test + void testMultipleSequentialEdits() { + final Document document = new Document( "test.ttl", "" ); + + // Edit 1: Add prefix + final String text1 = "@prefix ex: ."; + applyChange( document, pos( 0, 0 ), pos( 0, 0 ), text1 ); + + TSTree tree = parserService.getAbstractSyntaxTree( document ); + assertThat( tree.getRootNode().hasError() ).isFalse(); + + // Edit 2: Add first triple + final String text2 = "\n\nex:subject1 ex:predicate1 ex:object1 ."; + applyChange( document, pos( 0, 35 ), pos( 0, 35 ), text2 ); + + tree = parserService.getAbstractSyntaxTree( document ); + assertThat( tree.getRootNode().hasError() ).isFalse(); + assertThat( document.getContent() ).contains( "ex:subject1" ); + + // Edit 3: Add second triple + final String text3 = "\nex:subject2 ex:predicate2 ex:object2 ."; + applyChange( document, pos( 2, 38 ), pos( 2, 38 ), text3 ); + + tree = parserService.getAbstractSyntaxTree( document ); + assertThat( tree.getRootNode().hasError() ).isFalse(); + assertThat( document.getContent() ).contains( "ex:subject1" ) + .contains( "ex:subject2" ); + + // Edit 4: Delete the first triple + applyChange( document, pos( 2, 0 ), pos( 2, 38 ), "" ); + + tree = parserService.getAbstractSyntaxTree( document ); + assertThat( tree.getRootNode().hasError() ).isFalse(); + assertThat( document.getContent() ).doesNotContain( "ex:subject1" ); + assertThat( document.getContent() ).contains( "ex:subject2" ); + } + + @Test + void testEditAcrossMultipleLines() { + final String initialContent = """ + @prefix ex: . + + ex:subject + ex:predicate1 ex:object1 ; + ex:predicate2 ex:object2 . + """; + + final Document document = new Document( "test.ttl", initialContent ); + parserService.getAbstractSyntaxTree( document ); + + final String replacement = "ex:newPredicate"; + applyChange( document, pos( 3, 2 ), pos( 4, 14 ), replacement ); + + final TSTree tree = parserService.getAbstractSyntaxTree( document ); + assertThat( tree.getRootNode().hasError() ).isFalse(); + assertThat( document.getContent() ).contains( "ex:newPredicate" ); + assertThat( document.getContent() ).doesNotContain( "ex:predicate1" ); + } + + @Test + void testPrefixAddition() { + final String initialContent = "ex:subject ex:predicate ex:object ."; + + final Document document = new Document( "test.ttl", initialContent ); + parserService.getAbstractSyntaxTree( document ); + + final String prefix = "@prefix ex: .\n\n"; + applyChange( document, pos( 0, 0 ), pos( 0, 0 ), prefix ); + + final TSTree tree = parserService.getAbstractSyntaxTree( document ); + assertThat( tree.getRootNode().hasError() ).isFalse(); + assertThat( document.getContent() ).startsWith( "@prefix ex:" ); + } + + @Test + void testComplexEditSequence() { + final Document document = new Document( "test.ttl", "" ); + TSTree tree; + + // 1. Add base and prefix + applyChange( document, pos( 0, 0 ), pos( 0, 0 ), + "@base .\n@prefix ex: .\n\n" ); + tree = parserService.getAbstractSyntaxTree( document ); + assertThat( tree.getRootNode().hasError() ).isFalse(); + + // 2. Add a triple + applyChange( document, pos( 3, 0 ), pos( 3, 0 ), + "ex:subject ex:predicate ex:object ." ); + tree = parserService.getAbstractSyntaxTree( document ); + assertThat( tree.getRootNode().hasError() ).isFalse(); + + // 3. Add more predicates using semicolon syntax + applyChange( document, pos( 3, 33 ), pos( 3, 34 ), + " ;\n ex:predicate2 ex:object2 ;\n ex:predicate3 ex:object3 ." ); + tree = parserService.getAbstractSyntaxTree( document ); + assertThat( tree.getRootNode().hasError() ).isFalse(); + + // 4. Modify one of the predicates + final String content = document.getContent(); + final int predicateStart = content.indexOf( "ex:predicate2" ); + final int line = content.substring( 0, predicateStart ).split( "\n" ).length - 1; + final int col = predicateStart - content.lastIndexOf( '\n', predicateStart ) - 1; + + applyChange( document, pos( line, col ), pos( line, col + 12 ), "ex:modified" ); + tree = parserService.getAbstractSyntaxTree( document ); + assertThat( tree.getRootNode().hasError() ).isFalse(); + assertThat( document.getContent() ).contains( "ex:modified" ); + assertThat( document.getContent() ).doesNotContain( "ex:predicate2" ); + + // 5. Verify final structure + assertThat( document.getContent() ) + .contains( "@base" ) + .contains( "@prefix" ) + .contains( "ex:subject" ) + .contains( "ex:predicate" ) + .contains( "ex:predicate3" ) + .contains( "ex:modified" ); + } + + @Test + void testInvalidSyntaxHandling() { + final String initialContent = "@prefix ex: ."; + final Document document = new Document( "test.ttl", initialContent ); + + TSTree tree = parserService.getAbstractSyntaxTree( document ); + assertThat( tree.getRootNode().hasError() ).isFalse(); + + final String invalidText = "\n\nthis is not valid turtle syntax @#$%"; + applyChange( document, pos( 0, 35 ), pos( 0, 35 ), invalidText ); + + tree = parserService.getAbstractSyntaxTree( document ); + assertThat( tree.getRootNode() ).isNotNull(); + // Tree-sitter should still parse it, but with errors + assertThat( tree.getRootNode().hasError() ).isTrue(); + } + + @Test + void testFullDocumentChange() { + final String initialContent = "@prefix ex: ."; + final Document document = new Document( "test.ttl", initialContent ); + + parserService.getAbstractSyntaxTree( document ); + + // Simulate full document replacement (no range provided) + final String newContent = """ + @prefix rdf: . + @prefix rdfs: . + + rdf:type rdf:type rdf:Property . + """; + + final TextDocumentContentChangeEvent change = new TextDocumentContentChangeEvent(); + change.setText( newContent ); + // Note: Full document change means we need to recreate the document + // This tests the null range handling in treeChangeFromLspChange + + final Document newDocument = new Document( "test.ttl", newContent ); + parserService.onChange( newDocument, change ); + + final TSTree tree = parserService.getAbstractSyntaxTree( newDocument ); + assertThat( tree.getRootNode().hasError() ).isFalse(); + assertThat( newDocument.getContent() ).contains( "rdfs:" ); + } + + @Test + void testWhitespaceOnlyChanges() { + final String initialContent = "ex:subject ex:predicate ex:object."; + final Document document = new Document( "test.ttl", initialContent ); + final TSTree oldTree = parserService.getAbstractSyntaxTree( document ); + final Range range = new Range( pos( 0, 33 ), pos( 0, 33 ) ); + final TextDocumentContentChangeEvent change = new TextDocumentContentChangeEvent( range, " " ); + document.update( range, " " ); + parserService.onChange( document, change ); + + final TSTree tree = parserService.getAbstractSyntaxTree( document ); + assertThat( tree.getRootNode().hasError() ).isFalse(); + assertThat( document.getContent() ).endsWith( "object ." ); + assertThat( oldTree.getRootNode().toString() ).isEqualTo( tree.getRootNode().toString() ); + } + + void printDocumentAndTree( final Document document, final TSTree tree ) { + System.out.println( "Document" ); + System.out.println( "--------" ); + System.out.println( document.getContent() ); + System.out.println(); + System.out.println( "Tree" ); + System.out.println( "----" ); + System.out.println( TreeSitterUtil.print( tree ) ); + } + + private Position pos( final int line, final int character ) { + return new Position( line, character ); + } + + private void applyChange( final Document document, final Position start, final Position end, final String text ) { + final Range range = new Range( start, end ); + final TextDocumentContentChangeEvent change = new TextDocumentContentChangeEvent( range, text ); + document.update( range, text ); + parserService.onChange( document, change ); + } +} + + From 344112e1d3dffc37e199ec87a540f133fee9435d Mon Sep 17 00:00:00 2001 From: Andreas Textor Date: Mon, 27 Apr 2026 10:26:45 +0200 Subject: [PATCH 05/41] Base tree-sitter tree edits on previous document structure --- .../esmf/treesitterturtle/TreeSitterUtil.java | 2 +- .../languageserver/lsp/text/Document.java | 31 ++--------- .../turtle/languageserver/lsp/text/Rope.java | 55 ------------------- .../lsp/text/TurtleParserService.java | 26 +++++---- .../lsp/text/TurtleParserServiceTest.java | 14 ----- 5 files changed, 21 insertions(+), 107 deletions(-) diff --git a/core/esmf-tree-sitter-turtle/src/main/java/org/eclipse/esmf/treesitterturtle/TreeSitterUtil.java b/core/esmf-tree-sitter-turtle/src/main/java/org/eclipse/esmf/treesitterturtle/TreeSitterUtil.java index 39ee86d6f..7a46f6f1f 100644 --- a/core/esmf-tree-sitter-turtle/src/main/java/org/eclipse/esmf/treesitterturtle/TreeSitterUtil.java +++ b/core/esmf-tree-sitter-turtle/src/main/java/org/eclipse/esmf/treesitterturtle/TreeSitterUtil.java @@ -30,7 +30,7 @@ public static String print( final TSNode node ) { } private static void print( final TSNode node, final StringBuilder builder, final int indentLevel ) { - builder.append( " ".repeat( indentLevel ) ); + builder.repeat( " ", indentLevel ); builder.append( "- '" ); builder.append( node.getType() ); builder.append( "'" ); diff --git a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/Document.java b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/Document.java index d753da5dd..fd208ec82 100644 --- a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/Document.java +++ b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/Document.java @@ -35,6 +35,10 @@ public String getContent() { return content.toString(); } + public Rope getRope() { + return content; + } + public InputStream getInputStream() { return content.inputStream(); } @@ -43,33 +47,6 @@ public int getIndex( final int targetLine, final int targetColumn ) { return content.getIndex( targetLine, targetColumn ); } - /** - * Reads at most many bytes from the given offset into the buffer array, as the array provides, or - * fewer, if - * not as many are left at the offset. Returns 0 if the end of the source code was reached, - * otherwise the number of bytes read. - * - * @param buffer the buffer to write to - * @param offset offset to read from - * @return the number of bytes read - */ - public int read( final byte[] buffer, final int offset ) { - return content.read( buffer, offset ); - } - - /** - * Reads bytes from a specific position (row, column) in the document into the buffer. - * - * @param buffer the buffer to write to - * @param offset offset in the buffer to write to - * @param row the row/line to read from - * @param column the column in the row to read from - * @return the number of bytes read - */ - public int read( final byte[] buffer, final int offset, final int row, final int column ) { - return content.read( buffer, offset, row, column ); - } - public void update( final Range range, final String newContent ) { final Position start = range.getStart(); final Position end = range.getEnd(); diff --git a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/Rope.java b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/Rope.java index 2771e079f..63a5bb7e4 100644 --- a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/Rope.java +++ b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/Rope.java @@ -379,61 +379,6 @@ public int read( final byte[] buffer, final int offset ) { } } - /** - * Reads bytes from a specific position (row, column) in the rope into the buffer. - * - * @param buffer the buffer to read into - * @param offset offset in the buffer to write to - * @param row row/line to read from - * @param column column or nth byte in the line to read from - * @return the number of bytes read - */ - public int read( final byte[] buffer, final int offset, final int row, final int column ) { - if ( buffer == null || offset < 0 || offset >= buffer.length ) { - return 0; - } - - try ( final InputStream stream = inputStream( StandardCharsets.UTF_8 ) ) { - final byte[] allBytes = stream.readAllBytes(); - - // Find the byte position of the start of the row - int bytePosition = 0; - int currentLine = 0; - - for ( int i = 0; i < allBytes.length && currentLine < row; i++ ) { - if ( allBytes[i] == '\n' ) { - currentLine++; - bytePosition = i + 1; // Start of next line - } - } - - // Add the column offset - bytePosition += column; - - if ( bytePosition >= allBytes.length ) { - return 0; // Beyond end of content - } - - // Calculate how many bytes to read - final int availableInBuffer = buffer.length - offset; - final int availableInSource = allBytes.length - bytePosition; - final int bytesToRead = Math.min( availableInBuffer, availableInSource ); - - if ( bytesToRead <= 0 ) { - return 0; - } - - // Copy bytes into the buffer - System.arraycopy( allBytes, bytePosition, buffer, offset, bytesToRead ); - - return bytesToRead; - - } catch ( final Exception exception ) { - LOG.debug( "Exception while reading document content at position ({}, {})", row, column, exception ); - return 0; - } - } - public class RopeInputStream extends InputStream { private final Deque stack; private byte @Nullable [] currentBytes; diff --git a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TurtleParserService.java b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TurtleParserService.java index ff01a7d7c..786b7d90c 100644 --- a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TurtleParserService.java +++ b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TurtleParserService.java @@ -16,12 +16,14 @@ import java.nio.charset.StandardCharsets; import java.util.HashMap; import java.util.Map; +import java.util.WeakHashMap; import org.eclipse.esmf.treesitterturtle.TreeSitterTurtle; import org.eclipse.lsp4j.Position; import org.eclipse.lsp4j.Range; import org.eclipse.lsp4j.TextDocumentContentChangeEvent; +import org.jspecify.annotations.Nullable; import org.treesitter.TSInputEdit; import org.treesitter.TSLanguage; import org.treesitter.TSParser; @@ -35,6 +37,7 @@ public class TurtleParserService { private final TSParser parser; private final Map syntaxTrees = new HashMap<>(); + private final Map previousDocumentStates = new WeakHashMap<>(); public TurtleParserService() { parser = new TSParser(); @@ -47,20 +50,20 @@ public TSTree getAbstractSyntaxTree( final Document document ) { } private TSTree parseDocument( final Document document ) { + previousDocumentStates.put( document, document.getRope() ); return parser.parseString( null, document.getContent() ); } /** * Converts an LSP text change event into a Tree-sitter input edit. * - * @param document the document (used to calculate byte offsets) + * @param oldRope the rope before the change was applied * @param changeEvent the LSP change event * @return a TSInputEdit, or null if this is a full document change */ - private TSInputEdit treeChangeFromLspChange( final Document document, final TextDocumentContentChangeEvent changeEvent ) { + private @Nullable TSInputEdit treeChangeFromLspChange( final Rope oldRope, final TextDocumentContentChangeEvent changeEvent ) { final Range range = changeEvent.getRange(); if ( range == null ) { - // Full document change - return null to indicate full reparse needed return null; } @@ -70,8 +73,8 @@ private TSInputEdit treeChangeFromLspChange( final Document document, final Text final TSPoint startPoint = new TSPoint( startPos.getLine(), startPos.getCharacter() ); final TSPoint oldEndPoint = new TSPoint( endPos.getLine(), endPos.getCharacter() ); - final int startByte = document.getIndex( startPos.getLine(), startPos.getCharacter() ); - final int oldEndByte = document.getIndex( endPos.getLine(), endPos.getCharacter() ); + final int startByte = oldRope.getIndex( startPos.getLine(), startPos.getCharacter() ); + final int oldEndByte = oldRope.getIndex( endPos.getLine(), endPos.getCharacter() ); final TSPoint newEndPoint = calculateNewEndPoint( startPoint, newText ); final int newEndByte = startByte + newText.getBytes( StandardCharsets.UTF_8 ).length; return new TSInputEdit( startByte, oldEndByte, newEndByte, startPoint, oldEndPoint, newEndPoint ); @@ -107,15 +110,19 @@ private TSPoint calculateNewEndPoint( final TSPoint startPoint, final String new public void onChange( final Document document, final TextDocumentContentChangeEvent changeEvent ) { final TSTree oldTree = syntaxTrees.get( document ); - if ( oldTree == null ) { syntaxTrees.put( document, parseDocument( document ) ); return; } - final TSInputEdit edit = treeChangeFromLspChange( document, changeEvent ); + final Rope oldRope = previousDocumentStates.get( document ); + if ( oldRope == null ) { + syntaxTrees.put( document, parseDocument( document ) ); + return; + } + + final TSInputEdit edit = treeChangeFromLspChange( oldRope, changeEvent ); if ( edit == null ) { - // Full document change - reparse from scratch syntaxTrees.put( document, parseDocument( document ) ); return; } @@ -123,7 +130,6 @@ public void onChange( final Document document, final TextDocumentContentChangeEv oldTree.edit( edit ); final TSTree newTree = parser.parseString( oldTree, document.getContent() ); syntaxTrees.put( document, newTree ); + previousDocumentStates.put( document, document.getRope() ); } } - - diff --git a/core/esmf-turtle-language-server/src/test/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TurtleParserServiceTest.java b/core/esmf-turtle-language-server/src/test/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TurtleParserServiceTest.java index 60d9ded14..455dde00c 100644 --- a/core/esmf-turtle-language-server/src/test/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TurtleParserServiceTest.java +++ b/core/esmf-turtle-language-server/src/test/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TurtleParserServiceTest.java @@ -166,14 +166,12 @@ void testReplacement() { void testMultipleSequentialEdits() { final Document document = new Document( "test.ttl", "" ); - // Edit 1: Add prefix final String text1 = "@prefix ex: ."; applyChange( document, pos( 0, 0 ), pos( 0, 0 ), text1 ); TSTree tree = parserService.getAbstractSyntaxTree( document ); assertThat( tree.getRootNode().hasError() ).isFalse(); - // Edit 2: Add first triple final String text2 = "\n\nex:subject1 ex:predicate1 ex:object1 ."; applyChange( document, pos( 0, 35 ), pos( 0, 35 ), text2 ); @@ -181,7 +179,6 @@ void testMultipleSequentialEdits() { assertThat( tree.getRootNode().hasError() ).isFalse(); assertThat( document.getContent() ).contains( "ex:subject1" ); - // Edit 3: Add second triple final String text3 = "\nex:subject2 ex:predicate2 ex:object2 ."; applyChange( document, pos( 2, 38 ), pos( 2, 38 ), text3 ); @@ -190,7 +187,6 @@ void testMultipleSequentialEdits() { assertThat( document.getContent() ).contains( "ex:subject1" ) .contains( "ex:subject2" ); - // Edit 4: Delete the first triple applyChange( document, pos( 2, 0 ), pos( 2, 38 ), "" ); tree = parserService.getAbstractSyntaxTree( document ); @@ -241,25 +237,21 @@ void testComplexEditSequence() { final Document document = new Document( "test.ttl", "" ); TSTree tree; - // 1. Add base and prefix applyChange( document, pos( 0, 0 ), pos( 0, 0 ), "@base .\n@prefix ex: .\n\n" ); tree = parserService.getAbstractSyntaxTree( document ); assertThat( tree.getRootNode().hasError() ).isFalse(); - // 2. Add a triple applyChange( document, pos( 3, 0 ), pos( 3, 0 ), "ex:subject ex:predicate ex:object ." ); tree = parserService.getAbstractSyntaxTree( document ); assertThat( tree.getRootNode().hasError() ).isFalse(); - // 3. Add more predicates using semicolon syntax applyChange( document, pos( 3, 33 ), pos( 3, 34 ), " ;\n ex:predicate2 ex:object2 ;\n ex:predicate3 ex:object3 ." ); tree = parserService.getAbstractSyntaxTree( document ); assertThat( tree.getRootNode().hasError() ).isFalse(); - // 4. Modify one of the predicates final String content = document.getContent(); final int predicateStart = content.indexOf( "ex:predicate2" ); final int line = content.substring( 0, predicateStart ).split( "\n" ).length - 1; @@ -271,7 +263,6 @@ void testComplexEditSequence() { assertThat( document.getContent() ).contains( "ex:modified" ); assertThat( document.getContent() ).doesNotContain( "ex:predicate2" ); - // 5. Verify final structure assertThat( document.getContent() ) .contains( "@base" ) .contains( "@prefix" ) @@ -304,8 +295,6 @@ void testFullDocumentChange() { final Document document = new Document( "test.ttl", initialContent ); parserService.getAbstractSyntaxTree( document ); - - // Simulate full document replacement (no range provided) final String newContent = """ @prefix rdf: . @prefix rdfs: . @@ -315,9 +304,6 @@ void testFullDocumentChange() { final TextDocumentContentChangeEvent change = new TextDocumentContentChangeEvent(); change.setText( newContent ); - // Note: Full document change means we need to recreate the document - // This tests the null range handling in treeChangeFromLspChange - final Document newDocument = new Document( "test.ttl", newContent ); parserService.onChange( newDocument, change ); From 0f997219a66be252ae00ac2049c0a0d7b3431288 Mon Sep 17 00:00:00 2001 From: Andreas Textor Date: Thu, 30 Apr 2026 07:46:03 +0200 Subject: [PATCH 06/41] Include tree-parser based syntax validation in Turtle service --- .../resolver/AspectModelFileLoader.java | 2 +- .../TreeSitterTurtleTest.java | 442 +++++++++++++++++- .../languageserver/TurtleLanguageServer.java | 4 +- .../diagnostic/AspectDiagnosticMapper.java | 42 +- .../aspect/model/AspectValidationError.java | 19 - .../aspect/model/AspectValidationResult.java | 23 - .../aspect/model/AspectViolationInfo.java | 24 - .../service/AspectModelValidationService.java | 78 +++- .../service/AspectValidationCoordinator.java | 55 ++- .../DefaultAspectModelValidationService.java | 124 ----- .../diagnostic/DiagnosticReport.java | 34 ++ .../diagnostic/TurtleBaseDiagnostic.java | 34 ++ .../diagnostic/TurtleDiagnostic.java | 53 +++ .../TurtleDiagnosticsService.java} | 11 +- .../diagnostic/TurtleDocumentDiagnostic.java | 57 +++ .../lsp/text/AspectDiagnosticsWorkflow.java | 45 +- .../languageserver/lsp/text/Document.java | 6 + .../text/DocumentAspectValidationService.java | 21 +- .../lsp/text/DocumentDiagnosticsService.java | 60 --- .../lsp/text/DocumentDiagnosticsStore.java | 50 -- .../lsp/text/DocumentStore.java | 33 -- ...=> JenaTurtleSyntaxValidationService.java} | 43 +- .../lsp/text/TextDocumentClientNotifier.java | 20 +- ...eSitterTurtleSyntaxValidationService.java} | 36 +- .../lsp/text}/TreeSitterUtil.java | 29 +- .../lsp/text/TurtleSyntaxTree.java | 364 +++++++++++++++ .../lsp/text/TurtleTextDocumentService.java | 87 ++-- .../lsp/text/TurtleParserServiceTest.java | 33 +- 28 files changed, 1290 insertions(+), 539 deletions(-) delete mode 100644 core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/aspect/model/AspectValidationError.java delete mode 100644 core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/aspect/model/AspectValidationResult.java delete mode 100644 core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/aspect/model/AspectViolationInfo.java delete mode 100644 core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/aspect/service/DefaultAspectModelValidationService.java create mode 100644 core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/diagnostic/DiagnosticReport.java create mode 100644 core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/diagnostic/TurtleBaseDiagnostic.java create mode 100644 core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/diagnostic/TurtleDiagnostic.java rename core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/{aspect/model/AspectValidationErrorType.java => diagnostic/TurtleDiagnosticsService.java} (66%) create mode 100644 core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/diagnostic/TurtleDocumentDiagnostic.java delete mode 100644 core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/DocumentDiagnosticsService.java delete mode 100644 core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/DocumentDiagnosticsStore.java delete mode 100644 core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/DocumentStore.java rename core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/{TurtleSyntaxValidationService.java => JenaTurtleSyntaxValidationService.java} (52%) rename core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/{TurtleParserService.java => TreeSitterTurtleSyntaxValidationService.java} (75%) rename core/{esmf-tree-sitter-turtle/src/main/java/org/eclipse/esmf/treesitterturtle => esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text}/TreeSitterUtil.java (51%) create mode 100644 core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TurtleSyntaxTree.java diff --git a/core/esmf-aspect-meta-model-java/src/main/java/org/eclipse/esmf/aspectmodel/resolver/AspectModelFileLoader.java b/core/esmf-aspect-meta-model-java/src/main/java/org/eclipse/esmf/aspectmodel/resolver/AspectModelFileLoader.java index 4533350bb..c763f8383 100644 --- a/core/esmf-aspect-meta-model-java/src/main/java/org/eclipse/esmf/aspectmodel/resolver/AspectModelFileLoader.java +++ b/core/esmf-aspect-meta-model-java/src/main/java/org/eclipse/esmf/aspectmodel/resolver/AspectModelFileLoader.java @@ -104,7 +104,7 @@ public static RawAspectModelFile load( final InputStream inputStream, final URI * Loads the content of an AspectModelFile from an RDF model * * @param model the input model - * @param sourceLocation the logical location of the file file source + * @param sourceLocation the logical location of the file source * @return the loaded file content */ public static RawAspectModelFile load( final Model model, final URI sourceLocation ) { diff --git a/core/esmf-tree-sitter-turtle/src/test/java/org/eclipse/esmf/treesitterturtle/TreeSitterTurtleTest.java b/core/esmf-tree-sitter-turtle/src/test/java/org/eclipse/esmf/treesitterturtle/TreeSitterTurtleTest.java index 9ded35f1b..70c0f5dba 100644 --- a/core/esmf-tree-sitter-turtle/src/test/java/org/eclipse/esmf/treesitterturtle/TreeSitterTurtleTest.java +++ b/core/esmf-tree-sitter-turtle/src/test/java/org/eclipse/esmf/treesitterturtle/TreeSitterTurtleTest.java @@ -15,25 +15,453 @@ import static org.assertj.core.api.Assertions.assertThat; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.treesitter.TSLanguage; import org.treesitter.TSNode; import org.treesitter.TSParser; import org.treesitter.TSTree; +@SuppressWarnings( "HttpUrlsUsage" ) public class TreeSitterTurtleTest { - @Test - void testParser() { - final TSParser parser = new TSParser(); + private TSParser parser; + + @BeforeEach + void setUp() { + parser = new TSParser(); final TSLanguage turtle = new TreeSitterTurtle(); parser.setLanguage( turtle ); - final TSTree tree = parser.parseString( null, """ + } + + @Test + void testBasicPrefixAndTriple() { + final String content = """ @prefix : . :a a :b . - """ ); + """; + final TSTree tree = parser.parseString( null, content ); final TSNode rootNode = tree.getRootNode(); - assertThat( rootNode.toString() ).doesNotContain( "ERROR" ); + assertThat( print( rootNode, content ) ).doesNotContain( "ERROR" ); + assertThat( rootNode.hasError() ).isFalse(); assertThat( rootNode.getChild( 0 ).getChild( 0 ).getChild( 0 ).getGrammarType() ).isEqualTo( "@prefix" ); - System.out.println( rootNode ); + } + + @Test + void testNumericLiterals() { + final String content = """ + @prefix ex: . + + ex:entity ex:intValue 42 . + ex:entity ex:decimalValue 3.14 . + ex:entity ex:doubleValue 1.23e10 . + ex:entity ex:negativeInt -100 . + ex:entity ex:positiveDouble +2.5 . + """; + + final TSTree tree = parser.parseString( null, content ); + final TSNode rootNode = tree.getRootNode(); + + assertThat( rootNode.hasError() ).isFalse(); + assertThat( print( rootNode, content ) ).doesNotContain( "ERROR" ); + + // Verify the document parses successfully with numeric literals + final String treeString = print( rootNode, content ); + assertThat( treeString ).contains( "42" ); + assertThat( treeString ).contains( "3.14" ); + assertThat( treeString ).contains( "1.23e10" ); + } + + @Test + void testStringLiterals() { + final String content = """ + @prefix ex: . + + ex:entity ex:simpleString "Hello World" . + ex:entity ex:stringWithEscapes "Line 1\\nLine 2\\tTabbed" . + ex:entity ex:multilineString \"\"\"This is a + multiline + string literal\"\"\" . + ex:entity ex:singleQuote 'Single quoted string' . + """; + + final TSTree tree = parser.parseString( null, content ); + final TSNode rootNode = tree.getRootNode(); + + assertThat( rootNode.hasError() ).isFalse(); + assertThat( print( rootNode, content ) ).doesNotContain( "ERROR" ); + } + + @Test + void testBooleanLiterals() { + final String content = """ + @prefix ex: . + + ex:entity ex:isTrue true . + ex:entity ex:isFalse false . + """; + + final TSTree tree = parser.parseString( null, content ); + final TSNode rootNode = tree.getRootNode(); + + assertThat( rootNode.hasError() ).isFalse(); + assertThat( print( rootNode, content ) ).doesNotContain( "ERROR" ); + assertThat( print( rootNode, content ) ).contains( "true" ); + assertThat( print( rootNode, content ) ).contains( "false" ); + } + + @Test + void testLanguageTaggedLiterals() { + final String content = """ + @prefix ex: . + @prefix rdfs: . + + ex:entity rdfs:label "Hello"@en . + ex:entity rdfs:label "Hallo"@de . + ex:entity rdfs:label "Bonjour"@fr . + ex:entity rdfs:label "こんにちは"@ja . + ex:entity rdfs:comment "Multi-word label"@en-US . + """; + + final TSTree tree = parser.parseString( null, content ); + final TSNode rootNode = tree.getRootNode(); + + assertThat( rootNode.hasError() ).isFalse(); + assertThat( print( rootNode, content ) ).doesNotContain( "ERROR" ); + assertThat( print( rootNode, content ) ).contains( "@en" ); + assertThat( print( rootNode, content ) ).contains( "@de" ); + assertThat( print( rootNode, content ) ).contains( "@fr" ); + } + + @Test + void testTypedLiterals() { + final String content = """ + @prefix ex: . + @prefix xsd: . + + ex:entity ex:dateValue "2026-04-30"^^xsd:date . + ex:entity ex:intValue "42"^^xsd:integer . + ex:entity ex:boolValue "true"^^xsd:boolean . + ex:entity ex:customType "custom value"^^ex:MyType . + ex:entity ex:fullUri "value"^^ . + """; + + final TSTree tree = parser.parseString( null, content ); + final TSNode rootNode = tree.getRootNode(); + + assertThat( rootNode.hasError() ).isFalse(); + assertThat( print( rootNode, content ) ).doesNotContain( "ERROR" ); + assertThat( print( rootNode, content ) ).contains( "^^" ); + } + + @Test + void testRdfListSyntax() { + final String content = """ + @prefix ex: . + @prefix rdf: . + + ex:entity ex:emptyList () . + ex:entity ex:numberList (1 2 3 4 5) . + ex:entity ex:stringList ("a" "b" "c") . + ex:entity ex:mixedList (1 "two" 3.0 true ex:resource) . + ex:entity ex:nestedList (1 (2 3) 4) . + """; + + final TSTree tree = parser.parseString( null, content ); + final TSNode rootNode = tree.getRootNode(); + + assertThat( rootNode.hasError() ).isFalse(); + assertThat( print( rootNode, content ) ).doesNotContain( "ERROR" ); + assertThat( print( rootNode, content ) ).contains( "(" ); + assertThat( print( rootNode, content ) ).contains( ")" ); + } + + @Test + void testAnonymousNodes() { + final String content = """ + @prefix ex: . + + ex:entity ex:hasBlankNode [ + ex:property1 "value1" ; + ex:property2 "value2" + ] . + + ex:entity ex:simpleBlank [ ex:prop "val" ] . + + ex:entity ex:nestedBlank [ + ex:inner [ + ex:nested "deeply" + ] + ] . + + # Blank node with multiple predicates and objects + ex:person [ + ex:firstName "John" ; + ex:lastName "Doe" ; + ex:age 30 ; + ex:knows [ + ex:firstName "Jane" ; + ex:lastName "Smith" + ] + ] . + """; + + final TSTree tree = parser.parseString( null, content ); + final TSNode rootNode = tree.getRootNode(); + + assertThat( rootNode.hasError() ).isFalse(); + assertThat( print( rootNode, content ) ).doesNotContain( "ERROR" ); + assertThat( print( rootNode, content ) ).contains( "[" ); + assertThat( print( rootNode, content ) ).contains( "]" ); + } + + @Test + void testComplexDocument() { + final String content = """ + @prefix ex: . + @prefix rdf: . + @prefix xsd: . + @base . + + ex:Person a ex:Class ; + ex:name "Person"@en ; + ex:properties ( + ex:firstName + ex:lastName + ex:age + ) . + + ex:john a ex:Person ; + ex:firstName "John" ; + ex:lastName "Doe" ; + ex:age "30"^^xsd:integer ; + ex:active true ; + ex:salary 50000.50 ; + ex:address [ + ex:street "123 Main St" ; + ex:city "Anytown" ; + ex:country "USA"@en + ] ; + ex:hobbies ("reading" "coding" "music") . + """; + + final TSTree tree = parser.parseString( null, content ); + final TSNode rootNode = tree.getRootNode(); + + assertThat( rootNode.hasError() ).isFalse(); + assertThat( print( rootNode, content ) ).doesNotContain( "ERROR" ); + } + + @Test + void testBrokenSyntaxMissingDot() { + final String content = """ + @prefix ex: + + ex:entity ex:property "value" . + """; + + final TSTree tree = parser.parseString( null, content ); + final TSNode rootNode = tree.getRootNode(); + + // Should have errors due to missing dot after prefix declaration + assertThat( rootNode.hasError() ).isTrue(); + assertThat( print( rootNode, content ) ).contains( "ERROR" ); + } + + @Test + void testBrokenSyntaxInvalidUri() { + final String content = """ + @prefix ex: . + + ex:entity ex:property . + """; + + final TSTree tree = parser.parseString( null, content ); + final TSNode rootNode = tree.getRootNode(); + + // Should have errors due to invalid URI + assertThat( rootNode.hasError() ).isTrue(); + assertThat( print( rootNode, content ) ).contains( "ERROR" ); + } + + @Test + void testBrokenSyntaxUnterminatedString() { + final String content = """ + @prefix ex: . + + ex:entity ex:property "unterminated string . + """; + + final TSTree tree = parser.parseString( null, content ); + final TSNode rootNode = tree.getRootNode(); + + // Should have errors due to unterminated string + assertThat( rootNode.hasError() ).isTrue(); + assertThat( print( rootNode, content ) ).contains( "ERROR" ); + } + + @Test + void testBrokenSyntaxMismatchedBrackets() { + final String content = """ + @prefix ex: . + + ex:entity ex:property [ + ex:nested "value" + . + """; + + final TSTree tree = parser.parseString( null, content ); + final TSNode rootNode = tree.getRootNode(); + + // Should have errors due to mismatched brackets + assertThat( rootNode.hasError() ).isTrue(); + assertThat( print( rootNode, content ) ).contains( "ERROR" ); + } + + @Test + void testBrokenSyntaxInvalidPrefix() { + final String content = """ + @prefix 123invalid: . + + 123invalid:entity ex:property "value" . + """; + + final TSTree tree = parser.parseString( null, content ); + final TSNode rootNode = tree.getRootNode(); + + // Should have errors due to invalid prefix name (starts with number) + assertThat( rootNode.hasError() ).isTrue(); + assertThat( print( rootNode, content ) ).contains( "ERROR" ); + } + + @Test + void testBrokenSyntaxIncompleteTriple() { + final String content = """ + @prefix ex: . + + ex:entity ex:property . + """; + + final TSTree tree = parser.parseString( null, content ); + final TSNode rootNode = tree.getRootNode(); + + // Should have errors due to missing object + assertThat( rootNode.hasError() ).isTrue(); + assertThat( print( rootNode, content ) ).contains( "ERROR" ); + } + + @Test + void testSemicolonAndCommaSyntax() { + final String content = """ + @prefix ex: . + + ex:entity + ex:prop1 "value1" ; + ex:prop2 "value2" , "value3" , "value4" ; + ex:prop3 "value5" . + """; + + final TSTree tree = parser.parseString( null, content ); + final TSNode rootNode = tree.getRootNode(); + + assertThat( rootNode.hasError() ).isFalse(); + assertThat( print( rootNode, content ) ).doesNotContain( "ERROR" ); + } + + @Test + void testComments() { + final String content = """ + # This is a comment + @prefix ex: . + + # Another comment + ex:entity ex:property "value" . # Inline comment + + # Multi-line comments + # are also supported + ex:entity2 ex:property2 "value2" . + """; + + final TSTree tree = parser.parseString( null, content ); + final TSNode rootNode = tree.getRootNode(); + + assertThat( rootNode.hasError() ).isFalse(); + assertThat( print( rootNode, content ) ).doesNotContain( "ERROR" ); + } + + public static String print( final TSNode node, final String source ) { + final StringBuilder builder = new StringBuilder(); + print( node, builder, 0, source ); + return builder.toString(); + } + + private static void print( final TSNode node, final StringBuilder builder, final int indentLevel, final String source ) { + builder.repeat( " ", indentLevel ); + builder.append( "- '" ); + builder.append( node.getType() ); + builder.append( "'" ); + if ( node.hasError() ) { + builder.append( " (ERROR)" ); + } else if ( node.getStartPoint().getRow() == node.getEndPoint().getRow() ) { + final String nodeContent = getSubDocument( source, node.getStartPoint().getRow(), node.getStartPoint().getColumn(), + node.getEndPoint().getRow(), node.getEndPoint().getColumn() ); + if ( !nodeContent.equals( node.getType() ) ) { + builder.append( " (" ); + builder.append( nodeContent ); + builder.append( ")" ); + } + } + builder.append( "\n" ); + for ( int i = 0; i < node.getChildCount(); i++ ) { + print( node.getChild( i ), builder, indentLevel + 1, source ); + } + } + + /** + * Extracts a substring from a multi-line string using line and column coordinates. + * + * @param originalString the source string + * @param fromLine the starting line (0-based) + * @param fromColumn the starting column (0-based) + * @param toLine the ending line (0-based) + * @param toColumn the ending column (0-based, exclusive) + * @return the extracted substring + */ + private static String getSubDocument( final String originalString, final int fromLine, final int fromColumn, + final int toLine, final int toColumn ) { + if ( originalString == null || originalString.isEmpty() ) { + return ""; + } + + // Calculate the start index by navigating to the start line + int currentLine = 0; + int i = 0; + + while ( i < originalString.length() && currentLine < fromLine ) { + if ( originalString.charAt( i ) == '\n' ) { + currentLine++; + } + i++; + } + + final int startIndex = i + fromColumn; + + // Calculate the end index by navigating to the end line + currentLine = 0; + i = 0; + + while ( i < originalString.length() && currentLine < toLine ) { + if ( originalString.charAt( i ) == '\n' ) { + currentLine++; + } + i++; + } + + final int endIndex = i + toColumn; + + // Clamp indices to valid range + final int clampedStart = Math.clamp( startIndex, 0, originalString.length() ); + final int clampedEnd = Math.clamp( endIndex, clampedStart, originalString.length() ); + + return originalString.substring( clampedStart, clampedEnd ); } } diff --git a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/TurtleLanguageServer.java b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/TurtleLanguageServer.java index 4f39596ec..71afcd08a 100644 --- a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/TurtleLanguageServer.java +++ b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/TurtleLanguageServer.java @@ -28,7 +28,7 @@ import org.eclipse.lsp4j.services.TextDocumentService; import org.eclipse.lsp4j.services.WorkspaceService; -import org.eclipse.esmf.turtle.languageserver.aspect.model.AspectValidationResult; +import org.eclipse.esmf.turtle.languageserver.diagnostic.DiagnosticReport; import org.eclipse.esmf.turtle.languageserver.aspect.request.ValidateDocumentParams; import org.eclipse.esmf.turtle.languageserver.lsp.text.TurtleTextDocumentService; import org.eclipse.esmf.turtle.languageserver.lsp.workspace.TurtleWorkspaceService; @@ -86,7 +86,7 @@ public void connect( final LanguageClient client ) { } @JsonRequest( "turtle/aspectValidation/validateDocument" ) - public CompletableFuture validateDocument( final ValidateDocumentParams params ) { + public CompletableFuture validateDocument( final ValidateDocumentParams params ) { final String uri = params != null ? params.uri() : null; return CompletableFuture.completedFuture( textDocumentService.validateDocument( uri ) ); } diff --git a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/aspect/diagnostic/AspectDiagnosticMapper.java b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/aspect/diagnostic/AspectDiagnosticMapper.java index 838d94bd9..9247f13fe 100644 --- a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/aspect/diagnostic/AspectDiagnosticMapper.java +++ b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/aspect/diagnostic/AspectDiagnosticMapper.java @@ -13,51 +13,49 @@ package org.eclipse.esmf.turtle.languageserver.aspect.diagnostic; -import java.net.URI; import java.util.List; -import org.eclipse.esmf.turtle.languageserver.aspect.model.AspectValidationResult; -import org.eclipse.esmf.turtle.languageserver.aspect.model.AspectViolationInfo; +import org.eclipse.esmf.turtle.languageserver.diagnostic.DiagnosticReport; +import org.eclipse.esmf.turtle.languageserver.diagnostic.TurtleDiagnostic; +import org.eclipse.esmf.turtle.languageserver.diagnostic.TurtleDocumentDiagnostic; +import org.eclipse.esmf.turtle.languageserver.lsp.text.Document; import org.eclipse.lsp4j.Diagnostic; import org.eclipse.lsp4j.DiagnosticSeverity; import org.eclipse.lsp4j.Position; import org.eclipse.lsp4j.Range; -import org.eclipse.lsp4j.jsonrpc.messages.Either; public final class AspectDiagnosticMapper { public static final String SOURCE = "lsp-server.aspect"; - public List toDiagnostics( final String documentUri, final AspectValidationResult result ) { - return result.violations().stream() - .filter( violation -> appliesToDocument( documentUri, violation ) ) + public List toDiagnostics( final Document document, final DiagnosticReport result ) { + return result.diagnostics().stream() + .filter( violation -> appliesToDocument( document, violation ) ) .map( this::toDiagnostic ) .toList(); } - private boolean appliesToDocument( final String documentUri, final AspectViolationInfo violation ) { - if ( violation.sourceLocation() == null ) { - return true; + private boolean appliesToDocument( final Document document, final TurtleDiagnostic turtleDiagnostic ) { + if ( turtleDiagnostic instanceof final TurtleDocumentDiagnostic turtleDocumentDiagnostic ) { + return document.getUri().equals( turtleDocumentDiagnostic.sourceLocation() ); } - - return URI.create( documentUri ).equals( violation.sourceLocation() ); + return true; } - private Diagnostic toDiagnostic( final AspectViolationInfo violation ) { + private Diagnostic toDiagnostic( final TurtleDiagnostic turtleDiagnostic ) { final Diagnostic diagnostic = new Diagnostic(); diagnostic.setSource( SOURCE ); diagnostic.setSeverity( DiagnosticSeverity.Error ); - diagnostic.setMessage( violation.message() ); - diagnostic.setCode( Either.forLeft( violation.code() ) ); - diagnostic.setRange( toRange( violation ) ); + diagnostic.setMessage( turtleDiagnostic.message() ); + diagnostic.setCode( turtleDiagnostic.code().code() ); + if ( turtleDiagnostic instanceof final TurtleDocumentDiagnostic turtleDocumentDiagnostic ) { + diagnostic.setRange( toRange( turtleDocumentDiagnostic ) ); + } return diagnostic; } - private Range toRange( final AspectViolationInfo violation ) { - final long line = violation.line() != null ? violation.line() : 1L; - final long column = violation.column() != null ? violation.column() : 1L; - final int safeLine = (int) Math.max( 0, line - 1 ); - final int safeColumn = (int) Math.max( 0, column - 1 ); - return new Range( new Position( safeLine, safeColumn ), new Position( safeLine, safeColumn + 1 ) ); + private Range toRange( final TurtleDocumentDiagnostic violation ) { + return new Range( new Position( violation.fromLine(), violation.fromColumn() ), + new Position( violation.toLine(), violation.toColumn() ) ); } } diff --git a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/aspect/model/AspectValidationError.java b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/aspect/model/AspectValidationError.java deleted file mode 100644 index 478924c9a..000000000 --- a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/aspect/model/AspectValidationError.java +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (c) 2026 Robert Bosch Manufacturing Solutions GmbH - * - * See the AUTHORS file(s) distributed with this work for additional - * information regarding authorship. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * SPDX-License-Identifier: MPL-2.0 - */ - -package org.eclipse.esmf.turtle.languageserver.aspect.model; - -public record AspectValidationError( - AspectValidationErrorType type, - String message -) {} diff --git a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/aspect/model/AspectValidationResult.java b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/aspect/model/AspectValidationResult.java deleted file mode 100644 index 7d7fbd338..000000000 --- a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/aspect/model/AspectValidationResult.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (c) 2026 Robert Bosch Manufacturing Solutions GmbH - * - * See the AUTHORS file(s) distributed with this work for additional - * information regarding authorship. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * SPDX-License-Identifier: MPL-2.0 - */ - -package org.eclipse.esmf.turtle.languageserver.aspect.model; - -import java.util.List; - -public record AspectValidationResult( - boolean valid, - String report, - List violations, - AspectValidationError error -) {} diff --git a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/aspect/model/AspectViolationInfo.java b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/aspect/model/AspectViolationInfo.java deleted file mode 100644 index 018393438..000000000 --- a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/aspect/model/AspectViolationInfo.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (c) 2026 Robert Bosch Manufacturing Solutions GmbH - * - * See the AUTHORS file(s) distributed with this work for additional - * information regarding authorship. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * SPDX-License-Identifier: MPL-2.0 - */ - -package org.eclipse.esmf.turtle.languageserver.aspect.model; - -import java.net.URI; - -public record AspectViolationInfo( - String code, - String message, - URI sourceLocation, - Long line, - Long column -) {} diff --git a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/aspect/service/AspectModelValidationService.java b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/aspect/service/AspectModelValidationService.java index ab425663f..fb7609f20 100644 --- a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/aspect/service/AspectModelValidationService.java +++ b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/aspect/service/AspectModelValidationService.java @@ -13,9 +13,81 @@ package org.eclipse.esmf.turtle.languageserver.aspect.service; -import org.eclipse.esmf.turtle.languageserver.aspect.model.AspectValidationResult; +import java.io.InputStream; +import java.net.URI; +import java.util.List; + +import org.eclipse.esmf.aspectmodel.loader.AspectModelLoader; +import org.eclipse.esmf.aspectmodel.shacl.violation.Violation; +import org.eclipse.esmf.aspectmodel.validation.InvalidLexicalValueViolation; +import org.eclipse.esmf.aspectmodel.validation.InvalidSyntaxViolation; +import org.eclipse.esmf.aspectmodel.validation.services.AspectModelValidator; +import org.eclipse.esmf.turtle.languageserver.diagnostic.DiagnosticReport; +import org.eclipse.esmf.turtle.languageserver.diagnostic.TurtleBaseDiagnostic; +import org.eclipse.esmf.turtle.languageserver.diagnostic.TurtleDiagnostic; +import org.eclipse.esmf.turtle.languageserver.diagnostic.TurtleDiagnosticsService; +import org.eclipse.esmf.turtle.languageserver.diagnostic.TurtleDocumentDiagnostic; import org.eclipse.esmf.turtle.languageserver.lsp.text.Document; -public interface AspectModelValidationService { - AspectValidationResult validate( Document document ); +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class AspectModelValidationService implements TurtleDiagnosticsService { + private static final Logger LOG = LoggerFactory.getLogger( AspectModelValidationService.class ); + + private final AspectModelLoader loader; + private final AspectModelValidator validator; + + public AspectModelValidationService() { + this( new AspectModelLoader(), new AspectModelValidator() ); + } + + AspectModelValidationService( final AspectModelLoader loader, final AspectModelValidator validator ) { + this.loader = loader; + this.validator = validator; + } + + @Override + public DiagnosticReport check( final Document document ) { + try ( final InputStream inputStream = document.getInputStream() ) { + LOG.debug( "[load] loading aspect model from {}", document.getUri() ); + final List violations = + validator.validateModel( () -> loader.load( inputStream, URI.create( document.getUri() ) ) ); + LOG.debug( "[validate] validation finished for {} with {} violation(s)", document.getUri(), violations.size() ); + return new DiagnosticReport( violations.stream().map( this::toViolationInfo ).toList() ); + } catch ( final Exception exception ) { + LOG.error( "[validate] unexpected runtime failure for {}", document.getUri(), exception ); + return new DiagnosticReport( exception.getMessage(), TurtleDiagnostic.TurtleCode.E0000 ); + } + } + + private TurtleDiagnostic.Code classifyViolation( final Violation violation ) { + return TurtleDiagnostic.TurtleCode.E0000; + } + + private TurtleDiagnostic toViolationInfo( final Violation violation ) { + return switch ( violation ) { + case final InvalidSyntaxViolation syntaxViolation -> + new TurtleDocumentDiagnostic( + syntaxViolation.message(), + classifyViolation( violation ), + syntaxViolation.sourceLocation().map( URI::toString ).orElseThrow(), + (int) syntaxViolation.line(), + (int) syntaxViolation.column(), + (int) syntaxViolation.line(), + (int) syntaxViolation.column() ); + case final InvalidLexicalValueViolation lexicalValueViolation -> + new TurtleDocumentDiagnostic( + lexicalValueViolation.message(), + classifyViolation( violation ), + lexicalValueViolation.sourceLocation().map( URI::toString ).orElseThrow(), + lexicalValueViolation.line(), + lexicalValueViolation.column(), + lexicalValueViolation.line(), + lexicalValueViolation.column() ); + default -> new TurtleBaseDiagnostic( + violation.message(), + classifyViolation( violation ) ); + }; + } } diff --git a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/aspect/service/AspectValidationCoordinator.java b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/aspect/service/AspectValidationCoordinator.java index 5b8712ef6..6fabae8bf 100644 --- a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/aspect/service/AspectValidationCoordinator.java +++ b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/aspect/service/AspectValidationCoordinator.java @@ -13,7 +13,6 @@ package org.eclipse.esmf.turtle.languageserver.aspect.service; -import java.util.List; import java.util.Map; import java.util.concurrent.CancellationException; import java.util.concurrent.CompletableFuture; @@ -23,9 +22,9 @@ import java.util.concurrent.atomic.AtomicLong; import java.util.function.BiConsumer; -import org.eclipse.esmf.turtle.languageserver.aspect.model.AspectValidationError; -import org.eclipse.esmf.turtle.languageserver.aspect.model.AspectValidationErrorType; -import org.eclipse.esmf.turtle.languageserver.aspect.model.AspectValidationResult; +import org.eclipse.esmf.turtle.languageserver.diagnostic.DiagnosticReport; +import org.eclipse.esmf.turtle.languageserver.diagnostic.TurtleDiagnostic; +import org.eclipse.esmf.turtle.languageserver.diagnostic.TurtleDiagnosticsService; import org.eclipse.esmf.turtle.languageserver.lsp.text.Document; import org.slf4j.Logger; @@ -33,63 +32,61 @@ public class AspectValidationCoordinator implements AutoCloseable { private static final Logger LOG = LoggerFactory.getLogger( AspectValidationCoordinator.class ); - private final AspectModelValidationService validationService; + private final TurtleDiagnosticsService validationService; private final ExecutorService executorService; - private final Map> inFlight = new ConcurrentHashMap<>(); - private final Map generations = new ConcurrentHashMap<>(); + private final Map> inFlight = new ConcurrentHashMap<>(); + private final Map generations = new ConcurrentHashMap<>(); - public AspectValidationCoordinator( final AspectModelValidationService validationService ) { + public AspectValidationCoordinator( final TurtleDiagnosticsService validationService ) { this( validationService, Executors.newSingleThreadExecutor( Thread.ofPlatform().name( "aspect-validation-", 0 ).factory() ) ); } - AspectValidationCoordinator( final AspectModelValidationService validationService, final ExecutorService executorService ) { + AspectValidationCoordinator( final TurtleDiagnosticsService validationService, final ExecutorService executorService ) { this.validationService = validationService; this.executorService = executorService; } - public long nextGeneration( final String uri ) { - return generations.computeIfAbsent( uri, ignored -> new AtomicLong() ).incrementAndGet(); + public long nextGeneration( final Document document ) { + return generations.computeIfAbsent( document, ignored -> new AtomicLong() ).incrementAndGet(); } - public long currentGeneration( final String uri ) { - final AtomicLong generation = generations.get( uri ); + public long currentGeneration( final Document document ) { + final AtomicLong generation = generations.get( document ); return generation != null ? generation.get() : 0L; } - public void cancel( final String uri ) { - final CompletableFuture previous = inFlight.remove( uri ); + public void cancel( final Document document ) { + final CompletableFuture previous = inFlight.remove( document ); if ( previous != null ) { - LOG.debug( "[cancel] cancelling previous aspect validation for {}", uri ); + LOG.debug( "[cancel] cancelling previous aspect validation for {}", document.getUri() ); previous.cancel( true ); } } - public void submit( final Document document, final long generation, final BiConsumer callback ) { - final String uri = document.getUri(); - cancel( uri ); - final CompletableFuture future = CompletableFuture.supplyAsync( - () -> validationService.validate( document ), + public void submit( final Document document, final long generation, final BiConsumer callback ) { + cancel( document ); + final CompletableFuture future = CompletableFuture.supplyAsync( + () -> validationService.check( document ), executorService ); - inFlight.put( uri, future ); + inFlight.put( document, future ); future.whenComplete( ( result, throwable ) -> { - inFlight.remove( uri, future ); + inFlight.remove( document, future ); if ( throwable instanceof CancellationException || future.isCancelled() ) { - LOG.debug( "[cancel] aspect validation cancelled for {}", uri ); + LOG.debug( "[cancel] aspect validation cancelled for {}", document.getUri() ); return; } if ( throwable != null ) { - LOG.error( "[publish diagnostics] aspect validation failed for {}", uri, throwable ); - callback.accept( generation, new AspectValidationResult( false, throwable.getMessage(), List.of(), - new AspectValidationError( AspectValidationErrorType.PROCESSING, throwable.getMessage() ) ) ); + LOG.error( "[publish diagnostics] aspect validation failed for {}", document.getUri(), throwable ); + callback.accept( generation, new DiagnosticReport( throwable.getMessage(), TurtleDiagnostic.TurtleCode.E0002 ) ); return; } callback.accept( generation, result ); } ); } - public AspectValidationResult validateSync( final Document document ) { - return validationService.validate( document ); + public DiagnosticReport validateSync( final Document document ) { + return validationService.check( document ); } @Override diff --git a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/aspect/service/DefaultAspectModelValidationService.java b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/aspect/service/DefaultAspectModelValidationService.java deleted file mode 100644 index 5301920a3..000000000 --- a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/aspect/service/DefaultAspectModelValidationService.java +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright (c) 2026 Robert Bosch Manufacturing Solutions GmbH - * - * See the AUTHORS file(s) distributed with this work for additional - * information regarding authorship. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * SPDX-License-Identifier: MPL-2.0 - */ - -package org.eclipse.esmf.turtle.languageserver.aspect.service; - -import java.io.InputStream; -import java.net.URI; -import java.util.List; -import java.util.Optional; - -import org.eclipse.esmf.aspectmodel.loader.AspectModelLoader; -import org.eclipse.esmf.aspectmodel.shacl.violation.Violation; -import org.eclipse.esmf.aspectmodel.validation.InvalidLexicalValueViolation; -import org.eclipse.esmf.aspectmodel.validation.InvalidSyntaxViolation; -import org.eclipse.esmf.aspectmodel.validation.ProcessingViolation; -import org.eclipse.esmf.aspectmodel.validation.services.AspectModelValidator; -import org.eclipse.esmf.aspectmodel.validation.services.DetailedViolationFormatter; -import org.eclipse.esmf.turtle.languageserver.aspect.model.AspectValidationError; -import org.eclipse.esmf.turtle.languageserver.aspect.model.AspectValidationErrorType; -import org.eclipse.esmf.turtle.languageserver.aspect.model.AspectValidationResult; -import org.eclipse.esmf.turtle.languageserver.aspect.model.AspectViolationInfo; -import org.eclipse.esmf.turtle.languageserver.lsp.text.Document; - -import org.jspecify.annotations.Nullable; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class DefaultAspectModelValidationService implements AspectModelValidationService { - private static final Logger LOG = LoggerFactory.getLogger( DefaultAspectModelValidationService.class ); - - private final AspectModelLoader loader; - private final AspectModelValidator validator; - - public DefaultAspectModelValidationService() { - this( new AspectModelLoader(), new AspectModelValidator() ); - } - - DefaultAspectModelValidationService( final AspectModelLoader loader, final AspectModelValidator validator ) { - this.loader = loader; - this.validator = validator; - } - - @Override - public AspectValidationResult validate( final Document document ) { - try ( final InputStream inputStream = document.getInputStream() ) { - LOG.debug( "[load] loading aspect model from {}", document.getUri() ); - final List violations = - validator.validateModel( () -> loader.load( inputStream, URI.create( document.getUri() ) ) ); - LOG.debug( "[validate] validation finished for {} with {} violation(s)", document.getUri(), violations.size() ); - final String report = new DetailedViolationFormatter().apply( violations ); - final AspectValidationError error = classifyError( violations ); - return new AspectValidationResult( violations.isEmpty(), report, violations.stream().map( this::toViolationInfo ).toList(), - error ); - } catch ( final Exception exception ) { - LOG.error( "[validate] unexpected runtime failure for {}", document.getUri(), exception ); - return failedResult( AspectValidationErrorType.PROCESSING, exception.getMessage() ); - } - } - - private AspectValidationResult failedResult( final AspectValidationErrorType type, final String message ) { - return new AspectValidationResult( false, message, List.of(), new AspectValidationError( type, message ) ); - } - - private @Nullable AspectValidationError classifyError( final List violations ) { - final Optional firstFailure = violations.stream() - .filter( violation -> violation instanceof InvalidSyntaxViolation || violation instanceof InvalidLexicalValueViolation - || violation instanceof ProcessingViolation ) - .findFirst(); - - if ( firstFailure.isEmpty() ) { - return null; - } - - final Violation violation = firstFailure.get(); - if ( violation instanceof final InvalidSyntaxViolation syntaxViolation ) { - return new AspectValidationError( AspectValidationErrorType.PARSE, syntaxViolation.message() ); - } - if ( violation instanceof final InvalidLexicalValueViolation lexicalValueViolation ) { - return new AspectValidationError( AspectValidationErrorType.PARSE, lexicalValueViolation.message() ); - } - - final String message = violation.message(); - final AspectValidationErrorType type = message != null && message.toLowerCase().contains( "resolve" ) - ? AspectValidationErrorType.RESOLVE - : AspectValidationErrorType.PROCESSING; - return new AspectValidationError( type, message ); - } - - private AspectViolationInfo toViolationInfo( final Violation violation ) { - return switch ( violation ) { - case final InvalidSyntaxViolation syntaxViolation -> - new AspectViolationInfo( - syntaxViolation.errorCode(), - syntaxViolation.message(), - syntaxViolation.sourceLocation().orElse( null ), - syntaxViolation.line(), - syntaxViolation.column() ); - case final InvalidLexicalValueViolation lexicalValueViolation -> - new AspectViolationInfo( - lexicalValueViolation.errorCode(), - lexicalValueViolation.message(), - lexicalValueViolation.sourceLocation().orElse( null ), - (long) lexicalValueViolation.line(), - (long) lexicalValueViolation.column() ); - default -> new AspectViolationInfo( - violation.errorCode(), - violation.message(), - violation.sourceLocation().orElse( null ), - null, - null - ); - }; - } -} diff --git a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/diagnostic/DiagnosticReport.java b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/diagnostic/DiagnosticReport.java new file mode 100644 index 000000000..dbc7a5dc1 --- /dev/null +++ b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/diagnostic/DiagnosticReport.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2026 Robert Bosch Manufacturing Solutions GmbH + * + * See the AUTHORS file(s) distributed with this work for additional + * information regarding authorship. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * SPDX-License-Identifier: MPL-2.0 + */ + +package org.eclipse.esmf.turtle.languageserver.diagnostic; + +import java.util.List; + +public record DiagnosticReport( + List diagnostics +) { + public DiagnosticReport( final TurtleDiagnostic diagnostic ) { + this( List.of( diagnostic ) ); + } + + /** + * Convenience constructor to create are report for one {@link TurtleBaseDiagnostic} + * + * @param message the message + * @param code the code + */ + public DiagnosticReport( final String message, final TurtleDiagnostic.TurtleCode code ) { + this( new TurtleBaseDiagnostic( message, code ) ); + } +} diff --git a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/diagnostic/TurtleBaseDiagnostic.java b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/diagnostic/TurtleBaseDiagnostic.java new file mode 100644 index 000000000..c5094842b --- /dev/null +++ b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/diagnostic/TurtleBaseDiagnostic.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2026 Robert Bosch Manufacturing Solutions GmbH + * + * See the AUTHORS file(s) distributed with this work for additional + * information regarding authorship. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * SPDX-License-Identifier: MPL-2.0 + */ + +package org.eclipse.esmf.turtle.languageserver.diagnostic; + +public class TurtleBaseDiagnostic implements TurtleDiagnostic { + private final String message; + private final Code code; + + public TurtleBaseDiagnostic( final String message, final Code code ) { + this.message = message; + this.code = code; + } + + @Override + public String message() { + return message; + } + + @Override + public Code code() { + return code; + } +} diff --git a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/diagnostic/TurtleDiagnostic.java b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/diagnostic/TurtleDiagnostic.java new file mode 100644 index 000000000..459db8725 --- /dev/null +++ b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/diagnostic/TurtleDiagnostic.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2026 Robert Bosch Manufacturing Solutions GmbH + * + * See the AUTHORS file(s) distributed with this work for additional + * information regarding authorship. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * SPDX-License-Identifier: MPL-2.0 + */ + +package org.eclipse.esmf.turtle.languageserver.diagnostic; + +public interface TurtleDiagnostic { + Code code(); + + String message(); + + default boolean hasLocation() { + return false; + } + + interface Code { + String code(); + + String description(); + } + + enum TurtleCode implements Code { + E0000( "No more info available" ), + E0001( "Could not load document" ), + E0002( "Document validation failed" ), + E0003( "Syntax error" ); + + private final String description; + + TurtleCode( final String description ) { + this.description = description; + } + + @Override + public String code() { + return name(); + } + + @Override + public String description() { + return description; + } + } +} diff --git a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/aspect/model/AspectValidationErrorType.java b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/diagnostic/TurtleDiagnosticsService.java similarity index 66% rename from core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/aspect/model/AspectValidationErrorType.java rename to core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/diagnostic/TurtleDiagnosticsService.java index 1ccd3e90d..8bdd66b34 100644 --- a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/aspect/model/AspectValidationErrorType.java +++ b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/diagnostic/TurtleDiagnosticsService.java @@ -11,11 +11,10 @@ * SPDX-License-Identifier: MPL-2.0 */ -package org.eclipse.esmf.turtle.languageserver.aspect.model; +package org.eclipse.esmf.turtle.languageserver.diagnostic; -public enum AspectValidationErrorType { - LOAD, - PARSE, - RESOLVE, - PROCESSING +import org.eclipse.esmf.turtle.languageserver.lsp.text.Document; + +public interface TurtleDiagnosticsService { + DiagnosticReport check( Document document ); } diff --git a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/diagnostic/TurtleDocumentDiagnostic.java b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/diagnostic/TurtleDocumentDiagnostic.java new file mode 100644 index 000000000..0f5d584e7 --- /dev/null +++ b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/diagnostic/TurtleDocumentDiagnostic.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2026 Robert Bosch Manufacturing Solutions GmbH + * + * See the AUTHORS file(s) distributed with this work for additional + * information regarding authorship. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * SPDX-License-Identifier: MPL-2.0 + */ + +package org.eclipse.esmf.turtle.languageserver.diagnostic; + +public class TurtleDocumentDiagnostic extends TurtleBaseDiagnostic { + private final String sourceLocation; + private final int fromLine; + private final int fromColumn; + private final int toLine; + private final int toColumn; + + public TurtleDocumentDiagnostic( final String message, final Code code, final String sourceLocation, final int fromLine, + final int fromColumn, final int toLine, final int toColumn ) { + super( message, code ); + this.sourceLocation = sourceLocation; + this.fromLine = fromLine; + this.fromColumn = fromColumn; + this.toLine = toLine; + this.toColumn = toColumn; + } + + public String sourceLocation() { + return sourceLocation; + } + + public int fromLine() { + return fromLine; + } + + public int fromColumn() { + return fromColumn; + } + + public int toLine() { + return toLine; + } + + public int toColumn() { + return toColumn; + } + + @Override + public boolean hasLocation() { + return true; + } +} diff --git a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/AspectDiagnosticsWorkflow.java b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/AspectDiagnosticsWorkflow.java index 3dce10d86..7a90118f6 100644 --- a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/AspectDiagnosticsWorkflow.java +++ b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/AspectDiagnosticsWorkflow.java @@ -13,7 +13,11 @@ package org.eclipse.esmf.turtle.languageserver.lsp.text; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + import org.eclipse.esmf.turtle.languageserver.aspect.service.AspectValidationCoordinator; +import org.eclipse.esmf.turtle.languageserver.diagnostic.DiagnosticReport; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -21,50 +25,37 @@ public class AspectDiagnosticsWorkflow { private static final Logger LOG = LoggerFactory.getLogger( AspectDiagnosticsWorkflow.class ); private final AspectValidationCoordinator aspectValidationCoordinator; - private final DocumentDiagnosticsService diagnosticsService; private final TextDocumentClientNotifier clientNotifier; - private final DocumentStore documentStore; + private final Map diagnostics = new ConcurrentHashMap<>(); public AspectDiagnosticsWorkflow( final AspectValidationCoordinator aspectValidationCoordinator, - final DocumentDiagnosticsService diagnosticsService, - final TextDocumentClientNotifier clientNotifier, final DocumentStore documentStore ) { + final TextDocumentClientNotifier clientNotifier ) { this.aspectValidationCoordinator = aspectValidationCoordinator; - this.diagnosticsService = diagnosticsService; this.clientNotifier = clientNotifier; - this.documentStore = documentStore; } - public void onDocumentChanged( final String uri ) { - aspectValidationCoordinator.cancel( uri ); - diagnosticsService.clearAspect( uri ); + public void onDocumentChanged( final Document document ) { + aspectValidationCoordinator.cancel( document ); + diagnostics.remove( document ); } - public void onDocumentClosed( final String uri ) { - aspectValidationCoordinator.cancel( uri ); - diagnosticsService.clearAll( uri ); + public void onDocumentClosed( final Document document ) { + aspectValidationCoordinator.cancel( document ); + diagnostics.clear(); } - public void onDocumentSaved( final String uri ) { - final Document document = documentStore.get( uri ); - if ( document == null ) { - LOG.info( "[scheduleAspectValidation] unsupported uri={}, skipping aspect validation", uri ); - diagnosticsService.clearAspect( uri ); - clientNotifier.publishCombinedDiagnostics( uri ); - return; - } - - final long generation = aspectValidationCoordinator.nextGeneration( uri ); + public void onDocumentSaved( final Document document ) { + final long generation = aspectValidationCoordinator.nextGeneration( document ); aspectValidationCoordinator.submit( document, generation, ( completedGeneration, result ) -> { - final long currentGeneration = aspectValidationCoordinator.currentGeneration( uri ); + final long currentGeneration = aspectValidationCoordinator.currentGeneration( document ); if ( completedGeneration != currentGeneration ) { - LOG.debug( "[publish diagnostics] ignoring stale aspect diagnostics for uri={}, generation={}, current={}", uri, + LOG.debug( "[publish diagnostics] ignoring stale aspect diagnostics for uri={}, generation={}, current={}", document.getUri(), completedGeneration, currentGeneration ); return; } - - diagnosticsService.updateAspect( uri, result ); - clientNotifier.publishCombinedDiagnostics( uri ); + diagnostics.put( document, result ); + clientNotifier.publishDiagnostics( document, result ); } ); } } diff --git a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/Document.java b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/Document.java index fd208ec82..f996b3cdc 100644 --- a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/Document.java +++ b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/Document.java @@ -47,6 +47,12 @@ public int getIndex( final int targetLine, final int targetColumn ) { return content.getIndex( targetLine, targetColumn ); } + public String subSequence( final int fromLine, final int fromColumn, final int toLine, final int toColumn ) { + final int fromIndex = getIndex( fromLine, fromColumn ); + final int toIndex = getIndex( toLine, toColumn ); + return content.subSequence( fromIndex, toIndex ).toString(); + } + public void update( final Range range, final String newContent ) { final Position start = range.getStart(); final Position end = range.getEnd(); diff --git a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/DocumentAspectValidationService.java b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/DocumentAspectValidationService.java index fb06e4a45..8d94a4ad1 100644 --- a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/DocumentAspectValidationService.java +++ b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/DocumentAspectValidationService.java @@ -13,32 +13,23 @@ package org.eclipse.esmf.turtle.languageserver.lsp.text; -import java.util.List; - -import org.eclipse.esmf.turtle.languageserver.aspect.model.AspectValidationError; -import org.eclipse.esmf.turtle.languageserver.aspect.model.AspectValidationErrorType; -import org.eclipse.esmf.turtle.languageserver.aspect.model.AspectValidationResult; import org.eclipse.esmf.turtle.languageserver.aspect.service.AspectValidationCoordinator; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import org.eclipse.esmf.turtle.languageserver.diagnostic.DiagnosticReport; +import org.eclipse.esmf.turtle.languageserver.diagnostic.TurtleBaseDiagnostic; +import org.eclipse.esmf.turtle.languageserver.diagnostic.TurtleDiagnostic; public class DocumentAspectValidationService { - private static final Logger LOG = LoggerFactory.getLogger( DocumentAspectValidationService.class ); private final AspectValidationCoordinator aspectValidationCoordinator; public DocumentAspectValidationService( final AspectValidationCoordinator aspectValidationCoordinator ) { this.aspectValidationCoordinator = aspectValidationCoordinator; } - public AspectValidationResult validateDocument( final String uri, final Document document ) { + public DiagnosticReport validateDocument( final String uri, final Document document ) { if ( document == null ) { - return failedValidation( AspectValidationErrorType.LOAD, "Document is not available in memory: " + uri ); + return new DiagnosticReport( + new TurtleBaseDiagnostic( "Document is not available in memory: " + uri, TurtleDiagnostic.TurtleCode.E0001 ) ); } return aspectValidationCoordinator.validateSync( document ); } - - private AspectValidationResult failedValidation( final AspectValidationErrorType type, final String message ) { - return new AspectValidationResult( false, message, List.of(), new AspectValidationError( type, message ) ); - } } diff --git a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/DocumentDiagnosticsService.java b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/DocumentDiagnosticsService.java deleted file mode 100644 index 574bf440c..000000000 --- a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/DocumentDiagnosticsService.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (c) 2026 Robert Bosch Manufacturing Solutions GmbH - * - * See the AUTHORS file(s) distributed with this work for additional - * information regarding authorship. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * SPDX-License-Identifier: MPL-2.0 - */ - -package org.eclipse.esmf.turtle.languageserver.lsp.text; - -import java.util.List; - -import org.eclipse.lsp4j.Diagnostic; - -import org.eclipse.esmf.turtle.languageserver.aspect.diagnostic.AspectDiagnosticMapper; -import org.eclipse.esmf.turtle.languageserver.aspect.model.AspectValidationResult; - -public class DocumentDiagnosticsService { - private final TurtleSyntaxValidationService syntaxValidationService; - private final AspectDiagnosticMapper aspectDiagnosticMapper; - private final DocumentDiagnosticsStore diagnosticsStore; - - public DocumentDiagnosticsService() { - this( new TurtleSyntaxValidationService(), new AspectDiagnosticMapper(), new DocumentDiagnosticsStore() ); - } - - DocumentDiagnosticsService( - final TurtleSyntaxValidationService syntaxValidationService, - final AspectDiagnosticMapper aspectDiagnosticMapper, - final DocumentDiagnosticsStore diagnosticsStore ) { - this.syntaxValidationService = syntaxValidationService; - this.aspectDiagnosticMapper = aspectDiagnosticMapper; - this.diagnosticsStore = diagnosticsStore; - } - - public void updateSyntax( final Document document ) { - diagnosticsStore.putSyntax( document.getUri(), syntaxValidationService.validate( document ) ); - } - - public void updateAspect( final String uri, final AspectValidationResult result ) { - diagnosticsStore.putAspect( uri, aspectDiagnosticMapper.toDiagnostics( uri, result ) ); - } - - public void clearAspect( final String uri ) { - diagnosticsStore.clearAspect( uri ); - } - - public void clearAll( final String uri ) { - diagnosticsStore.clear( uri ); - } - - public List getCombined( final String uri ) { - return diagnosticsStore.getCombined( uri ); - } -} diff --git a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/DocumentDiagnosticsStore.java b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/DocumentDiagnosticsStore.java deleted file mode 100644 index ee673441c..000000000 --- a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/DocumentDiagnosticsStore.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (c) 2026 Robert Bosch Manufacturing Solutions GmbH - * - * See the AUTHORS file(s) distributed with this work for additional - * information regarding authorship. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * SPDX-License-Identifier: MPL-2.0 - */ - -package org.eclipse.esmf.turtle.languageserver.lsp.text; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -import org.eclipse.lsp4j.Diagnostic; - -public class DocumentDiagnosticsStore { - private final Map> syntaxDiagnostics = new ConcurrentHashMap<>(); - private final Map> aspectDiagnostics = new ConcurrentHashMap<>(); - - public void putSyntax( final String uri, final List diagnostics ) { - syntaxDiagnostics.put( uri, List.copyOf( diagnostics ) ); - } - - public void putAspect( final String uri, final List diagnostics ) { - aspectDiagnostics.put( uri, List.copyOf( diagnostics ) ); - } - - public void clearAspect( final String uri ) { - aspectDiagnostics.remove( uri ); - } - - public void clear( final String uri ) { - syntaxDiagnostics.remove( uri ); - aspectDiagnostics.remove( uri ); - } - - public List getCombined( final String uri ) { - final List diagnostics = new ArrayList<>(); - diagnostics.addAll( syntaxDiagnostics.getOrDefault( uri, List.of() ) ); - diagnostics.addAll( aspectDiagnostics.getOrDefault( uri, List.of() ) ); - return diagnostics; - } -} diff --git a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/DocumentStore.java b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/DocumentStore.java deleted file mode 100644 index 8c32704e8..000000000 --- a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/DocumentStore.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (c) 2026 Robert Bosch Manufacturing Solutions GmbH - * - * See the AUTHORS file(s) distributed with this work for additional - * information regarding authorship. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * SPDX-License-Identifier: MPL-2.0 - */ - -package org.eclipse.esmf.turtle.languageserver.lsp.text; - -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -public class DocumentStore { - private final Map documents = new ConcurrentHashMap<>(); - - public void put( final Document document ) { - documents.put( document.getUri(), document ); - } - - public Document get( final String uri ) { - return documents.get( uri ); - } - - public void remove( final String uri ) { - documents.remove( uri ); - } -} diff --git a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TurtleSyntaxValidationService.java b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/JenaTurtleSyntaxValidationService.java similarity index 52% rename from core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TurtleSyntaxValidationService.java rename to core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/JenaTurtleSyntaxValidationService.java index 2b7bfd635..9d05c6a89 100644 --- a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TurtleSyntaxValidationService.java +++ b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/JenaTurtleSyntaxValidationService.java @@ -13,7 +13,6 @@ package org.eclipse.esmf.turtle.languageserver.lsp.text; -import java.io.IOException; import java.io.StringReader; import java.util.ArrayList; import java.util.List; @@ -24,19 +23,21 @@ import org.apache.jena.riot.RiotParseException; import org.apache.jena.riot.system.ErrorHandlerFactory; import org.apache.jena.riot.system.StreamRDFLib; -import org.eclipse.lsp4j.Diagnostic; -import org.eclipse.lsp4j.DiagnosticSeverity; -import org.eclipse.lsp4j.Position; -import org.eclipse.lsp4j.Range; + +import org.eclipse.esmf.turtle.languageserver.diagnostic.DiagnosticReport; +import org.eclipse.esmf.turtle.languageserver.diagnostic.TurtleDiagnostic; +import org.eclipse.esmf.turtle.languageserver.diagnostic.TurtleDiagnosticsService; +import org.eclipse.esmf.turtle.languageserver.diagnostic.TurtleDocumentDiagnostic; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class TurtleSyntaxValidationService { - private static final Logger LOG = LoggerFactory.getLogger( TurtleSyntaxValidationService.class ); - private static final String SYNTAX_SOURCE = "lsp-server.syntax"; +public class JenaTurtleSyntaxValidationService implements TurtleDiagnosticsService { + private static final Logger LOG = LoggerFactory.getLogger( JenaTurtleSyntaxValidationService.class ); - public List validate( final Document document ) { - final List diagnostics = new ArrayList<>(); + @Override + public DiagnosticReport check( final Document document ) { + final List diagnostics = new ArrayList<>(); try { RDFParser.create() @@ -47,25 +48,15 @@ public List validate( final Document document ) { LOG.debug( "[validate] turtle parsing successful" ); } catch ( final RiotParseException exception ) { LOG.warn( "[validate] parse error at line={}, col={}: {}", exception.getLine(), exception.getCol(), exception.getMessage() ); - diagnostics.add( toDiagnostic( exception.getMessage(), exception.getLine(), exception.getCol() ) ); + diagnostics.add( new TurtleDocumentDiagnostic( exception.getMessage(), TurtleDiagnostic.TurtleCode.E0003, document.getUri(), + (int) exception.getLine(), (int) exception.getCol(), (int) exception.getLine(), (int) exception.getCol() ) ); } catch ( final RiotException exception ) { - LOG.warn( "[validate] rdf error: {}", exception.getMessage() ); - diagnostics.add( toDiagnostic( exception.getMessage(), 1, 1 ) ); + LOG.warn( "[validate] RDF error: {}", exception.getMessage() ); + diagnostics.add( new TurtleDocumentDiagnostic( exception.getMessage(), TurtleDiagnostic.TurtleCode.E0003, document.getUri(), + 1, 1, 1, 1 ) ); } LOG.debug( "[validate] found {} diagnostic(s)", diagnostics.size() ); - return diagnostics; - } - - private Diagnostic toDiagnostic( final String message, final long line, final long column ) { - final int safeLine = (int) Math.max( 0, line - 1 ); - final int safeColumn = (int) Math.max( 0, column - 1 ); - - final Diagnostic diagnostic = new Diagnostic(); - diagnostic.setSource( SYNTAX_SOURCE ); - diagnostic.setSeverity( DiagnosticSeverity.Error ); - diagnostic.setMessage( message != null ? message : "Invalid Turtle syntax" ); - diagnostic.setRange( new Range( new Position( safeLine, safeColumn ), new Position( safeLine, safeColumn + 1 ) ) ); - return diagnostic; + return new DiagnosticReport( diagnostics ); } } diff --git a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TextDocumentClientNotifier.java b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TextDocumentClientNotifier.java index f63a43c6c..62d539927 100644 --- a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TextDocumentClientNotifier.java +++ b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TextDocumentClientNotifier.java @@ -15,7 +15,9 @@ import java.util.List; -import org.eclipse.lsp4j.Diagnostic; +import org.eclipse.esmf.turtle.languageserver.aspect.diagnostic.AspectDiagnosticMapper; +import org.eclipse.esmf.turtle.languageserver.diagnostic.DiagnosticReport; + import org.eclipse.lsp4j.PublishDiagnosticsParams; import org.eclipse.lsp4j.services.LanguageClient; import org.slf4j.Logger; @@ -24,26 +26,26 @@ public class TextDocumentClientNotifier { private static final Logger LOG = LoggerFactory.getLogger( TextDocumentClientNotifier.class ); - private final DocumentDiagnosticsService diagnosticsService; + private final AspectDiagnosticMapper diagnosticMapper; private LanguageClient client; - public TextDocumentClientNotifier( final DocumentDiagnosticsService diagnosticsService ) { - this.diagnosticsService = diagnosticsService; + public TextDocumentClientNotifier( final AspectDiagnosticMapper diagnosticMapper ) { + this.diagnosticMapper = diagnosticMapper; } public void connect( final LanguageClient client ) { this.client = client; } - public void publishCombinedDiagnostics( final String uri ) { + public void publishDiagnostics( final Document document, final DiagnosticReport diagnostics ) { if ( client == null ) { - LOG.warn( "[publishDiagnostics] client is null, skipping for uri={}", uri ); + LOG.warn( "[publishDiagnostics] client is null, skipping for uri={}", document.getUri() ); return; } - final List diagnostics = diagnosticsService.getCombined( uri ); - LOG.debug( "[publish diagnostics] publishing {} diagnostic(s) for uri={}", diagnostics.size(), uri ); - client.publishDiagnostics( new PublishDiagnosticsParams( uri, diagnostics ) ); + LOG.debug( "[publish diagnostics] publishing {} diagnostic(s) for uri={}", diagnostics.diagnostics().size(), document.getUri() ); + client.publishDiagnostics( + new PublishDiagnosticsParams( document.getUri(), diagnosticMapper.toDiagnostics( document, diagnostics ) ) ); } public void publishEmptyDiagnostics( final String uri ) { diff --git a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TurtleParserService.java b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TreeSitterTurtleSyntaxValidationService.java similarity index 75% rename from core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TurtleParserService.java rename to core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TreeSitterTurtleSyntaxValidationService.java index 786b7d90c..d0c6bf277 100644 --- a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TurtleParserService.java +++ b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TreeSitterTurtleSyntaxValidationService.java @@ -14,11 +14,17 @@ package org.eclipse.esmf.turtle.languageserver.lsp.text; import java.nio.charset.StandardCharsets; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.WeakHashMap; import org.eclipse.esmf.treesitterturtle.TreeSitterTurtle; +import org.eclipse.esmf.turtle.languageserver.diagnostic.DiagnosticReport; +import org.eclipse.esmf.turtle.languageserver.diagnostic.TurtleDiagnostic; +import org.eclipse.esmf.turtle.languageserver.diagnostic.TurtleDiagnosticsService; +import org.eclipse.esmf.turtle.languageserver.diagnostic.TurtleDocumentDiagnostic; import org.eclipse.lsp4j.Position; import org.eclipse.lsp4j.Range; @@ -26,6 +32,7 @@ import org.jspecify.annotations.Nullable; import org.treesitter.TSInputEdit; import org.treesitter.TSLanguage; +import org.treesitter.TSNode; import org.treesitter.TSParser; import org.treesitter.TSPoint; import org.treesitter.TSTree; @@ -34,12 +41,12 @@ * Service for parsing Turtle documents using Tree-sitter and maintaining their syntax trees. * Supports incremental parsing for efficient updates when documents change. */ -public class TurtleParserService { +public class TreeSitterTurtleSyntaxValidationService implements TurtleDiagnosticsService { private final TSParser parser; private final Map syntaxTrees = new HashMap<>(); private final Map previousDocumentStates = new WeakHashMap<>(); - public TurtleParserService() { + public TreeSitterTurtleSyntaxValidationService() { parser = new TSParser(); final TSLanguage turtle = new TreeSitterTurtle(); parser.setLanguage( turtle ); @@ -108,6 +115,10 @@ private TSPoint calculateNewEndPoint( final TSPoint startPoint, final String new } } + public void onOpen( final Document document ) { + syntaxTrees.put( document, parseDocument( document ) ); + } + public void onChange( final Document document, final TextDocumentContentChangeEvent changeEvent ) { final TSTree oldTree = syntaxTrees.get( document ); if ( oldTree == null ) { @@ -132,4 +143,25 @@ public void onChange( final Document document, final TextDocumentContentChangeEv syntaxTrees.put( document, newTree ); previousDocumentStates.put( document, document.getRope() ); } + + @Override + public DiagnosticReport check( final Document document ) { + final TSTree abstractSyntaxTree = getAbstractSyntaxTree( document ); + return new DiagnosticReport( checkNode( abstractSyntaxTree.getRootNode(), document.getUri() ) ); + } + + private List checkNode( final TSNode node, final String sourceLocation ) { + final List result = new ArrayList<>(); + if ( node.hasError() ) { + final TurtleDiagnostic diagnostic = new TurtleDocumentDiagnostic( "Syntax error: unexpected token '" + node.getType() + "'", + TurtleDiagnostic.TurtleCode.E0003, sourceLocation, + node.getStartPoint().getRow(), node.getStartPoint().getColumn(), + node.getEndPoint().getRow(), node.getEndPoint().getColumn() ); + result.add( diagnostic ); + } + for ( int i = 0; i < node.getChildCount(); i++ ) { + result.addAll( checkNode( node.getChild( i ), sourceLocation ) ); + } + return result; + } } diff --git a/core/esmf-tree-sitter-turtle/src/main/java/org/eclipse/esmf/treesitterturtle/TreeSitterUtil.java b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TreeSitterUtil.java similarity index 51% rename from core/esmf-tree-sitter-turtle/src/main/java/org/eclipse/esmf/treesitterturtle/TreeSitterUtil.java rename to core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TreeSitterUtil.java index 7a46f6f1f..adc93bc33 100644 --- a/core/esmf-tree-sitter-turtle/src/main/java/org/eclipse/esmf/treesitterturtle/TreeSitterUtil.java +++ b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TreeSitterUtil.java @@ -11,8 +11,9 @@ * SPDX-License-Identifier: MPL-2.0 */ -package org.eclipse.esmf.treesitterturtle; +package org.eclipse.esmf.turtle.languageserver.lsp.text; +import org.jspecify.annotations.Nullable; import org.treesitter.TSNode; import org.treesitter.TSTree; @@ -29,17 +30,39 @@ public static String print( final TSNode node ) { return builder.toString(); } - private static void print( final TSNode node, final StringBuilder builder, final int indentLevel ) { + public static String print( final TSTree tree, final Document document ) { + return print( tree.getRootNode(), document ); + } + + public static String print( final TSNode node, final Document document ) { + final StringBuilder builder = new StringBuilder(); + print( node, builder, 0, document ); + return builder.toString(); + } + + private static void print( final TSNode node, final StringBuilder builder, final int indentLevel, @Nullable final Document document ) { builder.repeat( " ", indentLevel ); builder.append( "- '" ); builder.append( node.getType() ); builder.append( "'" ); if ( node.hasError() ) { builder.append( " (ERROR)" ); + } else if ( document != null && node.getStartPoint().getRow() == node.getEndPoint().getRow() ) { + final String nodeContent = document.subSequence( node.getStartPoint().getRow(), node.getStartPoint().getColumn(), + node.getEndPoint().getRow(), node.getEndPoint().getColumn() ); + if ( !nodeContent.equals( node.getType() ) ) { + builder.append( " (" ); + builder.append( nodeContent ); + builder.append( ")" ); + } } builder.append( "\n" ); for ( int i = 0; i < node.getChildCount(); i++ ) { - print( node.getChild( i ), builder, indentLevel + 1 ); + print( node.getChild( i ), builder, indentLevel + 1, document ); } } + + private static void print( final TSNode node, final StringBuilder builder, final int indentLevel ) { + print( node, builder, indentLevel, null ); + } } diff --git a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TurtleSyntaxTree.java b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TurtleSyntaxTree.java new file mode 100644 index 000000000..8c5245862 --- /dev/null +++ b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TurtleSyntaxTree.java @@ -0,0 +1,364 @@ +/* + * Copyright (c) 2026 Robert Bosch Manufacturing Solutions GmbH + * + * See the AUTHORS file(s) distributed with this work for additional + * information regarding authorship. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * SPDX-License-Identifier: MPL-2.0 + */ + +package org.eclipse.esmf.turtle.languageserver.lsp.text; + +import java.util.List; +import java.util.Map; +import java.util.stream.Stream; + +import org.jspecify.annotations.Nullable; +import org.treesitter.TSNode; +import org.treesitter.TSTree; + +/** + *
+ * - 'document'
+ *   - 'directive' (@prefix ex:  .)
+ *     - 'prefix_id' (@prefix ex:  .)
+ *       - '@prefix'
+ *       - 'namespace' (ex:)
+ *         - 'pn_prefix' (ex)
+ *         - ':'
+ *       - 'iri_reference' ()
+ *         - '<'
+ *         - '>'
+ *       - '.'
+ *   - 'triple'
+ *     - 'subject' (ex:subject)
+ *       - 'prefixed_name' (ex:subject)
+ *         - 'namespace' (ex:)
+ *           - 'pn_prefix' (ex)
+ *           - ':'
+ *         - 'pn_local' (subject)
+ *     - 'property_list'
+ *       - 'property' (ex:predicate1 ex:object1)
+ *         - 'predicate' (ex:predicate1)
+ *           - 'prefixed_name' (ex:predicate1)
+ *             - 'namespace' (ex:)
+ *               - 'pn_prefix' (ex)
+ *               - ':'
+ *             - 'pn_local' (predicate1)
+ *         - 'object_list' (ex:object1)
+ *           - 'prefixed_name' (ex:object1)
+ *             - 'namespace' (ex:)
+ *               - 'pn_prefix' (ex)
+ *               - ':'
+ *             - 'pn_local' (object1)
+ *       - ';'
+ *       - 'property' (ex:predicate2 123)
+ *         - 'predicate' (ex:predicate2)
+ *           - 'prefixed_name' (ex:predicate2)
+ *             - 'namespace' (ex:)
+ *               - 'pn_prefix' (ex)
+ *               - ':'
+ *             - 'pn_local' (predicate2)
+ *         - 'object_list' (123)
+ *           - 'integer' (123)
+ *       - ';'
+ *       - 'property' (ex:predicate3 true)
+ *         - 'predicate' (ex:predicate3)
+ *           - 'prefixed_name' (ex:predicate3)
+ *             - 'namespace' (ex:)
+ *               - 'pn_prefix' (ex)
+ *               - ':'
+ *             - 'pn_local' (predicate3)
+ *         - 'object_list' (true)
+ *           - 'boolean_literal' (true)
+ *             - 'true'
+ *       - ';'
+ *       - 'property' (ex:predicate4 "some string")
+ *         - 'predicate' (ex:predicate4)
+ *           - 'prefixed_name' (ex:predicate4)
+ *             - 'namespace' (ex:)
+ *               - 'pn_prefix' (ex)
+ *               - ':'
+ *             - 'pn_local' (predicate4)
+ *         - 'object_list' ("some string")
+ *           - 'rdf_literal' ("some string")
+ *             - 'string' ("some string")
+ *               - '"'
+ *               - '"'
+ *       - ';'
+ *       - 'property' (ex:predicate5 "some langString"@en)
+ *         - 'predicate' (ex:predicate5)
+ *           - 'prefixed_name' (ex:predicate5)
+ *             - 'namespace' (ex:)
+ *               - 'pn_prefix' (ex)
+ *               - ':'
+ *             - 'pn_local' (predicate5)
+ *         - 'object_list' ("some langString"@en)
+ *           - 'rdf_literal' ("some langString"@en)
+ *             - 'string' ("some langString")
+ *               - '"'
+ *               - '"'
+ *             - 'lang_tag' (@en)
+ *       - ';'
+ *       - 'property' (ex:predicate6 "123"^^xsd:decimal)
+ *         - 'predicate' (ex:predicate6)
+ *           - 'prefixed_name' (ex:predicate6)
+ *             - 'namespace' (ex:)
+ *               - 'pn_prefix' (ex)
+ *               - ':'
+ *             - 'pn_local' (predicate6)
+ *         - 'object_list' ("123"^^xsd:decimal)
+ *           - 'rdf_literal' ("123"^^xsd:decimal)
+ *             - 'string' ("123")
+ *               - '"'
+ *               - '"'
+ *             - '^^'
+ *             - 'prefixed_name' (xsd:decimal)
+ *               - 'namespace' (xsd:)
+ *                 - 'pn_prefix' (xsd)
+ *                 - ':'
+ *               - 'pn_local' (decimal)
+ *       - ';'
+ *       - 'property' (ex:predicate7 )
+ *         - 'predicate' (ex:predicate7)
+ *           - 'prefixed_name' (ex:predicate7)
+ *             - 'namespace' (ex:)
+ *               - 'pn_prefix' (ex)
+ *               - ':'
+ *             - 'pn_local' (predicate7)
+ *         - 'object_list' ()
+ *           - 'iri_reference' ()
+ *             - '<'
+ *             - '>'
+ *     - '.'
+ *   - 'triple' ( a rdf:type .)
+ *     - 'subject' ()
+ *       - 'iri_reference' ()
+ *         - '<'
+ *         - '>'
+ *     - 'property_list' (a rdf:type)
+ *       - 'property' (a rdf:type)
+ *         - 'predicate' (a)
+ *           - 'a'
+ *         - 'object_list' (rdf:type)
+ *           - 'prefixed_name' (rdf:type)
+ *             - 'namespace' (rdf:)
+ *               - 'pn_prefix' (rdf)
+ *               - ':'
+ *             - 'pn_local' (type)
+ *     - '.'
+ * 
+ */ +public class TurtleSyntaxTree { + private final TSTree parserTree; + private final Document document; + + /** + * See rules in grammar.js + */ + private enum ParserType { + document, + graph, + comment, + triple, + directive, + prefix_id, + base, + sparql_base, + sparql_prefix, + property_list, + property, + object_list, + predicate, + subject, + blank_node_property_list, + collection, + string, + iri_reference, + integer, + decimal, + _double( "double" ), + rdf_literal, + boolean_literal, + prefixed_name, + namespace, + blank_node_label, + lang_tag, + anon, + pn_prefix, + pn_local; + + private final String type; + + ParserType() { + type = name().toLowerCase(); + } + + ParserType( final String type ) { + this.type = type; + } + + public static @Nullable ParserType fromString( final String type ) { + if ( type.equals( "double" ) ) { + return _double; + } + try { + return valueOf( type ); + } catch ( final IllegalArgumentException exception ) { + return null; + } + } + + public String getType() { + return type; + } + } + + public TurtleSyntaxTree( final TSTree parserTree, final Document document ) { + this.parserTree = parserTree; + this.document = document; + } + + public Map prefixes() { + return null; + } + + private static Stream children( final TSNode node ) { + final Stream.Builder builder = Stream.builder(); + for ( int i = 0; i < node.getChildCount(); i++ ) { + builder.add( node.getChild( 0 ) ); + } + return builder.build(); + } + + private static TurtleDocument parseRootNode( final TSNode rootNode ) { + return new DefaultTurtleDocument( children( rootNode ).map( TurtleSyntaxTree::parse ).toList() ); + } + + private static Node parse( final TSNode node ) { + return switch ( ParserType.fromString( node.getType() ) ) { + case directive -> parse( node.getChild( 0 ) ); + case prefix_id -> null; + case namespace -> null; + case pn_prefix -> null; + case document -> null; + case graph -> null; + case comment -> null; + case triple -> null; + case subject -> null; + case prefixed_name -> null; + case pn_local -> null; + case base -> null; + case sparql_base -> null; + case sparql_prefix -> null; + case property_list -> null; + case property -> null; + case predicate -> null; + case object_list -> null; + case integer -> null; + case boolean_literal -> null; + case rdf_literal -> null; + case blank_node_property_list -> null; + case collection -> null; + case string -> null; + case lang_tag -> null; + case iri_reference -> null; + case decimal -> null; + case _double -> null; + case blank_node_label -> null; + case anon -> null; + case null -> throw new UnsupportedOperationException(); + }; + } + + interface TurtleDocument { + List nodes(); + } + + public record DefaultTurtleDocument( + List nodes + ) implements TurtleDocument {} + + interface Node { + } + + interface Directive extends Node { + } + + interface Comment extends Node { + String comment(); + } + + interface PrefixDeclaration extends Directive { + String prefix(); + + String namespace(); + } + + public record DefaultPrefixDeclaration( + String prefix, String namespace + ) implements PrefixDeclaration {} + + interface RelativeOrAbsoluteIri extends Object { + } + + interface Iri extends RelativeOrAbsoluteIri { + String iri(); + } + + interface PrefixedName extends RelativeOrAbsoluteIri { + String prefix(); + + String localName(); + } + + interface Triple extends Node { + RelativeOrAbsoluteIri subject(); + + List properties(); + } + + interface PredicateDeclaration extends Node { + RelativeOrAbsoluteIri predicate(); + + List objects(); + } + + interface ObjectDeclaration extends Directive { + List objects(); + } + + interface Object { + } + + interface Literal extends Object { + String lexicalValue(); + } + + interface NumericLiteral extends Literal { + } + + interface BooleanLiteral extends Literal { + enum Value { + TRUE, FALSE + } + + Value value(); + } + + interface StringLiteral extends Literal { + } + + interface LangStringLiteral extends Literal { + String languageTag(); + } + + interface TypedLiteral extends Literal { + RelativeOrAbsoluteIri datatypeIri(); + } +} + diff --git a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TurtleTextDocumentService.java b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TurtleTextDocumentService.java index 38e76f54a..81989aeb8 100644 --- a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TurtleTextDocumentService.java +++ b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TurtleTextDocumentService.java @@ -13,13 +13,16 @@ package org.eclipse.esmf.turtle.languageserver.lsp.text; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.concurrent.CompletableFuture; -import org.eclipse.esmf.turtle.languageserver.aspect.model.AspectValidationResult; +import org.eclipse.esmf.turtle.languageserver.aspect.diagnostic.AspectDiagnosticMapper; import org.eclipse.esmf.turtle.languageserver.aspect.service.AspectModelValidationService; import org.eclipse.esmf.turtle.languageserver.aspect.service.AspectValidationCoordinator; -import org.eclipse.esmf.turtle.languageserver.aspect.service.DefaultAspectModelValidationService; +import org.eclipse.esmf.turtle.languageserver.diagnostic.DiagnosticReport; +import org.eclipse.esmf.turtle.languageserver.diagnostic.TurtleDiagnosticsService; import org.eclipse.esmf.turtle.languageserver.turtle.navigation.TurtlePrefixDefinitionService; import org.eclipse.lsp4j.DefinitionParams; @@ -38,44 +41,27 @@ public class TurtleTextDocumentService implements TextDocumentService { private static final Logger LOG = LoggerFactory.getLogger( TurtleTextDocumentService.class ); - private final DocumentStore documentStore; - private final DocumentDiagnosticsService diagnosticsService; + private final TextDocumentClientNotifier clientNotifier; private final TurtlePrefixDefinitionService prefixDefinitionService; - private final DocumentAspectValidationService documentValidationService; - private final AspectDiagnosticsWorkflow aspectDiagnosticsWorkflow; private final AspectValidationCoordinator aspectValidationCoordinator; - private final TurtleParserService turtleParserService; - - public TurtleTextDocumentService() { - this( new DefaultAspectModelValidationService() ); - } + private final TreeSitterTurtleSyntaxValidationService turtleParserService; + private final AspectDiagnosticsWorkflow aspectDiagnosticsWorkflow; + private final DocumentAspectValidationService documentValidationService; + private final TurtleDiagnosticsService syntaxValidationService; + private final Map documents = new HashMap<>(); - public TurtleTextDocumentService( final AspectModelValidationService aspectValidationService ) { - this( - new DocumentStore(), - new DocumentDiagnosticsService(), - new TurtlePrefixDefinitionService(), - new AspectValidationCoordinator( aspectValidationService ), - new TurtleParserService() - ); - } + // TODO determine and harmonize when to send which diagnostics - TurtleTextDocumentService( - final DocumentStore documentStore, - final DocumentDiagnosticsService diagnosticsService, - final TurtlePrefixDefinitionService prefixDefinitionService, - final AspectValidationCoordinator aspectValidationCoordinator, - final TurtleParserService turtleParserService ) { - this.documentStore = documentStore; - this.diagnosticsService = diagnosticsService; - this.prefixDefinitionService = prefixDefinitionService; - this.aspectValidationCoordinator = aspectValidationCoordinator; - clientNotifier = new TextDocumentClientNotifier( diagnosticsService ); + public TurtleTextDocumentService() { + clientNotifier = new TextDocumentClientNotifier( new AspectDiagnosticMapper() ); + prefixDefinitionService = new TurtlePrefixDefinitionService(); + aspectValidationCoordinator = new AspectValidationCoordinator( new AspectModelValidationService() ); + turtleParserService = new TreeSitterTurtleSyntaxValidationService(); + aspectDiagnosticsWorkflow = new AspectDiagnosticsWorkflow( aspectValidationCoordinator, clientNotifier ); documentValidationService = new DocumentAspectValidationService( aspectValidationCoordinator ); - aspectDiagnosticsWorkflow = - new AspectDiagnosticsWorkflow( aspectValidationCoordinator, diagnosticsService, clientNotifier, documentStore ); - this.turtleParserService = turtleParserService; + // syntaxValidationService = new JenaTurtleSyntaxValidationService(); + syntaxValidationService = turtleParserService; } public void connect( final LanguageClient client ) { @@ -86,8 +72,8 @@ public void shutdown() { aspectValidationCoordinator.close(); } - public AspectValidationResult validateDocument( final String uri ) { - return documentValidationService.validateDocument( uri, documentStore.get( uri ) ); + public DiagnosticReport validateDocument( final String uri ) { + return documentValidationService.validateDocument( uri, documents.get( uri ) ); } @Override @@ -96,48 +82,49 @@ public void didOpen( final DidOpenTextDocumentParams params ) { final String content = params.getTextDocument().getText(); LOG.info( "[didOpen] uri={}, contentLength={}", uri, content.length() ); final Document document = new Document( uri, content ); - documentStore.put( document ); - diagnosticsService.updateSyntax( document ); - clientNotifier.publishCombinedDiagnostics( uri ); + documents.put( uri, document ); + turtleParserService.onOpen( document ); + final DiagnosticReport report = syntaxValidationService.check( document ); + clientNotifier.publishDiagnostics( document, report ); } @Override public void didChange( final DidChangeTextDocumentParams params ) { final String uri = params.getTextDocument().getUri(); - final Document document = documentStore.get( params.getTextDocument().getUri() ); + final Document document = documents.get( params.getTextDocument().getUri() ); for ( final TextDocumentContentChangeEvent change : params.getContentChanges() ) { document.update( change.getRange(), change.getText() ); turtleParserService.onChange( document, change ); } LOG.debug( "[didChange] uri={}, changes={}", uri, params.getContentChanges().size() ); - diagnosticsService.updateSyntax( document ); - aspectDiagnosticsWorkflow.onDocumentChanged( uri ); - clientNotifier.publishCombinedDiagnostics( uri ); + final DiagnosticReport report = syntaxValidationService.check( document ); + clientNotifier.publishDiagnostics( document, report ); + aspectDiagnosticsWorkflow.onDocumentChanged( document ); } @Override public void didClose( final DidCloseTextDocumentParams params ) { final String uri = params.getTextDocument().getUri(); LOG.info( "[didClose] uri={}", uri ); - documentStore.remove( uri ); - aspectDiagnosticsWorkflow.onDocumentClosed( uri ); + final Document document = documents.get( uri ); + aspectDiagnosticsWorkflow.onDocumentClosed( document ); + documents.remove( uri ); clientNotifier.publishEmptyDiagnostics( uri ); } @Override public void didSave( final DidSaveTextDocumentParams params ) { final String uri = params.getTextDocument().getUri(); - final Document document = documentStore.get( uri ); + final Document document = documents.get( uri ); LOG.info( "[didSave] uri={}", uri ); - diagnosticsService.updateSyntax( document ); - clientNotifier.publishCombinedDiagnostics( uri ); - aspectDiagnosticsWorkflow.onDocumentSaved( uri ); + document.getRope().rebalance(); + aspectDiagnosticsWorkflow.onDocumentSaved( document ); } @Override public CompletableFuture, List>> definition( final DefinitionParams params ) { final String uri = params.getTextDocument().getUri(); - final Document document = documentStore.get( uri ); + final Document document = documents.get( uri ); if ( document == null ) { return CompletableFuture.completedFuture( Either.forLeft( List.of() ) ); } diff --git a/core/esmf-turtle-language-server/src/test/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TurtleParserServiceTest.java b/core/esmf-turtle-language-server/src/test/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TurtleParserServiceTest.java index 455dde00c..076f63375 100644 --- a/core/esmf-turtle-language-server/src/test/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TurtleParserServiceTest.java +++ b/core/esmf-turtle-language-server/src/test/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TurtleParserServiceTest.java @@ -15,8 +15,6 @@ import static org.assertj.core.api.Assertions.assertThat; -import org.eclipse.esmf.treesitterturtle.TreeSitterUtil; - import org.eclipse.lsp4j.Position; import org.eclipse.lsp4j.Range; import org.eclipse.lsp4j.TextDocumentContentChangeEvent; @@ -27,11 +25,11 @@ @SuppressWarnings( "HttpUrlsUsage" ) class TurtleParserServiceTest { - private TurtleParserService parserService; + private TreeSitterTurtleSyntaxValidationService parserService; @BeforeEach void setUp() { - parserService = new TurtleParserService(); + parserService = new TreeSitterTurtleSyntaxValidationService(); } @Test @@ -212,11 +210,38 @@ void testEditAcrossMultipleLines() { applyChange( document, pos( 3, 2 ), pos( 4, 14 ), replacement ); final TSTree tree = parserService.getAbstractSyntaxTree( document ); + System.out.println( TreeSitterUtil.print( tree, document ) ); assertThat( tree.getRootNode().hasError() ).isFalse(); assertThat( document.getContent() ).contains( "ex:newPredicate" ); assertThat( document.getContent() ).doesNotContain( "ex:predicate1" ); } + @Test + void testParseValidSyntax() { + final String initialContent = """ + # Document top comment + @prefix ex: . + + # Comment on subject + ex:subject + ex:predicate1 ex:object1 ; + ex:predicate2 123 ; + ex:predicate3 true ; + # comment on string + ex:predicate4 "some string" ; + ex:predicate5 "some langString"@en ; + ex:predicate6 "123"^^xsd:decimal ; + ex:predicate7 . + + a rdf:type . + """; + + final Document document = new Document( "test.ttl", initialContent ); + final TSTree tree = parserService.getAbstractSyntaxTree( document ); + System.out.println( TreeSitterUtil.print( tree, document ) ); + assertThat( tree.getRootNode().hasError() ).isFalse(); + } + @Test void testPrefixAddition() { final String initialContent = "ex:subject ex:predicate ex:object ."; From be2ac4a3c893e040a5fc7d1992a5f5f38695c9e1 Mon Sep 17 00:00:00 2001 From: Andreas Textor Date: Wed, 6 May 2026 06:56:33 +0200 Subject: [PATCH 07/41] Rename Turtle parser service --- ...ava => TreeSitterTurtleParserService.java} | 33 ++++++++++++------- .../lsp/text/TurtleTextDocumentService.java | 4 +-- .../lsp/text/TurtleParserServiceTest.java | 4 +-- 3 files changed, 25 insertions(+), 16 deletions(-) rename core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/{TreeSitterTurtleSyntaxValidationService.java => TreeSitterTurtleParserService.java} (85%) diff --git a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TreeSitterTurtleSyntaxValidationService.java b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TreeSitterTurtleParserService.java similarity index 85% rename from core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TreeSitterTurtleSyntaxValidationService.java rename to core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TreeSitterTurtleParserService.java index d0c6bf277..c7c9a2a3f 100644 --- a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TreeSitterTurtleSyntaxValidationService.java +++ b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TreeSitterTurtleParserService.java @@ -14,11 +14,11 @@ package org.eclipse.esmf.turtle.languageserver.lsp.text; import java.nio.charset.StandardCharsets; -import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.WeakHashMap; +import java.util.stream.IntStream; import org.eclipse.esmf.treesitterturtle.TreeSitterTurtle; import org.eclipse.esmf.turtle.languageserver.diagnostic.DiagnosticReport; @@ -41,12 +41,12 @@ * Service for parsing Turtle documents using Tree-sitter and maintaining their syntax trees. * Supports incremental parsing for efficient updates when documents change. */ -public class TreeSitterTurtleSyntaxValidationService implements TurtleDiagnosticsService { +public class TreeSitterTurtleParserService implements TurtleDiagnosticsService { private final TSParser parser; private final Map syntaxTrees = new HashMap<>(); private final Map previousDocumentStates = new WeakHashMap<>(); - public TreeSitterTurtleSyntaxValidationService() { + public TreeSitterTurtleParserService() { parser = new TSParser(); final TSLanguage turtle = new TreeSitterTurtle(); parser.setLanguage( turtle ); @@ -151,17 +151,26 @@ public DiagnosticReport check( final Document document ) { } private List checkNode( final TSNode node, final String sourceLocation ) { - final List result = new ArrayList<>(); - if ( node.hasError() ) { - final TurtleDiagnostic diagnostic = new TurtleDocumentDiagnostic( "Syntax error: unexpected token '" + node.getType() + "'", + final List childDiagnostics = IntStream.range( 0, node.getChildCount() ) + .mapToObj( node::getChild ) + .flatMap( child -> checkNode( child, sourceLocation ).stream() ) + .toList(); + if ( node.hasError() && childDiagnostics.isEmpty() ) { + final String message; + if ( node.isMissing() ) { + message = "Syntax error: Missing '" + node.getGrammarType() + "'"; + } else if ( node.isExtra() ) { + message = node.getGrammarType().equals( "ERROR" ) + ? "Syntax error: Unexpected token" + : "Syntax error: Unexpected token '" + node.getGrammarType() + "'"; + } else { + message = "Syntax error"; + } + return List.of( new TurtleDocumentDiagnostic( message, TurtleDiagnostic.TurtleCode.E0003, sourceLocation, node.getStartPoint().getRow(), node.getStartPoint().getColumn(), - node.getEndPoint().getRow(), node.getEndPoint().getColumn() ); - result.add( diagnostic ); + node.getEndPoint().getRow(), node.getEndPoint().getColumn() ) ); } - for ( int i = 0; i < node.getChildCount(); i++ ) { - result.addAll( checkNode( node.getChild( i ), sourceLocation ) ); - } - return result; + return childDiagnostics; } } diff --git a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TurtleTextDocumentService.java b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TurtleTextDocumentService.java index 81989aeb8..721d973f7 100644 --- a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TurtleTextDocumentService.java +++ b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TurtleTextDocumentService.java @@ -45,7 +45,7 @@ public class TurtleTextDocumentService implements TextDocumentService { private final TextDocumentClientNotifier clientNotifier; private final TurtlePrefixDefinitionService prefixDefinitionService; private final AspectValidationCoordinator aspectValidationCoordinator; - private final TreeSitterTurtleSyntaxValidationService turtleParserService; + private final TreeSitterTurtleParserService turtleParserService; private final AspectDiagnosticsWorkflow aspectDiagnosticsWorkflow; private final DocumentAspectValidationService documentValidationService; private final TurtleDiagnosticsService syntaxValidationService; @@ -57,7 +57,7 @@ public TurtleTextDocumentService() { clientNotifier = new TextDocumentClientNotifier( new AspectDiagnosticMapper() ); prefixDefinitionService = new TurtlePrefixDefinitionService(); aspectValidationCoordinator = new AspectValidationCoordinator( new AspectModelValidationService() ); - turtleParserService = new TreeSitterTurtleSyntaxValidationService(); + turtleParserService = new TreeSitterTurtleParserService(); aspectDiagnosticsWorkflow = new AspectDiagnosticsWorkflow( aspectValidationCoordinator, clientNotifier ); documentValidationService = new DocumentAspectValidationService( aspectValidationCoordinator ); // syntaxValidationService = new JenaTurtleSyntaxValidationService(); diff --git a/core/esmf-turtle-language-server/src/test/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TurtleParserServiceTest.java b/core/esmf-turtle-language-server/src/test/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TurtleParserServiceTest.java index 076f63375..4ce8dcdbb 100644 --- a/core/esmf-turtle-language-server/src/test/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TurtleParserServiceTest.java +++ b/core/esmf-turtle-language-server/src/test/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TurtleParserServiceTest.java @@ -25,11 +25,11 @@ @SuppressWarnings( "HttpUrlsUsage" ) class TurtleParserServiceTest { - private TreeSitterTurtleSyntaxValidationService parserService; + private TreeSitterTurtleParserService parserService; @BeforeEach void setUp() { - parserService = new TreeSitterTurtleSyntaxValidationService(); + parserService = new TreeSitterTurtleParserService(); } @Test From 6d2dae875832500ab543300f5436e9e8d0fa6a0f Mon Sep 17 00:00:00 2001 From: Andreas Textor Date: Wed, 6 May 2026 15:01:53 +0200 Subject: [PATCH 08/41] Add Turtle tokenizing --- .../treesitterturtle/ParserTokenType.java | 69 ++++++++ .../languageserver/TurtleLanguageServer.java | 23 ++- .../diagnostic/AspectDiagnosticMapper.java | 3 - .../diagnostic/DiagnosticReport.java | 2 + .../diagnostic/TurtleBaseDiagnostic.java | 11 ++ .../diagnostic/TurtleDiagnostic.java | 9 + .../languageserver/lsp/text/Document.java | 7 +- .../lsp/text/TurtleTextDocumentService.java | 15 ++ .../structure/TurtleTokenService.java | 154 ++++++++++++++++++ .../src/main/resources/logback.xml | 2 +- .../lsp/text/TurtleParserServiceTest.java | 10 ++ 11 files changed, 291 insertions(+), 14 deletions(-) create mode 100644 core/esmf-tree-sitter-turtle/src/main/java/org/eclipse/esmf/treesitterturtle/ParserTokenType.java create mode 100644 core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/structure/TurtleTokenService.java diff --git a/core/esmf-tree-sitter-turtle/src/main/java/org/eclipse/esmf/treesitterturtle/ParserTokenType.java b/core/esmf-tree-sitter-turtle/src/main/java/org/eclipse/esmf/treesitterturtle/ParserTokenType.java new file mode 100644 index 000000000..90964ffc2 --- /dev/null +++ b/core/esmf-tree-sitter-turtle/src/main/java/org/eclipse/esmf/treesitterturtle/ParserTokenType.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2026 Robert Bosch Manufacturing Solutions GmbH + * + * See the AUTHORS file(s) distributed with this work for additional + * information regarding authorship. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * SPDX-License-Identifier: MPL-2.0 + */ + +package org.eclipse.esmf.treesitterturtle; + +/** + * The types of parser tokens the RDF/Turtle parser produces, see also grammar.js. + */ +public class ParserTokenType { + private ParserTokenType() {} + + public static final String SYMBOL_COLON = ":"; + public static final String SYMBOL_DOT = "."; + public static final String SYMBOL_SEMICOLON = ";"; + public static final String SYMBOL_QUOTE = "\""; + public static final String SYMBOL_SINGLE_QUOTE = "'"; + public static final String SYMBOL_TRIPLE_QUOTE = "\"\"\""; + public static final String SYMBOL_TRIPLE_SINGLE_QUOTE = "'''"; + public static final String SYMBOL_DOUBLE_CARET = "^^"; + public static final String SYMBOL_OPENING_BRACKET = "("; + public static final String SYMBOL_CLOSING_BRACKET = ")"; + public static final String SYMBOL_OPENING_SQUARE_BRACKET = "["; + public static final String SYMBOL_CLOSING_SQUARE_BRACKET = "]"; + public static final String SYMBOL_OPENING_POINTY_BRACKET = "<"; + public static final String SYMBOL_CLOSING_POINTY_BRACKET = ">"; + + public static final String AT_PREFIX = "@prefix"; + public static final String AT_BASE = "@base"; + public static final String DOCUMENT = "document"; + public static final String GRAPH = "graph"; + public static final String COMMENT = "comment"; + public static final String TRIPLE = "triple"; + public static final String DIRECTIVE = "directive"; + public static final String PREFIX_ID = "prefix_id"; + public static final String BASE = "base"; + public static final String SPARQL_BASE = "sparql_base"; + public static final String SPARQL_PREFIX = "sparql_prefix"; + public static final String PROPERTY_LIST = "property_list"; + public static final String PROPERTY = "property"; + public static final String OBJECT_LIST = "object_list"; + public static final String PREDICATE = "predicate"; + public static final String SUBJECT = "subject"; + public static final String BLANK_NODE_PROPERTY_LIST = "blank_node_property_list"; + public static final String COLLECTION = "collection"; + public static final String STRING = "string"; + public static final String IRI_REFERENCE = "iri_reference"; + public static final String INTEGER = "integer"; + public static final String DECIMAL = "decimal"; + public static final String DOUBLE = "double"; + public static final String RDF_LITERAL = "rdf_literal"; + public static final String BOOLEAN_LITERAL = "boolean_literal"; + public static final String PREFIXED_NAME = "prefixed_name"; + public static final String NAMESPACE = "namespace"; + public static final String BLANK_NODE_LABEL = "blank_node_label"; + public static final String LANG_TAG = "lang_tag"; + public static final String ANON = "anon"; + public static final String PN_PREFIX = "pn_prefix"; + public static final String PN_LOCAL = "pn_local"; +} diff --git a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/TurtleLanguageServer.java b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/TurtleLanguageServer.java index 71afcd08a..31a8ee1b4 100644 --- a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/TurtleLanguageServer.java +++ b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/TurtleLanguageServer.java @@ -15,9 +15,16 @@ import java.util.concurrent.CompletableFuture; +import org.eclipse.esmf.turtle.languageserver.aspect.request.ValidateDocumentParams; +import org.eclipse.esmf.turtle.languageserver.diagnostic.DiagnosticReport; +import org.eclipse.esmf.turtle.languageserver.lsp.text.TurtleTextDocumentService; +import org.eclipse.esmf.turtle.languageserver.lsp.workspace.TurtleWorkspaceService; +import org.eclipse.esmf.turtle.languageserver.structure.TurtleTokenService; + import org.eclipse.lsp4j.InitializeParams; import org.eclipse.lsp4j.InitializeResult; import org.eclipse.lsp4j.SaveOptions; +import org.eclipse.lsp4j.SemanticTokensWithRegistrationOptions; import org.eclipse.lsp4j.ServerCapabilities; import org.eclipse.lsp4j.TextDocumentSyncKind; import org.eclipse.lsp4j.TextDocumentSyncOptions; @@ -28,11 +35,6 @@ import org.eclipse.lsp4j.services.TextDocumentService; import org.eclipse.lsp4j.services.WorkspaceService; -import org.eclipse.esmf.turtle.languageserver.diagnostic.DiagnosticReport; -import org.eclipse.esmf.turtle.languageserver.aspect.request.ValidateDocumentParams; -import org.eclipse.esmf.turtle.languageserver.lsp.text.TurtleTextDocumentService; -import org.eclipse.esmf.turtle.languageserver.lsp.workspace.TurtleWorkspaceService; - public class TurtleLanguageServer implements LanguageServer, LanguageClientAware { private final TurtleTextDocumentService textDocumentService; private final TurtleWorkspaceService workspaceService; @@ -55,7 +57,8 @@ public CompletableFuture initialize( final InitializeParams pa syncOptions.setSave( new SaveOptions( true ) ); capabilities.setTextDocumentSync( syncOptions ); capabilities.setDefinitionProvider( true ); - + capabilities.setSemanticTokensProvider( + new SemanticTokensWithRegistrationOptions( TurtleTokenService.SUPPORTED_TOKEN_TYPES, true, false ) ); return CompletableFuture.completedFuture( new InitializeResult( capabilities ) ); } @@ -67,7 +70,7 @@ public CompletableFuture shutdown() { @Override public void exit() { - throw new UnsupportedOperationException(); + System.exit( 0 ); } @Override @@ -87,7 +90,9 @@ public void connect( final LanguageClient client ) { @JsonRequest( "turtle/aspectValidation/validateDocument" ) public CompletableFuture validateDocument( final ValidateDocumentParams params ) { - final String uri = params != null ? params.uri() : null; - return CompletableFuture.completedFuture( textDocumentService.validateDocument( uri ) ); + if ( params == null || params.uri() == null ) { + return CompletableFuture.completedFuture( DiagnosticReport.EMPTY ); + } + return CompletableFuture.completedFuture( textDocumentService.validateDocument( params.uri() ) ); } } diff --git a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/aspect/diagnostic/AspectDiagnosticMapper.java b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/aspect/diagnostic/AspectDiagnosticMapper.java index 9247f13fe..f75c9e55e 100644 --- a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/aspect/diagnostic/AspectDiagnosticMapper.java +++ b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/aspect/diagnostic/AspectDiagnosticMapper.java @@ -26,8 +26,6 @@ import org.eclipse.lsp4j.Range; public final class AspectDiagnosticMapper { - public static final String SOURCE = "lsp-server.aspect"; - public List toDiagnostics( final Document document, final DiagnosticReport result ) { return result.diagnostics().stream() .filter( violation -> appliesToDocument( document, violation ) ) @@ -44,7 +42,6 @@ private boolean appliesToDocument( final Document document, final TurtleDiagnost private Diagnostic toDiagnostic( final TurtleDiagnostic turtleDiagnostic ) { final Diagnostic diagnostic = new Diagnostic(); - diagnostic.setSource( SOURCE ); diagnostic.setSeverity( DiagnosticSeverity.Error ); diagnostic.setMessage( turtleDiagnostic.message() ); diagnostic.setCode( turtleDiagnostic.code().code() ); diff --git a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/diagnostic/DiagnosticReport.java b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/diagnostic/DiagnosticReport.java index dbc7a5dc1..d20b14dec 100644 --- a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/diagnostic/DiagnosticReport.java +++ b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/diagnostic/DiagnosticReport.java @@ -18,6 +18,8 @@ public record DiagnosticReport( List diagnostics ) { + public static final DiagnosticReport EMPTY = new DiagnosticReport( List.of() ); + public DiagnosticReport( final TurtleDiagnostic diagnostic ) { this( List.of( diagnostic ) ); } diff --git a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/diagnostic/TurtleBaseDiagnostic.java b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/diagnostic/TurtleBaseDiagnostic.java index c5094842b..e0ef06b81 100644 --- a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/diagnostic/TurtleBaseDiagnostic.java +++ b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/diagnostic/TurtleBaseDiagnostic.java @@ -16,10 +16,16 @@ public class TurtleBaseDiagnostic implements TurtleDiagnostic { private final String message; private final Code code; + private final Severity severity; public TurtleBaseDiagnostic( final String message, final Code code ) { + this( message, code, Severity.ERROR ); + } + + public TurtleBaseDiagnostic( final String message, final Code code, final Severity severity ) { this.message = message; this.code = code; + this.severity = severity; } @Override @@ -31,4 +37,9 @@ public String message() { public Code code() { return code; } + + @Override + public Severity severity() { + return severity; + } } diff --git a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/diagnostic/TurtleDiagnostic.java b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/diagnostic/TurtleDiagnostic.java index 459db8725..9994bc8eb 100644 --- a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/diagnostic/TurtleDiagnostic.java +++ b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/diagnostic/TurtleDiagnostic.java @@ -18,6 +18,8 @@ public interface TurtleDiagnostic { String message(); + Severity severity(); + default boolean hasLocation() { return false; } @@ -50,4 +52,11 @@ public String description() { return description; } } + + enum Severity { + ERROR, + WARNING, + INFO, + HINT + } } diff --git a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/Document.java b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/Document.java index f996b3cdc..7143d1b46 100644 --- a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/Document.java +++ b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/Document.java @@ -17,6 +17,7 @@ import org.eclipse.lsp4j.Position; import org.eclipse.lsp4j.Range; +import org.jspecify.annotations.Nullable; public class Document { private final String uri; @@ -53,7 +54,11 @@ public String subSequence( final int fromLine, final int fromColumn, final int t return content.subSequence( fromIndex, toIndex ).toString(); } - public void update( final Range range, final String newContent ) { + public void update( final @Nullable Range range, final String newContent ) { + if ( range == null ) { + content = new Rope( newContent ); + return; + } final Position start = range.getStart(); final Position end = range.getEnd(); content = content.update( start.getLine(), start.getCharacter(), diff --git a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TurtleTextDocumentService.java b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TurtleTextDocumentService.java index 721d973f7..bf630209c 100644 --- a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TurtleTextDocumentService.java +++ b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TurtleTextDocumentService.java @@ -23,6 +23,7 @@ import org.eclipse.esmf.turtle.languageserver.aspect.service.AspectValidationCoordinator; import org.eclipse.esmf.turtle.languageserver.diagnostic.DiagnosticReport; import org.eclipse.esmf.turtle.languageserver.diagnostic.TurtleDiagnosticsService; +import org.eclipse.esmf.turtle.languageserver.structure.TurtleTokenService; import org.eclipse.esmf.turtle.languageserver.turtle.navigation.TurtlePrefixDefinitionService; import org.eclipse.lsp4j.DefinitionParams; @@ -32,6 +33,8 @@ import org.eclipse.lsp4j.DidSaveTextDocumentParams; import org.eclipse.lsp4j.Location; import org.eclipse.lsp4j.LocationLink; +import org.eclipse.lsp4j.SemanticTokens; +import org.eclipse.lsp4j.SemanticTokensParams; import org.eclipse.lsp4j.TextDocumentContentChangeEvent; import org.eclipse.lsp4j.jsonrpc.messages.Either; import org.eclipse.lsp4j.services.LanguageClient; @@ -49,6 +52,7 @@ public class TurtleTextDocumentService implements TextDocumentService { private final AspectDiagnosticsWorkflow aspectDiagnosticsWorkflow; private final DocumentAspectValidationService documentValidationService; private final TurtleDiagnosticsService syntaxValidationService; + private final TurtleTokenService tokenService; private final Map documents = new HashMap<>(); // TODO determine and harmonize when to send which diagnostics @@ -60,6 +64,7 @@ public TurtleTextDocumentService() { turtleParserService = new TreeSitterTurtleParserService(); aspectDiagnosticsWorkflow = new AspectDiagnosticsWorkflow( aspectValidationCoordinator, clientNotifier ); documentValidationService = new DocumentAspectValidationService( aspectValidationCoordinator ); + tokenService = new TurtleTokenService( turtleParserService ); // syntaxValidationService = new JenaTurtleSyntaxValidationService(); syntaxValidationService = turtleParserService; } @@ -118,9 +123,19 @@ public void didSave( final DidSaveTextDocumentParams params ) { final Document document = documents.get( uri ); LOG.info( "[didSave] uri={}", uri ); document.getRope().rebalance(); + turtleParserService.onOpen( document ); aspectDiagnosticsWorkflow.onDocumentSaved( document ); } + @Override + public CompletableFuture semanticTokensFull( final SemanticTokensParams params ) { + final String uri = params.getTextDocument().getUri(); + final Document document = documents.get( uri ); + LOG.info( "[semanticTokensFull] uri={}", uri ); + final SemanticTokens semanticTokens = tokenService.buildSemanticTokens( document ); + return CompletableFuture.completedFuture( semanticTokens ); + } + @Override public CompletableFuture, List>> definition( final DefinitionParams params ) { final String uri = params.getTextDocument().getUri(); diff --git a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/structure/TurtleTokenService.java b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/structure/TurtleTokenService.java new file mode 100644 index 000000000..b5a9d417b --- /dev/null +++ b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/structure/TurtleTokenService.java @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2026 Robert Bosch Manufacturing Solutions GmbH + * + * See the AUTHORS file(s) distributed with this work for additional + * information regarding authorship. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * SPDX-License-Identifier: MPL-2.0 + */ + +package org.eclipse.esmf.turtle.languageserver.structure; + +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.Deque; +import java.util.List; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +import org.eclipse.esmf.metamodel.vocabulary.SammNs; +import org.eclipse.esmf.treesitterturtle.ParserTokenType; +import org.eclipse.esmf.turtle.languageserver.lsp.text.Document; +import org.eclipse.esmf.turtle.languageserver.lsp.text.TreeSitterTurtleParserService; + +import org.eclipse.lsp4j.SemanticTokenModifiers; +import org.eclipse.lsp4j.SemanticTokenTypes; +import org.eclipse.lsp4j.SemanticTokens; +import org.eclipse.lsp4j.SemanticTokensLegend; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.treesitter.TSNode; +import org.treesitter.TSTree; + +import com.google.common.collect.ImmutableMap; + +public class TurtleTokenService { + private static final Logger LOG = LoggerFactory.getLogger( TurtleTokenService.class ); + public static final SemanticTokensLegend SUPPORTED_TOKEN_TYPES = new SemanticTokensLegend( + List.of( + SemanticTokenTypes.Type, + SemanticTokenTypes.Comment, + SemanticTokenTypes.Keyword, + SemanticTokenTypes.String, + SemanticTokenTypes.Class, + SemanticTokenTypes.Number, + SemanticTokenTypes.Decorator, + SemanticTokenTypes.Function + ), + List.of( SemanticTokenModifiers.DefaultLibrary ) + ); + + private static final Map PARSER_TOKEN_TO_SEMANTIC_TOKEN = ImmutableMap.builder() + .put( ParserTokenType.COMMENT, SemanticTokenTypes.Comment ) + .put( ParserTokenType.AT_BASE, SemanticTokenTypes.Keyword ) + .put( ParserTokenType.AT_PREFIX, SemanticTokenTypes.Keyword ) + .put( ParserTokenType.SPARQL_BASE, SemanticTokenTypes.Keyword ) + .put( ParserTokenType.SPARQL_PREFIX, SemanticTokenTypes.Keyword ) + .put( ParserTokenType.STRING, SemanticTokenTypes.String ) + .put( ParserTokenType.IRI_REFERENCE, SemanticTokenTypes.Class ) + .put( ParserTokenType.INTEGER, SemanticTokenTypes.Number ) + .put( ParserTokenType.DECIMAL, SemanticTokenTypes.Number ) + .put( ParserTokenType.DOUBLE, SemanticTokenTypes.Number ) + .put( ParserTokenType.RDF_LITERAL, SemanticTokenTypes.String ) + .put( ParserTokenType.BOOLEAN_LITERAL, SemanticTokenTypes.Keyword ) + .put( ParserTokenType.PREFIXED_NAME, SemanticTokenTypes.Class ) + .put( ParserTokenType.LANG_TAG, SemanticTokenTypes.Decorator ) + .put( ParserTokenType.PN_PREFIX, SemanticTokenTypes.Function ) + .build(); + private final TreeSitterTurtleParserService parserService; + + private final Map tokenTypeIds = IntStream.range( 0, SUPPORTED_TOKEN_TYPES.getTokenTypes().size() ) + .boxed() + .collect( Collectors.toMap( i -> SUPPORTED_TOKEN_TYPES.getTokenTypes().get( i ), Function.identity() ) ); + private final Map tokenModifierTypeIds = IntStream.range( 0, SUPPORTED_TOKEN_TYPES.getTokenModifiers().size() ) + .boxed() + .collect( Collectors.toMap( i -> SUPPORTED_TOKEN_TYPES.getTokenModifiers().get( i ), Function.identity() ) ); + + public TurtleTokenService( final TreeSitterTurtleParserService parserService ) { + this.parserService = parserService; + } + + public SemanticTokens buildSemanticTokens( final Document document ) { + final SemanticTokens semanticTokens = new SemanticTokens(); + final List data = new ArrayList<>(); + semanticTokens.setData( data ); + + final TSTree abstractSyntaxTree = parserService.getAbstractSyntaxTree( document ); + final Deque nodes = new ArrayDeque<>(); + TSNode node; + nodes.push( abstractSyntaxTree.getRootNode() ); + int lastLine = -1; + int lastColumn = -1; + while ( !nodes.isEmpty() ) { + node = nodes.pop(); + for ( int i = 0; i < node.getChildCount(); i++ ) { + nodes.push( node.getChild( i ) ); + } + + final int tokenId = tokenIdForNode( node ); + if ( tokenId == -1 ) { + continue; + } + + final int line = node.getStartPoint().getRow(); + final int column = node.getStartPoint().getColumn(); + final int length = node.getEndByte() - node.getEndByte(); + if ( lastLine == -1 ) { + data.add( line ); + data.add( column ); + } else { + data.add( (int) ( line - lastLine ) ); + data.add( (int) ( lastLine == line ? column - lastColumn : column ) ); + } + data.add( length ); + data.add( tokenId ); + data.add( tokenModifierBitSetForNode( node, document ) ); + lastLine = line; + lastColumn = column; + } + + return semanticTokens; + } + + private int tokenIdForNode( final TSNode node ) { + final String semanticToken = PARSER_TOKEN_TO_SEMANTIC_TOKEN.get( node.getGrammarType() ); + if ( semanticToken == null ) { + return -1; + } + + final Integer semanticTokenId = tokenTypeIds.get( semanticToken ); + if ( semanticTokenId == null ) { + LOG.error( "Trying to return unsupported token type for parser type {}", semanticToken ); + return -1; + } + return semanticTokenId; + } + + private int tokenModifierBitSetForNode( final TSNode node, final Document document ) { + int bitSet = 0; + if ( node.getGrammarType().equals( ParserTokenType.PN_PREFIX ) ) { + final String token = document.subSequence( node.getStartPoint().getRow(), node.getStartPoint().getColumn(), + node.getEndPoint().getRow(), node.getEndPoint().getColumn() ); + if ( token.equals( SammNs.SAMM.getShortForm() ) || token.equals( SammNs.SAMMC.getShortForm() ) ) { + bitSet = bitSet | ( 1 << tokenModifierTypeIds.get( SemanticTokenModifiers.DefaultLibrary ) ); + } + } + return bitSet; + } +} diff --git a/core/esmf-turtle-language-server/src/main/resources/logback.xml b/core/esmf-turtle-language-server/src/main/resources/logback.xml index 1d4deae08..67b63924f 100644 --- a/core/esmf-turtle-language-server/src/main/resources/logback.xml +++ b/core/esmf-turtle-language-server/src/main/resources/logback.xml @@ -26,7 +26,7 @@ - + diff --git a/core/esmf-turtle-language-server/src/test/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TurtleParserServiceTest.java b/core/esmf-turtle-language-server/src/test/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TurtleParserServiceTest.java index 4ce8dcdbb..9f728c8f4 100644 --- a/core/esmf-turtle-language-server/src/test/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TurtleParserServiceTest.java +++ b/core/esmf-turtle-language-server/src/test/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TurtleParserServiceTest.java @@ -234,6 +234,16 @@ void testParseValidSyntax() { ex:predicate7 . a rdf:type . + + ex:subject2 ex:bla [ + ex:blub true ; + ] . + + ex:subject3 ex:bla ( 1 2 3 ) . + + ex:subject4 ex:bla \"""hello\""" . + + ex:subject5 ex:bla '''hello''' . """; final Document document = new Document( "test.ttl", initialContent ); From 5dae4579eaf7706e535ed6f639882289ce8db7a9 Mon Sep 17 00:00:00 2001 From: Andreas Textor Date: Wed, 6 May 2026 15:24:20 +0200 Subject: [PATCH 09/41] Start LSP server on local port --- .../esmf/turtle/languageserver/App.java | 46 +++++++++++-------- 1 file changed, 27 insertions(+), 19 deletions(-) diff --git a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/App.java b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/App.java index 5398ec1aa..186b9ee57 100644 --- a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/App.java +++ b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/App.java @@ -13,34 +13,42 @@ package org.eclipse.esmf.turtle.languageserver; +import java.io.IOException; +import java.net.InetSocketAddress; +import java.nio.channels.AsynchronousServerSocketChannel; +import java.nio.channels.AsynchronousSocketChannel; +import java.nio.channels.Channels; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.function.Function; + import org.eclipse.lsp4j.jsonrpc.Launcher; import org.eclipse.lsp4j.services.LanguageClient; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class App { + public static final int PORT = 1846; private static final Logger LOG = LoggerFactory.getLogger( App.class ); static void main( final String[] args ) { - LOG.info( "Starting lsp-server" ); - final TurtleLanguageServer server = new TurtleLanguageServer(); - - try { - final Launcher launcher = Launcher.createLauncher( - server, - LanguageClient.class, - System.in, - System.out - ); - - server.connect( launcher.getRemoteProxy() ); - launcher.startListening().get(); - LOG.info( "Language server listener stopped" ); - } catch ( final InterruptedException ex ) { - Thread.currentThread().interrupt(); - LOG.error( "Language server listener was interrupted", ex ); - } catch ( final Exception ex ) { - LOG.error( "Language server terminated with an error", ex ); + LOG.info( "Starting lsp-server on port {}", PORT ); + final TurtleLanguageServer languageServer = new TurtleLanguageServer(); + try ( final AsynchronousServerSocketChannel serverSocket = AsynchronousServerSocketChannel.open() ) { + serverSocket.bind( new InetSocketAddress( "localhost", PORT ) ); + final AsynchronousSocketChannel socketChannel = serverSocket.accept().get(); + final Launcher launcher = + Launcher.createIoLauncher( languageServer, LanguageClient.class, Channels.newInputStream( socketChannel ), + Channels.newOutputStream( socketChannel ), Executors.newCachedThreadPool(), Function.identity() ); + final Future future = launcher.startListening(); + languageServer.connect( launcher.getRemoteProxy() ); + while ( !future.isDone() ) { + // noinspection BusyWait + Thread.sleep( 10_000L ); + } + } catch ( final InterruptedException | ExecutionException | IOException exception ) { + LOG.warn( "Could not launch Language Server", exception ); } } } From 792b7a093a2c71aadf5eaa8d96fe06297190d340 Mon Sep 17 00:00:00 2001 From: Andreas Textor Date: Wed, 6 May 2026 15:24:59 +0200 Subject: [PATCH 10/41] Build semantic tokens from concrete syntax tree tree --- .../treesitterturtle/ParserTokenType.java | 1 + .../text/TreeSitterTurtleParserService.java | 4 +- .../structure/TurtleTokenService.java | 100 ++++++++++++++---- .../lsp/text/TurtleParserServiceTest.java | 56 +++++----- 4 files changed, 110 insertions(+), 51 deletions(-) diff --git a/core/esmf-tree-sitter-turtle/src/main/java/org/eclipse/esmf/treesitterturtle/ParserTokenType.java b/core/esmf-tree-sitter-turtle/src/main/java/org/eclipse/esmf/treesitterturtle/ParserTokenType.java index 90964ffc2..0f66c7a40 100644 --- a/core/esmf-tree-sitter-turtle/src/main/java/org/eclipse/esmf/treesitterturtle/ParserTokenType.java +++ b/core/esmf-tree-sitter-turtle/src/main/java/org/eclipse/esmf/treesitterturtle/ParserTokenType.java @@ -34,6 +34,7 @@ private ParserTokenType() {} public static final String SYMBOL_OPENING_POINTY_BRACKET = "<"; public static final String SYMBOL_CLOSING_POINTY_BRACKET = ">"; + public static final String A = "a"; // the syntactic shortcut for rdf:type public static final String AT_PREFIX = "@prefix"; public static final String AT_BASE = "@base"; public static final String DOCUMENT = "document"; diff --git a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TreeSitterTurtleParserService.java b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TreeSitterTurtleParserService.java index c7c9a2a3f..569a3f56b 100644 --- a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TreeSitterTurtleParserService.java +++ b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TreeSitterTurtleParserService.java @@ -52,7 +52,7 @@ public TreeSitterTurtleParserService() { parser.setLanguage( turtle ); } - public TSTree getAbstractSyntaxTree( final Document document ) { + public TSTree getConcreteSyntaxTree( final Document document ) { return syntaxTrees.computeIfAbsent( document, this::parseDocument ); } @@ -146,7 +146,7 @@ public void onChange( final Document document, final TextDocumentContentChangeEv @Override public DiagnosticReport check( final Document document ) { - final TSTree abstractSyntaxTree = getAbstractSyntaxTree( document ); + final TSTree abstractSyntaxTree = getConcreteSyntaxTree( document ); return new DiagnosticReport( checkNode( abstractSyntaxTree.getRootNode(), document.getUri() ) ); } diff --git a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/structure/TurtleTokenService.java b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/structure/TurtleTokenService.java index b5a9d417b..1b7cb79b4 100644 --- a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/structure/TurtleTokenService.java +++ b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/structure/TurtleTokenService.java @@ -15,6 +15,7 @@ import java.util.ArrayDeque; import java.util.ArrayList; +import java.util.Comparator; import java.util.Deque; import java.util.List; import java.util.Map; @@ -38,6 +39,9 @@ import com.google.common.collect.ImmutableMap; +/** + * Service that maps parser tokens to LSP semantic tokens + */ public class TurtleTokenService { private static final Logger LOG = LoggerFactory.getLogger( TurtleTokenService.class ); public static final SemanticTokensLegend SUPPORTED_TOKEN_TYPES = new SemanticTokensLegend( @@ -49,9 +53,13 @@ public class TurtleTokenService { SemanticTokenTypes.Class, SemanticTokenTypes.Number, SemanticTokenTypes.Decorator, - SemanticTokenTypes.Function + SemanticTokenTypes.Function, + SemanticTokenTypes.Property ), - List.of( SemanticTokenModifiers.DefaultLibrary ) + List.of( + SemanticTokenModifiers.DefaultLibrary, + SemanticTokenModifiers.Deprecated + ) ); private static final Map PARSER_TOKEN_TO_SEMANTIC_TOKEN = ImmutableMap.builder() @@ -60,16 +68,18 @@ public class TurtleTokenService { .put( ParserTokenType.AT_PREFIX, SemanticTokenTypes.Keyword ) .put( ParserTokenType.SPARQL_BASE, SemanticTokenTypes.Keyword ) .put( ParserTokenType.SPARQL_PREFIX, SemanticTokenTypes.Keyword ) + .put( ParserTokenType.A, SemanticTokenTypes.Keyword ) .put( ParserTokenType.STRING, SemanticTokenTypes.String ) - .put( ParserTokenType.IRI_REFERENCE, SemanticTokenTypes.Class ) .put( ParserTokenType.INTEGER, SemanticTokenTypes.Number ) .put( ParserTokenType.DECIMAL, SemanticTokenTypes.Number ) .put( ParserTokenType.DOUBLE, SemanticTokenTypes.Number ) - .put( ParserTokenType.RDF_LITERAL, SemanticTokenTypes.String ) .put( ParserTokenType.BOOLEAN_LITERAL, SemanticTokenTypes.Keyword ) - .put( ParserTokenType.PREFIXED_NAME, SemanticTokenTypes.Class ) .put( ParserTokenType.LANG_TAG, SemanticTokenTypes.Decorator ) .put( ParserTokenType.PN_PREFIX, SemanticTokenTypes.Function ) + .put( ParserTokenType.PN_LOCAL, SemanticTokenTypes.Property ) + .put( ParserTokenType.SYMBOL_DOUBLE_CARET, SemanticTokenTypes.Decorator ) + .put( ParserTokenType.SYMBOL_DOT, SemanticTokenTypes.Decorator ) + .put( ParserTokenType.SYMBOL_SEMICOLON, SemanticTokenTypes.Decorator ) .build(); private final TreeSitterTurtleParserService parserService; @@ -84,17 +94,34 @@ public TurtleTokenService( final TreeSitterTurtleParserService parserService ) { this.parserService = parserService; } + /** + * Represents a single token over a given range + * + * @param line the line where the token appears + * @param column the column in the line + * @param length the length of the token in characters + * @param tokenType the token type + * @param tokenModifiers the token modifiers bit set + */ + private record TokenRange( + int line, + int column, + int length, + int tokenType, + int tokenModifiers + ) {} + + /** + * Builds the SemanticTokens for a Document + * + * @param document the document + */ public SemanticTokens buildSemanticTokens( final Document document ) { - final SemanticTokens semanticTokens = new SemanticTokens(); - final List data = new ArrayList<>(); - semanticTokens.setData( data ); - - final TSTree abstractSyntaxTree = parserService.getAbstractSyntaxTree( document ); + final List tokenRanges = new ArrayList<>(); + final TSTree concreteSyntaxTree = parserService.getConcreteSyntaxTree( document ); final Deque nodes = new ArrayDeque<>(); TSNode node; - nodes.push( abstractSyntaxTree.getRootNode() ); - int lastLine = -1; - int lastColumn = -1; + nodes.push( concreteSyntaxTree.getRootNode() ); while ( !nodes.isEmpty() ) { node = nodes.pop(); for ( int i = 0; i < node.getChildCount(); i++ ) { @@ -108,24 +135,55 @@ public SemanticTokens buildSemanticTokens( final Document document ) { final int line = node.getStartPoint().getRow(); final int column = node.getStartPoint().getColumn(); - final int length = node.getEndByte() - node.getEndByte(); + final int length = node.getEndByte() - node.getStartByte(); + tokenRanges.add( new TokenRange( line, column, length, tokenId, tokenModifierBitSetForNode( node, document ) ) ); + } + + return buildSemanticTokens( tokenRanges ); + } + + /** + * Builds the SemanticTokens for the given list of token ranges. In LSP, this is described as a list + * of integers. + * + * @param tokenRanges the input list of token ranges + * @see Semantic + * Tokens at LSP specification + * @return the SemanticTokens representation + */ + private SemanticTokens buildSemanticTokens( final List tokenRanges ) { + tokenRanges.sort( Comparator.comparingInt( TokenRange::line ).thenComparingInt( TokenRange::column ) ); + final List data = new ArrayList<>(); + int lastLine = -1; + int lastColumn = -1; + for ( final TokenRange tokenRange : tokenRanges ) { + final int line = tokenRange.line(); + final int column = tokenRange.column(); if ( lastLine == -1 ) { data.add( line ); data.add( column ); } else { - data.add( (int) ( line - lastLine ) ); - data.add( (int) ( lastLine == line ? column - lastColumn : column ) ); + data.add( line - lastLine ); + data.add( lastLine == line ? column - lastColumn : column ); } - data.add( length ); - data.add( tokenId ); - data.add( tokenModifierBitSetForNode( node, document ) ); + data.add( tokenRange.length() ); + data.add( tokenRange.tokenType() ); + data.add( tokenRange.tokenModifiers() ); lastLine = line; lastColumn = column; } - - return semanticTokens; + return new SemanticTokens( data ); } + /** + * Returns the tokenId for a given parser node, i.e., the index of the type of token in the + * SemanticTokenLegends.tokenTypes + * + * @param node the parser node + * @see TurtleTokenService#SUPPORTED_TOKEN_TYPES + * @return the corresponding tokenId + */ private int tokenIdForNode( final TSNode node ) { final String semanticToken = PARSER_TOKEN_TO_SEMANTIC_TOKEN.get( node.getGrammarType() ); if ( semanticToken == null ) { diff --git a/core/esmf-turtle-language-server/src/test/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TurtleParserServiceTest.java b/core/esmf-turtle-language-server/src/test/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TurtleParserServiceTest.java index 9f728c8f4..de41b137d 100644 --- a/core/esmf-turtle-language-server/src/test/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TurtleParserServiceTest.java +++ b/core/esmf-turtle-language-server/src/test/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TurtleParserServiceTest.java @@ -41,7 +41,7 @@ void testInitialParsing() { """; final Document document = new Document( "test.ttl", content ); - final TSTree tree = parserService.getAbstractSyntaxTree( document ); + final TSTree tree = parserService.getConcreteSyntaxTree( document ); assertThat( tree ).isNotNull(); final TSNode rootNode = tree.getRootNode(); @@ -68,7 +68,7 @@ void testInitialParsing() { @Test void testEmptyDocument() { final Document document = new Document( "empty.ttl", "" ); - final TSTree tree = parserService.getAbstractSyntaxTree( document ); + final TSTree tree = parserService.getConcreteSyntaxTree( document ); assertThat( tree ).isNotNull(); final TSNode rootNode = tree.getRootNode(); @@ -83,13 +83,13 @@ void testSingleLineInsertion() { """; final Document document = new Document( "test.ttl", initialContent ); - final TSTree initialTree = parserService.getAbstractSyntaxTree( document ); + final TSTree initialTree = parserService.getConcreteSyntaxTree( document ); assertThat( initialTree.getRootNode().hasError() ).isFalse(); final String newText = "\nex:subject ex:predicate ex:object ."; applyChange( document, pos( 1, 0 ), pos( 1, 0 ), newText ); - final TSTree updatedTree = parserService.getAbstractSyntaxTree( document ); + final TSTree updatedTree = parserService.getConcreteSyntaxTree( document ); assertThat( updatedTree ).isNotNull(); assertThat( updatedTree.getRootNode().hasError() ).isFalse(); @@ -109,7 +109,7 @@ void testMultiLineInsertion() { applyChange( document, pos( 0, initialContent.length() ), pos( 0, initialContent.length() ), newText ); - final TSTree tree = parserService.getAbstractSyntaxTree( document ); + final TSTree tree = parserService.getConcreteSyntaxTree( document ); assertThat( tree.getRootNode().hasError() ).isFalse(); assertThat( document.getContent() ) .contains( "ex:subject1" ) @@ -127,11 +127,11 @@ void testDeletion() { """; final Document document = new Document( "test.ttl", initialContent ); - parserService.getAbstractSyntaxTree( document ); + parserService.getConcreteSyntaxTree( document ); applyChange( document, pos( 3, 0 ), pos( 3, 38 ), "" ); - final TSTree tree = parserService.getAbstractSyntaxTree( document ); + final TSTree tree = parserService.getConcreteSyntaxTree( document ); assertThat( tree.getRootNode().hasError() ).isFalse(); assertThat( document.getContent() ).doesNotContain( "ex:ToDelete" ); assertThat( document.getContent() ).contains( "ex:subject ex:predicate ex:object" ); @@ -146,12 +146,12 @@ void testReplacement() { """; final Document document = new Document( "test.ttl", initialContent ); - parserService.getAbstractSyntaxTree( document ); + parserService.getConcreteSyntaxTree( document ); final String replacement = "NewObject"; applyChange( document, pos( 2, 27 ), pos( 2, 35 ), replacement ); - final TSTree tree = parserService.getAbstractSyntaxTree( document ); + final TSTree tree = parserService.getConcreteSyntaxTree( document ); if ( tree.getRootNode().hasError() ) { printDocumentAndTree( document, tree ); } @@ -167,27 +167,27 @@ void testMultipleSequentialEdits() { final String text1 = "@prefix ex: ."; applyChange( document, pos( 0, 0 ), pos( 0, 0 ), text1 ); - TSTree tree = parserService.getAbstractSyntaxTree( document ); + TSTree tree = parserService.getConcreteSyntaxTree( document ); assertThat( tree.getRootNode().hasError() ).isFalse(); final String text2 = "\n\nex:subject1 ex:predicate1 ex:object1 ."; applyChange( document, pos( 0, 35 ), pos( 0, 35 ), text2 ); - tree = parserService.getAbstractSyntaxTree( document ); + tree = parserService.getConcreteSyntaxTree( document ); assertThat( tree.getRootNode().hasError() ).isFalse(); assertThat( document.getContent() ).contains( "ex:subject1" ); final String text3 = "\nex:subject2 ex:predicate2 ex:object2 ."; applyChange( document, pos( 2, 38 ), pos( 2, 38 ), text3 ); - tree = parserService.getAbstractSyntaxTree( document ); + tree = parserService.getConcreteSyntaxTree( document ); assertThat( tree.getRootNode().hasError() ).isFalse(); assertThat( document.getContent() ).contains( "ex:subject1" ) .contains( "ex:subject2" ); applyChange( document, pos( 2, 0 ), pos( 2, 38 ), "" ); - tree = parserService.getAbstractSyntaxTree( document ); + tree = parserService.getConcreteSyntaxTree( document ); assertThat( tree.getRootNode().hasError() ).isFalse(); assertThat( document.getContent() ).doesNotContain( "ex:subject1" ); assertThat( document.getContent() ).contains( "ex:subject2" ); @@ -204,12 +204,12 @@ void testEditAcrossMultipleLines() { """; final Document document = new Document( "test.ttl", initialContent ); - parserService.getAbstractSyntaxTree( document ); + parserService.getConcreteSyntaxTree( document ); final String replacement = "ex:newPredicate"; applyChange( document, pos( 3, 2 ), pos( 4, 14 ), replacement ); - final TSTree tree = parserService.getAbstractSyntaxTree( document ); + final TSTree tree = parserService.getConcreteSyntaxTree( document ); System.out.println( TreeSitterUtil.print( tree, document ) ); assertThat( tree.getRootNode().hasError() ).isFalse(); assertThat( document.getContent() ).contains( "ex:newPredicate" ); @@ -247,7 +247,7 @@ void testParseValidSyntax() { """; final Document document = new Document( "test.ttl", initialContent ); - final TSTree tree = parserService.getAbstractSyntaxTree( document ); + final TSTree tree = parserService.getConcreteSyntaxTree( document ); System.out.println( TreeSitterUtil.print( tree, document ) ); assertThat( tree.getRootNode().hasError() ).isFalse(); } @@ -257,12 +257,12 @@ void testPrefixAddition() { final String initialContent = "ex:subject ex:predicate ex:object ."; final Document document = new Document( "test.ttl", initialContent ); - parserService.getAbstractSyntaxTree( document ); + parserService.getConcreteSyntaxTree( document ); final String prefix = "@prefix ex: .\n\n"; applyChange( document, pos( 0, 0 ), pos( 0, 0 ), prefix ); - final TSTree tree = parserService.getAbstractSyntaxTree( document ); + final TSTree tree = parserService.getConcreteSyntaxTree( document ); assertThat( tree.getRootNode().hasError() ).isFalse(); assertThat( document.getContent() ).startsWith( "@prefix ex:" ); } @@ -274,17 +274,17 @@ void testComplexEditSequence() { applyChange( document, pos( 0, 0 ), pos( 0, 0 ), "@base .\n@prefix ex: .\n\n" ); - tree = parserService.getAbstractSyntaxTree( document ); + tree = parserService.getConcreteSyntaxTree( document ); assertThat( tree.getRootNode().hasError() ).isFalse(); applyChange( document, pos( 3, 0 ), pos( 3, 0 ), "ex:subject ex:predicate ex:object ." ); - tree = parserService.getAbstractSyntaxTree( document ); + tree = parserService.getConcreteSyntaxTree( document ); assertThat( tree.getRootNode().hasError() ).isFalse(); applyChange( document, pos( 3, 33 ), pos( 3, 34 ), " ;\n ex:predicate2 ex:object2 ;\n ex:predicate3 ex:object3 ." ); - tree = parserService.getAbstractSyntaxTree( document ); + tree = parserService.getConcreteSyntaxTree( document ); assertThat( tree.getRootNode().hasError() ).isFalse(); final String content = document.getContent(); @@ -293,7 +293,7 @@ void testComplexEditSequence() { final int col = predicateStart - content.lastIndexOf( '\n', predicateStart ) - 1; applyChange( document, pos( line, col ), pos( line, col + 12 ), "ex:modified" ); - tree = parserService.getAbstractSyntaxTree( document ); + tree = parserService.getConcreteSyntaxTree( document ); assertThat( tree.getRootNode().hasError() ).isFalse(); assertThat( document.getContent() ).contains( "ex:modified" ); assertThat( document.getContent() ).doesNotContain( "ex:predicate2" ); @@ -312,13 +312,13 @@ void testInvalidSyntaxHandling() { final String initialContent = "@prefix ex: ."; final Document document = new Document( "test.ttl", initialContent ); - TSTree tree = parserService.getAbstractSyntaxTree( document ); + TSTree tree = parserService.getConcreteSyntaxTree( document ); assertThat( tree.getRootNode().hasError() ).isFalse(); final String invalidText = "\n\nthis is not valid turtle syntax @#$%"; applyChange( document, pos( 0, 35 ), pos( 0, 35 ), invalidText ); - tree = parserService.getAbstractSyntaxTree( document ); + tree = parserService.getConcreteSyntaxTree( document ); assertThat( tree.getRootNode() ).isNotNull(); // Tree-sitter should still parse it, but with errors assertThat( tree.getRootNode().hasError() ).isTrue(); @@ -329,7 +329,7 @@ void testFullDocumentChange() { final String initialContent = "@prefix ex: ."; final Document document = new Document( "test.ttl", initialContent ); - parserService.getAbstractSyntaxTree( document ); + parserService.getConcreteSyntaxTree( document ); final String newContent = """ @prefix rdf: . @prefix rdfs: . @@ -342,7 +342,7 @@ void testFullDocumentChange() { final Document newDocument = new Document( "test.ttl", newContent ); parserService.onChange( newDocument, change ); - final TSTree tree = parserService.getAbstractSyntaxTree( newDocument ); + final TSTree tree = parserService.getConcreteSyntaxTree( newDocument ); assertThat( tree.getRootNode().hasError() ).isFalse(); assertThat( newDocument.getContent() ).contains( "rdfs:" ); } @@ -351,13 +351,13 @@ void testFullDocumentChange() { void testWhitespaceOnlyChanges() { final String initialContent = "ex:subject ex:predicate ex:object."; final Document document = new Document( "test.ttl", initialContent ); - final TSTree oldTree = parserService.getAbstractSyntaxTree( document ); + final TSTree oldTree = parserService.getConcreteSyntaxTree( document ); final Range range = new Range( pos( 0, 33 ), pos( 0, 33 ) ); final TextDocumentContentChangeEvent change = new TextDocumentContentChangeEvent( range, " " ); document.update( range, " " ); parserService.onChange( document, change ); - final TSTree tree = parserService.getAbstractSyntaxTree( document ); + final TSTree tree = parserService.getConcreteSyntaxTree( document ); assertThat( tree.getRootNode().hasError() ).isFalse(); assertThat( document.getContent() ).endsWith( "object ." ); assertThat( oldTree.getRootNode().toString() ).isEqualTo( tree.getRootNode().toString() ); From 2542c6e9af6894b948550030eea6b03f755251b0 Mon Sep 17 00:00:00 2001 From: Andreas Textor Date: Thu, 7 May 2026 07:19:52 +0200 Subject: [PATCH 11/41] Unifiy diagnostics report building --- .../service/AspectModelValidationService.java | 9 ++- .../service/AspectValidationCoordinator.java | 15 ++-- .../diagnostic/DiagnosticReport.java | 14 +++- .../diagnostic/TurtleDiagnosticsService.java | 18 ++++- .../lsp/text/AspectDiagnosticsWorkflow.java | 10 +-- .../text/DocumentAspectValidationService.java | 2 +- .../JenaTurtleSyntaxValidationService.java | 62 ----------------- .../lsp/text/ParsedDocument.java | 25 +++++++ .../text/TreeSitterTurtleParserService.java | 45 ++---------- .../lsp/text/TurtleTextDocumentService.java | 38 ++++++++--- .../structure/TurtleTokenService.java | 2 +- .../TurtleSyntaxDiagnosticsService.java | 57 ++++++++++++++++ .../lsp/text/TurtleParserServiceTest.java | 68 +++++++++---------- 13 files changed, 200 insertions(+), 165 deletions(-) delete mode 100644 core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/JenaTurtleSyntaxValidationService.java create mode 100644 core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/ParsedDocument.java create mode 100644 core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/turtle/TurtleSyntaxDiagnosticsService.java diff --git a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/aspect/service/AspectModelValidationService.java b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/aspect/service/AspectModelValidationService.java index fb7609f20..8b54b5d59 100644 --- a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/aspect/service/AspectModelValidationService.java +++ b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/aspect/service/AspectModelValidationService.java @@ -28,6 +28,7 @@ import org.eclipse.esmf.turtle.languageserver.diagnostic.TurtleDiagnosticsService; import org.eclipse.esmf.turtle.languageserver.diagnostic.TurtleDocumentDiagnostic; import org.eclipse.esmf.turtle.languageserver.lsp.text.Document; +import org.eclipse.esmf.turtle.languageserver.lsp.text.ParsedDocument; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -48,7 +49,13 @@ public AspectModelValidationService() { } @Override - public DiagnosticReport check( final Document document ) { + public DiagnosticReport onChange( final ParsedDocument document ) { + return DiagnosticReport.EMPTY; + } + + @Override + public DiagnosticReport defaultValidate( final ParsedDocument parsedDocument ) { + final Document document = parsedDocument.sourceDocument(); try ( final InputStream inputStream = document.getInputStream() ) { LOG.debug( "[load] loading aspect model from {}", document.getUri() ); final List violations = diff --git a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/aspect/service/AspectValidationCoordinator.java b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/aspect/service/AspectValidationCoordinator.java index 6fabae8bf..895610bd3 100644 --- a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/aspect/service/AspectValidationCoordinator.java +++ b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/aspect/service/AspectValidationCoordinator.java @@ -26,6 +26,7 @@ import org.eclipse.esmf.turtle.languageserver.diagnostic.TurtleDiagnostic; import org.eclipse.esmf.turtle.languageserver.diagnostic.TurtleDiagnosticsService; import org.eclipse.esmf.turtle.languageserver.lsp.text.Document; +import org.eclipse.esmf.turtle.languageserver.lsp.text.ParsedDocument; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -63,15 +64,15 @@ public void cancel( final Document document ) { } } - public void submit( final Document document, final long generation, final BiConsumer callback ) { - cancel( document ); + public void submit( final ParsedDocument document, final long generation, final BiConsumer callback ) { + cancel( document.sourceDocument() ); final CompletableFuture future = CompletableFuture.supplyAsync( - () -> validationService.check( document ), + () -> validationService.defaultValidate( document ), executorService ); - inFlight.put( document, future ); + inFlight.put( document.sourceDocument(), future ); future.whenComplete( ( result, throwable ) -> { - inFlight.remove( document, future ); + inFlight.remove( document.sourceDocument(), future ); if ( throwable instanceof CancellationException || future.isCancelled() ) { LOG.debug( "[cancel] aspect validation cancelled for {}", document.getUri() ); return; @@ -85,8 +86,8 @@ public void submit( final Document document, final long generation, final BiCons } ); } - public DiagnosticReport validateSync( final Document document ) { - return validationService.check( document ); + public DiagnosticReport validateSync( final ParsedDocument document ) { + return validationService.defaultValidate( document ); } @Override diff --git a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/diagnostic/DiagnosticReport.java b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/diagnostic/DiagnosticReport.java index d20b14dec..b02c33806 100644 --- a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/diagnostic/DiagnosticReport.java +++ b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/diagnostic/DiagnosticReport.java @@ -15,6 +15,8 @@ import java.util.List; +import com.google.common.collect.Streams; + public record DiagnosticReport( List diagnostics ) { @@ -26,11 +28,21 @@ public DiagnosticReport( final TurtleDiagnostic diagnostic ) { /** * Convenience constructor to create are report for one {@link TurtleBaseDiagnostic} - * + * * @param message the message * @param code the code */ public DiagnosticReport( final String message, final TurtleDiagnostic.TurtleCode code ) { this( new TurtleBaseDiagnostic( message, code ) ); } + + /** + * Create a new DiagnosticsReport from this and another + * + * @param diagnosticReport the other report + * @return the new merged report + */ + public DiagnosticReport merge( final DiagnosticReport diagnosticReport ) { + return new DiagnosticReport( Streams.concat( diagnostics.stream(), diagnosticReport.diagnostics().stream() ).toList() ); + } } diff --git a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/diagnostic/TurtleDiagnosticsService.java b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/diagnostic/TurtleDiagnosticsService.java index 8bdd66b34..b285c3cc5 100644 --- a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/diagnostic/TurtleDiagnosticsService.java +++ b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/diagnostic/TurtleDiagnosticsService.java @@ -13,8 +13,22 @@ package org.eclipse.esmf.turtle.languageserver.diagnostic; -import org.eclipse.esmf.turtle.languageserver.lsp.text.Document; +import org.eclipse.esmf.turtle.languageserver.lsp.text.ParsedDocument; public interface TurtleDiagnosticsService { - DiagnosticReport check( Document document ); + default DiagnosticReport defaultValidate( final ParsedDocument document ) { + return DiagnosticReport.EMPTY; + } + + default DiagnosticReport onOpen( final ParsedDocument document ) { + return defaultValidate( document ); + } + + default DiagnosticReport onChange( final ParsedDocument document ) { + return defaultValidate( document ); + } + + default DiagnosticReport onSave( final ParsedDocument document ) { + return defaultValidate( document ); + } } diff --git a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/AspectDiagnosticsWorkflow.java b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/AspectDiagnosticsWorkflow.java index 7a90118f6..5fe84fdb2 100644 --- a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/AspectDiagnosticsWorkflow.java +++ b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/AspectDiagnosticsWorkflow.java @@ -45,17 +45,17 @@ public void onDocumentClosed( final Document document ) { diagnostics.clear(); } - public void onDocumentSaved( final Document document ) { - final long generation = aspectValidationCoordinator.nextGeneration( document ); + public void onDocumentSaved( final ParsedDocument document ) { + final long generation = aspectValidationCoordinator.nextGeneration( document.sourceDocument() ); aspectValidationCoordinator.submit( document, generation, ( completedGeneration, result ) -> { - final long currentGeneration = aspectValidationCoordinator.currentGeneration( document ); + final long currentGeneration = aspectValidationCoordinator.currentGeneration( document.sourceDocument() ); if ( completedGeneration != currentGeneration ) { LOG.debug( "[publish diagnostics] ignoring stale aspect diagnostics for uri={}, generation={}, current={}", document.getUri(), completedGeneration, currentGeneration ); return; } - diagnostics.put( document, result ); - clientNotifier.publishDiagnostics( document, result ); + diagnostics.put( document.sourceDocument(), result ); + clientNotifier.publishDiagnostics( document.sourceDocument(), result ); } ); } } diff --git a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/DocumentAspectValidationService.java b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/DocumentAspectValidationService.java index 8d94a4ad1..e35fba4c3 100644 --- a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/DocumentAspectValidationService.java +++ b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/DocumentAspectValidationService.java @@ -25,7 +25,7 @@ public DocumentAspectValidationService( final AspectValidationCoordinator aspect this.aspectValidationCoordinator = aspectValidationCoordinator; } - public DiagnosticReport validateDocument( final String uri, final Document document ) { + public DiagnosticReport validateDocument( final String uri, final ParsedDocument document ) { if ( document == null ) { return new DiagnosticReport( new TurtleBaseDiagnostic( "Document is not available in memory: " + uri, TurtleDiagnostic.TurtleCode.E0001 ) ); diff --git a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/JenaTurtleSyntaxValidationService.java b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/JenaTurtleSyntaxValidationService.java deleted file mode 100644 index 9d05c6a89..000000000 --- a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/JenaTurtleSyntaxValidationService.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (c) 2026 Robert Bosch Manufacturing Solutions GmbH - * - * See the AUTHORS file(s) distributed with this work for additional - * information regarding authorship. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * SPDX-License-Identifier: MPL-2.0 - */ - -package org.eclipse.esmf.turtle.languageserver.lsp.text; - -import java.io.StringReader; -import java.util.ArrayList; -import java.util.List; - -import org.apache.jena.riot.Lang; -import org.apache.jena.riot.RDFParser; -import org.apache.jena.riot.RiotException; -import org.apache.jena.riot.RiotParseException; -import org.apache.jena.riot.system.ErrorHandlerFactory; -import org.apache.jena.riot.system.StreamRDFLib; - -import org.eclipse.esmf.turtle.languageserver.diagnostic.DiagnosticReport; -import org.eclipse.esmf.turtle.languageserver.diagnostic.TurtleDiagnostic; -import org.eclipse.esmf.turtle.languageserver.diagnostic.TurtleDiagnosticsService; -import org.eclipse.esmf.turtle.languageserver.diagnostic.TurtleDocumentDiagnostic; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class JenaTurtleSyntaxValidationService implements TurtleDiagnosticsService { - private static final Logger LOG = LoggerFactory.getLogger( JenaTurtleSyntaxValidationService.class ); - - @Override - public DiagnosticReport check( final Document document ) { - final List diagnostics = new ArrayList<>(); - - try { - RDFParser.create() - .source( new StringReader( document.getContent() ) ) - .lang( Lang.TTL ) - .errorHandler( ErrorHandlerFactory.errorHandlerStrictNoLogging ) - .parse( StreamRDFLib.sinkNull() ); - LOG.debug( "[validate] turtle parsing successful" ); - } catch ( final RiotParseException exception ) { - LOG.warn( "[validate] parse error at line={}, col={}: {}", exception.getLine(), exception.getCol(), exception.getMessage() ); - diagnostics.add( new TurtleDocumentDiagnostic( exception.getMessage(), TurtleDiagnostic.TurtleCode.E0003, document.getUri(), - (int) exception.getLine(), (int) exception.getCol(), (int) exception.getLine(), (int) exception.getCol() ) ); - } catch ( final RiotException exception ) { - LOG.warn( "[validate] RDF error: {}", exception.getMessage() ); - diagnostics.add( new TurtleDocumentDiagnostic( exception.getMessage(), TurtleDiagnostic.TurtleCode.E0003, document.getUri(), - 1, 1, 1, 1 ) ); - } - - LOG.debug( "[validate] found {} diagnostic(s)", diagnostics.size() ); - return new DiagnosticReport( diagnostics ); - } -} diff --git a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/ParsedDocument.java b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/ParsedDocument.java new file mode 100644 index 000000000..2f94291d9 --- /dev/null +++ b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/ParsedDocument.java @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2026 Robert Bosch Manufacturing Solutions GmbH + * + * See the AUTHORS file(s) distributed with this work for additional + * information regarding authorship. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * SPDX-License-Identifier: MPL-2.0 + */ + +package org.eclipse.esmf.turtle.languageserver.lsp.text; + +import org.treesitter.TSTree; + +public record ParsedDocument( + Document sourceDocument, + TSTree concreteSyntaxTree +) { + public String getUri() { + return sourceDocument().getUri(); + } +} diff --git a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TreeSitterTurtleParserService.java b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TreeSitterTurtleParserService.java index 569a3f56b..d0f5ea9fe 100644 --- a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TreeSitterTurtleParserService.java +++ b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TreeSitterTurtleParserService.java @@ -15,16 +15,11 @@ import java.nio.charset.StandardCharsets; import java.util.HashMap; -import java.util.List; import java.util.Map; import java.util.WeakHashMap; -import java.util.stream.IntStream; +import java.util.function.Function; import org.eclipse.esmf.treesitterturtle.TreeSitterTurtle; -import org.eclipse.esmf.turtle.languageserver.diagnostic.DiagnosticReport; -import org.eclipse.esmf.turtle.languageserver.diagnostic.TurtleDiagnostic; -import org.eclipse.esmf.turtle.languageserver.diagnostic.TurtleDiagnosticsService; -import org.eclipse.esmf.turtle.languageserver.diagnostic.TurtleDocumentDiagnostic; import org.eclipse.lsp4j.Position; import org.eclipse.lsp4j.Range; @@ -32,7 +27,6 @@ import org.jspecify.annotations.Nullable; import org.treesitter.TSInputEdit; import org.treesitter.TSLanguage; -import org.treesitter.TSNode; import org.treesitter.TSParser; import org.treesitter.TSPoint; import org.treesitter.TSTree; @@ -41,7 +35,7 @@ * Service for parsing Turtle documents using Tree-sitter and maintaining their syntax trees. * Supports incremental parsing for efficient updates when documents change. */ -public class TreeSitterTurtleParserService implements TurtleDiagnosticsService { +public class TreeSitterTurtleParserService implements Function { private final TSParser parser; private final Map syntaxTrees = new HashMap<>(); private final Map previousDocumentStates = new WeakHashMap<>(); @@ -52,8 +46,9 @@ public TreeSitterTurtleParserService() { parser.setLanguage( turtle ); } - public TSTree getConcreteSyntaxTree( final Document document ) { - return syntaxTrees.computeIfAbsent( document, this::parseDocument ); + @Override + public ParsedDocument apply( final Document document ) { + return new ParsedDocument( document, syntaxTrees.computeIfAbsent( document, this::parseDocument ) ); } private TSTree parseDocument( final Document document ) { @@ -143,34 +138,4 @@ public void onChange( final Document document, final TextDocumentContentChangeEv syntaxTrees.put( document, newTree ); previousDocumentStates.put( document, document.getRope() ); } - - @Override - public DiagnosticReport check( final Document document ) { - final TSTree abstractSyntaxTree = getConcreteSyntaxTree( document ); - return new DiagnosticReport( checkNode( abstractSyntaxTree.getRootNode(), document.getUri() ) ); - } - - private List checkNode( final TSNode node, final String sourceLocation ) { - final List childDiagnostics = IntStream.range( 0, node.getChildCount() ) - .mapToObj( node::getChild ) - .flatMap( child -> checkNode( child, sourceLocation ).stream() ) - .toList(); - if ( node.hasError() && childDiagnostics.isEmpty() ) { - final String message; - if ( node.isMissing() ) { - message = "Syntax error: Missing '" + node.getGrammarType() + "'"; - } else if ( node.isExtra() ) { - message = node.getGrammarType().equals( "ERROR" ) - ? "Syntax error: Unexpected token" - : "Syntax error: Unexpected token '" + node.getGrammarType() + "'"; - } else { - message = "Syntax error"; - } - return List.of( new TurtleDocumentDiagnostic( message, - TurtleDiagnostic.TurtleCode.E0003, sourceLocation, - node.getStartPoint().getRow(), node.getStartPoint().getColumn(), - node.getEndPoint().getRow(), node.getEndPoint().getColumn() ) ); - } - return childDiagnostics; - } } diff --git a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TurtleTextDocumentService.java b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TurtleTextDocumentService.java index bf630209c..9321791cb 100644 --- a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TurtleTextDocumentService.java +++ b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TurtleTextDocumentService.java @@ -24,6 +24,7 @@ import org.eclipse.esmf.turtle.languageserver.diagnostic.DiagnosticReport; import org.eclipse.esmf.turtle.languageserver.diagnostic.TurtleDiagnosticsService; import org.eclipse.esmf.turtle.languageserver.structure.TurtleTokenService; +import org.eclipse.esmf.turtle.languageserver.turtle.TurtleSyntaxDiagnosticsService; import org.eclipse.esmf.turtle.languageserver.turtle.navigation.TurtlePrefixDefinitionService; import org.eclipse.lsp4j.DefinitionParams; @@ -50,23 +51,20 @@ public class TurtleTextDocumentService implements TextDocumentService { private final AspectValidationCoordinator aspectValidationCoordinator; private final TreeSitterTurtleParserService turtleParserService; private final AspectDiagnosticsWorkflow aspectDiagnosticsWorkflow; - private final DocumentAspectValidationService documentValidationService; - private final TurtleDiagnosticsService syntaxValidationService; private final TurtleTokenService tokenService; + private final List diagnosticsServices = List.of( + new TurtleSyntaxDiagnosticsService(), + new AspectModelValidationService() + ); private final Map documents = new HashMap<>(); - // TODO determine and harmonize when to send which diagnostics - public TurtleTextDocumentService() { clientNotifier = new TextDocumentClientNotifier( new AspectDiagnosticMapper() ); prefixDefinitionService = new TurtlePrefixDefinitionService(); aspectValidationCoordinator = new AspectValidationCoordinator( new AspectModelValidationService() ); turtleParserService = new TreeSitterTurtleParserService(); aspectDiagnosticsWorkflow = new AspectDiagnosticsWorkflow( aspectValidationCoordinator, clientNotifier ); - documentValidationService = new DocumentAspectValidationService( aspectValidationCoordinator ); tokenService = new TurtleTokenService( turtleParserService ); - // syntaxValidationService = new JenaTurtleSyntaxValidationService(); - syntaxValidationService = turtleParserService; } public void connect( final LanguageClient client ) { @@ -78,7 +76,14 @@ public void shutdown() { } public DiagnosticReport validateDocument( final String uri ) { - return documentValidationService.validateDocument( uri, documents.get( uri ) ); + final Document document = documents.get( uri ); + if ( document == null ) { + return DiagnosticReport.EMPTY; + } + final ParsedDocument parsedDocument = turtleParserService.apply( document ); + return diagnosticsServices.stream() + .map( service -> service.defaultValidate( parsedDocument ) ) + .reduce( DiagnosticReport.EMPTY, DiagnosticReport::merge ); } @Override @@ -89,7 +94,10 @@ public void didOpen( final DidOpenTextDocumentParams params ) { final Document document = new Document( uri, content ); documents.put( uri, document ); turtleParserService.onOpen( document ); - final DiagnosticReport report = syntaxValidationService.check( document ); + final ParsedDocument parsedDocument = turtleParserService.apply( document ); + final DiagnosticReport report = diagnosticsServices.stream() + .map( service -> service.onOpen( parsedDocument ) ) + .reduce( DiagnosticReport.EMPTY, DiagnosticReport::merge ); clientNotifier.publishDiagnostics( document, report ); } @@ -102,7 +110,10 @@ public void didChange( final DidChangeTextDocumentParams params ) { turtleParserService.onChange( document, change ); } LOG.debug( "[didChange] uri={}, changes={}", uri, params.getContentChanges().size() ); - final DiagnosticReport report = syntaxValidationService.check( document ); + final ParsedDocument parsedDocument = turtleParserService.apply( document ); + final DiagnosticReport report = diagnosticsServices.stream() + .map( service -> service.onChange( parsedDocument ) ) + .reduce( DiagnosticReport.EMPTY, DiagnosticReport::merge ); clientNotifier.publishDiagnostics( document, report ); aspectDiagnosticsWorkflow.onDocumentChanged( document ); } @@ -124,7 +135,12 @@ public void didSave( final DidSaveTextDocumentParams params ) { LOG.info( "[didSave] uri={}", uri ); document.getRope().rebalance(); turtleParserService.onOpen( document ); - aspectDiagnosticsWorkflow.onDocumentSaved( document ); + final ParsedDocument parsedDocument = turtleParserService.apply( document ); + final DiagnosticReport report = diagnosticsServices.stream() + .map( service -> service.onSave( parsedDocument ) ) + .reduce( DiagnosticReport.EMPTY, DiagnosticReport::merge ); + clientNotifier.publishDiagnostics( document, report ); + aspectDiagnosticsWorkflow.onDocumentSaved( parsedDocument ); } @Override diff --git a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/structure/TurtleTokenService.java b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/structure/TurtleTokenService.java index 1b7cb79b4..6f585ed28 100644 --- a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/structure/TurtleTokenService.java +++ b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/structure/TurtleTokenService.java @@ -118,7 +118,7 @@ private record TokenRange( */ public SemanticTokens buildSemanticTokens( final Document document ) { final List tokenRanges = new ArrayList<>(); - final TSTree concreteSyntaxTree = parserService.getConcreteSyntaxTree( document ); + final TSTree concreteSyntaxTree = parserService.apply( document ).concreteSyntaxTree(); final Deque nodes = new ArrayDeque<>(); TSNode node; nodes.push( concreteSyntaxTree.getRootNode() ); diff --git a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/turtle/TurtleSyntaxDiagnosticsService.java b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/turtle/TurtleSyntaxDiagnosticsService.java new file mode 100644 index 000000000..45346fdf0 --- /dev/null +++ b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/turtle/TurtleSyntaxDiagnosticsService.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2026 Robert Bosch Manufacturing Solutions GmbH + * + * See the AUTHORS file(s) distributed with this work for additional + * information regarding authorship. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * SPDX-License-Identifier: MPL-2.0 + */ + +package org.eclipse.esmf.turtle.languageserver.turtle; + +import java.util.List; +import java.util.stream.IntStream; + +import org.eclipse.esmf.turtle.languageserver.diagnostic.DiagnosticReport; +import org.eclipse.esmf.turtle.languageserver.diagnostic.TurtleDiagnostic; +import org.eclipse.esmf.turtle.languageserver.diagnostic.TurtleDiagnosticsService; +import org.eclipse.esmf.turtle.languageserver.diagnostic.TurtleDocumentDiagnostic; +import org.eclipse.esmf.turtle.languageserver.lsp.text.ParsedDocument; + +import org.treesitter.TSNode; + +public class TurtleSyntaxDiagnosticsService implements TurtleDiagnosticsService { + @Override + public DiagnosticReport defaultValidate( final ParsedDocument parsedDocument ) { + return new DiagnosticReport( + checkNode( parsedDocument.concreteSyntaxTree().getRootNode(), parsedDocument.sourceDocument().getUri() ) ); + } + + private List checkNode( final TSNode node, final String sourceLocation ) { + final List childDiagnostics = IntStream.range( 0, node.getChildCount() ) + .mapToObj( node::getChild ) + .flatMap( child -> checkNode( child, sourceLocation ).stream() ) + .toList(); + if ( node.hasError() && childDiagnostics.isEmpty() ) { + final String message; + if ( node.isMissing() ) { + message = "Syntax error: Missing '" + node.getGrammarType() + "'"; + } else if ( node.isExtra() ) { + message = node.getGrammarType().equals( "ERROR" ) + ? "Syntax error: Unexpected token" + : "Syntax error: Unexpected token '" + node.getGrammarType() + "'"; + } else { + message = "Syntax error"; + } + return List.of( new TurtleDocumentDiagnostic( message, + TurtleDiagnostic.TurtleCode.E0003, sourceLocation, + node.getStartPoint().getRow(), node.getStartPoint().getColumn(), + node.getEndPoint().getRow(), node.getEndPoint().getColumn() ) ); + } + return childDiagnostics; + } +} diff --git a/core/esmf-turtle-language-server/src/test/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TurtleParserServiceTest.java b/core/esmf-turtle-language-server/src/test/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TurtleParserServiceTest.java index de41b137d..b4f12ce02 100644 --- a/core/esmf-turtle-language-server/src/test/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TurtleParserServiceTest.java +++ b/core/esmf-turtle-language-server/src/test/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TurtleParserServiceTest.java @@ -23,7 +23,7 @@ import org.treesitter.TSNode; import org.treesitter.TSTree; -@SuppressWarnings( "HttpUrlsUsage" ) +@SuppressWarnings( { "HttpUrlsUsage", "resource" } ) class TurtleParserServiceTest { private TreeSitterTurtleParserService parserService; @@ -41,7 +41,7 @@ void testInitialParsing() { """; final Document document = new Document( "test.ttl", content ); - final TSTree tree = parserService.getConcreteSyntaxTree( document ); + final TSTree tree = parserService.apply( document ).concreteSyntaxTree(); assertThat( tree ).isNotNull(); final TSNode rootNode = tree.getRootNode(); @@ -68,7 +68,7 @@ void testInitialParsing() { @Test void testEmptyDocument() { final Document document = new Document( "empty.ttl", "" ); - final TSTree tree = parserService.getConcreteSyntaxTree( document ); + final TSTree tree = parserService.apply( document ).concreteSyntaxTree(); assertThat( tree ).isNotNull(); final TSNode rootNode = tree.getRootNode(); @@ -83,13 +83,13 @@ void testSingleLineInsertion() { """; final Document document = new Document( "test.ttl", initialContent ); - final TSTree initialTree = parserService.getConcreteSyntaxTree( document ); + final TSTree initialTree = parserService.apply( document ).concreteSyntaxTree(); assertThat( initialTree.getRootNode().hasError() ).isFalse(); final String newText = "\nex:subject ex:predicate ex:object ."; applyChange( document, pos( 1, 0 ), pos( 1, 0 ), newText ); - final TSTree updatedTree = parserService.getConcreteSyntaxTree( document ); + final TSTree updatedTree = parserService.apply( document ).concreteSyntaxTree(); assertThat( updatedTree ).isNotNull(); assertThat( updatedTree.getRootNode().hasError() ).isFalse(); @@ -109,7 +109,7 @@ void testMultiLineInsertion() { applyChange( document, pos( 0, initialContent.length() ), pos( 0, initialContent.length() ), newText ); - final TSTree tree = parserService.getConcreteSyntaxTree( document ); + final TSTree tree = parserService.apply( document ).concreteSyntaxTree(); assertThat( tree.getRootNode().hasError() ).isFalse(); assertThat( document.getContent() ) .contains( "ex:subject1" ) @@ -127,11 +127,11 @@ void testDeletion() { """; final Document document = new Document( "test.ttl", initialContent ); - parserService.getConcreteSyntaxTree( document ); + parserService.apply( document ).concreteSyntaxTree(); applyChange( document, pos( 3, 0 ), pos( 3, 38 ), "" ); - final TSTree tree = parserService.getConcreteSyntaxTree( document ); + final TSTree tree = parserService.apply( document ).concreteSyntaxTree(); assertThat( tree.getRootNode().hasError() ).isFalse(); assertThat( document.getContent() ).doesNotContain( "ex:ToDelete" ); assertThat( document.getContent() ).contains( "ex:subject ex:predicate ex:object" ); @@ -146,12 +146,12 @@ void testReplacement() { """; final Document document = new Document( "test.ttl", initialContent ); - parserService.getConcreteSyntaxTree( document ); + parserService.apply( document ).concreteSyntaxTree(); final String replacement = "NewObject"; applyChange( document, pos( 2, 27 ), pos( 2, 35 ), replacement ); - final TSTree tree = parserService.getConcreteSyntaxTree( document ); + final TSTree tree = parserService.apply( document ).concreteSyntaxTree(); if ( tree.getRootNode().hasError() ) { printDocumentAndTree( document, tree ); } @@ -167,27 +167,27 @@ void testMultipleSequentialEdits() { final String text1 = "@prefix ex: ."; applyChange( document, pos( 0, 0 ), pos( 0, 0 ), text1 ); - TSTree tree = parserService.getConcreteSyntaxTree( document ); + TSTree tree = parserService.apply( document ).concreteSyntaxTree(); assertThat( tree.getRootNode().hasError() ).isFalse(); final String text2 = "\n\nex:subject1 ex:predicate1 ex:object1 ."; applyChange( document, pos( 0, 35 ), pos( 0, 35 ), text2 ); - tree = parserService.getConcreteSyntaxTree( document ); + tree = parserService.apply( document ).concreteSyntaxTree(); assertThat( tree.getRootNode().hasError() ).isFalse(); assertThat( document.getContent() ).contains( "ex:subject1" ); final String text3 = "\nex:subject2 ex:predicate2 ex:object2 ."; applyChange( document, pos( 2, 38 ), pos( 2, 38 ), text3 ); - tree = parserService.getConcreteSyntaxTree( document ); + tree = parserService.apply( document ).concreteSyntaxTree(); assertThat( tree.getRootNode().hasError() ).isFalse(); assertThat( document.getContent() ).contains( "ex:subject1" ) .contains( "ex:subject2" ); applyChange( document, pos( 2, 0 ), pos( 2, 38 ), "" ); - tree = parserService.getConcreteSyntaxTree( document ); + tree = parserService.apply( document ).concreteSyntaxTree(); assertThat( tree.getRootNode().hasError() ).isFalse(); assertThat( document.getContent() ).doesNotContain( "ex:subject1" ); assertThat( document.getContent() ).contains( "ex:subject2" ); @@ -204,12 +204,12 @@ void testEditAcrossMultipleLines() { """; final Document document = new Document( "test.ttl", initialContent ); - parserService.getConcreteSyntaxTree( document ); + parserService.apply( document ).concreteSyntaxTree(); final String replacement = "ex:newPredicate"; applyChange( document, pos( 3, 2 ), pos( 4, 14 ), replacement ); - final TSTree tree = parserService.getConcreteSyntaxTree( document ); + final TSTree tree = parserService.apply( document ).concreteSyntaxTree(); System.out.println( TreeSitterUtil.print( tree, document ) ); assertThat( tree.getRootNode().hasError() ).isFalse(); assertThat( document.getContent() ).contains( "ex:newPredicate" ); @@ -232,22 +232,22 @@ void testParseValidSyntax() { ex:predicate5 "some langString"@en ; ex:predicate6 "123"^^xsd:decimal ; ex:predicate7 . - + a rdf:type . - + ex:subject2 ex:bla [ ex:blub true ; ] . - + ex:subject3 ex:bla ( 1 2 3 ) . - + ex:subject4 ex:bla \"""hello\""" . - + ex:subject5 ex:bla '''hello''' . """; final Document document = new Document( "test.ttl", initialContent ); - final TSTree tree = parserService.getConcreteSyntaxTree( document ); + final TSTree tree = parserService.apply( document ).concreteSyntaxTree(); System.out.println( TreeSitterUtil.print( tree, document ) ); assertThat( tree.getRootNode().hasError() ).isFalse(); } @@ -257,12 +257,12 @@ void testPrefixAddition() { final String initialContent = "ex:subject ex:predicate ex:object ."; final Document document = new Document( "test.ttl", initialContent ); - parserService.getConcreteSyntaxTree( document ); + parserService.apply( document ).concreteSyntaxTree(); final String prefix = "@prefix ex: .\n\n"; applyChange( document, pos( 0, 0 ), pos( 0, 0 ), prefix ); - final TSTree tree = parserService.getConcreteSyntaxTree( document ); + final TSTree tree = parserService.apply( document ).concreteSyntaxTree(); assertThat( tree.getRootNode().hasError() ).isFalse(); assertThat( document.getContent() ).startsWith( "@prefix ex:" ); } @@ -274,17 +274,17 @@ void testComplexEditSequence() { applyChange( document, pos( 0, 0 ), pos( 0, 0 ), "@base .\n@prefix ex: .\n\n" ); - tree = parserService.getConcreteSyntaxTree( document ); + tree = parserService.apply( document ).concreteSyntaxTree(); assertThat( tree.getRootNode().hasError() ).isFalse(); applyChange( document, pos( 3, 0 ), pos( 3, 0 ), "ex:subject ex:predicate ex:object ." ); - tree = parserService.getConcreteSyntaxTree( document ); + tree = parserService.apply( document ).concreteSyntaxTree(); assertThat( tree.getRootNode().hasError() ).isFalse(); applyChange( document, pos( 3, 33 ), pos( 3, 34 ), " ;\n ex:predicate2 ex:object2 ;\n ex:predicate3 ex:object3 ." ); - tree = parserService.getConcreteSyntaxTree( document ); + tree = parserService.apply( document ).concreteSyntaxTree(); assertThat( tree.getRootNode().hasError() ).isFalse(); final String content = document.getContent(); @@ -293,7 +293,7 @@ void testComplexEditSequence() { final int col = predicateStart - content.lastIndexOf( '\n', predicateStart ) - 1; applyChange( document, pos( line, col ), pos( line, col + 12 ), "ex:modified" ); - tree = parserService.getConcreteSyntaxTree( document ); + tree = parserService.apply( document ).concreteSyntaxTree(); assertThat( tree.getRootNode().hasError() ).isFalse(); assertThat( document.getContent() ).contains( "ex:modified" ); assertThat( document.getContent() ).doesNotContain( "ex:predicate2" ); @@ -312,13 +312,13 @@ void testInvalidSyntaxHandling() { final String initialContent = "@prefix ex: ."; final Document document = new Document( "test.ttl", initialContent ); - TSTree tree = parserService.getConcreteSyntaxTree( document ); + TSTree tree = parserService.apply( document ).concreteSyntaxTree(); assertThat( tree.getRootNode().hasError() ).isFalse(); final String invalidText = "\n\nthis is not valid turtle syntax @#$%"; applyChange( document, pos( 0, 35 ), pos( 0, 35 ), invalidText ); - tree = parserService.getConcreteSyntaxTree( document ); + tree = parserService.apply( document ).concreteSyntaxTree(); assertThat( tree.getRootNode() ).isNotNull(); // Tree-sitter should still parse it, but with errors assertThat( tree.getRootNode().hasError() ).isTrue(); @@ -329,7 +329,7 @@ void testFullDocumentChange() { final String initialContent = "@prefix ex: ."; final Document document = new Document( "test.ttl", initialContent ); - parserService.getConcreteSyntaxTree( document ); + parserService.apply( document ).concreteSyntaxTree(); final String newContent = """ @prefix rdf: . @prefix rdfs: . @@ -342,7 +342,7 @@ void testFullDocumentChange() { final Document newDocument = new Document( "test.ttl", newContent ); parserService.onChange( newDocument, change ); - final TSTree tree = parserService.getConcreteSyntaxTree( newDocument ); + final TSTree tree = parserService.apply( newDocument ).concreteSyntaxTree(); assertThat( tree.getRootNode().hasError() ).isFalse(); assertThat( newDocument.getContent() ).contains( "rdfs:" ); } @@ -351,13 +351,13 @@ void testFullDocumentChange() { void testWhitespaceOnlyChanges() { final String initialContent = "ex:subject ex:predicate ex:object."; final Document document = new Document( "test.ttl", initialContent ); - final TSTree oldTree = parserService.getConcreteSyntaxTree( document ); + final TSTree oldTree = parserService.apply( document ).concreteSyntaxTree(); final Range range = new Range( pos( 0, 33 ), pos( 0, 33 ) ); final TextDocumentContentChangeEvent change = new TextDocumentContentChangeEvent( range, " " ); document.update( range, " " ); parserService.onChange( document, change ); - final TSTree tree = parserService.getConcreteSyntaxTree( document ); + final TSTree tree = parserService.apply( document ).concreteSyntaxTree(); assertThat( tree.getRootNode().hasError() ).isFalse(); assertThat( document.getContent() ).endsWith( "object ." ); assertThat( oldTree.getRootNode().toString() ).isEqualTo( tree.getRootNode().toString() ); From aa914e6db00feb8a3da5e7c779c9acbdbc09c8cd Mon Sep 17 00:00:00 2001 From: Andreas Textor Date: Thu, 7 May 2026 08:33:38 +0200 Subject: [PATCH 12/41] Refactor Download and ProcessLauncher into separate util module This is necessary to resolve the cyclic dependency between esmf-tree-sitter (which needs the utils at build time) and esmf-aspect-meta-model-java (which needs to depend on tree sitter in order to load models from concrete syntax trees) --- core/esmf-aspect-meta-model-java/pom.xml | 4 ++ core/esmf-tree-sitter-turtle/pom.xml | 2 +- core/esmf-util/pom.xml | 63 +++++++++++++++++++ .../esmf/aspectmodel/resolver/Download.java | 8 +-- .../resolver/DownloadException.java | 24 +++++++ .../aspectmodel/resolver/ProxyConfig.java | 0 .../exceptions/ProcessExecutionException.java | 0 .../resolver/process/BinaryLauncher.java | 0 .../process/ExecutableJarLauncher.java | 0 .../resolver/process/OsProcessLauncher.java | 0 .../resolver/process/ProcessLauncher.java | 0 pom.xml | 6 ++ 12 files changed, 101 insertions(+), 6 deletions(-) create mode 100644 core/esmf-util/pom.xml rename core/{esmf-aspect-meta-model-java => esmf-util}/src/main/java/org/eclipse/esmf/aspectmodel/resolver/Download.java (91%) create mode 100644 core/esmf-util/src/main/java/org/eclipse/esmf/aspectmodel/resolver/DownloadException.java rename core/{esmf-aspect-meta-model-java => esmf-util}/src/main/java/org/eclipse/esmf/aspectmodel/resolver/ProxyConfig.java (100%) rename core/{esmf-aspect-meta-model-java => esmf-util}/src/main/java/org/eclipse/esmf/aspectmodel/resolver/exceptions/ProcessExecutionException.java (100%) rename core/{esmf-aspect-meta-model-java => esmf-util}/src/main/java/org/eclipse/esmf/aspectmodel/resolver/process/BinaryLauncher.java (100%) rename core/{esmf-aspect-meta-model-java => esmf-util}/src/main/java/org/eclipse/esmf/aspectmodel/resolver/process/ExecutableJarLauncher.java (100%) rename core/{esmf-aspect-meta-model-java => esmf-util}/src/main/java/org/eclipse/esmf/aspectmodel/resolver/process/OsProcessLauncher.java (100%) rename core/{esmf-aspect-meta-model-java => esmf-util}/src/main/java/org/eclipse/esmf/aspectmodel/resolver/process/ProcessLauncher.java (100%) diff --git a/core/esmf-aspect-meta-model-java/pom.xml b/core/esmf-aspect-meta-model-java/pom.xml index a0a23969d..ac78b1ed1 100644 --- a/core/esmf-aspect-meta-model-java/pom.xml +++ b/core/esmf-aspect-meta-model-java/pom.xml @@ -34,6 +34,10 @@ + + org.eclipse.esmf + esmf-util + org.eclipse.esmf esmf-semantic-aspect-meta-model diff --git a/core/esmf-tree-sitter-turtle/pom.xml b/core/esmf-tree-sitter-turtle/pom.xml index db70c78bb..e9fa944bf 100644 --- a/core/esmf-tree-sitter-turtle/pom.xml +++ b/core/esmf-tree-sitter-turtle/pom.xml @@ -54,7 +54,7 @@ org.eclipse.esmf - esmf-aspect-meta-model-java + esmf-util compile diff --git a/core/esmf-util/pom.xml b/core/esmf-util/pom.xml new file mode 100644 index 000000000..fef99db23 --- /dev/null +++ b/core/esmf-util/pom.xml @@ -0,0 +1,63 @@ + + + + + + org.eclipse.esmf + esmf-sdk-parent + DEV-SNAPSHOT + ../../pom.xml + + 4.0.0 + + esmf-util + ESMF Util + jar + + + + org.eclipse.esmf + esmf-aspect-meta-model-interface + + + org.slf4j + slf4j-api + + + io.soabase.record-builder + record-builder-processor + provided + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + + + io.soabase.record-builder + record-builder-processor + ${record-builder.version} + + + + + + + diff --git a/core/esmf-aspect-meta-model-java/src/main/java/org/eclipse/esmf/aspectmodel/resolver/Download.java b/core/esmf-util/src/main/java/org/eclipse/esmf/aspectmodel/resolver/Download.java similarity index 91% rename from core/esmf-aspect-meta-model-java/src/main/java/org/eclipse/esmf/aspectmodel/resolver/Download.java rename to core/esmf-util/src/main/java/org/eclipse/esmf/aspectmodel/resolver/Download.java index 2cd5ddc02..fe1e232b7 100644 --- a/core/esmf-aspect-meta-model-java/src/main/java/org/eclipse/esmf/aspectmodel/resolver/Download.java +++ b/core/esmf-util/src/main/java/org/eclipse/esmf/aspectmodel/resolver/Download.java @@ -25,8 +25,6 @@ import java.util.Map; import java.util.stream.Stream; -import org.eclipse.esmf.aspectmodel.resolver.exceptions.ModelResolutionException; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -94,7 +92,7 @@ public HttpResponse downloadFileAsResponse( final URL fileUrl, final Map final HttpRequest request = builder.build(); return client.send( request, HttpResponse.BodyHandlers.ofByteArray() ); } catch ( final InterruptedException | URISyntaxException | IOException exception ) { - throw new ModelResolutionException( "Could not retrieve " + fileUrl, exception ); + throw new DownloadException( "Could not retrieve " + fileUrl, exception ); } } @@ -125,10 +123,10 @@ public File downloadFile( final URL fileUrl, final Map headers, if ( httpResponse.statusCode() >= 200 && httpResponse.statusCode() < 300 ) { outputStream.write( httpResponse.body() ); } else { - throw new ModelResolutionException( "Could not download file (status code: " + httpResponse.statusCode() + ")" ); + throw new DownloadException( "Could not download file (status code: " + httpResponse.statusCode() + ")" ); } } catch ( final IOException exception ) { - throw new ModelResolutionException( "Could not write file " + outputFile, exception ); + throw new DownloadException( "Could not write file " + outputFile, exception ); } LOG.info( "Downloaded {} to local file {}", fileUrl.getPath(), outputFile ); diff --git a/core/esmf-util/src/main/java/org/eclipse/esmf/aspectmodel/resolver/DownloadException.java b/core/esmf-util/src/main/java/org/eclipse/esmf/aspectmodel/resolver/DownloadException.java new file mode 100644 index 000000000..7e336180f --- /dev/null +++ b/core/esmf-util/src/main/java/org/eclipse/esmf/aspectmodel/resolver/DownloadException.java @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2026 Robert Bosch Manufacturing Solutions GmbH + * + * See the AUTHORS file(s) distributed with this work for additional + * information regarding authorship. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * SPDX-License-Identifier: MPL-2.0 + */ + +package org.eclipse.esmf.aspectmodel.resolver; + +public class DownloadException extends RuntimeException { + public DownloadException( final String message ) { + super( message ); + } + + public DownloadException( final String message, final Throwable cause ) { + super( message, cause ); + } +} diff --git a/core/esmf-aspect-meta-model-java/src/main/java/org/eclipse/esmf/aspectmodel/resolver/ProxyConfig.java b/core/esmf-util/src/main/java/org/eclipse/esmf/aspectmodel/resolver/ProxyConfig.java similarity index 100% rename from core/esmf-aspect-meta-model-java/src/main/java/org/eclipse/esmf/aspectmodel/resolver/ProxyConfig.java rename to core/esmf-util/src/main/java/org/eclipse/esmf/aspectmodel/resolver/ProxyConfig.java diff --git a/core/esmf-aspect-meta-model-java/src/main/java/org/eclipse/esmf/aspectmodel/resolver/exceptions/ProcessExecutionException.java b/core/esmf-util/src/main/java/org/eclipse/esmf/aspectmodel/resolver/exceptions/ProcessExecutionException.java similarity index 100% rename from core/esmf-aspect-meta-model-java/src/main/java/org/eclipse/esmf/aspectmodel/resolver/exceptions/ProcessExecutionException.java rename to core/esmf-util/src/main/java/org/eclipse/esmf/aspectmodel/resolver/exceptions/ProcessExecutionException.java diff --git a/core/esmf-aspect-meta-model-java/src/main/java/org/eclipse/esmf/aspectmodel/resolver/process/BinaryLauncher.java b/core/esmf-util/src/main/java/org/eclipse/esmf/aspectmodel/resolver/process/BinaryLauncher.java similarity index 100% rename from core/esmf-aspect-meta-model-java/src/main/java/org/eclipse/esmf/aspectmodel/resolver/process/BinaryLauncher.java rename to core/esmf-util/src/main/java/org/eclipse/esmf/aspectmodel/resolver/process/BinaryLauncher.java diff --git a/core/esmf-aspect-meta-model-java/src/main/java/org/eclipse/esmf/aspectmodel/resolver/process/ExecutableJarLauncher.java b/core/esmf-util/src/main/java/org/eclipse/esmf/aspectmodel/resolver/process/ExecutableJarLauncher.java similarity index 100% rename from core/esmf-aspect-meta-model-java/src/main/java/org/eclipse/esmf/aspectmodel/resolver/process/ExecutableJarLauncher.java rename to core/esmf-util/src/main/java/org/eclipse/esmf/aspectmodel/resolver/process/ExecutableJarLauncher.java diff --git a/core/esmf-aspect-meta-model-java/src/main/java/org/eclipse/esmf/aspectmodel/resolver/process/OsProcessLauncher.java b/core/esmf-util/src/main/java/org/eclipse/esmf/aspectmodel/resolver/process/OsProcessLauncher.java similarity index 100% rename from core/esmf-aspect-meta-model-java/src/main/java/org/eclipse/esmf/aspectmodel/resolver/process/OsProcessLauncher.java rename to core/esmf-util/src/main/java/org/eclipse/esmf/aspectmodel/resolver/process/OsProcessLauncher.java diff --git a/core/esmf-aspect-meta-model-java/src/main/java/org/eclipse/esmf/aspectmodel/resolver/process/ProcessLauncher.java b/core/esmf-util/src/main/java/org/eclipse/esmf/aspectmodel/resolver/process/ProcessLauncher.java similarity index 100% rename from core/esmf-aspect-meta-model-java/src/main/java/org/eclipse/esmf/aspectmodel/resolver/process/ProcessLauncher.java rename to core/esmf-util/src/main/java/org/eclipse/esmf/aspectmodel/resolver/process/ProcessLauncher.java diff --git a/pom.xml b/pom.xml index e85e56579..cd0a89b63 100644 --- a/pom.xml +++ b/pom.xml @@ -49,6 +49,7 @@ + core/esmf-util core/esmf-aspect-meta-model-interface core/esmf-aspect-meta-model-java core/esmf-aspect-model-aas-generator @@ -88,6 +89,11 @@ + + org.eclipse.esmf + esmf-util + ${project.version} + org.eclipse.esmf esmf-aspect-meta-model-interface From 90fc6b1ff20770b68217d7412c26e5e2c983a8f3 Mon Sep 17 00:00:00 2001 From: Andreas Textor Date: Thu, 7 May 2026 08:48:43 +0200 Subject: [PATCH 13/41] Move util classes to reasonable packages --- .../esmf/aspectmodel/resolver/CommandExecutor.java | 8 ++++---- .../resolver/services/TurtleLoader.java | 14 ++++++++------ .../resolver/github/GitHubModelSource.java | 2 +- .../resolver/github/GithubModelSourceConfig.java | 2 +- .../org/eclipse/esmf/buildtime/DownloadZig.java | 8 ++++---- .../org/eclipse/esmf/buildtime/NativeCompile.java | 4 ++-- .../resolver => util/download}/Download.java | 4 ++-- .../download}/DownloadException.java | 2 +- .../resolver => util/download}/ProxyConfig.java | 4 ++-- .../resolver => util}/process/BinaryLauncher.java | 4 ++-- .../process/ExecutableJarLauncher.java | 4 ++-- .../process/OsProcessLauncher.java | 6 ++---- .../process}/ProcessExecutionException.java | 4 ++-- .../resolver => util}/process/ProcessLauncher.java | 6 ++---- .../eclipse/esmf/aspectmodel/AspectModelMojo.java | 2 +- .../namespacepackage/PackageImportCommand.java | 2 +- .../org/eclipse/esmf/MainClassProcessLauncher.java | 4 ++-- .../java/org/eclipse/esmf/SammCliAbstractTest.java | 2 +- .../org/eclipse/esmf/SammCliIntegrationTest.java | 6 +++--- .../test/java/org/eclipse/esmf/SammCliTest.java | 4 ++-- 20 files changed, 45 insertions(+), 47 deletions(-) rename core/esmf-util/src/main/java/org/eclipse/esmf/{aspectmodel/resolver => util/download}/Download.java (97%) rename core/esmf-util/src/main/java/org/eclipse/esmf/{aspectmodel/resolver => util/download}/DownloadException.java (93%) rename core/esmf-util/src/main/java/org/eclipse/esmf/{aspectmodel/resolver => util/download}/ProxyConfig.java (95%) rename core/esmf-util/src/main/java/org/eclipse/esmf/{aspectmodel/resolver => util}/process/BinaryLauncher.java (84%) rename core/esmf-util/src/main/java/org/eclipse/esmf/{aspectmodel/resolver => util}/process/ExecutableJarLauncher.java (93%) rename core/esmf-util/src/main/java/org/eclipse/esmf/{aspectmodel/resolver => util}/process/OsProcessLauncher.java (95%) rename core/esmf-util/src/main/java/org/eclipse/esmf/{aspectmodel/resolver/exceptions => util/process}/ProcessExecutionException.java (83%) rename core/esmf-util/src/main/java/org/eclipse/esmf/{aspectmodel/resolver => util}/process/ProcessLauncher.java (95%) diff --git a/core/esmf-aspect-meta-model-java/src/main/java/org/eclipse/esmf/aspectmodel/resolver/CommandExecutor.java b/core/esmf-aspect-meta-model-java/src/main/java/org/eclipse/esmf/aspectmodel/resolver/CommandExecutor.java index 848bf869a..076716662 100644 --- a/core/esmf-aspect-meta-model-java/src/main/java/org/eclipse/esmf/aspectmodel/resolver/CommandExecutor.java +++ b/core/esmf-aspect-meta-model-java/src/main/java/org/eclipse/esmf/aspectmodel/resolver/CommandExecutor.java @@ -18,10 +18,10 @@ import java.util.List; import java.util.Optional; -import org.eclipse.esmf.aspectmodel.resolver.exceptions.ProcessExecutionException; -import org.eclipse.esmf.aspectmodel.resolver.process.BinaryLauncher; -import org.eclipse.esmf.aspectmodel.resolver.process.ExecutableJarLauncher; -import org.eclipse.esmf.aspectmodel.resolver.process.ProcessLauncher; +import org.eclipse.esmf.util.process.ProcessExecutionException; +import org.eclipse.esmf.util.process.BinaryLauncher; +import org.eclipse.esmf.util.process.ExecutableJarLauncher; +import org.eclipse.esmf.util.process.ProcessLauncher; /** * Executes an external resolver via the underlying OS command and returns the stdout from the diff --git a/core/esmf-aspect-meta-model-java/src/main/java/org/eclipse/esmf/aspectmodel/resolver/services/TurtleLoader.java b/core/esmf-aspect-meta-model-java/src/main/java/org/eclipse/esmf/aspectmodel/resolver/services/TurtleLoader.java index 2369c9682..ae777796d 100644 --- a/core/esmf-aspect-meta-model-java/src/main/java/org/eclipse/esmf/aspectmodel/resolver/services/TurtleLoader.java +++ b/core/esmf-aspect-meta-model-java/src/main/java/org/eclipse/esmf/aspectmodel/resolver/services/TurtleLoader.java @@ -23,23 +23,25 @@ import java.util.Objects; import java.util.stream.Collectors; -import org.eclipse.esmf.aspectmodel.ValueParsingException; -import org.eclipse.esmf.aspectmodel.resolver.exceptions.ParserException; -import org.eclipse.esmf.aspectmodel.resolver.parser.ReaderRiotTurtle; -import org.eclipse.esmf.metamodel.datatype.SammXsdType; - -import io.vavr.control.Try; import org.apache.jena.rdf.model.Model; import org.apache.jena.riot.Lang; import org.apache.jena.riot.RDFParser; import org.apache.jena.riot.RDFParserRegistry; import org.apache.jena.riot.RiotException; import org.apache.jena.riot.system.FactoryRDFStd; + +import org.eclipse.esmf.aspectmodel.ValueParsingException; +import org.eclipse.esmf.aspectmodel.resolver.exceptions.ParserException; +import org.eclipse.esmf.aspectmodel.resolver.parser.ReaderRiotTurtle; +import org.eclipse.esmf.metamodel.datatype.SammXsdType; + import org.jspecify.annotations.NonNull; import org.jspecify.annotations.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import io.vavr.control.Try; + public final class TurtleLoader { private static final Logger LOG = LoggerFactory.getLogger( TurtleLoader.class ); diff --git a/core/esmf-aspect-model-github-resolver/src/main/java/org/eclipse/esmf/aspectmodel/resolver/github/GitHubModelSource.java b/core/esmf-aspect-model-github-resolver/src/main/java/org/eclipse/esmf/aspectmodel/resolver/github/GitHubModelSource.java index ea37b8b54..cda29b1c2 100644 --- a/core/esmf-aspect-model-github-resolver/src/main/java/org/eclipse/esmf/aspectmodel/resolver/github/GitHubModelSource.java +++ b/core/esmf-aspect-model-github-resolver/src/main/java/org/eclipse/esmf/aspectmodel/resolver/github/GitHubModelSource.java @@ -29,7 +29,7 @@ import org.eclipse.esmf.aspectmodel.AspectModelFile; import org.eclipse.esmf.aspectmodel.resolver.AspectModelFileLoader; -import org.eclipse.esmf.aspectmodel.resolver.Download; +import org.eclipse.esmf.util.download.Download; import org.eclipse.esmf.aspectmodel.resolver.GithubRepository; import org.eclipse.esmf.aspectmodel.resolver.ModelSource; import org.eclipse.esmf.aspectmodel.resolver.modelfile.RawAspectModelFile; diff --git a/core/esmf-aspect-model-github-resolver/src/main/java/org/eclipse/esmf/aspectmodel/resolver/github/GithubModelSourceConfig.java b/core/esmf-aspect-model-github-resolver/src/main/java/org/eclipse/esmf/aspectmodel/resolver/github/GithubModelSourceConfig.java index b68e601ac..1c9004643 100644 --- a/core/esmf-aspect-model-github-resolver/src/main/java/org/eclipse/esmf/aspectmodel/resolver/github/GithubModelSourceConfig.java +++ b/core/esmf-aspect-model-github-resolver/src/main/java/org/eclipse/esmf/aspectmodel/resolver/github/GithubModelSourceConfig.java @@ -16,7 +16,7 @@ import java.util.Optional; import org.eclipse.esmf.aspectmodel.resolver.GithubRepository; -import org.eclipse.esmf.aspectmodel.resolver.ProxyConfig; +import org.eclipse.esmf.util.download.ProxyConfig; import io.soabase.recordbuilder.core.RecordBuilder; diff --git a/core/esmf-tree-sitter-turtle/src-buildtime/main/java/org/eclipse/esmf/buildtime/DownloadZig.java b/core/esmf-tree-sitter-turtle/src-buildtime/main/java/org/eclipse/esmf/buildtime/DownloadZig.java index 0853fc048..56988889a 100644 --- a/core/esmf-tree-sitter-turtle/src-buildtime/main/java/org/eclipse/esmf/buildtime/DownloadZig.java +++ b/core/esmf-tree-sitter-turtle/src-buildtime/main/java/org/eclipse/esmf/buildtime/DownloadZig.java @@ -41,10 +41,10 @@ import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; -import org.eclipse.esmf.aspectmodel.resolver.Download; -import org.eclipse.esmf.aspectmodel.resolver.ProxyConfig; -import org.eclipse.esmf.aspectmodel.resolver.process.BinaryLauncher; -import org.eclipse.esmf.aspectmodel.resolver.process.ProcessLauncher; +import org.eclipse.esmf.util.download.Download; +import org.eclipse.esmf.util.download.ProxyConfig; +import org.eclipse.esmf.util.process.BinaryLauncher; +import org.eclipse.esmf.util.process.ProcessLauncher; public class DownloadZig extends ZigContext { private static final String ZIG_PUB_KEY = "RWSGOq2NVecA2UPNdBUZykf1CCb147pkmdtYxgb3Ti+JO/wCYvhbAb/U"; diff --git a/core/esmf-tree-sitter-turtle/src-buildtime/main/java/org/eclipse/esmf/buildtime/NativeCompile.java b/core/esmf-tree-sitter-turtle/src-buildtime/main/java/org/eclipse/esmf/buildtime/NativeCompile.java index 463657243..ec64a4905 100644 --- a/core/esmf-tree-sitter-turtle/src-buildtime/main/java/org/eclipse/esmf/buildtime/NativeCompile.java +++ b/core/esmf-tree-sitter-turtle/src-buildtime/main/java/org/eclipse/esmf/buildtime/NativeCompile.java @@ -22,8 +22,8 @@ import java.util.Optional; import java.util.stream.Stream; -import org.eclipse.esmf.aspectmodel.resolver.process.BinaryLauncher; -import org.eclipse.esmf.aspectmodel.resolver.process.ProcessLauncher; +import org.eclipse.esmf.util.process.BinaryLauncher; +import org.eclipse.esmf.util.process.ProcessLauncher; public class NativeCompile extends ZigContext { private static final String LIB_NAME = "tree-sitter-turtle"; diff --git a/core/esmf-util/src/main/java/org/eclipse/esmf/aspectmodel/resolver/Download.java b/core/esmf-util/src/main/java/org/eclipse/esmf/util/download/Download.java similarity index 97% rename from core/esmf-util/src/main/java/org/eclipse/esmf/aspectmodel/resolver/Download.java rename to core/esmf-util/src/main/java/org/eclipse/esmf/util/download/Download.java index fe1e232b7..d0df5d54c 100644 --- a/core/esmf-util/src/main/java/org/eclipse/esmf/aspectmodel/resolver/Download.java +++ b/core/esmf-util/src/main/java/org/eclipse/esmf/util/download/Download.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 Robert Bosch Manufacturing Solutions GmbH + * Copyright (c) 2026 Robert Bosch Manufacturing Solutions GmbH * * See the AUTHORS file(s) distributed with this work for additional * information regarding authorship. @@ -11,7 +11,7 @@ * SPDX-License-Identifier: MPL-2.0 */ -package org.eclipse.esmf.aspectmodel.resolver; +package org.eclipse.esmf.util.download; import java.io.File; import java.io.FileOutputStream; diff --git a/core/esmf-util/src/main/java/org/eclipse/esmf/aspectmodel/resolver/DownloadException.java b/core/esmf-util/src/main/java/org/eclipse/esmf/util/download/DownloadException.java similarity index 93% rename from core/esmf-util/src/main/java/org/eclipse/esmf/aspectmodel/resolver/DownloadException.java rename to core/esmf-util/src/main/java/org/eclipse/esmf/util/download/DownloadException.java index 7e336180f..243432a91 100644 --- a/core/esmf-util/src/main/java/org/eclipse/esmf/aspectmodel/resolver/DownloadException.java +++ b/core/esmf-util/src/main/java/org/eclipse/esmf/util/download/DownloadException.java @@ -11,7 +11,7 @@ * SPDX-License-Identifier: MPL-2.0 */ -package org.eclipse.esmf.aspectmodel.resolver; +package org.eclipse.esmf.util.download; public class DownloadException extends RuntimeException { public DownloadException( final String message ) { diff --git a/core/esmf-util/src/main/java/org/eclipse/esmf/aspectmodel/resolver/ProxyConfig.java b/core/esmf-util/src/main/java/org/eclipse/esmf/util/download/ProxyConfig.java similarity index 95% rename from core/esmf-util/src/main/java/org/eclipse/esmf/aspectmodel/resolver/ProxyConfig.java rename to core/esmf-util/src/main/java/org/eclipse/esmf/util/download/ProxyConfig.java index c2cfd702a..0eb557233 100644 --- a/core/esmf-util/src/main/java/org/eclipse/esmf/aspectmodel/resolver/ProxyConfig.java +++ b/core/esmf-util/src/main/java/org/eclipse/esmf/util/download/ProxyConfig.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 Robert Bosch Manufacturing Solutions GmbH + * Copyright (c) 2026 Robert Bosch Manufacturing Solutions GmbH * * See the AUTHORS file(s) distributed with this work for additional * information regarding authorship. @@ -11,7 +11,7 @@ * SPDX-License-Identifier: MPL-2.0 */ -package org.eclipse.esmf.aspectmodel.resolver; +package org.eclipse.esmf.util.download; import java.net.Authenticator; import java.net.InetSocketAddress; diff --git a/core/esmf-util/src/main/java/org/eclipse/esmf/aspectmodel/resolver/process/BinaryLauncher.java b/core/esmf-util/src/main/java/org/eclipse/esmf/util/process/BinaryLauncher.java similarity index 84% rename from core/esmf-util/src/main/java/org/eclipse/esmf/aspectmodel/resolver/process/BinaryLauncher.java rename to core/esmf-util/src/main/java/org/eclipse/esmf/util/process/BinaryLauncher.java index 506e77e9f..affe96f61 100644 --- a/core/esmf-util/src/main/java/org/eclipse/esmf/aspectmodel/resolver/process/BinaryLauncher.java +++ b/core/esmf-util/src/main/java/org/eclipse/esmf/util/process/BinaryLauncher.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025 Robert Bosch Manufacturing Solutions GmbH + * Copyright (c) 2026 Robert Bosch Manufacturing Solutions GmbH * * See the AUTHORS file(s) distributed with this work for additional * information regarding authorship. @@ -11,7 +11,7 @@ * SPDX-License-Identifier: MPL-2.0 */ -package org.eclipse.esmf.aspectmodel.resolver.process; +package org.eclipse.esmf.util.process; import java.io.File; import java.util.List; diff --git a/core/esmf-util/src/main/java/org/eclipse/esmf/aspectmodel/resolver/process/ExecutableJarLauncher.java b/core/esmf-util/src/main/java/org/eclipse/esmf/util/process/ExecutableJarLauncher.java similarity index 93% rename from core/esmf-util/src/main/java/org/eclipse/esmf/aspectmodel/resolver/process/ExecutableJarLauncher.java rename to core/esmf-util/src/main/java/org/eclipse/esmf/util/process/ExecutableJarLauncher.java index de2fe76fe..8fbf98aa4 100644 --- a/core/esmf-util/src/main/java/org/eclipse/esmf/aspectmodel/resolver/process/ExecutableJarLauncher.java +++ b/core/esmf-util/src/main/java/org/eclipse/esmf/util/process/ExecutableJarLauncher.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025 Robert Bosch Manufacturing Solutions GmbH + * Copyright (c) 2026 Robert Bosch Manufacturing Solutions GmbH * * See the AUTHORS file(s) distributed with this work for additional * information regarding authorship. @@ -11,7 +11,7 @@ * SPDX-License-Identifier: MPL-2.0 */ -package org.eclipse.esmf.aspectmodel.resolver.process; +package org.eclipse.esmf.util.process; import java.io.File; import java.util.ArrayList; diff --git a/core/esmf-util/src/main/java/org/eclipse/esmf/aspectmodel/resolver/process/OsProcessLauncher.java b/core/esmf-util/src/main/java/org/eclipse/esmf/util/process/OsProcessLauncher.java similarity index 95% rename from core/esmf-util/src/main/java/org/eclipse/esmf/aspectmodel/resolver/process/OsProcessLauncher.java rename to core/esmf-util/src/main/java/org/eclipse/esmf/util/process/OsProcessLauncher.java index 02f3100bf..9b37a276a 100644 --- a/core/esmf-util/src/main/java/org/eclipse/esmf/aspectmodel/resolver/process/OsProcessLauncher.java +++ b/core/esmf-util/src/main/java/org/eclipse/esmf/util/process/OsProcessLauncher.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025 Robert Bosch Manufacturing Solutions GmbH + * Copyright (c) 2026 Robert Bosch Manufacturing Solutions GmbH * * See the AUTHORS file(s) distributed with this work for additional * information regarding authorship. @@ -11,7 +11,7 @@ * SPDX-License-Identifier: MPL-2.0 */ -package org.eclipse.esmf.aspectmodel.resolver.process; +package org.eclipse.esmf.util.process; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; @@ -28,8 +28,6 @@ import java.util.concurrent.Future; import java.util.stream.Collectors; -import org.eclipse.esmf.aspectmodel.resolver.exceptions.ProcessExecutionException; - import org.apache.commons.io.IOUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/core/esmf-util/src/main/java/org/eclipse/esmf/aspectmodel/resolver/exceptions/ProcessExecutionException.java b/core/esmf-util/src/main/java/org/eclipse/esmf/util/process/ProcessExecutionException.java similarity index 83% rename from core/esmf-util/src/main/java/org/eclipse/esmf/aspectmodel/resolver/exceptions/ProcessExecutionException.java rename to core/esmf-util/src/main/java/org/eclipse/esmf/util/process/ProcessExecutionException.java index 766f853ad..5162dfb3c 100644 --- a/core/esmf-util/src/main/java/org/eclipse/esmf/aspectmodel/resolver/exceptions/ProcessExecutionException.java +++ b/core/esmf-util/src/main/java/org/eclipse/esmf/util/process/ProcessExecutionException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025 Robert Bosch Manufacturing Solutions GmbH + * Copyright (c) 2026 Robert Bosch Manufacturing Solutions GmbH * * See the AUTHORS file(s) distributed with this work for additional * information regarding authorship. @@ -11,7 +11,7 @@ * SPDX-License-Identifier: MPL-2.0 */ -package org.eclipse.esmf.aspectmodel.resolver.exceptions; +package org.eclipse.esmf.util.process; public class ProcessExecutionException extends RuntimeException { public ProcessExecutionException( final String message ) { diff --git a/core/esmf-util/src/main/java/org/eclipse/esmf/aspectmodel/resolver/process/ProcessLauncher.java b/core/esmf-util/src/main/java/org/eclipse/esmf/util/process/ProcessLauncher.java similarity index 95% rename from core/esmf-util/src/main/java/org/eclipse/esmf/aspectmodel/resolver/process/ProcessLauncher.java rename to core/esmf-util/src/main/java/org/eclipse/esmf/util/process/ProcessLauncher.java index 5a96519a5..5bd1d1864 100644 --- a/core/esmf-util/src/main/java/org/eclipse/esmf/aspectmodel/resolver/process/ProcessLauncher.java +++ b/core/esmf-util/src/main/java/org/eclipse/esmf/util/process/ProcessLauncher.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025 Robert Bosch Manufacturing Solutions GmbH + * Copyright (c) 2026 Robert Bosch Manufacturing Solutions GmbH * * See the AUTHORS file(s) distributed with this work for additional * information regarding authorship. @@ -11,7 +11,7 @@ * SPDX-License-Identifier: MPL-2.0 */ -package org.eclipse.esmf.aspectmodel.resolver.process; +package org.eclipse.esmf.util.process; import java.io.File; import java.util.Arrays; @@ -21,8 +21,6 @@ import java.util.function.Consumer; import java.util.function.Function; -import org.eclipse.esmf.aspectmodel.resolver.exceptions.ProcessExecutionException; - /** * This class abstracts running a "process", i.e. running a program by providing its arguments, * optional stdin and its working directory, and representing the output using exit status and diff --git a/tools/esmf-aspect-model-maven-plugin/src/main/java/org/eclipse/esmf/aspectmodel/AspectModelMojo.java b/tools/esmf-aspect-model-maven-plugin/src/main/java/org/eclipse/esmf/aspectmodel/AspectModelMojo.java index 58fb09059..72c3c6586 100644 --- a/tools/esmf-aspect-model-maven-plugin/src/main/java/org/eclipse/esmf/aspectmodel/AspectModelMojo.java +++ b/tools/esmf-aspect-model-maven-plugin/src/main/java/org/eclipse/esmf/aspectmodel/AspectModelMojo.java @@ -36,7 +36,7 @@ import org.eclipse.esmf.aspectmodel.loader.AspectModelLoader; import org.eclipse.esmf.aspectmodel.resolver.FileSystemStrategy; import org.eclipse.esmf.aspectmodel.resolver.GithubRepository; -import org.eclipse.esmf.aspectmodel.resolver.ProxyConfig; +import org.eclipse.esmf.util.download.ProxyConfig; import org.eclipse.esmf.aspectmodel.resolver.ResolutionStrategy; import org.eclipse.esmf.aspectmodel.resolver.github.GitHubStrategy; import org.eclipse.esmf.aspectmodel.resolver.github.GithubModelSourceConfig; diff --git a/tools/samm-cli/src/main/java/org/eclipse/esmf/namespacepackage/PackageImportCommand.java b/tools/samm-cli/src/main/java/org/eclipse/esmf/namespacepackage/PackageImportCommand.java index dc0784086..f9b9725ab 100644 --- a/tools/samm-cli/src/main/java/org/eclipse/esmf/namespacepackage/PackageImportCommand.java +++ b/tools/samm-cli/src/main/java/org/eclipse/esmf/namespacepackage/PackageImportCommand.java @@ -30,7 +30,7 @@ import org.eclipse.esmf.aspectmodel.edit.AspectChangeManagerConfig; import org.eclipse.esmf.aspectmodel.edit.AspectChangeManagerConfigBuilder; import org.eclipse.esmf.aspectmodel.edit.Change; -import org.eclipse.esmf.aspectmodel.resolver.Download; +import org.eclipse.esmf.util.download.Download; import org.eclipse.esmf.aspectmodel.resolver.NamespacePackage; import org.eclipse.esmf.aspectmodel.resolver.fs.ModelsRoot; import org.eclipse.esmf.exception.SubCommandException; diff --git a/tools/samm-cli/src/test/java/org/eclipse/esmf/MainClassProcessLauncher.java b/tools/samm-cli/src/test/java/org/eclipse/esmf/MainClassProcessLauncher.java index f63a02cd9..db3c6b288 100644 --- a/tools/samm-cli/src/test/java/org/eclipse/esmf/MainClassProcessLauncher.java +++ b/tools/samm-cli/src/test/java/org/eclipse/esmf/MainClassProcessLauncher.java @@ -19,8 +19,8 @@ import java.util.function.Predicate; import java.util.stream.Stream; -import org.eclipse.esmf.aspectmodel.resolver.process.OsProcessLauncher; -import org.eclipse.esmf.aspectmodel.resolver.process.ProcessLauncher; +import org.eclipse.esmf.util.process.OsProcessLauncher; +import org.eclipse.esmf.util.process.ProcessLauncher; /** * A {@link ProcessLauncher} that executes the static main(String[] args) function of a given class diff --git a/tools/samm-cli/src/test/java/org/eclipse/esmf/SammCliAbstractTest.java b/tools/samm-cli/src/test/java/org/eclipse/esmf/SammCliAbstractTest.java index af7a9e0b4..9c56016e7 100644 --- a/tools/samm-cli/src/test/java/org/eclipse/esmf/SammCliAbstractTest.java +++ b/tools/samm-cli/src/test/java/org/eclipse/esmf/SammCliAbstractTest.java @@ -23,7 +23,7 @@ import java.nio.file.Path; import java.util.stream.Stream; -import org.eclipse.esmf.aspectmodel.resolver.process.ProcessLauncher; +import org.eclipse.esmf.util.process.ProcessLauncher; import org.eclipse.esmf.samm.KnownVersion; import org.eclipse.esmf.test.InvalidTestAspect; import org.eclipse.esmf.test.OrderingTestAspect; diff --git a/tools/samm-cli/src/test/java/org/eclipse/esmf/SammCliIntegrationTest.java b/tools/samm-cli/src/test/java/org/eclipse/esmf/SammCliIntegrationTest.java index 17ca8aa94..2e9b84c9a 100644 --- a/tools/samm-cli/src/test/java/org/eclipse/esmf/SammCliIntegrationTest.java +++ b/tools/samm-cli/src/test/java/org/eclipse/esmf/SammCliIntegrationTest.java @@ -18,9 +18,9 @@ import java.io.File; import java.util.List; -import org.eclipse.esmf.aspectmodel.resolver.exceptions.ProcessExecutionException; -import org.eclipse.esmf.aspectmodel.resolver.process.ExecutableJarLauncher; -import org.eclipse.esmf.aspectmodel.resolver.process.ProcessLauncher; +import org.eclipse.esmf.util.process.ProcessExecutionException; +import org.eclipse.esmf.util.process.ExecutableJarLauncher; +import org.eclipse.esmf.util.process.ProcessLauncher; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestInstance; diff --git a/tools/samm-cli/src/test/java/org/eclipse/esmf/SammCliTest.java b/tools/samm-cli/src/test/java/org/eclipse/esmf/SammCliTest.java index 96f6e6652..89c7beae9 100644 --- a/tools/samm-cli/src/test/java/org/eclipse/esmf/SammCliTest.java +++ b/tools/samm-cli/src/test/java/org/eclipse/esmf/SammCliTest.java @@ -29,8 +29,8 @@ import java.util.regex.Pattern; import org.eclipse.esmf.aspectmodel.generator.jsonschema.AspectModelJsonSchemaGenerator; -import org.eclipse.esmf.aspectmodel.resolver.process.ProcessLauncher; -import org.eclipse.esmf.aspectmodel.resolver.process.ProcessLauncher.ExecutionResult; +import org.eclipse.esmf.util.process.ProcessLauncher; +import org.eclipse.esmf.util.process.ProcessLauncher.ExecutionResult; import org.eclipse.esmf.aspectmodel.urn.AspectModelUrn; import org.eclipse.esmf.aspectmodel.validation.InvalidSyntaxViolation; import org.eclipse.esmf.aspectmodel.validation.ProcessingViolation; From 7399a24e109a968bff2f7ed2350709fdd25f9328 Mon Sep 17 00:00:00 2001 From: Andreas Textor Date: Tue, 12 May 2026 07:37:05 +0200 Subject: [PATCH 14/41] Push Aspect Model violations results as diagnostics --- .development/esmf-checkstyle.xml | 2 +- .../aspectmodel/AspectLoadingException.java | 13 ++ core/esmf-aspect-meta-model-java/pom.xml | 4 + .../esmf/aspectmodel/loader/Instantiator.java | 19 +- .../resolver/AspectModelFileLoader.java | 28 ++- .../resolver/parser/ReaderRiotTurtle.java | 24 ++- .../resolver/parser/SmartToken.java | 127 +++++++++--- .../resolver/parser/TurtleParser.java | 1 - .../resolver/parser/TurtleParserProfile.java | 63 +++++- .../resolver/services/TurtleLoader.java | 41 +++- .../resolver/services/TurtleLoaderTest.java | 52 ++++- .../org/eclipse/esmf/test/TestResources.java | 14 ++ .../shacl/violation/Violation.java | 8 +- .../treesitterturtle/TreeSitterTurtle.java | 8 + .../treesitterturtle/TurtleSyntaxTree.java | 181 ++++++++++++++++++ .../esmf/turtle/languageserver/App.java | 4 +- .../service/AspectModelValidationService.java | 63 +++--- 17 files changed, 562 insertions(+), 90 deletions(-) create mode 100644 core/esmf-tree-sitter-turtle/src/main/java/org/eclipse/esmf/treesitterturtle/TurtleSyntaxTree.java diff --git a/.development/esmf-checkstyle.xml b/.development/esmf-checkstyle.xml index f927584fc..71838114b 100644 --- a/.development/esmf-checkstyle.xml +++ b/.development/esmf-checkstyle.xml @@ -191,7 +191,7 @@ value="Local variable name ''{0}'' must match pattern ''{1}''."/> - + diff --git a/core/esmf-aspect-meta-model-interface/src/main/java/org/eclipse/esmf/aspectmodel/AspectLoadingException.java b/core/esmf-aspect-meta-model-interface/src/main/java/org/eclipse/esmf/aspectmodel/AspectLoadingException.java index c4b8c7956..d99ad93a6 100644 --- a/core/esmf-aspect-meta-model-interface/src/main/java/org/eclipse/esmf/aspectmodel/AspectLoadingException.java +++ b/core/esmf-aspect-meta-model-interface/src/main/java/org/eclipse/esmf/aspectmodel/AspectLoadingException.java @@ -13,18 +13,31 @@ package org.eclipse.esmf.aspectmodel; +import org.apache.jena.rdf.model.RDFNode; +import org.jspecify.annotations.Nullable; + public class AspectLoadingException extends RuntimeException { private static final long serialVersionUID = 7687644022103150329L; + private final @Nullable RDFNode highlightElement; + public AspectLoadingException( final Throwable cause ) { super( cause ); + highlightElement = null; } public AspectLoadingException( final String message ) { super( message ); + highlightElement = null; } public AspectLoadingException( final String message, final Throwable cause ) { super( message, cause ); + highlightElement = null; + } + + public AspectLoadingException( final String message, final RDFNode highlightElement ) { + super( message ); + this.highlightElement = highlightElement; } } diff --git a/core/esmf-aspect-meta-model-java/pom.xml b/core/esmf-aspect-meta-model-java/pom.xml index ac78b1ed1..2ee6a02b7 100644 --- a/core/esmf-aspect-meta-model-java/pom.xml +++ b/core/esmf-aspect-meta-model-java/pom.xml @@ -46,6 +46,10 @@ org.eclipse.esmf esmf-aspect-meta-model-interface + + org.eclipse.esmf + esmf-tree-sitter-turtle + org.apache.commons commons-text diff --git a/core/esmf-aspect-meta-model-java/src/main/java/org/eclipse/esmf/aspectmodel/loader/Instantiator.java b/core/esmf-aspect-meta-model-java/src/main/java/org/eclipse/esmf/aspectmodel/loader/Instantiator.java index c9c151551..6ce6175cd 100644 --- a/core/esmf-aspect-meta-model-java/src/main/java/org/eclipse/esmf/aspectmodel/loader/Instantiator.java +++ b/core/esmf-aspect-meta-model-java/src/main/java/org/eclipse/esmf/aspectmodel/loader/Instantiator.java @@ -23,6 +23,14 @@ import java.util.stream.Collectors; import java.util.stream.Stream; +import org.apache.jena.rdf.model.Literal; +import org.apache.jena.rdf.model.Model; +import org.apache.jena.rdf.model.RDFList; +import org.apache.jena.rdf.model.RDFNode; +import org.apache.jena.rdf.model.Resource; +import org.apache.jena.rdf.model.Statement; +import org.apache.jena.vocabulary.RDF; + import org.eclipse.esmf.aspectmodel.AspectLoadingException; import org.eclipse.esmf.aspectmodel.RdfUtil; import org.eclipse.esmf.aspectmodel.urn.AspectModelUrn; @@ -44,14 +52,6 @@ import org.eclipse.esmf.metamodel.vocabulary.SAMM; import org.eclipse.esmf.metamodel.vocabulary.SammNs; -import org.apache.jena.rdf.model.Literal; -import org.apache.jena.rdf.model.Model; -import org.apache.jena.rdf.model.RDFList; -import org.apache.jena.rdf.model.RDFNode; -import org.apache.jena.rdf.model.Resource; -import org.apache.jena.rdf.model.Statement; -import org.apache.jena.vocabulary.RDF; - public abstract class Instantiator extends AttributeValueRetriever implements Function { protected final ModelElementFactory modelElementFactory; protected Class targetClass; @@ -128,7 +128,8 @@ private Statement getDataType( final Resource resource ) { final Statement dataType = resource.getProperty( SammNs.SAMM.dataType() ); if ( dataType == null ) { throw new AspectLoadingException( - String.format( "No datatype is defined on the Characteristic instance '%s: '.", resource.getLocalName() ) ); + String.format( "No datatype is defined on the Characteristic instance '%s: '.", resource.getLocalName() ), + resource ); } return dataType; } ); diff --git a/core/esmf-aspect-meta-model-java/src/main/java/org/eclipse/esmf/aspectmodel/resolver/AspectModelFileLoader.java b/core/esmf-aspect-meta-model-java/src/main/java/org/eclipse/esmf/aspectmodel/resolver/AspectModelFileLoader.java index c763f8383..f63aa40f9 100644 --- a/core/esmf-aspect-meta-model-java/src/main/java/org/eclipse/esmf/aspectmodel/resolver/AspectModelFileLoader.java +++ b/core/esmf-aspect-meta-model-java/src/main/java/org/eclipse/esmf/aspectmodel/resolver/AspectModelFileLoader.java @@ -32,15 +32,19 @@ import java.util.List; import java.util.Optional; +import org.apache.jena.rdf.model.Model; + import org.eclipse.esmf.aspectmodel.RdfUtil; import org.eclipse.esmf.aspectmodel.loader.AspectModelLoader; import org.eclipse.esmf.aspectmodel.resolver.exceptions.ModelResolutionException; import org.eclipse.esmf.aspectmodel.resolver.exceptions.ParserException; import org.eclipse.esmf.aspectmodel.resolver.modelfile.RawAspectModelFile; import org.eclipse.esmf.aspectmodel.resolver.services.TurtleLoader; +import org.eclipse.esmf.treesitterturtle.ParserTokenType; +import org.eclipse.esmf.treesitterturtle.TurtleSyntaxTree; +import org.eclipse.esmf.util.download.Download; import io.vavr.control.Try; -import org.apache.jena.rdf.model.Model; /** * Loads an input source into a {@link RawAspectModelFile}, i.e., an Aspect Model file that does not @@ -89,6 +93,18 @@ public static RawAspectModelFile load( final String rdfTurtle, final URI sourceL return new RawAspectModelFile( rdfTurtle, model, headerComment, Optional.of( sourceLocation ) ); } + public static RawAspectModelFile load( final TurtleSyntaxTree syntaxTree, final URI sourceLocation ) { + final String sourceRepresentation = syntaxTree.sourceRepresentationSupplier().get(); + final List headerComment = headerComment( syntaxTree ); + final Try tryModel = TurtleLoader.loadTurtle( syntaxTree, sourceLocation ); + if ( tryModel.isFailure() && tryModel.getCause() instanceof final ParserException parserException ) { + throw parserException; + } + final Model model = tryModel.getOrElseThrow( + () -> new ModelResolutionException( "Can not load model", tryModel.getCause() ) ); + return new RawAspectModelFile( sourceRepresentation, model, headerComment, Optional.of( sourceLocation ) ); + } + /** * Loads the content of an AspectModelFile from an input stream * @@ -191,6 +207,16 @@ private static List headerComment( final String content ) { .toList(); } + private static List headerComment( final TurtleSyntaxTree turtleSyntaxTree ) { + return turtleSyntaxTree.tokens() + .filter( token -> !token.type().equals( ParserTokenType.DOCUMENT ) ) + .takeWhile( token -> token.type().equals( ParserTokenType.COMMENT ) ) + .map( TurtleSyntaxTree.Token::content ) + .dropWhile( String::isBlank ) + .map( line -> line.substring( 1 ).trim() ) + .toList(); + } + private static URI buildArtificialUri( final Object object, final String objectType ) { return URI.create( "inmemory:%s:%s".formatted( objectType, object.hashCode() ) ); } diff --git a/core/esmf-aspect-meta-model-java/src/main/java/org/eclipse/esmf/aspectmodel/resolver/parser/ReaderRiotTurtle.java b/core/esmf-aspect-meta-model-java/src/main/java/org/eclipse/esmf/aspectmodel/resolver/parser/ReaderRiotTurtle.java index aa0abe41e..c46f1472b 100644 --- a/core/esmf-aspect-meta-model-java/src/main/java/org/eclipse/esmf/aspectmodel/resolver/parser/ReaderRiotTurtle.java +++ b/core/esmf-aspect-meta-model-java/src/main/java/org/eclipse/esmf/aspectmodel/resolver/parser/ReaderRiotTurtle.java @@ -26,28 +26,36 @@ import org.apache.jena.riot.tokens.TokenizerText; import org.apache.jena.sparql.util.Context; +import org.eclipse.esmf.aspectmodel.resolver.services.TurtleLoader; +import org.eclipse.esmf.treesitterturtle.TurtleSyntaxTree; + public class ReaderRiotTurtle implements ReaderRIOT { public static ReaderRIOTFactory factory = ReaderRiotTurtle::new; - - private final Lang lang; private final ParserProfile parserProfile; ReaderRiotTurtle( final Lang lang, final ParserProfile parserProfile ) { - this.lang = lang; - this.parserProfile = new TurtleParserProfile( parserProfile ); + this.parserProfile = parserProfile; } @Override public void read( final InputStream in, final String baseUri, final ContentType ct, final StreamRDF output, final Context context ) { - final TurtleTokenizer tokenizer = new TurtleTokenizer( in, parserProfile.getErrorHandler() ); - final TurtleParser parser = TurtleParser.create( tokenizer, parserProfile, output ); + final TurtleSyntaxTree syntaxTree = context != null && context.get( TurtleLoader.TREE_SITTER_SYNTAX_TREE ) != null + ? context.get( TurtleLoader.TREE_SITTER_SYNTAX_TREE ) + : null; + final ParserProfile wrappedParserProfile = new TurtleParserProfile( parserProfile, syntaxTree ); + final TurtleTokenizer tokenizer = new TurtleTokenizer( in, wrappedParserProfile.getErrorHandler() ); + final TurtleParser parser = TurtleParser.create( tokenizer, wrappedParserProfile, output ); parser.parse(); } @Override public void read( final Reader in, final String baseUri, final ContentType ct, final StreamRDF output, final Context context ) { - final Tokenizer tokenizer = TokenizerText.create().source( in ).errorHandler( parserProfile.getErrorHandler() ).build(); - final TurtleParser parser = TurtleParser.create( tokenizer, parserProfile, output ); + final TurtleSyntaxTree syntaxTree = context != null && context.get( TurtleLoader.TREE_SITTER_SYNTAX_TREE ) != null + ? context.get( TurtleLoader.TREE_SITTER_SYNTAX_TREE ) + : null; + final ParserProfile wrappedParserProfile = new TurtleParserProfile( parserProfile, syntaxTree ); + final Tokenizer tokenizer = TokenizerText.create().source( in ).errorHandler( wrappedParserProfile.getErrorHandler() ).build(); + final TurtleParser parser = TurtleParser.create( tokenizer, wrappedParserProfile, output ); parser.parse(); } } diff --git a/core/esmf-aspect-meta-model-java/src/main/java/org/eclipse/esmf/aspectmodel/resolver/parser/SmartToken.java b/core/esmf-aspect-meta-model-java/src/main/java/org/eclipse/esmf/aspectmodel/resolver/parser/SmartToken.java index f18020229..e3512e009 100644 --- a/core/esmf-aspect-meta-model-java/src/main/java/org/eclipse/esmf/aspectmodel/resolver/parser/SmartToken.java +++ b/core/esmf-aspect-meta-model-java/src/main/java/org/eclipse/esmf/aspectmodel/resolver/parser/SmartToken.java @@ -16,28 +16,38 @@ import java.util.Objects; import java.util.Optional; -import org.eclipse.esmf.aspectmodel.AspectModelFile; - import org.apache.jena.riot.tokens.Token; import org.apache.jena.riot.tokens.TokenType; +import org.eclipse.esmf.aspectmodel.AspectModelFile; +import org.eclipse.esmf.treesitterturtle.TurtleSyntaxTree; + +import org.jspecify.annotations.Nullable; + /** * Wrapper class for a {@link Token}. This provides access to the actual string representation of * the token, 1-based line and column information. */ public final class SmartToken { - private final Token token; + private final Token jenaToken; + private final TurtleSyntaxTree.Token treesitterToken; private AspectModelFile originatingFile; /** - * @param token the token + * @param jenaToken the token */ - public SmartToken( final Token token ) { - this.token = token; + public SmartToken( final Token jenaToken ) { + this.jenaToken = jenaToken; + treesitterToken = null; + } + + public SmartToken( final TurtleSyntaxTree.Token treesitterToken ) { + jenaToken = null; + this.treesitterToken = treesitterToken; } - public TokenType type() { - return token.getType(); + public @Nullable TokenType type() { + return jenaToken.getType(); } /** @@ -46,7 +56,10 @@ public TokenType type() { * @return the lexical representation */ public String image() { - return token.getImage(); + if ( jenaToken != null ) { + return jenaToken.getImage(); + } + return treesitterToken.content(); } /** @@ -55,15 +68,24 @@ public String image() { * @return the lexical representation */ public String image2() { - return token.getImage2(); + if ( jenaToken != null ) { + return jenaToken.getImage2(); + } + return ""; } - public Token subToken1() { - return token.getSubToken1(); + public @Nullable Token subToken1() { + if ( jenaToken != null ) { + return jenaToken.getSubToken1(); + } + return null; } - public Token subToken2() { - return token.getSubToken2(); + public @Nullable Token subToken2() { + if ( jenaToken != null ) { + return jenaToken.getSubToken2(); + } + return null; } /** @@ -72,16 +94,46 @@ public Token subToken2() { * @return the line */ public int line() { - return (int) token.getLine(); + if ( jenaToken != null ) { + return (int) jenaToken.getLine(); + } + return treesitterToken.location().fromLine() + 1; } /** - * The column of the token, 1-based. * + * The column of the token, 1-based. * * @return the column */ public int column() { - return (int) token.getColumn(); + if ( jenaToken != null ) { + return (int) jenaToken.getColumn(); + } + return treesitterToken.location().fromColumn() + 1; + } + + /** + * The line where the token ends, 1-based. + * + * @return the line + */ + public int toLine() { + if ( jenaToken != null ) { + return line(); + } + return treesitterToken.location().toLine() + 1; + } + + /** + * The column where the token ends, 1-based. + * + * @return the colum + */ + public int toColumn() { + if ( jenaToken != null ) { + return column() + content().length(); + } + return treesitterToken.location().toColumn() + 1; } /** @@ -93,11 +145,15 @@ public int column() { * @return the token's effective content */ public String content() { - return switch ( token.getType() ) { - case IRI -> "<" + token.getImage() + ">"; - case DIRECTIVE -> "@" + token.getImage(); + if ( treesitterToken != null ) { + return treesitterToken.content(); + } + // For Jena, only an approximation of the token can be provided + return switch ( jenaToken.getType() ) { + case IRI -> "<" + jenaToken.getImage() + ">"; + case DIRECTIVE -> "@" + jenaToken.getImage(); case PREFIXED_NAME -> - Optional.ofNullable( token.getImage() ).orElse( "" ) + ":" + Optional.ofNullable( token.getImage2() ).orElse( "" ); + Optional.ofNullable( jenaToken.getImage() ).orElse( "" ) + ":" + Optional.ofNullable( jenaToken.getImage2() ).orElse( "" ); case LT -> "<"; case GT -> ">"; case LE -> "<="; @@ -122,16 +178,17 @@ public String content() { case STAR -> "*"; case SLASH -> "/"; case RSLASH -> "\\"; - case STRING -> "\"" + token.getImage() + "\""; - case LITERAL_LANG -> String.format( "\"%s\"@%s", token.getImage(), token.getImage2() ); + case STRING -> "\"" + jenaToken.getImage() + "\""; + case LITERAL_LANG -> String.format( "\"%s\"@%s", jenaToken.getImage(), jenaToken.getImage2() ); case LITERAL_DT -> - String.format( "\"%s\"^^%s:%s", token.getImage(), token.getSubToken2().getImage(), token.getSubToken2().getImage2() ); - default -> token.getImage(); + String.format( "\"%s\"^^%s:%s", jenaToken.getImage(), jenaToken.getSubToken2().getImage(), + jenaToken.getSubToken2().getImage2() ); + default -> jenaToken.getImage(); }; } public Token token() { - return token; + return jenaToken; } @Override @@ -143,21 +200,29 @@ public boolean equals( final Object obj ) { return false; } final var that = (SmartToken) obj; - return Objects.equals( token, that.token ); + return jenaToken != null + ? Objects.equals( jenaToken, that.jenaToken ) + : Objects.equals( treesitterToken, that.treesitterToken ); } @Override public int hashCode() { - return Objects.hash( token ); + return Objects.hash( jenaToken ); } @Override public String toString() { - return "SmartToken[token=" + token + ']'; + return jenaToken != null + ? "SmartToken[jenaToken=" + jenaToken + ']' + : "SmartToken[treesitterToken=" + treesitterToken + ']'; + } + + public Token getJenaToken() { + return jenaToken; } - public Token getToken() { - return token; + public TurtleSyntaxTree.Token getTreesitterToken() { + return treesitterToken; } public AspectModelFile getOriginatingFile() { diff --git a/core/esmf-aspect-meta-model-java/src/main/java/org/eclipse/esmf/aspectmodel/resolver/parser/TurtleParser.java b/core/esmf-aspect-meta-model-java/src/main/java/org/eclipse/esmf/aspectmodel/resolver/parser/TurtleParser.java index e12ba5263..9fb8bffac 100644 --- a/core/esmf-aspect-meta-model-java/src/main/java/org/eclipse/esmf/aspectmodel/resolver/parser/TurtleParser.java +++ b/core/esmf-aspect-meta-model-java/src/main/java/org/eclipse/esmf/aspectmodel/resolver/parser/TurtleParser.java @@ -19,7 +19,6 @@ import org.apache.jena.riot.tokens.Tokenizer; public class TurtleParser extends LangTurtle { - private TurtleParser( final Tokenizer tokenizer, final ParserProfile parserProfile, final StreamRDF output ) { super( tokenizer, parserProfile, output ); } diff --git a/core/esmf-aspect-meta-model-java/src/main/java/org/eclipse/esmf/aspectmodel/resolver/parser/TurtleParserProfile.java b/core/esmf-aspect-meta-model-java/src/main/java/org/eclipse/esmf/aspectmodel/resolver/parser/TurtleParserProfile.java index 21692680e..4bc0b644f 100644 --- a/core/esmf-aspect-meta-model-java/src/main/java/org/eclipse/esmf/aspectmodel/resolver/parser/TurtleParserProfile.java +++ b/core/esmf-aspect-meta-model-java/src/main/java/org/eclipse/esmf/aspectmodel/resolver/parser/TurtleParserProfile.java @@ -13,8 +13,6 @@ package org.eclipse.esmf.aspectmodel.resolver.parser; -import org.eclipse.esmf.aspectmodel.ValueParsingException; - import org.apache.jena.datatypes.RDFDatatype; import org.apache.jena.graph.Graph; import org.apache.jena.graph.Node; @@ -28,16 +26,26 @@ import org.apache.jena.riot.tokens.TokenType; import org.apache.jena.sparql.core.Quad; +import org.eclipse.esmf.aspectmodel.ValueParsingException; +import org.eclipse.esmf.treesitterturtle.TurtleSyntaxTree; + +import org.jspecify.annotations.Nullable; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * Customized parser profile that delegates to Jena's built-in Node generation but also registers * the nodes in the {@link TokenRegistry}, where information about the line/column/token can be * retrieved at a later time. */ public class TurtleParserProfile implements ParserProfile { + private static final Logger LOG = LoggerFactory.getLogger( TurtleParserProfile.class ); private final ParserProfile parserProfile; + private final @Nullable TurtleSyntaxTree syntaxTree; - public TurtleParserProfile( final ParserProfile parserProfile ) { + public TurtleParserProfile( final ParserProfile parserProfile, final @Nullable TurtleSyntaxTree syntaxTree ) { this.parserProfile = parserProfile; + this.syntaxTree = syntaxTree; } @Override @@ -45,11 +53,58 @@ public String getBaseURI() { return parserProfile.getBaseURI(); } + /** + * Finds the matching Tree-sitter token for a given Jena token based on line and column position. + * If no exact match is found, returns the nearest token. + * + * @param token the Jena token to find a match for + * @return the matching Tree-sitter token, or null if syntax tree is not available or no tokens + * found + */ + private TurtleSyntaxTree.@Nullable Token findMatchingTreeSitterToken( final Token token ) { + if ( syntaxTree == null ) { + return null; + } + + final long targetLine = token.getLine() - 1; + final long targetColumn = token.getColumn(); + + TurtleSyntaxTree.Token exactMatch = null; + TurtleSyntaxTree.Token nearestMatch = null; + long minDistance = Long.MAX_VALUE; + + // Iterate through all tokens in the syntax tree + for ( final TurtleSyntaxTree.Token treeToken : syntaxTree.tokens().toList() ) { + final int tokenLine = treeToken.location().fromLine(); + final int tokenColumn = treeToken.location().fromColumn(); + + // Check for exact match + if ( tokenLine == targetLine && tokenColumn == targetColumn ) { + exactMatch = treeToken; + break; + } + + // Calculate Manhattan distance for nearest match + final long distance = Math.abs( tokenLine - targetLine ) * 1000 + Math.abs( tokenColumn - targetColumn ); + + if ( distance < minDistance ) { + minDistance = distance; + nearestMatch = treeToken; + } + } + + return exactMatch != null ? exactMatch : nearestMatch; + } + @Override public Node create( final Node currentGraph, final Token token ) { try { final Node node = parserProfile.create( currentGraph, token ); - TokenRegistry.put( node, new SmartToken( token ) ); + final TurtleSyntaxTree.@Nullable Token treeSitterToken = findMatchingTreeSitterToken( token ); + final SmartToken smartToken = treeSitterToken == null + ? new SmartToken( token ) + : new SmartToken( treeSitterToken ); + TokenRegistry.put( node, smartToken ); return node; } catch ( final ValueParsingException exception ) { exception.setLine( token.getLine() ); diff --git a/core/esmf-aspect-meta-model-java/src/main/java/org/eclipse/esmf/aspectmodel/resolver/services/TurtleLoader.java b/core/esmf-aspect-meta-model-java/src/main/java/org/eclipse/esmf/aspectmodel/resolver/services/TurtleLoader.java index ae777796d..c93a03d81 100644 --- a/core/esmf-aspect-meta-model-java/src/main/java/org/eclipse/esmf/aspectmodel/resolver/services/TurtleLoader.java +++ b/core/esmf-aspect-meta-model-java/src/main/java/org/eclipse/esmf/aspectmodel/resolver/services/TurtleLoader.java @@ -23,17 +23,21 @@ import java.util.Objects; import java.util.stream.Collectors; +import org.apache.commons.io.IOUtils; import org.apache.jena.rdf.model.Model; import org.apache.jena.riot.Lang; import org.apache.jena.riot.RDFParser; import org.apache.jena.riot.RDFParserRegistry; import org.apache.jena.riot.RiotException; import org.apache.jena.riot.system.FactoryRDFStd; +import org.apache.jena.sparql.util.Context; +import org.apache.jena.sparql.util.Symbol; import org.eclipse.esmf.aspectmodel.ValueParsingException; import org.eclipse.esmf.aspectmodel.resolver.exceptions.ParserException; import org.eclipse.esmf.aspectmodel.resolver.parser.ReaderRiotTurtle; import org.eclipse.esmf.metamodel.datatype.SammXsdType; +import org.eclipse.esmf.treesitterturtle.TurtleSyntaxTree; import org.jspecify.annotations.NonNull; import org.jspecify.annotations.Nullable; @@ -44,13 +48,11 @@ public final class TurtleLoader { private static final Logger LOG = LoggerFactory.getLogger( TurtleLoader.class ); - private static volatile boolean isTurtleRegistered = false; private TurtleLoader() {} public static void init() { - SammXsdType.setupTypeMapping(); registerTurtle(); } @@ -116,6 +118,40 @@ public static Try loadTurtle( @NonNull final String modelContent, @Nullab } } + public static class TreeSitterTurtleSyntaxTreeSymbol extends Symbol { + protected TreeSitterTurtleSyntaxTreeSymbol() { + super( "treesittersyntaxtree" ); + } + } + + public static final Symbol TREE_SITTER_SYNTAX_TREE = new TreeSitterTurtleSyntaxTreeSymbol(); + + public static Try loadTurtle( final TurtleSyntaxTree syntaxTree, final URI location ) { + init(); + final String sourceRepresentation = syntaxTree.sourceRepresentationSupplier().get(); + try ( final InputStream input = IOUtils.toInputStream( sourceRepresentation, StandardCharsets.UTF_8 ) ) { + final Context context = Context.create(); + context.put( new TreeSitterTurtleSyntaxTreeSymbol(), syntaxTree ); + final Model streamModel = RDFParser.create() + .factory( new FactoryRDFStd() ) + .source( input ) + .lang( Lang.TURTLE ) + .context( context ) + .toModel(); + return Try.success( streamModel ); + } catch ( final ValueParsingException exception ) { + // This is thrown by the custom value parsers in SammXsdType + exception.setSourceDocument( sourceRepresentation ); + exception.setSourceLocation( location ); + throw exception; + } catch ( final RiotException exception ) { + // Thrown by Jena for regular syntax errors + return Try.failure( new ParserException( exception, sourceRepresentation, location ) ); + } catch ( final IOException exception ) { + return Try.failure( exception ); + } + } + /** * Loads a Turtle model from a String containing RDF/Turtle * @@ -132,6 +168,7 @@ private static void registerTurtle() { } synchronized ( TurtleLoader.class ) { if ( !isTurtleRegistered ) { + SammXsdType.setupTypeMapping(); RDFParserRegistry.registerLangTriples( Lang.TURTLE, ReaderRiotTurtle.factory ); isTurtleRegistered = true; } diff --git a/core/esmf-aspect-meta-model-java/src/test/java/org/eclipse/esmf/aspectmodel/resolver/services/TurtleLoaderTest.java b/core/esmf-aspect-meta-model-java/src/test/java/org/eclipse/esmf/aspectmodel/resolver/services/TurtleLoaderTest.java index f4af86f27..4d2b36a7a 100644 --- a/core/esmf-aspect-meta-model-java/src/test/java/org/eclipse/esmf/aspectmodel/resolver/services/TurtleLoaderTest.java +++ b/core/esmf-aspect-meta-model-java/src/test/java/org/eclipse/esmf/aspectmodel/resolver/services/TurtleLoaderTest.java @@ -20,16 +20,26 @@ import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; +import java.net.URI; import java.nio.charset.StandardCharsets; -import org.eclipse.esmf.aspectmodel.resolver.exceptions.ParserException; - -import io.vavr.control.Try; import org.apache.jena.rdf.model.Model; import org.apache.jena.rdf.model.ModelFactory; import org.apache.jena.riot.RDFLanguages; import org.apache.jena.riot.RiotException; + +import org.eclipse.esmf.aspectmodel.resolver.exceptions.ParserException; +import org.eclipse.esmf.test.InvalidTestAspect; +import org.eclipse.esmf.test.TestAspect; +import org.eclipse.esmf.test.TestResources; +import org.eclipse.esmf.treesitterturtle.TreeSitterTurtle; +import org.eclipse.esmf.treesitterturtle.TurtleSyntaxTree; + import org.junit.jupiter.api.Test; +import org.treesitter.TSParser; +import org.treesitter.TSTree; + +import io.vavr.control.Try; public class TurtleLoaderTest { private static final String MODEL = """ @@ -57,4 +67,40 @@ void jenaReaderSucceedsWhenPrefixIsNotDefined() throws IOException { .hasMessageContaining( "[line: 2, col: 13] Undefined prefix: aPrefix" ); } } + + @Test + void loadModelUsingTreeSitter() throws IOException { + final String turtle = + new String( TestResources.testModelSource( TestAspect.ASPECT_WITH_BINARY ).readAllBytes(), StandardCharsets.UTF_8 ); + try ( final TSParser parser = new TSParser() ) { + parser.setLanguage( new TreeSitterTurtle() ); + final TSTree tsTree = parser.parseString( null, turtle ); + final TurtleSyntaxTree turtleSyntaxTree = TurtleSyntaxTree.fromConcreteSyntaxTree( tsTree, () -> turtle, + new TurtleSyntaxTree.StringTokenProvider( turtle ) ); + assertThatCode( () -> { + final Try tryModel = TurtleLoader.loadTurtle( turtleSyntaxTree, buildArtificialUri( turtle, "model" ) ); + assertThat( tryModel.isFailure() ).isFalse(); + final Model model = tryModel.get(); + assertThat( model.listStatements().toList() ).isNotEmpty(); + } ).doesNotThrowAnyException(); + } + } + + @Test + void loadModelWithSyntaxErrorUsingTreeSitter() throws IOException { + final String turtle = + new String( TestResources.testModelSource( InvalidTestAspect.INVALID_SYNTAX ).readAllBytes(), StandardCharsets.UTF_8 ); + try ( final TSParser parser = new TSParser() ) { + parser.setLanguage( new TreeSitterTurtle() ); + final TSTree tsTree = parser.parseString( null, turtle ); + final TurtleSyntaxTree turtleSyntaxTree = TurtleSyntaxTree.fromConcreteSyntaxTree( tsTree, () -> turtle, + new TurtleSyntaxTree.StringTokenProvider( turtle ) ); + final Try tryModel = TurtleLoader.loadTurtle( turtleSyntaxTree, buildArtificialUri( turtle, "model" ) ); + assertThat( tryModel.isFailure() ).isTrue(); + } + } + + private static URI buildArtificialUri( final Object object, final String objectType ) { + return URI.create( "inmemory:%s:%s".formatted( objectType, object.hashCode() ) ); + } } diff --git a/core/esmf-aspect-meta-model-java/src/test/java/org/eclipse/esmf/test/TestResources.java b/core/esmf-aspect-meta-model-java/src/test/java/org/eclipse/esmf/test/TestResources.java index 75456bfc7..20566c1ae 100644 --- a/core/esmf-aspect-meta-model-java/src/test/java/org/eclipse/esmf/test/TestResources.java +++ b/core/esmf-aspect-meta-model-java/src/test/java/org/eclipse/esmf/test/TestResources.java @@ -23,6 +23,13 @@ import org.eclipse.esmf.samm.KnownVersion; public class TestResources { + @SuppressWarnings( "DataFlowIssue" ) + public static InputStream testModelSource( final TestAspect model ) { + final String path = String.format( "valid/%s/%s/%s.ttl", model.getUrn().getNamespaceMainPart(), model.getUrn().getVersion(), + model.getName() ); + return TestResources.class.getClassLoader().getResourceAsStream( path ); + } + public static AspectModel load( final TestAspect model ) { final KnownVersion metaModelVersion = KnownVersion.getLatest(); final String path = String.format( "valid/%s/%s/%s.ttl", model.getUrn().getNamespaceMainPart(), model.getUrn().getVersion(), @@ -49,6 +56,13 @@ public static AspectModel load( final OrderingTestAspect model ) { return new AspectModelLoader( testModelsResolutionStrategy ).load( inputStream, URI.create( "testmodel:" + path ) ); } + @SuppressWarnings( "DataFlowIssue" ) + public static InputStream testModelSource( final InvalidTestAspect model ) { + final String path = String.format( "invalid/%s/%s/%s.ttl", model.getUrn().getNamespaceMainPart(), model.getUrn().getVersion(), + model.getName() ); + return TestResources.class.getClassLoader().getResourceAsStream( path ); + } + public static AspectModel load( final InvalidTestAspect model ) { final KnownVersion metaModelVersion = KnownVersion.getLatest(); final String path = String.format( "invalid/%s/%s/%s.ttl", model.getUrn().getNamespaceMainPart(), model.getUrn().getVersion(), diff --git a/core/esmf-aspect-model-validator/src/main/java/org/eclipse/esmf/aspectmodel/shacl/violation/Violation.java b/core/esmf-aspect-model-validator/src/main/java/org/eclipse/esmf/aspectmodel/shacl/violation/Violation.java index ba76c0166..c1dab3513 100644 --- a/core/esmf-aspect-model-validator/src/main/java/org/eclipse/esmf/aspectmodel/shacl/violation/Violation.java +++ b/core/esmf-aspect-model-validator/src/main/java/org/eclipse/esmf/aspectmodel/shacl/violation/Violation.java @@ -17,6 +17,8 @@ import java.util.List; import java.util.Optional; +import org.apache.jena.rdf.model.RDFNode; + import org.eclipse.esmf.aspectmodel.AspectModelFile; import org.eclipse.esmf.aspectmodel.resolver.parser.SmartToken; import org.eclipse.esmf.aspectmodel.resolver.parser.TokenRegistry; @@ -27,7 +29,7 @@ import org.eclipse.esmf.aspectmodel.validation.ProcessingViolation; import org.eclipse.esmf.aspectmodel.validation.RegularExpressionConstraintViolation; -import org.apache.jena.rdf.model.RDFNode; +import org.jspecify.annotations.Nullable; /** * Represents a single violation raised by one or more SHACL shapes against an RDF model. A @@ -59,8 +61,8 @@ public interface Violation { /** * The RDF node this violation focusses on */ - default RDFNode highlight() { - return context().element(); + default @Nullable RDFNode highlight() { + return context() == null ? null : context().element(); } /** diff --git a/core/esmf-tree-sitter-turtle/src/main/java/org/eclipse/esmf/treesitterturtle/TreeSitterTurtle.java b/core/esmf-tree-sitter-turtle/src/main/java/org/eclipse/esmf/treesitterturtle/TreeSitterTurtle.java index 4e0446f5a..fb861059e 100644 --- a/core/esmf-tree-sitter-turtle/src/main/java/org/eclipse/esmf/treesitterturtle/TreeSitterTurtle.java +++ b/core/esmf-tree-sitter-turtle/src/main/java/org/eclipse/esmf/treesitterturtle/TreeSitterTurtle.java @@ -14,8 +14,16 @@ package org.eclipse.esmf.treesitterturtle; import org.treesitter.TSLanguage; +import org.treesitter.TSParser; import org.treesitter.utils.NativeUtils; +/** + * Language definition for RDF/Turtle to be used with {@link TSParser}: + * {@code + * TSParser parser = new TSParser(); + * parser.setLanguage( new TreeSitterTurtle() ); + * } + */ public class TreeSitterTurtle extends TSLanguage { static { NativeUtils.loadLib( "lib/tree-sitter-turtle" ); diff --git a/core/esmf-tree-sitter-turtle/src/main/java/org/eclipse/esmf/treesitterturtle/TurtleSyntaxTree.java b/core/esmf-tree-sitter-turtle/src/main/java/org/eclipse/esmf/treesitterturtle/TurtleSyntaxTree.java new file mode 100644 index 000000000..19fe18557 --- /dev/null +++ b/core/esmf-tree-sitter-turtle/src/main/java/org/eclipse/esmf/treesitterturtle/TurtleSyntaxTree.java @@ -0,0 +1,181 @@ +/* + * Copyright (c) 2026 Robert Bosch Manufacturing Solutions GmbH + * + * See the AUTHORS file(s) distributed with this work for additional + * information regarding authorship. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * SPDX-License-Identifier: MPL-2.0 + */ + +package org.eclipse.esmf.treesitterturtle; + +import java.util.Comparator; +import java.util.List; +import java.util.Objects; +import java.util.function.Function; +import java.util.function.Supplier; +import java.util.stream.IntStream; +import java.util.stream.Stream; + +import org.treesitter.TSNode; +import org.treesitter.TSTree; + +/** + * Represents the concrete syntax tree of a turtle document + */ +public class TurtleSyntaxTree { + private final Supplier sourceRepresentationSupplier; + private final Node rootNode; + + public sealed interface Node { + String type(); + + Location location(); + + default boolean isError() { + return false; + } + + default List children() { + return List.of(); + } + } + + /** + * Represents one node in the concrete syntax tree in the source document + * + * @param type the type of token, expected to be one of the constants in {@link ParserTokenType} + * @param content the actual content of the token + * @param location the location in the source document + * @param children children of the node + */ + public record Token( + String type, + String content, + Location location, + List children + ) implements Node {} + + public record Error( + String type, + Location location, + boolean isMissing, + boolean isExtra + ) implements Node { + @Override + public boolean isError() { + return true; + } + } + + public record Location( + int fromLine, + int fromColumn, + int toLine, + int toColumn + ) {} + + public interface TokenProvider extends Function { + } + + /** + * TokenProvider implementation for an input document given as a string + */ + public static class StringTokenProvider implements TokenProvider { + private final String sourceDocument; + + public StringTokenProvider( final String sourceDocument ) { + this.sourceDocument = sourceDocument; + } + + @Override + public String apply( final Location location ) { + if ( sourceDocument == null || sourceDocument.isEmpty() ) { + return ""; + } + + int startIndex = 0; + int currentLine = 0; + for ( int i = 0; i < sourceDocument.length() && currentLine < location.fromLine(); i++ ) { + if ( sourceDocument.charAt( i ) == '\n' ) { + currentLine++; + } + startIndex = i + 1; + } + startIndex += location.fromColumn(); + int endIndex = 0; + currentLine = 0; + + for ( int i = 0; i < sourceDocument.length() && currentLine < location.toLine(); i++ ) { + if ( sourceDocument.charAt( i ) == '\n' ) { + currentLine++; + } + endIndex = i + 1; + } + endIndex += location.toColumn(); + startIndex = Math.clamp( startIndex, 0, sourceDocument.length() ); + endIndex = Math.clamp( endIndex, 0, sourceDocument.length() ); + + if ( startIndex > endIndex ) { + return ""; + } + + return sourceDocument.substring( startIndex, endIndex ); + } + } + + private TurtleSyntaxTree( final Node rootNode, final Supplier sourceRepresentationSupplier ) { + this.rootNode = rootNode; + this.sourceRepresentationSupplier = sourceRepresentationSupplier; + } + + public Node rootNode() { + return rootNode; + } + + public Supplier sourceRepresentationSupplier() { + return sourceRepresentationSupplier; + } + + public static TurtleSyntaxTree fromConcreteSyntaxTree( final TSTree syntaxTree, final Supplier sourceRepresentationSupplier, + final TokenProvider tokenProvider ) { + return new TurtleSyntaxTree( nodeForTsNode( syntaxTree.getRootNode(), tokenProvider ), sourceRepresentationSupplier ); + } + + private static Node nodeForTsNode( final TSNode inputNode, final TokenProvider tokenProvider ) { + final Location location = new Location( + inputNode.getStartPoint().getRow(), + inputNode.getStartPoint().getColumn(), + inputNode.getEndPoint().getRow(), + inputNode.getEndPoint().getColumn() ); + if ( inputNode.isError() ) { + return new Error( inputNode.getType(), location, inputNode.isMissing(), inputNode.isExtra() ); + } + final String token = tokenProvider.apply( location ); + final List children = IntStream.range( 0, inputNode.getChildCount() ) + .mapToObj( inputNode::getChild ) + .filter( Objects::nonNull ) + .map( child -> nodeForTsNode( child, tokenProvider ) ) + .toList(); + return new Token( inputNode.getType(), token, location, children ); + } + + private Stream nodes( final Node fromNode ) { + final Stream children = fromNode.children().stream().flatMap( this::nodes ); + return Stream.concat( Stream.of( fromNode ), children ) + .sorted( Comparator.comparingInt( node -> node.location().fromLine() ) + .thenComparingInt( node -> node.location().fromColumn() ) ); + } + + public Stream nodes() { + return nodes( rootNode() ); + } + + public Stream tokens() { + return nodes().filter( Token.class::isInstance ).map( Token.class::cast ); + } +} diff --git a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/App.java b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/App.java index 186b9ee57..7f1ddf3ec 100644 --- a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/App.java +++ b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/App.java @@ -33,10 +33,10 @@ public class App { private static final Logger LOG = LoggerFactory.getLogger( App.class ); static void main( final String[] args ) { - LOG.info( "Starting lsp-server on port {}", PORT ); final TurtleLanguageServer languageServer = new TurtleLanguageServer(); try ( final AsynchronousServerSocketChannel serverSocket = AsynchronousServerSocketChannel.open() ) { serverSocket.bind( new InetSocketAddress( "localhost", PORT ) ); + LOG.info( "Starting lsp-server on port {}", PORT ); final AsynchronousSocketChannel socketChannel = serverSocket.accept().get(); final Launcher launcher = Launcher.createIoLauncher( languageServer, LanguageClient.class, Channels.newInputStream( socketChannel ), @@ -48,7 +48,7 @@ static void main( final String[] args ) { Thread.sleep( 10_000L ); } } catch ( final InterruptedException | ExecutionException | IOException exception ) { - LOG.warn( "Could not launch Language Server", exception ); + LOG.info( "Could not launch Language Server", exception ); } } } diff --git a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/aspect/service/AspectModelValidationService.java b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/aspect/service/AspectModelValidationService.java index 8b54b5d59..1c0490aee 100644 --- a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/aspect/service/AspectModelValidationService.java +++ b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/aspect/service/AspectModelValidationService.java @@ -16,12 +16,18 @@ import java.io.InputStream; import java.net.URI; import java.util.List; +import java.util.Optional; + +import org.apache.jena.rdf.model.RDFNode; import org.eclipse.esmf.aspectmodel.loader.AspectModelLoader; +import org.eclipse.esmf.aspectmodel.resolver.AspectModelFileLoader; +import org.eclipse.esmf.aspectmodel.resolver.modelfile.RawAspectModelFile; +import org.eclipse.esmf.aspectmodel.resolver.parser.TokenRegistry; import org.eclipse.esmf.aspectmodel.shacl.violation.Violation; -import org.eclipse.esmf.aspectmodel.validation.InvalidLexicalValueViolation; import org.eclipse.esmf.aspectmodel.validation.InvalidSyntaxViolation; import org.eclipse.esmf.aspectmodel.validation.services.AspectModelValidator; +import org.eclipse.esmf.treesitterturtle.TurtleSyntaxTree; import org.eclipse.esmf.turtle.languageserver.diagnostic.DiagnosticReport; import org.eclipse.esmf.turtle.languageserver.diagnostic.TurtleBaseDiagnostic; import org.eclipse.esmf.turtle.languageserver.diagnostic.TurtleDiagnostic; @@ -58,10 +64,15 @@ public DiagnosticReport defaultValidate( final ParsedDocument parsedDocument ) { final Document document = parsedDocument.sourceDocument(); try ( final InputStream inputStream = document.getInputStream() ) { LOG.debug( "[load] loading aspect model from {}", document.getUri() ); + final TurtleSyntaxTree syntaxTree = TurtleSyntaxTree.fromConcreteSyntaxTree( parsedDocument.concreteSyntaxTree(), + () -> parsedDocument.sourceDocument().getContent(), + location -> parsedDocument.sourceDocument().subSequence( location.fromLine(), location.fromColumn(), + location.toLine(), location.toColumn() ) ); + final RawAspectModelFile file = AspectModelFileLoader.load( syntaxTree, URI.create( document.getUri() ) ); final List violations = - validator.validateModel( () -> loader.load( inputStream, URI.create( document.getUri() ) ) ); + validator.validateModel( () -> loader.loadAspectModelFiles( List.of( file ) ) ); LOG.debug( "[validate] validation finished for {} with {} violation(s)", document.getUri(), violations.size() ); - return new DiagnosticReport( violations.stream().map( this::toViolationInfo ).toList() ); + return new DiagnosticReport( violations.stream().flatMap( violation -> toViolationInfo( violation ).stream() ).toList() ); } catch ( final Exception exception ) { LOG.error( "[validate] unexpected runtime failure for {}", document.getUri(), exception ); return new DiagnosticReport( exception.getMessage(), TurtleDiagnostic.TurtleCode.E0000 ); @@ -72,29 +83,31 @@ private TurtleDiagnostic.Code classifyViolation( final Violation violation ) { return TurtleDiagnostic.TurtleCode.E0000; } - private TurtleDiagnostic toViolationInfo( final Violation violation ) { + private Optional toViolationInfo( final Violation violation ) { return switch ( violation ) { - case final InvalidSyntaxViolation syntaxViolation -> - new TurtleDocumentDiagnostic( - syntaxViolation.message(), - classifyViolation( violation ), - syntaxViolation.sourceLocation().map( URI::toString ).orElseThrow(), - (int) syntaxViolation.line(), - (int) syntaxViolation.column(), - (int) syntaxViolation.line(), - (int) syntaxViolation.column() ); - case final InvalidLexicalValueViolation lexicalValueViolation -> - new TurtleDocumentDiagnostic( - lexicalValueViolation.message(), - classifyViolation( violation ), - lexicalValueViolation.sourceLocation().map( URI::toString ).orElseThrow(), - lexicalValueViolation.line(), - lexicalValueViolation.column(), - lexicalValueViolation.line(), - lexicalValueViolation.column() ); - default -> new TurtleBaseDiagnostic( - violation.message(), - classifyViolation( violation ) ); + // Syntax violation diagnostics are provided by TurtleSyntaxDiagnosticsService + case final InvalidSyntaxViolation _ -> Optional.empty(); + // TODO Add other specific violations here + default -> { + final TurtleSyntaxTree.Location location = Optional.ofNullable( violation.highlight() ) + .map( RDFNode::asNode ) + .flatMap( TokenRegistry::getToken ) + .flatMap( smartToken -> Optional.ofNullable( smartToken.getTreesitterToken() ) ) + .map( TurtleSyntaxTree.Token::location ) + .orElse( null ); + yield location == null + ? Optional.of( new TurtleBaseDiagnostic( + violation.message(), + classifyViolation( violation ) ) ) + : Optional.of( new TurtleDocumentDiagnostic( + violation.message(), + classifyViolation( violation ), + violation.sourceLocation().map( URI::toString ).orElseThrow(), + location.fromLine(), + location.fromColumn(), + location.toLine(), + location.toColumn() ) ); + } }; } } From a177a4227ca8ab65507ed886b30e453b3ddea030 Mon Sep 17 00:00:00 2001 From: Andreas Textor Date: Mon, 18 May 2026 11:57:23 +0200 Subject: [PATCH 15/41] Fix code style --- .../resolver/parser/SmartToken.java | 4 +- core/esmf-tree-sitter-turtle/README.md | 2 +- .../treesitterturtle/TurtleSyntaxTree.java | 2 +- .../turtle/languageserver/lsp/text/Rope.java | 24 +- .../lsp/text/TurtleSyntaxTree.java | 364 ------------------ .../lsp/text/TurtleParserServiceTest.java | 2 - 6 files changed, 16 insertions(+), 382 deletions(-) delete mode 100644 core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TurtleSyntaxTree.java diff --git a/core/esmf-aspect-meta-model-java/src/main/java/org/eclipse/esmf/aspectmodel/resolver/parser/SmartToken.java b/core/esmf-aspect-meta-model-java/src/main/java/org/eclipse/esmf/aspectmodel/resolver/parser/SmartToken.java index e3512e009..2e2ed90c6 100644 --- a/core/esmf-aspect-meta-model-java/src/main/java/org/eclipse/esmf/aspectmodel/resolver/parser/SmartToken.java +++ b/core/esmf-aspect-meta-model-java/src/main/java/org/eclipse/esmf/aspectmodel/resolver/parser/SmartToken.java @@ -114,7 +114,7 @@ public int column() { /** * The line where the token ends, 1-based. - * + * * @return the line */ public int toLine() { @@ -126,7 +126,7 @@ public int toLine() { /** * The column where the token ends, 1-based. - * + * * @return the colum */ public int toColumn() { diff --git a/core/esmf-tree-sitter-turtle/README.md b/core/esmf-tree-sitter-turtle/README.md index 9404eacb3..18d9528c4 100644 --- a/core/esmf-tree-sitter-turtle/README.md +++ b/core/esmf-tree-sitter-turtle/README.md @@ -18,5 +18,5 @@ The build works as follows, in chronological order: | process-sources | exec-maven-plugin | java | Execute DownloadZig class, to download and extract Zig release | | compile | maven-compiler-plugin | compile | Compile regular Java binding class (TreeSitterTurtle) | | compile | exec-maven-plugin | java | Execute NativeCompile class, to use Zig compiler to create native libraries from Turtle parser C code | - + At the end of the build, platform-specific native libs are present in target/classes/libs. diff --git a/core/esmf-tree-sitter-turtle/src/main/java/org/eclipse/esmf/treesitterturtle/TurtleSyntaxTree.java b/core/esmf-tree-sitter-turtle/src/main/java/org/eclipse/esmf/treesitterturtle/TurtleSyntaxTree.java index 19fe18557..67caac7e6 100644 --- a/core/esmf-tree-sitter-turtle/src/main/java/org/eclipse/esmf/treesitterturtle/TurtleSyntaxTree.java +++ b/core/esmf-tree-sitter-turtle/src/main/java/org/eclipse/esmf/treesitterturtle/TurtleSyntaxTree.java @@ -47,7 +47,7 @@ default List children() { /** * Represents one node in the concrete syntax tree in the source document - * + * * @param type the type of token, expected to be one of the constants in {@link ParserTokenType} * @param content the actual content of the token * @param location the location in the source document diff --git a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/Rope.java b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/Rope.java index 63a5bb7e4..af05742a7 100644 --- a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/Rope.java +++ b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/Rope.java @@ -38,7 +38,7 @@ public class Rope implements CharSequence { /** * Constructs a new rope from a given string value - * + * * @param value the value */ public Rope( final String value ) { @@ -49,7 +49,7 @@ public Rope( final String value ) { /** * Constructs a new rope from left and right children - * + * * @param left left children * @param right right children */ @@ -77,7 +77,7 @@ public int weight() { /** * Returns the length of the rope in characters - * + * * @return the length */ @Override @@ -95,7 +95,7 @@ private int length( final Rope r ) { /** * Concatenates another rope to this one - * + * * @param rope the other rope * @return the new rope representing the concatenated result */ @@ -123,7 +123,7 @@ private char charAt( final Rope node, final int index ) { /** * Returns the character at given index - * + * * @param index the index of the {@code char} value to be returned * * @return the character at the index @@ -135,7 +135,7 @@ public char charAt( final int index ) { /** * Splits this rope into two parts at the given index - * + * * @param index the index * @return an array with two elements, representing the left and right parts of the index. Both * elements could be null, @@ -176,7 +176,7 @@ private Rope[] split( final Rope node, final int index ) { /** * Returns the subsequence of characters between to indices - * + * * @param start the start index, inclusive * @param end the end index, exclusive * @return the subsequence of characters @@ -188,7 +188,7 @@ private Rope[] split( final Rope node, final int index ) { /** * Inserts another rope at the given index. The index must be inside the rope. - * + * * @param rope the other rope * @param index the index. This must be less or equal than this rope's length * @return the resulting new rope @@ -200,7 +200,7 @@ public Rope insert( final Rope rope, final int index ) { /** * Deletes a section at the given index. The index and index+length must be inside the rope. - * + * * @param index the index * @param length the length to delete * @return the resulting new rope @@ -218,7 +218,7 @@ public Rope delete( final int index, final int length ) { /** * Returns the index of the nth linebreak in a string, or -1 if no nth linebreak exists - * + * * @param string the text to search in * @param n the number of the linebreak * @return the index or -1 @@ -269,7 +269,7 @@ public int getIndex( final int targetLine, final int targetColumn ) { /** * Prints the rope as a tree structure - * + * * @return the tree structure as a visual string */ public String print() { @@ -360,7 +360,7 @@ public InputStream inputStream() { * fewer, if * not as many are left at the offset. Returns 0 if the end of the source code was reached, * otherwise the number of bytes read. - * + * * @param buffer the buffer to write to * @param offset offset to read from * @return the number of bytes read diff --git a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TurtleSyntaxTree.java b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TurtleSyntaxTree.java deleted file mode 100644 index 8c5245862..000000000 --- a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TurtleSyntaxTree.java +++ /dev/null @@ -1,364 +0,0 @@ -/* - * Copyright (c) 2026 Robert Bosch Manufacturing Solutions GmbH - * - * See the AUTHORS file(s) distributed with this work for additional - * information regarding authorship. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * SPDX-License-Identifier: MPL-2.0 - */ - -package org.eclipse.esmf.turtle.languageserver.lsp.text; - -import java.util.List; -import java.util.Map; -import java.util.stream.Stream; - -import org.jspecify.annotations.Nullable; -import org.treesitter.TSNode; -import org.treesitter.TSTree; - -/** - *
- * - 'document'
- *   - 'directive' (@prefix ex:  .)
- *     - 'prefix_id' (@prefix ex:  .)
- *       - '@prefix'
- *       - 'namespace' (ex:)
- *         - 'pn_prefix' (ex)
- *         - ':'
- *       - 'iri_reference' ()
- *         - '<'
- *         - '>'
- *       - '.'
- *   - 'triple'
- *     - 'subject' (ex:subject)
- *       - 'prefixed_name' (ex:subject)
- *         - 'namespace' (ex:)
- *           - 'pn_prefix' (ex)
- *           - ':'
- *         - 'pn_local' (subject)
- *     - 'property_list'
- *       - 'property' (ex:predicate1 ex:object1)
- *         - 'predicate' (ex:predicate1)
- *           - 'prefixed_name' (ex:predicate1)
- *             - 'namespace' (ex:)
- *               - 'pn_prefix' (ex)
- *               - ':'
- *             - 'pn_local' (predicate1)
- *         - 'object_list' (ex:object1)
- *           - 'prefixed_name' (ex:object1)
- *             - 'namespace' (ex:)
- *               - 'pn_prefix' (ex)
- *               - ':'
- *             - 'pn_local' (object1)
- *       - ';'
- *       - 'property' (ex:predicate2 123)
- *         - 'predicate' (ex:predicate2)
- *           - 'prefixed_name' (ex:predicate2)
- *             - 'namespace' (ex:)
- *               - 'pn_prefix' (ex)
- *               - ':'
- *             - 'pn_local' (predicate2)
- *         - 'object_list' (123)
- *           - 'integer' (123)
- *       - ';'
- *       - 'property' (ex:predicate3 true)
- *         - 'predicate' (ex:predicate3)
- *           - 'prefixed_name' (ex:predicate3)
- *             - 'namespace' (ex:)
- *               - 'pn_prefix' (ex)
- *               - ':'
- *             - 'pn_local' (predicate3)
- *         - 'object_list' (true)
- *           - 'boolean_literal' (true)
- *             - 'true'
- *       - ';'
- *       - 'property' (ex:predicate4 "some string")
- *         - 'predicate' (ex:predicate4)
- *           - 'prefixed_name' (ex:predicate4)
- *             - 'namespace' (ex:)
- *               - 'pn_prefix' (ex)
- *               - ':'
- *             - 'pn_local' (predicate4)
- *         - 'object_list' ("some string")
- *           - 'rdf_literal' ("some string")
- *             - 'string' ("some string")
- *               - '"'
- *               - '"'
- *       - ';'
- *       - 'property' (ex:predicate5 "some langString"@en)
- *         - 'predicate' (ex:predicate5)
- *           - 'prefixed_name' (ex:predicate5)
- *             - 'namespace' (ex:)
- *               - 'pn_prefix' (ex)
- *               - ':'
- *             - 'pn_local' (predicate5)
- *         - 'object_list' ("some langString"@en)
- *           - 'rdf_literal' ("some langString"@en)
- *             - 'string' ("some langString")
- *               - '"'
- *               - '"'
- *             - 'lang_tag' (@en)
- *       - ';'
- *       - 'property' (ex:predicate6 "123"^^xsd:decimal)
- *         - 'predicate' (ex:predicate6)
- *           - 'prefixed_name' (ex:predicate6)
- *             - 'namespace' (ex:)
- *               - 'pn_prefix' (ex)
- *               - ':'
- *             - 'pn_local' (predicate6)
- *         - 'object_list' ("123"^^xsd:decimal)
- *           - 'rdf_literal' ("123"^^xsd:decimal)
- *             - 'string' ("123")
- *               - '"'
- *               - '"'
- *             - '^^'
- *             - 'prefixed_name' (xsd:decimal)
- *               - 'namespace' (xsd:)
- *                 - 'pn_prefix' (xsd)
- *                 - ':'
- *               - 'pn_local' (decimal)
- *       - ';'
- *       - 'property' (ex:predicate7 )
- *         - 'predicate' (ex:predicate7)
- *           - 'prefixed_name' (ex:predicate7)
- *             - 'namespace' (ex:)
- *               - 'pn_prefix' (ex)
- *               - ':'
- *             - 'pn_local' (predicate7)
- *         - 'object_list' ()
- *           - 'iri_reference' ()
- *             - '<'
- *             - '>'
- *     - '.'
- *   - 'triple' ( a rdf:type .)
- *     - 'subject' ()
- *       - 'iri_reference' ()
- *         - '<'
- *         - '>'
- *     - 'property_list' (a rdf:type)
- *       - 'property' (a rdf:type)
- *         - 'predicate' (a)
- *           - 'a'
- *         - 'object_list' (rdf:type)
- *           - 'prefixed_name' (rdf:type)
- *             - 'namespace' (rdf:)
- *               - 'pn_prefix' (rdf)
- *               - ':'
- *             - 'pn_local' (type)
- *     - '.'
- * 
- */ -public class TurtleSyntaxTree { - private final TSTree parserTree; - private final Document document; - - /** - * See rules in grammar.js - */ - private enum ParserType { - document, - graph, - comment, - triple, - directive, - prefix_id, - base, - sparql_base, - sparql_prefix, - property_list, - property, - object_list, - predicate, - subject, - blank_node_property_list, - collection, - string, - iri_reference, - integer, - decimal, - _double( "double" ), - rdf_literal, - boolean_literal, - prefixed_name, - namespace, - blank_node_label, - lang_tag, - anon, - pn_prefix, - pn_local; - - private final String type; - - ParserType() { - type = name().toLowerCase(); - } - - ParserType( final String type ) { - this.type = type; - } - - public static @Nullable ParserType fromString( final String type ) { - if ( type.equals( "double" ) ) { - return _double; - } - try { - return valueOf( type ); - } catch ( final IllegalArgumentException exception ) { - return null; - } - } - - public String getType() { - return type; - } - } - - public TurtleSyntaxTree( final TSTree parserTree, final Document document ) { - this.parserTree = parserTree; - this.document = document; - } - - public Map prefixes() { - return null; - } - - private static Stream children( final TSNode node ) { - final Stream.Builder builder = Stream.builder(); - for ( int i = 0; i < node.getChildCount(); i++ ) { - builder.add( node.getChild( 0 ) ); - } - return builder.build(); - } - - private static TurtleDocument parseRootNode( final TSNode rootNode ) { - return new DefaultTurtleDocument( children( rootNode ).map( TurtleSyntaxTree::parse ).toList() ); - } - - private static Node parse( final TSNode node ) { - return switch ( ParserType.fromString( node.getType() ) ) { - case directive -> parse( node.getChild( 0 ) ); - case prefix_id -> null; - case namespace -> null; - case pn_prefix -> null; - case document -> null; - case graph -> null; - case comment -> null; - case triple -> null; - case subject -> null; - case prefixed_name -> null; - case pn_local -> null; - case base -> null; - case sparql_base -> null; - case sparql_prefix -> null; - case property_list -> null; - case property -> null; - case predicate -> null; - case object_list -> null; - case integer -> null; - case boolean_literal -> null; - case rdf_literal -> null; - case blank_node_property_list -> null; - case collection -> null; - case string -> null; - case lang_tag -> null; - case iri_reference -> null; - case decimal -> null; - case _double -> null; - case blank_node_label -> null; - case anon -> null; - case null -> throw new UnsupportedOperationException(); - }; - } - - interface TurtleDocument { - List nodes(); - } - - public record DefaultTurtleDocument( - List nodes - ) implements TurtleDocument {} - - interface Node { - } - - interface Directive extends Node { - } - - interface Comment extends Node { - String comment(); - } - - interface PrefixDeclaration extends Directive { - String prefix(); - - String namespace(); - } - - public record DefaultPrefixDeclaration( - String prefix, String namespace - ) implements PrefixDeclaration {} - - interface RelativeOrAbsoluteIri extends Object { - } - - interface Iri extends RelativeOrAbsoluteIri { - String iri(); - } - - interface PrefixedName extends RelativeOrAbsoluteIri { - String prefix(); - - String localName(); - } - - interface Triple extends Node { - RelativeOrAbsoluteIri subject(); - - List properties(); - } - - interface PredicateDeclaration extends Node { - RelativeOrAbsoluteIri predicate(); - - List objects(); - } - - interface ObjectDeclaration extends Directive { - List objects(); - } - - interface Object { - } - - interface Literal extends Object { - String lexicalValue(); - } - - interface NumericLiteral extends Literal { - } - - interface BooleanLiteral extends Literal { - enum Value { - TRUE, FALSE - } - - Value value(); - } - - interface StringLiteral extends Literal { - } - - interface LangStringLiteral extends Literal { - String languageTag(); - } - - interface TypedLiteral extends Literal { - RelativeOrAbsoluteIri datatypeIri(); - } -} - diff --git a/core/esmf-turtle-language-server/src/test/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TurtleParserServiceTest.java b/core/esmf-turtle-language-server/src/test/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TurtleParserServiceTest.java index b4f12ce02..a940607f5 100644 --- a/core/esmf-turtle-language-server/src/test/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TurtleParserServiceTest.java +++ b/core/esmf-turtle-language-server/src/test/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TurtleParserServiceTest.java @@ -384,5 +384,3 @@ private void applyChange( final Document document, final Position start, final P parserService.onChange( document, change ); } } - - From b3f1d7a78793d53fc81af68fce3fcd5e25ef25a9 Mon Sep 17 00:00:00 2001 From: Andreas Textor Date: Mon, 18 May 2026 13:08:40 +0200 Subject: [PATCH 16/41] Create build time cache directory if it doesn't exist yet --- .../main/java/org/eclipse/esmf/buildtime/ZigContext.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/core/esmf-tree-sitter-turtle/src-buildtime/main/java/org/eclipse/esmf/buildtime/ZigContext.java b/core/esmf-tree-sitter-turtle/src-buildtime/main/java/org/eclipse/esmf/buildtime/ZigContext.java index 381cab29f..a775dc69a 100644 --- a/core/esmf-tree-sitter-turtle/src-buildtime/main/java/org/eclipse/esmf/buildtime/ZigContext.java +++ b/core/esmf-tree-sitter-turtle/src-buildtime/main/java/org/eclipse/esmf/buildtime/ZigContext.java @@ -82,6 +82,12 @@ public ZigContext( final Path cacheLocation, final String zigVersion ) { } else { throw new BuildTimeException( "Unsupported operating system: " + SystemUtils.OS_NAME ); } + + try { + Files.createDirectories( cacheLocation ); + } catch ( final IOException exception ) { + throw new BuildTimeException( "Could not create cache directory: " + cacheLocation ); + } } protected Path zigDir() { From 4a815aac9e3f149a1c5135a950ea598f3ca2a5a7 Mon Sep 17 00:00:00 2001 From: Andreas Textor Date: Mon, 18 May 2026 13:24:52 +0200 Subject: [PATCH 17/41] Make sure xz is available at build time execution --- core/esmf-tree-sitter-turtle/pom.xml | 13 +++++++++++++ pom.xml | 7 +++++++ 2 files changed, 20 insertions(+) diff --git a/core/esmf-tree-sitter-turtle/pom.xml b/core/esmf-tree-sitter-turtle/pom.xml index e9fa944bf..aac0f4522 100644 --- a/core/esmf-tree-sitter-turtle/pom.xml +++ b/core/esmf-tree-sitter-turtle/pom.xml @@ -66,6 +66,16 @@ org.slf4j slf4j-nop + + org.apache.commons + commons-compress + compile + + + org.tukaani + xz + compile + @@ -185,6 +195,9 @@ ${minisign.version} + + ${settings.localRepository}/org/tukaani/xz/${xz.version}/xz-${xz.version}.jar + diff --git a/pom.xml b/pom.xml index cd0a89b63..51356c63f 100644 --- a/pom.xml +++ b/pom.xml @@ -84,6 +84,7 @@ 1.15.2 3.4.1 1.12.0 + 1.11 @@ -251,6 +252,12 @@ + + org.tukaani + xz + ${xz.version} + + org.apache.maven.shared From 1930d847725461afd5ddeab5221b48086032f81a Mon Sep 17 00:00:00 2001 From: Andreas Textor Date: Mon, 18 May 2026 13:31:48 +0200 Subject: [PATCH 18/41] Fix native lib compilation on Windows --- .../main/java/org/eclipse/esmf/buildtime/NativeCompile.java | 1 + 1 file changed, 1 insertion(+) diff --git a/core/esmf-tree-sitter-turtle/src-buildtime/main/java/org/eclipse/esmf/buildtime/NativeCompile.java b/core/esmf-tree-sitter-turtle/src-buildtime/main/java/org/eclipse/esmf/buildtime/NativeCompile.java index ec64a4905..39bf7795b 100644 --- a/core/esmf-tree-sitter-turtle/src-buildtime/main/java/org/eclipse/esmf/buildtime/NativeCompile.java +++ b/core/esmf-tree-sitter-turtle/src-buildtime/main/java/org/eclipse/esmf/buildtime/NativeCompile.java @@ -79,6 +79,7 @@ private void runZig() { args.add( "c++" ); args.add( "-g0" ); args.add( "-fno-sanitize=undefined" ); + args.add( "-fdeclspec" ); args.add( "-shared" ); args.add( "-target" ); args.add( target.getTargetName() ); From e512e7db49103d520089caf3472baa3a059b6ee3 Mon Sep 17 00:00:00 2001 From: Andreas Textor Date: Mon, 18 May 2026 13:42:03 +0200 Subject: [PATCH 19/41] Fix checksum detection in build workflow --- .github/workflows/pull-request-check.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pull-request-check.yml b/.github/workflows/pull-request-check.yml index 18612fb14..c75905751 100644 --- a/.github/workflows/pull-request-check.yml +++ b/.github/workflows/pull-request-check.yml @@ -124,7 +124,7 @@ jobs: cp tools/samm-cli/scripts/windows/run.bat ./${bundle}/ curl -Lo warp-packer.exe https://github.com/dgiagio/warp/releases/download/v0.3.0/windows-x64.warp-packer.exe - if [ "$(sha256sum warp-packer | cut -d' ' -f1)" != "4f9a0f223f0e9f689fc718fdf86a147a357921ffa69c236deadc3274091070c1" ]; then + if [ "$(sha256sum warp-packer.exe | cut -d' ' -f1)" != "4f9a0f223f0e9f689fc718fdf86a147a357921ffa69c236deadc3274091070c1" ]; then echo "Warp packer checksum does not match" exit 1 fi @@ -145,7 +145,7 @@ jobs: chmod +x ./${bundle}/run.sh curl -Lo warp-packer https://github.com/dgiagio/warp/releases/download/v0.3.0/macos-x64.warp-packer - if [ "$(sha256sum warp-packer | cut -d' ' -f1)" != "01d00038dbbe4e5a6e2ca19c1235f051617ac0e6e582d2407a06cec33125044b" ]; then + if [ "$(shasum -a 256 warp-packer | cut -d' ' -f1)" != "01d00038dbbe4e5a6e2ca19c1235f051617ac0e6e582d2407a06cec33125044b" ]; then echo "Warp packer checksum does not match" exit 1 fi From c13a01e622a6c952f3e7cd56eaa8035f2973819f Mon Sep 17 00:00:00 2001 From: Andreas Textor Date: Mon, 18 May 2026 14:16:21 +0200 Subject: [PATCH 20/41] Deduplicate utils and move TreeSitterUtil to esmf-tree-sitter --- .../treesitterturtle}/TreeSitterUtil.java | 31 ++-- .../treesitterturtle/TurtleSyntaxTree.java | 3 + .../TreeSitterTurtleTest.java | 133 ++++-------------- .../languageserver/lsp/text/Document.java | 9 +- .../lsp/text/TurtleParserServiceTest.java | 2 + 5 files changed, 57 insertions(+), 121 deletions(-) rename core/{esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text => esmf-tree-sitter-turtle/src/main/java/org/eclipse/esmf/treesitterturtle}/TreeSitterUtil.java (59%) diff --git a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TreeSitterUtil.java b/core/esmf-tree-sitter-turtle/src/main/java/org/eclipse/esmf/treesitterturtle/TreeSitterUtil.java similarity index 59% rename from core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TreeSitterUtil.java rename to core/esmf-tree-sitter-turtle/src/main/java/org/eclipse/esmf/treesitterturtle/TreeSitterUtil.java index adc93bc33..14f47e26f 100644 --- a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TreeSitterUtil.java +++ b/core/esmf-tree-sitter-turtle/src/main/java/org/eclipse/esmf/treesitterturtle/TreeSitterUtil.java @@ -11,7 +11,7 @@ * SPDX-License-Identifier: MPL-2.0 */ -package org.eclipse.esmf.turtle.languageserver.lsp.text; +package org.eclipse.esmf.treesitterturtle; import org.jspecify.annotations.Nullable; import org.treesitter.TSNode; @@ -26,30 +26,35 @@ public static String print( final TSTree tree ) { public static String print( final TSNode node ) { final StringBuilder builder = new StringBuilder(); - print( node, builder, 0 ); + print( node, builder, 0, null ); return builder.toString(); } - public static String print( final TSTree tree, final Document document ) { - return print( tree.getRootNode(), document ); + public static String print( final TSTree tree, final TurtleSyntaxTree.TokenProvider tokenProvider ) { + return print( tree.getRootNode(), tokenProvider ); } - public static String print( final TSNode node, final Document document ) { + public static String print( final TSNode node, final TurtleSyntaxTree.TokenProvider tokenProvider ) { final StringBuilder builder = new StringBuilder(); - print( node, builder, 0, document ); + print( node, builder, 0, tokenProvider ); return builder.toString(); } - private static void print( final TSNode node, final StringBuilder builder, final int indentLevel, @Nullable final Document document ) { + private static void print( final TSNode node, final StringBuilder builder, final int indentLevel, + final TurtleSyntaxTree.@Nullable TokenProvider tokenProvider ) { builder.repeat( " ", indentLevel ); builder.append( "- '" ); builder.append( node.getType() ); builder.append( "'" ); if ( node.hasError() ) { builder.append( " (ERROR)" ); - } else if ( document != null && node.getStartPoint().getRow() == node.getEndPoint().getRow() ) { - final String nodeContent = document.subSequence( node.getStartPoint().getRow(), node.getStartPoint().getColumn(), - node.getEndPoint().getRow(), node.getEndPoint().getColumn() ); + } else if ( tokenProvider != null && node.getStartPoint().getRow() == node.getEndPoint().getRow() ) { + final TurtleSyntaxTree.Location location = new TurtleSyntaxTree.Location( + node.getStartPoint().getRow(), + node.getStartPoint().getColumn(), + node.getEndPoint().getRow(), + node.getEndPoint().getColumn() ); + final String nodeContent = tokenProvider.apply( location ); if ( !nodeContent.equals( node.getType() ) ) { builder.append( " (" ); builder.append( nodeContent ); @@ -58,11 +63,7 @@ private static void print( final TSNode node, final StringBuilder builder, final } builder.append( "\n" ); for ( int i = 0; i < node.getChildCount(); i++ ) { - print( node.getChild( i ), builder, indentLevel + 1, document ); + print( node.getChild( i ), builder, indentLevel + 1, tokenProvider ); } } - - private static void print( final TSNode node, final StringBuilder builder, final int indentLevel ) { - print( node, builder, indentLevel, null ); - } } diff --git a/core/esmf-tree-sitter-turtle/src/main/java/org/eclipse/esmf/treesitterturtle/TurtleSyntaxTree.java b/core/esmf-tree-sitter-turtle/src/main/java/org/eclipse/esmf/treesitterturtle/TurtleSyntaxTree.java index 67caac7e6..66649ad48 100644 --- a/core/esmf-tree-sitter-turtle/src/main/java/org/eclipse/esmf/treesitterturtle/TurtleSyntaxTree.java +++ b/core/esmf-tree-sitter-turtle/src/main/java/org/eclipse/esmf/treesitterturtle/TurtleSyntaxTree.java @@ -79,6 +79,9 @@ public record Location( int toColumn ) {} + /** + * Provides the token (substring) for a given location + */ public interface TokenProvider extends Function { } diff --git a/core/esmf-tree-sitter-turtle/src/test/java/org/eclipse/esmf/treesitterturtle/TreeSitterTurtleTest.java b/core/esmf-tree-sitter-turtle/src/test/java/org/eclipse/esmf/treesitterturtle/TreeSitterTurtleTest.java index 70c0f5dba..d8ce38d92 100644 --- a/core/esmf-tree-sitter-turtle/src/test/java/org/eclipse/esmf/treesitterturtle/TreeSitterTurtleTest.java +++ b/core/esmf-tree-sitter-turtle/src/test/java/org/eclipse/esmf/treesitterturtle/TreeSitterTurtleTest.java @@ -41,7 +41,7 @@ void testBasicPrefixAndTriple() { """; final TSTree tree = parser.parseString( null, content ); final TSNode rootNode = tree.getRootNode(); - assertThat( print( rootNode, content ) ).doesNotContain( "ERROR" ); + assertThat( TreeSitterUtil.print( rootNode, new TurtleSyntaxTree.StringTokenProvider( content ) ) ).doesNotContain( "ERROR" ); assertThat( rootNode.hasError() ).isFalse(); assertThat( rootNode.getChild( 0 ).getChild( 0 ).getChild( 0 ).getGrammarType() ).isEqualTo( "@prefix" ); } @@ -62,10 +62,10 @@ void testNumericLiterals() { final TSNode rootNode = tree.getRootNode(); assertThat( rootNode.hasError() ).isFalse(); - assertThat( print( rootNode, content ) ).doesNotContain( "ERROR" ); + assertThat( TreeSitterUtil.print( rootNode, new TurtleSyntaxTree.StringTokenProvider( content ) ) ).doesNotContain( "ERROR" ); // Verify the document parses successfully with numeric literals - final String treeString = print( rootNode, content ); + final String treeString = TreeSitterUtil.print( rootNode, new TurtleSyntaxTree.StringTokenProvider( content ) ); assertThat( treeString ).contains( "42" ); assertThat( treeString ).contains( "3.14" ); assertThat( treeString ).contains( "1.23e10" ); @@ -88,7 +88,7 @@ void testStringLiterals() { final TSNode rootNode = tree.getRootNode(); assertThat( rootNode.hasError() ).isFalse(); - assertThat( print( rootNode, content ) ).doesNotContain( "ERROR" ); + assertThat( TreeSitterUtil.print( rootNode, new TurtleSyntaxTree.StringTokenProvider( content ) ) ).doesNotContain( "ERROR" ); } @Test @@ -104,9 +104,9 @@ void testBooleanLiterals() { final TSNode rootNode = tree.getRootNode(); assertThat( rootNode.hasError() ).isFalse(); - assertThat( print( rootNode, content ) ).doesNotContain( "ERROR" ); - assertThat( print( rootNode, content ) ).contains( "true" ); - assertThat( print( rootNode, content ) ).contains( "false" ); + assertThat( TreeSitterUtil.print( rootNode, new TurtleSyntaxTree.StringTokenProvider( content ) ) ).doesNotContain( "ERROR" ); + assertThat( TreeSitterUtil.print( rootNode, new TurtleSyntaxTree.StringTokenProvider( content ) ) ).contains( "true" ); + assertThat( TreeSitterUtil.print( rootNode, new TurtleSyntaxTree.StringTokenProvider( content ) ) ).contains( "false" ); } @Test @@ -126,10 +126,10 @@ void testLanguageTaggedLiterals() { final TSNode rootNode = tree.getRootNode(); assertThat( rootNode.hasError() ).isFalse(); - assertThat( print( rootNode, content ) ).doesNotContain( "ERROR" ); - assertThat( print( rootNode, content ) ).contains( "@en" ); - assertThat( print( rootNode, content ) ).contains( "@de" ); - assertThat( print( rootNode, content ) ).contains( "@fr" ); + assertThat( TreeSitterUtil.print( rootNode, new TurtleSyntaxTree.StringTokenProvider( content ) ) ).doesNotContain( "ERROR" ); + assertThat( TreeSitterUtil.print( rootNode, new TurtleSyntaxTree.StringTokenProvider( content ) ) ).contains( "@en" ); + assertThat( TreeSitterUtil.print( rootNode, new TurtleSyntaxTree.StringTokenProvider( content ) ) ).contains( "@de" ); + assertThat( TreeSitterUtil.print( rootNode, new TurtleSyntaxTree.StringTokenProvider( content ) ) ).contains( "@fr" ); } @Test @@ -149,8 +149,8 @@ void testTypedLiterals() { final TSNode rootNode = tree.getRootNode(); assertThat( rootNode.hasError() ).isFalse(); - assertThat( print( rootNode, content ) ).doesNotContain( "ERROR" ); - assertThat( print( rootNode, content ) ).contains( "^^" ); + assertThat( TreeSitterUtil.print( rootNode, new TurtleSyntaxTree.StringTokenProvider( content ) ) ).doesNotContain( "ERROR" ); + assertThat( TreeSitterUtil.print( rootNode, new TurtleSyntaxTree.StringTokenProvider( content ) ) ).contains( "^^" ); } @Test @@ -170,9 +170,9 @@ void testRdfListSyntax() { final TSNode rootNode = tree.getRootNode(); assertThat( rootNode.hasError() ).isFalse(); - assertThat( print( rootNode, content ) ).doesNotContain( "ERROR" ); - assertThat( print( rootNode, content ) ).contains( "(" ); - assertThat( print( rootNode, content ) ).contains( ")" ); + assertThat( TreeSitterUtil.print( rootNode, new TurtleSyntaxTree.StringTokenProvider( content ) ) ).doesNotContain( "ERROR" ); + assertThat( TreeSitterUtil.print( rootNode, new TurtleSyntaxTree.StringTokenProvider( content ) ) ).contains( "(" ); + assertThat( TreeSitterUtil.print( rootNode, new TurtleSyntaxTree.StringTokenProvider( content ) ) ).contains( ")" ); } @Test @@ -209,9 +209,9 @@ void testAnonymousNodes() { final TSNode rootNode = tree.getRootNode(); assertThat( rootNode.hasError() ).isFalse(); - assertThat( print( rootNode, content ) ).doesNotContain( "ERROR" ); - assertThat( print( rootNode, content ) ).contains( "[" ); - assertThat( print( rootNode, content ) ).contains( "]" ); + assertThat( TreeSitterUtil.print( rootNode, new TurtleSyntaxTree.StringTokenProvider( content ) ) ).doesNotContain( "ERROR" ); + assertThat( TreeSitterUtil.print( rootNode, new TurtleSyntaxTree.StringTokenProvider( content ) ) ).contains( "[" ); + assertThat( TreeSitterUtil.print( rootNode, new TurtleSyntaxTree.StringTokenProvider( content ) ) ).contains( "]" ); } @Test @@ -248,7 +248,7 @@ void testComplexDocument() { final TSNode rootNode = tree.getRootNode(); assertThat( rootNode.hasError() ).isFalse(); - assertThat( print( rootNode, content ) ).doesNotContain( "ERROR" ); + assertThat( TreeSitterUtil.print( rootNode, new TurtleSyntaxTree.StringTokenProvider( content ) ) ).doesNotContain( "ERROR" ); } @Test @@ -264,7 +264,7 @@ void testBrokenSyntaxMissingDot() { // Should have errors due to missing dot after prefix declaration assertThat( rootNode.hasError() ).isTrue(); - assertThat( print( rootNode, content ) ).contains( "ERROR" ); + assertThat( TreeSitterUtil.print( rootNode, new TurtleSyntaxTree.StringTokenProvider( content ) ) ).contains( "ERROR" ); } @Test @@ -280,7 +280,7 @@ void testBrokenSyntaxInvalidUri() { // Should have errors due to invalid URI assertThat( rootNode.hasError() ).isTrue(); - assertThat( print( rootNode, content ) ).contains( "ERROR" ); + assertThat( TreeSitterUtil.print( rootNode, new TurtleSyntaxTree.StringTokenProvider( content ) ) ).contains( "ERROR" ); } @Test @@ -296,7 +296,7 @@ void testBrokenSyntaxUnterminatedString() { // Should have errors due to unterminated string assertThat( rootNode.hasError() ).isTrue(); - assertThat( print( rootNode, content ) ).contains( "ERROR" ); + assertThat( TreeSitterUtil.print( rootNode, new TurtleSyntaxTree.StringTokenProvider( content ) ) ).contains( "ERROR" ); } @Test @@ -314,7 +314,7 @@ void testBrokenSyntaxMismatchedBrackets() { // Should have errors due to mismatched brackets assertThat( rootNode.hasError() ).isTrue(); - assertThat( print( rootNode, content ) ).contains( "ERROR" ); + assertThat( TreeSitterUtil.print( rootNode, new TurtleSyntaxTree.StringTokenProvider( content ) ) ).contains( "ERROR" ); } @Test @@ -330,7 +330,7 @@ void testBrokenSyntaxInvalidPrefix() { // Should have errors due to invalid prefix name (starts with number) assertThat( rootNode.hasError() ).isTrue(); - assertThat( print( rootNode, content ) ).contains( "ERROR" ); + assertThat( TreeSitterUtil.print( rootNode, new TurtleSyntaxTree.StringTokenProvider( content ) ) ).contains( "ERROR" ); } @Test @@ -346,7 +346,7 @@ void testBrokenSyntaxIncompleteTriple() { // Should have errors due to missing object assertThat( rootNode.hasError() ).isTrue(); - assertThat( print( rootNode, content ) ).contains( "ERROR" ); + assertThat( TreeSitterUtil.print( rootNode, new TurtleSyntaxTree.StringTokenProvider( content ) ) ).contains( "ERROR" ); } @Test @@ -364,7 +364,7 @@ void testSemicolonAndCommaSyntax() { final TSNode rootNode = tree.getRootNode(); assertThat( rootNode.hasError() ).isFalse(); - assertThat( print( rootNode, content ) ).doesNotContain( "ERROR" ); + assertThat( TreeSitterUtil.print( rootNode, new TurtleSyntaxTree.StringTokenProvider( content ) ) ).doesNotContain( "ERROR" ); } @Test @@ -385,83 +385,6 @@ void testComments() { final TSNode rootNode = tree.getRootNode(); assertThat( rootNode.hasError() ).isFalse(); - assertThat( print( rootNode, content ) ).doesNotContain( "ERROR" ); - } - - public static String print( final TSNode node, final String source ) { - final StringBuilder builder = new StringBuilder(); - print( node, builder, 0, source ); - return builder.toString(); - } - - private static void print( final TSNode node, final StringBuilder builder, final int indentLevel, final String source ) { - builder.repeat( " ", indentLevel ); - builder.append( "- '" ); - builder.append( node.getType() ); - builder.append( "'" ); - if ( node.hasError() ) { - builder.append( " (ERROR)" ); - } else if ( node.getStartPoint().getRow() == node.getEndPoint().getRow() ) { - final String nodeContent = getSubDocument( source, node.getStartPoint().getRow(), node.getStartPoint().getColumn(), - node.getEndPoint().getRow(), node.getEndPoint().getColumn() ); - if ( !nodeContent.equals( node.getType() ) ) { - builder.append( " (" ); - builder.append( nodeContent ); - builder.append( ")" ); - } - } - builder.append( "\n" ); - for ( int i = 0; i < node.getChildCount(); i++ ) { - print( node.getChild( i ), builder, indentLevel + 1, source ); - } - } - - /** - * Extracts a substring from a multi-line string using line and column coordinates. - * - * @param originalString the source string - * @param fromLine the starting line (0-based) - * @param fromColumn the starting column (0-based) - * @param toLine the ending line (0-based) - * @param toColumn the ending column (0-based, exclusive) - * @return the extracted substring - */ - private static String getSubDocument( final String originalString, final int fromLine, final int fromColumn, - final int toLine, final int toColumn ) { - if ( originalString == null || originalString.isEmpty() ) { - return ""; - } - - // Calculate the start index by navigating to the start line - int currentLine = 0; - int i = 0; - - while ( i < originalString.length() && currentLine < fromLine ) { - if ( originalString.charAt( i ) == '\n' ) { - currentLine++; - } - i++; - } - - final int startIndex = i + fromColumn; - - // Calculate the end index by navigating to the end line - currentLine = 0; - i = 0; - - while ( i < originalString.length() && currentLine < toLine ) { - if ( originalString.charAt( i ) == '\n' ) { - currentLine++; - } - i++; - } - - final int endIndex = i + toColumn; - - // Clamp indices to valid range - final int clampedStart = Math.clamp( startIndex, 0, originalString.length() ); - final int clampedEnd = Math.clamp( endIndex, clampedStart, originalString.length() ); - - return originalString.substring( clampedStart, clampedEnd ); + assertThat( TreeSitterUtil.print( rootNode, new TurtleSyntaxTree.StringTokenProvider( content ) ) ).doesNotContain( "ERROR" ); } } diff --git a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/Document.java b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/Document.java index 7143d1b46..ab74c2fa0 100644 --- a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/Document.java +++ b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/Document.java @@ -15,11 +15,13 @@ import java.io.InputStream; +import org.eclipse.esmf.treesitterturtle.TurtleSyntaxTree; + import org.eclipse.lsp4j.Position; import org.eclipse.lsp4j.Range; import org.jspecify.annotations.Nullable; -public class Document { +public class Document implements TurtleSyntaxTree.TokenProvider { private final String uri; private Rope content; @@ -64,4 +66,9 @@ public void update( final @Nullable Range range, final String newContent ) { content = content.update( start.getLine(), start.getCharacter(), end.getLine(), end.getCharacter(), newContent ); } + + @Override + public String apply( final TurtleSyntaxTree.Location location ) { + return subSequence( location.fromLine(), location.fromColumn(), location.toLine(), location.toColumn() ); + } } diff --git a/core/esmf-turtle-language-server/src/test/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TurtleParserServiceTest.java b/core/esmf-turtle-language-server/src/test/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TurtleParserServiceTest.java index a940607f5..45ba2d197 100644 --- a/core/esmf-turtle-language-server/src/test/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TurtleParserServiceTest.java +++ b/core/esmf-turtle-language-server/src/test/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TurtleParserServiceTest.java @@ -15,6 +15,8 @@ import static org.assertj.core.api.Assertions.assertThat; +import org.eclipse.esmf.treesitterturtle.TreeSitterUtil; + import org.eclipse.lsp4j.Position; import org.eclipse.lsp4j.Range; import org.eclipse.lsp4j.TextDocumentContentChangeEvent; From 16ec7fbc450063c18cd8f7d5a1755035f8348e75 Mon Sep 17 00:00:00 2001 From: Andreas Textor Date: Mon, 18 May 2026 14:16:42 +0200 Subject: [PATCH 21/41] Fix broken RDF in test --- .../eclipse/esmf/treesitterturtle/TreeSitterTurtleTest.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/core/esmf-tree-sitter-turtle/src/test/java/org/eclipse/esmf/treesitterturtle/TreeSitterTurtleTest.java b/core/esmf-tree-sitter-turtle/src/test/java/org/eclipse/esmf/treesitterturtle/TreeSitterTurtleTest.java index d8ce38d92..64dd88861 100644 --- a/core/esmf-tree-sitter-turtle/src/test/java/org/eclipse/esmf/treesitterturtle/TreeSitterTurtleTest.java +++ b/core/esmf-tree-sitter-turtle/src/test/java/org/eclipse/esmf/treesitterturtle/TreeSitterTurtleTest.java @@ -194,15 +194,14 @@ void testAnonymousNodes() { ] . # Blank node with multiple predicates and objects - ex:person [ + ex:person ex:firstName "John" ; ex:lastName "Doe" ; ex:age 30 ; ex:knows [ ex:firstName "Jane" ; ex:lastName "Smith" - ] - ] . + ] . """; final TSTree tree = parser.parseString( null, content ); From a14372ed35b1158dac24c6e6dd4c4b34b3efd8f3 Mon Sep 17 00:00:00 2001 From: Andreas Textor Date: Tue, 19 May 2026 07:22:36 +0200 Subject: [PATCH 22/41] Fix AspectModelOpenApiGeneratorTest when NOP Logger is configured --- .../AspectModelOpenApiGeneratorTest.java | 30 +++++++++++-------- 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/core/esmf-aspect-model-document-generators/src/test/java/org/eclipse/esmf/aspectmodel/generator/openapi/AspectModelOpenApiGeneratorTest.java b/core/esmf-aspect-model-document-generators/src/test/java/org/eclipse/esmf/aspectmodel/generator/openapi/AspectModelOpenApiGeneratorTest.java index e382541de..ec80cc4b4 100644 --- a/core/esmf-aspect-model-document-generators/src/test/java/org/eclipse/esmf/aspectmodel/generator/openapi/AspectModelOpenApiGeneratorTest.java +++ b/core/esmf-aspect-model-document-generators/src/test/java/org/eclipse/esmf/aspectmodel/generator/openapi/AspectModelOpenApiGeneratorTest.java @@ -15,6 +15,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatCode; +import static org.assertj.core.api.Assumptions.assumeThat; import java.io.IOException; import java.io.InputStream; @@ -26,6 +27,9 @@ import java.util.Locale; import java.util.Map; +import org.apache.commons.io.IOUtils; +import org.assertj.core.api.InstanceOfAssertFactories; + import org.eclipse.esmf.aspectmodel.generator.AbstractSchemaArtifact; import org.eclipse.esmf.aspectmodel.generator.jsonschema.AspectModelJsonSchemaGenerator; import org.eclipse.esmf.metamodel.Aspect; @@ -33,9 +37,13 @@ import org.eclipse.esmf.test.TestAspect; import org.eclipse.esmf.test.TestResources; -import ch.qos.logback.classic.Logger; -import ch.qos.logback.classic.spi.ILoggingEvent; -import ch.qos.logback.core.read.ListAppender; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.parallel.Execution; +import org.junit.jupiter.api.parallel.ExecutionMode; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.EnumSource; +import org.slf4j.LoggerFactory; + import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonToken; import com.fasterxml.jackson.databind.JsonNode; @@ -50,6 +58,10 @@ import com.jayway.jsonpath.DocumentContext; import com.jayway.jsonpath.JsonPath; import com.jayway.jsonpath.Option; + +import ch.qos.logback.classic.Logger; +import ch.qos.logback.classic.spi.ILoggingEvent; +import ch.qos.logback.core.read.ListAppender; import io.swagger.parser.OpenAPIParser; import io.swagger.v3.oas.models.OpenAPI; import io.swagger.v3.oas.models.Operation; @@ -59,14 +71,6 @@ import io.swagger.v3.oas.models.parameters.Parameter; import io.swagger.v3.oas.models.responses.ApiResponse; import io.swagger.v3.parser.core.models.SwaggerParseResult; -import org.apache.commons.io.IOUtils; -import org.assertj.core.api.InstanceOfAssertFactories; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.parallel.Execution; -import org.junit.jupiter.api.parallel.ExecutionMode; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.EnumSource; -import org.slf4j.LoggerFactory; class AspectModelOpenApiGeneratorTest { private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); @@ -301,7 +305,9 @@ void testValidTemplate() throws IOException { @Test void testInValidParameterName() throws IOException { final ListAppender logAppender = new ListAppender<>(); - final Logger logger = (Logger) LoggerFactory.getLogger( AspectModelOpenApiGenerator.class ); + final org.slf4j.Logger theLogger = LoggerFactory.getLogger( AspectModelOpenApiGenerator.class ); + assumeThat( theLogger ).isInstanceOf( ch.qos.logback.classic.Logger.class ); + final Logger logger = (Logger) theLogger; logger.addAppender( logAppender ); logAppender.start(); final Aspect aspect = TestResources.load( TestAspect.ASPECT_WITHOUT_SEE_ATTRIBUTE ).aspect(); From de67330b59d36a5598058ea18c387b2ebfad1805 Mon Sep 17 00:00:00 2001 From: Andreas Textor Date: Tue, 19 May 2026 07:25:53 +0200 Subject: [PATCH 23/41] Highlight the cause of an AspectModelLoadingException --- .../aspectmodel/AspectLoadingException.java | 4 ++ .../aspectmodel/loader/AspectModelLoader.java | 1 - .../esmf/aspectmodel/loader/Instantiator.java | 13 ++--- .../loader/ModelElementFactory.java | 31 ++++++------ .../instantiator/PropertyInstantiator.java | 6 +-- .../resolver/parser/TurtleParserProfile.java | 49 +++++++++++++------ .../validation/ProcessingViolation.java | 10 ++++ 7 files changed, 76 insertions(+), 38 deletions(-) diff --git a/core/esmf-aspect-meta-model-interface/src/main/java/org/eclipse/esmf/aspectmodel/AspectLoadingException.java b/core/esmf-aspect-meta-model-interface/src/main/java/org/eclipse/esmf/aspectmodel/AspectLoadingException.java index d99ad93a6..a9dc1f037 100644 --- a/core/esmf-aspect-meta-model-interface/src/main/java/org/eclipse/esmf/aspectmodel/AspectLoadingException.java +++ b/core/esmf-aspect-meta-model-interface/src/main/java/org/eclipse/esmf/aspectmodel/AspectLoadingException.java @@ -40,4 +40,8 @@ public AspectLoadingException( final String message, final RDFNode highlightElem super( message ); this.highlightElement = highlightElement; } + + public @Nullable RDFNode highlightElement() { + return highlightElement; + } } diff --git a/core/esmf-aspect-meta-model-java/src/main/java/org/eclipse/esmf/aspectmodel/loader/AspectModelLoader.java b/core/esmf-aspect-meta-model-java/src/main/java/org/eclipse/esmf/aspectmodel/loader/AspectModelLoader.java index cb1708db1..3fcce8cf0 100644 --- a/core/esmf-aspect-meta-model-java/src/main/java/org/eclipse/esmf/aspectmodel/loader/AspectModelLoader.java +++ b/core/esmf-aspect-meta-model-java/src/main/java/org/eclipse/esmf/aspectmodel/loader/AspectModelLoader.java @@ -660,7 +660,6 @@ public AspectModel loadAspectModelFiles( final Collection input .filter( statement -> !statement.getObject().isURIResource() || !statement.getResource().equals( SammNs.SAMM.Namespace() ) ) .map( Statement::getSubject ) .filter( RDFNode::isURIResource ) - .map( resource -> mergedModel.createResource( resource.getURI() ) ) .map( resource -> modelElementFactory.create( ModelElement.class, resource ) ) .toList(); aspectModelFile.setElements( fileElements ); diff --git a/core/esmf-aspect-meta-model-java/src/main/java/org/eclipse/esmf/aspectmodel/loader/Instantiator.java b/core/esmf-aspect-meta-model-java/src/main/java/org/eclipse/esmf/aspectmodel/loader/Instantiator.java index 6ce6175cd..a8aed45b1 100644 --- a/core/esmf-aspect-meta-model-java/src/main/java/org/eclipse/esmf/aspectmodel/loader/Instantiator.java +++ b/core/esmf-aspect-meta-model-java/src/main/java/org/eclipse/esmf/aspectmodel/loader/Instantiator.java @@ -128,7 +128,7 @@ private Statement getDataType( final Resource resource ) { final Statement dataType = resource.getProperty( SammNs.SAMM.dataType() ); if ( dataType == null ) { throw new AspectLoadingException( - String.format( "No datatype is defined on the Characteristic instance '%s: '.", resource.getLocalName() ), + String.format( "No datatype is defined on the Characteristic instance '%s'.", resource.getLocalName() ), resource ); } return dataType; @@ -158,7 +158,7 @@ protected Value buildValue( final RDFNode node, final Optional charact if ( node.isLiteral() ) { final Literal literal = node.asLiteral(); return valueInstantiator.buildScalarValue( literal.getLexicalForm(), literal.getLanguage(), literal.getDatatypeURI() ) - .orElseThrow( () -> new AspectLoadingException( "Literal can not be parsed: " + literal ) ); + .orElseThrow( () -> new AspectLoadingException( "Literal can not be parsed: " + literal, literal ) ); } if ( node.isResource() ) { @@ -167,7 +167,7 @@ protected Value buildValue( final RDFNode node, final Optional charact final Optional valueOpt = optionalAttributeValue( resource, SammNs.SAMM.value() ).map( Statement::getString ); if ( valueOpt.isEmpty() ) { - throw new AspectLoadingException( "samm:Value must contain a samm:value property" ); + throw new AspectLoadingException( "samm:Value must contain a samm:value property", resource ); } return new DefaultScalarValue( buildBaseAttributes( resource ), valueOpt.get(), new DefaultScalar( type.getUrn() ) ); @@ -197,7 +197,7 @@ protected Value buildValue( final RDFNode node, final Optional charact // This could happen if an entity instance should be constructed for an AbstractEntity type if ( !type.is( Entity.class ) ) { - throw new AspectLoadingException( "Expected type of value " + node + " to be samm:Entity, but it is not" ); + throw new AspectLoadingException( "Expected type of value " + node + " to be samm:Entity, but it is not", node ); } // Entities @@ -222,11 +222,12 @@ protected EntityInstance buildEntityInstance( final Resource entityInstance, fin if ( property.isOptional() ) { return; } - throw new AspectLoadingException( "Mandatory Property " + property + " not found in Entity instance " + entityInstance ); + throw new AspectLoadingException( "Mandatory Property " + property + " not found in Entity instance " + entityInstance, + entityInstance ); } final RDFNode rdfValue = entityInstance.getProperty( rdfProperty ).getObject(); final Type propertyType = property.getDataType() - .orElseThrow( () -> new AspectLoadingException( "Invalid Property without a dataType found" ) ); + .orElseThrow( () -> new AspectLoadingException( "Invalid Property without a dataType found", entityInstance ) ); final Resource characteristic = attributeValue( rdfProperty, SammNs.SAMM.characteristic() ).getResource(); final Value value = buildValue( rdfValue, Optional.of( characteristic ), propertyType ); assertions.put( property, value ); diff --git a/core/esmf-aspect-meta-model-java/src/main/java/org/eclipse/esmf/aspectmodel/loader/ModelElementFactory.java b/core/esmf-aspect-meta-model-java/src/main/java/org/eclipse/esmf/aspectmodel/loader/ModelElementFactory.java index 075bc3291..2c093f00d 100644 --- a/core/esmf-aspect-meta-model-java/src/main/java/org/eclipse/esmf/aspectmodel/loader/ModelElementFactory.java +++ b/core/esmf-aspect-meta-model-java/src/main/java/org/eclipse/esmf/aspectmodel/loader/ModelElementFactory.java @@ -26,6 +26,15 @@ import java.util.stream.Collectors; import java.util.stream.Stream; +import org.apache.commons.lang3.StringUtils; +import org.apache.jena.rdf.model.Model; +import org.apache.jena.rdf.model.RDFNode; +import org.apache.jena.rdf.model.Resource; +import org.apache.jena.rdf.model.Statement; +import org.apache.jena.rdf.model.StmtIterator; +import org.apache.jena.vocabulary.RDF; +import org.apache.jena.vocabulary.RDFS; + import org.eclipse.esmf.aspectmodel.AspectLoadingException; import org.eclipse.esmf.aspectmodel.AspectModelFile; import org.eclipse.esmf.aspectmodel.loader.instantiator.AbstractEntityInstantiator; @@ -77,14 +86,6 @@ import org.eclipse.esmf.metamodel.vocabulary.SammNs; import com.google.common.collect.Streams; -import org.apache.commons.lang3.StringUtils; -import org.apache.jena.rdf.model.Model; -import org.apache.jena.rdf.model.RDFNode; -import org.apache.jena.rdf.model.Resource; -import org.apache.jena.rdf.model.Statement; -import org.apache.jena.rdf.model.StmtIterator; -import org.apache.jena.vocabulary.RDF; -import org.apache.jena.vocabulary.RDFS; /** * Used as part of the loading process in the {@link AspectModelLoader}, it creates instance for the @@ -170,11 +171,12 @@ public T create( final Class clazz, final Resource m // No generic instantiator could be found. This means the element is an entity instance if ( !model.contains( targetType, RDF.type, (RDFNode) null ) ) { - throw new AspectLoadingException( "Could not load " + modelElement + ": Unknown type " + targetType ); + throw new AspectLoadingException( "Could not load " + modelElement + ": Unknown type " + targetType, modelElement ); } final Entity entity = create( Entity.class, targetType ); if ( entity == null ) { - throw new AspectLoadingException( "Could not load " + modelElement + ": Expected " + targetType + " to be an Entity" ); + throw new AspectLoadingException( "Could not load " + modelElement + ": Expected " + targetType + " to be an Entity", + modelElement ); } return (T) new EntityInstanceInstantiator( this, entity ).apply( modelElement ); } @@ -190,7 +192,7 @@ public Unit findOrCreateUnit( final Resource unitResource ) { if ( SammNs.UNIT.getNamespace().equals( unitResource.getNameSpace() ) ) { final AspectModelUrn unitUrn = AspectModelUrn.fromUrn( unitResource.getURI() ); return Units.fromName( unitUrn.getName() ) - .orElseThrow( () -> new AspectLoadingException( "Unit definition for " + unitUrn + " is invalid" ) ); + .orElseThrow( () -> new AspectLoadingException( "Unit definition for " + unitUrn + " is invalid", unitResource ) ); } final Set quantityKinds = Streams.stream( @@ -220,7 +222,7 @@ private Resource resourceType( final Resource resource ) { .filter( Optional::isPresent ) .map( Optional::get ) .findFirst() - .orElseThrow( () -> new AspectLoadingException( "Resource " + resource + " has no type" ) ); + .orElseThrow( () -> new AspectLoadingException( "Resource " + resource + " has no type", resource ) ); } protected Model getModel() { @@ -301,7 +303,8 @@ private static List getSeeValues( final Resource resource, final Attribu private static String getSyntheticName( final Resource modelElement ) { final Resource namedParent = getNamedParent( modelElement, modelElement.getModel() ); if ( namedParent == null ) { - throw new AspectLoadingException( "At least one anonymous node in the model does not have a parent with a regular name." ); + throw new AspectLoadingException( "At least one anonymous node in the model does not have a parent with a regular name.", + modelElement ); } final String parentModelElementUri = namedParent.getURI(); final String parentModelElementName = AspectModelUrn.from( parentModelElementUri ) @@ -365,7 +368,7 @@ private static Resource getModelElementType( final Resource modelElement ) { // This model element has no type, but maybe it extends another element final Statement extendsStatement = modelElement.getProperty( SammNs.SAMM._extends() ); if ( extendsStatement == null ) { - throw new AspectLoadingException( "Model element has no type and does not extend another type: " + modelElement ); + throw new AspectLoadingException( "Model element has no type and does not extend another type: " + modelElement, modelElement ); } final Resource superElement = extendsStatement.getObject().asResource(); diff --git a/core/esmf-aspect-meta-model-java/src/main/java/org/eclipse/esmf/aspectmodel/loader/instantiator/PropertyInstantiator.java b/core/esmf-aspect-meta-model-java/src/main/java/org/eclipse/esmf/aspectmodel/loader/instantiator/PropertyInstantiator.java index 192d60106..be9087cd7 100644 --- a/core/esmf-aspect-meta-model-java/src/main/java/org/eclipse/esmf/aspectmodel/loader/instantiator/PropertyInstantiator.java +++ b/core/esmf-aspect-meta-model-java/src/main/java/org/eclipse/esmf/aspectmodel/loader/instantiator/PropertyInstantiator.java @@ -98,7 +98,7 @@ private ScalarValue buildScalarValue( final RDFNode node, final Type expectedTyp if ( node.isLiteral() ) { final Literal literal = node.asLiteral(); return valueInstantiator.buildScalarValue( literal.getLexicalForm(), literal.getLanguage(), literal.getDatatypeURI() ) - .orElseThrow( () -> new AspectLoadingException( "Literal cannot be parsed: " + literal ) ); + .orElseThrow( () -> new AspectLoadingException( "Literal cannot be parsed: " + literal, literal ) ); } if ( node.isResource() ) { @@ -108,7 +108,7 @@ private ScalarValue buildScalarValue( final RDFNode node, final Type expectedTyp final Optional valueOpt = optionalAttributeValue( resource, SammNs.SAMM.value() ).map( Statement::getString ); if ( valueOpt.isEmpty() ) { - throw new AspectLoadingException( "samm:Value must contain a samm:value property" ); + throw new AspectLoadingException( "samm:Value must contain a samm:value property", resource ); } return new DefaultScalarValue( buildBaseAttributes( resource ), valueOpt.get(), new DefaultScalar( expectedType.toString() ) ); @@ -117,6 +117,6 @@ private ScalarValue buildScalarValue( final RDFNode node, final Type expectedTyp return new DefaultScalarValue( buildBaseAttributes( resource ), resource.getURI(), new DefaultScalar( expectedType.toString() ) ); } - throw new AspectLoadingException( "Unexpected RDF node type: " + node ); + throw new AspectLoadingException( "Unexpected RDF node type: " + node, node ); } } diff --git a/core/esmf-aspect-meta-model-java/src/main/java/org/eclipse/esmf/aspectmodel/resolver/parser/TurtleParserProfile.java b/core/esmf-aspect-meta-model-java/src/main/java/org/eclipse/esmf/aspectmodel/resolver/parser/TurtleParserProfile.java index 4bc0b644f..d9a04ca90 100644 --- a/core/esmf-aspect-meta-model-java/src/main/java/org/eclipse/esmf/aspectmodel/resolver/parser/TurtleParserProfile.java +++ b/core/esmf-aspect-meta-model-java/src/main/java/org/eclipse/esmf/aspectmodel/resolver/parser/TurtleParserProfile.java @@ -13,6 +13,8 @@ package org.eclipse.esmf.aspectmodel.resolver.parser; +import java.util.List; + import org.apache.jena.datatypes.RDFDatatype; import org.apache.jena.graph.Graph; import org.apache.jena.graph.Node; @@ -27,6 +29,7 @@ import org.apache.jena.sparql.core.Quad; import org.eclipse.esmf.aspectmodel.ValueParsingException; +import org.eclipse.esmf.treesitterturtle.ParserTokenType; import org.eclipse.esmf.treesitterturtle.TurtleSyntaxTree; import org.jspecify.annotations.Nullable; @@ -41,11 +44,11 @@ public class TurtleParserProfile implements ParserProfile { private static final Logger LOG = LoggerFactory.getLogger( TurtleParserProfile.class ); private final ParserProfile parserProfile; - private final @Nullable TurtleSyntaxTree syntaxTree; + private final List tokens; public TurtleParserProfile( final ParserProfile parserProfile, final @Nullable TurtleSyntaxTree syntaxTree ) { this.parserProfile = parserProfile; - this.syntaxTree = syntaxTree; + tokens = syntaxTree == null ? List.of() : syntaxTree.tokens().toList(); } @Override @@ -57,35 +60,36 @@ public String getBaseURI() { * Finds the matching Tree-sitter token for a given Jena token based on line and column position. * If no exact match is found, returns the nearest token. * - * @param token the Jena token to find a match for + * @param targetLine the line of the originating Jena token (1-based) + * @param targetColumn the column of the originating Jena token (1-based) * @return the matching Tree-sitter token, or null if syntax tree is not available or no tokens * found */ - private TurtleSyntaxTree.@Nullable Token findMatchingTreeSitterToken( final Token token ) { - if ( syntaxTree == null ) { + private TurtleSyntaxTree.@Nullable Token findMatchingTreeSitterToken( final long targetLine, final long targetColumn ) { + if ( tokens.isEmpty() ) { return null; } - final long targetLine = token.getLine() - 1; - final long targetColumn = token.getColumn(); - TurtleSyntaxTree.Token exactMatch = null; TurtleSyntaxTree.Token nearestMatch = null; long minDistance = Long.MAX_VALUE; + final long originatingLine = targetLine - 1; + final long originatingColumn = targetColumn - 1; - // Iterate through all tokens in the syntax tree - for ( final TurtleSyntaxTree.Token treeToken : syntaxTree.tokens().toList() ) { + for ( final TurtleSyntaxTree.Token treeToken : tokens ) { + if ( treeToken.type().equals( ParserTokenType.OBJECT_LIST ) || treeToken.type().equals( ParserTokenType.TRIPLE ) ) { + continue; + } final int tokenLine = treeToken.location().fromLine(); final int tokenColumn = treeToken.location().fromColumn(); - // Check for exact match - if ( tokenLine == targetLine && tokenColumn == targetColumn ) { + if ( tokenLine == originatingLine && tokenColumn == originatingColumn ) { exactMatch = treeToken; break; } // Calculate Manhattan distance for nearest match - final long distance = Math.abs( tokenLine - targetLine ) * 1000 + Math.abs( tokenColumn - targetColumn ); + final long distance = Math.abs( tokenLine - originatingLine ) * 1000 + Math.abs( tokenColumn - originatingColumn ); if ( distance < minDistance ) { minDistance = distance; @@ -96,6 +100,18 @@ public String getBaseURI() { return exactMatch != null ? exactMatch : nearestMatch; } + /** + * Finds the matching Tree-sitter token for a given Jena token based on line and column position. + * If no exact match is found, returns the nearest token. + * + * @param token the Jena token to find a match for + * @return the matching Tree-sitter token, or null if syntax tree is not available or no tokens + * found + */ + private TurtleSyntaxTree.@Nullable Token findMatchingTreeSitterToken( final Token token ) { + return findMatchingTreeSitterToken( token.getLine(), token.getColumn() ); + } + @Override public Node create( final Node currentGraph, final Token token ) { try { @@ -145,7 +161,12 @@ public void setBaseIRI( final String baseIri ) { @Override public Triple createTriple( final Node subject, final Node predicate, final Node object, final long line, final long col ) { - return parserProfile.createTriple( subject, predicate, object, line, col ); + final Triple triple = parserProfile.createTriple( subject, predicate, object, line, col ); + final TurtleSyntaxTree.@Nullable Token treeSitterToken = findMatchingTreeSitterToken( line, col ); + if ( treeSitterToken != null ) { + TokenRegistry.put( object, new SmartToken( treeSitterToken ) ); + } + return triple; } @Override diff --git a/core/esmf-aspect-model-validator/src/main/java/org/eclipse/esmf/aspectmodel/validation/ProcessingViolation.java b/core/esmf-aspect-model-validator/src/main/java/org/eclipse/esmf/aspectmodel/validation/ProcessingViolation.java index 5ca9f32d5..c26fbb65f 100644 --- a/core/esmf-aspect-model-validator/src/main/java/org/eclipse/esmf/aspectmodel/validation/ProcessingViolation.java +++ b/core/esmf-aspect-model-validator/src/main/java/org/eclipse/esmf/aspectmodel/validation/ProcessingViolation.java @@ -13,9 +13,14 @@ package org.eclipse.esmf.aspectmodel.validation; +import org.apache.jena.rdf.model.RDFNode; + +import org.eclipse.esmf.aspectmodel.AspectLoadingException; import org.eclipse.esmf.aspectmodel.shacl.violation.EvaluationContext; import org.eclipse.esmf.aspectmodel.shacl.violation.Violation; +import org.jspecify.annotations.Nullable; + /** * Meta violation: The validation was unsuccessful, for example because the model could not be * loaded or not be resolved @@ -42,6 +47,11 @@ public String message() { return violationSpecificMessage(); } + @Override + public @Nullable RDFNode highlight() { + return cause instanceof final AspectLoadingException aspectLoadingException ? aspectLoadingException.highlightElement() : null; + } + @Override public T accept( final Visitor visitor ) { return visitor.visitProcessingViolation( this ); From 796b907f94632a85d1d760ffccd78ed95034af6b Mon Sep 17 00:00:00 2001 From: Andreas Textor Date: Tue, 19 May 2026 07:58:39 +0200 Subject: [PATCH 24/41] Update TokenRegistry with newly created resources in merged graph --- .../aspectmodel/loader/AspectModelLoader.java | 5 +++++ .../resolver/parser/TokenRegistry.java | 16 +++++++++++++++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/core/esmf-aspect-meta-model-java/src/main/java/org/eclipse/esmf/aspectmodel/loader/AspectModelLoader.java b/core/esmf-aspect-meta-model-java/src/main/java/org/eclipse/esmf/aspectmodel/loader/AspectModelLoader.java index 3fcce8cf0..909fa5a1c 100644 --- a/core/esmf-aspect-meta-model-java/src/main/java/org/eclipse/esmf/aspectmodel/loader/AspectModelLoader.java +++ b/core/esmf-aspect-meta-model-java/src/main/java/org/eclipse/esmf/aspectmodel/loader/AspectModelLoader.java @@ -660,6 +660,11 @@ public AspectModel loadAspectModelFiles( final Collection input .filter( statement -> !statement.getObject().isURIResource() || !statement.getResource().equals( SammNs.SAMM.Namespace() ) ) .map( Statement::getSubject ) .filter( RDFNode::isURIResource ) + .map( resource -> { + final Resource newResource = mergedModel.createResource( resource.getURI() ); + TokenRegistry.updateNode( resource.asNode(), newResource.asNode() ); + return newResource; + } ) .map( resource -> modelElementFactory.create( ModelElement.class, resource ) ) .toList(); aspectModelFile.setElements( fileElements ); diff --git a/core/esmf-aspect-meta-model-java/src/main/java/org/eclipse/esmf/aspectmodel/resolver/parser/TokenRegistry.java b/core/esmf-aspect-meta-model-java/src/main/java/org/eclipse/esmf/aspectmodel/resolver/parser/TokenRegistry.java index 5c2d7b942..4ffa539a7 100644 --- a/core/esmf-aspect-meta-model-java/src/main/java/org/eclipse/esmf/aspectmodel/resolver/parser/TokenRegistry.java +++ b/core/esmf-aspect-meta-model-java/src/main/java/org/eclipse/esmf/aspectmodel/resolver/parser/TokenRegistry.java @@ -16,10 +16,11 @@ import java.util.Map; import java.util.Optional; +import org.apache.jena.graph.Node; + import org.eclipse.esmf.aspectmodel.resolver.services.TurtleLoader; import com.google.common.collect.MapMaker; -import org.apache.jena.graph.Node; /** * This map keeps track of location information for nodes, i.e., when an RDF document is parsed @@ -44,4 +45,17 @@ public static void put( final Node node, final SmartToken token ) { public static Optional getToken( final Node node ) { return Optional.ofNullable( TOKENS.get( node ) ); } + + /** + * Replace a registered node, but keep the associated token + * + * @param oldNode the old node + * @param newNode the new node + */ + public static synchronized void updateNode( final Node oldNode, final Node newNode ) { + if ( TOKENS.containsKey( oldNode ) ) { + final SmartToken token = TOKENS.remove( oldNode ); + TOKENS.put( newNode, token ); + } + } } From c15d976d4f24f81df9ca007c679f8b9641f0f901 Mon Sep 17 00:00:00 2001 From: Andreas Textor Date: Tue, 19 May 2026 08:07:13 +0200 Subject: [PATCH 25/41] Fix failing test --- .../eclipse/esmf/aspectmodel/loader/AspectModelLoaderTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/esmf-aspect-meta-model-java/src/test/java/org/eclipse/esmf/aspectmodel/loader/AspectModelLoaderTest.java b/core/esmf-aspect-meta-model-java/src/test/java/org/eclipse/esmf/aspectmodel/loader/AspectModelLoaderTest.java index c320a4733..807c54198 100644 --- a/core/esmf-aspect-meta-model-java/src/test/java/org/eclipse/esmf/aspectmodel/loader/AspectModelLoaderTest.java +++ b/core/esmf-aspect-meta-model-java/src/test/java/org/eclipse/esmf/aspectmodel/loader/AspectModelLoaderTest.java @@ -66,7 +66,7 @@ void testLoadAspectModelsSourceFilesArePresent( final TestAspect testAspect ) { void loadAspectModelWithoutCharacteristicDatatype() { assertThatThrownBy( () -> TestResources.load( InvalidTestAspect.INVALID_CHARACTERISTIC_DATATYPE ) ) .isInstanceOf( AspectLoadingException.class ) - .hasMessage( "No datatype is defined on the Characteristic instance 'Characteristic1: '." ); + .hasMessage( "No datatype is defined on the Characteristic instance 'Characteristic1'." ); } @Test From 86c12576e052fdb64ead77ba1721c5ca5938e373 Mon Sep 17 00:00:00 2001 From: Andreas Textor Date: Tue, 19 May 2026 08:29:18 +0200 Subject: [PATCH 26/41] Fix slf4j setup in esmf-tree-sitter-turtle --- core/esmf-tree-sitter-turtle/pom.xml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/core/esmf-tree-sitter-turtle/pom.xml b/core/esmf-tree-sitter-turtle/pom.xml index aac0f4522..87127c321 100644 --- a/core/esmf-tree-sitter-turtle/pom.xml +++ b/core/esmf-tree-sitter-turtle/pom.xml @@ -62,10 +62,6 @@ tree-sitter ${tree-sitter.version} - - org.slf4j - slf4j-nop - org.apache.commons commons-compress @@ -88,6 +84,11 @@ assertj-core test + + org.slf4j + slf4j-nop + test + From b3cf0b1f38b72d78371fea0dce3592f671353df3 Mon Sep 17 00:00:00 2001 From: Andreas Textor Date: Wed, 20 May 2026 09:59:57 +0200 Subject: [PATCH 27/41] Download Turtle treesitter grammar at build instead of copying it --- core/esmf-tree-sitter-turtle/.gitignore | 1 + core/esmf-tree-sitter-turtle/pom.xml | 16 +- .../eclipse/esmf/buildtime/BuildTimeTool.java | 74 +++ .../esmf/buildtime/DownloadTurtleGrammar.java | 44 ++ .../eclipse/esmf/buildtime/DownloadZig.java | 34 +- .../eclipse/esmf/buildtime/ZigContext.java | 5 +- .../src/main/js/NOTICE.md | 3 - .../src/main/js/grammar.js | 466 ------------------ 8 files changed, 139 insertions(+), 504 deletions(-) create mode 100644 core/esmf-tree-sitter-turtle/src-buildtime/main/java/org/eclipse/esmf/buildtime/BuildTimeTool.java create mode 100644 core/esmf-tree-sitter-turtle/src-buildtime/main/java/org/eclipse/esmf/buildtime/DownloadTurtleGrammar.java delete mode 100644 core/esmf-tree-sitter-turtle/src/main/js/NOTICE.md delete mode 100644 core/esmf-tree-sitter-turtle/src/main/js/grammar.js diff --git a/core/esmf-tree-sitter-turtle/.gitignore b/core/esmf-tree-sitter-turtle/.gitignore index 6f1a609c2..982df7da0 100644 --- a/core/esmf-tree-sitter-turtle/.gitignore +++ b/core/esmf-tree-sitter-turtle/.gitignore @@ -2,6 +2,7 @@ src/main/c/parser.c src/main/c/grammar.json src/main/c/node-types.json src/main/c/tree_sitter/* +src/main/js/grammar.js src/main/js/bindings src/main/js/js .zig-cache diff --git a/core/esmf-tree-sitter-turtle/pom.xml b/core/esmf-tree-sitter-turtle/pom.xml index 87127c321..ebbb271b7 100644 --- a/core/esmf-tree-sitter-turtle/pom.xml +++ b/core/esmf-tree-sitter-turtle/pom.xml @@ -166,6 +166,20 @@ org.codehaus.mojo exec-maven-plugin + + download-turtle-grammar + generate-sources + + java + + + org.eclipse.esmf.buildtime.DownloadTurtleGrammar + + + ${project.basedir}/src/main/${js.source.directory} + + + tree-sitter-generate generate-sources @@ -235,7 +249,7 @@ compile-build-time-code - generate-sources + initialize compile diff --git a/core/esmf-tree-sitter-turtle/src-buildtime/main/java/org/eclipse/esmf/buildtime/BuildTimeTool.java b/core/esmf-tree-sitter-turtle/src-buildtime/main/java/org/eclipse/esmf/buildtime/BuildTimeTool.java new file mode 100644 index 000000000..2f5b9c41e --- /dev/null +++ b/core/esmf-tree-sitter-turtle/src-buildtime/main/java/org/eclipse/esmf/buildtime/BuildTimeTool.java @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2026 Robert Bosch Manufacturing Solutions GmbH + * + * See the AUTHORS file(s) distributed with this work for additional + * information regarding authorship. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * SPDX-License-Identifier: MPL-2.0 + */ + +package org.eclipse.esmf.buildtime; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URL; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.security.DigestInputStream; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.time.Duration; + +import org.eclipse.esmf.util.download.Download; +import org.eclipse.esmf.util.download.ProxyConfig; + +import jakarta.xml.bind.annotation.adapters.HexBinaryAdapter; + +public abstract class BuildTimeTool { + protected final Path cacheLocation; + protected final ProxyConfig proxyConfig; + + public BuildTimeTool( final Path cacheLocation ) { + this.cacheLocation = cacheLocation; + proxyConfig = ProxyConfig.detectProxySettings(); + } + + protected URL url( final String url ) { + try { + return URI.create( url ).toURL(); + } catch ( final MalformedURLException exception ) { + throw new BuildTimeException( exception ); + } + } + + protected File getOrDownloadFile( final URL location ) { + final Path filePath = Paths.get( location.getPath() ); + final String filename = filePath.getName( filePath.getNameCount() - 1 ).toString(); + final File targetFile = cacheLocation.resolve( filename ).toFile(); + if ( targetFile.exists() ) { + return targetFile; + } + + final Download.Config config = new Download.Config( proxyConfig, Duration.ofSeconds( 3L ) ); + System.out.println( "Downloading " + location + " to " + targetFile.getName() + "..." ); + return new Download( config ).downloadFile( location, targetFile ); + } + + public String sha1( final File file ) { + try ( final InputStream input = new FileInputStream( file ); + final DigestInputStream digestStream = new DigestInputStream( input, MessageDigest.getInstance( "SHA-1" ) ) ) { + digestStream.readAllBytes(); + return new HexBinaryAdapter().marshal( digestStream.getMessageDigest().digest() ).toLowerCase(); + } catch ( final NoSuchAlgorithmException | IOException exception ) { + throw new BuildTimeException( "Could not calculate SHA1 sum for " + file ); + } + } +} diff --git a/core/esmf-tree-sitter-turtle/src-buildtime/main/java/org/eclipse/esmf/buildtime/DownloadTurtleGrammar.java b/core/esmf-tree-sitter-turtle/src-buildtime/main/java/org/eclipse/esmf/buildtime/DownloadTurtleGrammar.java new file mode 100644 index 000000000..3e56b6acc --- /dev/null +++ b/core/esmf-tree-sitter-turtle/src-buildtime/main/java/org/eclipse/esmf/buildtime/DownloadTurtleGrammar.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2026 Robert Bosch Manufacturing Solutions GmbH + * + * See the AUTHORS file(s) distributed with this work for additional + * information regarding authorship. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * SPDX-License-Identifier: MPL-2.0 + */ + +package org.eclipse.esmf.buildtime; + +import java.io.File; +import java.net.URL; +import java.nio.file.Path; + +public class DownloadTurtleGrammar extends BuildTimeTool { + private static final String GRAMMAR_JS_SHA1 = "6146fa24f0dd601a34025ef3618c3cd4d5dfdb4b"; + + public DownloadTurtleGrammar( final Path cacheLocation ) { + super( cacheLocation ); + } + + public void downloadTurtleGrammar() { + final URL url = url( "https://raw.githubusercontent.com/GordianDziwis/tree-sitter-turtle/refs/heads/main/grammar.js" ); + final File grammarJs = getOrDownloadFile( url ); + if ( !grammarJs.exists() ) { + throw new BuildTimeException( "Downloading Turtle grammar failed" ); + } + final String sha1 = sha1( grammarJs ); + if ( !sha1.equals( GRAMMAR_JS_SHA1 ) ) { + throw new BuildTimeException( "Invalid SHA1 sum for grammar.js. Expected: " + GRAMMAR_JS_SHA1 + ", found: " + sha1 ); + } + } + + static void main( final String[] args ) { + final Path cacheLocation = Path.of( args[0] ); + final DownloadTurtleGrammar downloadTurtleGrammar = new DownloadTurtleGrammar( cacheLocation ); + downloadTurtleGrammar.downloadTurtleGrammar(); + } +} diff --git a/core/esmf-tree-sitter-turtle/src-buildtime/main/java/org/eclipse/esmf/buildtime/DownloadZig.java b/core/esmf-tree-sitter-turtle/src-buildtime/main/java/org/eclipse/esmf/buildtime/DownloadZig.java index 56988889a..f79bfd9e9 100644 --- a/core/esmf-tree-sitter-turtle/src-buildtime/main/java/org/eclipse/esmf/buildtime/DownloadZig.java +++ b/core/esmf-tree-sitter-turtle/src-buildtime/main/java/org/eclipse/esmf/buildtime/DownloadZig.java @@ -18,13 +18,9 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; -import java.net.MalformedURLException; -import java.net.URI; import java.net.URL; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; -import java.time.Duration; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; @@ -41,35 +37,19 @@ import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; -import org.eclipse.esmf.util.download.Download; -import org.eclipse.esmf.util.download.ProxyConfig; import org.eclipse.esmf.util.process.BinaryLauncher; import org.eclipse.esmf.util.process.ProcessLauncher; public class DownloadZig extends ZigContext { private static final String ZIG_PUB_KEY = "RWSGOq2NVecA2UPNdBUZykf1CCb147pkmdtYxgb3Ti+JO/wCYvhbAb/U"; - private static final URL MIRRORS_LIST_URL = url( "https://ziglang.org/download/community-mirrors.txt" ); + private final URL mirrorsListUrl; - private final ProxyConfig proxyConfig; private final String minisignVersion; public DownloadZig( final Path cacheLocation, final String zigVersion, final String minisignVersion ) { super( cacheLocation, zigVersion ); - proxyConfig = ProxyConfig.detectProxySettings(); this.minisignVersion = minisignVersion; - } - - private File getOrDownloadFile( final URL location ) { - final Path filePath = Paths.get( location.getPath() ); - final String filename = filePath.getName( filePath.getNameCount() - 1 ).toString(); - final File targetFile = cacheLocation.resolve( filename ).toFile(); - if ( targetFile.exists() ) { - return targetFile; - } - - final Download.Config config = new Download.Config( proxyConfig, Duration.ofSeconds( 3L ) ); - System.out.println( "Downloading " + location + " to " + targetFile.getName() + "..." ); - return new Download( config ).downloadFile( location, targetFile ); + mirrorsListUrl = url( "https://ziglang.org/download/community-mirrors.txt" ); } private String zigReleaseFileName() { @@ -96,7 +76,7 @@ private Path minisignExecutablePath() { } private List zigMirrorUrls() { - final File mirrors = getOrDownloadFile( MIRRORS_LIST_URL ); + final File mirrors = getOrDownloadFile( mirrorsListUrl ); try { return Files.readAllLines( mirrors.toPath() ).stream().collect( Collectors.collectingAndThen( Collectors.toList(), collected -> { Collections.shuffle( collected ); @@ -127,14 +107,6 @@ private File getOrDownloadFileFromMirror( final List mirrorUrls, final F .collect( Collectors.joining( "\n" ) ) ); } - private static URL url( final String url ) { - try { - return URI.create( url ).toURL(); - } catch ( final MalformedURLException exception ) { - throw new BuildTimeException( exception ); - } - } - private void extractZip( final File zipFile, final Path outputDir ) { if ( outputDir.toFile().exists() ) { return; diff --git a/core/esmf-tree-sitter-turtle/src-buildtime/main/java/org/eclipse/esmf/buildtime/ZigContext.java b/core/esmf-tree-sitter-turtle/src-buildtime/main/java/org/eclipse/esmf/buildtime/ZigContext.java index a775dc69a..702ce0dde 100644 --- a/core/esmf-tree-sitter-turtle/src-buildtime/main/java/org/eclipse/esmf/buildtime/ZigContext.java +++ b/core/esmf-tree-sitter-turtle/src-buildtime/main/java/org/eclipse/esmf/buildtime/ZigContext.java @@ -22,10 +22,9 @@ import org.apache.commons.lang3.SystemUtils; import org.apache.commons.lang3.arch.Processor; -public class ZigContext { +public class ZigContext extends BuildTimeTool { protected final OperatingSystem currentOs; protected final Architecture currentArchitecture; - protected final Path cacheLocation; protected final String zigVersion; protected enum OperatingSystem { @@ -56,7 +55,7 @@ protected void mkdir( final Path path ) { public ZigContext( final Path cacheLocation, final String zigVersion ) { - this.cacheLocation = cacheLocation; + super( cacheLocation ); this.zigVersion = zigVersion; final Processor processor = ArchUtils.getProcessor(); diff --git a/core/esmf-tree-sitter-turtle/src/main/js/NOTICE.md b/core/esmf-tree-sitter-turtle/src/main/js/NOTICE.md deleted file mode 100644 index c3efbd98b..000000000 --- a/core/esmf-tree-sitter-turtle/src/main/js/NOTICE.md +++ /dev/null @@ -1,3 +0,0 @@ -The source of grammar.js is https://github.com/GordianDziwis/tree-sitter-turtle/blob/main/grammar.js - -This file is licensed under the terms of the MIT License, see https://github.com/GordianDziwis/tree-sitter-turtle/blob/main/LICENSE diff --git a/core/esmf-tree-sitter-turtle/src/main/js/grammar.js b/core/esmf-tree-sitter-turtle/src/main/js/grammar.js deleted file mode 100644 index 402aae1e0..000000000 --- a/core/esmf-tree-sitter-turtle/src/main/js/grammar.js +++ /dev/null @@ -1,466 +0,0 @@ -// [X] See section "6.5 Grammar" in https://www.w3.org/TR/turtle/#sec-grammar-grammar for -// corresponding rule x. - -// [26] -const UCHAR = /(\\u[0-9A-Fa-f]{4}|\\U[0-9A-Fa-f]{8})/ - -// [154s] -const EXPONENT = [ - /[eE]/, - /[+-]?/, - /\d+/ -] - -// [161s] -const WS = [ - /\x20/, - /\x09/, - /\x0D/, - /\x0A/ -] - -// [163s] -const PN_CHARS_BASE = [ - /[A-Z]/, - /[a-z]/, - /[\u00C0-\u00D6]/, - /[\u00D8-\u00F6]/, - /[\u00F8-\u02FF]/, - /[\u0370-\u037D]/, - /[\u037F-\u1FFF]/, - /[\u200C-\u200D]/, - /[\u2070-\u218F]/, - /[\u2C00-\u2FEF]/, - /[\u3001-\uD7FF]/, - /[\uF900-\uFDCF]/, - /[\uFDF0-\uFFFD]/, - /[\u{10000}-\u{EFFFF}]/u -] - -// [164s] -const PN_CHARS_U = PN_CHARS_BASE.concat('_') - -// [166s] -const PN_CHARS = PN_CHARS_U.concat([ - '-', - /\d/, - /[\u00B7]/, - /[\u0300-\u036F]/, - /[\u203F-\u2040]/ -]) - -// [171s] -const HEX = [ - /\d/, - /[A-F]/, - /[a-f]/ -] - -// [172s] -const PN_LOCAL_ESC = [ - '_', - '~', - '.', - '-', - '!', - '$', - '&', - "'", - '(', - ')', - '*', - '+', - ',', - ';', - '=', - '/', - '?', - '#', - '@', - '%' -].map(char => '\\' + char) - -String.prototype.toCaseInsensitive = function() { - return alias( - token(new RegExp( - this - .split('') - .map(letter => `[${letter}${letter.toLowerCase()}]`) - .join('') - )), - this - ) -} - -module.exports = grammar({ - name: 'turtle', - - extras: $ => [ - $.comment, - /\s/ - ], - - word: $ => $.pn_prefix, - - rules: { - - // [1g] trigDoc ::= (directive | block)* - document: $ => repeat(choice($.directive, $.triple, $.graph)), - - // wrappedGraph ::= '{' triplesBlock? '}' - // NOTE the last wrappedGraph triple does not have to terminate in a '.' - graph: $ => seq( - optional(field('label', $._label)), - '{', - seq( - repeat($.triple), - optional($._triples), - ), - '}', - ), - - // [7g] labelOrSubject ::= iri | BlankNode - _label: $ => seq(optional('GRAPH'), choice($._iri, $._blank_node)), - - comment: _ => token(prec(-1, /#.*/)), - - // [2] - // Triple Statement vs Graph Statement: - // https://www.w3.org/TR/trig/#sec-triple-statements - triple: $ => seq($._triples, '.'), - - // [3] - directive: $ => choice( - $.prefix_id, - $.base, - $.sparql_prefix, - $.sparql_base - ), - - // [4] - prefix_id: $ => seq( - '@prefix', - $.namespace, - $.iri_reference, - '.' - ), - - // [5] - base: $ => seq( - '@base', - $.iri_reference, - '.' - ), - - // [5s] - sparql_base: $ => seq( - 'BASE'.toCaseInsensitive(), - $.iri_reference, - ), - - // [6s] - sparql_prefix: $ => seq( - 'PREFIX'.toCaseInsensitive(), - $.namespace, - $.iri_reference, - ), - - // [6] - _triples: $ => choice( - seq( - $.subject, - $.property_list - ), - seq( - $.blank_node_property_list, - optional($.property_list) - ) - ), - - // [7] - property_list: $ => seq( - $.property, - repeat(seq( - ';', - optional($.property) - )) - ), - - // Enable incremental selection of properties - property: $ => seq( - $.predicate, - $.object_list, - ), - - // [8] - object_list: $ => seq( - $._object, - repeat(seq( - ',', - $._object - )) - ), - - // [9] - // [11] - predicate: $ => choice( - $._iri, - 'a' - ), - - // [10] - subject: $ => choice( - $._iri, - $._blank_node, - $.collection - ), - - // [12] - _object: $ => choice( - $._iri, - $._blank_node, - $.collection, - $.blank_node_property_list, - $._literal - ), - - // [13] - _literal: $ => choice( - $.rdf_literal, - $._numeric_literal, - $.boolean_literal - ), - - // [14] - blank_node_property_list: $ => seq( - '[', - $.property_list, - ']' - ), - - // [15] - collection: $ => seq( - '(', - optional($.object_collection), - ')' - ), - - // Enable incremental selection analog to blank_node_property_list - object_collection: $ => repeat1( - $._object, - ), - - // [16] - _numeric_literal: $ => choice( - $.integer, - $.decimal, - $.double - ), - - // [17] - string: $ => choice( - $._string_literal_quote, - $._string_literal_single_quote, - $._string_literal_long_quote, - $._string_literal_long_single_quote, - ), - - // [18] - iri_reference: _ => - seq( - '<', - // expose <#leading> anchor for syntax highlighting - optional(token(prec(1, '#'))), - token.immediate( - repeat(choice(/([^<>"{}|^`\\\x00-\x20])/, UCHAR)), - ), - - token.immediate('>'), - ), - - // [19] - integer: _ => token(/[+-]?\d+/), - - // [20] - decimal: _ => token(seq(/[+-]?/, /\d*/, '.', /\d+/)), - - // [21] - double: _ => token(seq( - /[+-]?/, - choice( - seq(/\d+/, '.', /\d*/, seq(...EXPONENT)), - seq('.', /\d+/, seq(...EXPONENT)), - seq(/\d+/, seq(...EXPONENT)) - )) - ), - - // [22] - _string_literal_quote: $ => seq( - '"', - repeat(choice( - /[^\x22\x5C\x0A\x0D]/, - $.echar, - UCHAR - )), - '"', - ), - - // [23] - _string_literal_single_quote: $ => seq( - "'", - repeat(choice( - /[^\x27\x5C\x0A\x0D]/, - $.echar, - UCHAR - )), - "'" - ), - - // [24] - _string_literal_long_single_quote: $ => seq( - "'''", - repeat(seq( - optional(choice( - "'", - "''", - )), - choice( - /[^'\\]/, - $.echar, - UCHAR - ) - )), - "'''", - ), - - // [25] - _string_literal_long_quote: $ => seq( - '"""', - repeat(seq( - optional(choice( - '"', - '""', - )), - choice( - /[^"\\]/, - $.echar, - UCHAR - ) - )), - '"""', - ), - - // [128s] - rdf_literal: $ => seq( - field('value', $.string), - optional(choice( - $.lang_tag, - field('datatype', seq('^^', $._iri)) - )) - ), - - // [133s] - boolean_literal: _ => choice( - 'true', - 'false' - ), - - // [135s] - _iri: $ => choice( - $.iri_reference, - $.prefixed_name - ), - - // [136s] - prefixed_name: $ => seq( - $.namespace, - optional($.pn_local) - ), - - // [137s] - _blank_node: $ => choice( - $.blank_node_label, - $.anon - ), - - // [139s] - namespace: $ => seq( - optional($.pn_prefix), - ':' - ), - - // [141s] - blank_node_label: _ => seq( - '_:', - token.immediate(seq( - choice( - ...PN_CHARS_U, - /\d/ - ), - optional(seq( - repeat(choice( - ...PN_CHARS, - '.' - )), - choice(...PN_CHARS) - )) - )) - ), - - // [144s] - lang_tag: _ => token(seq( - '@', - /[a-zA-Z]+/, - repeat(seq('-', /[a-zA-Z0-9]+/)) - )), - - // [159s] - echar: _ => /\\[tbnrf\\"']/, - - // [162s] - anon: _ => token(seq( - '[', - repeat(choice(...WS)), - ']' - )), - - // [167s] - pn_prefix: _ => token(seq( - choice(...PN_CHARS_BASE), - optional(seq( - repeat(choice( - ...PN_CHARS, - '.' - )), - choice(...PN_CHARS) - )) - )), - - // [168s] - pn_local: _ => token.immediate(seq( - choice( - ...PN_CHARS_U, - ':', - /\d/, - seq('%', choice(...HEX), choice(...HEX)), - ...PN_LOCAL_ESC - ), - optional(seq( - repeat(choice( - ...PN_CHARS, - '.', - ':', - seq('%', choice(...HEX), choice(...HEX)), - ...PN_LOCAL_ESC - )), - choice( - ...PN_CHARS, - ':', - seq('%', choice(...HEX), choice(...HEX)), - ...PN_LOCAL_ESC - ) - )) - )), - - } -}) From 4f089f39eec2a2324d491ac0bd23ce57298a2046 Mon Sep 17 00:00:00 2001 From: Andreas Textor Date: Wed, 20 May 2026 14:34:14 +0200 Subject: [PATCH 28/41] Generate parser token types constants based on node-types.json --- core/esmf-tree-sitter-turtle/pom.xml | 45 +++++++++ .../eclipse/esmf/buildtime/BuildTimeTool.java | 42 +++++++- .../eclipse/esmf/buildtime/DownloadZig.java | 6 +- .../buildtime/GenerateParserTokenType.java | 99 +++++++++++++++++++ .../eclipse/esmf/buildtime/ZigContext.java | 11 +-- .../treesitterturtle/ParserTokenType.java | 70 ------------- .../structure/TurtleTokenService.java | 2 +- .../lsp/text/TurtleParserServiceTest.java | 2 - 8 files changed, 187 insertions(+), 90 deletions(-) create mode 100644 core/esmf-tree-sitter-turtle/src-buildtime/main/java/org/eclipse/esmf/buildtime/GenerateParserTokenType.java delete mode 100644 core/esmf-tree-sitter-turtle/src/main/java/org/eclipse/esmf/treesitterturtle/ParserTokenType.java diff --git a/core/esmf-tree-sitter-turtle/pom.xml b/core/esmf-tree-sitter-turtle/pom.xml index ebbb271b7..4da6e215f 100644 --- a/core/esmf-tree-sitter-turtle/pom.xml +++ b/core/esmf-tree-sitter-turtle/pom.xml @@ -72,6 +72,11 @@ xz compile + + com.fasterxml.jackson.core + jackson-databind + compile + @@ -107,6 +112,18 @@ org.codehaus.mojo build-helper-maven-plugin + + add-generated-sources + initialize + + add-source + + + + ${generated-sources}/main/java + + + add-buildtime-sources initialize @@ -132,6 +149,18 @@ + + org.apache.maven.plugins + maven-clean-plugin + + + + ${generated-sources} + + + + + com.github.eirslett frontend-maven-plugin @@ -235,6 +264,22 @@ + + generate-parser-token-types + process-sources + + java + + + org.eclipse.esmf.buildtime.GenerateParserTokenType + + + ${project.basedir}/src/main/${c.source.directory}/node-types.json + + ${generated-sources} + + + diff --git a/core/esmf-tree-sitter-turtle/src-buildtime/main/java/org/eclipse/esmf/buildtime/BuildTimeTool.java b/core/esmf-tree-sitter-turtle/src-buildtime/main/java/org/eclipse/esmf/buildtime/BuildTimeTool.java index 2f5b9c41e..b7e89c9a9 100644 --- a/core/esmf-tree-sitter-turtle/src-buildtime/main/java/org/eclipse/esmf/buildtime/BuildTimeTool.java +++ b/core/esmf-tree-sitter-turtle/src-buildtime/main/java/org/eclipse/esmf/buildtime/BuildTimeTool.java @@ -15,11 +15,15 @@ import java.io.File; import java.io.FileInputStream; +import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; +import java.io.OutputStream; import java.net.MalformedURLException; import java.net.URI; import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.security.DigestInputStream; @@ -30,17 +34,31 @@ import org.eclipse.esmf.util.download.Download; import org.eclipse.esmf.util.download.ProxyConfig; +import org.jspecify.annotations.Nullable; + import jakarta.xml.bind.annotation.adapters.HexBinaryAdapter; public abstract class BuildTimeTool { - protected final Path cacheLocation; + private final @Nullable Path cacheLocation; protected final ProxyConfig proxyConfig; - public BuildTimeTool( final Path cacheLocation ) { + public BuildTimeTool() { + this( null ); + } + + public BuildTimeTool( final @Nullable Path cacheLocation ) { this.cacheLocation = cacheLocation; proxyConfig = ProxyConfig.detectProxySettings(); } + protected void mkdir( final Path path ) { + try { + Files.createDirectories( path ); + } catch ( final IOException exception ) { + throw new BuildTimeException( exception ); + } + } + protected URL url( final String url ) { try { return URI.create( url ).toURL(); @@ -49,10 +67,17 @@ protected URL url( final String url ) { } } + protected Path cacheLocation() { + if ( cacheLocation == null ) { + throw new BuildTimeException( "Cache was not initialized" ); + } + return cacheLocation; + } + protected File getOrDownloadFile( final URL location ) { final Path filePath = Paths.get( location.getPath() ); final String filename = filePath.getName( filePath.getNameCount() - 1 ).toString(); - final File targetFile = cacheLocation.resolve( filename ).toFile(); + final File targetFile = cacheLocation().resolve( filename ).toFile(); if ( targetFile.exists() ) { return targetFile; } @@ -62,7 +87,7 @@ protected File getOrDownloadFile( final URL location ) { return new Download( config ).downloadFile( location, targetFile ); } - public String sha1( final File file ) { + protected String sha1( final File file ) { try ( final InputStream input = new FileInputStream( file ); final DigestInputStream digestStream = new DigestInputStream( input, MessageDigest.getInstance( "SHA-1" ) ) ) { digestStream.readAllBytes(); @@ -71,4 +96,13 @@ public String sha1( final File file ) { throw new BuildTimeException( "Could not calculate SHA1 sum for " + file ); } } + + protected void write( final File outputFile, final String fileContent ) { + try ( final OutputStream outputStream = new FileOutputStream( outputFile ) ) { + outputStream.write( fileContent.getBytes( StandardCharsets.UTF_8 ) ); + } catch ( final IOException exception ) { + throw new RuntimeException( "Could not write source code file " + outputFile, exception ); + } + System.out.println( "Written " + outputFile ); + } } diff --git a/core/esmf-tree-sitter-turtle/src-buildtime/main/java/org/eclipse/esmf/buildtime/DownloadZig.java b/core/esmf-tree-sitter-turtle/src-buildtime/main/java/org/eclipse/esmf/buildtime/DownloadZig.java index f79bfd9e9..8d677ca8f 100644 --- a/core/esmf-tree-sitter-turtle/src-buildtime/main/java/org/eclipse/esmf/buildtime/DownloadZig.java +++ b/core/esmf-tree-sitter-turtle/src-buildtime/main/java/org/eclipse/esmf/buildtime/DownloadZig.java @@ -176,7 +176,7 @@ private void extractArchive( final File archiveFile, final Path targetDirectory } private File downloadAndExtractMinisign() { - final Path minisignDir = cacheLocation.resolve( "minisign" ); + final Path minisignDir = cacheLocation().resolve( "minisign" ); final File minisignExe = minisignDir.resolve( minisignExecutablePath() ).toFile(); if ( minisignExe.exists() ) { return minisignExe; @@ -203,8 +203,8 @@ private File downloadAndExtractZig( final File minisignExe ) { final List mirrors = zigMirrorUrls(); final String fileName = zigReleaseFileName(); - final File signatureOutputFile = cacheLocation.resolve( fileName + ".minisig" ).toFile(); - final File zigReleaseArchive = getOrDownloadFileFromMirror( mirrors, cacheLocation.resolve( fileName ).toFile() ); + final File signatureOutputFile = cacheLocation().resolve( fileName + ".minisig" ).toFile(); + final File zigReleaseArchive = getOrDownloadFileFromMirror( mirrors, cacheLocation().resolve( fileName ).toFile() ); getOrDownloadFileFromMirror( mirrors, signatureOutputFile ); validateZigReleaseSignature( minisignExe, zigReleaseArchive ); diff --git a/core/esmf-tree-sitter-turtle/src-buildtime/main/java/org/eclipse/esmf/buildtime/GenerateParserTokenType.java b/core/esmf-tree-sitter-turtle/src-buildtime/main/java/org/eclipse/esmf/buildtime/GenerateParserTokenType.java new file mode 100644 index 000000000..2553d2736 --- /dev/null +++ b/core/esmf-tree-sitter-turtle/src-buildtime/main/java/org/eclipse/esmf/buildtime/GenerateParserTokenType.java @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2026 Robert Bosch Manufacturing Solutions GmbH + * + * See the AUTHORS file(s) distributed with this work for additional + * information regarding authorship. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * SPDX-License-Identifier: MPL-2.0 + */ + +package org.eclipse.esmf.buildtime; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Path; +import java.util.Collection; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.common.collect.Streams; + +public class GenerateParserTokenType extends BuildTimeTool { + private static final String CLASS_NAME = "ParserTokenType"; + + public void generate( final File nodeTypesJson, final Path srcGen ) throws IOException { + final Path packagePath = srcGen.resolve( "main" ).resolve( "java" ) + .resolve( "org" ).resolve( "eclipse" ).resolve( "esmf" ).resolve( "treesitterturtle" ); + mkdir( packagePath ); + + final ObjectMapper objectMapper = new ObjectMapper(); + final Set tokens = getNodeTypes( objectMapper.readTree( nodeTypesJson ) ) + .map( String::toLowerCase ) + .collect( Collectors.toSet() ); + final String declarations = javaConstantsForTokens( tokens ).entrySet().stream() + .sorted( Map.Entry.comparingByKey() ) + .map( entry -> " public static final String %s = \"%s\";%n".formatted( entry.getKey(), entry.getValue() ) ) + .collect( Collectors.joining() ); + final String classContent = """ + package org.eclipse.esmf.treesitterturtle; + + import javax.annotation.processing.Generated; + + @Generated( "org.eclipse.esmf.buildtime.GenerateParserTokenType" ) + public class %s { + %s + } + """.formatted( CLASS_NAME, declarations ); + write( packagePath.resolve( CLASS_NAME + ".java" ).toFile(), classContent ); + } + + private Map javaConstantsForTokens( final Collection tokens ) { + return tokens.stream().collect( Collectors.toMap( token -> { + if ( token.length() == 1 && !Character.isLetterOrDigit( token.charAt( 0 ) ) ) { + return "SYMBOL_" + Character.getName( token.charAt( 0 ) ) + .replace( '-', '_' ) + .replace( ' ', '_' ).toUpperCase(); + } + return switch ( token ) { + case "\"\"" -> "SYMBOL_DOUBLE_QUOTE"; + case "\"\"\"" -> "SYMBOL_TRIPLE_QUOTE"; + case "''" -> "SYMBOL_DOUBLE_SINGLE_QUOTE"; + case "'''" -> "SYMBOL_TRIPLE_SINGLE_QUOTE"; + case "@base" -> "AT_BASE"; + case "@prefix" -> "AT_PREFIX"; + case "^^" -> "SYMBOL_DOUBLE_CARET"; + case "_:" -> "BLANK_NODE_PREFIX"; + default -> token.toUpperCase(); + }; + }, token -> switch ( token ) { + case "\"" -> "\\\""; + case "\"\"" -> "\\\"\\\""; + case "\"\"\"" -> "\\\"\\\"\\\""; + default -> token; + } ) ); + } + + private Stream getNodeTypes( final JsonNode node ) { + return node.isArray() + ? Streams.stream( node.elements() ).flatMap( this::getNodeTypes ) + : Optional.ofNullable( node.get( "type" ) ).map( JsonNode::asText ).stream(); + } + + static void main( final String[] args ) { + try { + new GenerateParserTokenType().generate( new File( args[0] ), Path.of( args[1] ) ); + } catch ( final Exception exception ) { + throw new BuildTimeException( exception ); + } + } + +} diff --git a/core/esmf-tree-sitter-turtle/src-buildtime/main/java/org/eclipse/esmf/buildtime/ZigContext.java b/core/esmf-tree-sitter-turtle/src-buildtime/main/java/org/eclipse/esmf/buildtime/ZigContext.java index 702ce0dde..77bd155ab 100644 --- a/core/esmf-tree-sitter-turtle/src-buildtime/main/java/org/eclipse/esmf/buildtime/ZigContext.java +++ b/core/esmf-tree-sitter-turtle/src-buildtime/main/java/org/eclipse/esmf/buildtime/ZigContext.java @@ -45,15 +45,6 @@ public String toString() { } } - protected void mkdir( final Path path ) { - try { - Files.createDirectories( path ); - } catch ( final IOException exception ) { - throw new BuildTimeException( exception ); - } - } - - public ZigContext( final Path cacheLocation, final String zigVersion ) { super( cacheLocation ); this.zigVersion = zigVersion; @@ -90,7 +81,7 @@ public ZigContext( final Path cacheLocation, final String zigVersion ) { } protected Path zigDir() { - return cacheLocation.resolve( "zig" ); + return cacheLocation().resolve( "zig" ); } protected File zigExe() { diff --git a/core/esmf-tree-sitter-turtle/src/main/java/org/eclipse/esmf/treesitterturtle/ParserTokenType.java b/core/esmf-tree-sitter-turtle/src/main/java/org/eclipse/esmf/treesitterturtle/ParserTokenType.java deleted file mode 100644 index 0f66c7a40..000000000 --- a/core/esmf-tree-sitter-turtle/src/main/java/org/eclipse/esmf/treesitterturtle/ParserTokenType.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (c) 2026 Robert Bosch Manufacturing Solutions GmbH - * - * See the AUTHORS file(s) distributed with this work for additional - * information regarding authorship. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * SPDX-License-Identifier: MPL-2.0 - */ - -package org.eclipse.esmf.treesitterturtle; - -/** - * The types of parser tokens the RDF/Turtle parser produces, see also grammar.js. - */ -public class ParserTokenType { - private ParserTokenType() {} - - public static final String SYMBOL_COLON = ":"; - public static final String SYMBOL_DOT = "."; - public static final String SYMBOL_SEMICOLON = ";"; - public static final String SYMBOL_QUOTE = "\""; - public static final String SYMBOL_SINGLE_QUOTE = "'"; - public static final String SYMBOL_TRIPLE_QUOTE = "\"\"\""; - public static final String SYMBOL_TRIPLE_SINGLE_QUOTE = "'''"; - public static final String SYMBOL_DOUBLE_CARET = "^^"; - public static final String SYMBOL_OPENING_BRACKET = "("; - public static final String SYMBOL_CLOSING_BRACKET = ")"; - public static final String SYMBOL_OPENING_SQUARE_BRACKET = "["; - public static final String SYMBOL_CLOSING_SQUARE_BRACKET = "]"; - public static final String SYMBOL_OPENING_POINTY_BRACKET = "<"; - public static final String SYMBOL_CLOSING_POINTY_BRACKET = ">"; - - public static final String A = "a"; // the syntactic shortcut for rdf:type - public static final String AT_PREFIX = "@prefix"; - public static final String AT_BASE = "@base"; - public static final String DOCUMENT = "document"; - public static final String GRAPH = "graph"; - public static final String COMMENT = "comment"; - public static final String TRIPLE = "triple"; - public static final String DIRECTIVE = "directive"; - public static final String PREFIX_ID = "prefix_id"; - public static final String BASE = "base"; - public static final String SPARQL_BASE = "sparql_base"; - public static final String SPARQL_PREFIX = "sparql_prefix"; - public static final String PROPERTY_LIST = "property_list"; - public static final String PROPERTY = "property"; - public static final String OBJECT_LIST = "object_list"; - public static final String PREDICATE = "predicate"; - public static final String SUBJECT = "subject"; - public static final String BLANK_NODE_PROPERTY_LIST = "blank_node_property_list"; - public static final String COLLECTION = "collection"; - public static final String STRING = "string"; - public static final String IRI_REFERENCE = "iri_reference"; - public static final String INTEGER = "integer"; - public static final String DECIMAL = "decimal"; - public static final String DOUBLE = "double"; - public static final String RDF_LITERAL = "rdf_literal"; - public static final String BOOLEAN_LITERAL = "boolean_literal"; - public static final String PREFIXED_NAME = "prefixed_name"; - public static final String NAMESPACE = "namespace"; - public static final String BLANK_NODE_LABEL = "blank_node_label"; - public static final String LANG_TAG = "lang_tag"; - public static final String ANON = "anon"; - public static final String PN_PREFIX = "pn_prefix"; - public static final String PN_LOCAL = "pn_local"; -} diff --git a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/structure/TurtleTokenService.java b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/structure/TurtleTokenService.java index 6f585ed28..b2fcf7bf6 100644 --- a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/structure/TurtleTokenService.java +++ b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/structure/TurtleTokenService.java @@ -78,7 +78,7 @@ public class TurtleTokenService { .put( ParserTokenType.PN_PREFIX, SemanticTokenTypes.Function ) .put( ParserTokenType.PN_LOCAL, SemanticTokenTypes.Property ) .put( ParserTokenType.SYMBOL_DOUBLE_CARET, SemanticTokenTypes.Decorator ) - .put( ParserTokenType.SYMBOL_DOT, SemanticTokenTypes.Decorator ) + .put( ParserTokenType.SYMBOL_FULL_STOP, SemanticTokenTypes.Decorator ) .put( ParserTokenType.SYMBOL_SEMICOLON, SemanticTokenTypes.Decorator ) .build(); private final TreeSitterTurtleParserService parserService; diff --git a/core/esmf-turtle-language-server/src/test/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TurtleParserServiceTest.java b/core/esmf-turtle-language-server/src/test/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TurtleParserServiceTest.java index 45ba2d197..e34770efa 100644 --- a/core/esmf-turtle-language-server/src/test/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TurtleParserServiceTest.java +++ b/core/esmf-turtle-language-server/src/test/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TurtleParserServiceTest.java @@ -212,7 +212,6 @@ void testEditAcrossMultipleLines() { applyChange( document, pos( 3, 2 ), pos( 4, 14 ), replacement ); final TSTree tree = parserService.apply( document ).concreteSyntaxTree(); - System.out.println( TreeSitterUtil.print( tree, document ) ); assertThat( tree.getRootNode().hasError() ).isFalse(); assertThat( document.getContent() ).contains( "ex:newPredicate" ); assertThat( document.getContent() ).doesNotContain( "ex:predicate1" ); @@ -250,7 +249,6 @@ void testParseValidSyntax() { final Document document = new Document( "test.ttl", initialContent ); final TSTree tree = parserService.apply( document ).concreteSyntaxTree(); - System.out.println( TreeSitterUtil.print( tree, document ) ); assertThat( tree.getRootNode().hasError() ).isFalse(); } From 9bf15754661a70da43a3a107cea5a95dcedab95d Mon Sep 17 00:00:00 2001 From: Andreas Textor Date: Wed, 20 May 2026 15:02:46 +0200 Subject: [PATCH 29/41] Turn TurtleLanguageServer into the actual TurtleLanguageServer --- .../esmf/turtle/languageserver/App.java | 54 ------------------- .../languageserver/TurtleLanguageServer.java | 35 ++++++++++++ 2 files changed, 35 insertions(+), 54 deletions(-) delete mode 100644 core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/App.java diff --git a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/App.java b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/App.java deleted file mode 100644 index 7f1ddf3ec..000000000 --- a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/App.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (c) 2026 Robert Bosch Manufacturing Solutions GmbH - * - * See the AUTHORS file(s) distributed with this work for additional - * information regarding authorship. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * SPDX-License-Identifier: MPL-2.0 - */ - -package org.eclipse.esmf.turtle.languageserver; - -import java.io.IOException; -import java.net.InetSocketAddress; -import java.nio.channels.AsynchronousServerSocketChannel; -import java.nio.channels.AsynchronousSocketChannel; -import java.nio.channels.Channels; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; -import java.util.function.Function; - -import org.eclipse.lsp4j.jsonrpc.Launcher; -import org.eclipse.lsp4j.services.LanguageClient; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class App { - public static final int PORT = 1846; - private static final Logger LOG = LoggerFactory.getLogger( App.class ); - - static void main( final String[] args ) { - final TurtleLanguageServer languageServer = new TurtleLanguageServer(); - try ( final AsynchronousServerSocketChannel serverSocket = AsynchronousServerSocketChannel.open() ) { - serverSocket.bind( new InetSocketAddress( "localhost", PORT ) ); - LOG.info( "Starting lsp-server on port {}", PORT ); - final AsynchronousSocketChannel socketChannel = serverSocket.accept().get(); - final Launcher launcher = - Launcher.createIoLauncher( languageServer, LanguageClient.class, Channels.newInputStream( socketChannel ), - Channels.newOutputStream( socketChannel ), Executors.newCachedThreadPool(), Function.identity() ); - final Future future = launcher.startListening(); - languageServer.connect( launcher.getRemoteProxy() ); - while ( !future.isDone() ) { - // noinspection BusyWait - Thread.sleep( 10_000L ); - } - } catch ( final InterruptedException | ExecutionException | IOException exception ) { - LOG.info( "Could not launch Language Server", exception ); - } - } -} diff --git a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/TurtleLanguageServer.java b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/TurtleLanguageServer.java index 31a8ee1b4..813c9a460 100644 --- a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/TurtleLanguageServer.java +++ b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/TurtleLanguageServer.java @@ -13,7 +13,16 @@ package org.eclipse.esmf.turtle.languageserver; +import java.io.IOException; +import java.net.InetSocketAddress; +import java.nio.channels.AsynchronousServerSocketChannel; +import java.nio.channels.AsynchronousSocketChannel; +import java.nio.channels.Channels; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.function.Function; import org.eclipse.esmf.turtle.languageserver.aspect.request.ValidateDocumentParams; import org.eclipse.esmf.turtle.languageserver.diagnostic.DiagnosticReport; @@ -28,14 +37,20 @@ import org.eclipse.lsp4j.ServerCapabilities; import org.eclipse.lsp4j.TextDocumentSyncKind; import org.eclipse.lsp4j.TextDocumentSyncOptions; +import org.eclipse.lsp4j.jsonrpc.Launcher; import org.eclipse.lsp4j.jsonrpc.services.JsonRequest; import org.eclipse.lsp4j.services.LanguageClient; import org.eclipse.lsp4j.services.LanguageClientAware; import org.eclipse.lsp4j.services.LanguageServer; import org.eclipse.lsp4j.services.TextDocumentService; import org.eclipse.lsp4j.services.WorkspaceService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class TurtleLanguageServer implements LanguageServer, LanguageClientAware { + public static final int PORT = 1846; + + private static final Logger LOG = LoggerFactory.getLogger( TurtleLanguageServer.class ); private final TurtleTextDocumentService textDocumentService; private final TurtleWorkspaceService workspaceService; @@ -95,4 +110,24 @@ public CompletableFuture validateDocument( final ValidateDocum } return CompletableFuture.completedFuture( textDocumentService.validateDocument( params.uri() ) ); } + + static void main( final String[] args ) { + final TurtleLanguageServer languageServer = new TurtleLanguageServer(); + try ( final AsynchronousServerSocketChannel serverSocket = AsynchronousServerSocketChannel.open() ) { + serverSocket.bind( new InetSocketAddress( "localhost", PORT ) ); + LOG.info( "Starting lsp-server on port {}", PORT ); + final AsynchronousSocketChannel socketChannel = serverSocket.accept().get(); + final Launcher launcher = + Launcher.createIoLauncher( languageServer, LanguageClient.class, Channels.newInputStream( socketChannel ), + Channels.newOutputStream( socketChannel ), Executors.newCachedThreadPool(), Function.identity() ); + final Future future = launcher.startListening(); + languageServer.connect( launcher.getRemoteProxy() ); + while ( !future.isDone() ) { + // noinspection BusyWait + Thread.sleep( 10_000L ); + } + } catch ( final InterruptedException | ExecutionException | IOException exception ) { + LOG.info( "Could not launch Language Server", exception ); + } + } } From 92c2f2a45a6836eb398496344e3f6f4016de5a00 Mon Sep 17 00:00:00 2001 From: Andreas Textor Date: Wed, 20 May 2026 15:24:58 +0200 Subject: [PATCH 30/41] Make launching LSP available as `samm lsp` subcommand --- .../languageserver/TurtleLanguageServer.java | 42 ++++++++++---- pom.xml | 1 + tools/samm-cli/pom.xml | 4 ++ .../main/java/org/eclipse/esmf/SammCli.java | 2 + .../java/org/eclipse/esmf/lsp/LspCommand.java | 56 +++++++++++++++++++ 5 files changed, 95 insertions(+), 10 deletions(-) create mode 100644 tools/samm-cli/src/main/java/org/eclipse/esmf/lsp/LspCommand.java diff --git a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/TurtleLanguageServer.java b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/TurtleLanguageServer.java index 813c9a460..2dd7c7f40 100644 --- a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/TurtleLanguageServer.java +++ b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/TurtleLanguageServer.java @@ -48,18 +48,15 @@ import org.slf4j.LoggerFactory; public class TurtleLanguageServer implements LanguageServer, LanguageClientAware { - public static final int PORT = 1846; + // R=18, D=4, F=6 + public static final int DEFAULT_PORT = 1846; private static final Logger LOG = LoggerFactory.getLogger( TurtleLanguageServer.class ); private final TurtleTextDocumentService textDocumentService; private final TurtleWorkspaceService workspaceService; public TurtleLanguageServer() { - this( new TurtleTextDocumentService() ); - } - - TurtleLanguageServer( final TurtleTextDocumentService textDocumentService ) { - this.textDocumentService = textDocumentService; + textDocumentService = new TurtleTextDocumentService(); workspaceService = new TurtleWorkspaceService( textDocumentService ); } @@ -111,11 +108,36 @@ public CompletableFuture validateDocument( final ValidateDocum return CompletableFuture.completedFuture( textDocumentService.validateDocument( params.uri() ) ); } - static void main( final String[] args ) { + /** + * Starts the language server using stdin/stdout communication. + * This method does not return. + */ + @SuppressWarnings( "UseOfSystemOutOrSystemErr" ) + public static void launchForStdio() { + final TurtleLanguageServer server = new TurtleLanguageServer(); + try { + final Launcher launcher = Launcher.createLauncher( server, LanguageClient.class, System.in, System.out ); + server.connect( launcher.getRemoteProxy() ); + launcher.startListening().get(); + } catch ( final InterruptedException exception ) { + Thread.currentThread().interrupt(); + LOG.error( "Language server listener was interrupted", exception ); + } catch ( final Exception exception ) { + LOG.error( "Language server terminated with an error", exception ); + } + } + + /** + * Starts the language server using socket communication. + * This method does not return. + * + * @param port the port to listen on + */ + public static void launchForSocket( final int port ) { final TurtleLanguageServer languageServer = new TurtleLanguageServer(); try ( final AsynchronousServerSocketChannel serverSocket = AsynchronousServerSocketChannel.open() ) { - serverSocket.bind( new InetSocketAddress( "localhost", PORT ) ); - LOG.info( "Starting lsp-server on port {}", PORT ); + serverSocket.bind( new InetSocketAddress( "localhost", port ) ); + LOG.info( "Starting language server on port {}", port ); final AsynchronousSocketChannel socketChannel = serverSocket.accept().get(); final Launcher launcher = Launcher.createIoLauncher( languageServer, LanguageClient.class, Channels.newInputStream( socketChannel ), @@ -127,7 +149,7 @@ static void main( final String[] args ) { Thread.sleep( 10_000L ); } } catch ( final InterruptedException | ExecutionException | IOException exception ) { - LOG.info( "Could not launch Language Server", exception ); + LOG.info( "Could not launch language server", exception ); } } } diff --git a/pom.xml b/pom.xml index 51356c63f..da284eb2a 100644 --- a/pom.xml +++ b/pom.xml @@ -128,6 +128,7 @@ org.eclipse.esmf esmf-turtle-language-server + ${project.version} org.eclipse.esmf diff --git a/tools/samm-cli/pom.xml b/tools/samm-cli/pom.xml index 9fc6d451e..f6cbe3ab0 100644 --- a/tools/samm-cli/pom.xml +++ b/tools/samm-cli/pom.xml @@ -45,6 +45,10 @@ org.eclipse.esmf esmf-aspect-model-github-resolver + + org.eclipse.esmf + esmf-turtle-language-server + com.fasterxml.jackson.core jackson-databind diff --git a/tools/samm-cli/src/main/java/org/eclipse/esmf/SammCli.java b/tools/samm-cli/src/main/java/org/eclipse/esmf/SammCli.java index 38a3b83a8..21b084ad9 100644 --- a/tools/samm-cli/src/main/java/org/eclipse/esmf/SammCli.java +++ b/tools/samm-cli/src/main/java/org/eclipse/esmf/SammCli.java @@ -32,6 +32,7 @@ import org.eclipse.esmf.exception.CommandException; import org.eclipse.esmf.exception.SubCommandException; import org.eclipse.esmf.importer.ImportCommand; +import org.eclipse.esmf.lsp.LspCommand; import org.eclipse.esmf.namespacepackage.PackageCommand; import org.eclipse.esmf.namespacepackage.PackageExportCommand; import org.eclipse.esmf.namespacepackage.PackageImportCommand; @@ -106,6 +107,7 @@ public SammCli() { .addSubcommand( new AasCommand() ) .addSubcommand( new PackageCommand() ) .addSubcommand( new ImportCommand() ) + .addSubcommand( new LspCommand() ) .setCaseInsensitiveEnumValuesAllowed( true ) .setExecutionStrategy( LoggingMixin::executionStrategy ); initialCommandLine.getHelpSectionMap().put( SECTION_KEY_COMMAND_LIST, new CustomCommandListRenderer() ); diff --git a/tools/samm-cli/src/main/java/org/eclipse/esmf/lsp/LspCommand.java b/tools/samm-cli/src/main/java/org/eclipse/esmf/lsp/LspCommand.java new file mode 100644 index 000000000..5094326c3 --- /dev/null +++ b/tools/samm-cli/src/main/java/org/eclipse/esmf/lsp/LspCommand.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2026 Robert Bosch Manufacturing Solutions GmbH + * + * See the AUTHORS file(s) distributed with this work for additional + * information regarding authorship. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * SPDX-License-Identifier: MPL-2.0 + */ + +package org.eclipse.esmf.lsp; + +import org.eclipse.esmf.AbstractCommand; +import org.eclipse.esmf.LoggingMixin; +import org.eclipse.esmf.turtle.languageserver.TurtleLanguageServer; + +import picocli.CommandLine; + +@CommandLine.Command( + name = LspCommand.COMMAND_NAME, + description = "Launch Turtle Language Server", + subcommands = { + CommandLine.HelpCommand.class + }, + headerHeading = "@|bold Usage|@:%n%n", + descriptionHeading = "%n@|bold Description|@:%n%n", + parameterListHeading = "%n@|bold Parameters|@:%n", + optionListHeading = "%n@|bold Options|@:%n" ) +public class LspCommand extends AbstractCommand { + public static final String COMMAND_NAME = "lsp"; + + @CommandLine.Mixin + private LoggingMixin loggingMixin; + + @CommandLine.Option( + names = { "-p", "--port" }, + description = "Port to listen on when using socket communication (default: ${DEFAULT-VALUE})" ) + int port = TurtleLanguageServer.DEFAULT_PORT; + + @CommandLine.Option( + names = { "-s", "--stdio" }, + description = "Use standard input/output for communication instead of sockets" ) + boolean useStdio = false; + + @Override + public void run() { + if ( useStdio ) { + TurtleLanguageServer.launchForStdio(); + return; + } + TurtleLanguageServer.launchForSocket( port ); + } +} From 0ba2562d633b4b8b3156a60e805c4329eeda3f8e Mon Sep 17 00:00:00 2001 From: Andreas Textor Date: Thu, 21 May 2026 12:04:40 +0200 Subject: [PATCH 31/41] Shut logback up with its internal status --- tools/samm-cli/src/test/resources/logback.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/samm-cli/src/test/resources/logback.xml b/tools/samm-cli/src/test/resources/logback.xml index 9fdc8b5fe..6529242b6 100644 --- a/tools/samm-cli/src/test/resources/logback.xml +++ b/tools/samm-cli/src/test/resources/logback.xml @@ -11,6 +11,7 @@ ~ SPDX-License-Identifier: MPL-2.0 --> + System.out From 24c80c9dc7cea8aebc1d0bb07a95c4c7ea743d85 Mon Sep 17 00:00:00 2001 From: Andreas Textor Date: Thu, 21 May 2026 15:38:03 +0200 Subject: [PATCH 32/41] Gracefully handle Jena parser problems --- .../service/AspectModelValidationService.java | 5 ++ .../TurtleSyntaxDiagnosticsService.java | 47 +++++++++---------- 2 files changed, 28 insertions(+), 24 deletions(-) diff --git a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/aspect/service/AspectModelValidationService.java b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/aspect/service/AspectModelValidationService.java index 1c0490aee..c734cd11e 100644 --- a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/aspect/service/AspectModelValidationService.java +++ b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/aspect/service/AspectModelValidationService.java @@ -19,9 +19,11 @@ import java.util.Optional; import org.apache.jena.rdf.model.RDFNode; +import org.apache.jena.riot.RiotException; import org.eclipse.esmf.aspectmodel.loader.AspectModelLoader; import org.eclipse.esmf.aspectmodel.resolver.AspectModelFileLoader; +import org.eclipse.esmf.aspectmodel.resolver.exceptions.ParserException; import org.eclipse.esmf.aspectmodel.resolver.modelfile.RawAspectModelFile; import org.eclipse.esmf.aspectmodel.resolver.parser.TokenRegistry; import org.eclipse.esmf.aspectmodel.shacl.violation.Violation; @@ -73,6 +75,9 @@ public DiagnosticReport defaultValidate( final ParsedDocument parsedDocument ) { validator.validateModel( () -> loader.loadAspectModelFiles( List.of( file ) ) ); LOG.debug( "[validate] validation finished for {} with {} violation(s)", document.getUri(), violations.size() ); return new DiagnosticReport( violations.stream().flatMap( violation -> toViolationInfo( violation ).stream() ).toList() ); + } catch ( final RiotException | ParserException exception ) { + // Ignore. Syntax errors are handled by the TurtleSyntaxDiagnosticsService + return DiagnosticReport.EMPTY; } catch ( final Exception exception ) { LOG.error( "[validate] unexpected runtime failure for {}", document.getUri(), exception ); return new DiagnosticReport( exception.getMessage(), TurtleDiagnostic.TurtleCode.E0000 ); diff --git a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/turtle/TurtleSyntaxDiagnosticsService.java b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/turtle/TurtleSyntaxDiagnosticsService.java index 45346fdf0..c3fc479a4 100644 --- a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/turtle/TurtleSyntaxDiagnosticsService.java +++ b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/turtle/TurtleSyntaxDiagnosticsService.java @@ -13,8 +13,8 @@ package org.eclipse.esmf.turtle.languageserver.turtle; -import java.util.List; import java.util.stream.IntStream; +import java.util.stream.Stream; import org.eclipse.esmf.turtle.languageserver.diagnostic.DiagnosticReport; import org.eclipse.esmf.turtle.languageserver.diagnostic.TurtleDiagnostic; @@ -27,31 +27,30 @@ public class TurtleSyntaxDiagnosticsService implements TurtleDiagnosticsService { @Override public DiagnosticReport defaultValidate( final ParsedDocument parsedDocument ) { - return new DiagnosticReport( - checkNode( parsedDocument.concreteSyntaxTree().getRootNode(), parsedDocument.sourceDocument().getUri() ) ); + return new DiagnosticReport( checkNode( parsedDocument.concreteSyntaxTree().getRootNode(), + parsedDocument.sourceDocument().getUri() ).toList() ); } - private List checkNode( final TSNode node, final String sourceLocation ) { - final List childDiagnostics = IntStream.range( 0, node.getChildCount() ) - .mapToObj( node::getChild ) - .flatMap( child -> checkNode( child, sourceLocation ).stream() ) - .toList(); - if ( node.hasError() && childDiagnostics.isEmpty() ) { - final String message; - if ( node.isMissing() ) { - message = "Syntax error: Missing '" + node.getGrammarType() + "'"; - } else if ( node.isExtra() ) { - message = node.getGrammarType().equals( "ERROR" ) - ? "Syntax error: Unexpected token" - : "Syntax error: Unexpected token '" + node.getGrammarType() + "'"; - } else { - message = "Syntax error"; - } - return List.of( new TurtleDocumentDiagnostic( message, - TurtleDiagnostic.TurtleCode.E0003, sourceLocation, - node.getStartPoint().getRow(), node.getStartPoint().getColumn(), - node.getEndPoint().getRow(), node.getEndPoint().getColumn() ) ); + private Stream checkNode( final TSNode node, final String sourceLocation ) { + return Stream.concat( node.isError() ? Stream.of( diagnosticForNode( node, sourceLocation ) ) : Stream.empty(), + IntStream.range( 0, node.getChildCount() ).boxed().map( node::getChild ) + .flatMap( child -> checkNode( child, sourceLocation ) ) ); + } + + private TurtleDocumentDiagnostic diagnosticForNode( final TSNode node, final String sourceLocation ) { + final String message; + if ( node.isMissing() ) { + message = "Syntax error: Missing '" + node.getGrammarType() + "'"; + } else if ( node.isExtra() ) { + message = node.getGrammarType().equals( "ERROR" ) + ? "Syntax error: Unexpected token" + : "Syntax error: Unexpected token '" + node.getGrammarType() + "'"; + } else { + message = "Syntax error"; } - return childDiagnostics; + return new TurtleDocumentDiagnostic( message, + TurtleDiagnostic.TurtleCode.E0003, sourceLocation, + node.getStartPoint().getRow(), node.getStartPoint().getColumn(), + node.getEndPoint().getRow(), node.getEndPoint().getColumn() ); } } From c818ef1956240bf7d480292918c0c42e7976f837 Mon Sep 17 00:00:00 2001 From: Andreas Textor Date: Thu, 21 May 2026 16:03:45 +0200 Subject: [PATCH 33/41] Propagate Jena parser problems if they appear --- .../service/AspectModelValidationService.java | 12 +++++++- .../diagnostic/DiagnosticReport.java | 4 +++ .../lsp/text/TurtleTextDocumentService.java | 30 +++++++++---------- 3 files changed, 29 insertions(+), 17 deletions(-) diff --git a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/aspect/service/AspectModelValidationService.java b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/aspect/service/AspectModelValidationService.java index c734cd11e..8bff725d6 100644 --- a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/aspect/service/AspectModelValidationService.java +++ b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/aspect/service/AspectModelValidationService.java @@ -75,16 +75,26 @@ public DiagnosticReport defaultValidate( final ParsedDocument parsedDocument ) { validator.validateModel( () -> loader.loadAspectModelFiles( List.of( file ) ) ); LOG.debug( "[validate] validation finished for {} with {} violation(s)", document.getUri(), violations.size() ); return new DiagnosticReport( violations.stream().flatMap( violation -> toViolationInfo( violation ).stream() ).toList() ); - } catch ( final RiotException | ParserException exception ) { + } catch ( final RiotException exception ) { // Ignore. Syntax errors are handled by the TurtleSyntaxDiagnosticsService return DiagnosticReport.EMPTY; + } catch ( final ParserException exception ) { + // Can happen for cases where Jena complains but TreeSitter doesn't + return new DiagnosticReport( diagnosticFromParserException( exception, parsedDocument.getUri() ) ); } catch ( final Exception exception ) { LOG.error( "[validate] unexpected runtime failure for {}", document.getUri(), exception ); return new DiagnosticReport( exception.getMessage(), TurtleDiagnostic.TurtleCode.E0000 ); } } + private TurtleDiagnostic diagnosticFromParserException( final ParserException exception, final String sourceLocation ) { + return new TurtleDocumentDiagnostic( exception.getMessage(), TurtleDiagnostic.TurtleCode.E0003, sourceLocation, + (int) exception.getLine() - 1, (int) exception.getColumn() - 1, + (int) exception.getLine() - 1, (int) exception.getColumn() ); + } + private TurtleDiagnostic.Code classifyViolation( final Violation violation ) { + // TODO return TurtleDiagnostic.TurtleCode.E0000; } diff --git a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/diagnostic/DiagnosticReport.java b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/diagnostic/DiagnosticReport.java index b02c33806..3633bc41d 100644 --- a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/diagnostic/DiagnosticReport.java +++ b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/diagnostic/DiagnosticReport.java @@ -45,4 +45,8 @@ public DiagnosticReport( final String message, final TurtleDiagnostic.TurtleCode public DiagnosticReport merge( final DiagnosticReport diagnosticReport ) { return new DiagnosticReport( Streams.concat( diagnostics.stream(), diagnosticReport.diagnostics().stream() ).toList() ); } + + public boolean isEmpty() { + return diagnostics.isEmpty(); + } } diff --git a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TurtleTextDocumentService.java b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TurtleTextDocumentService.java index 9321791cb..d746fb2c4 100644 --- a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TurtleTextDocumentService.java +++ b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/lsp/text/TurtleTextDocumentService.java @@ -52,10 +52,8 @@ public class TurtleTextDocumentService implements TextDocumentService { private final TreeSitterTurtleParserService turtleParserService; private final AspectDiagnosticsWorkflow aspectDiagnosticsWorkflow; private final TurtleTokenService tokenService; - private final List diagnosticsServices = List.of( - new TurtleSyntaxDiagnosticsService(), - new AspectModelValidationService() - ); + private final TurtleDiagnosticsService syntaxDiagnostics; + private final TurtleDiagnosticsService aspectModelValidation; private final Map documents = new HashMap<>(); public TurtleTextDocumentService() { @@ -65,6 +63,8 @@ public TurtleTextDocumentService() { turtleParserService = new TreeSitterTurtleParserService(); aspectDiagnosticsWorkflow = new AspectDiagnosticsWorkflow( aspectValidationCoordinator, clientNotifier ); tokenService = new TurtleTokenService( turtleParserService ); + syntaxDiagnostics = new TurtleSyntaxDiagnosticsService(); + aspectModelValidation = new AspectModelValidationService(); } public void connect( final LanguageClient client ) { @@ -81,9 +81,8 @@ public DiagnosticReport validateDocument( final String uri ) { return DiagnosticReport.EMPTY; } final ParsedDocument parsedDocument = turtleParserService.apply( document ); - return diagnosticsServices.stream() - .map( service -> service.defaultValidate( parsedDocument ) ) - .reduce( DiagnosticReport.EMPTY, DiagnosticReport::merge ); + return syntaxDiagnostics.defaultValidate( parsedDocument ) + .merge( aspectModelValidation.defaultValidate( parsedDocument ) ); } @Override @@ -95,9 +94,8 @@ public void didOpen( final DidOpenTextDocumentParams params ) { documents.put( uri, document ); turtleParserService.onOpen( document ); final ParsedDocument parsedDocument = turtleParserService.apply( document ); - final DiagnosticReport report = diagnosticsServices.stream() - .map( service -> service.onOpen( parsedDocument ) ) - .reduce( DiagnosticReport.EMPTY, DiagnosticReport::merge ); + final DiagnosticReport report = syntaxDiagnostics.onOpen( parsedDocument ) + .merge( aspectModelValidation.onOpen( parsedDocument ) ); clientNotifier.publishDiagnostics( document, report ); } @@ -111,9 +109,10 @@ public void didChange( final DidChangeTextDocumentParams params ) { } LOG.debug( "[didChange] uri={}, changes={}", uri, params.getContentChanges().size() ); final ParsedDocument parsedDocument = turtleParserService.apply( document ); - final DiagnosticReport report = diagnosticsServices.stream() - .map( service -> service.onChange( parsedDocument ) ) - .reduce( DiagnosticReport.EMPTY, DiagnosticReport::merge ); + final DiagnosticReport syntaxReport = syntaxDiagnostics.onChange( parsedDocument ); + final DiagnosticReport report = syntaxReport.isEmpty() + ? syntaxReport + : syntaxReport.merge( aspectModelValidation.onChange( parsedDocument ) ); clientNotifier.publishDiagnostics( document, report ); aspectDiagnosticsWorkflow.onDocumentChanged( document ); } @@ -136,9 +135,8 @@ public void didSave( final DidSaveTextDocumentParams params ) { document.getRope().rebalance(); turtleParserService.onOpen( document ); final ParsedDocument parsedDocument = turtleParserService.apply( document ); - final DiagnosticReport report = diagnosticsServices.stream() - .map( service -> service.onSave( parsedDocument ) ) - .reduce( DiagnosticReport.EMPTY, DiagnosticReport::merge ); + final DiagnosticReport report = syntaxDiagnostics.onSave( parsedDocument ) + .merge( aspectModelValidation.onSave( parsedDocument ) ); clientNotifier.publishDiagnostics( document, report ); aspectDiagnosticsWorkflow.onDocumentSaved( parsedDocument ); } From 1320be150381c0b8915af7756dbe53d4741f378f Mon Sep 17 00:00:00 2001 From: Andreas Textor Date: Fri, 22 May 2026 08:24:41 +0200 Subject: [PATCH 34/41] Try different Zig mirrors --- .../main/java/org/eclipse/esmf/buildtime/DownloadZig.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/core/esmf-tree-sitter-turtle/src-buildtime/main/java/org/eclipse/esmf/buildtime/DownloadZig.java b/core/esmf-tree-sitter-turtle/src-buildtime/main/java/org/eclipse/esmf/buildtime/DownloadZig.java index 8d677ca8f..54ff89cfd 100644 --- a/core/esmf-tree-sitter-turtle/src-buildtime/main/java/org/eclipse/esmf/buildtime/DownloadZig.java +++ b/core/esmf-tree-sitter-turtle/src-buildtime/main/java/org/eclipse/esmf/buildtime/DownloadZig.java @@ -92,8 +92,7 @@ private File getOrDownloadFileFromMirror( final List mirrorUrls, final F return outputFile; } final List triedLocations = new ArrayList<>(); - for ( final Iterator it = mirrorUrls.iterator(); it.hasNext() && !outputFile.exists(); ) { - final String mirrorUrl = it.next(); + for ( final String mirrorUrl : mirrorUrls ) { try { final URL url = url( mirrorUrl + "/" + outputFile.getName() ); triedLocations.add( url.toString() ); From e043894c0bc2d9e476bfcf1b9d5be576e7226655 Mon Sep 17 00:00:00 2001 From: Andreas Textor Date: Fri, 22 May 2026 08:28:12 +0200 Subject: [PATCH 35/41] Remove unused import --- .../main/java/org/eclipse/esmf/buildtime/DownloadZig.java | 1 - 1 file changed, 1 deletion(-) diff --git a/core/esmf-tree-sitter-turtle/src-buildtime/main/java/org/eclipse/esmf/buildtime/DownloadZig.java b/core/esmf-tree-sitter-turtle/src-buildtime/main/java/org/eclipse/esmf/buildtime/DownloadZig.java index 54ff89cfd..f0832d849 100644 --- a/core/esmf-tree-sitter-turtle/src-buildtime/main/java/org/eclipse/esmf/buildtime/DownloadZig.java +++ b/core/esmf-tree-sitter-turtle/src-buildtime/main/java/org/eclipse/esmf/buildtime/DownloadZig.java @@ -23,7 +23,6 @@ import java.nio.file.Path; import java.util.ArrayList; import java.util.Collections; -import java.util.Iterator; import java.util.List; import java.util.Optional; import java.util.stream.Collectors; From 4f49e6a77b7d56c1e0cb7f0761cb1c87bf58c7c1 Mon Sep 17 00:00:00 2001 From: Andreas Wirth Date: Tue, 2 Jun 2026 11:41:57 +0200 Subject: [PATCH 36/41] Change npm install to npm ci --- core/esmf-tree-sitter-turtle/pom.xml | 32 +++++++++++++++++++++++++--- package-lock.json | 29 +++++++++++++++++++++++++ package.json | 14 ++++++++++++ 3 files changed, 72 insertions(+), 3 deletions(-) create mode 100644 package-lock.json create mode 100644 package.json diff --git a/core/esmf-tree-sitter-turtle/pom.xml b/core/esmf-tree-sitter-turtle/pom.xml index 4da6e215f..6d318b4b8 100644 --- a/core/esmf-tree-sitter-turtle/pom.xml +++ b/core/esmf-tree-sitter-turtle/pom.xml @@ -161,6 +161,32 @@ + + org.apache.maven.plugins + maven-resources-plugin + + + copy-npm-config + initialize + + copy-resources + + + + + ${project.basedir}/../.. + + package-lock.json + package.json + + + + ${project.build.directory} + + + + + com.github.eirslett frontend-maven-plugin @@ -185,7 +211,7 @@ ${project.build.directory} - install tree-sitter-cli@${tree-sitter-cli.version} + ci --prefix . @@ -216,10 +242,10 @@ exec - ${node.path} + ${project.build.directory}/node/npx ${project.basedir}/src/main/js - ${project.build.directory}/node_modules/tree-sitter-cli/cli.js generate grammar.js --output ../${c.source.directory} + tree-sitter-cli generate grammar.js --output ../${c.source.directory} diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 000000000..560fc2731 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,29 @@ +{ + "name": "maven-build-dependencies", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "maven-build-dependencies", + "version": "1.0.0", + "license": "Copyright Robert Bosch Manufacturing Solutions GmbH, Germany. All rights reserved.", + "dependencies": { + "tree-sitter-cli": "^0.25.10" + } + }, + "node_modules/tree-sitter-cli": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/tree-sitter-cli/-/tree-sitter-cli-0.25.10.tgz", + "integrity": "sha512-KoebQguKMCIghisEOdA372TIbrUl0kdnfZ9YQIBRAeOvNSKe85XbU4LuFW7hduRUwJj0rAG7pX5wo9sZhbBF1g==", + "hasInstallScript": true, + "license": "MIT", + "bin": { + "tree-sitter": "cli.js" + }, + "engines": { + "node": ">=12.0.0" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 000000000..71f24351f --- /dev/null +++ b/package.json @@ -0,0 +1,14 @@ +{ + "name": "maven-build-dependencies", + "version": "1.0.0", + "description": "Package containing all NPM packages for Maven build. No npm install required, fully integrated into maven build.", + "license": "MPL-2.0", + "author": "Robert Bosch Manufacturing Solutions GmbH", + "type": "commonjs", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "dependencies": { + "tree-sitter-cli": "^0.25.10" + } +} From 0b92fd2f9cc4602cb3f5cb63001e0b9ea0467f76 Mon Sep 17 00:00:00 2001 From: Andreas Wirth Date: Tue, 2 Jun 2026 11:42:41 +0200 Subject: [PATCH 37/41] Fix maven shade plugin to include required multi version classes --- tools/samm-cli/pom.xml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tools/samm-cli/pom.xml b/tools/samm-cli/pom.xml index f6cbe3ab0..0e596c902 100644 --- a/tools/samm-cli/pom.xml +++ b/tools/samm-cli/pom.xml @@ -245,12 +245,11 @@ *:* - module-info.class + + **/module-info.class META-INF/* META-INF/sisu/javax.inject.Named META-INF/plexus/components.xml - META-INF.versions*/** - META-INF/versions*/** META-INF/maven/** plugin.xml about.html From 5b1632c57a431ca99d265eb49dec3886518cf19e Mon Sep 17 00:00:00 2001 From: Andreas Wirth Date: Fri, 5 Jun 2026 13:16:03 +0200 Subject: [PATCH 38/41] Support multiple connections to lsp --- .../languageserver/TurtleLanguageServer.java | 51 ++++++++++++++----- 1 file changed, 39 insertions(+), 12 deletions(-) diff --git a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/TurtleLanguageServer.java b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/TurtleLanguageServer.java index 2dd7c7f40..8c9ddf4f8 100644 --- a/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/TurtleLanguageServer.java +++ b/core/esmf-turtle-language-server/src/main/java/org/eclipse/esmf/turtle/languageserver/TurtleLanguageServer.java @@ -21,7 +21,6 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import java.util.concurrent.Executors; -import java.util.concurrent.Future; import java.util.function.Function; import org.eclipse.esmf.turtle.languageserver.aspect.request.ValidateDocumentParams; @@ -52,6 +51,7 @@ public class TurtleLanguageServer implements LanguageServer, LanguageClientAware public static final int DEFAULT_PORT = 1846; private static final Logger LOG = LoggerFactory.getLogger( TurtleLanguageServer.class ); + private static volatile boolean serverRunning = true; private final TurtleTextDocumentService textDocumentService; private final TurtleWorkspaceService workspaceService; @@ -134,22 +134,49 @@ public static void launchForStdio() { * @param port the port to listen on */ public static void launchForSocket( final int port ) { - final TurtleLanguageServer languageServer = new TurtleLanguageServer(); try ( final AsynchronousServerSocketChannel serverSocket = AsynchronousServerSocketChannel.open() ) { serverSocket.bind( new InetSocketAddress( "localhost", port ) ); LOG.info( "Starting language server on port {}", port ); - final AsynchronousSocketChannel socketChannel = serverSocket.accept().get(); + + while ( serverRunning ) { + LOG.info( "Waiting for client connection on port {}", port ); + final AsynchronousSocketChannel socketChannel = serverSocket.accept().get(); + LOG.info( "Client connected" ); + + // Handle each connection in a separate thread so we can immediately accept new connections + final Thread clientThread = new Thread( () -> handleClientConnection( socketChannel ) ); + clientThread.setName( "LSP-Client-Handler-" + System.currentTimeMillis() ); + clientThread.setDaemon( true ); + clientThread.start(); + } + } catch ( final IOException exception ) { + LOG.error( "Could not launch language server", exception ); + } catch ( final InterruptedException exception ) { + Thread.currentThread().interrupt(); + serverRunning = false; + LOG.error( "Language server listener was interrupted", exception ); + } catch ( final ExecutionException exception ) { + LOG.error( "Error accepting client connection", exception ); + } + } + + private static void handleClientConnection( final AsynchronousSocketChannel socketChannel ) { + try ( final var inputStream = Channels.newInputStream( socketChannel ); + final var outputStream = Channels.newOutputStream( socketChannel ); + final var executorService = Executors.newCachedThreadPool(); + socketChannel ) { + final TurtleLanguageServer languageServer = new TurtleLanguageServer(); final Launcher launcher = - Launcher.createIoLauncher( languageServer, LanguageClient.class, Channels.newInputStream( socketChannel ), - Channels.newOutputStream( socketChannel ), Executors.newCachedThreadPool(), Function.identity() ); - final Future future = launcher.startListening(); + Launcher.createIoLauncher( languageServer, LanguageClient.class, inputStream, + outputStream, executorService, Function.identity() ); languageServer.connect( launcher.getRemoteProxy() ); - while ( !future.isDone() ) { - // noinspection BusyWait - Thread.sleep( 10_000L ); - } - } catch ( final InterruptedException | ExecutionException | IOException exception ) { - LOG.info( "Could not launch language server", exception ); + launcher.startListening().get(); + LOG.info( "Client disconnected" ); + } catch ( final InterruptedException exception ) { + Thread.currentThread().interrupt(); + LOG.error( "Client connection handler was interrupted", exception ); + } catch ( final Exception exception ) { + LOG.error( "Error handling client connection", exception ); } } } From b297b40ab599aca0bba06ff9655f18d1b5ba5dc5 Mon Sep 17 00:00:00 2001 From: Andreas Wirth Date: Mon, 8 Jun 2026 09:53:07 +0200 Subject: [PATCH 39/41] Use npm instead of npx because of windows compatibility --- core/esmf-tree-sitter-turtle/pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/esmf-tree-sitter-turtle/pom.xml b/core/esmf-tree-sitter-turtle/pom.xml index 6d318b4b8..6a2c7f264 100644 --- a/core/esmf-tree-sitter-turtle/pom.xml +++ b/core/esmf-tree-sitter-turtle/pom.xml @@ -242,10 +242,10 @@ exec - ${project.build.directory}/node/npx + ${node.path} ${project.basedir}/src/main/js - tree-sitter-cli generate grammar.js --output ../${c.source.directory} + ${project.build.directory}/node_modules/tree-sitter-cli/cli.js generate grammar.js --output ../${c.source.directory} From 74e9a75bc7bb3da79f82e075075629bc7aaed8e9 Mon Sep 17 00:00:00 2001 From: Andreas Wirth Date: Tue, 9 Jun 2026 09:05:38 +0200 Subject: [PATCH 40/41] Download jni header files during maven build --- core/esmf-tree-sitter-turtle/.gitignore | 10 + core/esmf-tree-sitter-turtle/pom.xml | 137 + .../src/main/c/include/NOTICE.md | 2 - .../src/main/c/include/jni.h | 2013 --------------- .../src/main/c/include/linux/jawt_md.h | 60 - .../src/main/c/include/linux/jni_md.h | 64 - .../src/main/c/include/macos/jawt_md.h | 77 - .../src/main/c/include/macos/jni_md.h | 64 - .../windows/bridge/AccessBridgeCallbacks.h | 92 - .../windows/bridge/AccessBridgeCalls.h | 724 ------ .../windows/bridge/AccessBridgePackages.h | 2217 ----------------- .../src/main/c/include/windows/jawt_md.h | 59 - .../src/main/c/include/windows/jni_md.h | 38 - 13 files changed, 147 insertions(+), 5410 deletions(-) delete mode 100644 core/esmf-tree-sitter-turtle/src/main/c/include/NOTICE.md delete mode 100644 core/esmf-tree-sitter-turtle/src/main/c/include/jni.h delete mode 100644 core/esmf-tree-sitter-turtle/src/main/c/include/linux/jawt_md.h delete mode 100644 core/esmf-tree-sitter-turtle/src/main/c/include/linux/jni_md.h delete mode 100644 core/esmf-tree-sitter-turtle/src/main/c/include/macos/jawt_md.h delete mode 100644 core/esmf-tree-sitter-turtle/src/main/c/include/macos/jni_md.h delete mode 100755 core/esmf-tree-sitter-turtle/src/main/c/include/windows/bridge/AccessBridgeCallbacks.h delete mode 100755 core/esmf-tree-sitter-turtle/src/main/c/include/windows/bridge/AccessBridgeCalls.h delete mode 100755 core/esmf-tree-sitter-turtle/src/main/c/include/windows/bridge/AccessBridgePackages.h delete mode 100755 core/esmf-tree-sitter-turtle/src/main/c/include/windows/jawt_md.h delete mode 100755 core/esmf-tree-sitter-turtle/src/main/c/include/windows/jni_md.h diff --git a/core/esmf-tree-sitter-turtle/.gitignore b/core/esmf-tree-sitter-turtle/.gitignore index 982df7da0..eb4c9a6ad 100644 --- a/core/esmf-tree-sitter-turtle/.gitignore +++ b/core/esmf-tree-sitter-turtle/.gitignore @@ -2,6 +2,16 @@ src/main/c/parser.c src/main/c/grammar.json src/main/c/node-types.json src/main/c/tree_sitter/* +src/main/c/include/jni.h +src/main/c/include/linux/jni_md.h +src/main/c/include/linux/jawt_md.h +src/main/c/include/macos/jni_md.h +src/main/c/include/macos/jawt_md.h +src/main/c/include/windows/jni_md.h +src/main/c/include/windows/jawt_md.h +src/main/c/include/windows/bridge/AccessBridgeCallbacks.h +src/main/c/include/windows/bridge/AccessBridgeCalls.h +src/main/c/include/windows/bridge/AccessBridgePackages.h src/main/js/grammar.js src/main/js/bindings src/main/js/js diff --git a/core/esmf-tree-sitter-turtle/pom.xml b/core/esmf-tree-sitter-turtle/pom.xml index 6a2c7f264..987e61eb3 100644 --- a/core/esmf-tree-sitter-turtle/pom.xml +++ b/core/esmf-tree-sitter-turtle/pom.xml @@ -31,11 +31,14 @@ 1.12.1 0.2.1 + 1.9.0 11.2.0 22.14.0 0.15.2 0.11 + + jdk-25+36 @@ -187,6 +190,140 @@ + + com.googlecode.maven-download-plugin + download-maven-plugin + ${download-maven-plugin.version} + + + download-jni-header + initialize + + wget + + + https://raw.githubusercontent.com/openjdk/jdk/refs/tags/${openjdk.tag}/src/java.base/share/native/include/jni.h + ${project.basedir}/src/main/c/include + true + + + + download-jni-headers-unix + initialize + + wget + + + https://raw.githubusercontent.com/openjdk/jdk/refs/tags/${openjdk.tag}/src/java.base/unix/native/include/jni_md.h + ${project.basedir}/src/main/c/include/linux + true + + + + download-jni-headers-macos + initialize + + wget + + + https://raw.githubusercontent.com/openjdk/jdk/refs/tags/${openjdk.tag}/src/java.base/unix/native/include/jni_md.h + ${project.basedir}/src/main/c/include/macos + true + + + + download-jni-headers-windows + initialize + + wget + + + https://raw.githubusercontent.com/openjdk/jdk/refs/tags/${openjdk.tag}/src/java.base/windows/native/include/jni_md.h + ${project.basedir}/src/main/c/include/windows + true + + + + download-jawt-headers-unix + initialize + + wget + + + https://raw.githubusercontent.com/openjdk/jdk/refs/tags/${openjdk.tag}/src/java.desktop/unix/native/include/jawt_md.h + ${project.basedir}/src/main/c/include/linux + true + + + + download-jawt-headers-macos + initialize + + wget + + + https://raw.githubusercontent.com/openjdk/jdk/refs/tags/${openjdk.tag}/src/java.desktop/unix/native/include/jawt_md.h + ${project.basedir}/src/main/c/include/macos + true + + + + download-jawt-headers-windows + initialize + + wget + + + https://raw.githubusercontent.com/openjdk/jdk/refs/tags/${openjdk.tag}/src/java.desktop/windows/native/include/jawt_md.h + ${project.basedir}/src/main/c/include/windows + true + + + + download-accessbridge-callbacks-windows + initialize + + wget + + + + https://raw.githubusercontent.com/openjdk/jdk/refs/tags/${openjdk.tag}/src/jdk.accessibility/windows/native/include/bridge/AccessBridgeCallbacks.h + + ${project.basedir}/src/main/c/include/windows/bridge + true + + + + download-accessbridge-calls-windows + initialize + + wget + + + + https://raw.githubusercontent.com/openjdk/jdk/refs/tags/${openjdk.tag}/src/jdk.accessibility/windows/native/include/bridge/AccessBridgeCalls.h + + ${project.basedir}/src/main/c/include/windows/bridge + true + + + + download-accessbridge-packages-windows + initialize + + wget + + + + https://raw.githubusercontent.com/openjdk/jdk/refs/tags/${openjdk.tag}/src/jdk.accessibility/windows/native/include/bridge/AccessBridgePackages.h + + ${project.basedir}/src/main/c/include/windows/bridge + true + + + + + com.github.eirslett frontend-maven-plugin diff --git a/core/esmf-tree-sitter-turtle/src/main/c/include/NOTICE.md b/core/esmf-tree-sitter-turtle/src/main/c/include/NOTICE.md deleted file mode 100644 index 4811eceea..000000000 --- a/core/esmf-tree-sitter-turtle/src/main/c/include/NOTICE.md +++ /dev/null @@ -1,2 +0,0 @@ -Header files that adapted from OpenJDK. -These files are required during JNI compilation but will not be part of the resulting compiled file. diff --git a/core/esmf-tree-sitter-turtle/src/main/c/include/jni.h b/core/esmf-tree-sitter-turtle/src/main/c/include/jni.h deleted file mode 100644 index 1a31c38b3..000000000 --- a/core/esmf-tree-sitter-turtle/src/main/c/include/jni.h +++ /dev/null @@ -1,2013 +0,0 @@ -/* - * Copyright (c) 1996, 2024, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - * We used part of Netscape's Java Runtime Interface (JRI) as the starting - * point of our design and implementation. - */ - -/****************************************************************************** - * Java Runtime Interface - * Copyright (c) 1996 Netscape Communications Corporation. All rights reserved. - *****************************************************************************/ - -#ifndef _JAVASOFT_JNI_H_ -#define _JAVASOFT_JNI_H_ - -#include -#include - -/* jni_md.h contains the machine-dependent typedefs for jbyte, jint - and jlong */ - -#include "jni_md.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define JNICALL - -/* - * JNI Types - */ - -#ifndef JNI_TYPES_ALREADY_DEFINED_IN_JNI_MD_H - -typedef unsigned char jboolean; -typedef unsigned short jchar; -typedef short jshort; -typedef float jfloat; -typedef double jdouble; - -typedef jint jsize; - -#ifdef __cplusplus - -class _jobject {}; -class _jclass : public _jobject {}; -class _jthrowable : public _jobject {}; -class _jstring : public _jobject {}; -class _jarray : public _jobject {}; -class _jbooleanArray : public _jarray {}; -class _jbyteArray : public _jarray {}; -class _jcharArray : public _jarray {}; -class _jshortArray : public _jarray {}; -class _jintArray : public _jarray {}; -class _jlongArray : public _jarray {}; -class _jfloatArray : public _jarray {}; -class _jdoubleArray : public _jarray {}; -class _jobjectArray : public _jarray {}; - -typedef _jobject *jobject; -typedef _jclass *jclass; -typedef _jthrowable *jthrowable; -typedef _jstring *jstring; -typedef _jarray *jarray; -typedef _jbooleanArray *jbooleanArray; -typedef _jbyteArray *jbyteArray; -typedef _jcharArray *jcharArray; -typedef _jshortArray *jshortArray; -typedef _jintArray *jintArray; -typedef _jlongArray *jlongArray; -typedef _jfloatArray *jfloatArray; -typedef _jdoubleArray *jdoubleArray; -typedef _jobjectArray *jobjectArray; - -#else - -struct _jobject; - -typedef struct _jobject *jobject; -typedef jobject jclass; -typedef jobject jthrowable; -typedef jobject jstring; -typedef jobject jarray; -typedef jarray jbooleanArray; -typedef jarray jbyteArray; -typedef jarray jcharArray; -typedef jarray jshortArray; -typedef jarray jintArray; -typedef jarray jlongArray; -typedef jarray jfloatArray; -typedef jarray jdoubleArray; -typedef jarray jobjectArray; - -#endif - -typedef jobject jweak; - -typedef union jvalue { - jboolean z; - jbyte b; - jchar c; - jshort s; - jint i; - jlong j; - jfloat f; - jdouble d; - jobject l; -} jvalue; - -struct _jfieldID; -typedef struct _jfieldID *jfieldID; - -struct _jmethodID; -typedef struct _jmethodID *jmethodID; - -/* Return values from jobjectRefType */ -typedef enum _jobjectType { - JNIInvalidRefType = 0, - JNILocalRefType = 1, - JNIGlobalRefType = 2, - JNIWeakGlobalRefType = 3 -} jobjectRefType; - - -#endif /* JNI_TYPES_ALREADY_DEFINED_IN_JNI_MD_H */ - -/* - * jboolean constants - */ - -#define JNI_FALSE 0 -#define JNI_TRUE 1 - -/* - * possible return values for JNI functions. - */ - -#define JNI_OK 0 /* success */ -#define JNI_ERR (-1) /* unknown error */ -#define JNI_EDETACHED (-2) /* thread detached from the VM */ -#define JNI_EVERSION (-3) /* JNI version error */ -#define JNI_ENOMEM (-4) /* not enough memory */ -#define JNI_EEXIST (-5) /* VM already created */ -#define JNI_EINVAL (-6) /* invalid arguments */ - -/* - * used in ReleaseScalarArrayElements - */ - -#define JNI_COMMIT 1 -#define JNI_ABORT 2 - -/* - * used in RegisterNatives to describe native method name, signature, - * and function pointer. - */ - -typedef struct { - char *name; - char *signature; - void *fnPtr; -} JNINativeMethod; - -/* - * JNI Native Method Interface. - */ - -struct JNINativeInterface_; - -struct JNIEnv_; - -#ifdef __cplusplus -typedef JNIEnv_ JNIEnv; -#else -typedef const struct JNINativeInterface_ *JNIEnv; -#endif - -/* - * JNI Invocation Interface. - */ - -struct JNIInvokeInterface_; - -struct JavaVM_; - -#ifdef __cplusplus -typedef JavaVM_ JavaVM; -#else -typedef const struct JNIInvokeInterface_ *JavaVM; -#endif - -struct JNINativeInterface_ { - void *reserved0; - void *reserved1; - void *reserved2; - - void *reserved3; - jint (JNICALL *GetVersion)(JNIEnv *env); - - jclass (JNICALL *DefineClass) - (JNIEnv *env, const char *name, jobject loader, const jbyte *buf, - jsize len); - jclass (JNICALL *FindClass) - (JNIEnv *env, const char *name); - - jmethodID (JNICALL *FromReflectedMethod) - (JNIEnv *env, jobject method); - jfieldID (JNICALL *FromReflectedField) - (JNIEnv *env, jobject field); - - jobject (JNICALL *ToReflectedMethod) - (JNIEnv *env, jclass cls, jmethodID methodID, jboolean isStatic); - - jclass (JNICALL *GetSuperclass) - (JNIEnv *env, jclass sub); - jboolean (JNICALL *IsAssignableFrom) - (JNIEnv *env, jclass sub, jclass sup); - - jobject (JNICALL *ToReflectedField) - (JNIEnv *env, jclass cls, jfieldID fieldID, jboolean isStatic); - - jint (JNICALL *Throw) - (JNIEnv *env, jthrowable obj); - jint (JNICALL *ThrowNew) - (JNIEnv *env, jclass clazz, const char *msg); - jthrowable (JNICALL *ExceptionOccurred) - (JNIEnv *env); - void (JNICALL *ExceptionDescribe) - (JNIEnv *env); - void (JNICALL *ExceptionClear) - (JNIEnv *env); - void (JNICALL *FatalError) - (JNIEnv *env, const char *msg); - - jint (JNICALL *PushLocalFrame) - (JNIEnv *env, jint capacity); - jobject (JNICALL *PopLocalFrame) - (JNIEnv *env, jobject result); - - jobject (JNICALL *NewGlobalRef) - (JNIEnv *env, jobject lobj); - void (JNICALL *DeleteGlobalRef) - (JNIEnv *env, jobject gref); - void (JNICALL *DeleteLocalRef) - (JNIEnv *env, jobject obj); - jboolean (JNICALL *IsSameObject) - (JNIEnv *env, jobject obj1, jobject obj2); - jobject (JNICALL *NewLocalRef) - (JNIEnv *env, jobject ref); - jint (JNICALL *EnsureLocalCapacity) - (JNIEnv *env, jint capacity); - - jobject (JNICALL *AllocObject) - (JNIEnv *env, jclass clazz); - jobject (JNICALL *NewObject) - (JNIEnv *env, jclass clazz, jmethodID methodID, ...); - jobject (JNICALL *NewObjectV) - (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args); - jobject (JNICALL *NewObjectA) - (JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args); - - jclass (JNICALL *GetObjectClass) - (JNIEnv *env, jobject obj); - jboolean (JNICALL *IsInstanceOf) - (JNIEnv *env, jobject obj, jclass clazz); - - jmethodID (JNICALL *GetMethodID) - (JNIEnv *env, jclass clazz, const char *name, const char *sig); - - jobject (JNICALL *CallObjectMethod) - (JNIEnv *env, jobject obj, jmethodID methodID, ...); - jobject (JNICALL *CallObjectMethodV) - (JNIEnv *env, jobject obj, jmethodID methodID, va_list args); - jobject (JNICALL *CallObjectMethodA) - (JNIEnv *env, jobject obj, jmethodID methodID, const jvalue * args); - - jboolean (JNICALL *CallBooleanMethod) - (JNIEnv *env, jobject obj, jmethodID methodID, ...); - jboolean (JNICALL *CallBooleanMethodV) - (JNIEnv *env, jobject obj, jmethodID methodID, va_list args); - jboolean (JNICALL *CallBooleanMethodA) - (JNIEnv *env, jobject obj, jmethodID methodID, const jvalue * args); - - jbyte (JNICALL *CallByteMethod) - (JNIEnv *env, jobject obj, jmethodID methodID, ...); - jbyte (JNICALL *CallByteMethodV) - (JNIEnv *env, jobject obj, jmethodID methodID, va_list args); - jbyte (JNICALL *CallByteMethodA) - (JNIEnv *env, jobject obj, jmethodID methodID, const jvalue *args); - - jchar (JNICALL *CallCharMethod) - (JNIEnv *env, jobject obj, jmethodID methodID, ...); - jchar (JNICALL *CallCharMethodV) - (JNIEnv *env, jobject obj, jmethodID methodID, va_list args); - jchar (JNICALL *CallCharMethodA) - (JNIEnv *env, jobject obj, jmethodID methodID, const jvalue *args); - - jshort (JNICALL *CallShortMethod) - (JNIEnv *env, jobject obj, jmethodID methodID, ...); - jshort (JNICALL *CallShortMethodV) - (JNIEnv *env, jobject obj, jmethodID methodID, va_list args); - jshort (JNICALL *CallShortMethodA) - (JNIEnv *env, jobject obj, jmethodID methodID, const jvalue *args); - - jint (JNICALL *CallIntMethod) - (JNIEnv *env, jobject obj, jmethodID methodID, ...); - jint (JNICALL *CallIntMethodV) - (JNIEnv *env, jobject obj, jmethodID methodID, va_list args); - jint (JNICALL *CallIntMethodA) - (JNIEnv *env, jobject obj, jmethodID methodID, const jvalue *args); - - jlong (JNICALL *CallLongMethod) - (JNIEnv *env, jobject obj, jmethodID methodID, ...); - jlong (JNICALL *CallLongMethodV) - (JNIEnv *env, jobject obj, jmethodID methodID, va_list args); - jlong (JNICALL *CallLongMethodA) - (JNIEnv *env, jobject obj, jmethodID methodID, const jvalue *args); - - jfloat (JNICALL *CallFloatMethod) - (JNIEnv *env, jobject obj, jmethodID methodID, ...); - jfloat (JNICALL *CallFloatMethodV) - (JNIEnv *env, jobject obj, jmethodID methodID, va_list args); - jfloat (JNICALL *CallFloatMethodA) - (JNIEnv *env, jobject obj, jmethodID methodID, const jvalue *args); - - jdouble (JNICALL *CallDoubleMethod) - (JNIEnv *env, jobject obj, jmethodID methodID, ...); - jdouble (JNICALL *CallDoubleMethodV) - (JNIEnv *env, jobject obj, jmethodID methodID, va_list args); - jdouble (JNICALL *CallDoubleMethodA) - (JNIEnv *env, jobject obj, jmethodID methodID, const jvalue *args); - - void (JNICALL *CallVoidMethod) - (JNIEnv *env, jobject obj, jmethodID methodID, ...); - void (JNICALL *CallVoidMethodV) - (JNIEnv *env, jobject obj, jmethodID methodID, va_list args); - void (JNICALL *CallVoidMethodA) - (JNIEnv *env, jobject obj, jmethodID methodID, const jvalue * args); - - jobject (JNICALL *CallNonvirtualObjectMethod) - (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...); - jobject (JNICALL *CallNonvirtualObjectMethodV) - (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, - va_list args); - jobject (JNICALL *CallNonvirtualObjectMethodA) - (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, - const jvalue * args); - - jboolean (JNICALL *CallNonvirtualBooleanMethod) - (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...); - jboolean (JNICALL *CallNonvirtualBooleanMethodV) - (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, - va_list args); - jboolean (JNICALL *CallNonvirtualBooleanMethodA) - (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, - const jvalue * args); - - jbyte (JNICALL *CallNonvirtualByteMethod) - (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...); - jbyte (JNICALL *CallNonvirtualByteMethodV) - (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, - va_list args); - jbyte (JNICALL *CallNonvirtualByteMethodA) - (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, - const jvalue *args); - - jchar (JNICALL *CallNonvirtualCharMethod) - (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...); - jchar (JNICALL *CallNonvirtualCharMethodV) - (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, - va_list args); - jchar (JNICALL *CallNonvirtualCharMethodA) - (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, - const jvalue *args); - - jshort (JNICALL *CallNonvirtualShortMethod) - (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...); - jshort (JNICALL *CallNonvirtualShortMethodV) - (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, - va_list args); - jshort (JNICALL *CallNonvirtualShortMethodA) - (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, - const jvalue *args); - - jint (JNICALL *CallNonvirtualIntMethod) - (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...); - jint (JNICALL *CallNonvirtualIntMethodV) - (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, - va_list args); - jint (JNICALL *CallNonvirtualIntMethodA) - (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, - const jvalue *args); - - jlong (JNICALL *CallNonvirtualLongMethod) - (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...); - jlong (JNICALL *CallNonvirtualLongMethodV) - (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, - va_list args); - jlong (JNICALL *CallNonvirtualLongMethodA) - (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, - const jvalue *args); - - jfloat (JNICALL *CallNonvirtualFloatMethod) - (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...); - jfloat (JNICALL *CallNonvirtualFloatMethodV) - (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, - va_list args); - jfloat (JNICALL *CallNonvirtualFloatMethodA) - (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, - const jvalue *args); - - jdouble (JNICALL *CallNonvirtualDoubleMethod) - (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...); - jdouble (JNICALL *CallNonvirtualDoubleMethodV) - (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, - va_list args); - jdouble (JNICALL *CallNonvirtualDoubleMethodA) - (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, - const jvalue *args); - - void (JNICALL *CallNonvirtualVoidMethod) - (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...); - void (JNICALL *CallNonvirtualVoidMethodV) - (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, - va_list args); - void (JNICALL *CallNonvirtualVoidMethodA) - (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, - const jvalue * args); - - jfieldID (JNICALL *GetFieldID) - (JNIEnv *env, jclass clazz, const char *name, const char *sig); - - jobject (JNICALL *GetObjectField) - (JNIEnv *env, jobject obj, jfieldID fieldID); - jboolean (JNICALL *GetBooleanField) - (JNIEnv *env, jobject obj, jfieldID fieldID); - jbyte (JNICALL *GetByteField) - (JNIEnv *env, jobject obj, jfieldID fieldID); - jchar (JNICALL *GetCharField) - (JNIEnv *env, jobject obj, jfieldID fieldID); - jshort (JNICALL *GetShortField) - (JNIEnv *env, jobject obj, jfieldID fieldID); - jint (JNICALL *GetIntField) - (JNIEnv *env, jobject obj, jfieldID fieldID); - jlong (JNICALL *GetLongField) - (JNIEnv *env, jobject obj, jfieldID fieldID); - jfloat (JNICALL *GetFloatField) - (JNIEnv *env, jobject obj, jfieldID fieldID); - jdouble (JNICALL *GetDoubleField) - (JNIEnv *env, jobject obj, jfieldID fieldID); - - void (JNICALL *SetObjectField) - (JNIEnv *env, jobject obj, jfieldID fieldID, jobject val); - void (JNICALL *SetBooleanField) - (JNIEnv *env, jobject obj, jfieldID fieldID, jboolean val); - void (JNICALL *SetByteField) - (JNIEnv *env, jobject obj, jfieldID fieldID, jbyte val); - void (JNICALL *SetCharField) - (JNIEnv *env, jobject obj, jfieldID fieldID, jchar val); - void (JNICALL *SetShortField) - (JNIEnv *env, jobject obj, jfieldID fieldID, jshort val); - void (JNICALL *SetIntField) - (JNIEnv *env, jobject obj, jfieldID fieldID, jint val); - void (JNICALL *SetLongField) - (JNIEnv *env, jobject obj, jfieldID fieldID, jlong val); - void (JNICALL *SetFloatField) - (JNIEnv *env, jobject obj, jfieldID fieldID, jfloat val); - void (JNICALL *SetDoubleField) - (JNIEnv *env, jobject obj, jfieldID fieldID, jdouble val); - - jmethodID (JNICALL *GetStaticMethodID) - (JNIEnv *env, jclass clazz, const char *name, const char *sig); - - jobject (JNICALL *CallStaticObjectMethod) - (JNIEnv *env, jclass clazz, jmethodID methodID, ...); - jobject (JNICALL *CallStaticObjectMethodV) - (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args); - jobject (JNICALL *CallStaticObjectMethodA) - (JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args); - - jboolean (JNICALL *CallStaticBooleanMethod) - (JNIEnv *env, jclass clazz, jmethodID methodID, ...); - jboolean (JNICALL *CallStaticBooleanMethodV) - (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args); - jboolean (JNICALL *CallStaticBooleanMethodA) - (JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args); - - jbyte (JNICALL *CallStaticByteMethod) - (JNIEnv *env, jclass clazz, jmethodID methodID, ...); - jbyte (JNICALL *CallStaticByteMethodV) - (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args); - jbyte (JNICALL *CallStaticByteMethodA) - (JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args); - - jchar (JNICALL *CallStaticCharMethod) - (JNIEnv *env, jclass clazz, jmethodID methodID, ...); - jchar (JNICALL *CallStaticCharMethodV) - (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args); - jchar (JNICALL *CallStaticCharMethodA) - (JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args); - - jshort (JNICALL *CallStaticShortMethod) - (JNIEnv *env, jclass clazz, jmethodID methodID, ...); - jshort (JNICALL *CallStaticShortMethodV) - (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args); - jshort (JNICALL *CallStaticShortMethodA) - (JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args); - - jint (JNICALL *CallStaticIntMethod) - (JNIEnv *env, jclass clazz, jmethodID methodID, ...); - jint (JNICALL *CallStaticIntMethodV) - (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args); - jint (JNICALL *CallStaticIntMethodA) - (JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args); - - jlong (JNICALL *CallStaticLongMethod) - (JNIEnv *env, jclass clazz, jmethodID methodID, ...); - jlong (JNICALL *CallStaticLongMethodV) - (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args); - jlong (JNICALL *CallStaticLongMethodA) - (JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args); - - jfloat (JNICALL *CallStaticFloatMethod) - (JNIEnv *env, jclass clazz, jmethodID methodID, ...); - jfloat (JNICALL *CallStaticFloatMethodV) - (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args); - jfloat (JNICALL *CallStaticFloatMethodA) - (JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args); - - jdouble (JNICALL *CallStaticDoubleMethod) - (JNIEnv *env, jclass clazz, jmethodID methodID, ...); - jdouble (JNICALL *CallStaticDoubleMethodV) - (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args); - jdouble (JNICALL *CallStaticDoubleMethodA) - (JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args); - - void (JNICALL *CallStaticVoidMethod) - (JNIEnv *env, jclass cls, jmethodID methodID, ...); - void (JNICALL *CallStaticVoidMethodV) - (JNIEnv *env, jclass cls, jmethodID methodID, va_list args); - void (JNICALL *CallStaticVoidMethodA) - (JNIEnv *env, jclass cls, jmethodID methodID, const jvalue * args); - - jfieldID (JNICALL *GetStaticFieldID) - (JNIEnv *env, jclass clazz, const char *name, const char *sig); - jobject (JNICALL *GetStaticObjectField) - (JNIEnv *env, jclass clazz, jfieldID fieldID); - jboolean (JNICALL *GetStaticBooleanField) - (JNIEnv *env, jclass clazz, jfieldID fieldID); - jbyte (JNICALL *GetStaticByteField) - (JNIEnv *env, jclass clazz, jfieldID fieldID); - jchar (JNICALL *GetStaticCharField) - (JNIEnv *env, jclass clazz, jfieldID fieldID); - jshort (JNICALL *GetStaticShortField) - (JNIEnv *env, jclass clazz, jfieldID fieldID); - jint (JNICALL *GetStaticIntField) - (JNIEnv *env, jclass clazz, jfieldID fieldID); - jlong (JNICALL *GetStaticLongField) - (JNIEnv *env, jclass clazz, jfieldID fieldID); - jfloat (JNICALL *GetStaticFloatField) - (JNIEnv *env, jclass clazz, jfieldID fieldID); - jdouble (JNICALL *GetStaticDoubleField) - (JNIEnv *env, jclass clazz, jfieldID fieldID); - - void (JNICALL *SetStaticObjectField) - (JNIEnv *env, jclass clazz, jfieldID fieldID, jobject value); - void (JNICALL *SetStaticBooleanField) - (JNIEnv *env, jclass clazz, jfieldID fieldID, jboolean value); - void (JNICALL *SetStaticByteField) - (JNIEnv *env, jclass clazz, jfieldID fieldID, jbyte value); - void (JNICALL *SetStaticCharField) - (JNIEnv *env, jclass clazz, jfieldID fieldID, jchar value); - void (JNICALL *SetStaticShortField) - (JNIEnv *env, jclass clazz, jfieldID fieldID, jshort value); - void (JNICALL *SetStaticIntField) - (JNIEnv *env, jclass clazz, jfieldID fieldID, jint value); - void (JNICALL *SetStaticLongField) - (JNIEnv *env, jclass clazz, jfieldID fieldID, jlong value); - void (JNICALL *SetStaticFloatField) - (JNIEnv *env, jclass clazz, jfieldID fieldID, jfloat value); - void (JNICALL *SetStaticDoubleField) - (JNIEnv *env, jclass clazz, jfieldID fieldID, jdouble value); - - jstring (JNICALL *NewString) - (JNIEnv *env, const jchar *unicode, jsize len); - jsize (JNICALL *GetStringLength) - (JNIEnv *env, jstring str); - const jchar *(JNICALL *GetStringChars) - (JNIEnv *env, jstring str, jboolean *isCopy); - void (JNICALL *ReleaseStringChars) - (JNIEnv *env, jstring str, const jchar *chars); - - jstring (JNICALL *NewStringUTF) - (JNIEnv *env, const char *utf); - jsize (JNICALL *GetStringUTFLength) - (JNIEnv *env, jstring str); - const char* (JNICALL *GetStringUTFChars) - (JNIEnv *env, jstring str, jboolean *isCopy); - void (JNICALL *ReleaseStringUTFChars) - (JNIEnv *env, jstring str, const char* chars); - - - jsize (JNICALL *GetArrayLength) - (JNIEnv *env, jarray array); - - jobjectArray (JNICALL *NewObjectArray) - (JNIEnv *env, jsize len, jclass clazz, jobject init); - jobject (JNICALL *GetObjectArrayElement) - (JNIEnv *env, jobjectArray array, jsize index); - void (JNICALL *SetObjectArrayElement) - (JNIEnv *env, jobjectArray array, jsize index, jobject val); - - jbooleanArray (JNICALL *NewBooleanArray) - (JNIEnv *env, jsize len); - jbyteArray (JNICALL *NewByteArray) - (JNIEnv *env, jsize len); - jcharArray (JNICALL *NewCharArray) - (JNIEnv *env, jsize len); - jshortArray (JNICALL *NewShortArray) - (JNIEnv *env, jsize len); - jintArray (JNICALL *NewIntArray) - (JNIEnv *env, jsize len); - jlongArray (JNICALL *NewLongArray) - (JNIEnv *env, jsize len); - jfloatArray (JNICALL *NewFloatArray) - (JNIEnv *env, jsize len); - jdoubleArray (JNICALL *NewDoubleArray) - (JNIEnv *env, jsize len); - - jboolean * (JNICALL *GetBooleanArrayElements) - (JNIEnv *env, jbooleanArray array, jboolean *isCopy); - jbyte * (JNICALL *GetByteArrayElements) - (JNIEnv *env, jbyteArray array, jboolean *isCopy); - jchar * (JNICALL *GetCharArrayElements) - (JNIEnv *env, jcharArray array, jboolean *isCopy); - jshort * (JNICALL *GetShortArrayElements) - (JNIEnv *env, jshortArray array, jboolean *isCopy); - jint * (JNICALL *GetIntArrayElements) - (JNIEnv *env, jintArray array, jboolean *isCopy); - jlong * (JNICALL *GetLongArrayElements) - (JNIEnv *env, jlongArray array, jboolean *isCopy); - jfloat * (JNICALL *GetFloatArrayElements) - (JNIEnv *env, jfloatArray array, jboolean *isCopy); - jdouble * (JNICALL *GetDoubleArrayElements) - (JNIEnv *env, jdoubleArray array, jboolean *isCopy); - - void (JNICALL *ReleaseBooleanArrayElements) - (JNIEnv *env, jbooleanArray array, jboolean *elems, jint mode); - void (JNICALL *ReleaseByteArrayElements) - (JNIEnv *env, jbyteArray array, jbyte *elems, jint mode); - void (JNICALL *ReleaseCharArrayElements) - (JNIEnv *env, jcharArray array, jchar *elems, jint mode); - void (JNICALL *ReleaseShortArrayElements) - (JNIEnv *env, jshortArray array, jshort *elems, jint mode); - void (JNICALL *ReleaseIntArrayElements) - (JNIEnv *env, jintArray array, jint *elems, jint mode); - void (JNICALL *ReleaseLongArrayElements) - (JNIEnv *env, jlongArray array, jlong *elems, jint mode); - void (JNICALL *ReleaseFloatArrayElements) - (JNIEnv *env, jfloatArray array, jfloat *elems, jint mode); - void (JNICALL *ReleaseDoubleArrayElements) - (JNIEnv *env, jdoubleArray array, jdouble *elems, jint mode); - - void (JNICALL *GetBooleanArrayRegion) - (JNIEnv *env, jbooleanArray array, jsize start, jsize l, jboolean *buf); - void (JNICALL *GetByteArrayRegion) - (JNIEnv *env, jbyteArray array, jsize start, jsize len, jbyte *buf); - void (JNICALL *GetCharArrayRegion) - (JNIEnv *env, jcharArray array, jsize start, jsize len, jchar *buf); - void (JNICALL *GetShortArrayRegion) - (JNIEnv *env, jshortArray array, jsize start, jsize len, jshort *buf); - void (JNICALL *GetIntArrayRegion) - (JNIEnv *env, jintArray array, jsize start, jsize len, jint *buf); - void (JNICALL *GetLongArrayRegion) - (JNIEnv *env, jlongArray array, jsize start, jsize len, jlong *buf); - void (JNICALL *GetFloatArrayRegion) - (JNIEnv *env, jfloatArray array, jsize start, jsize len, jfloat *buf); - void (JNICALL *GetDoubleArrayRegion) - (JNIEnv *env, jdoubleArray array, jsize start, jsize len, jdouble *buf); - - void (JNICALL *SetBooleanArrayRegion) - (JNIEnv *env, jbooleanArray array, jsize start, jsize l, const jboolean *buf); - void (JNICALL *SetByteArrayRegion) - (JNIEnv *env, jbyteArray array, jsize start, jsize len, const jbyte *buf); - void (JNICALL *SetCharArrayRegion) - (JNIEnv *env, jcharArray array, jsize start, jsize len, const jchar *buf); - void (JNICALL *SetShortArrayRegion) - (JNIEnv *env, jshortArray array, jsize start, jsize len, const jshort *buf); - void (JNICALL *SetIntArrayRegion) - (JNIEnv *env, jintArray array, jsize start, jsize len, const jint *buf); - void (JNICALL *SetLongArrayRegion) - (JNIEnv *env, jlongArray array, jsize start, jsize len, const jlong *buf); - void (JNICALL *SetFloatArrayRegion) - (JNIEnv *env, jfloatArray array, jsize start, jsize len, const jfloat *buf); - void (JNICALL *SetDoubleArrayRegion) - (JNIEnv *env, jdoubleArray array, jsize start, jsize len, const jdouble *buf); - - jint (JNICALL *RegisterNatives) - (JNIEnv *env, jclass clazz, const JNINativeMethod *methods, - jint nMethods); - jint (JNICALL *UnregisterNatives) - (JNIEnv *env, jclass clazz); - - jint (JNICALL *MonitorEnter) - (JNIEnv *env, jobject obj); - jint (JNICALL *MonitorExit) - (JNIEnv *env, jobject obj); - - jint (JNICALL *GetJavaVM) - (JNIEnv *env, JavaVM **vm); - - void (JNICALL *GetStringRegion) - (JNIEnv *env, jstring str, jsize start, jsize len, jchar *buf); - void (JNICALL *GetStringUTFRegion) - (JNIEnv *env, jstring str, jsize start, jsize len, char *buf); - - void * (JNICALL *GetPrimitiveArrayCritical) - (JNIEnv *env, jarray array, jboolean *isCopy); - void (JNICALL *ReleasePrimitiveArrayCritical) - (JNIEnv *env, jarray array, void *carray, jint mode); - - const jchar * (JNICALL *GetStringCritical) - (JNIEnv *env, jstring string, jboolean *isCopy); - void (JNICALL *ReleaseStringCritical) - (JNIEnv *env, jstring string, const jchar *cstring); - - jweak (JNICALL *NewWeakGlobalRef) - (JNIEnv *env, jobject obj); - void (JNICALL *DeleteWeakGlobalRef) - (JNIEnv *env, jweak ref); - - jboolean (JNICALL *ExceptionCheck) - (JNIEnv *env); - - jobject (JNICALL *NewDirectByteBuffer) - (JNIEnv* env, void* address, jlong capacity); - void* (JNICALL *GetDirectBufferAddress) - (JNIEnv* env, jobject buf); - jlong (JNICALL *GetDirectBufferCapacity) - (JNIEnv* env, jobject buf); - - /* New JNI 1.6 Features */ - - jobjectRefType (JNICALL *GetObjectRefType) - (JNIEnv* env, jobject obj); - - /* Module Features */ - - jobject (JNICALL *GetModule) - (JNIEnv* env, jclass clazz); - - /* Virtual threads */ - - jboolean (JNICALL *IsVirtualThread) - (JNIEnv* env, jobject obj); - - /* Large UTF8 Support */ - - jlong (JNICALL *GetStringUTFLengthAsLong) - (JNIEnv *env, jstring str); - -}; - -/* - * We use inlined functions for C++ so that programmers can write: - * - * env->FindClass("java/lang/String") - * - * in C++ rather than: - * - * (*env)->FindClass(env, "java/lang/String") - * - * in C. - */ - -struct JNIEnv_ { - const struct JNINativeInterface_ *functions; -#ifdef __cplusplus - - jint GetVersion() { - return functions->GetVersion(this); - } - jclass DefineClass(const char *name, jobject loader, const jbyte *buf, - jsize len) { - return functions->DefineClass(this, name, loader, buf, len); - } - jclass FindClass(const char *name) { - return functions->FindClass(this, name); - } - jmethodID FromReflectedMethod(jobject method) { - return functions->FromReflectedMethod(this,method); - } - jfieldID FromReflectedField(jobject field) { - return functions->FromReflectedField(this,field); - } - - jobject ToReflectedMethod(jclass cls, jmethodID methodID, jboolean isStatic) { - return functions->ToReflectedMethod(this, cls, methodID, isStatic); - } - - jclass GetSuperclass(jclass sub) { - return functions->GetSuperclass(this, sub); - } - jboolean IsAssignableFrom(jclass sub, jclass sup) { - return functions->IsAssignableFrom(this, sub, sup); - } - - jobject ToReflectedField(jclass cls, jfieldID fieldID, jboolean isStatic) { - return functions->ToReflectedField(this,cls,fieldID,isStatic); - } - - jint Throw(jthrowable obj) { - return functions->Throw(this, obj); - } - jint ThrowNew(jclass clazz, const char *msg) { - return functions->ThrowNew(this, clazz, msg); - } - jthrowable ExceptionOccurred() { - return functions->ExceptionOccurred(this); - } - void ExceptionDescribe() { - functions->ExceptionDescribe(this); - } - void ExceptionClear() { - functions->ExceptionClear(this); - } - void FatalError(const char *msg) { - functions->FatalError(this, msg); - } - - jint PushLocalFrame(jint capacity) { - return functions->PushLocalFrame(this,capacity); - } - jobject PopLocalFrame(jobject result) { - return functions->PopLocalFrame(this,result); - } - - jobject NewGlobalRef(jobject lobj) { - return functions->NewGlobalRef(this,lobj); - } - void DeleteGlobalRef(jobject gref) { - functions->DeleteGlobalRef(this,gref); - } - void DeleteLocalRef(jobject obj) { - functions->DeleteLocalRef(this, obj); - } - - jboolean IsSameObject(jobject obj1, jobject obj2) { - return functions->IsSameObject(this,obj1,obj2); - } - - jobject NewLocalRef(jobject ref) { - return functions->NewLocalRef(this,ref); - } - jint EnsureLocalCapacity(jint capacity) { - return functions->EnsureLocalCapacity(this,capacity); - } - - jobject AllocObject(jclass clazz) { - return functions->AllocObject(this,clazz); - } - jobject NewObject(jclass clazz, jmethodID methodID, ...) { - va_list args; - jobject result; - va_start(args, methodID); - result = functions->NewObjectV(this,clazz,methodID,args); - va_end(args); - return result; - } - jobject NewObjectV(jclass clazz, jmethodID methodID, - va_list args) { - return functions->NewObjectV(this,clazz,methodID,args); - } - jobject NewObjectA(jclass clazz, jmethodID methodID, - const jvalue *args) { - return functions->NewObjectA(this,clazz,methodID,args); - } - - jclass GetObjectClass(jobject obj) { - return functions->GetObjectClass(this,obj); - } - jboolean IsInstanceOf(jobject obj, jclass clazz) { - return functions->IsInstanceOf(this,obj,clazz); - } - - jmethodID GetMethodID(jclass clazz, const char *name, - const char *sig) { - return functions->GetMethodID(this,clazz,name,sig); - } - - jobject CallObjectMethod(jobject obj, jmethodID methodID, ...) { - va_list args; - jobject result; - va_start(args,methodID); - result = functions->CallObjectMethodV(this,obj,methodID,args); - va_end(args); - return result; - } - jobject CallObjectMethodV(jobject obj, jmethodID methodID, - va_list args) { - return functions->CallObjectMethodV(this,obj,methodID,args); - } - jobject CallObjectMethodA(jobject obj, jmethodID methodID, - const jvalue * args) { - return functions->CallObjectMethodA(this,obj,methodID,args); - } - - jboolean CallBooleanMethod(jobject obj, - jmethodID methodID, ...) { - va_list args; - jboolean result; - va_start(args,methodID); - result = functions->CallBooleanMethodV(this,obj,methodID,args); - va_end(args); - return result; - } - jboolean CallBooleanMethodV(jobject obj, jmethodID methodID, - va_list args) { - return functions->CallBooleanMethodV(this,obj,methodID,args); - } - jboolean CallBooleanMethodA(jobject obj, jmethodID methodID, - const jvalue * args) { - return functions->CallBooleanMethodA(this,obj,methodID, args); - } - - jbyte CallByteMethod(jobject obj, jmethodID methodID, ...) { - va_list args; - jbyte result; - va_start(args,methodID); - result = functions->CallByteMethodV(this,obj,methodID,args); - va_end(args); - return result; - } - jbyte CallByteMethodV(jobject obj, jmethodID methodID, - va_list args) { - return functions->CallByteMethodV(this,obj,methodID,args); - } - jbyte CallByteMethodA(jobject obj, jmethodID methodID, - const jvalue * args) { - return functions->CallByteMethodA(this,obj,methodID,args); - } - - jchar CallCharMethod(jobject obj, jmethodID methodID, ...) { - va_list args; - jchar result; - va_start(args,methodID); - result = functions->CallCharMethodV(this,obj,methodID,args); - va_end(args); - return result; - } - jchar CallCharMethodV(jobject obj, jmethodID methodID, - va_list args) { - return functions->CallCharMethodV(this,obj,methodID,args); - } - jchar CallCharMethodA(jobject obj, jmethodID methodID, - const jvalue * args) { - return functions->CallCharMethodA(this,obj,methodID,args); - } - - jshort CallShortMethod(jobject obj, jmethodID methodID, ...) { - va_list args; - jshort result; - va_start(args,methodID); - result = functions->CallShortMethodV(this,obj,methodID,args); - va_end(args); - return result; - } - jshort CallShortMethodV(jobject obj, jmethodID methodID, - va_list args) { - return functions->CallShortMethodV(this,obj,methodID,args); - } - jshort CallShortMethodA(jobject obj, jmethodID methodID, - const jvalue * args) { - return functions->CallShortMethodA(this,obj,methodID,args); - } - - jint CallIntMethod(jobject obj, jmethodID methodID, ...) { - va_list args; - jint result; - va_start(args,methodID); - result = functions->CallIntMethodV(this,obj,methodID,args); - va_end(args); - return result; - } - jint CallIntMethodV(jobject obj, jmethodID methodID, - va_list args) { - return functions->CallIntMethodV(this,obj,methodID,args); - } - jint CallIntMethodA(jobject obj, jmethodID methodID, - const jvalue * args) { - return functions->CallIntMethodA(this,obj,methodID,args); - } - - jlong CallLongMethod(jobject obj, jmethodID methodID, ...) { - va_list args; - jlong result; - va_start(args,methodID); - result = functions->CallLongMethodV(this,obj,methodID,args); - va_end(args); - return result; - } - jlong CallLongMethodV(jobject obj, jmethodID methodID, - va_list args) { - return functions->CallLongMethodV(this,obj,methodID,args); - } - jlong CallLongMethodA(jobject obj, jmethodID methodID, - const jvalue * args) { - return functions->CallLongMethodA(this,obj,methodID,args); - } - - jfloat CallFloatMethod(jobject obj, jmethodID methodID, ...) { - va_list args; - jfloat result; - va_start(args,methodID); - result = functions->CallFloatMethodV(this,obj,methodID,args); - va_end(args); - return result; - } - jfloat CallFloatMethodV(jobject obj, jmethodID methodID, - va_list args) { - return functions->CallFloatMethodV(this,obj,methodID,args); - } - jfloat CallFloatMethodA(jobject obj, jmethodID methodID, - const jvalue * args) { - return functions->CallFloatMethodA(this,obj,methodID,args); - } - - jdouble CallDoubleMethod(jobject obj, jmethodID methodID, ...) { - va_list args; - jdouble result; - va_start(args,methodID); - result = functions->CallDoubleMethodV(this,obj,methodID,args); - va_end(args); - return result; - } - jdouble CallDoubleMethodV(jobject obj, jmethodID methodID, - va_list args) { - return functions->CallDoubleMethodV(this,obj,methodID,args); - } - jdouble CallDoubleMethodA(jobject obj, jmethodID methodID, - const jvalue * args) { - return functions->CallDoubleMethodA(this,obj,methodID,args); - } - - void CallVoidMethod(jobject obj, jmethodID methodID, ...) { - va_list args; - va_start(args,methodID); - functions->CallVoidMethodV(this,obj,methodID,args); - va_end(args); - } - void CallVoidMethodV(jobject obj, jmethodID methodID, - va_list args) { - functions->CallVoidMethodV(this,obj,methodID,args); - } - void CallVoidMethodA(jobject obj, jmethodID methodID, - const jvalue * args) { - functions->CallVoidMethodA(this,obj,methodID,args); - } - - jobject CallNonvirtualObjectMethod(jobject obj, jclass clazz, - jmethodID methodID, ...) { - va_list args; - jobject result; - va_start(args,methodID); - result = functions->CallNonvirtualObjectMethodV(this,obj,clazz, - methodID,args); - va_end(args); - return result; - } - jobject CallNonvirtualObjectMethodV(jobject obj, jclass clazz, - jmethodID methodID, va_list args) { - return functions->CallNonvirtualObjectMethodV(this,obj,clazz, - methodID,args); - } - jobject CallNonvirtualObjectMethodA(jobject obj, jclass clazz, - jmethodID methodID, const jvalue * args) { - return functions->CallNonvirtualObjectMethodA(this,obj,clazz, - methodID,args); - } - - jboolean CallNonvirtualBooleanMethod(jobject obj, jclass clazz, - jmethodID methodID, ...) { - va_list args; - jboolean result; - va_start(args,methodID); - result = functions->CallNonvirtualBooleanMethodV(this,obj,clazz, - methodID,args); - va_end(args); - return result; - } - jboolean CallNonvirtualBooleanMethodV(jobject obj, jclass clazz, - jmethodID methodID, va_list args) { - return functions->CallNonvirtualBooleanMethodV(this,obj,clazz, - methodID,args); - } - jboolean CallNonvirtualBooleanMethodA(jobject obj, jclass clazz, - jmethodID methodID, const jvalue * args) { - return functions->CallNonvirtualBooleanMethodA(this,obj,clazz, - methodID, args); - } - - jbyte CallNonvirtualByteMethod(jobject obj, jclass clazz, - jmethodID methodID, ...) { - va_list args; - jbyte result; - va_start(args,methodID); - result = functions->CallNonvirtualByteMethodV(this,obj,clazz, - methodID,args); - va_end(args); - return result; - } - jbyte CallNonvirtualByteMethodV(jobject obj, jclass clazz, - jmethodID methodID, va_list args) { - return functions->CallNonvirtualByteMethodV(this,obj,clazz, - methodID,args); - } - jbyte CallNonvirtualByteMethodA(jobject obj, jclass clazz, - jmethodID methodID, const jvalue * args) { - return functions->CallNonvirtualByteMethodA(this,obj,clazz, - methodID,args); - } - - jchar CallNonvirtualCharMethod(jobject obj, jclass clazz, - jmethodID methodID, ...) { - va_list args; - jchar result; - va_start(args,methodID); - result = functions->CallNonvirtualCharMethodV(this,obj,clazz, - methodID,args); - va_end(args); - return result; - } - jchar CallNonvirtualCharMethodV(jobject obj, jclass clazz, - jmethodID methodID, va_list args) { - return functions->CallNonvirtualCharMethodV(this,obj,clazz, - methodID,args); - } - jchar CallNonvirtualCharMethodA(jobject obj, jclass clazz, - jmethodID methodID, const jvalue * args) { - return functions->CallNonvirtualCharMethodA(this,obj,clazz, - methodID,args); - } - - jshort CallNonvirtualShortMethod(jobject obj, jclass clazz, - jmethodID methodID, ...) { - va_list args; - jshort result; - va_start(args,methodID); - result = functions->CallNonvirtualShortMethodV(this,obj,clazz, - methodID,args); - va_end(args); - return result; - } - jshort CallNonvirtualShortMethodV(jobject obj, jclass clazz, - jmethodID methodID, va_list args) { - return functions->CallNonvirtualShortMethodV(this,obj,clazz, - methodID,args); - } - jshort CallNonvirtualShortMethodA(jobject obj, jclass clazz, - jmethodID methodID, const jvalue * args) { - return functions->CallNonvirtualShortMethodA(this,obj,clazz, - methodID,args); - } - - jint CallNonvirtualIntMethod(jobject obj, jclass clazz, - jmethodID methodID, ...) { - va_list args; - jint result; - va_start(args,methodID); - result = functions->CallNonvirtualIntMethodV(this,obj,clazz, - methodID,args); - va_end(args); - return result; - } - jint CallNonvirtualIntMethodV(jobject obj, jclass clazz, - jmethodID methodID, va_list args) { - return functions->CallNonvirtualIntMethodV(this,obj,clazz, - methodID,args); - } - jint CallNonvirtualIntMethodA(jobject obj, jclass clazz, - jmethodID methodID, const jvalue * args) { - return functions->CallNonvirtualIntMethodA(this,obj,clazz, - methodID,args); - } - - jlong CallNonvirtualLongMethod(jobject obj, jclass clazz, - jmethodID methodID, ...) { - va_list args; - jlong result; - va_start(args,methodID); - result = functions->CallNonvirtualLongMethodV(this,obj,clazz, - methodID,args); - va_end(args); - return result; - } - jlong CallNonvirtualLongMethodV(jobject obj, jclass clazz, - jmethodID methodID, va_list args) { - return functions->CallNonvirtualLongMethodV(this,obj,clazz, - methodID,args); - } - jlong CallNonvirtualLongMethodA(jobject obj, jclass clazz, - jmethodID methodID, const jvalue * args) { - return functions->CallNonvirtualLongMethodA(this,obj,clazz, - methodID,args); - } - - jfloat CallNonvirtualFloatMethod(jobject obj, jclass clazz, - jmethodID methodID, ...) { - va_list args; - jfloat result; - va_start(args,methodID); - result = functions->CallNonvirtualFloatMethodV(this,obj,clazz, - methodID,args); - va_end(args); - return result; - } - jfloat CallNonvirtualFloatMethodV(jobject obj, jclass clazz, - jmethodID methodID, - va_list args) { - return functions->CallNonvirtualFloatMethodV(this,obj,clazz, - methodID,args); - } - jfloat CallNonvirtualFloatMethodA(jobject obj, jclass clazz, - jmethodID methodID, - const jvalue * args) { - return functions->CallNonvirtualFloatMethodA(this,obj,clazz, - methodID,args); - } - - jdouble CallNonvirtualDoubleMethod(jobject obj, jclass clazz, - jmethodID methodID, ...) { - va_list args; - jdouble result; - va_start(args,methodID); - result = functions->CallNonvirtualDoubleMethodV(this,obj,clazz, - methodID,args); - va_end(args); - return result; - } - jdouble CallNonvirtualDoubleMethodV(jobject obj, jclass clazz, - jmethodID methodID, - va_list args) { - return functions->CallNonvirtualDoubleMethodV(this,obj,clazz, - methodID,args); - } - jdouble CallNonvirtualDoubleMethodA(jobject obj, jclass clazz, - jmethodID methodID, - const jvalue * args) { - return functions->CallNonvirtualDoubleMethodA(this,obj,clazz, - methodID,args); - } - - void CallNonvirtualVoidMethod(jobject obj, jclass clazz, - jmethodID methodID, ...) { - va_list args; - va_start(args,methodID); - functions->CallNonvirtualVoidMethodV(this,obj,clazz,methodID,args); - va_end(args); - } - void CallNonvirtualVoidMethodV(jobject obj, jclass clazz, - jmethodID methodID, - va_list args) { - functions->CallNonvirtualVoidMethodV(this,obj,clazz,methodID,args); - } - void CallNonvirtualVoidMethodA(jobject obj, jclass clazz, - jmethodID methodID, - const jvalue * args) { - functions->CallNonvirtualVoidMethodA(this,obj,clazz,methodID,args); - } - - jfieldID GetFieldID(jclass clazz, const char *name, - const char *sig) { - return functions->GetFieldID(this,clazz,name,sig); - } - - jobject GetObjectField(jobject obj, jfieldID fieldID) { - return functions->GetObjectField(this,obj,fieldID); - } - jboolean GetBooleanField(jobject obj, jfieldID fieldID) { - return functions->GetBooleanField(this,obj,fieldID); - } - jbyte GetByteField(jobject obj, jfieldID fieldID) { - return functions->GetByteField(this,obj,fieldID); - } - jchar GetCharField(jobject obj, jfieldID fieldID) { - return functions->GetCharField(this,obj,fieldID); - } - jshort GetShortField(jobject obj, jfieldID fieldID) { - return functions->GetShortField(this,obj,fieldID); - } - jint GetIntField(jobject obj, jfieldID fieldID) { - return functions->GetIntField(this,obj,fieldID); - } - jlong GetLongField(jobject obj, jfieldID fieldID) { - return functions->GetLongField(this,obj,fieldID); - } - jfloat GetFloatField(jobject obj, jfieldID fieldID) { - return functions->GetFloatField(this,obj,fieldID); - } - jdouble GetDoubleField(jobject obj, jfieldID fieldID) { - return functions->GetDoubleField(this,obj,fieldID); - } - - void SetObjectField(jobject obj, jfieldID fieldID, jobject val) { - functions->SetObjectField(this,obj,fieldID,val); - } - void SetBooleanField(jobject obj, jfieldID fieldID, - jboolean val) { - functions->SetBooleanField(this,obj,fieldID,val); - } - void SetByteField(jobject obj, jfieldID fieldID, - jbyte val) { - functions->SetByteField(this,obj,fieldID,val); - } - void SetCharField(jobject obj, jfieldID fieldID, - jchar val) { - functions->SetCharField(this,obj,fieldID,val); - } - void SetShortField(jobject obj, jfieldID fieldID, - jshort val) { - functions->SetShortField(this,obj,fieldID,val); - } - void SetIntField(jobject obj, jfieldID fieldID, - jint val) { - functions->SetIntField(this,obj,fieldID,val); - } - void SetLongField(jobject obj, jfieldID fieldID, - jlong val) { - functions->SetLongField(this,obj,fieldID,val); - } - void SetFloatField(jobject obj, jfieldID fieldID, - jfloat val) { - functions->SetFloatField(this,obj,fieldID,val); - } - void SetDoubleField(jobject obj, jfieldID fieldID, - jdouble val) { - functions->SetDoubleField(this,obj,fieldID,val); - } - - jmethodID GetStaticMethodID(jclass clazz, const char *name, - const char *sig) { - return functions->GetStaticMethodID(this,clazz,name,sig); - } - - jobject CallStaticObjectMethod(jclass clazz, jmethodID methodID, - ...) { - va_list args; - jobject result; - va_start(args,methodID); - result = functions->CallStaticObjectMethodV(this,clazz,methodID,args); - va_end(args); - return result; - } - jobject CallStaticObjectMethodV(jclass clazz, jmethodID methodID, - va_list args) { - return functions->CallStaticObjectMethodV(this,clazz,methodID,args); - } - jobject CallStaticObjectMethodA(jclass clazz, jmethodID methodID, - const jvalue *args) { - return functions->CallStaticObjectMethodA(this,clazz,methodID,args); - } - - jboolean CallStaticBooleanMethod(jclass clazz, - jmethodID methodID, ...) { - va_list args; - jboolean result; - va_start(args,methodID); - result = functions->CallStaticBooleanMethodV(this,clazz,methodID,args); - va_end(args); - return result; - } - jboolean CallStaticBooleanMethodV(jclass clazz, - jmethodID methodID, va_list args) { - return functions->CallStaticBooleanMethodV(this,clazz,methodID,args); - } - jboolean CallStaticBooleanMethodA(jclass clazz, - jmethodID methodID, const jvalue *args) { - return functions->CallStaticBooleanMethodA(this,clazz,methodID,args); - } - - jbyte CallStaticByteMethod(jclass clazz, - jmethodID methodID, ...) { - va_list args; - jbyte result; - va_start(args,methodID); - result = functions->CallStaticByteMethodV(this,clazz,methodID,args); - va_end(args); - return result; - } - jbyte CallStaticByteMethodV(jclass clazz, - jmethodID methodID, va_list args) { - return functions->CallStaticByteMethodV(this,clazz,methodID,args); - } - jbyte CallStaticByteMethodA(jclass clazz, - jmethodID methodID, const jvalue *args) { - return functions->CallStaticByteMethodA(this,clazz,methodID,args); - } - - jchar CallStaticCharMethod(jclass clazz, - jmethodID methodID, ...) { - va_list args; - jchar result; - va_start(args,methodID); - result = functions->CallStaticCharMethodV(this,clazz,methodID,args); - va_end(args); - return result; - } - jchar CallStaticCharMethodV(jclass clazz, - jmethodID methodID, va_list args) { - return functions->CallStaticCharMethodV(this,clazz,methodID,args); - } - jchar CallStaticCharMethodA(jclass clazz, - jmethodID methodID, const jvalue *args) { - return functions->CallStaticCharMethodA(this,clazz,methodID,args); - } - - jshort CallStaticShortMethod(jclass clazz, - jmethodID methodID, ...) { - va_list args; - jshort result; - va_start(args,methodID); - result = functions->CallStaticShortMethodV(this,clazz,methodID,args); - va_end(args); - return result; - } - jshort CallStaticShortMethodV(jclass clazz, - jmethodID methodID, va_list args) { - return functions->CallStaticShortMethodV(this,clazz,methodID,args); - } - jshort CallStaticShortMethodA(jclass clazz, - jmethodID methodID, const jvalue *args) { - return functions->CallStaticShortMethodA(this,clazz,methodID,args); - } - - jint CallStaticIntMethod(jclass clazz, - jmethodID methodID, ...) { - va_list args; - jint result; - va_start(args,methodID); - result = functions->CallStaticIntMethodV(this,clazz,methodID,args); - va_end(args); - return result; - } - jint CallStaticIntMethodV(jclass clazz, - jmethodID methodID, va_list args) { - return functions->CallStaticIntMethodV(this,clazz,methodID,args); - } - jint CallStaticIntMethodA(jclass clazz, - jmethodID methodID, const jvalue *args) { - return functions->CallStaticIntMethodA(this,clazz,methodID,args); - } - - jlong CallStaticLongMethod(jclass clazz, - jmethodID methodID, ...) { - va_list args; - jlong result; - va_start(args,methodID); - result = functions->CallStaticLongMethodV(this,clazz,methodID,args); - va_end(args); - return result; - } - jlong CallStaticLongMethodV(jclass clazz, - jmethodID methodID, va_list args) { - return functions->CallStaticLongMethodV(this,clazz,methodID,args); - } - jlong CallStaticLongMethodA(jclass clazz, - jmethodID methodID, const jvalue *args) { - return functions->CallStaticLongMethodA(this,clazz,methodID,args); - } - - jfloat CallStaticFloatMethod(jclass clazz, - jmethodID methodID, ...) { - va_list args; - jfloat result; - va_start(args,methodID); - result = functions->CallStaticFloatMethodV(this,clazz,methodID,args); - va_end(args); - return result; - } - jfloat CallStaticFloatMethodV(jclass clazz, - jmethodID methodID, va_list args) { - return functions->CallStaticFloatMethodV(this,clazz,methodID,args); - } - jfloat CallStaticFloatMethodA(jclass clazz, - jmethodID methodID, const jvalue *args) { - return functions->CallStaticFloatMethodA(this,clazz,methodID,args); - } - - jdouble CallStaticDoubleMethod(jclass clazz, - jmethodID methodID, ...) { - va_list args; - jdouble result; - va_start(args,methodID); - result = functions->CallStaticDoubleMethodV(this,clazz,methodID,args); - va_end(args); - return result; - } - jdouble CallStaticDoubleMethodV(jclass clazz, - jmethodID methodID, va_list args) { - return functions->CallStaticDoubleMethodV(this,clazz,methodID,args); - } - jdouble CallStaticDoubleMethodA(jclass clazz, - jmethodID methodID, const jvalue *args) { - return functions->CallStaticDoubleMethodA(this,clazz,methodID,args); - } - - void CallStaticVoidMethod(jclass cls, jmethodID methodID, ...) { - va_list args; - va_start(args,methodID); - functions->CallStaticVoidMethodV(this,cls,methodID,args); - va_end(args); - } - void CallStaticVoidMethodV(jclass cls, jmethodID methodID, - va_list args) { - functions->CallStaticVoidMethodV(this,cls,methodID,args); - } - void CallStaticVoidMethodA(jclass cls, jmethodID methodID, - const jvalue * args) { - functions->CallStaticVoidMethodA(this,cls,methodID,args); - } - - jfieldID GetStaticFieldID(jclass clazz, const char *name, - const char *sig) { - return functions->GetStaticFieldID(this,clazz,name,sig); - } - jobject GetStaticObjectField(jclass clazz, jfieldID fieldID) { - return functions->GetStaticObjectField(this,clazz,fieldID); - } - jboolean GetStaticBooleanField(jclass clazz, jfieldID fieldID) { - return functions->GetStaticBooleanField(this,clazz,fieldID); - } - jbyte GetStaticByteField(jclass clazz, jfieldID fieldID) { - return functions->GetStaticByteField(this,clazz,fieldID); - } - jchar GetStaticCharField(jclass clazz, jfieldID fieldID) { - return functions->GetStaticCharField(this,clazz,fieldID); - } - jshort GetStaticShortField(jclass clazz, jfieldID fieldID) { - return functions->GetStaticShortField(this,clazz,fieldID); - } - jint GetStaticIntField(jclass clazz, jfieldID fieldID) { - return functions->GetStaticIntField(this,clazz,fieldID); - } - jlong GetStaticLongField(jclass clazz, jfieldID fieldID) { - return functions->GetStaticLongField(this,clazz,fieldID); - } - jfloat GetStaticFloatField(jclass clazz, jfieldID fieldID) { - return functions->GetStaticFloatField(this,clazz,fieldID); - } - jdouble GetStaticDoubleField(jclass clazz, jfieldID fieldID) { - return functions->GetStaticDoubleField(this,clazz,fieldID); - } - - void SetStaticObjectField(jclass clazz, jfieldID fieldID, - jobject value) { - functions->SetStaticObjectField(this,clazz,fieldID,value); - } - void SetStaticBooleanField(jclass clazz, jfieldID fieldID, - jboolean value) { - functions->SetStaticBooleanField(this,clazz,fieldID,value); - } - void SetStaticByteField(jclass clazz, jfieldID fieldID, - jbyte value) { - functions->SetStaticByteField(this,clazz,fieldID,value); - } - void SetStaticCharField(jclass clazz, jfieldID fieldID, - jchar value) { - functions->SetStaticCharField(this,clazz,fieldID,value); - } - void SetStaticShortField(jclass clazz, jfieldID fieldID, - jshort value) { - functions->SetStaticShortField(this,clazz,fieldID,value); - } - void SetStaticIntField(jclass clazz, jfieldID fieldID, - jint value) { - functions->SetStaticIntField(this,clazz,fieldID,value); - } - void SetStaticLongField(jclass clazz, jfieldID fieldID, - jlong value) { - functions->SetStaticLongField(this,clazz,fieldID,value); - } - void SetStaticFloatField(jclass clazz, jfieldID fieldID, - jfloat value) { - functions->SetStaticFloatField(this,clazz,fieldID,value); - } - void SetStaticDoubleField(jclass clazz, jfieldID fieldID, - jdouble value) { - functions->SetStaticDoubleField(this,clazz,fieldID,value); - } - - jstring NewString(const jchar *unicode, jsize len) { - return functions->NewString(this,unicode,len); - } - jsize GetStringLength(jstring str) { - return functions->GetStringLength(this,str); - } - const jchar *GetStringChars(jstring str, jboolean *isCopy) { - return functions->GetStringChars(this,str,isCopy); - } - void ReleaseStringChars(jstring str, const jchar *chars) { - functions->ReleaseStringChars(this,str,chars); - } - - jstring NewStringUTF(const char *utf) { - return functions->NewStringUTF(this,utf); - } - jsize GetStringUTFLength(jstring str) { - return functions->GetStringUTFLength(this,str); - } - jlong GetStringUTFLengthAsLong(jstring str) { - return functions->GetStringUTFLengthAsLong(this,str); - } - const char* GetStringUTFChars(jstring str, jboolean *isCopy) { - return functions->GetStringUTFChars(this,str,isCopy); - } - void ReleaseStringUTFChars(jstring str, const char* chars) { - functions->ReleaseStringUTFChars(this,str,chars); - } - - jsize GetArrayLength(jarray array) { - return functions->GetArrayLength(this,array); - } - - jobjectArray NewObjectArray(jsize len, jclass clazz, - jobject init) { - return functions->NewObjectArray(this,len,clazz,init); - } - jobject GetObjectArrayElement(jobjectArray array, jsize index) { - return functions->GetObjectArrayElement(this,array,index); - } - void SetObjectArrayElement(jobjectArray array, jsize index, - jobject val) { - functions->SetObjectArrayElement(this,array,index,val); - } - - jbooleanArray NewBooleanArray(jsize len) { - return functions->NewBooleanArray(this,len); - } - jbyteArray NewByteArray(jsize len) { - return functions->NewByteArray(this,len); - } - jcharArray NewCharArray(jsize len) { - return functions->NewCharArray(this,len); - } - jshortArray NewShortArray(jsize len) { - return functions->NewShortArray(this,len); - } - jintArray NewIntArray(jsize len) { - return functions->NewIntArray(this,len); - } - jlongArray NewLongArray(jsize len) { - return functions->NewLongArray(this,len); - } - jfloatArray NewFloatArray(jsize len) { - return functions->NewFloatArray(this,len); - } - jdoubleArray NewDoubleArray(jsize len) { - return functions->NewDoubleArray(this,len); - } - - jboolean * GetBooleanArrayElements(jbooleanArray array, jboolean *isCopy) { - return functions->GetBooleanArrayElements(this,array,isCopy); - } - jbyte * GetByteArrayElements(jbyteArray array, jboolean *isCopy) { - return functions->GetByteArrayElements(this,array,isCopy); - } - jchar * GetCharArrayElements(jcharArray array, jboolean *isCopy) { - return functions->GetCharArrayElements(this,array,isCopy); - } - jshort * GetShortArrayElements(jshortArray array, jboolean *isCopy) { - return functions->GetShortArrayElements(this,array,isCopy); - } - jint * GetIntArrayElements(jintArray array, jboolean *isCopy) { - return functions->GetIntArrayElements(this,array,isCopy); - } - jlong * GetLongArrayElements(jlongArray array, jboolean *isCopy) { - return functions->GetLongArrayElements(this,array,isCopy); - } - jfloat * GetFloatArrayElements(jfloatArray array, jboolean *isCopy) { - return functions->GetFloatArrayElements(this,array,isCopy); - } - jdouble * GetDoubleArrayElements(jdoubleArray array, jboolean *isCopy) { - return functions->GetDoubleArrayElements(this,array,isCopy); - } - - void ReleaseBooleanArrayElements(jbooleanArray array, - jboolean *elems, - jint mode) { - functions->ReleaseBooleanArrayElements(this,array,elems,mode); - } - void ReleaseByteArrayElements(jbyteArray array, - jbyte *elems, - jint mode) { - functions->ReleaseByteArrayElements(this,array,elems,mode); - } - void ReleaseCharArrayElements(jcharArray array, - jchar *elems, - jint mode) { - functions->ReleaseCharArrayElements(this,array,elems,mode); - } - void ReleaseShortArrayElements(jshortArray array, - jshort *elems, - jint mode) { - functions->ReleaseShortArrayElements(this,array,elems,mode); - } - void ReleaseIntArrayElements(jintArray array, - jint *elems, - jint mode) { - functions->ReleaseIntArrayElements(this,array,elems,mode); - } - void ReleaseLongArrayElements(jlongArray array, - jlong *elems, - jint mode) { - functions->ReleaseLongArrayElements(this,array,elems,mode); - } - void ReleaseFloatArrayElements(jfloatArray array, - jfloat *elems, - jint mode) { - functions->ReleaseFloatArrayElements(this,array,elems,mode); - } - void ReleaseDoubleArrayElements(jdoubleArray array, - jdouble *elems, - jint mode) { - functions->ReleaseDoubleArrayElements(this,array,elems,mode); - } - - void GetBooleanArrayRegion(jbooleanArray array, - jsize start, jsize len, jboolean *buf) { - functions->GetBooleanArrayRegion(this,array,start,len,buf); - } - void GetByteArrayRegion(jbyteArray array, - jsize start, jsize len, jbyte *buf) { - functions->GetByteArrayRegion(this,array,start,len,buf); - } - void GetCharArrayRegion(jcharArray array, - jsize start, jsize len, jchar *buf) { - functions->GetCharArrayRegion(this,array,start,len,buf); - } - void GetShortArrayRegion(jshortArray array, - jsize start, jsize len, jshort *buf) { - functions->GetShortArrayRegion(this,array,start,len,buf); - } - void GetIntArrayRegion(jintArray array, - jsize start, jsize len, jint *buf) { - functions->GetIntArrayRegion(this,array,start,len,buf); - } - void GetLongArrayRegion(jlongArray array, - jsize start, jsize len, jlong *buf) { - functions->GetLongArrayRegion(this,array,start,len,buf); - } - void GetFloatArrayRegion(jfloatArray array, - jsize start, jsize len, jfloat *buf) { - functions->GetFloatArrayRegion(this,array,start,len,buf); - } - void GetDoubleArrayRegion(jdoubleArray array, - jsize start, jsize len, jdouble *buf) { - functions->GetDoubleArrayRegion(this,array,start,len,buf); - } - - void SetBooleanArrayRegion(jbooleanArray array, jsize start, jsize len, - const jboolean *buf) { - functions->SetBooleanArrayRegion(this,array,start,len,buf); - } - void SetByteArrayRegion(jbyteArray array, jsize start, jsize len, - const jbyte *buf) { - functions->SetByteArrayRegion(this,array,start,len,buf); - } - void SetCharArrayRegion(jcharArray array, jsize start, jsize len, - const jchar *buf) { - functions->SetCharArrayRegion(this,array,start,len,buf); - } - void SetShortArrayRegion(jshortArray array, jsize start, jsize len, - const jshort *buf) { - functions->SetShortArrayRegion(this,array,start,len,buf); - } - void SetIntArrayRegion(jintArray array, jsize start, jsize len, - const jint *buf) { - functions->SetIntArrayRegion(this,array,start,len,buf); - } - void SetLongArrayRegion(jlongArray array, jsize start, jsize len, - const jlong *buf) { - functions->SetLongArrayRegion(this,array,start,len,buf); - } - void SetFloatArrayRegion(jfloatArray array, jsize start, jsize len, - const jfloat *buf) { - functions->SetFloatArrayRegion(this,array,start,len,buf); - } - void SetDoubleArrayRegion(jdoubleArray array, jsize start, jsize len, - const jdouble *buf) { - functions->SetDoubleArrayRegion(this,array,start,len,buf); - } - - jint RegisterNatives(jclass clazz, const JNINativeMethod *methods, - jint nMethods) { - return functions->RegisterNatives(this,clazz,methods,nMethods); - } - jint UnregisterNatives(jclass clazz) { - return functions->UnregisterNatives(this,clazz); - } - - jint MonitorEnter(jobject obj) { - return functions->MonitorEnter(this,obj); - } - jint MonitorExit(jobject obj) { - return functions->MonitorExit(this,obj); - } - - jint GetJavaVM(JavaVM **vm) { - return functions->GetJavaVM(this,vm); - } - - void GetStringRegion(jstring str, jsize start, jsize len, jchar *buf) { - functions->GetStringRegion(this,str,start,len,buf); - } - void GetStringUTFRegion(jstring str, jsize start, jsize len, char *buf) { - functions->GetStringUTFRegion(this,str,start,len,buf); - } - - void * GetPrimitiveArrayCritical(jarray array, jboolean *isCopy) { - return functions->GetPrimitiveArrayCritical(this,array,isCopy); - } - void ReleasePrimitiveArrayCritical(jarray array, void *carray, jint mode) { - functions->ReleasePrimitiveArrayCritical(this,array,carray,mode); - } - - const jchar * GetStringCritical(jstring string, jboolean *isCopy) { - return functions->GetStringCritical(this,string,isCopy); - } - void ReleaseStringCritical(jstring string, const jchar *cstring) { - functions->ReleaseStringCritical(this,string,cstring); - } - - jweak NewWeakGlobalRef(jobject obj) { - return functions->NewWeakGlobalRef(this,obj); - } - void DeleteWeakGlobalRef(jweak ref) { - functions->DeleteWeakGlobalRef(this,ref); - } - - jboolean ExceptionCheck() { - return functions->ExceptionCheck(this); - } - - jobject NewDirectByteBuffer(void* address, jlong capacity) { - return functions->NewDirectByteBuffer(this, address, capacity); - } - void* GetDirectBufferAddress(jobject buf) { - return functions->GetDirectBufferAddress(this, buf); - } - jlong GetDirectBufferCapacity(jobject buf) { - return functions->GetDirectBufferCapacity(this, buf); - } - jobjectRefType GetObjectRefType(jobject obj) { - return functions->GetObjectRefType(this, obj); - } - - /* Module Features */ - - jobject GetModule(jclass clazz) { - return functions->GetModule(this, clazz); - } - - /* Virtual threads */ - - jboolean IsVirtualThread(jobject obj) { - return functions->IsVirtualThread(this, obj); - } - -#endif /* __cplusplus */ -}; - -/* - * optionString may be any option accepted by the JVM, or one of the - * following: - * - * -D= Set a system property. - * -verbose[:class|gc|jni] Enable verbose output, comma-separated. E.g. - * "-verbose:class" or "-verbose:gc,class" - * Standard names include: gc, class, and jni. - * All nonstandard (VM-specific) names must begin - * with "X". - * vfprintf extraInfo is a pointer to the vfprintf hook. - * exit extraInfo is a pointer to the exit hook. - * abort extraInfo is a pointer to the abort hook. - */ -typedef struct JavaVMOption { - char *optionString; - void *extraInfo; -} JavaVMOption; - -typedef struct JavaVMInitArgs { - jint version; - - jint nOptions; - JavaVMOption *options; - jboolean ignoreUnrecognized; -} JavaVMInitArgs; - -typedef struct JavaVMAttachArgs { - jint version; - - char *name; - jobject group; -} JavaVMAttachArgs; - -/* These will be VM-specific. */ - -#define JDK1_2 -#define JDK1_4 - -/* End VM-specific. */ - -struct JNIInvokeInterface_ { - void *reserved0; - void *reserved1; - void *reserved2; - - jint (JNICALL *DestroyJavaVM)(JavaVM *vm); - - jint (JNICALL *AttachCurrentThread)(JavaVM *vm, void **penv, void *args); - - jint (JNICALL *DetachCurrentThread)(JavaVM *vm); - - jint (JNICALL *GetEnv)(JavaVM *vm, void **penv, jint version); - - jint (JNICALL *AttachCurrentThreadAsDaemon)(JavaVM *vm, void **penv, void *args); -}; - -struct JavaVM_ { - const struct JNIInvokeInterface_ *functions; -#ifdef __cplusplus - - jint DestroyJavaVM() { - return functions->DestroyJavaVM(this); - } - jint AttachCurrentThread(void **penv, void *args) { - return functions->AttachCurrentThread(this, penv, args); - } - jint DetachCurrentThread() { - return functions->DetachCurrentThread(this); - } - - jint GetEnv(void **penv, jint version) { - return functions->GetEnv(this, penv, version); - } - jint AttachCurrentThreadAsDaemon(void **penv, void *args) { - return functions->AttachCurrentThreadAsDaemon(this, penv, args); - } -#endif -}; - -#ifdef _JNI_IMPLEMENTATION_ -#define _JNI_IMPORT_OR_EXPORT_ JNIEXPORT -#else -#define _JNI_IMPORT_OR_EXPORT_ JNIIMPORT -#endif -_JNI_IMPORT_OR_EXPORT_ jint JNICALL -JNI_GetDefaultJavaVMInitArgs(void *args); - -_JNI_IMPORT_OR_EXPORT_ jint JNICALL -JNI_CreateJavaVM(JavaVM **pvm, void **penv, void *args); - -_JNI_IMPORT_OR_EXPORT_ jint JNICALL -JNI_GetCreatedJavaVMs(JavaVM **, jsize, jsize *); - -/* Defined by native libraries. */ -JNIEXPORT jint JNICALL -JNI_OnLoad(JavaVM *vm, void *reserved); - -JNIEXPORT void JNICALL -JNI_OnUnload(JavaVM *vm, void *reserved); - -#define JNI_VERSION_1_1 0x00010001 -#define JNI_VERSION_1_2 0x00010002 -#define JNI_VERSION_1_4 0x00010004 -#define JNI_VERSION_1_6 0x00010006 -#define JNI_VERSION_1_8 0x00010008 -#define JNI_VERSION_9 0x00090000 -#define JNI_VERSION_10 0x000a0000 -#define JNI_VERSION_19 0x00130000 -#define JNI_VERSION_20 0x00140000 -#define JNI_VERSION_21 0x00150000 -#define JNI_VERSION_24 0x00180000 - -#ifdef __cplusplus -} /* extern "C" */ -#endif /* __cplusplus */ - -#endif /* !_JAVASOFT_JNI_H_ */ diff --git a/core/esmf-tree-sitter-turtle/src/main/c/include/linux/jawt_md.h b/core/esmf-tree-sitter-turtle/src/main/c/include/linux/jawt_md.h deleted file mode 100644 index 2ba3a8e83..000000000 --- a/core/esmf-tree-sitter-turtle/src/main/c/include/linux/jawt_md.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (c) 1999, 2001, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#ifndef _JAVASOFT_JAWT_MD_H_ -#define _JAVASOFT_JAWT_MD_H_ - -#include -#include -#include "jawt.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/* - * X11-specific declarations for AWT native interface. - * See notes in jawt.h for an example of use. - */ -typedef struct jawt_X11DrawingSurfaceInfo { - Drawable drawable; - Display* display; - VisualID visualID; - Colormap colormapID; - int depth; - /* - * Since 1.4 - * Returns a pixel value from a set of RGB values. - * This is useful for paletted color (256 color) modes. - */ - int (JNICALL *GetAWTColor)(JAWT_DrawingSurface* ds, - int r, int g, int b); -} JAWT_X11DrawingSurfaceInfo; - -#ifdef __cplusplus -} -#endif - -#endif /* !_JAVASOFT_JAWT_MD_H_ */ diff --git a/core/esmf-tree-sitter-turtle/src/main/c/include/linux/jni_md.h b/core/esmf-tree-sitter-turtle/src/main/c/include/linux/jni_md.h deleted file mode 100644 index b4ed87e0c..000000000 --- a/core/esmf-tree-sitter-turtle/src/main/c/include/linux/jni_md.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (c) 1996, 2024, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#ifndef _JAVASOFT_JNI_MD_H_ -#define _JAVASOFT_JNI_MD_H_ - -#ifndef __has_attribute - #define __has_attribute(x) 0 -#endif - -#ifndef JNIEXPORT - #if (defined(__GNUC__) && ((__GNUC__ > 4) || (__GNUC__ == 4) && (__GNUC_MINOR__ > 2))) || __has_attribute(visibility) - #ifdef ARM - #define JNIEXPORT __attribute__((externally_visible,visibility("default"))) - #else - #define JNIEXPORT __attribute__((visibility("default"))) - #endif - #else - #define JNIEXPORT - #endif -#endif - -#if (defined(__GNUC__) && ((__GNUC__ > 4) || (__GNUC__ == 4) && (__GNUC_MINOR__ > 2))) || __has_attribute(visibility) - #ifdef ARM - #define JNIIMPORT __attribute__((externally_visible,visibility("default"))) - #else - #define JNIIMPORT __attribute__((visibility("default"))) - #endif -#else - #define JNIIMPORT -#endif - -typedef int jint; -#ifdef _LP64 -typedef long jlong; -#else -typedef long long jlong; -#endif - -typedef signed char jbyte; - -#endif /* !_JAVASOFT_JNI_MD_H_ */ diff --git a/core/esmf-tree-sitter-turtle/src/main/c/include/macos/jawt_md.h b/core/esmf-tree-sitter-turtle/src/main/c/include/macos/jawt_md.h deleted file mode 100644 index 94a13c9ab..000000000 --- a/core/esmf-tree-sitter-turtle/src/main/c/include/macos/jawt_md.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#ifndef _JAVASOFT_JAWT_MD_H_ -#define _JAVASOFT_JAWT_MD_H_ - -#include "jawt.h" - -#ifdef __OBJC__ -#import -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -/* - * MacOS specific declarations for AWT native interface. - * See notes in jawt.h for an example of use. - */ - -/* - * When calling JAWT_GetAWT with a JAWT version less than 1.7, you must pass this - * flag or you will not be able to get a valid drawing surface and JAWT_GetAWT will - * return false. This is to maintain compatibility with applications that used the - * interface with Java 6 which had multiple rendering models. This flag is not necessary - * when JAWT version 1.7 or greater is used as this is the only supported rendering mode. - * - * Example: - * JAWT awt; - * awt.version = JAWT_VERSION_1_4 | JAWT_MACOSX_USE_CALAYER; - * jboolean success = JAWT_GetAWT(env, &awt); - */ -#define JAWT_MACOSX_USE_CALAYER 0x80000000 - -/* - * When the native Cocoa toolkit is in use, the pointer stored in - * JAWT_DrawingSurfaceInfo->platformInfo points to a NSObject that conforms to the - * JAWT_SurfaceLayers protocol. Setting the layer property of this object will cause the - * specified layer to be overlaid on the Components rectangle. If the window the - * Component belongs to has a CALayer attached to it, this layer will be accessible via - * the windowLayer property. - */ -#ifdef __OBJC__ -@protocol JAWT_SurfaceLayers -@property (readwrite, retain) CALayer *layer; -@property (readonly) CALayer *windowLayer; -@end -#endif - -#ifdef __cplusplus -} -#endif - -#endif /* !_JAVASOFT_JAWT_MD_H_ */ diff --git a/core/esmf-tree-sitter-turtle/src/main/c/include/macos/jni_md.h b/core/esmf-tree-sitter-turtle/src/main/c/include/macos/jni_md.h deleted file mode 100644 index b4ed87e0c..000000000 --- a/core/esmf-tree-sitter-turtle/src/main/c/include/macos/jni_md.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (c) 1996, 2024, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#ifndef _JAVASOFT_JNI_MD_H_ -#define _JAVASOFT_JNI_MD_H_ - -#ifndef __has_attribute - #define __has_attribute(x) 0 -#endif - -#ifndef JNIEXPORT - #if (defined(__GNUC__) && ((__GNUC__ > 4) || (__GNUC__ == 4) && (__GNUC_MINOR__ > 2))) || __has_attribute(visibility) - #ifdef ARM - #define JNIEXPORT __attribute__((externally_visible,visibility("default"))) - #else - #define JNIEXPORT __attribute__((visibility("default"))) - #endif - #else - #define JNIEXPORT - #endif -#endif - -#if (defined(__GNUC__) && ((__GNUC__ > 4) || (__GNUC__ == 4) && (__GNUC_MINOR__ > 2))) || __has_attribute(visibility) - #ifdef ARM - #define JNIIMPORT __attribute__((externally_visible,visibility("default"))) - #else - #define JNIIMPORT __attribute__((visibility("default"))) - #endif -#else - #define JNIIMPORT -#endif - -typedef int jint; -#ifdef _LP64 -typedef long jlong; -#else -typedef long long jlong; -#endif - -typedef signed char jbyte; - -#endif /* !_JAVASOFT_JNI_MD_H_ */ diff --git a/core/esmf-tree-sitter-turtle/src/main/c/include/windows/bridge/AccessBridgeCallbacks.h b/core/esmf-tree-sitter-turtle/src/main/c/include/windows/bridge/AccessBridgeCallbacks.h deleted file mode 100755 index 3f907d5f9..000000000 --- a/core/esmf-tree-sitter-turtle/src/main/c/include/windows/bridge/AccessBridgeCallbacks.h +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - * Header file defining callback typedefs for Windows routines - * which are called from Java (responding to events, etc.). - */ - -#ifndef __AccessBridgeCallbacks_H__ -#define __AccessBridgeCallbacks_H__ - -#include -#include "AccessBridgePackages.h" - -#ifdef __cplusplus -extern "C" { -#endif - -typedef void (*AccessBridge_PropertyChangeFP) (long vmID, JOBJECT64 event, JOBJECT64 source, - wchar_t *property, wchar_t *oldValue, wchar_t *newValue); - -typedef void (*AccessBridge_JavaShutdownFP) (long vmID); -typedef void (*AccessBridge_JavaShutdownFP) (long vmID); - -typedef void (*AccessBridge_FocusGainedFP) (long vmID, JOBJECT64 event, JOBJECT64 source); -typedef void (*AccessBridge_FocusLostFP) (long vmID, JOBJECT64 event, JOBJECT64 source); - -typedef void (*AccessBridge_CaretUpdateFP) (long vmID, JOBJECT64 event, JOBJECT64 source); - -typedef void (*AccessBridge_MouseClickedFP) (long vmID, JOBJECT64 event, JOBJECT64 source); -typedef void (*AccessBridge_MouseEnteredFP) (long vmID, JOBJECT64 event, JOBJECT64 source); -typedef void (*AccessBridge_MouseExitedFP) (long vmID, JOBJECT64 event, JOBJECT64 source); -typedef void (*AccessBridge_MousePressedFP) (long vmID, JOBJECT64 event, JOBJECT64 source); -typedef void (*AccessBridge_MouseReleasedFP) (long vmID, JOBJECT64 event, JOBJECT64 source); - -typedef void (*AccessBridge_MenuCanceledFP) (long vmID, JOBJECT64 event, JOBJECT64 source); -typedef void (*AccessBridge_MenuDeselectedFP) (long vmID, JOBJECT64 event, JOBJECT64 source); -typedef void (*AccessBridge_MenuSelectedFP) (long vmID, JOBJECT64 event, JOBJECT64 source); -typedef void (*AccessBridge_PopupMenuCanceledFP) (long vmID, JOBJECT64 event, JOBJECT64 source); -typedef void (*AccessBridge_PopupMenuWillBecomeInvisibleFP) (long vmID, JOBJECT64 event, JOBJECT64 source); -typedef void (*AccessBridge_PopupMenuWillBecomeVisibleFP) (long vmID, JOBJECT64 event, JOBJECT64 source); - -typedef void (*AccessBridge_PropertyNameChangeFP) (long vmID, JOBJECT64 event, JOBJECT64 source, - wchar_t *oldName, wchar_t *newName); -typedef void (*AccessBridge_PropertyDescriptionChangeFP) (long vmID, JOBJECT64 event, JOBJECT64 source, - wchar_t *oldDescription, wchar_t *newDescription); -typedef void (*AccessBridge_PropertyStateChangeFP) (long vmID, JOBJECT64 event, JOBJECT64 source, - wchar_t *oldState, wchar_t *newState); -typedef void (*AccessBridge_PropertyValueChangeFP) (long vmID, JOBJECT64 event, JOBJECT64 source, - wchar_t *oldValue, wchar_t *newValue); -typedef void (*AccessBridge_PropertySelectionChangeFP) (long vmID, JOBJECT64 event, JOBJECT64 source); -typedef void (*AccessBridge_PropertyTextChangeFP) (long vmID, JOBJECT64 event, JOBJECT64 source); -typedef void (*AccessBridge_PropertyCaretChangeFP) (long vmID, JOBJECT64 event, JOBJECT64 source, - int oldPosition, int newPosition); -typedef void (*AccessBridge_PropertyVisibleDataChangeFP) (long vmID, JOBJECT64 event, JOBJECT64 source); -typedef void (*AccessBridge_PropertyChildChangeFP) (long vmID, JOBJECT64 event, JOBJECT64 source, - JOBJECT64 oldChild, JOBJECT64 newChild); -typedef void (*AccessBridge_PropertyActiveDescendentChangeFP) (long vmID, JOBJECT64 event, - JOBJECT64 source, - JOBJECT64 oldActiveDescendent, - JOBJECT64 newActiveDescendent); - -typedef void (*AccessBridge_PropertyTableModelChangeFP) (long vmID, JOBJECT64 event, JOBJECT64 src, - wchar_t *oldValue, wchar_t *newValue); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/core/esmf-tree-sitter-turtle/src/main/c/include/windows/bridge/AccessBridgeCalls.h b/core/esmf-tree-sitter-turtle/src/main/c/include/windows/bridge/AccessBridgeCalls.h deleted file mode 100755 index b2d95f643..000000000 --- a/core/esmf-tree-sitter-turtle/src/main/c/include/windows/bridge/AccessBridgeCalls.h +++ /dev/null @@ -1,724 +0,0 @@ -/* - * Copyright (c) 2005, 2022, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* Note: In addition to this header file AccessBridgeCalls.c must be compiled and - * linked to your application. AccessBridgeCalls.c implements the Java Access - * Bridge API and also hides the complexities associated with interfacing to the - * associated Java Access Bridge DLL which is installed when Java is installed. - * - * AccessBridgeCalls.c is available for download from the OpenJDK repository using - * the following link: - * - * https://git.openjdk.org/jdk17/blob/master/src/jdk.accessibility/windows/native/bridge/AccessBridgeCalls.c - * - * Also note that the API is used in the jaccessinspector and jaccesswalker tools. - * The source for those tools is available in the OpenJDK repository at these links: - * - * https://git.openjdk.org/jdk17/blob/master/src/jdk.accessibility/windows/native/jaccessinspector/jaccessinspector.cpp - * https://git.openjdk.org/jdk17/blob/master/src/jdk.accessibility/windows/native/jaccesswalker/jaccesswalker.cpp - * - * - */ - -/* - * Wrapper functions around calls to the AccessBridge DLL - */ - -#include -#include -#include "AccessBridgeCallbacks.h" -#include "AccessBridgePackages.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define null NULL - - typedef JOBJECT64 AccessibleContext; - typedef JOBJECT64 AccessibleText; - typedef JOBJECT64 AccessibleValue; - typedef JOBJECT64 AccessibleSelection; - typedef JOBJECT64 Java_Object; - typedef JOBJECT64 PropertyChangeEvent; - typedef JOBJECT64 FocusEvent; - typedef JOBJECT64 CaretEvent; - typedef JOBJECT64 MouseEvent; - typedef JOBJECT64 MenuEvent; - typedef JOBJECT64 AccessibleTable; - typedef JOBJECT64 AccessibleHyperlink; - typedef JOBJECT64 AccessibleHypertext; - - - typedef void (*Windows_runFP) (); - - typedef void (*SetPropertyChangeFP) (AccessBridge_PropertyChangeFP fp); - - typedef void (*SetJavaShutdownFP) (AccessBridge_JavaShutdownFP fp); - typedef void (*SetFocusGainedFP) (AccessBridge_FocusGainedFP fp); - typedef void (*SetFocusLostFP) (AccessBridge_FocusLostFP fp); - - typedef void (*SetCaretUpdateFP) (AccessBridge_CaretUpdateFP fp); - - typedef void (*SetMouseClickedFP) (AccessBridge_MouseClickedFP fp); - typedef void (*SetMouseEnteredFP) (AccessBridge_MouseEnteredFP fp); - typedef void (*SetMouseExitedFP) (AccessBridge_MouseExitedFP fp); - typedef void (*SetMousePressedFP) (AccessBridge_MousePressedFP fp); - typedef void (*SetMouseReleasedFP) (AccessBridge_MouseReleasedFP fp); - - typedef void (*SetMenuCanceledFP) (AccessBridge_MenuCanceledFP fp); - typedef void (*SetMenuDeselectedFP) (AccessBridge_MenuDeselectedFP fp); - typedef void (*SetMenuSelectedFP) (AccessBridge_MenuSelectedFP fp); - typedef void (*SetPopupMenuCanceledFP) (AccessBridge_PopupMenuCanceledFP fp); - typedef void (*SetPopupMenuWillBecomeInvisibleFP) (AccessBridge_PopupMenuWillBecomeInvisibleFP fp); - typedef void (*SetPopupMenuWillBecomeVisibleFP) (AccessBridge_PopupMenuWillBecomeVisibleFP fp); - - typedef void (*SetPropertyNameChangeFP) (AccessBridge_PropertyNameChangeFP fp); - typedef void (*SetPropertyDescriptionChangeFP) (AccessBridge_PropertyDescriptionChangeFP fp); - typedef void (*SetPropertyStateChangeFP) (AccessBridge_PropertyStateChangeFP fp); - typedef void (*SetPropertyValueChangeFP) (AccessBridge_PropertyValueChangeFP fp); - typedef void (*SetPropertySelectionChangeFP) (AccessBridge_PropertySelectionChangeFP fp); - typedef void (*SetPropertyTextChangeFP) (AccessBridge_PropertyTextChangeFP fp); - typedef void (*SetPropertyCaretChangeFP) (AccessBridge_PropertyCaretChangeFP fp); - typedef void (*SetPropertyVisibleDataChangeFP) (AccessBridge_PropertyVisibleDataChangeFP fp); - typedef void (*SetPropertyChildChangeFP) (AccessBridge_PropertyChildChangeFP fp); - typedef void (*SetPropertyActiveDescendentChangeFP) (AccessBridge_PropertyActiveDescendentChangeFP fp); - - typedef void (*SetPropertyTableModelChangeFP) (AccessBridge_PropertyTableModelChangeFP fp); - - typedef void (*ReleaseJavaObjectFP) (long vmID, Java_Object object); - - typedef BOOL (*GetVersionInfoFP) (long vmID, AccessBridgeVersionInfo *info); - - typedef BOOL (*IsJavaWindowFP) (HWND window); - typedef BOOL (*IsSameObjectFP) (long vmID, JOBJECT64 obj1, JOBJECT64 obj2); - typedef BOOL (*GetAccessibleContextFromHWNDFP) (HWND window, long *vmID, AccessibleContext *ac); - typedef HWND (*getHWNDFromAccessibleContextFP) (long vmID, AccessibleContext ac); - - typedef BOOL (*GetAccessibleContextAtFP) (long vmID, AccessibleContext acParent, - jint x, jint y, AccessibleContext *ac); - typedef BOOL (*GetAccessibleContextWithFocusFP) (HWND window, long *vmID, AccessibleContext *ac); - typedef BOOL (*GetAccessibleContextInfoFP) (long vmID, AccessibleContext ac, AccessibleContextInfo *info); - typedef AccessibleContext (*GetAccessibleChildFromContextFP) (long vmID, AccessibleContext ac, jint i); - typedef AccessibleContext (*GetAccessibleParentFromContextFP) (long vmID, AccessibleContext ac); - - /* begin AccessibleTable */ - typedef BOOL (*getAccessibleTableInfoFP) (long vmID, AccessibleContext ac, AccessibleTableInfo *tableInfo); - typedef BOOL (*getAccessibleTableCellInfoFP) (long vmID, AccessibleTable accessibleTable, - jint row, jint column, AccessibleTableCellInfo *tableCellInfo); - - typedef BOOL (*getAccessibleTableRowHeaderFP) (long vmID, AccessibleContext acParent, AccessibleTableInfo *tableInfo); - typedef BOOL (*getAccessibleTableColumnHeaderFP) (long vmID, AccessibleContext acParent, AccessibleTableInfo *tableInfo); - - typedef AccessibleContext (*getAccessibleTableRowDescriptionFP) (long vmID, AccessibleContext acParent, jint row); - typedef AccessibleContext (*getAccessibleTableColumnDescriptionFP) (long vmID, AccessibleContext acParent, jint column); - - typedef jint (*getAccessibleTableRowSelectionCountFP) (long vmID, AccessibleTable table); - typedef BOOL (*isAccessibleTableRowSelectedFP) (long vmID, AccessibleTable table, jint row); - typedef BOOL (*getAccessibleTableRowSelectionsFP) (long vmID, AccessibleTable table, jint count, - jint *selections); - - typedef jint (*getAccessibleTableColumnSelectionCountFP) (long vmID, AccessibleTable table); - typedef BOOL (*isAccessibleTableColumnSelectedFP) (long vmID, AccessibleTable table, jint column); - typedef BOOL (*getAccessibleTableColumnSelectionsFP) (long vmID, AccessibleTable table, jint count, - jint *selections); - - typedef jint (*getAccessibleTableRowFP) (long vmID, AccessibleTable table, jint index); - typedef jint (*getAccessibleTableColumnFP) (long vmID, AccessibleTable table, jint index); - typedef jint (*getAccessibleTableIndexFP) (long vmID, AccessibleTable table, jint row, jint column); - /* end AccessibleTable */ - - /* AccessibleRelationSet */ - typedef BOOL (*getAccessibleRelationSetFP) (long vmID, AccessibleContext accessibleContext, - AccessibleRelationSetInfo *relationSetInfo); - - /* AccessibleHypertext */ - typedef BOOL (*getAccessibleHypertextFP)(long vmID, AccessibleContext accessibleContext, - AccessibleHypertextInfo *hypertextInfo); - - typedef BOOL (*activateAccessibleHyperlinkFP)(long vmID, AccessibleContext accessibleContext, - AccessibleHyperlink accessibleHyperlink); - - typedef jint (*getAccessibleHyperlinkCountFP)(const long vmID, - const AccessibleContext accessibleContext); - - typedef BOOL (*getAccessibleHypertextExtFP) (const long vmID, - const AccessibleContext accessibleContext, - const jint nStartIndex, - AccessibleHypertextInfo *hypertextInfo); - - typedef jint (*getAccessibleHypertextLinkIndexFP)(const long vmID, - const AccessibleHypertext hypertext, - const jint nIndex); - - typedef BOOL (*getAccessibleHyperlinkFP)(const long vmID, - const AccessibleHypertext hypertext, - const jint nIndex, - AccessibleHyperlinkInfo *hyperlinkInfo); - - - /* Accessible KeyBindings, Icons and Actions */ - typedef BOOL (*getAccessibleKeyBindingsFP)(long vmID, AccessibleContext accessibleContext, - AccessibleKeyBindings *keyBindings); - - typedef BOOL (*getAccessibleIconsFP)(long vmID, AccessibleContext accessibleContext, - AccessibleIcons *icons); - - typedef BOOL (*getAccessibleActionsFP)(long vmID, AccessibleContext accessibleContext, - AccessibleActions *actions); - - typedef BOOL (*doAccessibleActionsFP)(long vmID, AccessibleContext accessibleContext, - AccessibleActionsToDo *actionsToDo, jint *failure); - - - /* AccessibleText */ - - typedef BOOL (*GetAccessibleTextInfoFP) (long vmID, AccessibleText at, AccessibleTextInfo *textInfo, jint x, jint y); - typedef BOOL (*GetAccessibleTextItemsFP) (long vmID, AccessibleText at, AccessibleTextItemsInfo *textItems, jint index); - typedef BOOL (*GetAccessibleTextSelectionInfoFP) (long vmID, AccessibleText at, AccessibleTextSelectionInfo *textSelection); - typedef BOOL (*GetAccessibleTextAttributesFP) (long vmID, AccessibleText at, jint index, AccessibleTextAttributesInfo *attributes); - typedef BOOL (*GetAccessibleTextRectFP) (long vmID, AccessibleText at, AccessibleTextRectInfo *rectInfo, jint index); - typedef BOOL (*GetAccessibleTextLineBoundsFP) (long vmID, AccessibleText at, jint index, jint *startIndex, jint *endIndex); - typedef BOOL (*GetAccessibleTextRangeFP) (long vmID, AccessibleText at, jint start, jint end, wchar_t *text, short len); - - typedef BOOL (*GetCurrentAccessibleValueFromContextFP) (long vmID, AccessibleValue av, wchar_t *value, short len); - typedef BOOL (*GetMaximumAccessibleValueFromContextFP) (long vmID, AccessibleValue av, wchar_t *value, short len); - typedef BOOL (*GetMinimumAccessibleValueFromContextFP) (long vmID, AccessibleValue av, wchar_t *value, short len); - - typedef void (*AddAccessibleSelectionFromContextFP) (long vmID, AccessibleSelection as, int i); - typedef void (*ClearAccessibleSelectionFromContextFP) (long vmID, AccessibleSelection as); - typedef JOBJECT64 (*GetAccessibleSelectionFromContextFP) (long vmID, AccessibleSelection as, int i); - typedef int (*GetAccessibleSelectionCountFromContextFP) (long vmID, AccessibleSelection as); - typedef BOOL (*IsAccessibleChildSelectedFromContextFP) (long vmID, AccessibleSelection as, int i); - typedef void (*RemoveAccessibleSelectionFromContextFP) (long vmID, AccessibleSelection as, int i); - typedef void (*SelectAllAccessibleSelectionFromContextFP) (long vmID, AccessibleSelection as); - - /* Utility methods */ - - typedef BOOL (*setTextContentsFP) (const long vmID, const AccessibleContext ac, const wchar_t *text); - typedef AccessibleContext (*getParentWithRoleFP) (const long vmID, const AccessibleContext ac, const wchar_t *role); - typedef AccessibleContext (*getParentWithRoleElseRootFP) (const long vmID, const AccessibleContext ac, const wchar_t *role); - typedef AccessibleContext (*getTopLevelObjectFP) (const long vmID, const AccessibleContext ac); - typedef int (*getObjectDepthFP) (const long vmID, const AccessibleContext ac); - typedef AccessibleContext (*getActiveDescendentFP) (const long vmID, const AccessibleContext ac); - - - typedef BOOL (*getVirtualAccessibleNameFP) (const long vmID, const AccessibleContext accessibleContext, - wchar_t *name, int len); - - typedef BOOL (*requestFocusFP) (const long vmID, const AccessibleContext accessibleContext); - - typedef BOOL (*selectTextRangeFP) (const long vmID, const AccessibleContext accessibleContext, - const int startIndex, const int endIndex); - - typedef BOOL (*getTextAttributesInRangeFP) (const long vmID, const AccessibleContext accessibleContext, - const int startIndex, const int endIndex, - AccessibleTextAttributesInfo *attributes, short *len); - - typedef int (*getVisibleChildrenCountFP) (const long vmID, const AccessibleContext accessibleContext); - - typedef BOOL (*getVisibleChildrenFP) (const long vmID, const AccessibleContext accessibleContext, - const int startIndex, VisibleChildrenInfo *children); - - typedef BOOL (*setCaretPositionFP) (const long vmID, const AccessibleContext accessibleContext, const int position); - - typedef BOOL (*getCaretLocationFP) (long vmID, AccessibleContext ac, AccessibleTextRectInfo *rectInfo, jint index); - - typedef int (*getEventsWaitingFP) (); - - typedef struct AccessBridgeFPsTag { - Windows_runFP Windows_run; - - SetPropertyChangeFP SetPropertyChange; - - SetJavaShutdownFP SetJavaShutdown; - SetFocusGainedFP SetFocusGained; - SetFocusLostFP SetFocusLost; - - SetCaretUpdateFP SetCaretUpdate; - - SetMouseClickedFP SetMouseClicked; - SetMouseEnteredFP SetMouseEntered; - SetMouseExitedFP SetMouseExited; - SetMousePressedFP SetMousePressed; - SetMouseReleasedFP SetMouseReleased; - - SetMenuCanceledFP SetMenuCanceled; - SetMenuDeselectedFP SetMenuDeselected; - SetMenuSelectedFP SetMenuSelected; - SetPopupMenuCanceledFP SetPopupMenuCanceled; - SetPopupMenuWillBecomeInvisibleFP SetPopupMenuWillBecomeInvisible; - SetPopupMenuWillBecomeVisibleFP SetPopupMenuWillBecomeVisible; - - SetPropertyNameChangeFP SetPropertyNameChange; - SetPropertyDescriptionChangeFP SetPropertyDescriptionChange; - SetPropertyStateChangeFP SetPropertyStateChange; - SetPropertyValueChangeFP SetPropertyValueChange; - SetPropertySelectionChangeFP SetPropertySelectionChange; - SetPropertyTextChangeFP SetPropertyTextChange; - SetPropertyCaretChangeFP SetPropertyCaretChange; - SetPropertyVisibleDataChangeFP SetPropertyVisibleDataChange; - SetPropertyChildChangeFP SetPropertyChildChange; - SetPropertyActiveDescendentChangeFP SetPropertyActiveDescendentChange; - - SetPropertyTableModelChangeFP SetPropertyTableModelChange; - - ReleaseJavaObjectFP ReleaseJavaObject; - GetVersionInfoFP GetVersionInfo; - - IsJavaWindowFP IsJavaWindow; - IsSameObjectFP IsSameObject; - GetAccessibleContextFromHWNDFP GetAccessibleContextFromHWND; - getHWNDFromAccessibleContextFP getHWNDFromAccessibleContext; - - GetAccessibleContextAtFP GetAccessibleContextAt; - GetAccessibleContextWithFocusFP GetAccessibleContextWithFocus; - GetAccessibleContextInfoFP GetAccessibleContextInfo; - GetAccessibleChildFromContextFP GetAccessibleChildFromContext; - GetAccessibleParentFromContextFP GetAccessibleParentFromContext; - - getAccessibleTableInfoFP getAccessibleTableInfo; - getAccessibleTableCellInfoFP getAccessibleTableCellInfo; - - getAccessibleTableRowHeaderFP getAccessibleTableRowHeader; - getAccessibleTableColumnHeaderFP getAccessibleTableColumnHeader; - - getAccessibleTableRowDescriptionFP getAccessibleTableRowDescription; - getAccessibleTableColumnDescriptionFP getAccessibleTableColumnDescription; - - getAccessibleTableRowSelectionCountFP getAccessibleTableRowSelectionCount; - isAccessibleTableRowSelectedFP isAccessibleTableRowSelected; - getAccessibleTableRowSelectionsFP getAccessibleTableRowSelections; - - getAccessibleTableColumnSelectionCountFP getAccessibleTableColumnSelectionCount; - isAccessibleTableColumnSelectedFP isAccessibleTableColumnSelected; - getAccessibleTableColumnSelectionsFP getAccessibleTableColumnSelections; - - getAccessibleTableRowFP getAccessibleTableRow; - getAccessibleTableColumnFP getAccessibleTableColumn; - getAccessibleTableIndexFP getAccessibleTableIndex; - - getAccessibleRelationSetFP getAccessibleRelationSet; - - getAccessibleHypertextFP getAccessibleHypertext; - activateAccessibleHyperlinkFP activateAccessibleHyperlink; - getAccessibleHyperlinkCountFP getAccessibleHyperlinkCount; - getAccessibleHypertextExtFP getAccessibleHypertextExt; - getAccessibleHypertextLinkIndexFP getAccessibleHypertextLinkIndex; - getAccessibleHyperlinkFP getAccessibleHyperlink; - - getAccessibleKeyBindingsFP getAccessibleKeyBindings; - getAccessibleIconsFP getAccessibleIcons; - getAccessibleActionsFP getAccessibleActions; - doAccessibleActionsFP doAccessibleActions; - - GetAccessibleTextInfoFP GetAccessibleTextInfo; - GetAccessibleTextItemsFP GetAccessibleTextItems; - GetAccessibleTextSelectionInfoFP GetAccessibleTextSelectionInfo; - GetAccessibleTextAttributesFP GetAccessibleTextAttributes; - GetAccessibleTextRectFP GetAccessibleTextRect; - GetAccessibleTextLineBoundsFP GetAccessibleTextLineBounds; - GetAccessibleTextRangeFP GetAccessibleTextRange; - - GetCurrentAccessibleValueFromContextFP GetCurrentAccessibleValueFromContext; - GetMaximumAccessibleValueFromContextFP GetMaximumAccessibleValueFromContext; - GetMinimumAccessibleValueFromContextFP GetMinimumAccessibleValueFromContext; - - AddAccessibleSelectionFromContextFP AddAccessibleSelectionFromContext; - ClearAccessibleSelectionFromContextFP ClearAccessibleSelectionFromContext; - GetAccessibleSelectionFromContextFP GetAccessibleSelectionFromContext; - GetAccessibleSelectionCountFromContextFP GetAccessibleSelectionCountFromContext; - IsAccessibleChildSelectedFromContextFP IsAccessibleChildSelectedFromContext; - RemoveAccessibleSelectionFromContextFP RemoveAccessibleSelectionFromContext; - SelectAllAccessibleSelectionFromContextFP SelectAllAccessibleSelectionFromContext; - - setTextContentsFP setTextContents; - getParentWithRoleFP getParentWithRole; - getTopLevelObjectFP getTopLevelObject; - getParentWithRoleElseRootFP getParentWithRoleElseRoot; - getObjectDepthFP getObjectDepth; - getActiveDescendentFP getActiveDescendent; - - getVirtualAccessibleNameFP getVirtualAccessibleName; - requestFocusFP requestFocus; - selectTextRangeFP selectTextRange; - getTextAttributesInRangeFP getTextAttributesInRange; - getVisibleChildrenCountFP getVisibleChildrenCount; - getVisibleChildrenFP getVisibleChildren; - setCaretPositionFP setCaretPosition; - getCaretLocationFP getCaretLocation; - - getEventsWaitingFP getEventsWaiting; - - } AccessBridgeFPs; - - - /** - * Initialize the world - */ - BOOL initializeAccessBridge(); - BOOL shutdownAccessBridge(); - - /** - * Window routines - */ - BOOL IsJavaWindow(HWND window); - - // Returns the virtual machine ID and AccessibleContext for a top-level window - BOOL GetAccessibleContextFromHWND(HWND target, long *vmID, AccessibleContext *ac); - - // Returns the HWND from the AccessibleContext of a top-level window - HWND getHWNDFromAccessibleContext(long vmID, AccessibleContext ac); - - - /** - * Event handling routines - */ - void SetJavaShutdown(AccessBridge_JavaShutdownFP fp); - void SetFocusGained(AccessBridge_FocusGainedFP fp); - void SetFocusLost(AccessBridge_FocusLostFP fp); - - void SetCaretUpdate(AccessBridge_CaretUpdateFP fp); - - void SetMouseClicked(AccessBridge_MouseClickedFP fp); - void SetMouseEntered(AccessBridge_MouseEnteredFP fp); - void SetMouseExited(AccessBridge_MouseExitedFP fp); - void SetMousePressed(AccessBridge_MousePressedFP fp); - void SetMouseReleased(AccessBridge_MouseReleasedFP fp); - - void SetMenuCanceled(AccessBridge_MenuCanceledFP fp); - void SetMenuDeselected(AccessBridge_MenuDeselectedFP fp); - void SetMenuSelected(AccessBridge_MenuSelectedFP fp); - void SetPopupMenuCanceled(AccessBridge_PopupMenuCanceledFP fp); - void SetPopupMenuWillBecomeInvisible(AccessBridge_PopupMenuWillBecomeInvisibleFP fp); - void SetPopupMenuWillBecomeVisible(AccessBridge_PopupMenuWillBecomeVisibleFP fp); - - void SetPropertyNameChange(AccessBridge_PropertyNameChangeFP fp); - void SetPropertyDescriptionChange(AccessBridge_PropertyDescriptionChangeFP fp); - void SetPropertyStateChange(AccessBridge_PropertyStateChangeFP fp); - void SetPropertyValueChange(AccessBridge_PropertyValueChangeFP fp); - void SetPropertySelectionChange(AccessBridge_PropertySelectionChangeFP fp); - void SetPropertyTextChange(AccessBridge_PropertyTextChangeFP fp); - void SetPropertyCaretChange(AccessBridge_PropertyCaretChangeFP fp); - void SetPropertyVisibleDataChange(AccessBridge_PropertyVisibleDataChangeFP fp); - void SetPropertyChildChange(AccessBridge_PropertyChildChangeFP fp); - void SetPropertyActiveDescendentChange(AccessBridge_PropertyActiveDescendentChangeFP fp); - - void SetPropertyTableModelChange(AccessBridge_PropertyTableModelChangeFP fp); - - - /** - * General routines - */ - void ReleaseJavaObject(long vmID, Java_Object object); - BOOL GetVersionInfo(long vmID, AccessBridgeVersionInfo *info); - HWND GetHWNDFromAccessibleContext(long vmID, JOBJECT64 accesibleContext); - - /** - * Accessible Context routines - */ - BOOL GetAccessibleContextAt(long vmID, AccessibleContext acParent, - jint x, jint y, AccessibleContext *ac); - BOOL GetAccessibleContextWithFocus(HWND window, long *vmID, AccessibleContext *ac); - BOOL GetAccessibleContextInfo(long vmID, AccessibleContext ac, AccessibleContextInfo *info); - AccessibleContext GetAccessibleChildFromContext(long vmID, AccessibleContext ac, jint index); - AccessibleContext GetAccessibleParentFromContext(long vmID, AccessibleContext ac); - - /** - * Accessible Text routines - */ - BOOL GetAccessibleTextInfo(long vmID, AccessibleText at, AccessibleTextInfo *textInfo, jint x, jint y); - BOOL GetAccessibleTextItems(long vmID, AccessibleText at, AccessibleTextItemsInfo *textItems, jint index); - BOOL GetAccessibleTextSelectionInfo(long vmID, AccessibleText at, AccessibleTextSelectionInfo *textSelection); - BOOL GetAccessibleTextAttributes(long vmID, AccessibleText at, jint index, AccessibleTextAttributesInfo *attributes); - BOOL GetAccessibleTextRect(long vmID, AccessibleText at, AccessibleTextRectInfo *rectInfo, jint index); - BOOL GetAccessibleTextLineBounds(long vmID, AccessibleText at, jint index, jint *startIndex, jint *endIndex); - BOOL GetAccessibleTextRange(long vmID, AccessibleText at, jint start, jint end, wchar_t *text, short len); - - /* begin AccessibleTable routines */ - BOOL getAccessibleTableInfo(long vmID, AccessibleContext acParent, AccessibleTableInfo *tableInfo); - - BOOL getAccessibleTableCellInfo(long vmID, AccessibleTable accessibleTable, jint row, jint column, - AccessibleTableCellInfo *tableCellInfo); - - BOOL getAccessibleTableRowHeader(long vmID, AccessibleContext acParent, AccessibleTableInfo *tableInfo); - BOOL getAccessibleTableColumnHeader(long vmID, AccessibleContext acParent, AccessibleTableInfo *tableInfo); - - AccessibleContext getAccessibleTableRowDescription(long vmID, AccessibleContext acParent, jint row); - AccessibleContext getAccessibleTableColumnDescription(long vmID, AccessibleContext acParent, jint column); - - jint getAccessibleTableRowSelectionCount(long vmID, AccessibleTable table); - BOOL isAccessibleTableRowSelected(long vmID, AccessibleTable table, jint row); - BOOL getAccessibleTableRowSelections(long vmID, AccessibleTable table, jint count, jint *selections); - - jint getAccessibleTableColumnSelectionCount(long vmID, AccessibleTable table); - BOOL isAccessibleTableColumnSelected(long vmID, AccessibleTable table, jint column); - BOOL getAccessibleTableColumnSelections(long vmID, AccessibleTable table, jint count, jint *selections); - - jint getAccessibleTableRow(long vmID, AccessibleTable table, jint index); - jint getAccessibleTableColumn(long vmID, AccessibleTable table, jint index); - jint getAccessibleTableIndex(long vmID, AccessibleTable table, jint row, jint column); - /* end AccessibleTable */ - - /* ----- AccessibleRelationSet routines */ - BOOL getAccessibleRelationSet(long vmID, AccessibleContext accessibleContext, - AccessibleRelationSetInfo *relationSetInfo); - - /* ----- AccessibleHypertext routines */ - - /* - * Returns hypertext information associated with a component. - */ - BOOL getAccessibleHypertext(long vmID, AccessibleContext accessibleContext, - AccessibleHypertextInfo *hypertextInfo); - - /* - * Requests that a hyperlink be activated. - */ - BOOL activateAccessibleHyperlink(long vmID, AccessibleContext accessibleContext, - AccessibleHyperlink accessibleHyperlink); - - /* - * Returns the number of hyperlinks in a component - * Maps to AccessibleHypertext.getLinkCount. - * Returns -1 on error. - */ - jint getAccessibleHyperlinkCount(const long vmID, - const AccessibleHypertext hypertext); - - /* - * This method is used to iterate through the hyperlinks in a component. It - * returns hypertext information for a component starting at hyperlink index - * nStartIndex. No more than MAX_HYPERLINKS AccessibleHypertextInfo objects will - * be returned for each call to this method. - * Returns FALSE on error. - */ - BOOL getAccessibleHypertextExt(const long vmID, - const AccessibleContext accessibleContext, - const jint nStartIndex, - /* OUT */ AccessibleHypertextInfo *hypertextInfo); - - /* - * Returns the index into an array of hyperlinks that is associated with - * a character index in document; maps to AccessibleHypertext.getLinkIndex - * Returns -1 on error. - */ - jint getAccessibleHypertextLinkIndex(const long vmID, - const AccessibleHypertext hypertext, - const jint nIndex); - - /* - * Returns the nth hyperlink in a document - * Maps to AccessibleHypertext.getLink. - * Returns FALSE on error - */ - BOOL getAccessibleHyperlink(const long vmID, - const AccessibleHypertext hypertext, - const jint nIndex, - /* OUT */ AccessibleHyperlinkInfo *hyperlinkInfo); - - /* Accessible KeyBindings, Icons and Actions */ - - /* - * Returns a list of key bindings associated with a component. - */ - BOOL getAccessibleKeyBindings(long vmID, AccessibleContext accessibleContext, - AccessibleKeyBindings *keyBindings); - - /* - * Returns a list of icons associate with a component. - */ - BOOL getAccessibleIcons(long vmID, AccessibleContext accessibleContext, - AccessibleIcons *icons); - - /* - * Returns a list of actions that a component can perform. - */ - BOOL getAccessibleActions(long vmID, AccessibleContext accessibleContext, - AccessibleActions *actions); - - /* - * Request that a list of AccessibleActions be performed by a component. - * Returns TRUE if all actions are performed. Returns FALSE - * when the first requested action fails in which case "failure" - * contains the index of the action that failed. - */ - BOOL doAccessibleActions(long vmID, AccessibleContext accessibleContext, - AccessibleActionsToDo *actionsToDo, jint *failure); - - - - /* Additional utility methods */ - - /* - * Returns whether two object references refer to the same object. - */ - BOOL IsSameObject(long vmID, JOBJECT64 obj1, JOBJECT64 obj2); - - /** - * Sets editable text contents. The AccessibleContext must implement AccessibleEditableText and - * be editable. The maximum text length that can be set is MAX_STRING_SIZE - 1. - * Returns whether successful - */ - BOOL setTextContents (const long vmID, const AccessibleContext accessibleContext, const wchar_t *text); - - /** - * Returns the Accessible Context with the specified role that is the - * ancestor of a given object. The role is one of the role strings - * defined in AccessBridgePackages.h - * If there is no ancestor object that has the specified role, - * returns (AccessibleContext)0. - */ - AccessibleContext getParentWithRole (const long vmID, const AccessibleContext accessibleContext, - const wchar_t *role); - - /** - * Returns the Accessible Context with the specified role that is the - * ancestor of a given object. The role is one of the role strings - * defined in AccessBridgePackages.h. If an object with the specified - * role does not exist, returns the top level object for the Java Window. - * Returns (AccessibleContext)0 on error. - */ - AccessibleContext getParentWithRoleElseRoot (const long vmID, const AccessibleContext accessibleContext, - const wchar_t *role); - - /** - * Returns the Accessible Context for the top level object in - * a Java Window. This is same Accessible Context that is obtained - * from GetAccessibleContextFromHWND for that window. Returns - * (AccessibleContext)0 on error. - */ - AccessibleContext getTopLevelObject (const long vmID, const AccessibleContext accessibleContext); - - /** - * Returns how deep in the object hierarchy a given object is. - * The top most object in the object hierarchy has an object depth of 0. - * Returns -1 on error. - */ - int getObjectDepth (const long vmID, const AccessibleContext accessibleContext); - - /** - * Returns the Accessible Context of the current ActiveDescendent of an object. - * This method assumes the ActiveDescendent is the component that is currently - * selected in a container object. - * Returns (AccessibleContext)0 on error or if there is no selection. - */ - AccessibleContext getActiveDescendent (const long vmID, const AccessibleContext accessibleContext); - - /** - * Accessible Value routines - */ - BOOL GetCurrentAccessibleValueFromContext(long vmID, AccessibleValue av, wchar_t *value, short len); - BOOL GetMaximumAccessibleValueFromContext(long vmID, AccessibleValue av, wchar_t *value, short len); - BOOL GetMinimumAccessibleValueFromContext(long vmID, AccessibleValue av, wchar_t *value, short len); - - /** - * Accessible Selection routines - */ - void AddAccessibleSelectionFromContext(long vmID, AccessibleSelection as, int i); - void ClearAccessibleSelectionFromContext(long vmID, AccessibleSelection as); - JOBJECT64 GetAccessibleSelectionFromContext(long vmID, AccessibleSelection as, int i); - int GetAccessibleSelectionCountFromContext(long vmID, AccessibleSelection as); - BOOL IsAccessibleChildSelectedFromContext(long vmID, AccessibleSelection as, int i); - void RemoveAccessibleSelectionFromContext(long vmID, AccessibleSelection as, int i); - void SelectAllAccessibleSelectionFromContext(long vmID, AccessibleSelection as); - - /** - * Additional methods for Teton - */ - - /** - * Gets the AccessibleName for a component based upon the JAWS algorithm. Returns - * whether successful. - * - * Bug ID 4916682 - Implement JAWS AccessibleName policy - */ - BOOL getVirtualAccessibleName(const long vmID, const AccessibleContext accessibleContext, - wchar_t *name, int len); - - /** - * Request focus for a component. Returns whether successful. - * - * Bug ID 4944757 - requestFocus method needed - */ - BOOL requestFocus(const long vmID, const AccessibleContext accessibleContext); - - /** - * Selects text between two indices. Selection includes the text at the start index - * and the text at the end index. Returns whether successful. - * - * Bug ID 4944758 - selectTextRange method needed - */ - BOOL selectTextRange(const long vmID, const AccessibleContext accessibleContext, const int startIndex, - const int endIndex); - - /** - * Get text attributes between two indices. The attribute list includes the text at the - * start index and the text at the end index. Returns whether successful; - * - * Bug ID 4944761 - getTextAttributes between two indices method needed - */ - BOOL getTextAttributesInRange(const long vmID, const AccessibleContext accessibleContext, - const int startIndex, const int endIndex, - AccessibleTextAttributesInfo *attributes, short *len); - - /** - * Returns the number of visible children of a component. Returns -1 on error. - * - * Bug ID 4944762- getVisibleChildren for list-like components needed - */ - int getVisibleChildrenCount(const long vmID, const AccessibleContext accessibleContext); - - /** - * Gets the visible children of an AccessibleContext. Returns whether successful. - * - * Bug ID 4944762- getVisibleChildren for list-like components needed - */ - BOOL getVisibleChildren(const long vmID, const AccessibleContext accessibleContext, - const int startIndex, - VisibleChildrenInfo *visibleChildrenInfo); - - /** - * Set the caret to a text position. Returns whether successful. - * - * Bug ID 4944770 - setCaretPosition method needed - */ - BOOL setCaretPosition(const long vmID, const AccessibleContext accessibleContext, - const int position); - - /** - * Gets the text caret location - */ - BOOL getCaretLocation(long vmID, AccessibleContext ac, - AccessibleTextRectInfo *rectInfo, jint index); - - /** - * Gets the number of events waiting to fire - */ - int getEventsWaiting(); - -#ifdef __cplusplus -} -#endif diff --git a/core/esmf-tree-sitter-turtle/src/main/c/include/windows/bridge/AccessBridgePackages.h b/core/esmf-tree-sitter-turtle/src/main/c/include/windows/bridge/AccessBridgePackages.h deleted file mode 100755 index 232cab4b2..000000000 --- a/core/esmf-tree-sitter-turtle/src/main/c/include/windows/bridge/AccessBridgePackages.h +++ /dev/null @@ -1,2217 +0,0 @@ -/* - * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - * Header file for packages of paramaters passed between Java Accessibility - * and native Assistive Technologies - */ - -#ifndef __AccessBridgePackages_H__ -#define __AccessBridgePackages_H__ - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#ifdef ACCESSBRIDGE_ARCH_LEGACY -typedef jobject JOBJECT64; -typedef HWND ABHWND64; -#define ABHandleToLong -#define ABLongToHandle -#else -typedef jlong JOBJECT64; -typedef long ABHWND64; -#define ABHandleToLong HandleToLong -#define ABLongToHandle LongToHandle -#endif - -#define MAX_BUFFER_SIZE 10240 -#define MAX_STRING_SIZE 1024 -#define SHORT_STRING_SIZE 256 - - // object types - typedef JOBJECT64 AccessibleContext; - typedef JOBJECT64 AccessibleText; - typedef JOBJECT64 AccessibleValue; - typedef JOBJECT64 AccessibleSelection; - typedef JOBJECT64 Java_Object; - typedef JOBJECT64 PropertyChangeEvent; - typedef JOBJECT64 FocusEvent; - typedef JOBJECT64 CaretEvent; - typedef JOBJECT64 MouseEvent; - typedef JOBJECT64 MenuEvent; - typedef JOBJECT64 AccessibleTable; - typedef JOBJECT64 AccessibleHyperlink; - typedef JOBJECT64 AccessibleHypertext; - - /** - ****************************************************** - * Java event types - ****************************************************** - */ - -#define cPropertyChangeEvent (jlong) 1 // 1 -#define cFocusGainedEvent (jlong) 2 // 2 -#define cFocusLostEvent (jlong) 4 // 4 -#define cCaretUpdateEvent (jlong) 8 // 8 -#define cMouseClickedEvent (jlong) 16 // 10 -#define cMouseEnteredEvent (jlong) 32 // 20 -#define cMouseExitedEvent (jlong) 64 // 40 -#define cMousePressedEvent (jlong) 128 // 80 -#define cMouseReleasedEvent (jlong) 256 // 100 -#define cMenuCanceledEvent (jlong) 512 // 200 -#define cMenuDeselectedEvent (jlong) 1024 // 400 -#define cMenuSelectedEvent (jlong) 2048 // 800 -#define cPopupMenuCanceledEvent (jlong) 4096 // 1000 -#define cPopupMenuWillBecomeInvisibleEvent (jlong) 8192 // 2000 -#define cPopupMenuWillBecomeVisibleEvent (jlong) 16384 // 4000 -#define cJavaShutdownEvent (jlong) 32768 // 8000 - - /** - ****************************************************** - * Accessible Roles - * Defines all AccessibleRoles in Local.US - ****************************************************** - */ - - /** - * Object is used to alert the user about something. - */ -#define ACCESSIBLE_ALERT L"alert" - - /** - * The header for a column of data. - */ -#define ACCESSIBLE_COLUMN_HEADER L"column header" - - /** - * Object that can be drawn into and is used to trap - * events. - * see ACCESSIBLE_FRAME - * see ACCESSIBLE_GLASS_PANE - * see ACCESSIBLE_LAYERED_PANE - */ -#define ACCESSIBLE_CANVAS L"canvas" - - /** - * A list of choices the user can select from. Also optionally - * allows the user to enter a choice of their own. - */ -#define ACCESSIBLE_COMBO_BOX L"combo box" - - /** - * An iconified internal frame in a DESKTOP_PANE. - * see ACCESSIBLE_DESKTOP_PANE - * see ACCESSIBLE_INTERNAL_FRAME - */ -#define ACCESSIBLE_DESKTOP_ICON L"desktop icon" - - /** - * A frame-like object that is clipped by a desktop pane. The - * desktop pane, internal frame, and desktop icon objects are - * often used to create multiple document interfaces within an - * application. - * see ACCESSIBLE_DESKTOP_ICON - * see ACCESSIBLE_DESKTOP_PANE - * see ACCESSIBLE_FRAME - */ -#define ACCESSIBLE_INTERNAL_FRAME L"internal frame" - - /** - * A pane that supports internal frames and - * iconified versions of those internal frames. - * see ACCESSIBLE_DESKTOP_ICON - * see ACCESSIBLE_INTERNAL_FRAME - */ -#define ACCESSIBLE_DESKTOP_PANE L"desktop pane" - - /** - * A specialized pane whose primary use is inside a DIALOG - * see ACCESSIBLE_DIALOG - */ -#define ACCESSIBLE_OPTION_PANE L"option pane" - - /** - * A top level window with no title or border. - * see ACCESSIBLE_FRAME - * see ACCESSIBLE_DIALOG - */ -#define ACCESSIBLE_WINDOW L"window" - - /** - * A top level window with a title bar, border, menu bar, etc. It is - * often used as the primary window for an application. - * see ACCESSIBLE_DIALOG - * see ACCESSIBLE_CANVAS - * see ACCESSIBLE_WINDOW - */ -#define ACCESSIBLE_FRAME L"frame" - - /** - * A top level window with title bar and a border. A dialog is similar - * to a frame, but it has fewer properties and is often used as a - * secondary window for an application. - * see ACCESSIBLE_FRAME - * see ACCESSIBLE_WINDOW - */ -#define ACCESSIBLE_DIALOG L"dialog" - - /** - * A specialized dialog that lets the user choose a color. - */ -#define ACCESSIBLE_COLOR_CHOOSER L"color chooser" - - - /** - * A pane that allows the user to navigate through - * and select the contents of a directory. May be used - * by a file chooser. - * see ACCESSIBLE_FILE_CHOOSER - */ -#define ACCESSIBLE_DIRECTORY_PANE L"directory pane" - - /** - * A specialized dialog that displays the files in the directory - * and lets the user select a file, browse a different directory, - * or specify a filename. May use the directory pane to show the - * contents of a directory. - * see ACCESSIBLE_DIRECTORY_PANE - */ -#define ACCESSIBLE_FILE_CHOOSER L"file chooser" - - /** - * An object that fills up space in a user interface. It is often - * used in interfaces to tweak the spacing between components, - * but serves no other purpose. - */ -#define ACCESSIBLE_FILLER L"filler" - - /** - * A hypertext anchor - */ -#define ACCESSIBLE_HYPERLINK L"hyperlink" - - /** - * A small fixed size picture, typically used to decorate components. - */ -#define ACCESSIBLE_ICON L"icon" - - /** - * An object used to present an icon or short string in an interface. - */ -#define ACCESSIBLE_LABEL L"label" - - /** - * A specialized pane that has a glass pane and a layered pane as its - * children. - * see ACCESSIBLE_GLASS_PANE - * see ACCESSIBLE_LAYERED_PANE - */ -#define ACCESSIBLE_ROOT_PANE L"root pane" - - /** - * A pane that is guaranteed to be painted on top - * of all panes beneath it. - * see ACCESSIBLE_ROOT_PANE - * see ACCESSIBLE_CANVAS - */ -#define ACCESSIBLE_GLASS_PANE L"glass pane" - - /** - * A specialized pane that allows its children to be drawn in layers, - * providing a form of stacking order. This is usually the pane that - * holds the menu bar as well as the pane that contains most of the - * visual components in a window. - * see ACCESSIBLE_GLASS_PANE - * see ACCESSIBLE_ROOT_PANE - */ -#define ACCESSIBLE_LAYERED_PANE L"layered pane" - - /** - * An object that presents a list of objects to the user and allows the - * user to select one or more of them. A list is usually contained - * within a scroll pane. - * see ACCESSIBLE_SCROLL_PANE - * see ACCESSIBLE_LIST_ITEM - */ -#define ACCESSIBLE_LIST L"list" - - /** - * An object that presents an element in a list. A list is usually - * contained within a scroll pane. - * see ACCESSIBLE_SCROLL_PANE - * see ACCESSIBLE_LIST - */ -#define ACCESSIBLE_LIST_ITEM L"list item" - - /** - * An object usually drawn at the top of the primary dialog box of - * an application that contains a list of menus the user can choose - * from. For example, a menu bar might contain menus for "File," - * "Edit," and "Help." - * see ACCESSIBLE_MENU - * see ACCESSIBLE_POPUP_MENU - * see ACCESSIBLE_LAYERED_PANE - */ -#define ACCESSIBLE_MENU_BAR L"menu bar" - - /** - * A temporary window that is usually used to offer the user a - * list of choices, and then hides when the user selects one of - * those choices. - * see ACCESSIBLE_MENU - * see ACCESSIBLE_MENU_ITEM - */ -#define ACCESSIBLE_POPUP_MENU L"popup menu" - - /** - * An object usually found inside a menu bar that contains a list - * of actions the user can choose from. A menu can have any object - * as its children, but most often they are menu items, other menus, - * or rudimentary objects such as radio buttons, check boxes, or - * separators. For example, an application may have an "Edit" menu - * that contains menu items for "Cut" and "Paste." - * see ACCESSIBLE_MENU_BAR - * see ACCESSIBLE_MENU_ITEM - * see ACCESSIBLE_SEPARATOR - * see ACCESSIBLE_RADIO_BUTTON - * see ACCESSIBLE_CHECK_BOX - * see ACCESSIBLE_POPUP_MENU - */ -#define ACCESSIBLE_MENU L"menu" - - /** - * An object usually contained in a menu that presents an action - * the user can choose. For example, the "Cut" menu item in an - * "Edit" menu would be an action the user can select to cut the - * selected area of text in a document. - * see ACCESSIBLE_MENU_BAR - * see ACCESSIBLE_SEPARATOR - * see ACCESSIBLE_POPUP_MENU - */ -#define ACCESSIBLE_MENU_ITEM L"menu item" - - /** - * An object usually contained in a menu to provide a visual - * and logical separation of the contents in a menu. For example, - * the "File" menu of an application might contain menu items for - * "Open," "Close," and "Exit," and will place a separator between - * "Close" and "Exit" menu items. - * see ACCESSIBLE_MENU - * see ACCESSIBLE_MENU_ITEM - */ -#define ACCESSIBLE_SEPARATOR L"separator" - - /** - * An object that presents a series of panels (or page tabs), one at a - * time, through some mechanism provided by the object. The most common - * mechanism is a list of tabs at the top of the panel. The children of - * a page tab list are all page tabs. - * see ACCESSIBLE_PAGE_TAB - */ -#define ACCESSIBLE_PAGE_TAB_LIST L"page tab list" - - /** - * An object that is a child of a page tab list. Its sole child is - * the panel that is to be presented to the user when the user - * selects the page tab from the list of tabs in the page tab list. - * see ACCESSIBLE_PAGE_TAB_LIST - */ -#define ACCESSIBLE_PAGE_TAB L"page tab" - - /** - * A generic container that is often used to group objects. - */ -#define ACCESSIBLE_PANEL L"panel" - - /** - * An object used to indicate how much of a task has been completed. - */ -#define ACCESSIBLE_PROGRESS_BAR L"progress bar" - - /** - * A text object used for passwords, or other places where the - * text contents is not shown visibly to the user - */ -#define ACCESSIBLE_PASSWORD_TEXT L"password text" - - /** - * An object the user can manipulate to tell the application to do - * something. - * see ACCESSIBLE_CHECK_BOX - * see ACCESSIBLE_TOGGLE_BUTTON - * see ACCESSIBLE_RADIO_BUTTON - */ -#define ACCESSIBLE_PUSH_BUTTON L"push button" - - /** - * A specialized push button that can be checked or unchecked, but - * does not provide a separate indicator for the current state. - * see ACCESSIBLE_PUSH_BUTTON - * see ACCESSIBLE_CHECK_BOX - * see ACCESSIBLE_RADIO_BUTTON - */ -#define ACCESSIBLE_TOGGLE_BUTTON L"toggle button" - - /** - * A choice that can be checked or unchecked and provides a - * separate indicator for the current state. - * see ACCESSIBLE_PUSH_BUTTON - * see ACCESSIBLE_TOGGLE_BUTTON - * see ACCESSIBLE_RADIO_BUTTON - */ -#define ACCESSIBLE_CHECK_BOX L"check box" - - /** - * A specialized check box that will cause other radio buttons in the - * same group to become unchecked when this one is checked. - * see ACCESSIBLE_PUSH_BUTTON - * see ACCESSIBLE_TOGGLE_BUTTON - * see ACCESSIBLE_CHECK_BOX - */ -#define ACCESSIBLE_RADIO_BUTTON L"radio button" - - /** - * The header for a row of data. - */ -#define ACCESSIBLE_ROW_HEADER L"row header" - - /** - * An object that allows a user to incrementally view a large amount - * of information. Its children can include scroll bars and a viewport. - * see ACCESSIBLE_SCROLL_BAR - * see ACCESSIBLE_VIEWPORT - */ -#define ACCESSIBLE_SCROLL_PANE L"scroll pane" - - /** - * An object usually used to allow a user to incrementally view a - * large amount of data. Usually used only by a scroll pane. - * see ACCESSIBLE_SCROLL_PANE - */ -#define ACCESSIBLE_SCROLL_BAR L"scroll bar" - - /** - * An object usually used in a scroll pane. It represents the portion - * of the entire data that the user can see. As the user manipulates - * the scroll bars, the contents of the viewport can change. - * see ACCESSIBLE_SCROLL_PANE - */ -#define ACCESSIBLE_VIEWPORT L"viewport" - - /** - * An object that allows the user to select from a bounded range. For - * example, a slider might be used to select a number between 0 and 100. - */ -#define ACCESSIBLE_SLIDER L"slider" - - /** - * A specialized panel that presents two other panels at the same time. - * Between the two panels is a divider the user can manipulate to make - * one panel larger and the other panel smaller. - */ -#define ACCESSIBLE_SPLIT_PANE L"split pane" - - /** - * An object used to present information in terms of rows and columns. - * An example might include a spreadsheet application. - */ -#define ACCESSIBLE_TABLE L"table" - - /** - * An object that presents text to the user. The text is usually - * editable by the user as opposed to a label. - * see ACCESSIBLE_LABEL - */ -#define ACCESSIBLE_TEXT L"text" - - /** - * An object used to present hierarchical information to the user. - * The individual nodes in the tree can be collapsed and expanded - * to provide selective disclosure of the tree's contents. - */ -#define ACCESSIBLE_TREE L"tree" - - /** - * A bar or palette usually composed of push buttons or toggle buttons. - * It is often used to provide the most frequently used functions for an - * application. - */ -#define ACCESSIBLE_TOOL_BAR L"tool bar" - - /** - * An object that provides information about another object. The - * accessibleDescription property of the tool tip is often displayed - * to the user in a small L"help bubble" when the user causes the - * mouse to hover over the object associated with the tool tip. - */ -#define ACCESSIBLE_TOOL_TIP L"tool tip" - - /** - * An AWT component, but nothing else is known about it. - * see ACCESSIBLE_SWING_COMPONENT - * see ACCESSIBLE_UNKNOWN - */ -#define ACCESSIBLE_AWT_COMPONENT L"awt component" - - /** - * A Swing component, but nothing else is known about it. - * see ACCESSIBLE_AWT_COMPONENT - * see ACCESSIBLE_UNKNOWN - */ -#define ACCESSIBLE_SWING_COMPONENT L"swing component" - - /** - * The object contains some Accessible information, but its role is - * not known. - * see ACCESSIBLE_AWT_COMPONENT - * see ACCESSIBLE_SWING_COMPONENT - */ -#define ACCESSIBLE_UNKNOWN L"unknown" - - /** - * A STATUS_BAR is an simple component that can contain - * multiple labels of status information to the user. - */ -#define ACCESSIBLE_STATUS_BAR L"status bar" - - /** - * A DATE_EDITOR is a component that allows users to edit - * java.util.Date and java.util.Time objects - */ -#define ACCESSIBLE_DATE_EDITOR L"date editor" - - /** - * A SPIN_BOX is a simple spinner component and its main use - * is for simple numbers. - */ -#define ACCESSIBLE_SPIN_BOX L"spin box" - - /** - * A FONT_CHOOSER is a component that lets the user pick various - * attributes for fonts. - */ -#define ACCESSIBLE_FONT_CHOOSER L"font chooser" - - /** - * A GROUP_BOX is a simple container that contains a border - * around it and contains components inside it. - */ -#define ACCESSIBLE_GROUP_BOX L"group box" - - /** - * A text header - */ -#define ACCESSIBLE_HEADER L"header" - - /** - * A text footer - */ -#define ACCESSIBLE_FOOTER L"footer" - - /** - * A text paragraph - */ -#define ACCESSIBLE_PARAGRAPH L"paragraph" - - /** - * A ruler is an object used to measure distance - */ -#define ACCESSIBLE_RULER L"ruler" - - /** - * A role indicating the object acts as a formula for - * calculating a value. An example is a formula in - * a spreadsheet cell. - */ -#define ACCESSIBLE_EDITBAR L"editbar" - - /** - * A role indicating the object monitors the progress - * of some operation. - */ -#define PROGRESS_MONITOR L"progress monitor" - - - /** - ****************************************************** - * Accessibility event types - ****************************************************** - */ - -#define cPropertyNameChangeEvent (jlong) 1 // 1 -#define cPropertyDescriptionChangeEvent (jlong) 2 // 2 -#define cPropertyStateChangeEvent (jlong) 4 // 4 -#define cPropertyValueChangeEvent (jlong) 8 // 8 -#define cPropertySelectionChangeEvent (jlong) 16 // 10 -#define cPropertyTextChangeEvent (jlong) 32 // 20 -#define cPropertyCaretChangeEvent (jlong) 64 // 40 -#define cPropertyVisibleDataChangeEvent (jlong) 128 // 80 -#define cPropertyChildChangeEvent (jlong) 256 // 100 -#define cPropertyActiveDescendentChangeEvent (jlong) 512 // 200 -#define cPropertyTableModelChangeEvent (jlong) 1024 // 400 - - /** - ****************************************************** - * optional AccessibleContext interfaces - * - * This version of the bridge reuses the accessibleValue - * field in the AccessibleContextInfo struct to represent - * additional optional interfaces that are supported by - * the Java AccessibleContext. This is backwardly compatable - * because the old accessibleValue was set to the BOOL - * value TRUE (i.e., 1) if the AccessibleValue interface is - * supported. - ****************************************************** - */ - -#define cAccessibleValueInterface (jlong) 1 // 1 << 1 (TRUE) -#define cAccessibleActionInterface (jlong) 2 // 1 << 2 -#define cAccessibleComponentInterface (jlong) 4 // 1 << 3 -#define cAccessibleSelectionInterface (jlong) 8 // 1 << 4 -#define cAccessibleTableInterface (jlong) 16 // 1 << 5 -#define cAccessibleTextInterface (jlong) 32 // 1 << 6 -#define cAccessibleHypertextInterface (jlong) 64 // 1 << 7 - - - /** - ****************************************************** - * Accessibility information bundles - ****************************************************** - */ - - typedef struct AccessBridgeVersionInfoTag { - wchar_t VMversion[SHORT_STRING_SIZE]; // output of "java -version" - wchar_t bridgeJavaClassVersion[SHORT_STRING_SIZE]; // version of the AccessBridge.class - wchar_t bridgeJavaDLLVersion[SHORT_STRING_SIZE]; // version of JavaAccessBridge.dll - wchar_t bridgeWinDLLVersion[SHORT_STRING_SIZE]; // version of WindowsAccessBridge.dll - } AccessBridgeVersionInfo; - - - typedef struct AccessibleContextInfoTag { - wchar_t name[MAX_STRING_SIZE]; // the AccessibleName of the object - wchar_t description[MAX_STRING_SIZE]; // the AccessibleDescription of the object - - wchar_t role[SHORT_STRING_SIZE]; // localized AccesibleRole string - wchar_t role_en_US[SHORT_STRING_SIZE]; // AccesibleRole string in the en_US locale - wchar_t states[SHORT_STRING_SIZE]; // localized AccesibleStateSet string (comma separated) - wchar_t states_en_US[SHORT_STRING_SIZE]; // AccesibleStateSet string in the en_US locale (comma separated) - - jint indexInParent; // index of object in parent - jint childrenCount; // # of children, if any - - jint x; // screen coords in pixels - jint y; // " - jint width; // pixel width of object - jint height; // pixel height of object - - BOOL accessibleComponent; // flags for various additional - BOOL accessibleAction; // Java Accessibility interfaces - BOOL accessibleSelection; // FALSE if this object doesn't - BOOL accessibleText; // implement the additional interface - // in question - - // BOOL accessibleValue; // old BOOL indicating whether AccessibleValue is supported - BOOL accessibleInterfaces; // new bitfield containing additional interface flags - - } AccessibleContextInfo; - - - - // AccessibleText packages - typedef struct AccessibleTextInfoTag { - jint charCount; // # of characters in this text object - jint caretIndex; // index of caret - jint indexAtPoint; // index at the passsed in point - } AccessibleTextInfo; - - typedef struct AccessibleTextItemsInfoTag { - wchar_t letter; - wchar_t word[SHORT_STRING_SIZE]; - wchar_t sentence[MAX_STRING_SIZE]; - } AccessibleTextItemsInfo; - - typedef struct AccessibleTextSelectionInfoTag { - jint selectionStartIndex; - jint selectionEndIndex; - wchar_t selectedText[MAX_STRING_SIZE]; - } AccessibleTextSelectionInfo; - - typedef struct AccessibleTextRectInfoTag { - jint x; // bounding rect of char at index - jint y; // " - jint width; // " - jint height; // " - } AccessibleTextRectInfo; - - // standard attributes for text; note: tabstops are not supported - typedef struct AccessibleTextAttributesInfoTag { - BOOL bold; - BOOL italic; - BOOL underline; - BOOL strikethrough; - BOOL superscript; - BOOL subscript; - - wchar_t backgroundColor[SHORT_STRING_SIZE]; - wchar_t foregroundColor[SHORT_STRING_SIZE]; - wchar_t fontFamily[SHORT_STRING_SIZE]; - jint fontSize; - - jint alignment; - jint bidiLevel; - - jfloat firstLineIndent; - jfloat leftIndent; - jfloat rightIndent; - jfloat lineSpacing; - jfloat spaceAbove; - jfloat spaceBelow; - - wchar_t fullAttributesString[MAX_STRING_SIZE]; - } AccessibleTextAttributesInfo; - - /** - ****************************************************** - * IPC management typedefs - ****************************************************** - */ - -#define cMemoryMappedNameSize 255 - - /** - * sent by the WindowsDLL -> the memory-mapped file is setup - * - */ - typedef struct MemoryMappedFileCreatedPackageTag { -// HWND bridgeWindow; // redundant, but easier to get to here... - ABHWND64 bridgeWindow; // redundant, but easier to get to here... - char filename[cMemoryMappedNameSize]; - } MemoryMappedFileCreatedPackage; - - - - - /** - * sent when a new JavaVM attaches to the Bridge - * - */ - typedef struct JavaVMCreatedPackageTag { - ABHWND64 bridgeWindow; - long vmID; - } JavaVMCreatedPackage; - - /** - * sent when a JavaVM detatches from the Bridge - * - */ - typedef struct JavaVMDestroyedPackageTag { - ABHWND64 bridgeWindow; - } JavaVMDestroyedPackage; - - /** - * sent when a new AT attaches to the Bridge - * - */ - typedef struct WindowsATCreatedPackageTag { - ABHWND64 bridgeWindow; - } WindowsATCreatedPackage; - - /** - * sent when an AT detatches from the Bridge - * - */ - typedef struct WindowsATDestroyedPackageTag { - ABHWND64 bridgeWindow; - } WindowsATDestroyedPackage; - - - /** - * sent by JVM Bridges in response to a WindowsATCreate - * message; saying "howdy, welcome to the neighborhood" - * - */ - typedef struct JavaVMPresentNotificationPackageTag { - ABHWND64 bridgeWindow; - long vmID; - } JavaVMPresentNotificationPackage; - - /** - * sent by AT Bridges in response to a JavaVMCreate - * message; saying "howdy, welcome to the neighborhood" - * - */ - typedef struct WindowsATPresentNotificationPackageTag { - ABHWND64 bridgeWindow; - } WindowsATPresentNotificationPackage; - - - /** - ****************************************************** - * Core packages - ****************************************************** - */ - - typedef struct ReleaseJavaObjectPackageTag { - long vmID; - JOBJECT64 object; - } ReleaseJavaObjectPackage; - - typedef struct GetAccessBridgeVersionPackageTag { - long vmID; // can't get VM info w/out a VM! - AccessBridgeVersionInfo rVersionInfo; - } GetAccessBridgeVersionPackage; - - typedef struct IsSameObjectPackageTag { - long vmID; - JOBJECT64 obj1; - JOBJECT64 obj2; - jboolean rResult; - } IsSameObjectPackage; - - /** - ****************************************************** - * Windows packages - ****************************************************** - */ - - typedef struct IsJavaWindowPackageTag { - jint window; - jboolean rResult; - } IsJavaWindowPackage; - - typedef struct GetAccessibleContextFromHWNDPackageTag { - jint window; - long rVMID; - JOBJECT64 rAccessibleContext; - } GetAccessibleContextFromHWNDPackage; - - typedef struct GetHWNDFromAccessibleContextPackageTag { - JOBJECT64 accessibleContext; - ABHWND64 rHWND; - } GetHWNDFromAccessibleContextPackage; - - /** -****************************************************** -* AccessibleContext packages -****************************************************** -*/ - - typedef struct GetAccessibleContextAtPackageTag { - jint x; - jint y; - long vmID; - JOBJECT64 AccessibleContext; // look within this AC - JOBJECT64 rAccessibleContext; - } GetAccessibleContextAtPackage; - - typedef struct GetAccessibleContextWithFocusPackageTag { - long rVMID; - JOBJECT64 rAccessibleContext; - } GetAccessibleContextWithFocusPackage; - - typedef struct GetAccessibleContextInfoPackageTag { - long vmID; - JOBJECT64 AccessibleContext; - AccessibleContextInfo rAccessibleContextInfo; - } GetAccessibleContextInfoPackage; - - typedef struct GetAccessibleChildFromContextPackageTag { - long vmID; - JOBJECT64 AccessibleContext; - jint childIndex; - JOBJECT64 rAccessibleContext; - } GetAccessibleChildFromContextPackage; - - typedef struct GetAccessibleParentFromContextPackageTag { - long vmID; - JOBJECT64 AccessibleContext; - JOBJECT64 rAccessibleContext; - } GetAccessibleParentFromContextPackage; - - /** -****************************************************** -* AccessibleTable packages -****************************************************** -*/ - -#define MAX_TABLE_SELECTIONS 64 - - // table information - typedef struct AccessibleTableInfoTag { - JOBJECT64 caption; // AccesibleContext - JOBJECT64 summary; // AccessibleContext - jint rowCount; - jint columnCount; - JOBJECT64 accessibleContext; - JOBJECT64 accessibleTable; - } AccessibleTableInfo; - - typedef struct GetAccessibleTableInfoPackageTag { - long vmID; - JOBJECT64 accessibleContext; - AccessibleTableInfo rTableInfo; - } GetAccessibleTableInfoPackage; - - // table cell information - typedef struct AccessibleTableCellInfoTag { - JOBJECT64 accessibleContext; - jint index; - jint row; - jint column; - jint rowExtent; - jint columnExtent; - jboolean isSelected; - } AccessibleTableCellInfo; - - typedef struct GetAccessibleTableCellInfoPackageTag { - long vmID; - JOBJECT64 accessibleTable; - jint row; - jint column; - AccessibleTableCellInfo rTableCellInfo; - } GetAccessibleTableCellInfoPackage; - - typedef struct GetAccessibleTableRowHeaderPackageTag { - long vmID; - JOBJECT64 accessibleContext; - AccessibleTableInfo rTableInfo; - } GetAccessibleTableRowHeaderPackage; - - typedef struct GetAccessibleTableColumnHeaderPackageTag { - long vmID; - JOBJECT64 accessibleContext; - AccessibleTableInfo rTableInfo; - } GetAccessibleTableColumnHeaderPackage; - - typedef struct GetAccessibleTableRowDescriptionPackageTag { - long vmID; - JOBJECT64 accessibleContext; - jint row; - JOBJECT64 rAccessibleContext; - } GetAccessibleTableRowDescriptionPackage; - - typedef struct GetAccessibleTableColumnDescriptionPackageTag { - long vmID; - JOBJECT64 accessibleContext; - jint column; - JOBJECT64 rAccessibleContext; - } GetAccessibleTableColumnDescriptionPackage; - - typedef struct GetAccessibleTableRowSelectionCountPackageTag { - long vmID; - JOBJECT64 accessibleTable; - jint rCount; - } GetAccessibleTableRowSelectionCountPackage; - - typedef struct IsAccessibleTableRowSelectedPackageTag { - long vmID; - JOBJECT64 accessibleTable; - jint row; - jboolean rResult; - } IsAccessibleTableRowSelectedPackage; - - typedef struct GetAccessibleTableRowSelectionsPackageTag { - long vmID; - JOBJECT64 accessibleTable; - jint count; - jint rSelections[MAX_TABLE_SELECTIONS]; - } GetAccessibleTableRowSelectionsPackage; - - typedef struct GetAccessibleTableColumnSelectionCountPackageTag { - long vmID; - JOBJECT64 accessibleTable; - jint rCount; - } GetAccessibleTableColumnSelectionCountPackage; - - typedef struct IsAccessibleTableColumnSelectedPackageTag { - long vmID; - JOBJECT64 accessibleTable; - jint column; - jboolean rResult; - } IsAccessibleTableColumnSelectedPackage; - - typedef struct GetAccessibleTableColumnSelectionsPackageTag { - long vmID; - JOBJECT64 accessibleTable; - jint count; - jint rSelections[MAX_TABLE_SELECTIONS]; - } GetAccessibleTableColumnSelectionsPackage; - - - typedef struct GetAccessibleTableRowPackageTag { - long vmID; - JOBJECT64 accessibleTable; - jint index; - jint rRow; - } GetAccessibleTableRowPackage; - - typedef struct GetAccessibleTableColumnPackageTag { - long vmID; - JOBJECT64 accessibleTable; - jint index; - jint rColumn; - } GetAccessibleTableColumnPackage; - - typedef struct GetAccessibleTableIndexPackageTag { - long vmID; - JOBJECT64 accessibleTable; - jint row; - jint column; - jint rIndex; - } GetAccessibleTableIndexPackage; - - - /** - ****************************************************** - * AccessibleRelationSet packages - ****************************************************** - */ - -#define MAX_RELATION_TARGETS 25 -#define MAX_RELATIONS 5 - - typedef struct AccessibleRelationInfoTag { - wchar_t key[SHORT_STRING_SIZE]; - jint targetCount; - JOBJECT64 targets[MAX_RELATION_TARGETS]; // AccessibleContexts - } AccessibleRelationInfo; - - typedef struct AccessibleRelationSetInfoTag { - jint relationCount; - AccessibleRelationInfo relations[MAX_RELATIONS]; - } AccessibleRelationSetInfo; - - typedef struct GetAccessibleRelationSetPackageTag { - long vmID; - JOBJECT64 accessibleContext; - AccessibleRelationSetInfo rAccessibleRelationSetInfo; - } GetAccessibleRelationSetPackage; - - /** - ****************************************************** - * AccessibleHypertext packagess - ****************************************************** - */ - -#define MAX_HYPERLINKS 64 // maximum number of hyperlinks returned - - // hyperlink information - typedef struct AccessibleHyperlinkInfoTag { - wchar_t text[SHORT_STRING_SIZE]; // the hyperlink text - jint startIndex; //index in the hypertext document where the link begins - jint endIndex; //index in the hypertext document where the link ends - JOBJECT64 accessibleHyperlink; // AccessibleHyperlink object - } AccessibleHyperlinkInfo; - - // hypertext information - typedef struct AccessibleHypertextInfoTag { - jint linkCount; // number of hyperlinks - AccessibleHyperlinkInfo links[MAX_HYPERLINKS]; // the hyperlinks - JOBJECT64 accessibleHypertext; // AccessibleHypertext object - } AccessibleHypertextInfo; - - // struct for sending a message to get the hypertext for an AccessibleContext - typedef struct GetAccessibleHypertextPackageTag { - long vmID; // the virtual machine ID - JOBJECT64 accessibleContext; // AccessibleContext with hypertext - AccessibleHypertextInfo rAccessibleHypertextInfo; // returned hypertext - } GetAccessibleHypertextPackage; - - // struct for sending an message to activate a hyperlink - typedef struct ActivateAccessibleHyperlinkPackageTag { - long vmID; // the virtual machine ID - JOBJECT64 accessibleContext; // AccessibleContext containing the link - JOBJECT64 accessibleHyperlink; // the link to activate - BOOL rResult; // hyperlink activation return value - } ActivateAccessibleHyperlinkPackage; - - // struct for sending a message to get the number of hyperlinks in a component - typedef struct GetAccessibleHyperlinkCountPackageTag { - long vmID; // the virtual machine ID - JOBJECT64 accessibleContext; // AccessibleContext containing AccessibleHypertext - jint rLinkCount; // link count return value - } GetAccessibleHyperlinkCountPackage; - - // struct for sending a message to get the hypertext for an AccessibleContext - // starting at a specified index in the document - typedef struct GetAccessibleHypertextExtPackageTag { - long vmID; // the virtual machine ID - JOBJECT64 accessibleContext; // AccessibleContext with hypertext - jint startIndex; // start index in document - AccessibleHypertextInfo rAccessibleHypertextInfo; // returned hypertext - BOOL rSuccess; // whether call succeeded - } GetAccessibleHypertextExtPackage; - - // struct for sending a message to get the nth hyperlink in a document; - // maps to AccessibleHypertext.getLink - typedef struct GetAccessibleHyperlinkPackageTag { - long vmID; // the virtual machine ID - JOBJECT64 hypertext; // AccessibleHypertext - jint linkIndex; // hyperlink index - AccessibleHyperlinkInfo rAccessibleHyperlinkInfo; // returned hyperlink - } GetAccessibleHyperlinkPackage; - - // struct for sending a message to get the index into an array - // of hyperlinks that is associated with a character index in a - // document; maps to AccessibleHypertext.getLinkIndex - typedef struct GetAccessibleHypertextLinkIndexPackageTag { - long vmID; // the virtual machine ID - JOBJECT64 hypertext; // AccessibleHypertext - jint charIndex; // character index in document - jint rLinkIndex; // returned hyperlink index - } GetAccessibleHypertextLinkIndexPackage; - - /** - ****************************************************** - * Accessible Key Bindings packages - ****************************************************** - */ - -#define MAX_KEY_BINDINGS 10 - - // keyboard character modifiers -#define ACCESSIBLE_SHIFT_KEYSTROKE 1 -#define ACCESSIBLE_CONTROL_KEYSTROKE 2 -#define ACCESSIBLE_META_KEYSTROKE 4 -#define ACCESSIBLE_ALT_KEYSTROKE 8 -#define ACCESSIBLE_ALT_GRAPH_KEYSTROKE 16 -#define ACCESSIBLE_BUTTON1_KEYSTROKE 32 -#define ACCESSIBLE_BUTTON2_KEYSTROKE 64 -#define ACCESSIBLE_BUTTON3_KEYSTROKE 128 -#define ACCESSIBLE_FKEY_KEYSTROKE 256 // F key pressed, character contains 1-24 -#define ACCESSIBLE_CONTROLCODE_KEYSTROKE 512 // Control code key pressed, character contains control code. - -// The supported control code keys are: -#define ACCESSIBLE_VK_TAB 9 -#define ACCESSIBLE_VK_SPACE 32 -#define ACCESSIBLE_VK_BACK_SPACE 8 -#define ACCESSIBLE_VK_DELETE 127 -#define ACCESSIBLE_VK_DOWN 40 -#define ACCESSIBLE_VK_END 35 -#define ACCESSIBLE_VK_HOME 36 -#define ACCESSIBLE_VK_INSERT 155 -#define ACCESSIBLE_VK_KP_DOWN 225 -#define ACCESSIBLE_VK_KP_LEFT 226 -#define ACCESSIBLE_VK_KP_RIGHT 227 -#define ACCESSIBLE_VK_KP_UP 224 -#define ACCESSIBLE_VK_LEFT 37 -#define ACCESSIBLE_VK_PAGE_DOWN 34 -#define ACCESSIBLE_VK_PAGE_UP 33 -#define ACCESSIBLE_VK_RIGHT 39 -#define ACCESSIBLE_VK_UP 38 - - // a key binding associates with a component - typedef struct AccessibleKeyBindingInfoTag { - jchar character; // the key character - jint modifiers; // the key modifiers - } AccessibleKeyBindingInfo; - - // all of the key bindings associated with a component - typedef struct AccessibleKeyBindingsTag { - int keyBindingsCount; // number of key bindings - AccessibleKeyBindingInfo keyBindingInfo[MAX_KEY_BINDINGS]; - } AccessibleKeyBindings; - - // struct to get the key bindings associated with a component - typedef struct GetAccessibleKeyBindingsPackageTag { - long vmID; // the virtual machine id - JOBJECT64 accessibleContext; // the component - AccessibleKeyBindings rAccessibleKeyBindings; // the key bindings - } GetAccessibleKeyBindingsPackage; - - /** -****************************************************** -* AccessibleIcon packages -****************************************************** -*/ -#define MAX_ICON_INFO 8 - - // an icon assocated with a component - typedef struct AccessibleIconInfoTag { - wchar_t description[SHORT_STRING_SIZE]; // icon description - jint height; // icon height - jint width; // icon width - } AccessibleIconInfo; - - // all of the icons associated with a component - typedef struct AccessibleIconsTag { - jint iconsCount; // number of icons - AccessibleIconInfo iconInfo[MAX_ICON_INFO]; // the icons - } AccessibleIcons; - - // struct to get the icons associated with a component - typedef struct GetAccessibleIconsPackageTag { - long vmID; // the virtual machine id - JOBJECT64 accessibleContext; // the component - AccessibleIcons rAccessibleIcons; // the icons - } GetAccessibleIconsPackage; - - - /** -****************************************************** -* AccessibleAction packages -****************************************************** -*/ -#define MAX_ACTION_INFO 256 -#define MAX_ACTIONS_TO_DO 32 - - // an action assocated with a component - typedef struct AccessibleActionInfoTag { - wchar_t name[SHORT_STRING_SIZE]; // action name - } AccessibleActionInfo; - - // all of the actions associated with a component - typedef struct AccessibleActionsTag { - jint actionsCount; // number of actions - AccessibleActionInfo actionInfo[MAX_ACTION_INFO]; // the action information - } AccessibleActions; - - // struct for requesting the actions associated with a component - typedef struct GetAccessibleActionsPackageTag { - long vmID; - JOBJECT64 accessibleContext; // the component - AccessibleActions rAccessibleActions; // the actions - } GetAccessibleActionsPackage; - - // list of AccessibleActions to do - typedef struct AccessibleActionsToDoTag { - jint actionsCount; // number of actions to do - AccessibleActionInfo actions[MAX_ACTIONS_TO_DO];// the accessible actions to do - } AccessibleActionsToDo; - - // struct for sending an message to do one or more actions - typedef struct DoAccessibleActionsPackageTag { - long vmID; // the virtual machine ID - JOBJECT64 accessibleContext; // component to do the action - AccessibleActionsToDo actionsToDo; // the accessible actions to do - BOOL rResult; // action return value - jint failure; // index of action that failed if rResult is FALSE - } DoAccessibleActionsPackage; - - /** -****************************************************** -* AccessibleText packages -****************************************************** -*/ - - typedef struct GetAccessibleTextInfoPackageTag { - long vmID; - JOBJECT64 AccessibleContext; - jint x; - jint y; - AccessibleTextInfo rTextInfo; - } GetAccessibleTextInfoPackage; - - typedef struct GetAccessibleTextItemsPackageTag { - long vmID; - JOBJECT64 AccessibleContext; - jint index; - AccessibleTextItemsInfo rTextItemsInfo; - } GetAccessibleTextItemsPackage; - - typedef struct GetAccessibleTextSelectionInfoPackageTag { - long vmID; - JOBJECT64 AccessibleContext; - AccessibleTextSelectionInfo rTextSelectionItemsInfo; - } GetAccessibleTextSelectionInfoPackage; - - typedef struct GetAccessibleTextAttributeInfoPackageTag { - long vmID; - JOBJECT64 AccessibleContext; - jint index; - AccessibleTextAttributesInfo rAttributeInfo; - } GetAccessibleTextAttributeInfoPackage; - - typedef struct GetAccessibleTextRectInfoPackageTag { - long vmID; - JOBJECT64 AccessibleContext; - jint index; - AccessibleTextRectInfo rTextRectInfo; - } GetAccessibleTextRectInfoPackage; - - typedef struct GetCaretLocationPackageTag { - long vmID; - JOBJECT64 AccessibleContext; - jint index; - AccessibleTextRectInfo rTextRectInfo; - } GetCaretLocationPackage; - - typedef struct GetAccessibleTextLineBoundsPackageTag { - long vmID; - JOBJECT64 AccessibleContext; - jint index; - jint rLineStart; - jint rLineEnd; - } GetAccessibleTextLineBoundsPackage; - - typedef struct GetAccessibleTextRangePackageTag { - long vmID; - JOBJECT64 AccessibleContext; - jint start; - jint end; - wchar_t rText[MAX_BUFFER_SIZE]; - } GetAccessibleTextRangePackage; - - /** -****************************************************** -* -* Utility method packages -****************************************************** -*/ - - typedef struct SetTextContentsPackageTag { - long vmID; - JOBJECT64 accessibleContext; // the text field - wchar_t text[MAX_STRING_SIZE]; // the text - BOOL rResult; - } SetTextContentsPackage; - - typedef struct GetParentWithRolePackageTag { - long vmID; - JOBJECT64 accessibleContext; - wchar_t role[SHORT_STRING_SIZE]; // one of Accessible Roles above - JOBJECT64 rAccessibleContext; - } GetParentWithRolePackage; - - typedef struct GetTopLevelObjectPackageTag { - long vmID; - JOBJECT64 accessibleContext; - JOBJECT64 rAccessibleContext; - } GetTopLevelObjectPackage; - - typedef struct GetParentWithRoleElseRootPackageTag { - long vmID; - JOBJECT64 accessibleContext; - wchar_t role[SHORT_STRING_SIZE]; // one of Accessible Roles above - JOBJECT64 rAccessibleContext; - } GetParentWithRoleElseRootPackage; - - typedef struct GetObjectDepthPackageTag { - long vmID; - JOBJECT64 accessibleContext; - jint rResult; - } GetObjectDepthPackage; - - typedef struct GetActiveDescendentPackageTag { - long vmID; - JOBJECT64 accessibleContext; - JOBJECT64 rAccessibleContext; - } GetActiveDescendentPackage; - - /** -****************************************************** -* AccessibleValue packages -****************************************************** -*/ - - typedef struct GetCurrentAccessibleValueFromContextPackageTag { - long vmID; - JOBJECT64 AccessibleContext; - wchar_t rValue[SHORT_STRING_SIZE]; - } GetCurrentAccessibleValueFromContextPackage; - - typedef struct GetMaximumAccessibleValueFromContextPackageTag { - long vmID; - JOBJECT64 AccessibleContext; - wchar_t rValue[SHORT_STRING_SIZE]; - } GetMaximumAccessibleValueFromContextPackage; - - typedef struct GetMinimumAccessibleValueFromContextPackageTag { - long vmID; - JOBJECT64 AccessibleContext; - wchar_t rValue[SHORT_STRING_SIZE]; - } GetMinimumAccessibleValueFromContextPackage; - - - /** -****************************************************** -* AccessibleSelection packages -****************************************************** -*/ - - typedef struct AddAccessibleSelectionFromContextPackageTag { - long vmID; - JOBJECT64 AccessibleContext; - jint index; - } AddAccessibleSelectionFromContextPackage; - - typedef struct ClearAccessibleSelectionFromContextPackageTag { - long vmID; - JOBJECT64 AccessibleContext; - } ClearAccessibleSelectionFromContextPackage; - - typedef struct GetAccessibleSelectionFromContextPackageTag { - long vmID; - JOBJECT64 AccessibleContext; - jint index; - JOBJECT64 rAccessibleContext; - } GetAccessibleSelectionFromContextPackage; - - typedef struct GetAccessibleSelectionCountFromContextPackageTag { - long vmID; - JOBJECT64 AccessibleContext; - jint rCount; - } GetAccessibleSelectionCountFromContextPackage; - - typedef struct IsAccessibleChildSelectedFromContextPackageTag { - long vmID; - JOBJECT64 AccessibleContext; - jint index; - jboolean rResult; - } IsAccessibleChildSelectedFromContextPackage; - - typedef struct RemoveAccessibleSelectionFromContextPackageTag { - long vmID; - JOBJECT64 AccessibleContext; - jint index; - } RemoveAccessibleSelectionFromContextPackage; - - typedef struct SelectAllAccessibleSelectionFromContextPackageTag { - long vmID; - JOBJECT64 AccessibleContext; - } SelectAllAccessibleSelectionFromContextPackage; - - - /** -****************************************************** -* Java Event Notification Registration packages -****************************************************** -*/ - - typedef struct AddJavaEventNotificationPackageTag { - jlong type; - //HWND DLLwindow; - ABHWND64 DLLwindow; - } AddJavaEventNotificationPackage; - - typedef struct RemoveJavaEventNotificationPackageTag { - jlong type; - //HWND DLLwindow; - ABHWND64 DLLwindow; - } RemoveJavaEventNotificationPackage; - - - /** -****************************************************** -* Accessibility Event Notification Registration packages -****************************************************** -*/ - - typedef struct AddAccessibilityEventNotificationPackageTag { - jlong type; - //HWND DLLwindow; - ABHWND64 DLLwindow; - } AddAccessibilityEventNotificationPackage; - - typedef struct RemoveAccessibilityEventNotificationPackageTag { - jlong type; - //HWND DLLwindow; - ABHWND64 DLLwindow; - } RemoveAccessibilityEventNotificationPackage; - - - /** -****************************************************** -* Accessibility Property Change Event packages -****************************************************** -*/ - - typedef struct PropertyCaretChangePackageTag { - long vmID; - JOBJECT64 Event; - JOBJECT64 AccessibleContextSource; - jint oldPosition; - jint newPosition; - } PropertyCaretChangePackage; - - typedef struct PropertyDescriptionChangePackageTag { - long vmID; - JOBJECT64 Event; - JOBJECT64 AccessibleContextSource; - wchar_t oldDescription[SHORT_STRING_SIZE]; - wchar_t newDescription[SHORT_STRING_SIZE]; - } PropertyDescriptionChangePackage; - - typedef struct PropertyNameChangePackageTag { - long vmID; - JOBJECT64 Event; - JOBJECT64 AccessibleContextSource; - wchar_t oldName[SHORT_STRING_SIZE]; - wchar_t newName[SHORT_STRING_SIZE]; - } PropertyNameChangePackage; - - typedef struct PropertySelectionChangePackageTag { - long vmID; - JOBJECT64 Event; - JOBJECT64 AccessibleContextSource; - } PropertySelectionChangePackage; - - typedef struct PropertyStateChangePackageTag { - long vmID; - JOBJECT64 Event; - JOBJECT64 AccessibleContextSource; - wchar_t oldState[SHORT_STRING_SIZE]; - wchar_t newState[SHORT_STRING_SIZE]; - } PropertyStateChangePackage; - - typedef struct PropertyTextChangePackageTag { - long vmID; - JOBJECT64 Event; - JOBJECT64 AccessibleContextSource; - } PropertyTextChangePackage; - - typedef struct PropertyValueChangePackageTag { - long vmID; - JOBJECT64 Event; - JOBJECT64 AccessibleContextSource; - wchar_t oldValue[SHORT_STRING_SIZE]; - wchar_t newValue[SHORT_STRING_SIZE]; - } PropertyValueChangePackage; - - typedef struct PropertyVisibleDataChangePackageTag { - long vmID; - JOBJECT64 Event; - JOBJECT64 AccessibleContextSource; - } PropertyVisibleDataChangePackage; - - typedef struct PropertyChildChangePackageTag { - long vmID; - JOBJECT64 Event; - JOBJECT64 AccessibleContextSource; - JOBJECT64 oldChildAccessibleContext; - JOBJECT64 newChildAccessibleContext; - } PropertyChildChangePackage; - - typedef struct PropertyActiveDescendentChangePackageTag { - long vmID; - JOBJECT64 Event; - JOBJECT64 AccessibleContextSource; - JOBJECT64 oldActiveDescendentAccessibleContext; - JOBJECT64 newActiveDescendentAccessibleContext; - } PropertyActiveDescendentChangePackage; - - - // String format for newValue is: - // "type" one of "INSERT", "UPDATE" or "DELETE" - // "firstRow" - // "lastRow" - // "firstColumn" - // "lastColumn" - // - // oldValue is currently unused - // - typedef struct PropertyTableModelChangePackageTag { - long vmID; - JOBJECT64 Event; - JOBJECT64 AccessibleContextSource; - wchar_t oldValue[SHORT_STRING_SIZE]; - wchar_t newValue[SHORT_STRING_SIZE]; - } PropertyTableModelChangePackage; - - - /** -****************************************************** -* Property Change Event packages -****************************************************** -*/ - - /* - typedef struct PropertyChangePackageTag { - long vmID; - jobject Event; - jobject AccessibleContextSource; - char propertyName[SHORT_STRING_SIZE]; - char oldValue[SHORT_STRING_SIZE]; // PropertyChangeEvent().getOldValue().toString() - char newValue[SHORT_STRING_SIZE]; // PropertyChangeEvent().getNewValue().toString() - } PropertyChangePackage; - */ - - /* - * Java shutdown event package - */ - typedef struct JavaShutdownPackageTag { - long vmID; - } JavaShutdownPackage; - - - /** -****************************************************** -* Focus Event packages -****************************************************** -*/ - - typedef struct FocusGainedPackageTag { - long vmID; - JOBJECT64 Event; - JOBJECT64 AccessibleContextSource; - } FocusGainedPackage; - - typedef struct FocusLostPackageTag { - long vmID; - JOBJECT64 Event; - JOBJECT64 AccessibleContextSource; - } FocusLostPackage; - - - /** -****************************************************** -* Caret Event packages -****************************************************** -*/ - - typedef struct CaretUpdatePackageTag { - long vmID; - JOBJECT64 Event; - JOBJECT64 AccessibleContextSource; - } CaretUpdatePackage; - - - /** -****************************************************** -* Mouse Event packages -****************************************************** -*/ - - typedef struct MouseClickedPackageTag { - long vmID; - JOBJECT64 Event; - JOBJECT64 AccessibleContextSource; - } MouseClickedPackage; - - typedef struct MouseEnteredPackageTag { - long vmID; - JOBJECT64 Event; - JOBJECT64 AccessibleContextSource; - } MouseEnteredPackage; - - typedef struct MouseExitedPackageTag { - long vmID; - JOBJECT64 Event; - JOBJECT64 AccessibleContextSource; - } MouseExitedPackage; - - typedef struct MousePressedPackageTag { - long vmID; - JOBJECT64 Event; - JOBJECT64 AccessibleContextSource; - } MousePressedPackage; - - typedef struct MouseReleasedPackageTag { - long vmID; - JOBJECT64 Event; - JOBJECT64 AccessibleContextSource; - } MouseReleasedPackage; - - - /** -****************************************************** -* Menu/PopupMenu Event packages -****************************************************** -*/ - - typedef struct MenuCanceledPackageTag { - long vmID; - JOBJECT64 Event; - JOBJECT64 AccessibleContextSource; - } MenuCanceledPackage; - - typedef struct MenuDeselectedPackageTag { - long vmID; - JOBJECT64 Event; - JOBJECT64 AccessibleContextSource; - } MenuDeselectedPackage; - - typedef struct MenuSelectedPackageTag { - long vmID; - JOBJECT64 Event; - JOBJECT64 AccessibleContextSource; - } MenuSelectedPackage; - - - typedef struct PopupMenuCanceledPackageTag { - long vmID; - JOBJECT64 Event; - JOBJECT64 AccessibleContextSource; - } PopupMenuCanceledPackage; - - typedef struct PopupMenuWillBecomeInvisiblePackageTag { - long vmID; - JOBJECT64 Event; - JOBJECT64 AccessibleContextSource; - } PopupMenuWillBecomeInvisiblePackage; - - typedef struct PopupMenuWillBecomeVisiblePackageTag { - long vmID; - JOBJECT64 Event; - JOBJECT64 AccessibleContextSource; - } PopupMenuWillBecomeVisiblePackage; - - /** -****************************************************** -* Additional methods for Teton -****************************************************** -*/ - - /** - * Gets the AccessibleName for a component based upon the JAWS algorithm. Returns - * whether successful. - * - * Bug ID 4916682 - Implement JAWS AccessibleName policy - */ - typedef struct GetVirtualAccessibleNamePackageTag { - long vmID; - AccessibleContext accessibleContext; - wchar_t rName[MAX_STRING_SIZE]; - int len; - } GetVirtualAccessibleNamePackage; - - /** - * Request focus for a component. Returns whether successful; - * - * Bug ID 4944757 - requestFocus method needed - */ - typedef struct RequestFocusPackageTag { - long vmID; - AccessibleContext accessibleContext; - } RequestFocusPackage; - - /** - * Selects text between two indices. Selection includes the text at the start index - * and the text at the end index. Returns whether successful; - * - * Bug ID 4944758 - selectTextRange method needed - */ - typedef struct SelectTextRangePackageTag { - long vmID; - AccessibleContext accessibleContext; - jint startIndex; - jint endIndex; - } SelectTextRangePackage; - - /** - * Gets the number of contiguous characters with the same attributes. - * - * Bug ID 4944761 - getTextAttributes between two indices method needed - */ - typedef struct GetTextAttributesInRangePackageTag { - long vmID; - AccessibleContext accessibleContext; - jint startIndex; // start index (inclusive) - jint endIndex; // end index (inclusive) - AccessibleTextAttributesInfo attributes; // character attributes to match - short rLength; // number of contiguous characters with matching attributes - } GetTextAttributesInRangePackage; - -#define MAX_VISIBLE_CHILDREN 256 - - // visible children information - typedef struct VisibleChildenInfoTag { - int returnedChildrenCount; // number of children returned - AccessibleContext children[MAX_VISIBLE_CHILDREN]; // the visible children - } VisibleChildrenInfo; - - // struct for sending a message to get the number of visible children - typedef struct GetVisibleChildrenCountPackageTag { - long vmID; // the virtual machine ID - JOBJECT64 accessibleContext; // AccessibleContext of parent component - jint rChildrenCount; // visible children count return value - } GetVisibleChildrenCountPackage; - - // struct for sending a message to get the hypertext for an AccessibleContext - // starting at a specified index in the document - typedef struct GetVisibleChildrenPackageTag { - long vmID; // the virtual machine ID - JOBJECT64 accessibleContext; // AccessibleContext of parent component - jint startIndex; // start index for retrieving children - VisibleChildrenInfo rVisibleChildrenInfo; // returned info - BOOL rSuccess; // whether call succeeded - } GetVisibleChildrenPackage; - - /** - * Set the caret to a text position. Returns whether successful; - * - * Bug ID 4944770 - setCaretPosition method needed - */ - typedef struct SetCaretPositionPackageTag { - long vmID; - AccessibleContext accessibleContext; - jint position; - } SetCaretPositionPackage; - - - /** - ****************************************************** - * Wrapping up all of the packages - ****************************************************** - */ - - /** - * What is the type of this package - */ - typedef enum PackageType { - - cMemoryMappedFileCreatedPackage = 0x11000, - - // many of these will go away... - cJavaVMCreatedPackage = 0x10000, - cJavaVMDestroyedPackage, - cWindowsATCreatedPackage, - cWindowsATDestroyedPackage, - cJavaVMPresentNotificationPackage, - cWindowsATPresentNotificationPackage, - - cReleaseJavaObjectPackage = 1, - cGetAccessBridgeVersionPackage = 2, - - cGetAccessibleContextFromHWNDPackage = 0x10, - cIsJavaWindowPackage, - cGetHWNDFromAccessibleContextPackage, - - cGetAccessibleContextAtPackage = 0x100, - cGetAccessibleContextWithFocusPackage, - cGetAccessibleContextInfoPackage, - cGetAccessibleChildFromContextPackage, - cGetAccessibleParentFromContextPackage, - cIsSameObjectPackage, - - cGetAccessibleTextInfoPackage = 0x200, - cGetAccessibleTextItemsPackage, - cGetAccessibleTextSelectionInfoPackage, - cGetAccessibleTextAttributeInfoPackage, - cGetAccessibleTextRectInfoPackage, - cGetAccessibleTextLineBoundsPackage, - cGetAccessibleTextRangePackage, - - cGetCurrentAccessibleValueFromContextPackage = 0x300, - cGetMaximumAccessibleValueFromContextPackage, - cGetMinimumAccessibleValueFromContextPackage, - - cAddAccessibleSelectionFromContextPackage = 0x400, - cClearAccessibleSelectionFromContextPackage, - cGetAccessibleSelectionFromContextPackage, - cGetAccessibleSelectionCountFromContextPackage, - cIsAccessibleChildSelectedFromContextPackage, - cRemoveAccessibleSelectionFromContextPackage, - cSelectAllAccessibleSelectionFromContextPackage, - - cAddJavaEventNotificationPackage = 0x900, - cRemoveJavaEventNotificationPackage, - cAddAccessibilityEventNotificationPackage, - cRemoveAccessibilityEventNotificationPackage, - - cPropertyChangePackage = 0x1000, - - cJavaShutdownPackage = 0x1010, - cFocusGainedPackage, - cFocusLostPackage, - - cCaretUpdatePackage = 0x1020, - - cMouseClickedPackage = 0x1030, - cMouseEnteredPackage, - cMouseExitedPackage, - cMousePressedPackage, - cMouseReleasedPackage, - - cMenuCanceledPackage = 0x1040, - cMenuDeselectedPackage, - cMenuSelectedPackage, - cPopupMenuCanceledPackage, - cPopupMenuWillBecomeInvisiblePackage, - cPopupMenuWillBecomeVisiblePackage, - - cPropertyCaretChangePackage = 0x1100, - cPropertyDescriptionChangePackage, - cPropertyNameChangePackage, - cPropertySelectionChangePackage, - cPropertyStateChangePackage, - cPropertyTextChangePackage, - cPropertyValueChangePackage, - cPropertyVisibleDataChangePackage, - cPropertyChildChangePackage, - cPropertyActiveDescendentChangePackage, - - - // AccessibleTable - cGetAccessibleTableInfoPackage = 0x1200, - cGetAccessibleTableCellInfoPackage, - - cGetAccessibleTableRowHeaderPackage, - cGetAccessibleTableColumnHeaderPackage, - - cGetAccessibleTableRowDescriptionPackage, - cGetAccessibleTableColumnDescriptionPackage, - - cGetAccessibleTableRowSelectionCountPackage, - cIsAccessibleTableRowSelectedPackage, - cGetAccessibleTableRowSelectionsPackage, - - cGetAccessibleTableColumnSelectionCountPackage, - cIsAccessibleTableColumnSelectedPackage, - cGetAccessibleTableColumnSelectionsPackage, - - cGetAccessibleTableRowPackage, - cGetAccessibleTableColumnPackage, - cGetAccessibleTableIndexPackage, - - cPropertyTableModelChangePackage, - - - // AccessibleRelationSet - cGetAccessibleRelationSetPackage = 0x1300, - - // AccessibleHypertext - cGetAccessibleHypertextPackage = 0x1400, - cActivateAccessibleHyperlinkPackage, - cGetAccessibleHyperlinkCountPackage, - cGetAccessibleHypertextExtPackage, - cGetAccessibleHypertextLinkIndexPackage, - cGetAccessibleHyperlinkPackage, - - // Accessible KeyBinding, Icon and Action - cGetAccessibleKeyBindingsPackage = 0x1500, - cGetAccessibleIconsPackage, - cGetAccessibleActionsPackage, - cDoAccessibleActionsPackage, - - // Utility methods - cSetTextContentsPackage = 0x1600, - cGetParentWithRolePackage, - cGetTopLevelObjectPackage, - cGetParentWithRoleElseRootPackage, - cGetObjectDepthPackage, - cGetActiveDescendentPackage, - - // Additional methods for Teton - cGetVirtualAccessibleNamePackage = 0x1700, - cRequestFocusPackage, - cSelectTextRangePackage, - cGetTextAttributesInRangePackage, - cGetSameTextAttributesInRangePackage, - cGetVisibleChildrenCountPackage, - cGetVisibleChildrenPackage, - cSetCaretPositionPackage, - cGetCaretLocationPackage - - - } PackageType; - - - /** - * Union of all package contents - */ - typedef union AllPackagesTag { - - // Initial Rendezvous packages - MemoryMappedFileCreatedPackage memoryMappedFileCreatedPackage; - - JavaVMCreatedPackage javaVMCreatedPackage; - JavaVMDestroyedPackage javaVMDestroyedPackage; - WindowsATCreatedPackage windowsATCreatedPackage; - WindowsATDestroyedPackage windowsATDestroyedPackage; - JavaVMPresentNotificationPackage javaVMPresentNotificationPackage; - WindowsATPresentNotificationPackage windowsATPresentNotificationPackage; - - // Core packages - ReleaseJavaObjectPackage releaseJavaObject; - GetAccessBridgeVersionPackage getAccessBridgeVersion; - - // Window packages - GetAccessibleContextFromHWNDPackage getAccessibleContextFromHWND; - GetHWNDFromAccessibleContextPackage getHWNDFromAccessibleContext; - - // AccessibleContext packages - GetAccessibleContextAtPackage getAccessibleContextAt; - GetAccessibleContextWithFocusPackage getAccessibleContextWithFocus; - GetAccessibleContextInfoPackage getAccessibleContextInfo; - GetAccessibleChildFromContextPackage getAccessibleChildFromContext; - GetAccessibleParentFromContextPackage getAccessibleParentFromContext; - - // AccessibleText packages - GetAccessibleTextInfoPackage getAccessibleTextInfo; - GetAccessibleTextItemsPackage getAccessibleTextItems; - GetAccessibleTextSelectionInfoPackage getAccessibleTextSelectionInfo; - GetAccessibleTextAttributeInfoPackage getAccessibleTextAttributeInfo; - GetAccessibleTextRectInfoPackage getAccessibleTextRectInfo; - GetAccessibleTextLineBoundsPackage getAccessibleTextLineBounds; - GetAccessibleTextRangePackage getAccessibleTextRange; - - // AccessibleValue packages - GetCurrentAccessibleValueFromContextPackage getCurrentAccessibleValueFromContext; - GetMaximumAccessibleValueFromContextPackage getMaximumAccessibleValueFromContext; - GetMinimumAccessibleValueFromContextPackage getMinimumAccessibleValueFromContext; - - // AccessibleSelection packages - AddAccessibleSelectionFromContextPackage addAccessibleSelectionFromContext; - ClearAccessibleSelectionFromContextPackage clearAccessibleSelectionFromContext; - GetAccessibleSelectionFromContextPackage getAccessibleSelectionFromContext; - GetAccessibleSelectionCountFromContextPackage getAccessibleSelectionCountFromContext; - IsAccessibleChildSelectedFromContextPackage isAccessibleChildSelectedFromContext; - RemoveAccessibleSelectionFromContextPackage removeAccessibleSelectionFromContext; - SelectAllAccessibleSelectionFromContextPackage selectAllAccessibleSelectionFromContext; - - // Event Notification Registration packages - AddJavaEventNotificationPackage addJavaEventNotification; - RemoveJavaEventNotificationPackage removeJavaEventNotification; - AddAccessibilityEventNotificationPackage addAccessibilityEventNotification; - RemoveAccessibilityEventNotificationPackage removeAccessibilityEventNotification; - - // Event contents packages - // PropertyChangePackage propertyChange; - PropertyCaretChangePackage propertyCaretChangePackage; - PropertyDescriptionChangePackage propertyDescriptionChangePackage; - PropertyNameChangePackage propertyNameChangePackage; - PropertySelectionChangePackage propertySelectionChangePackage; - PropertyStateChangePackage propertyStateChangePackage; - PropertyTextChangePackage propertyTextChangePackage; - PropertyValueChangePackage propertyValueChangePackage; - PropertyVisibleDataChangePackage propertyVisibleDataChangePackage; - PropertyChildChangePackage propertyChildChangePackage; - PropertyActiveDescendentChangePackage propertyActiveDescendentChangePackage; - - PropertyTableModelChangePackage propertyTableModelChangePackage; - - JavaShutdownPackage JavaShutdown; - FocusGainedPackage focusGained; - FocusLostPackage focusLost; - - CaretUpdatePackage caretUpdate; - - MouseClickedPackage mouseClicked; - MouseEnteredPackage mouseEntered; - MouseExitedPackage mouseExited; - MousePressedPackage mousePressed; - MouseReleasedPackage mouseReleased; - - MenuCanceledPackage menuCanceled; - MenuDeselectedPackage menuDeselected; - MenuSelectedPackage menuSelected; - PopupMenuCanceledPackage popupMenuCanceled; - PopupMenuWillBecomeInvisiblePackage popupMenuWillBecomeInvisible; - PopupMenuWillBecomeVisiblePackage popupMenuWillBecomeVisible; - - // AccessibleRelationSet - GetAccessibleRelationSetPackage getAccessibleRelationSet; - - // AccessibleHypertext - GetAccessibleHypertextPackage _getAccessibleHypertext; - ActivateAccessibleHyperlinkPackage _activateAccessibleHyperlink; - GetAccessibleHyperlinkCountPackage _getAccessibleHyperlinkCount; - GetAccessibleHypertextExtPackage _getAccessibleHypertextExt; - GetAccessibleHypertextLinkIndexPackage _getAccessibleHypertextLinkIndex; - GetAccessibleHyperlinkPackage _getAccessibleHyperlink; - - // Accessible KeyBinding, Icon and Action - GetAccessibleKeyBindingsPackage getAccessibleKeyBindings; - GetAccessibleIconsPackage getAccessibleIcons; - GetAccessibleActionsPackage getAccessibleActions; - DoAccessibleActionsPackage doAccessibleActions; - - // utility methods - SetTextContentsPackage _setTextContents; - GetParentWithRolePackage _getParentWithRole; - GetTopLevelObjectPackage _getTopLevelObject; - GetParentWithRoleElseRootPackage _getParentWithRoleElseRoot; - GetObjectDepthPackage _getObjectDepth; - GetActiveDescendentPackage _getActiveDescendent; - - // Additional methods for Teton - GetVirtualAccessibleNamePackage _getVirtualAccessibleName; - RequestFocusPackage _requestFocus; - SelectTextRangePackage _selectTextRange; - GetTextAttributesInRangePackage _getTextAttributesInRange; - GetVisibleChildrenCountPackage _getVisibleChildrenCount; - GetVisibleChildrenPackage _getVisibleChildren; - SetCaretPositionPackage _setCaretPosition; - - } AllPackages; - - - /** - * Union of all Java-initiated package contents - */ - typedef union JavaInitiatedPackagesTag { - - // Initial Rendezvous packages - JavaVMCreatedPackage javaVMCreatedPackage; - JavaVMDestroyedPackage javaVMDestroyedPackage; - JavaVMPresentNotificationPackage javaVMPresentNotificationPackage; - - // Event contents packages - PropertyCaretChangePackage propertyCaretChangePackage; - PropertyDescriptionChangePackage propertyDescriptionChangePackage; - PropertyNameChangePackage propertyNameChangePackage; - PropertySelectionChangePackage propertySelectionChangePackage; - PropertyStateChangePackage propertyStateChangePackage; - PropertyTextChangePackage propertyTextChangePackage; - PropertyValueChangePackage propertyValueChangePackage; - PropertyVisibleDataChangePackage propertyVisibleDataChangePackage; - PropertyChildChangePackage propertyChildChangePackage; - PropertyActiveDescendentChangePackage propertyActiveDescendentChangePackage; - - PropertyTableModelChangePackage propertyTableModelChangePackage; - - JavaShutdownPackage JavaShutdown; - FocusGainedPackage focusGained; - FocusLostPackage focusLost; - - CaretUpdatePackage caretUpdate; - - MouseClickedPackage mouseClicked; - MouseEnteredPackage mouseEntered; - MouseExitedPackage mouseExited; - MousePressedPackage mousePressed; - MouseReleasedPackage mouseReleased; - - MenuCanceledPackage menuCanceled; - MenuDeselectedPackage menuDeselected; - MenuSelectedPackage menuSelected; - PopupMenuCanceledPackage popupMenuCanceled; - PopupMenuWillBecomeInvisiblePackage popupMenuWillBecomeInvisible; - PopupMenuWillBecomeVisiblePackage popupMenuWillBecomeVisible; - - } JavaInitiatedPackages; - - - /** - * Union of all Windows-initiated package contents - */ - typedef union WindowsInitiatedPackagesTag { - - // Initial Rendezvous packages - MemoryMappedFileCreatedPackage memoryMappedFileCreatedPackage; - - WindowsATCreatedPackage windowsATCreatedPackage; - WindowsATDestroyedPackage windowsATDestroyedPackage; - WindowsATPresentNotificationPackage windowsATPresentNotificationPackage; - - // Core packages - ReleaseJavaObjectPackage releaseJavaObject; - GetAccessBridgeVersionPackage getAccessBridgeVersion; - - // Window packages - GetAccessibleContextFromHWNDPackage getAccessibleContextFromHWND; - GetHWNDFromAccessibleContextPackage getHWNDFromAccessibleContext; - - // AccessibleContext packages - GetAccessibleContextAtPackage getAccessibleContextAt; - GetAccessibleContextWithFocusPackage getAccessibleContextWithFocus; - GetAccessibleContextInfoPackage getAccessibleContextInfo; - GetAccessibleChildFromContextPackage getAccessibleChildFromContext; - GetAccessibleParentFromContextPackage getAccessibleParentFromContext; - - // AccessibleText packages - GetAccessibleTextInfoPackage getAccessibleTextInfo; - GetAccessibleTextItemsPackage getAccessibleTextItems; - GetAccessibleTextSelectionInfoPackage getAccessibleTextSelectionInfo; - GetAccessibleTextAttributeInfoPackage getAccessibleTextAttributeInfo; - GetAccessibleTextRectInfoPackage getAccessibleTextRectInfo; - GetAccessibleTextLineBoundsPackage getAccessibleTextLineBounds; - GetAccessibleTextRangePackage getAccessibleTextRange; - - // AccessibleValue packages - GetCurrentAccessibleValueFromContextPackage getCurrentAccessibleValueFromContext; - GetMaximumAccessibleValueFromContextPackage getMaximumAccessibleValueFromContext; - GetMinimumAccessibleValueFromContextPackage getMinimumAccessibleValueFromContext; - - // AccessibleSelection packages - AddAccessibleSelectionFromContextPackage addAccessibleSelectionFromContext; - ClearAccessibleSelectionFromContextPackage clearAccessibleSelectionFromContext; - GetAccessibleSelectionFromContextPackage getAccessibleSelectionFromContext; - GetAccessibleSelectionCountFromContextPackage getAccessibleSelectionCountFromContext; - IsAccessibleChildSelectedFromContextPackage isAccessibleChildSelectedFromContext; - RemoveAccessibleSelectionFromContextPackage removeAccessibleSelectionFromContext; - SelectAllAccessibleSelectionFromContextPackage selectAllAccessibleSelectionFromContext; - - // Event Notification Registration packages - AddJavaEventNotificationPackage addJavaEventNotification; - RemoveJavaEventNotificationPackage removeJavaEventNotification; - AddAccessibilityEventNotificationPackage addAccessibilityEventNotification; - RemoveAccessibilityEventNotificationPackage removeAccessibilityEventNotification; - - // AccessibleTable - GetAccessibleTableInfoPackage _getAccessibleTableInfo; - GetAccessibleTableCellInfoPackage _getAccessibleTableCellInfo; - - GetAccessibleTableRowHeaderPackage _getAccessibleTableRowHeader; - GetAccessibleTableColumnHeaderPackage _getAccessibleTableColumnHeader; - - GetAccessibleTableRowDescriptionPackage _getAccessibleTableRowDescription; - GetAccessibleTableColumnDescriptionPackage _getAccessibleTableColumnDescription; - - GetAccessibleTableRowSelectionCountPackage _getAccessibleTableRowSelectionCount; - IsAccessibleTableRowSelectedPackage _isAccessibleTableRowSelected; - GetAccessibleTableRowSelectionsPackage _getAccessibleTableRowSelections; - - GetAccessibleTableColumnSelectionCountPackage _getAccessibleTableColumnSelectionCount; - IsAccessibleTableColumnSelectedPackage _isAccessibleTableColumnSelected; - GetAccessibleTableColumnSelectionsPackage _getAccessibleTableColumnSelections; - - GetAccessibleTableRowPackage _getAccessibleTableRow; - GetAccessibleTableColumnPackage _getAccessibleTableColumn; - GetAccessibleTableIndexPackage _getAccessibleTableIndex; - - // AccessibleRelationSet - GetAccessibleRelationSetPackage _getAccessibleRelationSet; - - // Accessible KeyBindings, Icons and Actions - GetAccessibleKeyBindingsPackage _getAccessibleKeyBindings; - GetAccessibleIconsPackage _getAccessibleIcons; - GetAccessibleActionsPackage _getAccessibleActions; - DoAccessibleActionsPackage _doAccessibleActions; - - - IsSameObjectPackage _isSameObject; - - // utility methods - SetTextContentsPackage _setTextContents; - GetParentWithRolePackage _getParentWithRole; - GetTopLevelObjectPackage _getTopLevelObject; - GetParentWithRoleElseRootPackage _getParentWithRoleElseRoot; - GetObjectDepthPackage _getObjectDepth; - GetActiveDescendentPackage _getActiveDescendent; - - // Additional methods for Teton - GetVirtualAccessibleNamePackage _getVirtualAccessibleName; - RequestFocusPackage _requestFocus; - SelectTextRangePackage _selectTextRange; - GetTextAttributesInRangePackage _getTextAttributesInRange; - GetVisibleChildrenCountPackage _getVisibleChildrenCount; - GetVisibleChildrenPackage _getVisibleChildren; - SetCaretPositionPackage _setCaretPosition; - - - } WindowsInitiatedPackages; - - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/core/esmf-tree-sitter-turtle/src/main/c/include/windows/jawt_md.h b/core/esmf-tree-sitter-turtle/src/main/c/include/windows/jawt_md.h deleted file mode 100755 index 7d43ff827..000000000 --- a/core/esmf-tree-sitter-turtle/src/main/c/include/windows/jawt_md.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (c) 1999, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#ifndef _JAVASOFT_JAWT_MD_H_ -#define _JAVASOFT_JAWT_MD_H_ - -#include -#include "jawt.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/* - * Win32-specific declarations for AWT native interface. - * See notes in jawt.h for an example of use. - */ -typedef struct jawt_Win32DrawingSurfaceInfo { - /* Native window, DDB, or DIB handle */ - union { - HWND hwnd; - HBITMAP hbitmap; - void* pbits; - }; - /* - * This HDC should always be used instead of the HDC returned from - * BeginPaint() or any calls to GetDC(). - */ - HDC hdc; - HPALETTE hpalette; -} JAWT_Win32DrawingSurfaceInfo; - -#ifdef __cplusplus -} -#endif - -#endif /* !_JAVASOFT_JAWT_MD_H_ */ diff --git a/core/esmf-tree-sitter-turtle/src/main/c/include/windows/jni_md.h b/core/esmf-tree-sitter-turtle/src/main/c/include/windows/jni_md.h deleted file mode 100755 index 6d217733d..000000000 --- a/core/esmf-tree-sitter-turtle/src/main/c/include/windows/jni_md.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 1996, 2024, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#ifndef _JAVASOFT_JNI_MD_H_ -#define _JAVASOFT_JNI_MD_H_ - -#ifndef JNIEXPORT - #define JNIEXPORT __declspec(dllexport) -#endif -#define JNIIMPORT __declspec(dllimport) - -typedef int jint; -typedef long long jlong; -typedef signed char jbyte; - -#endif /* !_JAVASOFT_JNI_MD_H_ */ From 69fb3d2c87a7d538220f232e1a900c2c456eeeb6 Mon Sep 17 00:00:00 2001 From: Andreas Textor Date: Tue, 9 Jun 2026 14:52:24 +0200 Subject: [PATCH 41/41] Update copyright --- core/esmf-util/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/esmf-util/pom.xml b/core/esmf-util/pom.xml index fef99db23..ec667bc66 100644 --- a/core/esmf-util/pom.xml +++ b/core/esmf-util/pom.xml @@ -1,6 +1,6 @@