diff --git a/.github/detekt.yml b/.github/detekt.yml index 1d15fa7..b53d2ea 100644 --- a/.github/detekt.yml +++ b/.github/detekt.yml @@ -1,4 +1,7 @@ complexity: + CyclomaticComplexMethod: + ignoreFunction: + - "io.github.treesitter.ktreesitter.Query.Companion.init" TooManyFunctions: active: false LongParameterList: diff --git a/.github/scripts/build-jni.ps1 b/.github/scripts/build-jni.ps1 index cc33042..5539ddb 100755 --- a/.github/scripts/build-jni.ps1 +++ b/.github/scripts/build-jni.ps1 @@ -2,7 +2,7 @@ & cmake -S ktreesitter -B ktreesitter/.cmake/build ` -DCMAKE_VERBOSE_MAKEFILE=ON ` - -DCMAKE_INSTALL_PREFIX=ktreesitter/src/jvmMain/resources ` + -DCMAKE_INSTALL_PREFIX=ktreesitter/src/jvmMain/resources ` -DCMAKE_INSTALL_BINDIR="$env:CMAKE_INSTALL_LIBDIR" & cmake --build ktreesitter/.cmake/build --config Debug & cmake --install ktreesitter/.cmake/build --config Debug diff --git a/.github/scripts/build-jni.sh b/.github/scripts/build-jni.sh index 89474b8..85df4b9 100755 --- a/.github/scripts/build-jni.sh +++ b/.github/scripts/build-jni.sh @@ -3,7 +3,7 @@ cmake -S ktreesitter -B ktreesitter/.cmake/build \ -DCMAKE_BUILD_TYPE=RelWithDebugInfo \ -DCMAKE_VERBOSE_MAKEFILE=ON \ - -DCMAKE_OSX_ARCHITECTURES=arm64 \ + -DCMAKE_OSX_ARCHITECTURES='arm64;x86_64' \ -DCMAKE_INSTALL_PREFIX=ktreesitter/src/jvmMain/resources \ -DCMAKE_INSTALL_LIBDIR="$CMAKE_INSTALL_LIBDIR" cmake --build ktreesitter/.cmake/build @@ -12,7 +12,7 @@ cmake --install ktreesitter/.cmake/build for dir in languages/*/; do cmake -S "${dir}build/generated" -B "${dir}.cmake/build" \ -DCMAKE_BUILD_TYPE=RelWithDebugInfo \ - -DCMAKE_OSX_ARCHITECTURES=arm64 \ + -DCMAKE_OSX_ARCHITECTURES='arm64;x86_64' \ -DCMAKE_INSTALL_PREFIX="${dir}build/generated/src/jvmMain/resources" \ -DCMAKE_INSTALL_LIBDIR="$CMAKE_INSTALL_LIBDIR" cmake --build "${dir}.cmake/build" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 52bd8e9..a37448b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -9,6 +9,7 @@ on: - "**/jni/*" - gradle/** - gradle.properties + - ktreesitter/gradle.lockfile pull_request: paths: - "/*.kt" @@ -16,6 +17,7 @@ on: - "**/jni/*" - gradle/** - gradle.properties + - ktreesitter/gradle.lockfile concurrency: cancel-in-progress: true @@ -42,15 +44,13 @@ jobs: cache-dependency-path: | gradle/libs.versions.toml gradle/wrapper/gradle-wrapper.properties - - name: Cache Kotlin/Native prebuilt - uses: actions/cache@v4 + ktreesitter/gradle.lockfile + - name: Set up Kotlin/Native + uses: ObserverOfTime/setup-konan-action@v1 with: - path: ${{runner.tool_cache}}/konan/kotlin-native-prebuilt-* - key: konan-${{runner.os}}-prebuilt-1.9 + kotlin_version: 2.1.21 - name: Generate files run: ./gradlew --no-daemon generateGrammarFiles - env: - KONAN_DATA_DIR: ${{runner.tool_cache}}/konan - name: Upload artifact uses: actions/upload-artifact@v4 with: @@ -113,14 +113,20 @@ jobs: cache-dependency-path: | gradle/libs.versions.toml gradle/wrapper/gradle-wrapper.properties + - name: Set up Kotlin/Native + uses: ObserverOfTime/setup-konan-action@v1 + with: + kotlin_version: 2.1.21 - name: Set up cross compilation - run: sudo apt-get install -qy {binutils,gcc}-aarch64-linux-gnu if: matrix.platform == 'Linux' - - name: Restore Kotlin/Native prebuilt - uses: actions/cache/restore@v4 - with: - path: ${{runner.tool_cache}}/konan/kotlin-native-prebuilt-* - key: konan-${{runner.os}}-prebuilt-1.9 + run: |- + sudo apt-get update + sudo apt-get install -qy {binutils,gcc}-aarch64-linux-gnu + - name: Set up Ninja + if: matrix.platform == 'Android' + run: |- + sudo apt-get update + sudo apt-get install -qy ninja-build - name: Download generated files uses: actions/download-artifact@v4 with: @@ -131,30 +137,8 @@ jobs: run: .github/scripts/build-jni.${{matrix.os == 'windows-latest' && 'ps1' || 'sh'}} env: CMAKE_INSTALL_LIBDIR: lib/${{matrix.lib_platform}}/${{matrix.lib_arch}} - - name: Cache Kotlin/Native dependencies - id: cache-dependencies - uses: actions/cache@v4 - if: matrix.platform != 'JVM' && matrix.platform != 'Android' - with: - path: ${{runner.tool_cache}}/konan/dependencies - key: konan-${{runner.os}}-dependencies - - name: Download Kotlin/Native dependencies - if: matrix.platform == 'macOS/iOS' && steps.cache-dependencies.outputs.cache-hit != 'true' - run: |- - mkdir -p "$RUNNER_TOOL_CACHE/konan/dependencies" - curl -LSs https://download-cdn.jetbrains.com/kotlin/native/$DEP.tar.gz | \ - tar -xzf - -C "$RUNNER_TOOL_CACHE/konan/dependencies" - env: - DEP: apple-llvm-20200714-macos-aarch64-essentials - - name: Set up Ninja - if: matrix.platform == 'Android' - run: |- - sudo apt-get update - sudo apt-get install -y ninja-build - name: Run tests run: ./gradlew --no-daemon ${{matrix.targets}} - env: - KONAN_DATA_DIR: ${{runner.tool_cache}}/konan - name: Report test results uses: mikepenz/action-junit-report@v5 if: matrix.platform == 'JVM' && !cancelled() diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index f013fb7..953e350 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -44,24 +44,22 @@ jobs: cache-dependency-path: | gradle/libs.versions.toml gradle/wrapper/gradle-wrapper.properties - - name: Restore Kotlin/Native prebuilt - uses: actions/cache/restore@v4 + - name: Set up Kotlin/Native + uses: ObserverOfTime/setup-konan-action@v1 with: - path: ${{runner.tool_cache}}/konan/kotlin-native-prebuilt-* - key: konan-${{runner.os}}-prebuilt-1.9 - - name: Restore Kotlin/Native dependencies - uses: actions/cache/restore@v4 - with: - path: ${{runner.tool_cache}}/konan/dependencies - key: konan-${{runner.os}}-dependencies + kotlin_version: 2.1.21 + - name: Set up cross compilation + if: matrix.platform == 'Linux' + run: |- + sudo apt-get update + sudo apt-get install -qy {binutils,gcc}-aarch64-linux-gnu - name: Set up Ninja + if: matrix.platform == 'Android' run: |- sudo apt-get update - sudo apt-get install -y ninja-build + sudo apt-get install -qy ninja-build - name: Build documentation - run: ./gradlew --no-daemon generateFiles :ktreesitter:dokkaHtml - env: - KONAN_DATA_DIR: ${{runner.tool_cache}}/konan + run: ./gradlew --no-daemon generateFiles :ktreesitter:dokkaGeneratePublicationHtml - name: Upload pages artifact uses: actions/upload-pages-artifact@v3 with: diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 36aea66..c182474 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -34,7 +34,7 @@ jobs: java-version: 17 - name: Install ktlint run: |- - curl -sSLO https://github.com/pinterest/ktlint/releases/download/1.3.1/ktlint + curl -sSLO https://github.com/pinterest/ktlint/releases/download/1.6.0/ktlint chmod a+x ktlint && mv ktlint $RUNNER_TOOL_CACHE/ktlint - name: Run ktlint id: ktlint @@ -59,8 +59,8 @@ jobs: java-version: 17 - name: Install detekt run: |- - curl -sSLO https://github.com/detekt/detekt/releases/download/v1.23.7/detekt-cli-1.23.7-all.jar - mv detekt-cli-1.23.7-all.jar $RUNNER_TOOL_CACHE/detekt-cli.jar + curl -sSLO https://github.com/detekt/detekt/releases/download/v1.23.8/detekt-cli-1.23.8-all.jar + mv detekt-cli-1.23.8-all.jar $RUNNER_TOOL_CACHE/detekt-cli.jar - name: Run detekt id: detekt run: >- diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 4b4e134..6e89bf6 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -132,20 +132,20 @@ jobs: cache-dependency-path: | gradle/libs.versions.toml gradle/wrapper/gradle-wrapper.properties - - name: Set up cross compilation - run: sudo apt-get install -qy {binutils,gcc}-aarch64-linux-gnu - if: matrix.platform == 'Linux' || matrix.platform == 'common' - - name: Restore Kotlin/Native prebuilt - uses: actions/cache/restore@v4 + - name: Set up Kotlin/Native + uses: ObserverOfTime/setup-konan-action@v1 with: - path: ${{runner.tool_cache}}/konan/kotlin-native-prebuilt-* - key: konan-${{runner.os}}-prebuilt-1.9 - - name: Restore Kotlin/Native dependencies - uses: actions/cache/restore@v4 - if: matrix.platform != 'JVM' && matrix.platform != 'Android' - with: - path: ${{runner.tool_cache}}/konan/dependencies - key: konan-${{runner.os}}-dependencies + kotlin_version: 2.1.21 + - name: Set up cross compilation + if: matrix.platform == 'Linux' + run: |- + sudo apt-get update + sudo apt-get install -qy {binutils,gcc}-aarch64-linux-gnu + - name: Set up Ninja + if: matrix.platform == 'Android' + run: |- + sudo apt-get update + sudo apt-get install -qy ninja-build - name: Download library artifacts uses: actions/download-artifact@v4 if: matrix.platform == 'JVM' @@ -153,17 +153,11 @@ jobs: path: ktreesitter/src/jvmMain/resources/lib pattern: ktreesitter-lib-* merge-multiple: true - - name: Set up Ninja - if: matrix.platform == 'Android' - run: |- - sudo apt-get update - sudo apt-get install -y ninja-build - name: Build packages run: ./gradlew --no-daemon ${{matrix.targets}} env: SIGNING_KEY: ${{secrets.SIGNING_KEY}} SIGNING_PASSWORD: ${{secrets.SIGNING_PASSWORD}} - KONAN_DATA_DIR: ${{runner.tool_cache}}/konan - name: Upload artifacts uses: actions/upload-artifact@v4 with: @@ -235,14 +229,12 @@ jobs: cache-dependency-path: | gradle/libs.versions.toml gradle/wrapper/gradle-wrapper.properties - - name: Restore Kotlin/Native prebuilt - uses: actions/cache/restore@v4 + - name: Set up Kotlin/Native + uses: ObserverOfTime/setup-konan-action@v1 with: - path: ${{runner.tool_cache}}/konan/kotlin-native-prebuilt-* - key: konan-${{runner.os}}-prebuilt-1.9 + kotlin_version: 2.1.21 - name: Publish Gradle plugin run: ./gradlew --no-daemon :ktreesitter-plugin:publishPlugins env: - KONAN_DATA_DIR: ${{runner.tool_cache}}/konan GRADLE_PUBLISH_KEY: ${{secrets.GRADLE_PUBLISH_KEY}} GRADLE_PUBLISH_SECRET: ${{secrets.GRADLE_PUBLISH_SECRET}} diff --git a/.gitignore b/.gitignore index cff9142..74ee895 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ ### Gradle ### .gradle/ build/ +.kotlin/ kotlin-js-store/ dependency-graph-reports/ local.properties diff --git a/.gitmodules b/.gitmodules index c059394..581ed41 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,7 +1,7 @@ [submodule "tree-sitter"] path = tree-sitter url = https://github.com/tree-sitter/tree-sitter - branch = release-0.24 + branch = release-0.25 [submodule "tree-sitter-java"] path = languages/java/tree-sitter-java diff --git a/.idea/ktlint-plugin.xml b/.idea/ktlint-plugin.xml index bee5678..e68ca2d 100644 --- a/.idea/ktlint-plugin.xml +++ b/.idea/ktlint-plugin.xml @@ -1,6 +1,7 @@ - + DISTRACT_FREE + DEFAULT - \ No newline at end of file + diff --git a/build.gradle.kts b/build.gradle.kts index ef9790e..7f3634f 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -17,6 +17,6 @@ subprojects { } tasks.wrapper { - gradleVersion = "8.7" + gradleVersion = "8.11" distributionType = Wrapper.DistributionType.BIN } diff --git a/gradle.properties b/gradle.properties index 2198304..863a326 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,13 +2,13 @@ project.version=0.24.1 # The Android SDK version that is used to compile the project. -sdk.version.compile=34 +sdk.version.compile=35 # The minimum supported Android SDK version. sdk.version.min=23 # The Android NDK version that is used to compile the project. -ndk.version=26.3.11579264 +ndk.version=27.2.12479018 # The CMake version that is used to compile the project. -cmake.version=3.31.3 +cmake.version=3.31.6 # Specifies the JVM arguments used for the daemon process. org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 @@ -23,6 +23,8 @@ kotlin.code.style=official kotlin.mpp.androidSourceSetLayoutVersion=2 # Enable C interop sharing kotlin.mpp.enableCInteropCommonization=true +# Enable cross-compilation of klib artifacts +kotlin.native.enableKlibsCrossCompilation=true # Disable default stdlib dependency kotlin.stdlib.default.dependency=false # Ignore disabled Kotlin/Native targets @@ -32,3 +34,7 @@ kotlin.native.ignoreDisabledTargets=true android.useAndroidX=true # Disables automatically downloading the Android SDK. android.builder.sdkDownload=false + +# Enables the experimental Dokka V2 mode. +org.jetbrains.dokka.experimental.gradle.pluginMode=V2Enabled +org.jetbrains.dokka.experimental.gradle.pluginMode.noWarn=true diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b6b9ff1..0c600e8 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,61 +1,24 @@ [versions] -kotlin-stdlib = "[1.9,2.0)" -#noinspection GradleDependency -android-gradle = {strictly = "8.2.0"} -kotest = "5.9.1" -dokka = "1.9.20" - -[libraries.kotlin-stdlib] -module = "org.jetbrains.kotlin:kotlin-stdlib" -version.ref = "kotlin-stdlib" - -[libraries.kotest-engine] -module = "io.kotest:kotest-framework-engine" -version.ref = "kotest" - -[libraries.kotest-assertions] -module = "io.kotest:kotest-assertions-core" -version.ref = "kotest" - -[libraries.kotest-junit-runner] -module = "io.kotest:kotest-runner-junit5" -version.ref = "kotest" - -[libraries.kotest-junit-reporter] -module = "io.kotest:kotest-extensions-junitxml" -version.ref = "kotest" - -[libraries.kotest-android-runner] -module = "br.com.colman:kotest-runner-android" -version = "1.1.1" - -[libraries.androidx-test-runner] -module = "androidx.test:runner" -version = "1.5.2" - -[libraries.dokka-base] -module = "org.jetbrains.dokka:dokka-base" -version.ref = "dokka" - -[plugins.kotlin-mpp] -id = "org.jetbrains.kotlin.multiplatform" -version.ref = "kotlin-stdlib" - -[plugins.android-library] -id = "com.android.library" -version.ref = "android-gradle" - -[plugins.kotest] -id = "io.kotest.multiplatform" -version.ref = "kotest" - -[plugins.dokka] -id = "org.jetbrains.dokka" -version.ref = "dokka" - -[plugins.gradle-publish] -id = "com.gradle.plugin-publish" -version = "1.2.1" +kotlin-stdlib = "2.1.+" +android-gradle = {strictly = "8.8.2"} +kotest = "6.0.0.M3" +dokka = "2.0.0" + +[libraries] +kotlin-stdlib = { module = "org.jetbrains.kotlin:kotlin-stdlib", version.ref = "kotlin-stdlib" } +kotest-engine = { module = "io.kotest:kotest-framework-engine", version.ref = "kotest" } +kotest-assertions = { module = "io.kotest:kotest-assertions-core", version.ref = "kotest" } +kotest-junit-runner = { module = "io.kotest:kotest-runner-junit5", version.ref = "kotest" } +kotest-junit-reporter = { module = "io.kotest:kotest-extensions-junitxml", version.ref = "kotest" } +kotest-android-runner = { module = "br.com.colman:kotest-runner-android", version = "1.1.1" } +androidx-test-runner = { module = "androidx.test:runner", version = "1.6.2" } +dokka-base = { module = "org.jetbrains.dokka:dokka-base", version.ref = "dokka" } + +[plugins] +kotlin-mpp = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin-stdlib" } +android-library = { id = "com.android.library", version.ref = "android-gradle" } +kotest = { id = "io.kotest.multiplatform", version.ref = "kotest" } +dokka = { id = "org.jetbrains.dokka", version.ref = "dokka" } [bundles] kotest-core = [ diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index d64cd49..a4b76b9 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index b82aa23..94113f2 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.11-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew index 1aa94a4..f5feea6 100755 --- a/gradlew +++ b/gradlew @@ -15,6 +15,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +# SPDX-License-Identifier: Apache-2.0 +# ############################################################################## # @@ -55,7 +57,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. @@ -84,7 +86,8 @@ done # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) -APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s +' "$PWD" ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum diff --git a/gradlew.bat b/gradlew.bat index 6689b85..9b42019 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -13,6 +13,8 @@ @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @@ -43,11 +45,11 @@ set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail @@ -57,11 +59,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail diff --git a/ktreesitter-plugin/README.md b/ktreesitter-plugin/README.md index 0fdc9f3..21c6421 100644 --- a/ktreesitter-plugin/README.md +++ b/ktreesitter-plugin/README.md @@ -35,10 +35,5 @@ grammar { className = "TreeSitterJava" // The name of the package packageName = "io.github.treesitter.ktreesitter.java" - // The source files of the grammar - files = arrayOf( - baseDir.get().resolve("src/parser.c"), - // baseDir.get().resolve("src/scanner.c") - ) } ``` diff --git a/ktreesitter-plugin/build.gradle.kts b/ktreesitter-plugin/build.gradle.kts index c22bc08..19d39b3 100644 --- a/ktreesitter-plugin/build.gradle.kts +++ b/ktreesitter-plugin/build.gradle.kts @@ -8,7 +8,7 @@ version = with(Properties()) { plugins { `java-gradle-plugin` - id("com.gradle.plugin-publish") version "1.2.1" + id("com.gradle.plugin-publish") version "1.3.1" } repositories { @@ -20,7 +20,6 @@ java { targetCompatibility = JavaVersion.VERSION_17 } -@Suppress("UnstableApiUsage") gradlePlugin { vcsUrl = "https://github.com/tree-sitter/kotlin-tree-sitter" website = "https://github.com/tree-sitter/kotlin-tree-sitter/tree/master/ktreesitter-plugin" diff --git a/ktreesitter-plugin/src/main/java/io/github/treesitter/ktreesitter/plugin/GrammarFilesTask.java b/ktreesitter-plugin/src/main/java/io/github/treesitter/ktreesitter/plugin/GrammarFilesTask.java index bd35b28..e443c62 100644 --- a/ktreesitter-plugin/src/main/java/io/github/treesitter/ktreesitter/plugin/GrammarFilesTask.java +++ b/ktreesitter-plugin/src/main/java/io/github/treesitter/ktreesitter/plugin/GrammarFilesTask.java @@ -6,6 +6,7 @@ import java.nio.charset.StandardCharsets; import java.nio.file.Path; import java.util.Arrays; +import java.util.List; import java.util.Map; import java.util.Objects; import java.util.regex.Pattern; @@ -25,8 +26,6 @@ public abstract class GrammarFilesTask extends DefaultTask { private String grammarName; - private File[] grammarFiles; - private String interopName; private String libraryName; @@ -63,18 +62,6 @@ public final void setGrammarName(String grammarName) { this.grammarName = grammarName; } - /** Get the source files of the grammar. */ - @InputFiles - @PathSensitive(PathSensitivity.RELATIVE) - public final File[] getGrammarFiles() { - return grammarFiles; - } - - /** Set the source files of the grammar. */ - public final void setGrammarFiles(File[] grammarFiles) { - this.grammarFiles = grammarFiles; - } - /** Get the name of the C interop def file. */ @Input public final String getInteropName() { @@ -281,9 +268,8 @@ jniPrefix, jniTransform(name), name private void generateCmakeLists(Path srcDir) throws GradleException { var jniBinding = srcDir.resolve("jni").resolve("binding.c"); - var files = Arrays.stream(grammarFiles).map(file -> relative(file.toPath()).toString()); var includeDir = relative(grammarDir.toPath().resolve("bindings/c")); - var sources = relative(jniBinding) + " " + String.join(" ", files.toList()); + var sources = String.format("%s %s", relative(jniBinding), srcFiles()); var template = readResource("CMakeLists.txt.in") .replace("@LIBRARY@", libraryName) .replace("@INCLUDE@", includeDir.toString()) @@ -305,6 +291,15 @@ private Path relative(Path file) { return getGeneratedSrc().get().getAsFile().toPath().getParent().relativize(file); } + private String srcFiles() { + var grammarSrcDir = grammarDir.toPath().resolve("src"); + var scannerFile = grammarSrcDir.resolve("scanner.c"); + if (!scannerFile.toFile().exists()) { + return grammarSrcDir.resolve("parser.c").toString(); + } + return String.format("%s %s", grammarSrcDir.resolve("parser.c"), scannerFile); + } + private String readResource(String file) throws GradleException { try (var stream = getClass().getResourceAsStream("/" + file)) { var bytes = Objects.requireNonNull(stream).readAllBytes(); diff --git a/ktreesitter-plugin/src/main/java/io/github/treesitter/ktreesitter/plugin/GrammarPlugin.java b/ktreesitter-plugin/src/main/java/io/github/treesitter/ktreesitter/plugin/GrammarPlugin.java index ef6953a..0bfc12f 100644 --- a/ktreesitter-plugin/src/main/java/io/github/treesitter/ktreesitter/plugin/GrammarPlugin.java +++ b/ktreesitter-plugin/src/main/java/io/github/treesitter/ktreesitter/plugin/GrammarPlugin.java @@ -30,7 +30,6 @@ public void apply(Project project) { project.getTasks().register("generateGrammarFiles", GrammarFilesTask.class, it -> { it.setGrammarDir(extension.getBaseDir().get()); it.setGrammarName(extension.getGrammarName().get()); - it.setGrammarFiles(extension.getFiles().get()); it.setInteropName(extension.getInteropName().get()); it.setLibraryName(extension.getLibraryName().get()); it.setPackageName(extension.getPackageName().get()); diff --git a/ktreesitter-plugin/src/main/resources/CMakeLists.txt.in b/ktreesitter-plugin/src/main/resources/CMakeLists.txt.in index 067086f..67e8422 100644 --- a/ktreesitter-plugin/src/main/resources/CMakeLists.txt.in +++ b/ktreesitter-plugin/src/main/resources/CMakeLists.txt.in @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.12.0) -project(ktreesitter-java LANGUAGES C) +project(@LIBRARY@ LANGUAGES C) find_package(JNI REQUIRED) @@ -10,12 +10,12 @@ set(CMAKE_C_STANDARD 11) if(MSVC) add_compile_options(/W3 /wd4244) -else(MSVC) +else() set(CMAKE_C_VISIBILITY_PRESET hidden) add_compile_options(-Wall -Wextra -Wno-unused-parameter -Werror=implicit-function-declaration) -endif(MSVC) +endif() include_directories(${JNI_INCLUDE_DIRS} @INCLUDE@) diff --git a/ktreesitter-plugin/src/main/resources/android.kt.in b/ktreesitter-plugin/src/main/resources/android.kt.in index e24a6d0..27a4d2c 100644 --- a/ktreesitter-plugin/src/main/resources/android.kt.in +++ b/ktreesitter-plugin/src/main/resources/android.kt.in @@ -12,5 +12,4 @@ actual object @CLASS@ { System.loadLibrary("@LIBRARY@") } -@METHODS@ -} +@METHODS@} diff --git a/ktreesitter-plugin/src/main/resources/jvm.kt.in b/ktreesitter-plugin/src/main/resources/jvm.kt.in index 8a5b180..6021d01 100644 --- a/ktreesitter-plugin/src/main/resources/jvm.kt.in +++ b/ktreesitter-plugin/src/main/resources/jvm.kt.in @@ -20,7 +20,6 @@ actual object @CLASS@ { } @METHODS@ - @JvmStatic @Suppress("ConvertToStringTemplate") @Throws(UnsupportedOperationException::class) diff --git a/ktreesitter/CMakeLists.txt b/ktreesitter/CMakeLists.txt index fdc786f..0e1d75c 100644 --- a/ktreesitter/CMakeLists.txt +++ b/ktreesitter/CMakeLists.txt @@ -11,20 +11,20 @@ set(CMAKE_C_STANDARD 11) if(MSVC) add_compile_options(/W3 /wd4244) -else(MSVC) +else() set(CMAKE_C_VISIBILITY_PRESET hidden) add_compile_options(-Wall -Wextra -Wno-unused-parameter -Wno-cast-function-type -Werror=incompatible-pointer-types -Werror=implicit-function-declaration) -endif(MSVC) +endif() include_directories(${JNI_INCLUDE_DIRS} ../tree-sitter/lib/src ../tree-sitter/lib/include) -add_compile_definitions(TREE_SITTER_HIDE_SYMBOLS) +add_compile_definitions(TREE_SITTER_HIDE_SYMBOLS _DEFAULT_SOURCE _POSIX_C_SOURCE=200112L) add_library(ktreesitter SHARED ./src/jni/language.c @@ -32,6 +32,7 @@ add_library(ktreesitter SHARED ./src/jni/node.c ./src/jni/parser.c ./src/jni/query.c + ./src/jni/query_cursor.c ./src/jni/tree.c ./src/jni/tree_cursor.c ./src/jni/module.c diff --git a/ktreesitter/build.gradle.kts b/ktreesitter/build.gradle.kts index b2acb3b..d97adf3 100644 --- a/ktreesitter/build.gradle.kts +++ b/ktreesitter/build.gradle.kts @@ -1,18 +1,28 @@ import java.io.OutputStream.nullOutputStream -import java.net.URI import org.gradle.internal.os.OperatingSystem import org.gradle.kotlin.dsl.support.useToRun -import org.jetbrains.dokka.base.DokkaBase -import org.jetbrains.dokka.base.DokkaBaseConfiguration +import org.jetbrains.dokka.gradle.tasks.DokkaGeneratePublicationTask import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi import org.jetbrains.kotlin.gradle.dsl.JvmTarget +import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget import org.jetbrains.kotlin.gradle.tasks.CInteropProcess import org.jetbrains.kotlin.gradle.tasks.KotlinJvmCompile -import org.jetbrains.kotlin.konan.target.PlatformManager inline val File.unixPath: String get() = if (!os.isWindows) path else path.replace("\\", "/") +fun KotlinNativeTarget.treesitter() { + compilations.configureEach { + cinterops.create("treesitter") { + val srcDir = treesitterDir.resolve("lib/src") + val includeDir = treesitterDir.resolve("lib/include") + includeDirs.allHeaders(srcDir, includeDir) + includeDirs.headerFilterOnly(includeDir) + extraOpts("-libraryPath", libsDir.dir(konanTarget.name)) + } + } +} + val os: OperatingSystem = OperatingSystem.current() val libsDir = layout.buildDirectory.get().dir("libs") val treesitterDir = rootDir.resolve("tree-sitter") @@ -34,6 +44,10 @@ buildscript { } } +dependencyLocking { + lockAllConfigurations() +} + kotlin { jvm {} @@ -42,30 +56,15 @@ kotlin { publishLibraryVariants("release") } - when { - os.isLinux -> listOf(linuxX64(), linuxArm64()) - os.isWindows -> listOf(mingwX64()) - os.isMacOsX -> listOf( - macosArm64(), - macosX64(), - iosArm64(), - iosSimulatorArm64() - ) - else -> { - val arch = System.getProperty("os.arch") - throw GradleException("Unsupported platform: $os ($arch)") - } - }.forEach { target -> - target.compilations.configureEach { - cinterops.create("treesitter") { - val srcDir = treesitterDir.resolve("lib/src") - val includeDir = treesitterDir.resolve("lib/include") - includeDirs.allHeaders(srcDir, includeDir) - includeDirs.headerFilterOnly(includeDir) - extraOpts("-libraryPath", libsDir.dir(konanTarget.name)) - } - } - } + linuxX64 { treesitter() } + linuxArm64 { treesitter() } + mingwX64 { treesitter() } + macosArm64 { treesitter() } + macosX64 { treesitter() } + iosArm64 { treesitter() } + iosSimulatorArm64 { treesitter() } + + applyDefaultHierarchyTemplate() jvmToolchain(17) @@ -117,7 +116,6 @@ android { defaultConfig { minSdk = (property("sdk.version.min") as String).toInt() ndk { - moduleName = "ktreesitter" //noinspection ChromeOsAbiSupport abiFilters += setOf("x86_64", "arm64-v8a", "armeabi-v7a") } @@ -214,31 +212,33 @@ signing { sign(publishing.publications) } -tasks.dokkaHtml { +dokka { val tmpDir = layout.buildDirectory.get().dir("tmp") val ref = System.getenv("GITHUB_SHA")?.subSequence(0, 7) ?: "master" val url = "https://github.com/tree-sitter/kotlin-tree-sitter/blob/$ref/ktreesitter" - inputs.file(file("README.md")) - moduleName.set("KTreeSitter") - pluginConfiguration { + pluginsConfiguration.html { footerMessage = "© 2024 tree-sitter" homepageLink = "https://tree-sitter.github.io/tree-sitter/" - customAssets = listOf(rootDir.resolve("gradle/logo-icon.svg")) + customAssets.from(rootDir.resolve("gradle/logo-icon.svg")) } dokkaSourceSets.configureEach { jdkVersion.set(17) - noStdlibLink.set(true) includes.from(tmpDir.file("README.md")) - externalDocumentationLink("https://kotlinlang.org/api/core/") sourceLink { + remoteUrl(url) localDirectory.set(projectDir) - remoteUrl.set(URI.create(url).toURL()) } } +} + +tasks.withType { + val tmpDir = layout.buildDirectory.get().dir("tmp") + + inputs.file("README.md") doFirst { copy { @@ -264,6 +264,8 @@ tasks.withType().configureEach { } } +// TODO: replace with cmake +@Suppress("DEPRECATION") tasks.withType().configureEach { if (name.startsWith("cinteropTest")) return@configureEach @@ -273,17 +275,16 @@ tasks.withType().configureEach { "${konanTarget.family.staticPrefix}tree-sitter.${konanTarget.family.staticSuffix}" ).asFile val objectFile = treesitterDir.resolve("lib.o") - val loader = PlatformManager(konanHome.get(), false, konanDataDir.orNull).loader(konanTarget) doFirst { - if (!File(loader.absoluteTargetToolchain).isDirectory) loader.downloadDependencies() - val argsFile = File.createTempFile("args", null) argsFile.deleteOnExit() argsFile.writer().useToRun { write("-I" + treesitterDir.resolve("lib/src").unixPath + "\n") write("-I" + treesitterDir.resolve("lib/include").unixPath + "\n") write("-DTREE_SITTER_HIDE_SYMBOLS\n") + write("-D_DEFAULT_SOURCE\n") + write("-D_POSIX_C_SOURCE=200112L\n") write("-fvisibility=hidden\n") write("-std=c11\n") write("-O2\n") diff --git a/ktreesitter/gradle.lockfile b/ktreesitter/gradle.lockfile new file mode 100644 index 0000000..6be66b0 --- /dev/null +++ b/ktreesitter/gradle.lockfile @@ -0,0 +1,235 @@ +# This is a Gradle generated file for dependency locking. +# Manual edits can break the build and are not advised. +# This file is expected to be part of source control. +androidx.annotation:annotation-jvm:1.7.0-beta01=androidDebugAndroidTestCompileClasspath,androidDebugAndroidTestRuntimeClasspath,debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath +androidx.annotation:annotation:1.7.0-beta01=allInstrumentedTestSourceSetsCompileDependenciesMetadata,androidDebugAndroidTestCompileClasspath,androidDebugAndroidTestRuntimeClasspath,androidInstrumentedTestApiDependenciesMetadata,androidInstrumentedTestCompileOnlyDependenciesMetadata,androidInstrumentedTestImplementationDependenciesMetadata,androidInstrumentedTestResolvableDependenciesMetadata,debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath +androidx.test.services:storage:1.5.0=allInstrumentedTestSourceSetsCompileDependenciesMetadata,androidDebugAndroidTestCompileClasspath,androidDebugAndroidTestRuntimeClasspath,androidInstrumentedTestApiDependenciesMetadata,androidInstrumentedTestCompileOnlyDependenciesMetadata,androidInstrumentedTestImplementationDependenciesMetadata,androidInstrumentedTestResolvableDependenciesMetadata,debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath +androidx.test:monitor:1.7.2=allInstrumentedTestSourceSetsCompileDependenciesMetadata,androidDebugAndroidTestCompileClasspath,androidDebugAndroidTestRuntimeClasspath,androidInstrumentedTestApiDependenciesMetadata,androidInstrumentedTestCompileOnlyDependenciesMetadata,androidInstrumentedTestImplementationDependenciesMetadata,androidInstrumentedTestResolvableDependenciesMetadata,debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath +androidx.test:runner:1.6.2=allInstrumentedTestSourceSetsCompileDependenciesMetadata,androidDebugAndroidTestCompileClasspath,androidDebugAndroidTestRuntimeClasspath,androidInstrumentedTestApiDependenciesMetadata,androidInstrumentedTestCompileOnlyDependenciesMetadata,androidInstrumentedTestImplementationDependenciesMetadata,androidInstrumentedTestResolvableDependenciesMetadata,debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath +androidx.tracing:tracing:1.1.0=allInstrumentedTestSourceSetsCompileDependenciesMetadata,androidDebugAndroidTestCompileClasspath,androidDebugAndroidTestRuntimeClasspath,androidInstrumentedTestApiDependenciesMetadata,androidInstrumentedTestCompileOnlyDependenciesMetadata,androidInstrumentedTestImplementationDependenciesMetadata,androidInstrumentedTestResolvableDependenciesMetadata,debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath +br.com.colman:kotest-runner-android:1.1.1=allInstrumentedTestSourceSetsCompileDependenciesMetadata,androidDebugAndroidTestCompileClasspath,androidDebugAndroidTestRuntimeClasspath,androidInstrumentedTestApiDependenciesMetadata,androidInstrumentedTestCompileOnlyDependenciesMetadata,androidInstrumentedTestImplementationDependenciesMetadata,androidInstrumentedTestResolvableDependenciesMetadata,debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath +com.android.tools.ddms:ddmlib:31.8.2=_internal-unified-test-platform-android-device-provider-ddmlib +com.android.tools.emulator:proto:31.8.2=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention +com.android.tools.utp:android-device-provider-ddmlib-proto:31.8.2=_internal-unified-test-platform-android-device-provider-ddmlib +com.android.tools.utp:android-device-provider-ddmlib:31.8.2=_internal-unified-test-platform-android-device-provider-ddmlib +com.android.tools.utp:android-device-provider-gradle-proto:31.8.2=_internal-unified-test-platform-android-device-provider-gradle +com.android.tools.utp:android-device-provider-gradle:31.8.2=_internal-unified-test-platform-android-device-provider-gradle +com.android.tools.utp:android-device-provider-profile-proto:31.8.2=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle +com.android.tools.utp:android-device-provider-profile:31.8.2=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle +com.android.tools.utp:android-test-plugin-host-additional-test-output-proto:31.8.2=_internal-unified-test-platform-android-test-plugin-host-additional-test-output +com.android.tools.utp:android-test-plugin-host-additional-test-output:31.8.2=_internal-unified-test-platform-android-test-plugin-host-additional-test-output +com.android.tools.utp:android-test-plugin-host-apk-installer-proto:31.8.2=_internal-unified-test-platform-android-test-plugin-host-apk-installer +com.android.tools.utp:android-test-plugin-host-apk-installer:31.8.2=_internal-unified-test-platform-android-test-plugin-host-apk-installer +com.android.tools.utp:android-test-plugin-host-coverage-proto:31.8.2=_internal-unified-test-platform-android-test-plugin-host-coverage +com.android.tools.utp:android-test-plugin-host-coverage:31.8.2=_internal-unified-test-platform-android-test-plugin-host-coverage +com.android.tools.utp:android-test-plugin-host-device-info-proto:31.8.2=_internal-unified-test-platform-android-test-plugin-host-device-info +com.android.tools.utp:android-test-plugin-host-device-info:31.8.2=_internal-unified-test-platform-android-test-plugin-host-device-info +com.android.tools.utp:android-test-plugin-host-emulator-control-proto:31.8.2=_internal-unified-test-platform-android-test-plugin-host-emulator-control +com.android.tools.utp:android-test-plugin-host-emulator-control:31.8.2=_internal-unified-test-platform-android-test-plugin-host-emulator-control +com.android.tools.utp:android-test-plugin-host-logcat-proto:31.8.2=_internal-unified-test-platform-android-test-plugin-host-logcat +com.android.tools.utp:android-test-plugin-host-logcat:31.8.2=_internal-unified-test-platform-android-test-plugin-host-logcat +com.android.tools.utp:android-test-plugin-host-retention-proto:31.8.2=_internal-unified-test-platform-android-test-plugin-host-retention +com.android.tools.utp:android-test-plugin-host-retention:31.8.2=_internal-unified-test-platform-android-test-plugin-host-retention +com.android.tools.utp:android-test-plugin-result-listener-gradle-proto:31.8.2=_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.android.tools.utp:android-test-plugin-result-listener-gradle:31.8.2=_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.android.tools.utp:utp-common:31.8.2=_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention +com.android.tools:annotations:31.8.2=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.android.tools:common:31.8.2=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.fasterxml.jackson.core:jackson-annotations:2.12.7=dokkaHtmlGeneratorRuntimeResolver~internal +com.fasterxml.jackson.core:jackson-core:2.12.7=dokkaHtmlGeneratorRuntimeResolver~internal +com.fasterxml.jackson.core:jackson-databind:2.12.7.1=dokkaHtmlGeneratorRuntimeResolver~internal +com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.12.7=dokkaHtmlGeneratorRuntimeResolver~internal +com.fasterxml.jackson.module:jackson-module-jaxb-annotations:2.12.7=dokkaHtmlGeneratorRuntimeResolver~internal +com.fasterxml.jackson.module:jackson-module-kotlin:2.12.7=dokkaHtmlGeneratorRuntimeResolver~internal +com.fasterxml.jackson:jackson-bom:2.12.7=dokkaHtmlGeneratorRuntimeResolver~internal +com.fasterxml.woodstox:woodstox-core:6.2.4=dokkaHtmlGeneratorRuntimeResolver~internal +com.github.ajalt:colormath:1.2.0=androidDebugAndroidTestCompileClasspath,androidDebugAndroidTestRuntimeClasspath,androidDebugUnitTestCompileClasspath,androidDebugUnitTestRuntimeClasspath,androidReleaseUnitTestCompileClasspath,androidReleaseUnitTestRuntimeClasspath,debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,jvmTestCompileClasspath,jvmTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +com.github.ajalt:mordant:1.2.1=androidDebugAndroidTestCompileClasspath,androidDebugAndroidTestRuntimeClasspath,androidDebugUnitTestCompileClasspath,androidDebugUnitTestRuntimeClasspath,androidReleaseUnitTestCompileClasspath,androidReleaseUnitTestRuntimeClasspath,debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,jvmTestCompileClasspath,jvmTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +com.google.android:annotations:4.1.1.4=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.google.api.grpc:proto-google-common-protos:2.17.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.google.code.findbugs:jsr305:3.0.2=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.google.code.gson:gson:2.10.1=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.google.crypto.tink:tink:1.7.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control +com.google.errorprone:error_prone_annotations:2.18.0=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.google.guava:failureaccess:1.0.1=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.google.guava:guava:32.0.1-jre=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.google.j2objc:j2objc-annotations:2.8=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.google.protobuf:protobuf-java:3.22.3=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.google.testing.platform:android-device-provider-local:0.0.9-alpha02=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.google.testing.platform:android-driver-instrumentation:0.0.9-alpha02=_internal-unified-test-platform-android-driver-instrumentation,_internal-unified-test-platform-android-test-plugin-host-emulator-control +com.google.testing.platform:android-test-plugin:0.0.9-alpha02=_internal-unified-test-platform-android-test-plugin +com.google.testing.platform:core-proto:0.0.9-alpha02=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +com.google.testing.platform:core:0.0.9-alpha02=_internal-unified-test-platform-core +com.google.testing.platform:launcher:0.0.9-alpha02=_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-launcher +commons-io:commons-io:2.13.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention +io.github.classgraph:classgraph:4.8.172=androidDebugAndroidTestRuntimeClasspath,debugAndroidTestRuntimeClasspath +io.github.java-diff-utils:java-diff-utils:4.12=androidDebugAndroidTestRuntimeClasspath,androidDebugUnitTestRuntimeClasspath,androidReleaseUnitTestRuntimeClasspath,debugAndroidTestRuntimeClasspath,debugUnitTestRuntimeClasspath,jvmTestRuntimeClasspath,releaseUnitTestRuntimeClasspath +io.grpc:grpc-api:1.57.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.grpc:grpc-context:1.57.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.grpc:grpc-core:1.57.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.grpc:grpc-netty:1.57.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.grpc:grpc-protobuf-lite:1.57.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.grpc:grpc-protobuf:1.57.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.grpc:grpc-stub:1.57.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.kotest:kotest-assertions-core-iosarm64:6.0.0.M3=iosArm64TestCInterop,iosArm64TestCompilationDependenciesMetadata,iosArm64TestCompileKlibraries +io.kotest:kotest-assertions-core-iossimulatorarm64:6.0.0.M3=iosSimulatorArm64TestCInterop,iosSimulatorArm64TestCompilationDependenciesMetadata,iosSimulatorArm64TestCompileKlibraries +io.kotest:kotest-assertions-core-jvm:6.0.0.M3=androidDebugAndroidTestCompileClasspath,androidDebugAndroidTestRuntimeClasspath,androidDebugUnitTestCompileClasspath,androidDebugUnitTestRuntimeClasspath,androidReleaseUnitTestCompileClasspath,androidReleaseUnitTestRuntimeClasspath,debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,jvmTestCompileClasspath,jvmTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +io.kotest:kotest-assertions-core-linuxarm64:6.0.0.M3=linuxArm64TestCInterop,linuxArm64TestCompilationDependenciesMetadata,linuxArm64TestCompileKlibraries +io.kotest:kotest-assertions-core-linuxx64:6.0.0.M3=linuxX64TestCInterop,linuxX64TestCompilationDependenciesMetadata,linuxX64TestCompileKlibraries +io.kotest:kotest-assertions-core-macosarm64:6.0.0.M3=macosArm64TestCInterop,macosArm64TestCompilationDependenciesMetadata,macosArm64TestCompileKlibraries +io.kotest:kotest-assertions-core-macosx64:6.0.0.M3=macosX64TestCInterop,macosX64TestCompilationDependenciesMetadata,macosX64TestCompileKlibraries +io.kotest:kotest-assertions-core-mingwx64:6.0.0.M3=mingwX64TestCInterop,mingwX64TestCompilationDependenciesMetadata,mingwX64TestCompileKlibraries +io.kotest:kotest-assertions-core:6.0.0.M3=allInstrumentedTestSourceSetsCompileDependenciesMetadata,allTestSourceSetsCompileDependenciesMetadata,androidDebugAndroidTestCompileClasspath,androidDebugAndroidTestRuntimeClasspath,androidDebugUnitTestCompileClasspath,androidDebugUnitTestRuntimeClasspath,androidInstrumentedTestApiDependenciesMetadata,androidInstrumentedTestCompileOnlyDependenciesMetadata,androidInstrumentedTestImplementationDependenciesMetadata,androidInstrumentedTestResolvableDependenciesMetadata,androidReleaseUnitTestCompileClasspath,androidReleaseUnitTestRuntimeClasspath,androidUnitTestApiDependenciesMetadata,androidUnitTestCompileOnlyDependenciesMetadata,androidUnitTestDebugApiDependenciesMetadata,androidUnitTestDebugCompileOnlyDependenciesMetadata,androidUnitTestDebugImplementationDependenciesMetadata,androidUnitTestDebugResolvableDependenciesMetadata,androidUnitTestImplementationDependenciesMetadata,androidUnitTestReleaseApiDependenciesMetadata,androidUnitTestReleaseCompileOnlyDependenciesMetadata,androidUnitTestReleaseImplementationDependenciesMetadata,androidUnitTestReleaseResolvableDependenciesMetadata,androidUnitTestResolvableDependenciesMetadata,appleTestApiDependenciesMetadata,appleTestCompileOnlyDependenciesMetadata,appleTestImplementationDependenciesMetadata,appleTestResolvableDependenciesMetadata,commonTestApiDependenciesMetadata,commonTestCompileOnlyDependenciesMetadata,commonTestImplementationDependenciesMetadata,commonTestResolvableDependenciesMetadata,debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,iosArm64TestApiDependenciesMetadata,iosArm64TestCInterop,iosArm64TestCompilationDependenciesMetadata,iosArm64TestCompileKlibraries,iosArm64TestCompileOnlyDependenciesMetadata,iosArm64TestImplementationDependenciesMetadata,iosArm64TestResolvableDependenciesMetadata,iosSimulatorArm64TestApiDependenciesMetadata,iosSimulatorArm64TestCInterop,iosSimulatorArm64TestCompilationDependenciesMetadata,iosSimulatorArm64TestCompileKlibraries,iosSimulatorArm64TestCompileOnlyDependenciesMetadata,iosSimulatorArm64TestImplementationDependenciesMetadata,iosSimulatorArm64TestResolvableDependenciesMetadata,iosTestApiDependenciesMetadata,iosTestCompileOnlyDependenciesMetadata,iosTestImplementationDependenciesMetadata,iosTestResolvableDependenciesMetadata,jvmTestApiDependenciesMetadata,jvmTestCompileClasspath,jvmTestCompileOnlyDependenciesMetadata,jvmTestImplementationDependenciesMetadata,jvmTestResolvableDependenciesMetadata,jvmTestRuntimeClasspath,linuxArm64TestApiDependenciesMetadata,linuxArm64TestCInterop,linuxArm64TestCompilationDependenciesMetadata,linuxArm64TestCompileKlibraries,linuxArm64TestCompileOnlyDependenciesMetadata,linuxArm64TestImplementationDependenciesMetadata,linuxArm64TestResolvableDependenciesMetadata,linuxTestApiDependenciesMetadata,linuxTestCompileOnlyDependenciesMetadata,linuxTestImplementationDependenciesMetadata,linuxTestResolvableDependenciesMetadata,linuxX64TestApiDependenciesMetadata,linuxX64TestCInterop,linuxX64TestCompilationDependenciesMetadata,linuxX64TestCompileKlibraries,linuxX64TestCompileOnlyDependenciesMetadata,linuxX64TestImplementationDependenciesMetadata,linuxX64TestResolvableDependenciesMetadata,macosArm64TestApiDependenciesMetadata,macosArm64TestCInterop,macosArm64TestCompilationDependenciesMetadata,macosArm64TestCompileKlibraries,macosArm64TestCompileOnlyDependenciesMetadata,macosArm64TestImplementationDependenciesMetadata,macosArm64TestResolvableDependenciesMetadata,macosTestApiDependenciesMetadata,macosTestCompileOnlyDependenciesMetadata,macosTestImplementationDependenciesMetadata,macosTestResolvableDependenciesMetadata,macosX64TestApiDependenciesMetadata,macosX64TestCInterop,macosX64TestCompilationDependenciesMetadata,macosX64TestCompileKlibraries,macosX64TestCompileOnlyDependenciesMetadata,macosX64TestImplementationDependenciesMetadata,macosX64TestResolvableDependenciesMetadata,mingwTestApiDependenciesMetadata,mingwTestCompileOnlyDependenciesMetadata,mingwTestImplementationDependenciesMetadata,mingwTestResolvableDependenciesMetadata,mingwX64TestApiDependenciesMetadata,mingwX64TestCInterop,mingwX64TestCompilationDependenciesMetadata,mingwX64TestCompileKlibraries,mingwX64TestCompileOnlyDependenciesMetadata,mingwX64TestImplementationDependenciesMetadata,mingwX64TestResolvableDependenciesMetadata,nativeTestApiDependenciesMetadata,nativeTestCompileOnlyDependenciesMetadata,nativeTestImplementationDependenciesMetadata,nativeTestResolvableDependenciesMetadata,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +io.kotest:kotest-assertions-shared-iosarm64:6.0.0.M3=iosArm64TestCInterop,iosArm64TestCompilationDependenciesMetadata,iosArm64TestCompileKlibraries +io.kotest:kotest-assertions-shared-iossimulatorarm64:6.0.0.M3=iosSimulatorArm64TestCInterop,iosSimulatorArm64TestCompilationDependenciesMetadata,iosSimulatorArm64TestCompileKlibraries +io.kotest:kotest-assertions-shared-jvm:6.0.0.M3=androidDebugAndroidTestCompileClasspath,androidDebugAndroidTestRuntimeClasspath,androidDebugUnitTestCompileClasspath,androidDebugUnitTestRuntimeClasspath,androidReleaseUnitTestCompileClasspath,androidReleaseUnitTestRuntimeClasspath,debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,jvmTestCompileClasspath,jvmTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +io.kotest:kotest-assertions-shared-linuxarm64:6.0.0.M3=linuxArm64TestCInterop,linuxArm64TestCompilationDependenciesMetadata,linuxArm64TestCompileKlibraries +io.kotest:kotest-assertions-shared-linuxx64:6.0.0.M3=linuxX64TestCInterop,linuxX64TestCompilationDependenciesMetadata,linuxX64TestCompileKlibraries +io.kotest:kotest-assertions-shared-macosarm64:6.0.0.M3=macosArm64TestCInterop,macosArm64TestCompilationDependenciesMetadata,macosArm64TestCompileKlibraries +io.kotest:kotest-assertions-shared-macosx64:6.0.0.M3=macosX64TestCInterop,macosX64TestCompilationDependenciesMetadata,macosX64TestCompileKlibraries +io.kotest:kotest-assertions-shared-mingwx64:6.0.0.M3=mingwX64TestCInterop,mingwX64TestCompilationDependenciesMetadata,mingwX64TestCompileKlibraries +io.kotest:kotest-assertions-shared:6.0.0.M3=allInstrumentedTestSourceSetsCompileDependenciesMetadata,allTestSourceSetsCompileDependenciesMetadata,androidDebugAndroidTestCompileClasspath,androidDebugAndroidTestRuntimeClasspath,androidDebugUnitTestCompileClasspath,androidDebugUnitTestRuntimeClasspath,androidInstrumentedTestApiDependenciesMetadata,androidInstrumentedTestCompileOnlyDependenciesMetadata,androidInstrumentedTestImplementationDependenciesMetadata,androidInstrumentedTestResolvableDependenciesMetadata,androidReleaseUnitTestCompileClasspath,androidReleaseUnitTestRuntimeClasspath,androidUnitTestApiDependenciesMetadata,androidUnitTestCompileOnlyDependenciesMetadata,androidUnitTestDebugApiDependenciesMetadata,androidUnitTestDebugCompileOnlyDependenciesMetadata,androidUnitTestDebugImplementationDependenciesMetadata,androidUnitTestDebugResolvableDependenciesMetadata,androidUnitTestImplementationDependenciesMetadata,androidUnitTestReleaseApiDependenciesMetadata,androidUnitTestReleaseCompileOnlyDependenciesMetadata,androidUnitTestReleaseImplementationDependenciesMetadata,androidUnitTestReleaseResolvableDependenciesMetadata,androidUnitTestResolvableDependenciesMetadata,appleTestApiDependenciesMetadata,appleTestCompileOnlyDependenciesMetadata,appleTestImplementationDependenciesMetadata,appleTestResolvableDependenciesMetadata,commonTestApiDependenciesMetadata,commonTestCompileOnlyDependenciesMetadata,commonTestImplementationDependenciesMetadata,commonTestResolvableDependenciesMetadata,debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,iosArm64TestApiDependenciesMetadata,iosArm64TestCInterop,iosArm64TestCompilationDependenciesMetadata,iosArm64TestCompileKlibraries,iosArm64TestCompileOnlyDependenciesMetadata,iosArm64TestImplementationDependenciesMetadata,iosArm64TestResolvableDependenciesMetadata,iosSimulatorArm64TestApiDependenciesMetadata,iosSimulatorArm64TestCInterop,iosSimulatorArm64TestCompilationDependenciesMetadata,iosSimulatorArm64TestCompileKlibraries,iosSimulatorArm64TestCompileOnlyDependenciesMetadata,iosSimulatorArm64TestImplementationDependenciesMetadata,iosSimulatorArm64TestResolvableDependenciesMetadata,iosTestApiDependenciesMetadata,iosTestCompileOnlyDependenciesMetadata,iosTestImplementationDependenciesMetadata,iosTestResolvableDependenciesMetadata,jvmTestApiDependenciesMetadata,jvmTestCompileClasspath,jvmTestCompileOnlyDependenciesMetadata,jvmTestImplementationDependenciesMetadata,jvmTestResolvableDependenciesMetadata,jvmTestRuntimeClasspath,linuxArm64TestApiDependenciesMetadata,linuxArm64TestCInterop,linuxArm64TestCompilationDependenciesMetadata,linuxArm64TestCompileKlibraries,linuxArm64TestCompileOnlyDependenciesMetadata,linuxArm64TestImplementationDependenciesMetadata,linuxArm64TestResolvableDependenciesMetadata,linuxTestApiDependenciesMetadata,linuxTestCompileOnlyDependenciesMetadata,linuxTestImplementationDependenciesMetadata,linuxTestResolvableDependenciesMetadata,linuxX64TestApiDependenciesMetadata,linuxX64TestCInterop,linuxX64TestCompilationDependenciesMetadata,linuxX64TestCompileKlibraries,linuxX64TestCompileOnlyDependenciesMetadata,linuxX64TestImplementationDependenciesMetadata,linuxX64TestResolvableDependenciesMetadata,macosArm64TestApiDependenciesMetadata,macosArm64TestCInterop,macosArm64TestCompilationDependenciesMetadata,macosArm64TestCompileKlibraries,macosArm64TestCompileOnlyDependenciesMetadata,macosArm64TestImplementationDependenciesMetadata,macosArm64TestResolvableDependenciesMetadata,macosTestApiDependenciesMetadata,macosTestCompileOnlyDependenciesMetadata,macosTestImplementationDependenciesMetadata,macosTestResolvableDependenciesMetadata,macosX64TestApiDependenciesMetadata,macosX64TestCInterop,macosX64TestCompilationDependenciesMetadata,macosX64TestCompileKlibraries,macosX64TestCompileOnlyDependenciesMetadata,macosX64TestImplementationDependenciesMetadata,macosX64TestResolvableDependenciesMetadata,mingwTestApiDependenciesMetadata,mingwTestCompileOnlyDependenciesMetadata,mingwTestImplementationDependenciesMetadata,mingwTestResolvableDependenciesMetadata,mingwX64TestApiDependenciesMetadata,mingwX64TestCInterop,mingwX64TestCompilationDependenciesMetadata,mingwX64TestCompileKlibraries,mingwX64TestCompileOnlyDependenciesMetadata,mingwX64TestImplementationDependenciesMetadata,mingwX64TestResolvableDependenciesMetadata,nativeTestApiDependenciesMetadata,nativeTestCompileOnlyDependenciesMetadata,nativeTestImplementationDependenciesMetadata,nativeTestResolvableDependenciesMetadata,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +io.kotest:kotest-common-iosarm64:6.0.0.M3=iosArm64TestCInterop,iosArm64TestCompilationDependenciesMetadata,iosArm64TestCompileKlibraries +io.kotest:kotest-common-iossimulatorarm64:6.0.0.M3=iosSimulatorArm64TestCInterop,iosSimulatorArm64TestCompilationDependenciesMetadata,iosSimulatorArm64TestCompileKlibraries +io.kotest:kotest-common-jvm:6.0.0.M3=androidDebugAndroidTestCompileClasspath,androidDebugAndroidTestRuntimeClasspath,androidDebugUnitTestCompileClasspath,androidDebugUnitTestRuntimeClasspath,androidReleaseUnitTestCompileClasspath,androidReleaseUnitTestRuntimeClasspath,debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,jvmTestCompileClasspath,jvmTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +io.kotest:kotest-common-linuxarm64:6.0.0.M3=linuxArm64TestCInterop,linuxArm64TestCompilationDependenciesMetadata,linuxArm64TestCompileKlibraries +io.kotest:kotest-common-linuxx64:6.0.0.M3=linuxX64TestCInterop,linuxX64TestCompilationDependenciesMetadata,linuxX64TestCompileKlibraries +io.kotest:kotest-common-macosarm64:6.0.0.M3=macosArm64TestCInterop,macosArm64TestCompilationDependenciesMetadata,macosArm64TestCompileKlibraries +io.kotest:kotest-common-macosx64:6.0.0.M3=macosX64TestCInterop,macosX64TestCompilationDependenciesMetadata,macosX64TestCompileKlibraries +io.kotest:kotest-common-mingwx64:6.0.0.M3=mingwX64TestCInterop,mingwX64TestCompilationDependenciesMetadata,mingwX64TestCompileKlibraries +io.kotest:kotest-common:6.0.0.M3=allInstrumentedTestSourceSetsCompileDependenciesMetadata,allTestSourceSetsCompileDependenciesMetadata,androidDebugAndroidTestCompileClasspath,androidDebugAndroidTestRuntimeClasspath,androidDebugUnitTestCompileClasspath,androidDebugUnitTestRuntimeClasspath,androidInstrumentedTestApiDependenciesMetadata,androidInstrumentedTestCompileOnlyDependenciesMetadata,androidInstrumentedTestImplementationDependenciesMetadata,androidInstrumentedTestResolvableDependenciesMetadata,androidReleaseUnitTestCompileClasspath,androidReleaseUnitTestRuntimeClasspath,androidUnitTestApiDependenciesMetadata,androidUnitTestCompileOnlyDependenciesMetadata,androidUnitTestDebugApiDependenciesMetadata,androidUnitTestDebugCompileOnlyDependenciesMetadata,androidUnitTestDebugImplementationDependenciesMetadata,androidUnitTestDebugResolvableDependenciesMetadata,androidUnitTestImplementationDependenciesMetadata,androidUnitTestReleaseApiDependenciesMetadata,androidUnitTestReleaseCompileOnlyDependenciesMetadata,androidUnitTestReleaseImplementationDependenciesMetadata,androidUnitTestReleaseResolvableDependenciesMetadata,androidUnitTestResolvableDependenciesMetadata,appleTestApiDependenciesMetadata,appleTestCompileOnlyDependenciesMetadata,appleTestImplementationDependenciesMetadata,appleTestResolvableDependenciesMetadata,commonTestApiDependenciesMetadata,commonTestCompileOnlyDependenciesMetadata,commonTestImplementationDependenciesMetadata,commonTestResolvableDependenciesMetadata,debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,iosArm64TestApiDependenciesMetadata,iosArm64TestCInterop,iosArm64TestCompilationDependenciesMetadata,iosArm64TestCompileKlibraries,iosArm64TestCompileOnlyDependenciesMetadata,iosArm64TestImplementationDependenciesMetadata,iosArm64TestResolvableDependenciesMetadata,iosSimulatorArm64TestApiDependenciesMetadata,iosSimulatorArm64TestCInterop,iosSimulatorArm64TestCompilationDependenciesMetadata,iosSimulatorArm64TestCompileKlibraries,iosSimulatorArm64TestCompileOnlyDependenciesMetadata,iosSimulatorArm64TestImplementationDependenciesMetadata,iosSimulatorArm64TestResolvableDependenciesMetadata,iosTestApiDependenciesMetadata,iosTestCompileOnlyDependenciesMetadata,iosTestImplementationDependenciesMetadata,iosTestResolvableDependenciesMetadata,jvmTestApiDependenciesMetadata,jvmTestCompileClasspath,jvmTestCompileOnlyDependenciesMetadata,jvmTestImplementationDependenciesMetadata,jvmTestResolvableDependenciesMetadata,jvmTestRuntimeClasspath,linuxArm64TestApiDependenciesMetadata,linuxArm64TestCInterop,linuxArm64TestCompilationDependenciesMetadata,linuxArm64TestCompileKlibraries,linuxArm64TestCompileOnlyDependenciesMetadata,linuxArm64TestImplementationDependenciesMetadata,linuxArm64TestResolvableDependenciesMetadata,linuxTestApiDependenciesMetadata,linuxTestCompileOnlyDependenciesMetadata,linuxTestImplementationDependenciesMetadata,linuxTestResolvableDependenciesMetadata,linuxX64TestApiDependenciesMetadata,linuxX64TestCInterop,linuxX64TestCompilationDependenciesMetadata,linuxX64TestCompileKlibraries,linuxX64TestCompileOnlyDependenciesMetadata,linuxX64TestImplementationDependenciesMetadata,linuxX64TestResolvableDependenciesMetadata,macosArm64TestApiDependenciesMetadata,macosArm64TestCInterop,macosArm64TestCompilationDependenciesMetadata,macosArm64TestCompileKlibraries,macosArm64TestCompileOnlyDependenciesMetadata,macosArm64TestImplementationDependenciesMetadata,macosArm64TestResolvableDependenciesMetadata,macosTestApiDependenciesMetadata,macosTestCompileOnlyDependenciesMetadata,macosTestImplementationDependenciesMetadata,macosTestResolvableDependenciesMetadata,macosX64TestApiDependenciesMetadata,macosX64TestCInterop,macosX64TestCompilationDependenciesMetadata,macosX64TestCompileKlibraries,macosX64TestCompileOnlyDependenciesMetadata,macosX64TestImplementationDependenciesMetadata,macosX64TestResolvableDependenciesMetadata,mingwTestApiDependenciesMetadata,mingwTestCompileOnlyDependenciesMetadata,mingwTestImplementationDependenciesMetadata,mingwTestResolvableDependenciesMetadata,mingwX64TestApiDependenciesMetadata,mingwX64TestCInterop,mingwX64TestCompilationDependenciesMetadata,mingwX64TestCompileKlibraries,mingwX64TestCompileOnlyDependenciesMetadata,mingwX64TestImplementationDependenciesMetadata,mingwX64TestResolvableDependenciesMetadata,nativeTestApiDependenciesMetadata,nativeTestCompileOnlyDependenciesMetadata,nativeTestImplementationDependenciesMetadata,nativeTestResolvableDependenciesMetadata,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +io.kotest:kotest-extensions-junitxml-jvm:6.0.0.M3=jvmTestCompileClasspath,jvmTestRuntimeClasspath +io.kotest:kotest-extensions-junitxml:6.0.0.M3=allTestSourceSetsCompileDependenciesMetadata,jvmTestApiDependenciesMetadata,jvmTestCompileClasspath,jvmTestCompileOnlyDependenciesMetadata,jvmTestImplementationDependenciesMetadata,jvmTestResolvableDependenciesMetadata,jvmTestRuntimeClasspath +io.kotest:kotest-extensions-jvm:6.0.0.M3=jvmTestCompileClasspath,jvmTestRuntimeClasspath +io.kotest:kotest-extensions:6.0.0.M3=jvmTestCompileClasspath,jvmTestRuntimeClasspath +io.kotest:kotest-framework-discovery-jvm:5.9.0=androidDebugAndroidTestCompileClasspath,androidDebugAndroidTestRuntimeClasspath,debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath +io.kotest:kotest-framework-discovery:5.9.0=allInstrumentedTestSourceSetsCompileDependenciesMetadata,androidDebugAndroidTestCompileClasspath,androidDebugAndroidTestRuntimeClasspath,androidInstrumentedTestApiDependenciesMetadata,androidInstrumentedTestCompileOnlyDependenciesMetadata,androidInstrumentedTestImplementationDependenciesMetadata,androidInstrumentedTestResolvableDependenciesMetadata,debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath +io.kotest:kotest-framework-engine-iosarm64:6.0.0.M3=iosArm64TestCInterop,iosArm64TestCompilationDependenciesMetadata,iosArm64TestCompileKlibraries +io.kotest:kotest-framework-engine-iossimulatorarm64:6.0.0.M3=iosSimulatorArm64TestCInterop,iosSimulatorArm64TestCompilationDependenciesMetadata,iosSimulatorArm64TestCompileKlibraries +io.kotest:kotest-framework-engine-jvm:6.0.0.M3=androidDebugAndroidTestCompileClasspath,androidDebugAndroidTestRuntimeClasspath,androidDebugUnitTestCompileClasspath,androidDebugUnitTestRuntimeClasspath,androidReleaseUnitTestCompileClasspath,androidReleaseUnitTestRuntimeClasspath,debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,jvmTestCompileClasspath,jvmTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +io.kotest:kotest-framework-engine-linuxarm64:6.0.0.M3=linuxArm64TestCInterop,linuxArm64TestCompilationDependenciesMetadata,linuxArm64TestCompileKlibraries +io.kotest:kotest-framework-engine-linuxx64:6.0.0.M3=linuxX64TestCInterop,linuxX64TestCompilationDependenciesMetadata,linuxX64TestCompileKlibraries +io.kotest:kotest-framework-engine-macosarm64:6.0.0.M3=macosArm64TestCInterop,macosArm64TestCompilationDependenciesMetadata,macosArm64TestCompileKlibraries +io.kotest:kotest-framework-engine-macosx64:6.0.0.M3=macosX64TestCInterop,macosX64TestCompilationDependenciesMetadata,macosX64TestCompileKlibraries +io.kotest:kotest-framework-engine-mingwx64:6.0.0.M3=mingwX64TestCInterop,mingwX64TestCompilationDependenciesMetadata,mingwX64TestCompileKlibraries +io.kotest:kotest-framework-engine:6.0.0.M3=allInstrumentedTestSourceSetsCompileDependenciesMetadata,allTestSourceSetsCompileDependenciesMetadata,androidDebugAndroidTestCompileClasspath,androidDebugAndroidTestRuntimeClasspath,androidDebugUnitTestCompileClasspath,androidDebugUnitTestRuntimeClasspath,androidInstrumentedTestApiDependenciesMetadata,androidInstrumentedTestCompileOnlyDependenciesMetadata,androidInstrumentedTestImplementationDependenciesMetadata,androidInstrumentedTestResolvableDependenciesMetadata,androidReleaseUnitTestCompileClasspath,androidReleaseUnitTestRuntimeClasspath,androidUnitTestApiDependenciesMetadata,androidUnitTestCompileOnlyDependenciesMetadata,androidUnitTestDebugApiDependenciesMetadata,androidUnitTestDebugCompileOnlyDependenciesMetadata,androidUnitTestDebugImplementationDependenciesMetadata,androidUnitTestDebugResolvableDependenciesMetadata,androidUnitTestImplementationDependenciesMetadata,androidUnitTestReleaseApiDependenciesMetadata,androidUnitTestReleaseCompileOnlyDependenciesMetadata,androidUnitTestReleaseImplementationDependenciesMetadata,androidUnitTestReleaseResolvableDependenciesMetadata,androidUnitTestResolvableDependenciesMetadata,appleTestApiDependenciesMetadata,appleTestCompileOnlyDependenciesMetadata,appleTestImplementationDependenciesMetadata,appleTestResolvableDependenciesMetadata,commonTestApiDependenciesMetadata,commonTestCompileOnlyDependenciesMetadata,commonTestImplementationDependenciesMetadata,commonTestResolvableDependenciesMetadata,debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,iosArm64TestApiDependenciesMetadata,iosArm64TestCInterop,iosArm64TestCompilationDependenciesMetadata,iosArm64TestCompileKlibraries,iosArm64TestCompileOnlyDependenciesMetadata,iosArm64TestImplementationDependenciesMetadata,iosArm64TestResolvableDependenciesMetadata,iosSimulatorArm64TestApiDependenciesMetadata,iosSimulatorArm64TestCInterop,iosSimulatorArm64TestCompilationDependenciesMetadata,iosSimulatorArm64TestCompileKlibraries,iosSimulatorArm64TestCompileOnlyDependenciesMetadata,iosSimulatorArm64TestImplementationDependenciesMetadata,iosSimulatorArm64TestResolvableDependenciesMetadata,iosTestApiDependenciesMetadata,iosTestCompileOnlyDependenciesMetadata,iosTestImplementationDependenciesMetadata,iosTestResolvableDependenciesMetadata,jvmTestApiDependenciesMetadata,jvmTestCompileClasspath,jvmTestCompileOnlyDependenciesMetadata,jvmTestImplementationDependenciesMetadata,jvmTestResolvableDependenciesMetadata,jvmTestRuntimeClasspath,linuxArm64TestApiDependenciesMetadata,linuxArm64TestCInterop,linuxArm64TestCompilationDependenciesMetadata,linuxArm64TestCompileKlibraries,linuxArm64TestCompileOnlyDependenciesMetadata,linuxArm64TestImplementationDependenciesMetadata,linuxArm64TestResolvableDependenciesMetadata,linuxTestApiDependenciesMetadata,linuxTestCompileOnlyDependenciesMetadata,linuxTestImplementationDependenciesMetadata,linuxTestResolvableDependenciesMetadata,linuxX64TestApiDependenciesMetadata,linuxX64TestCInterop,linuxX64TestCompilationDependenciesMetadata,linuxX64TestCompileKlibraries,linuxX64TestCompileOnlyDependenciesMetadata,linuxX64TestImplementationDependenciesMetadata,linuxX64TestResolvableDependenciesMetadata,macosArm64TestApiDependenciesMetadata,macosArm64TestCInterop,macosArm64TestCompilationDependenciesMetadata,macosArm64TestCompileKlibraries,macosArm64TestCompileOnlyDependenciesMetadata,macosArm64TestImplementationDependenciesMetadata,macosArm64TestResolvableDependenciesMetadata,macosTestApiDependenciesMetadata,macosTestCompileOnlyDependenciesMetadata,macosTestImplementationDependenciesMetadata,macosTestResolvableDependenciesMetadata,macosX64TestApiDependenciesMetadata,macosX64TestCInterop,macosX64TestCompilationDependenciesMetadata,macosX64TestCompileKlibraries,macosX64TestCompileOnlyDependenciesMetadata,macosX64TestImplementationDependenciesMetadata,macosX64TestResolvableDependenciesMetadata,mingwTestApiDependenciesMetadata,mingwTestCompileOnlyDependenciesMetadata,mingwTestImplementationDependenciesMetadata,mingwTestResolvableDependenciesMetadata,mingwX64TestApiDependenciesMetadata,mingwX64TestCInterop,mingwX64TestCompilationDependenciesMetadata,mingwX64TestCompileKlibraries,mingwX64TestCompileOnlyDependenciesMetadata,mingwX64TestImplementationDependenciesMetadata,mingwX64TestResolvableDependenciesMetadata,nativeTestApiDependenciesMetadata,nativeTestCompileOnlyDependenciesMetadata,nativeTestImplementationDependenciesMetadata,nativeTestResolvableDependenciesMetadata,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +io.kotest:kotest-framework-multiplatform-plugin-embeddable-compiler-jvm:6.0.0.M3=kotlinCompilerPluginClasspathIosArm64Main,kotlinCompilerPluginClasspathIosArm64Test,kotlinCompilerPluginClasspathIosSimulatorArm64Main,kotlinCompilerPluginClasspathIosSimulatorArm64Test,kotlinCompilerPluginClasspathLinuxArm64Main,kotlinCompilerPluginClasspathLinuxArm64Test,kotlinCompilerPluginClasspathLinuxX64Main,kotlinCompilerPluginClasspathLinuxX64Test,kotlinCompilerPluginClasspathMacosArm64Main,kotlinCompilerPluginClasspathMacosArm64Test,kotlinCompilerPluginClasspathMacosX64Main,kotlinCompilerPluginClasspathMacosX64Test,kotlinCompilerPluginClasspathMetadataAppleMain,kotlinCompilerPluginClasspathMetadataIosMain,kotlinCompilerPluginClasspathMetadataLinuxMain,kotlinCompilerPluginClasspathMetadataMacosMain,kotlinCompilerPluginClasspathMetadataNativeMain,kotlinCompilerPluginClasspathMingwX64Main,kotlinCompilerPluginClasspathMingwX64Test +io.kotest:kotest-framework-multiplatform-plugin-embeddable-compiler:6.0.0.M3=kotlinCompilerPluginClasspathIosArm64Main,kotlinCompilerPluginClasspathIosArm64Test,kotlinCompilerPluginClasspathIosSimulatorArm64Main,kotlinCompilerPluginClasspathIosSimulatorArm64Test,kotlinCompilerPluginClasspathLinuxArm64Main,kotlinCompilerPluginClasspathLinuxArm64Test,kotlinCompilerPluginClasspathLinuxX64Main,kotlinCompilerPluginClasspathLinuxX64Test,kotlinCompilerPluginClasspathMacosArm64Main,kotlinCompilerPluginClasspathMacosArm64Test,kotlinCompilerPluginClasspathMacosX64Main,kotlinCompilerPluginClasspathMacosX64Test,kotlinCompilerPluginClasspathMetadataAppleMain,kotlinCompilerPluginClasspathMetadataIosMain,kotlinCompilerPluginClasspathMetadataLinuxMain,kotlinCompilerPluginClasspathMetadataMacosMain,kotlinCompilerPluginClasspathMetadataNativeMain,kotlinCompilerPluginClasspathMingwX64Main,kotlinCompilerPluginClasspathMingwX64Test +io.kotest:kotest-runner-junit5-jvm:6.0.0.M3=jvmTestCompileClasspath,jvmTestRuntimeClasspath +io.kotest:kotest-runner-junit5:6.0.0.M3=allTestSourceSetsCompileDependenciesMetadata,jvmTestApiDependenciesMetadata,jvmTestCompileClasspath,jvmTestCompileOnlyDependenciesMetadata,jvmTestImplementationDependenciesMetadata,jvmTestResolvableDependenciesMetadata,jvmTestRuntimeClasspath +io.netty:netty-buffer:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.netty:netty-codec-http2:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.netty:netty-codec-http:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.netty:netty-codec-socks:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.netty:netty-codec:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.netty:netty-common:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.netty:netty-handler-proxy:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.netty:netty-handler:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.netty:netty-resolver:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.netty:netty-transport-native-unix-common:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.netty:netty-transport:4.1.93.Final=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +io.perfmark:perfmark-api:0.26.0=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +jakarta.activation:jakarta.activation-api:1.2.1=dokkaHtmlGeneratorRuntimeResolver~internal +jakarta.xml.bind:jakarta.xml.bind-api:2.3.2=dokkaHtmlGeneratorRuntimeResolver~internal +javax.annotation:javax.annotation-api:1.3.2=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +junit:junit:4.13.2=allInstrumentedTestSourceSetsCompileDependenciesMetadata,androidDebugAndroidTestCompileClasspath,androidDebugAndroidTestRuntimeClasspath,androidInstrumentedTestApiDependenciesMetadata,androidInstrumentedTestCompileOnlyDependenciesMetadata,androidInstrumentedTestImplementationDependenciesMetadata,androidInstrumentedTestResolvableDependenciesMetadata,debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath +net.bytebuddy:byte-buddy-agent:1.10.9=androidDebugAndroidTestRuntimeClasspath,androidDebugUnitTestRuntimeClasspath,androidReleaseUnitTestRuntimeClasspath,debugAndroidTestRuntimeClasspath,debugUnitTestRuntimeClasspath,jvmTestRuntimeClasspath,releaseUnitTestRuntimeClasspath +net.bytebuddy:byte-buddy:1.10.9=androidDebugAndroidTestRuntimeClasspath,androidDebugUnitTestRuntimeClasspath,androidReleaseUnitTestRuntimeClasspath,debugAndroidTestRuntimeClasspath,debugUnitTestRuntimeClasspath,jvmTestRuntimeClasspath,releaseUnitTestRuntimeClasspath +net.java.dev.jna:jna-platform:5.6.0=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +net.java.dev.jna:jna-platform:5.9.0=androidDebugAndroidTestCompileClasspath,androidDebugAndroidTestRuntimeClasspath,androidDebugUnitTestCompileClasspath,androidDebugUnitTestRuntimeClasspath,androidReleaseUnitTestCompileClasspath,androidReleaseUnitTestRuntimeClasspath,debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,jvmTestCompileClasspath,jvmTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +net.java.dev.jna:jna:5.6.0=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +net.java.dev.jna:jna:5.9.0=androidDebugAndroidTestCompileClasspath,androidDebugAndroidTestRuntimeClasspath,androidDebugUnitTestCompileClasspath,androidDebugUnitTestRuntimeClasspath,androidReleaseUnitTestCompileClasspath,androidReleaseUnitTestRuntimeClasspath,debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,jvmTestCompileClasspath,jvmTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +net.sf.kxml:kxml2:2.3.0=_internal-unified-test-platform-android-device-provider-ddmlib +org.apache.commons:commons-lang3:3.13.0=androidDebugAndroidTestRuntimeClasspath,androidDebugUnitTestRuntimeClasspath,androidReleaseUnitTestRuntimeClasspath,debugAndroidTestRuntimeClasspath,debugUnitTestRuntimeClasspath,jvmTestRuntimeClasspath,releaseUnitTestRuntimeClasspath +org.apiguardian:apiguardian-api:1.1.2=jvmTestCompileClasspath +org.checkerframework:checker-qual:3.33.0=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +org.codehaus.mojo:animal-sniffer-annotations:1.23=_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +org.codehaus.woodstox:stax2-api:4.2.1=dokkaHtmlGeneratorRuntimeResolver~internal +org.freemarker:freemarker:2.3.32=dokkaHtmlGeneratorRuntimeResolver~internal +org.hamcrest:hamcrest-core:1.3=allInstrumentedTestSourceSetsCompileDependenciesMetadata,androidDebugAndroidTestCompileClasspath,androidDebugAndroidTestRuntimeClasspath,androidInstrumentedTestApiDependenciesMetadata,androidInstrumentedTestCompileOnlyDependenciesMetadata,androidInstrumentedTestImplementationDependenciesMetadata,androidInstrumentedTestResolvableDependenciesMetadata,debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath +org.jdom:jdom2:2.0.6.1=jvmTestRuntimeClasspath +org.jetbrains.dokka:analysis-kotlin-descriptors:2.0.0=dokkaHtmlGeneratorRuntimeResolver~internal +org.jetbrains.dokka:analysis-markdown:2.0.0=dokkaHtmlGeneratorRuntimeResolver~internal +org.jetbrains.dokka:dokka-base:2.0.0=dokkaHtmlGeneratorRuntimeResolver~internal,dokkaHtmlPluginIntransitiveResolver~internal +org.jetbrains.dokka:dokka-core:2.0.0=dokkaHtmlGeneratorRuntimeResolver~internal +org.jetbrains.dokka:templating-plugin:2.0.0=dokkaHtmlGeneratorRuntimeResolver~internal,dokkaHtmlPluginIntransitiveResolver~internal +org.jetbrains.intellij.deps:trove4j:1.0.20200330=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinKlibCommonizerClasspath +org.jetbrains.kotlin:kotlin-build-tools-api:2.1.21=kotlinBuildToolsApiClasspath +org.jetbrains.kotlin:kotlin-build-tools-impl:2.1.21=kotlinBuildToolsApiClasspath +org.jetbrains.kotlin:kotlin-compiler-embeddable:2.1.21=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinKlibCommonizerClasspath +org.jetbrains.kotlin:kotlin-compiler-runner:2.1.21=kotlinBuildToolsApiClasspath +org.jetbrains.kotlin:kotlin-daemon-client:2.1.21=kotlinBuildToolsApiClasspath +org.jetbrains.kotlin:kotlin-daemon-embeddable:2.1.21=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinKlibCommonizerClasspath +org.jetbrains.kotlin:kotlin-klib-commonizer-embeddable:2.1.21=kotlinKlibCommonizerClasspath +org.jetbrains.kotlin:kotlin-native-prebuilt:2.1.21=kotlinNativeBundleConfiguration +org.jetbrains.kotlin:kotlin-reflect:1.6.10=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinKlibCommonizerClasspath +org.jetbrains.kotlin:kotlin-reflect:2.0.20=dokkaHtmlGeneratorRuntimeResolver~internal +org.jetbrains.kotlin:kotlin-reflect:2.1.20=allInstrumentedTestSourceSetsCompileDependenciesMetadata,allTestSourceSetsCompileDependenciesMetadata,androidDebugAndroidTestRuntimeClasspath,androidDebugUnitTestRuntimeClasspath,androidInstrumentedTestApiDependenciesMetadata,androidInstrumentedTestCompileOnlyDependenciesMetadata,androidInstrumentedTestImplementationDependenciesMetadata,androidInstrumentedTestResolvableDependenciesMetadata,androidReleaseUnitTestRuntimeClasspath,androidUnitTestApiDependenciesMetadata,androidUnitTestCompileOnlyDependenciesMetadata,androidUnitTestDebugApiDependenciesMetadata,androidUnitTestDebugCompileOnlyDependenciesMetadata,androidUnitTestDebugImplementationDependenciesMetadata,androidUnitTestDebugResolvableDependenciesMetadata,androidUnitTestImplementationDependenciesMetadata,androidUnitTestReleaseApiDependenciesMetadata,androidUnitTestReleaseCompileOnlyDependenciesMetadata,androidUnitTestReleaseImplementationDependenciesMetadata,androidUnitTestReleaseResolvableDependenciesMetadata,androidUnitTestResolvableDependenciesMetadata,appleTestApiDependenciesMetadata,appleTestCompileOnlyDependenciesMetadata,appleTestImplementationDependenciesMetadata,appleTestResolvableDependenciesMetadata,commonTestApiDependenciesMetadata,commonTestCompileOnlyDependenciesMetadata,commonTestImplementationDependenciesMetadata,commonTestResolvableDependenciesMetadata,debugAndroidTestRuntimeClasspath,debugUnitTestRuntimeClasspath,iosArm64TestApiDependenciesMetadata,iosArm64TestCInterop,iosArm64TestCompilationDependenciesMetadata,iosArm64TestCompileKlibraries,iosArm64TestCompileOnlyDependenciesMetadata,iosArm64TestImplementationDependenciesMetadata,iosArm64TestResolvableDependenciesMetadata,iosSimulatorArm64TestApiDependenciesMetadata,iosSimulatorArm64TestCInterop,iosSimulatorArm64TestCompilationDependenciesMetadata,iosSimulatorArm64TestCompileKlibraries,iosSimulatorArm64TestCompileOnlyDependenciesMetadata,iosSimulatorArm64TestImplementationDependenciesMetadata,iosSimulatorArm64TestResolvableDependenciesMetadata,iosTestApiDependenciesMetadata,iosTestCompileOnlyDependenciesMetadata,iosTestImplementationDependenciesMetadata,iosTestResolvableDependenciesMetadata,jvmTestApiDependenciesMetadata,jvmTestCompileOnlyDependenciesMetadata,jvmTestImplementationDependenciesMetadata,jvmTestResolvableDependenciesMetadata,jvmTestRuntimeClasspath,linuxArm64TestApiDependenciesMetadata,linuxArm64TestCInterop,linuxArm64TestCompilationDependenciesMetadata,linuxArm64TestCompileKlibraries,linuxArm64TestCompileOnlyDependenciesMetadata,linuxArm64TestImplementationDependenciesMetadata,linuxArm64TestResolvableDependenciesMetadata,linuxTestApiDependenciesMetadata,linuxTestCompileOnlyDependenciesMetadata,linuxTestImplementationDependenciesMetadata,linuxTestResolvableDependenciesMetadata,linuxX64TestApiDependenciesMetadata,linuxX64TestCInterop,linuxX64TestCompilationDependenciesMetadata,linuxX64TestCompileKlibraries,linuxX64TestCompileOnlyDependenciesMetadata,linuxX64TestImplementationDependenciesMetadata,linuxX64TestResolvableDependenciesMetadata,macosArm64TestApiDependenciesMetadata,macosArm64TestCInterop,macosArm64TestCompilationDependenciesMetadata,macosArm64TestCompileKlibraries,macosArm64TestCompileOnlyDependenciesMetadata,macosArm64TestImplementationDependenciesMetadata,macosArm64TestResolvableDependenciesMetadata,macosTestApiDependenciesMetadata,macosTestCompileOnlyDependenciesMetadata,macosTestImplementationDependenciesMetadata,macosTestResolvableDependenciesMetadata,macosX64TestApiDependenciesMetadata,macosX64TestCInterop,macosX64TestCompilationDependenciesMetadata,macosX64TestCompileKlibraries,macosX64TestCompileOnlyDependenciesMetadata,macosX64TestImplementationDependenciesMetadata,macosX64TestResolvableDependenciesMetadata,mingwTestApiDependenciesMetadata,mingwTestCompileOnlyDependenciesMetadata,mingwTestImplementationDependenciesMetadata,mingwTestResolvableDependenciesMetadata,mingwX64TestApiDependenciesMetadata,mingwX64TestCInterop,mingwX64TestCompilationDependenciesMetadata,mingwX64TestCompileKlibraries,mingwX64TestCompileOnlyDependenciesMetadata,mingwX64TestImplementationDependenciesMetadata,mingwX64TestResolvableDependenciesMetadata,nativeTestApiDependenciesMetadata,nativeTestCompileOnlyDependenciesMetadata,nativeTestImplementationDependenciesMetadata,nativeTestResolvableDependenciesMetadata,releaseUnitTestRuntimeClasspath +org.jetbrains.kotlin:kotlin-script-runtime:2.1.21=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinCompilerPluginClasspathAndroidDebug,kotlinCompilerPluginClasspathAndroidDebugAndroidTest,kotlinCompilerPluginClasspathAndroidDebugUnitTest,kotlinCompilerPluginClasspathAndroidRelease,kotlinCompilerPluginClasspathAndroidReleaseUnitTest,kotlinCompilerPluginClasspathJvmMain,kotlinCompilerPluginClasspathJvmTest,kotlinCompilerPluginClasspathMetadataCommonMain,kotlinCompilerPluginClasspathMetadataMain,kotlinKlibCommonizerClasspath +org.jetbrains.kotlin:kotlin-scripting-common:2.1.21=kotlinBuildToolsApiClasspath,kotlinCompilerPluginClasspathAndroidDebug,kotlinCompilerPluginClasspathAndroidDebugAndroidTest,kotlinCompilerPluginClasspathAndroidDebugUnitTest,kotlinCompilerPluginClasspathAndroidRelease,kotlinCompilerPluginClasspathAndroidReleaseUnitTest,kotlinCompilerPluginClasspathJvmMain,kotlinCompilerPluginClasspathJvmTest,kotlinCompilerPluginClasspathMetadataCommonMain,kotlinCompilerPluginClasspathMetadataMain +org.jetbrains.kotlin:kotlin-scripting-compiler-embeddable:2.1.21=kotlinBuildToolsApiClasspath,kotlinCompilerPluginClasspathAndroidDebug,kotlinCompilerPluginClasspathAndroidDebugAndroidTest,kotlinCompilerPluginClasspathAndroidDebugUnitTest,kotlinCompilerPluginClasspathAndroidRelease,kotlinCompilerPluginClasspathAndroidReleaseUnitTest,kotlinCompilerPluginClasspathJvmMain,kotlinCompilerPluginClasspathJvmTest,kotlinCompilerPluginClasspathMetadataCommonMain,kotlinCompilerPluginClasspathMetadataMain +org.jetbrains.kotlin:kotlin-scripting-compiler-impl-embeddable:2.1.21=kotlinBuildToolsApiClasspath,kotlinCompilerPluginClasspathAndroidDebug,kotlinCompilerPluginClasspathAndroidDebugAndroidTest,kotlinCompilerPluginClasspathAndroidDebugUnitTest,kotlinCompilerPluginClasspathAndroidRelease,kotlinCompilerPluginClasspathAndroidReleaseUnitTest,kotlinCompilerPluginClasspathJvmMain,kotlinCompilerPluginClasspathJvmTest,kotlinCompilerPluginClasspathMetadataCommonMain,kotlinCompilerPluginClasspathMetadataMain +org.jetbrains.kotlin:kotlin-scripting-jvm:2.1.21=kotlinBuildToolsApiClasspath,kotlinCompilerPluginClasspathAndroidDebug,kotlinCompilerPluginClasspathAndroidDebugAndroidTest,kotlinCompilerPluginClasspathAndroidDebugUnitTest,kotlinCompilerPluginClasspathAndroidRelease,kotlinCompilerPluginClasspathAndroidReleaseUnitTest,kotlinCompilerPluginClasspathJvmMain,kotlinCompilerPluginClasspathJvmTest,kotlinCompilerPluginClasspathMetadataCommonMain,kotlinCompilerPluginClasspathMetadataMain +org.jetbrains.kotlin:kotlin-stdlib-common:2.0.20=dokkaHtmlGeneratorRuntimeResolver~internal +org.jetbrains.kotlin:kotlin-stdlib-common:2.0.21=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +org.jetbrains.kotlin:kotlin-stdlib-common:2.1.21=allInstrumentedTestSourceSetsCompileDependenciesMetadata,allTestSourceSetsCompileDependenciesMetadata,androidInstrumentedTestApiDependenciesMetadata,androidInstrumentedTestCompileOnlyDependenciesMetadata,androidInstrumentedTestImplementationDependenciesMetadata,androidInstrumentedTestResolvableDependenciesMetadata,androidUnitTestApiDependenciesMetadata,androidUnitTestCompileOnlyDependenciesMetadata,androidUnitTestDebugResolvableDependenciesMetadata,androidUnitTestImplementationDependenciesMetadata,androidUnitTestReleaseResolvableDependenciesMetadata,androidUnitTestResolvableDependenciesMetadata,appleTestApiDependenciesMetadata,appleTestCompileOnlyDependenciesMetadata,appleTestImplementationDependenciesMetadata,appleTestResolvableDependenciesMetadata,commonTestApiDependenciesMetadata,commonTestCompileOnlyDependenciesMetadata,commonTestImplementationDependenciesMetadata,commonTestResolvableDependenciesMetadata,iosArm64TestResolvableDependenciesMetadata,iosSimulatorArm64TestResolvableDependenciesMetadata,iosTestApiDependenciesMetadata,iosTestCompileOnlyDependenciesMetadata,iosTestImplementationDependenciesMetadata,iosTestResolvableDependenciesMetadata,jvmTestResolvableDependenciesMetadata,linuxArm64TestResolvableDependenciesMetadata,linuxTestApiDependenciesMetadata,linuxTestCompileOnlyDependenciesMetadata,linuxTestImplementationDependenciesMetadata,linuxTestResolvableDependenciesMetadata,linuxX64TestResolvableDependenciesMetadata,macosArm64TestResolvableDependenciesMetadata,macosTestApiDependenciesMetadata,macosTestCompileOnlyDependenciesMetadata,macosTestImplementationDependenciesMetadata,macosTestResolvableDependenciesMetadata,macosX64TestResolvableDependenciesMetadata,mingwTestApiDependenciesMetadata,mingwTestCompileOnlyDependenciesMetadata,mingwTestImplementationDependenciesMetadata,mingwTestResolvableDependenciesMetadata,mingwX64TestResolvableDependenciesMetadata,nativeTestApiDependenciesMetadata,nativeTestCompileOnlyDependenciesMetadata,nativeTestImplementationDependenciesMetadata,nativeTestResolvableDependenciesMetadata +org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.20=allInstrumentedTestSourceSetsCompileDependenciesMetadata,androidDebugAndroidTestCompileClasspath,androidDebugAndroidTestRuntimeClasspath,androidInstrumentedTestApiDependenciesMetadata,androidInstrumentedTestCompileOnlyDependenciesMetadata,androidInstrumentedTestImplementationDependenciesMetadata,androidInstrumentedTestResolvableDependenciesMetadata,debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,dokkaHtmlGeneratorRuntimeResolver~internal +org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.0.21=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.20=allInstrumentedTestSourceSetsCompileDependenciesMetadata,androidDebugAndroidTestCompileClasspath,androidDebugAndroidTestRuntimeClasspath,androidInstrumentedTestApiDependenciesMetadata,androidInstrumentedTestCompileOnlyDependenciesMetadata,androidInstrumentedTestImplementationDependenciesMetadata,androidInstrumentedTestResolvableDependenciesMetadata,debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,dokkaHtmlGeneratorRuntimeResolver~internal +org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.0.21=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +org.jetbrains.kotlin:kotlin-stdlib:2.0.20=dokkaHtmlGeneratorRuntimeResolver~internal +org.jetbrains.kotlin:kotlin-stdlib:2.0.21=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +org.jetbrains.kotlin:kotlin-stdlib:2.1.20=kotlinCompilerPluginClasspathMetadataAppleMain,kotlinCompilerPluginClasspathMetadataIosMain,kotlinCompilerPluginClasspathMetadataLinuxMain,kotlinCompilerPluginClasspathMetadataMacosMain,kotlinCompilerPluginClasspathMetadataNativeMain +org.jetbrains.kotlin:kotlin-stdlib:2.1.21=allInstrumentedTestSourceSetsCompileDependenciesMetadata,allSourceSetsCompileDependenciesMetadata,allTestSourceSetsCompileDependenciesMetadata,androidDebugAndroidTestCompileClasspath,androidDebugAndroidTestRuntimeClasspath,androidDebugApiDependenciesMetadata,androidDebugCompileClasspath,androidDebugCompileOnlyDependenciesMetadata,androidDebugImplementationDependenciesMetadata,androidDebugResolvableDependenciesMetadata,androidDebugRuntimeClasspath,androidDebugUnitTestCompileClasspath,androidDebugUnitTestRuntimeClasspath,androidInstrumentedTestApiDependenciesMetadata,androidInstrumentedTestCompileOnlyDependenciesMetadata,androidInstrumentedTestDebugApiDependenciesMetadata,androidInstrumentedTestDebugCompileOnlyDependenciesMetadata,androidInstrumentedTestDebugImplementationDependenciesMetadata,androidInstrumentedTestDebugResolvableDependenciesMetadata,androidInstrumentedTestImplementationDependenciesMetadata,androidInstrumentedTestResolvableDependenciesMetadata,androidMainApiDependenciesMetadata,androidMainCompileOnlyDependenciesMetadata,androidMainImplementationDependenciesMetadata,androidMainResolvableDependenciesMetadata,androidReleaseApiDependenciesMetadata,androidReleaseCompileClasspath,androidReleaseCompileOnlyDependenciesMetadata,androidReleaseImplementationDependenciesMetadata,androidReleaseResolvableDependenciesMetadata,androidReleaseRuntimeClasspath,androidReleaseUnitTestCompileClasspath,androidReleaseUnitTestRuntimeClasspath,androidUnitTestApiDependenciesMetadata,androidUnitTestCompileOnlyDependenciesMetadata,androidUnitTestDebugApiDependenciesMetadata,androidUnitTestDebugCompileOnlyDependenciesMetadata,androidUnitTestDebugImplementationDependenciesMetadata,androidUnitTestDebugResolvableDependenciesMetadata,androidUnitTestImplementationDependenciesMetadata,androidUnitTestReleaseApiDependenciesMetadata,androidUnitTestReleaseCompileOnlyDependenciesMetadata,androidUnitTestReleaseImplementationDependenciesMetadata,androidUnitTestReleaseResolvableDependenciesMetadata,androidUnitTestResolvableDependenciesMetadata,commonMainApiDependenciesMetadata,commonMainCompileOnlyDependenciesMetadata,commonMainImplementationDependenciesMetadata,commonMainResolvableDependenciesMetadata,commonTestApiDependenciesMetadata,commonTestCompileOnlyDependenciesMetadata,commonTestImplementationDependenciesMetadata,commonTestResolvableDependenciesMetadata,debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,iosArm64CInterop,iosArm64CompilationDependenciesMetadata,iosArm64CompileKlibraries,iosArm64TestCInterop,iosArm64TestCompilationDependenciesMetadata,iosArm64TestCompileKlibraries,iosSimulatorArm64CInterop,iosSimulatorArm64CompilationDependenciesMetadata,iosSimulatorArm64CompileKlibraries,iosSimulatorArm64TestCInterop,iosSimulatorArm64TestCompilationDependenciesMetadata,iosSimulatorArm64TestCompileKlibraries,jvmCompileClasspath,jvmMainApiDependenciesMetadata,jvmMainCompileClasspath,jvmMainCompileOnlyDependenciesMetadata,jvmMainImplementationDependenciesMetadata,jvmMainResolvableDependenciesMetadata,jvmMainRuntimeClasspath,jvmRuntimeClasspath,jvmTestApiDependenciesMetadata,jvmTestCompileClasspath,jvmTestCompileOnlyDependenciesMetadata,jvmTestImplementationDependenciesMetadata,jvmTestResolvableDependenciesMetadata,jvmTestRuntimeClasspath,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinCompilerPluginClasspathAndroidDebug,kotlinCompilerPluginClasspathAndroidDebugAndroidTest,kotlinCompilerPluginClasspathAndroidDebugUnitTest,kotlinCompilerPluginClasspathAndroidRelease,kotlinCompilerPluginClasspathAndroidReleaseUnitTest,kotlinCompilerPluginClasspathJvmMain,kotlinCompilerPluginClasspathJvmTest,kotlinCompilerPluginClasspathMetadataCommonMain,kotlinCompilerPluginClasspathMetadataMain,kotlinKlibCommonizerClasspath,linuxArm64CInterop,linuxArm64CompilationDependenciesMetadata,linuxArm64CompileKlibraries,linuxArm64TestCInterop,linuxArm64TestCompilationDependenciesMetadata,linuxArm64TestCompileKlibraries,linuxX64CInterop,linuxX64CompilationDependenciesMetadata,linuxX64CompileKlibraries,linuxX64TestCInterop,linuxX64TestCompilationDependenciesMetadata,linuxX64TestCompileKlibraries,macosArm64CInterop,macosArm64CompilationDependenciesMetadata,macosArm64CompileKlibraries,macosArm64TestCInterop,macosArm64TestCompilationDependenciesMetadata,macosArm64TestCompileKlibraries,macosX64CInterop,macosX64CompilationDependenciesMetadata,macosX64CompileKlibraries,macosX64TestCInterop,macosX64TestCompilationDependenciesMetadata,macosX64TestCompileKlibraries,metadataAppleMainCompileClasspath,metadataCommonMainCompileClasspath,metadataCompileClasspath,metadataIosMainCompileClasspath,metadataLinuxMainCompileClasspath,metadataMacosMainCompileClasspath,metadataNativeMainCompileClasspath,mingwX64CInterop,mingwX64CompilationDependenciesMetadata,mingwX64CompileKlibraries,mingwX64TestCInterop,mingwX64TestCompilationDependenciesMetadata,mingwX64TestCompileKlibraries,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.jetbrains.kotlinx:atomicfu-iosarm64:0.26.1=iosArm64TestCInterop,iosArm64TestCompilationDependenciesMetadata,iosArm64TestCompileKlibraries +org.jetbrains.kotlinx:atomicfu-iossimulatorarm64:0.26.1=iosSimulatorArm64TestCInterop,iosSimulatorArm64TestCompilationDependenciesMetadata,iosSimulatorArm64TestCompileKlibraries +org.jetbrains.kotlinx:atomicfu-linuxarm64:0.26.1=linuxArm64TestCInterop,linuxArm64TestCompilationDependenciesMetadata,linuxArm64TestCompileKlibraries +org.jetbrains.kotlinx:atomicfu-linuxx64:0.26.1=linuxX64TestCInterop,linuxX64TestCompilationDependenciesMetadata,linuxX64TestCompileKlibraries +org.jetbrains.kotlinx:atomicfu-macosarm64:0.26.1=macosArm64TestCInterop,macosArm64TestCompilationDependenciesMetadata,macosArm64TestCompileKlibraries +org.jetbrains.kotlinx:atomicfu-macosx64:0.26.1=macosX64TestCInterop,macosX64TestCompilationDependenciesMetadata,macosX64TestCompileKlibraries +org.jetbrains.kotlinx:atomicfu-mingwx64:0.26.1=mingwX64TestCInterop,mingwX64TestCompilationDependenciesMetadata,mingwX64TestCompileKlibraries +org.jetbrains.kotlinx:atomicfu:0.23.1=allInstrumentedTestSourceSetsCompileDependenciesMetadata,allTestSourceSetsCompileDependenciesMetadata,androidInstrumentedTestApiDependenciesMetadata,androidInstrumentedTestCompileOnlyDependenciesMetadata,androidInstrumentedTestImplementationDependenciesMetadata,androidInstrumentedTestResolvableDependenciesMetadata,androidUnitTestApiDependenciesMetadata,androidUnitTestCompileOnlyDependenciesMetadata,androidUnitTestDebugApiDependenciesMetadata,androidUnitTestDebugCompileOnlyDependenciesMetadata,androidUnitTestDebugImplementationDependenciesMetadata,androidUnitTestDebugResolvableDependenciesMetadata,androidUnitTestImplementationDependenciesMetadata,androidUnitTestReleaseApiDependenciesMetadata,androidUnitTestReleaseCompileOnlyDependenciesMetadata,androidUnitTestReleaseImplementationDependenciesMetadata,androidUnitTestReleaseResolvableDependenciesMetadata,androidUnitTestResolvableDependenciesMetadata,appleTestApiDependenciesMetadata,appleTestCompileOnlyDependenciesMetadata,appleTestImplementationDependenciesMetadata,appleTestResolvableDependenciesMetadata,commonTestApiDependenciesMetadata,commonTestCompileOnlyDependenciesMetadata,commonTestImplementationDependenciesMetadata,commonTestResolvableDependenciesMetadata,iosArm64TestApiDependenciesMetadata,iosArm64TestCompileOnlyDependenciesMetadata,iosArm64TestImplementationDependenciesMetadata,iosArm64TestResolvableDependenciesMetadata,iosSimulatorArm64TestApiDependenciesMetadata,iosSimulatorArm64TestCompileOnlyDependenciesMetadata,iosSimulatorArm64TestImplementationDependenciesMetadata,iosSimulatorArm64TestResolvableDependenciesMetadata,iosTestApiDependenciesMetadata,iosTestCompileOnlyDependenciesMetadata,iosTestImplementationDependenciesMetadata,iosTestResolvableDependenciesMetadata,jvmTestApiDependenciesMetadata,jvmTestCompileOnlyDependenciesMetadata,jvmTestImplementationDependenciesMetadata,jvmTestResolvableDependenciesMetadata,linuxArm64TestApiDependenciesMetadata,linuxArm64TestCompileOnlyDependenciesMetadata,linuxArm64TestImplementationDependenciesMetadata,linuxArm64TestResolvableDependenciesMetadata,linuxTestApiDependenciesMetadata,linuxTestCompileOnlyDependenciesMetadata,linuxTestImplementationDependenciesMetadata,linuxTestResolvableDependenciesMetadata,linuxX64TestApiDependenciesMetadata,linuxX64TestCompileOnlyDependenciesMetadata,linuxX64TestImplementationDependenciesMetadata,linuxX64TestResolvableDependenciesMetadata,macosArm64TestApiDependenciesMetadata,macosArm64TestCompileOnlyDependenciesMetadata,macosArm64TestImplementationDependenciesMetadata,macosArm64TestResolvableDependenciesMetadata,macosTestApiDependenciesMetadata,macosTestCompileOnlyDependenciesMetadata,macosTestImplementationDependenciesMetadata,macosTestResolvableDependenciesMetadata,macosX64TestApiDependenciesMetadata,macosX64TestCompileOnlyDependenciesMetadata,macosX64TestImplementationDependenciesMetadata,macosX64TestResolvableDependenciesMetadata,mingwTestApiDependenciesMetadata,mingwTestCompileOnlyDependenciesMetadata,mingwTestImplementationDependenciesMetadata,mingwTestResolvableDependenciesMetadata,mingwX64TestApiDependenciesMetadata,mingwX64TestCompileOnlyDependenciesMetadata,mingwX64TestImplementationDependenciesMetadata,mingwX64TestResolvableDependenciesMetadata,nativeTestApiDependenciesMetadata,nativeTestCompileOnlyDependenciesMetadata,nativeTestImplementationDependenciesMetadata,nativeTestResolvableDependenciesMetadata +org.jetbrains.kotlinx:atomicfu:0.26.1=iosArm64TestCInterop,iosArm64TestCompilationDependenciesMetadata,iosArm64TestCompileKlibraries,iosSimulatorArm64TestCInterop,iosSimulatorArm64TestCompilationDependenciesMetadata,iosSimulatorArm64TestCompileKlibraries,linuxArm64TestCInterop,linuxArm64TestCompilationDependenciesMetadata,linuxArm64TestCompileKlibraries,linuxX64TestCInterop,linuxX64TestCompilationDependenciesMetadata,linuxX64TestCompileKlibraries,macosArm64TestCInterop,macosArm64TestCompilationDependenciesMetadata,macosArm64TestCompileKlibraries,macosX64TestCInterop,macosX64TestCompilationDependenciesMetadata,macosX64TestCompileKlibraries,mingwX64TestCInterop,mingwX64TestCompilationDependenciesMetadata,mingwX64TestCompileKlibraries +org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.10.0=androidDebugAndroidTestCompileClasspath,androidDebugAndroidTestRuntimeClasspath,androidDebugUnitTestCompileClasspath,androidDebugUnitTestRuntimeClasspath,androidReleaseUnitTestCompileClasspath,androidReleaseUnitTestRuntimeClasspath,debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,jvmTestCompileClasspath,jvmTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.6.4=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.7.3=dokkaHtmlGeneratorRuntimeResolver~internal +org.jetbrains.kotlinx:kotlinx-coroutines-core-iosarm64:1.10.0=iosArm64TestCInterop,iosArm64TestCompilationDependenciesMetadata,iosArm64TestCompileKlibraries +org.jetbrains.kotlinx:kotlinx-coroutines-core-iossimulatorarm64:1.10.0=iosSimulatorArm64TestCInterop,iosSimulatorArm64TestCompilationDependenciesMetadata,iosSimulatorArm64TestCompileKlibraries +org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.10.0=androidDebugAndroidTestCompileClasspath,androidDebugAndroidTestRuntimeClasspath,androidDebugUnitTestCompileClasspath,androidDebugUnitTestRuntimeClasspath,androidReleaseUnitTestCompileClasspath,androidReleaseUnitTestRuntimeClasspath,debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,jvmTestCompileClasspath,jvmTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.6.4=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.7.3=dokkaHtmlGeneratorRuntimeResolver~internal +org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.8.0=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinKlibCommonizerClasspath +org.jetbrains.kotlinx:kotlinx-coroutines-core-linuxarm64:1.10.0=linuxArm64TestCInterop,linuxArm64TestCompilationDependenciesMetadata,linuxArm64TestCompileKlibraries +org.jetbrains.kotlinx:kotlinx-coroutines-core-linuxx64:1.10.0=linuxX64TestCInterop,linuxX64TestCompilationDependenciesMetadata,linuxX64TestCompileKlibraries +org.jetbrains.kotlinx:kotlinx-coroutines-core-macosarm64:1.10.0=macosArm64TestCInterop,macosArm64TestCompilationDependenciesMetadata,macosArm64TestCompileKlibraries +org.jetbrains.kotlinx:kotlinx-coroutines-core-macosx64:1.10.0=macosX64TestCInterop,macosX64TestCompilationDependenciesMetadata,macosX64TestCompileKlibraries +org.jetbrains.kotlinx:kotlinx-coroutines-core-mingwx64:1.10.0=mingwX64TestCInterop,mingwX64TestCompilationDependenciesMetadata,mingwX64TestCompileKlibraries +org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.0=allInstrumentedTestSourceSetsCompileDependenciesMetadata,allTestSourceSetsCompileDependenciesMetadata,androidDebugAndroidTestCompileClasspath,androidDebugAndroidTestRuntimeClasspath,androidDebugUnitTestCompileClasspath,androidDebugUnitTestRuntimeClasspath,androidInstrumentedTestApiDependenciesMetadata,androidInstrumentedTestCompileOnlyDependenciesMetadata,androidInstrumentedTestImplementationDependenciesMetadata,androidInstrumentedTestResolvableDependenciesMetadata,androidReleaseUnitTestCompileClasspath,androidReleaseUnitTestRuntimeClasspath,androidUnitTestApiDependenciesMetadata,androidUnitTestCompileOnlyDependenciesMetadata,androidUnitTestDebugApiDependenciesMetadata,androidUnitTestDebugCompileOnlyDependenciesMetadata,androidUnitTestDebugImplementationDependenciesMetadata,androidUnitTestDebugResolvableDependenciesMetadata,androidUnitTestImplementationDependenciesMetadata,androidUnitTestReleaseApiDependenciesMetadata,androidUnitTestReleaseCompileOnlyDependenciesMetadata,androidUnitTestReleaseImplementationDependenciesMetadata,androidUnitTestReleaseResolvableDependenciesMetadata,androidUnitTestResolvableDependenciesMetadata,appleTestApiDependenciesMetadata,appleTestCompileOnlyDependenciesMetadata,appleTestImplementationDependenciesMetadata,appleTestResolvableDependenciesMetadata,commonTestApiDependenciesMetadata,commonTestCompileOnlyDependenciesMetadata,commonTestImplementationDependenciesMetadata,commonTestResolvableDependenciesMetadata,debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,iosArm64TestApiDependenciesMetadata,iosArm64TestCInterop,iosArm64TestCompilationDependenciesMetadata,iosArm64TestCompileKlibraries,iosArm64TestCompileOnlyDependenciesMetadata,iosArm64TestImplementationDependenciesMetadata,iosArm64TestResolvableDependenciesMetadata,iosSimulatorArm64TestApiDependenciesMetadata,iosSimulatorArm64TestCInterop,iosSimulatorArm64TestCompilationDependenciesMetadata,iosSimulatorArm64TestCompileKlibraries,iosSimulatorArm64TestCompileOnlyDependenciesMetadata,iosSimulatorArm64TestImplementationDependenciesMetadata,iosSimulatorArm64TestResolvableDependenciesMetadata,iosTestApiDependenciesMetadata,iosTestCompileOnlyDependenciesMetadata,iosTestImplementationDependenciesMetadata,iosTestResolvableDependenciesMetadata,jvmTestApiDependenciesMetadata,jvmTestCompileClasspath,jvmTestCompileOnlyDependenciesMetadata,jvmTestImplementationDependenciesMetadata,jvmTestResolvableDependenciesMetadata,jvmTestRuntimeClasspath,linuxArm64TestApiDependenciesMetadata,linuxArm64TestCInterop,linuxArm64TestCompilationDependenciesMetadata,linuxArm64TestCompileKlibraries,linuxArm64TestCompileOnlyDependenciesMetadata,linuxArm64TestImplementationDependenciesMetadata,linuxArm64TestResolvableDependenciesMetadata,linuxTestApiDependenciesMetadata,linuxTestCompileOnlyDependenciesMetadata,linuxTestImplementationDependenciesMetadata,linuxTestResolvableDependenciesMetadata,linuxX64TestApiDependenciesMetadata,linuxX64TestCInterop,linuxX64TestCompilationDependenciesMetadata,linuxX64TestCompileKlibraries,linuxX64TestCompileOnlyDependenciesMetadata,linuxX64TestImplementationDependenciesMetadata,linuxX64TestResolvableDependenciesMetadata,macosArm64TestApiDependenciesMetadata,macosArm64TestCInterop,macosArm64TestCompilationDependenciesMetadata,macosArm64TestCompileKlibraries,macosArm64TestCompileOnlyDependenciesMetadata,macosArm64TestImplementationDependenciesMetadata,macosArm64TestResolvableDependenciesMetadata,macosTestApiDependenciesMetadata,macosTestCompileOnlyDependenciesMetadata,macosTestImplementationDependenciesMetadata,macosTestResolvableDependenciesMetadata,macosX64TestApiDependenciesMetadata,macosX64TestCInterop,macosX64TestCompilationDependenciesMetadata,macosX64TestCompileKlibraries,macosX64TestCompileOnlyDependenciesMetadata,macosX64TestImplementationDependenciesMetadata,macosX64TestResolvableDependenciesMetadata,mingwTestApiDependenciesMetadata,mingwTestCompileOnlyDependenciesMetadata,mingwTestImplementationDependenciesMetadata,mingwTestResolvableDependenciesMetadata,mingwX64TestApiDependenciesMetadata,mingwX64TestCInterop,mingwX64TestCompilationDependenciesMetadata,mingwX64TestCompileKlibraries,mingwX64TestCompileOnlyDependenciesMetadata,mingwX64TestImplementationDependenciesMetadata,mingwX64TestResolvableDependenciesMetadata,nativeTestApiDependenciesMetadata,nativeTestCompileOnlyDependenciesMetadata,nativeTestImplementationDependenciesMetadata,nativeTestResolvableDependenciesMetadata,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4=_internal-unified-test-platform-android-device-provider-ddmlib,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle +org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3=dokkaHtmlGeneratorRuntimeResolver~internal +org.jetbrains.kotlinx:kotlinx-coroutines-debug:1.10.0=androidDebugAndroidTestCompileClasspath,androidDebugAndroidTestRuntimeClasspath,androidDebugUnitTestCompileClasspath,androidDebugUnitTestRuntimeClasspath,androidReleaseUnitTestCompileClasspath,androidReleaseUnitTestRuntimeClasspath,debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,jvmTestCompileClasspath,jvmTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.10.0=androidDebugAndroidTestRuntimeClasspath,androidDebugUnitTestRuntimeClasspath,androidReleaseUnitTestRuntimeClasspath,debugAndroidTestRuntimeClasspath,debugUnitTestRuntimeClasspath,jvmTestRuntimeClasspath,releaseUnitTestRuntimeClasspath +org.jetbrains.kotlinx:kotlinx-coroutines-test-iosarm64:1.10.0=iosArm64TestCInterop,iosArm64TestCompilationDependenciesMetadata,iosArm64TestCompileKlibraries +org.jetbrains.kotlinx:kotlinx-coroutines-test-iossimulatorarm64:1.10.0=iosSimulatorArm64TestCInterop,iosSimulatorArm64TestCompilationDependenciesMetadata,iosSimulatorArm64TestCompileKlibraries +org.jetbrains.kotlinx:kotlinx-coroutines-test-jvm:1.10.0=androidDebugAndroidTestRuntimeClasspath,androidDebugUnitTestRuntimeClasspath,androidReleaseUnitTestRuntimeClasspath,debugAndroidTestRuntimeClasspath,debugUnitTestRuntimeClasspath,jvmTestRuntimeClasspath,releaseUnitTestRuntimeClasspath +org.jetbrains.kotlinx:kotlinx-coroutines-test-linuxarm64:1.10.0=linuxArm64TestCInterop,linuxArm64TestCompilationDependenciesMetadata,linuxArm64TestCompileKlibraries +org.jetbrains.kotlinx:kotlinx-coroutines-test-linuxx64:1.10.0=linuxX64TestCInterop,linuxX64TestCompilationDependenciesMetadata,linuxX64TestCompileKlibraries +org.jetbrains.kotlinx:kotlinx-coroutines-test-macosarm64:1.10.0=macosArm64TestCInterop,macosArm64TestCompilationDependenciesMetadata,macosArm64TestCompileKlibraries +org.jetbrains.kotlinx:kotlinx-coroutines-test-macosx64:1.10.0=macosX64TestCInterop,macosX64TestCompilationDependenciesMetadata,macosX64TestCompileKlibraries +org.jetbrains.kotlinx:kotlinx-coroutines-test-mingwx64:1.10.0=mingwX64TestCInterop,mingwX64TestCompilationDependenciesMetadata,mingwX64TestCompileKlibraries +org.jetbrains.kotlinx:kotlinx-coroutines-test:1.10.0=allInstrumentedTestSourceSetsCompileDependenciesMetadata,allTestSourceSetsCompileDependenciesMetadata,androidDebugAndroidTestRuntimeClasspath,androidDebugUnitTestRuntimeClasspath,androidInstrumentedTestApiDependenciesMetadata,androidInstrumentedTestCompileOnlyDependenciesMetadata,androidInstrumentedTestImplementationDependenciesMetadata,androidInstrumentedTestResolvableDependenciesMetadata,androidReleaseUnitTestRuntimeClasspath,androidUnitTestApiDependenciesMetadata,androidUnitTestCompileOnlyDependenciesMetadata,androidUnitTestDebugApiDependenciesMetadata,androidUnitTestDebugCompileOnlyDependenciesMetadata,androidUnitTestDebugImplementationDependenciesMetadata,androidUnitTestDebugResolvableDependenciesMetadata,androidUnitTestImplementationDependenciesMetadata,androidUnitTestReleaseApiDependenciesMetadata,androidUnitTestReleaseCompileOnlyDependenciesMetadata,androidUnitTestReleaseImplementationDependenciesMetadata,androidUnitTestReleaseResolvableDependenciesMetadata,androidUnitTestResolvableDependenciesMetadata,appleTestApiDependenciesMetadata,appleTestCompileOnlyDependenciesMetadata,appleTestImplementationDependenciesMetadata,appleTestResolvableDependenciesMetadata,commonTestApiDependenciesMetadata,commonTestCompileOnlyDependenciesMetadata,commonTestImplementationDependenciesMetadata,commonTestResolvableDependenciesMetadata,debugAndroidTestRuntimeClasspath,debugUnitTestRuntimeClasspath,iosArm64TestApiDependenciesMetadata,iosArm64TestCInterop,iosArm64TestCompilationDependenciesMetadata,iosArm64TestCompileKlibraries,iosArm64TestCompileOnlyDependenciesMetadata,iosArm64TestImplementationDependenciesMetadata,iosArm64TestResolvableDependenciesMetadata,iosSimulatorArm64TestApiDependenciesMetadata,iosSimulatorArm64TestCInterop,iosSimulatorArm64TestCompilationDependenciesMetadata,iosSimulatorArm64TestCompileKlibraries,iosSimulatorArm64TestCompileOnlyDependenciesMetadata,iosSimulatorArm64TestImplementationDependenciesMetadata,iosSimulatorArm64TestResolvableDependenciesMetadata,iosTestApiDependenciesMetadata,iosTestCompileOnlyDependenciesMetadata,iosTestImplementationDependenciesMetadata,iosTestResolvableDependenciesMetadata,jvmTestApiDependenciesMetadata,jvmTestCompileOnlyDependenciesMetadata,jvmTestImplementationDependenciesMetadata,jvmTestResolvableDependenciesMetadata,jvmTestRuntimeClasspath,linuxArm64TestApiDependenciesMetadata,linuxArm64TestCInterop,linuxArm64TestCompilationDependenciesMetadata,linuxArm64TestCompileKlibraries,linuxArm64TestCompileOnlyDependenciesMetadata,linuxArm64TestImplementationDependenciesMetadata,linuxArm64TestResolvableDependenciesMetadata,linuxTestApiDependenciesMetadata,linuxTestCompileOnlyDependenciesMetadata,linuxTestImplementationDependenciesMetadata,linuxTestResolvableDependenciesMetadata,linuxX64TestApiDependenciesMetadata,linuxX64TestCInterop,linuxX64TestCompilationDependenciesMetadata,linuxX64TestCompileKlibraries,linuxX64TestCompileOnlyDependenciesMetadata,linuxX64TestImplementationDependenciesMetadata,linuxX64TestResolvableDependenciesMetadata,macosArm64TestApiDependenciesMetadata,macosArm64TestCInterop,macosArm64TestCompilationDependenciesMetadata,macosArm64TestCompileKlibraries,macosArm64TestCompileOnlyDependenciesMetadata,macosArm64TestImplementationDependenciesMetadata,macosArm64TestResolvableDependenciesMetadata,macosTestApiDependenciesMetadata,macosTestCompileOnlyDependenciesMetadata,macosTestImplementationDependenciesMetadata,macosTestResolvableDependenciesMetadata,macosX64TestApiDependenciesMetadata,macosX64TestCInterop,macosX64TestCompilationDependenciesMetadata,macosX64TestCompileKlibraries,macosX64TestCompileOnlyDependenciesMetadata,macosX64TestImplementationDependenciesMetadata,macosX64TestResolvableDependenciesMetadata,mingwTestApiDependenciesMetadata,mingwTestCompileOnlyDependenciesMetadata,mingwTestImplementationDependenciesMetadata,mingwTestResolvableDependenciesMetadata,mingwX64TestApiDependenciesMetadata,mingwX64TestCInterop,mingwX64TestCompilationDependenciesMetadata,mingwX64TestCompileKlibraries,mingwX64TestCompileOnlyDependenciesMetadata,mingwX64TestImplementationDependenciesMetadata,mingwX64TestResolvableDependenciesMetadata,nativeTestApiDependenciesMetadata,nativeTestCompileOnlyDependenciesMetadata,nativeTestImplementationDependenciesMetadata,nativeTestResolvableDependenciesMetadata,releaseUnitTestRuntimeClasspath +org.jetbrains.kotlinx:kotlinx-html-jvm:0.9.1=dokkaHtmlGeneratorRuntimeResolver~internal +org.jetbrains:annotations:13.0=_internal-unified-test-platform-android-device-provider-gradle,_internal-unified-test-platform-android-test-plugin-host-additional-test-output,_internal-unified-test-platform-android-test-plugin-host-apk-installer,_internal-unified-test-platform-android-test-plugin-host-coverage,_internal-unified-test-platform-android-test-plugin-host-device-info,_internal-unified-test-platform-android-test-plugin-host-emulator-control,_internal-unified-test-platform-android-test-plugin-host-logcat,_internal-unified-test-platform-android-test-plugin-host-retention,_internal-unified-test-platform-android-test-plugin-result-listener-gradle,androidDebugCompileClasspath,androidDebugRuntimeClasspath,androidReleaseCompileClasspath,androidReleaseRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,jvmCompileClasspath,jvmMainCompileClasspath,jvmMainRuntimeClasspath,jvmRuntimeClasspath,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinCompilerPluginClasspathAndroidDebug,kotlinCompilerPluginClasspathAndroidDebugAndroidTest,kotlinCompilerPluginClasspathAndroidDebugUnitTest,kotlinCompilerPluginClasspathAndroidRelease,kotlinCompilerPluginClasspathAndroidReleaseUnitTest,kotlinCompilerPluginClasspathJvmMain,kotlinCompilerPluginClasspathJvmTest,kotlinCompilerPluginClasspathMetadataAppleMain,kotlinCompilerPluginClasspathMetadataCommonMain,kotlinCompilerPluginClasspathMetadataIosMain,kotlinCompilerPluginClasspathMetadataLinuxMain,kotlinCompilerPluginClasspathMetadataMacosMain,kotlinCompilerPluginClasspathMetadataMain,kotlinCompilerPluginClasspathMetadataNativeMain,kotlinKlibCommonizerClasspath,releaseCompileClasspath,releaseRuntimeClasspath +org.jetbrains:annotations:23.0.0=_internal-unified-test-platform-android-device-provider-ddmlib,androidDebugAndroidTestCompileClasspath,androidDebugAndroidTestRuntimeClasspath,androidDebugUnitTestCompileClasspath,androidDebugUnitTestRuntimeClasspath,androidReleaseUnitTestCompileClasspath,androidReleaseUnitTestRuntimeClasspath,debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,dokkaHtmlGeneratorRuntimeResolver~internal,jvmTestCompileClasspath,jvmTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.jetbrains:markdown-jvm:0.7.3=dokkaHtmlGeneratorRuntimeResolver~internal +org.jetbrains:markdown:0.7.3=dokkaHtmlGeneratorRuntimeResolver~internal +org.jsoup:jsoup:1.16.1=dokkaHtmlGeneratorRuntimeResolver~internal +org.junit.jupiter:junit-jupiter-api:5.8.2=jvmTestCompileClasspath,jvmTestRuntimeClasspath +org.junit.platform:junit-platform-commons:1.8.2=jvmTestCompileClasspath,jvmTestRuntimeClasspath +org.junit.platform:junit-platform-engine:1.8.2=jvmTestCompileClasspath,jvmTestRuntimeClasspath +org.junit.platform:junit-platform-launcher:1.8.2=jvmTestCompileClasspath,jvmTestRuntimeClasspath +org.junit.platform:junit-platform-suite-api:1.8.2=jvmTestCompileClasspath,jvmTestRuntimeClasspath +org.junit:junit-bom:5.8.2=jvmTestCompileClasspath,jvmTestRuntimeClasspath +org.opentest4j:opentest4j:1.3.0=androidDebugAndroidTestCompileClasspath,androidDebugAndroidTestRuntimeClasspath,androidDebugUnitTestCompileClasspath,androidDebugUnitTestRuntimeClasspath,androidReleaseUnitTestCompileClasspath,androidReleaseUnitTestRuntimeClasspath,debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,jvmTestCompileClasspath,jvmTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +empty=androidApis,androidDebugIntransitiveDependenciesMetadata,androidInstrumentedTestDebugIntransitiveDependenciesMetadata,androidInstrumentedTestIntransitiveDependenciesMetadata,androidJdkImage,androidMainIntransitiveDependenciesMetadata,androidReleaseIntransitiveDependenciesMetadata,androidTestUtil,androidUnitTestDebugIntransitiveDependenciesMetadata,androidUnitTestIntransitiveDependenciesMetadata,androidUnitTestReleaseIntransitiveDependenciesMetadata,appleMainApiDependenciesMetadata,appleMainCInterop,appleMainCompileOnlyDependenciesMetadata,appleMainImplementationDependenciesMetadata,appleMainIntransitiveDependenciesMetadata,appleMainResolvableDependenciesMetadata,appleTestIntransitiveDependenciesMetadata,commonMainIntransitiveDependenciesMetadata,commonTestIntransitiveDependenciesMetadata,coreLibraryDesugaring,debugAndroidTestAnnotationProcessorClasspath,debugAnnotationProcessorClasspath,debugUnitTestAnnotationProcessorClasspath,dokkaHtmlModuleOutputDirectoriesResolver~internal,dokkaHtmlPublicationPluginResolver~internal,iosArm64MainApiDependenciesMetadata,iosArm64MainCompileOnlyDependenciesMetadata,iosArm64MainImplementationDependenciesMetadata,iosArm64MainIntransitiveDependenciesMetadata,iosArm64MainResolvableDependenciesMetadata,iosArm64TestIntransitiveDependenciesMetadata,iosMainApiDependenciesMetadata,iosMainCInterop,iosMainCompileOnlyDependenciesMetadata,iosMainImplementationDependenciesMetadata,iosMainIntransitiveDependenciesMetadata,iosMainResolvableDependenciesMetadata,iosSimulatorArm64MainApiDependenciesMetadata,iosSimulatorArm64MainCompileOnlyDependenciesMetadata,iosSimulatorArm64MainImplementationDependenciesMetadata,iosSimulatorArm64MainIntransitiveDependenciesMetadata,iosSimulatorArm64MainResolvableDependenciesMetadata,iosSimulatorArm64TestIntransitiveDependenciesMetadata,iosTestIntransitiveDependenciesMetadata,jvmMainAnnotationProcessor,jvmMainIntransitiveDependenciesMetadata,jvmTestAnnotationProcessor,jvmTestIntransitiveDependenciesMetadata,kotlinCompilerPluginClasspath,kotlinNativeCompilerPluginClasspath,kotlinScriptDefExtensions,lintChecks,lintPublish,linuxArm64MainApiDependenciesMetadata,linuxArm64MainCompileOnlyDependenciesMetadata,linuxArm64MainImplementationDependenciesMetadata,linuxArm64MainIntransitiveDependenciesMetadata,linuxArm64MainResolvableDependenciesMetadata,linuxArm64TestIntransitiveDependenciesMetadata,linuxMainApiDependenciesMetadata,linuxMainCInterop,linuxMainCompileOnlyDependenciesMetadata,linuxMainImplementationDependenciesMetadata,linuxMainIntransitiveDependenciesMetadata,linuxMainResolvableDependenciesMetadata,linuxTestIntransitiveDependenciesMetadata,linuxX64MainApiDependenciesMetadata,linuxX64MainCompileOnlyDependenciesMetadata,linuxX64MainImplementationDependenciesMetadata,linuxX64MainIntransitiveDependenciesMetadata,linuxX64MainResolvableDependenciesMetadata,linuxX64TestIntransitiveDependenciesMetadata,macosArm64MainApiDependenciesMetadata,macosArm64MainCompileOnlyDependenciesMetadata,macosArm64MainImplementationDependenciesMetadata,macosArm64MainIntransitiveDependenciesMetadata,macosArm64MainResolvableDependenciesMetadata,macosArm64TestIntransitiveDependenciesMetadata,macosMainApiDependenciesMetadata,macosMainCInterop,macosMainCompileOnlyDependenciesMetadata,macosMainImplementationDependenciesMetadata,macosMainIntransitiveDependenciesMetadata,macosMainResolvableDependenciesMetadata,macosTestIntransitiveDependenciesMetadata,macosX64MainApiDependenciesMetadata,macosX64MainCompileOnlyDependenciesMetadata,macosX64MainImplementationDependenciesMetadata,macosX64MainIntransitiveDependenciesMetadata,macosX64MainResolvableDependenciesMetadata,macosX64TestIntransitiveDependenciesMetadata,mingwMainApiDependenciesMetadata,mingwMainCompileOnlyDependenciesMetadata,mingwMainImplementationDependenciesMetadata,mingwMainIntransitiveDependenciesMetadata,mingwMainResolvableDependenciesMetadata,mingwTestIntransitiveDependenciesMetadata,mingwX64MainApiDependenciesMetadata,mingwX64MainCompileOnlyDependenciesMetadata,mingwX64MainImplementationDependenciesMetadata,mingwX64MainIntransitiveDependenciesMetadata,mingwX64MainResolvableDependenciesMetadata,mingwX64TestIntransitiveDependenciesMetadata,nativeMainApiDependenciesMetadata,nativeMainCInterop,nativeMainCompileOnlyDependenciesMetadata,nativeMainImplementationDependenciesMetadata,nativeMainIntransitiveDependenciesMetadata,nativeMainResolvableDependenciesMetadata,nativeTestIntransitiveDependenciesMetadata,releaseAnnotationProcessorClasspath,releaseUnitTestAnnotationProcessorClasspath,resolvableIosArm64CompilationApi,resolvableIosArm64TestCompilationApi,resolvableIosSimulatorArm64CompilationApi,resolvableIosSimulatorArm64TestCompilationApi,resolvableLinuxArm64CompilationApi,resolvableLinuxArm64TestCompilationApi,resolvableLinuxX64CompilationApi,resolvableLinuxX64TestCompilationApi,resolvableMacosArm64CompilationApi,resolvableMacosArm64TestCompilationApi,resolvableMacosX64CompilationApi,resolvableMacosX64TestCompilationApi,resolvableMingwX64CompilationApi,resolvableMingwX64TestCompilationApi,testKotlinScriptDefExtensions diff --git a/ktreesitter/src/androidInstrumentedTest/kotlin/io/github/treesitter/ktreesitter/LanguageTest.kt b/ktreesitter/src/androidInstrumentedTest/kotlin/io/github/treesitter/ktreesitter/LanguageTest.kt index 80672c8..289e2d7 100644 --- a/ktreesitter/src/androidInstrumentedTest/kotlin/io/github/treesitter/ktreesitter/LanguageTest.kt +++ b/ktreesitter/src/androidInstrumentedTest/kotlin/io/github/treesitter/ktreesitter/LanguageTest.kt @@ -2,9 +2,9 @@ package io.github.treesitter.ktreesitter import br.com.colman.kotest.KotestRunnerAndroid import io.github.treesitter.ktreesitter.java.TreeSitterJava -import io.kotest.assertions.throwables.shouldNotThrowAny import io.kotest.core.spec.style.FunSpec import io.kotest.matchers.* +import io.kotest.matchers.collections.shouldBeEmpty import io.kotest.matchers.comparables.* import io.kotest.matchers.nulls.* import io.kotest.matchers.string.* @@ -15,8 +15,8 @@ import org.junit.runner.RunWith class LanguageTest : FunSpec({ val language = Language(TreeSitterJava.language()) - test("version") { - language.version shouldBe 14U + test("abiVersion") { + language.abiVersion shouldBe 14U } test("symbolCount") { @@ -31,6 +31,19 @@ class LanguageTest : FunSpec({ language.fieldCount shouldBeGreaterThan 1U } + test("name") { + language.name.shouldBeNull() + } + + test("metadata") { + language.metadata.shouldBeNull() + } + + @OptIn(ExperimentalUnsignedTypes::class) + test("supertypes") { + language.supertypes.shouldBeEmpty() + } + test("symbolName()") { language.symbolName(1U) shouldBe "identifier" } @@ -40,6 +53,11 @@ class LanguageTest : FunSpec({ language.symbolForName("program", true) shouldBeGreaterThan 0U } + @OptIn(ExperimentalUnsignedTypes::class) + test("subtypes") { + language.subtypes(1U).shouldBeEmpty() + } + test("isNamed()") { language.isNamed(1U) shouldBe true } @@ -72,10 +90,6 @@ class LanguageTest : FunSpec({ lookahead.language shouldBe language } - test("query()") { - shouldNotThrowAny { language.query("(program) @root") } - } - test("equals()") { Language(TreeSitterJava.language()) shouldBe language.copy() } @@ -85,6 +99,6 @@ class LanguageTest : FunSpec({ } test("toString()") { - language.toString() shouldMatch Regex("""Language\(id=0x[0-9a-f]+, version=14\)""") + language.toString() shouldMatch Regex("""Language\(id=0x[0-9a-f]+, abiVersion=14\)""") } }) diff --git a/ktreesitter/src/androidInstrumentedTest/kotlin/io/github/treesitter/ktreesitter/NodeTest.kt b/ktreesitter/src/androidInstrumentedTest/kotlin/io/github/treesitter/ktreesitter/NodeTest.kt index dbcd3bc..f08e1a5 100644 --- a/ktreesitter/src/androidInstrumentedTest/kotlin/io/github/treesitter/ktreesitter/NodeTest.kt +++ b/ktreesitter/src/androidInstrumentedTest/kotlin/io/github/treesitter/ktreesitter/NodeTest.kt @@ -149,6 +149,14 @@ class NodeTest : FunSpec({ shouldThrow { rootNode.namedChild(1U) } } + test("firstChildForByte()") { + rootNode.firstChildForByte(10U)!!.type shouldBe "class_declaration" + } + + test("firstNamedChildForByte()") { + rootNode.firstNamedChildForByte(10U)!!.type shouldBe "class_declaration" + } + test("childByFieldId()") { rootNode.childByFieldId(0U).shouldBeNull() } @@ -177,13 +185,6 @@ class NodeTest : FunSpec({ rootNode.child(0U)!!.fieldNameForNamedChild(2U).shouldBeNull() } - @Suppress("DEPRECATION") - test("childContainingDescendant()") { - val descendant = rootNode.child(0U)!!.child(0U)!! - val child = rootNode.childContainingDescendant(descendant) - child?.type shouldBe "class_declaration" - } - test("childWithDescendant()") { val descendant = rootNode.child(0U)!! val child = rootNode.childWithDescendant(descendant) diff --git a/ktreesitter/src/androidInstrumentedTest/kotlin/io/github/treesitter/ktreesitter/ParserTest.kt b/ktreesitter/src/androidInstrumentedTest/kotlin/io/github/treesitter/ktreesitter/ParserTest.kt index 995c139..ce4cf34 100644 --- a/ktreesitter/src/androidInstrumentedTest/kotlin/io/github/treesitter/ktreesitter/ParserTest.kt +++ b/ktreesitter/src/androidInstrumentedTest/kotlin/io/github/treesitter/ktreesitter/ParserTest.kt @@ -30,12 +30,6 @@ class ParserTest : FunSpec({ parser.includedRanges shouldHaveSingleElement range } - test("timeoutMicros") { - parser.timeoutMicros shouldBe 0UL - parser.timeoutMicros = 10000UL - parser.timeoutMicros shouldBe 10000UL - } - test("logger") { shouldNotThrowAnyUnit { parser.logger = { _, _ -> @@ -61,12 +55,12 @@ class ParserTest : FunSpec({ } // UTF-16 - source = "var java = \"💩\"" - tree = parser.parse(source) - tree.text()?.subSequence(12, 14) shouldBe "\uD83D\uDCA9" + source = "\uFEFFvar java = \"💩\"" + tree = parser.parse(source, encoding = InputEncoding.UTF_16BE) + tree.text()?.subSequence(13, 15) shouldBe "\uD83D\uDCA9" } - test("parse(callback)") { + test("parse(readCallback)") { val source = "class Foo {}" val tree = parser.parse { byte, _ -> val end = minOf(byte.toInt() * 2, source.length) @@ -77,9 +71,8 @@ class ParserTest : FunSpec({ } afterTest { (test, _) -> - when (test.name.testName) { + when (test.name.name) { "includedRanges" -> parser.includedRanges = emptyList() - "timeoutMicros" -> parser.timeoutMicros = 0UL "logger" -> parser.logger = null } } diff --git a/ktreesitter/src/androidMain/kotlin/io/github/treesitter/ktreesitter/InputEncoding.kt b/ktreesitter/src/androidMain/kotlin/io/github/treesitter/ktreesitter/InputEncoding.kt new file mode 100644 index 0000000..f927ec4 --- /dev/null +++ b/ktreesitter/src/androidMain/kotlin/io/github/treesitter/ktreesitter/InputEncoding.kt @@ -0,0 +1,14 @@ +package io.github.treesitter.ktreesitter + +import java.nio.charset.Charset + +/** + * The encoding of the input text. + * + * @since 0.25.0 + */ +actual enum class InputEncoding(val charset: Charset) { + UTF_8(Charsets.UTF_8), + UTF_16LE(Charsets.UTF_16LE), + UTF_16BE(Charsets.UTF_16BE) +} diff --git a/ktreesitter/src/androidMain/kotlin/io/github/treesitter/ktreesitter/Language.kt b/ktreesitter/src/androidMain/kotlin/io/github/treesitter/ktreesitter/Language.kt index 4000182..2147011 100644 --- a/ktreesitter/src/androidMain/kotlin/io/github/treesitter/ktreesitter/Language.kt +++ b/ktreesitter/src/androidMain/kotlin/io/github/treesitter/ktreesitter/Language.kt @@ -6,12 +6,13 @@ import dalvik.annotation.optimization.FastNative /** * A class that defines how to parse a particular language. * - * When a [Language] is generated by the Tree-sitter CLI, it is assigned - * an ABI [version] number that corresponds to the current CLI version. + * When a [Language] is generated by the Tree-sitter CLI, it is assigned an + * [ABI version][abiVersion] number that corresponds to the current CLI version. * * @constructor Create a new instance from the given language pointer. * @param language A pointer to a `TSLanguage` cast to [Long]. - * @throws [IllegalArgumentException] If the pointer is invalid or the [version] is incompatible. + * @throws [IllegalArgumentException] + * If the pointer is invalid or the [version][abiVersion] is incompatible. */ actual class Language @Throws(IllegalArgumentException::class) actual constructor(language: Any) { @JvmField @@ -22,7 +23,17 @@ actual class Language @Throws(IllegalArgumentException::class) actual constructo checkVersion() } + /** + * The ABI version number for this language. + * + * @since 0.25.0 + */ + @get:JvmName("getAbiVersion") + actual val abiVersion: UInt + @FastNative external get + /** The ABI version number for this language. */ + @Deprecated("version is deprecated", ReplaceWith("abiVersion"), DeprecationLevel.ERROR) @get:JvmName("getVersion") actual val version: UInt @FastNative external get @@ -42,6 +53,32 @@ actual class Language @Throws(IllegalArgumentException::class) actual constructo actual val fieldCount: UInt @FastNative external get + /** + * The name of the language, if available. + * + * @since 0.25.0 + */ + actual val name: String? + @FastNative external get + + /** + * The metadata of the language, if available. + * + * @since 0.25.0 + */ + actual val metadata: Metadata? + @FastNative external get + + /** + * The supertype symbols of the language. + * + * @since 0.25.0 + */ + @OptIn(ExperimentalUnsignedTypes::class) + @get:JvmName("getSupertypes") + actual val supertypes: UShortArray + @FastNative external get + /** * Get another reference to the language. * @@ -59,6 +96,17 @@ actual class Language @Throws(IllegalArgumentException::class) actual constructo @JvmName("symbolForName") actual external fun symbolForName(name: String, isNamed: Boolean): UShort + /** + * Get the subtype symbols for the given supertype symbol + * + * @since 0.25.0 + * @see supertypes + */ + @FastNative + @JvmName("subtypes") + @OptIn(ExperimentalUnsignedTypes::class) + actual external fun subtypes(supertype: UShort): UShortArray + /** * Check if the node for the given numerical ID is named * @@ -119,11 +167,12 @@ actual class Language @Throws(IllegalArgumentException::class) actual constructo /** * Create a new [Query] from a string containing one or more S-expression - * [patterns](https://tree-sitter.github.io/tree-sitter/using-parsers#query-syntax). + * [patterns](https://tree-sitter.github.io/tree-sitter/using-parsers/queries/1-syntax.html). * * @throws [QueryError] If any error occurred while creating the query. */ @Throws(QueryError::class) + @Deprecated("Use the Query constructor instead") actual fun query(source: String) = Query(this, source) actual override fun equals(other: Any?) = @@ -131,12 +180,33 @@ actual class Language @Throws(IllegalArgumentException::class) actual constructo actual override fun hashCode() = self.hashCode() - override fun toString() = "Language(id=0x${self.toString(16)}, version=$version)" + override fun toString() = "Language(id=0x${self.toString(16)}, abiVersion=$abiVersion)" @FastNative @Throws(IllegalArgumentException::class) private external fun checkVersion() + /** + * A class containing the [Language] metadata. + * + * @property semanticVersion The [Semantic Version](https://semver.org/) of the [Language]. + */ + @ConsistentCopyVisibility + actual data class Metadata internal actual constructor( + @get:JvmName("getSemanticVersion") + actual val semanticVersion: Triple + ) { + actual override fun toString() = buildString { + append("Metadata(semanticVersion=\"") + append(semanticVersion.first) + append('.') + append(semanticVersion.second) + append('.') + append(semanticVersion.third) + append("\")") + } + } + private companion object { @JvmStatic @CriticalNative diff --git a/ktreesitter/src/androidMain/kotlin/io/github/treesitter/ktreesitter/LookaheadIterator.kt b/ktreesitter/src/androidMain/kotlin/io/github/treesitter/ktreesitter/LookaheadIterator.kt index afa9dfc..59c34f1 100644 --- a/ktreesitter/src/androidMain/kotlin/io/github/treesitter/ktreesitter/LookaheadIterator.kt +++ b/ktreesitter/src/androidMain/kotlin/io/github/treesitter/ktreesitter/LookaheadIterator.kt @@ -80,7 +80,7 @@ actual class LookaheadIterator @Throws(IllegalArgumentException::class) internal override fun close() = delete(self) - override fun computeNext() = if (nativeNext()) { + actual override fun computeNext() = if (nativeNext()) { setNext(Symbol(currentSymbol, currentSymbolName)) } else { done() diff --git a/ktreesitter/src/androidMain/kotlin/io/github/treesitter/ktreesitter/Node.kt b/ktreesitter/src/androidMain/kotlin/io/github/treesitter/ktreesitter/Node.kt index fe7f81a..8608780 100644 --- a/ktreesitter/src/androidMain/kotlin/io/github/treesitter/ktreesitter/Node.kt +++ b/ktreesitter/src/androidMain/kotlin/io/github/treesitter/ktreesitter/Node.kt @@ -207,6 +207,26 @@ actual class Node internal constructor( @Throws(IndexOutOfBoundsException::class) actual external fun namedChild(index: UInt): Node? + /** + * Get the node's first child that contains + * or starts after the given byte offset. + * + * @since 0.25.0 + */ + @FastNative + @JvmName("firstChildForByte") + actual external fun firstChildForByte(byte: UInt): Node? + + /** + * Get the node's first _named_ child that contains + * or starts after the given byte offset. + * + * @since 0.25.0 + */ + @FastNative + @JvmName("firstNamedChildForByte") + actual external fun firstNamedChildForByte(byte: UInt): Node? + /** * Get the node's child with the given field ID, if any. * @@ -249,14 +269,6 @@ actual class Node internal constructor( @Throws(IndexOutOfBoundsException::class) actual external fun fieldNameForNamedChild(index: UInt): String? - /** Get the child of the node that contains the given descendant, if any. */ - @FastNative - @Deprecated( - "This method will not return a direct descendant", - ReplaceWith("childWithDescendant(descendant)", "io.github.treesitter.ktreesitter.Node") - ) - actual external fun childContainingDescendant(descendant: Node): Node? - /** * Get the node that contains the given descendant, if any. * diff --git a/ktreesitter/src/androidMain/kotlin/io/github/treesitter/ktreesitter/Parser.kt b/ktreesitter/src/androidMain/kotlin/io/github/treesitter/ktreesitter/Parser.kt index 9cf1b3f..54de309 100644 --- a/ktreesitter/src/androidMain/kotlin/io/github/treesitter/ktreesitter/Parser.kt +++ b/ktreesitter/src/androidMain/kotlin/io/github/treesitter/ktreesitter/Parser.kt @@ -50,6 +50,7 @@ actual class Parser actual constructor() : AutoCloseable { */ @get:JvmName("getTimeoutMicros") @set:JvmName("setTimeoutMicros") + @Deprecated("Use the progressCallback in parse()") actual var timeoutMicros: ULong @FastNative external get @@ -82,11 +83,10 @@ actual class Parser actual constructor() : AutoCloseable { * [Tree.edit] method in a way that exactly matches the source code changes. * * @throws [IllegalStateException] - * If the parser does not have a [language] assigned or - * if parsing was cancelled due to a [timeout][timeoutMicros]. + * If the parser does not have a [language] assigned or if parsing was halted. */ @Throws(IllegalStateException::class) - actual external fun parse(source: String, oldTree: Tree?): Tree + actual external fun parse(source: String, encoding: InputEncoding, oldTree: Tree?): Tree /** * Parse source code from a callback and create a syntax tree. @@ -98,19 +98,22 @@ actual class Parser actual constructor() : AutoCloseable { * [Tree.edit] method in a way that exactly matches the source code changes. * * @throws [IllegalStateException] - * If the parser does not have a [language] assigned or - * if parsing was cancelled due to a [timeout][timeoutMicros]. + * If the parser does not have a [language] assigned or if parsing was halted. */ @Throws(IllegalStateException::class) - actual external fun parse(oldTree: Tree?, callback: ParseCallback): Tree + actual external fun parse( + encoding: InputEncoding, + oldTree: Tree?, + progressCallback: ParseProgressCallback?, + readCallback: ParseReadCallback + ): Tree /** * Instruct the parser to start the next [parse] from the beginning. * - * If the parser previously failed because of a [timeout][timeoutMicros], - * then by default, it will resume where it left off. If you don't - * want to resume, and instead intend to use this parser to parse - * some other document, you must call this method first. + * If parsing was previously halted, then by default, it will resume where + * it left off. If you don't want to resume, and instead intend to use this + * parser to parse some other document, you must call this method first. */ @FastNative actual external fun reset() diff --git a/ktreesitter/src/androidMain/kotlin/io/github/treesitter/ktreesitter/Query.kt b/ktreesitter/src/androidMain/kotlin/io/github/treesitter/ktreesitter/Query.kt index 2a1d173..b63dacc 100644 --- a/ktreesitter/src/androidMain/kotlin/io/github/treesitter/ktreesitter/Query.kt +++ b/ktreesitter/src/androidMain/kotlin/io/github/treesitter/ktreesitter/Query.kt @@ -18,13 +18,9 @@ actual class Query @Throws(QueryError::class) actual constructor( private val language: Language, private val source: String ) : AutoCloseable { - private val self: Long = init(language.self, source) + internal val self: Long = init(language.self, source) - private val cursor: Long = cursor() - - private val captureNames: MutableList - - private val predicates: List> + internal val predicates: List> private val settingList: List> @@ -33,25 +29,40 @@ actual class Query @Throws(QueryError::class) actual constructor( /** The number of patterns in the query. */ @get:JvmName("getPatternCount") actual val patternCount: UInt - @FastNative external get + get() = nativePatternCount().toUInt() /** The number of captures in the query. */ @get:JvmName("getCaptureCount") + @Deprecated("captureCount is deprecated.", ReplaceWith("captureNames.size")) actual val captureCount: UInt - @FastNative external get + get() = nativeCaptureCount().toUInt() + + /** + * The capture names used in the query. + * + * @since 0.25.0 + */ + actual val captureNames: List + + /** + * The string literals used in the query. + * + * @since 0.25.0 + */ + actual val stringValues: List init { - RefCleaner(this, CleanAction(self, cursor)) + RefCleaner(this, CleanAction(self)) - predicates = List(patternCount.toInt()) { mutableListOf() } - settingList = List(patternCount.toInt()) { mutableMapOf() } - assertionList = List(patternCount.toInt()) { mutableMapOf() } - captureNames = MutableList(captureCount.toInt()) { + predicates = List(nativePatternCount()) { mutableListOf() } + settingList = List(nativePatternCount()) { mutableMapOf() } + assertionList = List(nativePatternCount()) { mutableMapOf() } + captureNames = List(nativeCaptureCount()) { checkNotNull(captureNameForId(it)) { "Failed to get capture name at index $it" } } - val stringValues = List(stringCount()) { + stringValues = List(stringCount()) { checkNotNull(stringValueForId(it)) { "Failed to get string value at index $it" } @@ -268,134 +279,15 @@ actual class Query @Throws(QueryError::class) actual constructor( } /** - * The maximum duration in microseconds that query - * execution should be allowed to take before halting. - * - * Default: `0` - * - * @since 0.23.0 - */ - @get:JvmName("getTimeoutMicros") - @set:JvmName("setTimeoutMicros") - actual var timeoutMicros: ULong - @FastNative external get - - @FastNative external set - - /** - * The maximum number of in-progress matches. - * - * Default: `UInt.MAX_VALUE` - * - * @throws [IllegalArgumentException] If the match limit is set to `0`. - */ - @get:JvmName("getMatchLimit") - @set:JvmName("setMatchLimit") - actual var matchLimit: UInt - @FastNative external get - - @FastNative external set - - /** - * The maximum start depth for the query. - * - * This prevents cursors from exploring children nodes at a certain depth. - * Note that if a pattern includes many children, then they will still be checked. - * - * Default: `UInt.MAX_VALUE` - */ - @get:JvmName("getMaxStartDepth") - @set:JvmName("setMaxStartDepth") - actual var maxStartDepth: UInt = UInt.MAX_VALUE - @FastNative external set - - /** - * The range of bytes in which the query will be executed. - * - * Default: `UInt.MIN_VALUE..UInt.MAX_VALUE` - */ - actual var byteRange: UIntRange = UInt.MIN_VALUE..UInt.MAX_VALUE - set(value) { - nativeSetByteRange(value.first.toInt(), value.last.toInt()) - field = value - } - - /** - * The range of points in which the query will be executed. - * - * Default: `Point.MIN..Point.MAX` - */ - actual var pointRange: ClosedRange = Point.MIN..Point.MAX - set(value) { - nativeSetPointRange(value.start, value.endInclusive) - field = value - } - - /** - * Check if the query exceeded its maximum number of - * in-progress matches during its last execution. - */ - @get:JvmName("didExceedMatchLimit") - actual val didExceedMatchLimit: Boolean - @FastNative external get - - /** - * Iterate over all the matches in the order that they were found. - * - * #### Example - * - * ```kotlin - * query.matches(tree.rootNode) { - * if (name != "ieq?") return@matches true - * val node = it[(args[0] as QueryPredicateArg.Capture).value].first() - * val value = (args[1] as QueryPredicateArg.Literal).value - * value.equals(node.text()?.toString(), ignoreCase = true) - * } - * ``` - * - * @param node The node that the query will run on. - * @param predicate A function that handles custom predicates. - */ - @JvmOverloads - actual fun matches( - node: Node, - predicate: QueryPredicate.(QueryMatch) -> Boolean - ): Sequence { - exec(node) - return sequence { - var match = nextMatch(node.tree) - while (match != null) { - val result = match.check(node.tree, predicate) - if (result != null) yield(result) - match = nextMatch(node.tree) - } - } - } - - /** - * Iterate over all the individual captures in the order that they appear. + * Execute the query on the given [Node]. * - * This is useful if you don't care about _which_ pattern matched. - * - * @param node The node that the query will run on. - * @param predicate A function that handles custom predicates. + * @since 0.25.0 */ + @FastNative @JvmOverloads - actual fun captures( - node: Node, - predicate: QueryPredicate.(QueryMatch) -> Boolean - ): Sequence> { - exec(node) - return sequence { - var capture = nextCapture(node.tree) - while (capture != null) { - val index = capture.first - val match = capture.second.check(node.tree, predicate) - if (match != null) yield(index to match) - capture = nextCapture(node.tree) - } - } - } + @JvmName("exec") + actual operator fun invoke(node: Node, progressCallback: QueryProgressCallback?) = + QueryCursor(this, node, progressCallback) /** * Get the property settings for the given pattern index. @@ -410,7 +302,7 @@ actual class Query @Throws(QueryError::class) actual constructor( @Throws(IndexOutOfBoundsException::class) actual fun settings(index: UInt): Map { if (index >= patternCount) - throw IndexOutOfBoundsException("Pattern index $index is out of bounds") + throw IndexOutOfBoundsException("Index $index exceeds count $patternCount") return settingList[index] } @@ -429,7 +321,7 @@ actual class Query @Throws(QueryError::class) actual constructor( @Throws(IndexOutOfBoundsException::class) actual fun assertions(index: UInt): Map> { if (index >= patternCount) - throw IndexOutOfBoundsException("Pattern index $index is out of bounds") + throw IndexOutOfBoundsException("Index $index exceeds count $patternCount") return assertionList[index] } @@ -453,15 +345,9 @@ actual class Query @Throws(QueryError::class) actual constructor( * This prevents the capture from being returned in matches, * and also avoids most resource usage associated with recording * the capture. Currently, there is no way to undo this. - * - * @throws [NoSuchElementException] If the capture does not exist. */ - @Throws(NoSuchElementException::class) - actual fun disableCapture(name: String) { - if (!captureNames.remove(name)) - throw NoSuchElementException("Capture @$name does not exist") - nativeDisableCapture(name) - } + @FastNative + actual external fun disableCapture(name: String) /** * Get the byte offset where the given pattern starts in the query's source. @@ -517,7 +403,6 @@ actual class Query @Throws(QueryError::class) actual constructor( * Check if a pattern is guaranteed to match * once a given byte offset is reached. */ - @FastNative @JvmName("isPatternGuaranteedAtStep") @Throws(IndexOutOfBoundsException::class) actual fun isPatternGuaranteedAtStep(offset: UInt): Boolean { @@ -528,17 +413,16 @@ actual class Query @Throws(QueryError::class) actual constructor( override fun toString() = "Query(language=$language, source=$source)" - override fun close() = delete(self, cursor) + override fun close() = delete(self) @FastNative - private external fun stringCount(): Int + private external fun nativePatternCount(): Int @FastNative - private external fun exec(node: Node) - - private external fun nextMatch(tree: Tree): QueryMatch? + private external fun nativeCaptureCount(): Int - private external fun nextCapture(tree: Tree): Pair? + @FastNative + private external fun stringCount(): Int @FastNative private external fun captureNameForId(index: Int): String? @@ -546,31 +430,11 @@ actual class Query @Throws(QueryError::class) actual constructor( @FastNative private external fun stringValueForId(index: Int): String? - @FastNative - private external fun nativeSetByteRange(start: Int, end: Int) - - @FastNative - private external fun nativeSetPointRange(start: Point, end: Point) - - @FastNative - private external fun nativeDisableCapture(name: String) - @FastNative private external fun nativeIsPatternGuaranteedAtStep(index: Int): Boolean private external fun predicatesForPattern(index: Int): List? - private inline fun QueryMatch.check( - tree: Tree, - predicate: QueryPredicate.(QueryMatch) -> Boolean - ): QueryMatch? { - if (tree.text() == null) return this - val result = predicates[patternIndex].all { - if (it !is QueryPredicate.Generic) it(this) else predicate(it, this) - } - return if (result) this else null - } - @Suppress("NOTHING_TO_INLINE") private inline operator fun List.get(index: UInt) = get(index.toInt()) @@ -580,8 +444,8 @@ actual class Query @Throws(QueryError::class) actual constructor( private inline val IntArray.type: Int inline get() = get(1) - private class CleanAction(private val query: Long, private val cursor: Long) : Runnable { - override fun run() = delete(query, cursor) + private class CleanAction(private val ptr: Long) : Runnable { + override fun run() = delete(ptr) } @Suppress("ConstPropertyName") @@ -598,10 +462,6 @@ actual class Query @Throws(QueryError::class) actual constructor( @JvmStatic @CriticalNative - private external fun cursor(): Long - - @JvmStatic - @CriticalNative - private external fun delete(query: Long, cursor: Long) + private external fun delete(self: Long) } } diff --git a/ktreesitter/src/androidMain/kotlin/io/github/treesitter/ktreesitter/QueryCursor.kt b/ktreesitter/src/androidMain/kotlin/io/github/treesitter/ktreesitter/QueryCursor.kt new file mode 100644 index 0000000..4a24ccd --- /dev/null +++ b/ktreesitter/src/androidMain/kotlin/io/github/treesitter/ktreesitter/QueryCursor.kt @@ -0,0 +1,209 @@ +package io.github.treesitter.ktreesitter + +import dalvik.annotation.optimization.CriticalNative +import dalvik.annotation.optimization.FastNative + +/** + * A class that is used for executing a query. + * + * __NOTE:__ If you're targeting Android SDK level < 33, + * you must `use` or [close] the instance to free up resources. + * + * @since 0.25.0 + */ +actual class QueryCursor internal constructor( + private val query: Query, + private val node: Node, + progressCallback: QueryProgressCallback? = null +) : AutoCloseable { + private val self: Long = init() + + init { + RefCleaner(this, CleanAction(self)) + + exec(query.self, node, progressCallback) + } + + /** + * The maximum duration in microseconds that query + * execution should be allowed to take before halting. + * + * Default: `0` + * + * @since 0.23.0 + */ + @get:JvmName("getTimeoutMicros") + @set:JvmName("setTimeoutMicros") + @Deprecated("Use the progressCallback in Query.invoke()") + actual var timeoutMicros: ULong + @FastNative external get + + @FastNative external set + + /** + * The maximum number of in-progress matches. + * + * Default: `UInt.MAX_VALUE` + * + * @throws [IllegalArgumentException] If the match limit is set to `0`. + */ + @get:JvmName("getMatchLimit") + @set:JvmName("setMatchLimit") + @set:Throws(IllegalArgumentException::class) + actual var matchLimit: UInt + @FastNative external get + + @FastNative external set + + /** + * The maximum start depth for the query. + * + * This prevents cursors from exploring children nodes at a certain depth. + * Note that if a pattern includes many children, then they will still be checked. + * + * Default: `UInt.MAX_VALUE` + */ + @get:JvmName("getMaxStartDepth") + @set:JvmName("setMaxStartDepth") + actual var maxStartDepth: UInt = UInt.MAX_VALUE + @FastNative external set + + /** + * The range of bytes in which the query will be executed. + * + * The query cursor will return matches that intersect with + * the given range. This means that a match may be returned + * even if some of its captures fall outside the specified range, + * as long as at least part of the match overlaps with the range. + * + * Default: `UInt.MIN_VALUE..UInt.MAX_VALUE` + * + * @throws [IllegalArgumentException] If set to an invalid range. + */ + actual var byteRange: UIntRange = UInt.MIN_VALUE..UInt.MAX_VALUE + set(value) { + require(nativeSetByteRange(value.first.toInt(), value.last.toInt())) { + "Invalid byte range: [${value.first}, ${value.last}]" + } + field = value + } + + /** + * The range of points in which the query will be executed. + * + * The query cursor will return matches that intersect with + * the given range. This means that a match may be returned + * even if some of its captures fall outside the specified range, + * as long as at least part of the match overlaps with the range. + * + * Default: `Point.MIN..Point.MAX` + */ + actual var pointRange: ClosedRange = Point.MIN..Point.MAX + set(value) { + require(nativeSetPointRange(value.start, value.endInclusive)) { + "Invalid point range: [${value.start}, ${value.endInclusive}]" + } + field = value + } + + /** + * Check if the query exceeded its maximum number of + * in-progress matches during its last execution. + * + * @see matchLimit + */ + @get:JvmName("didExceedMatchLimit") + actual val didExceedMatchLimit: Boolean + @FastNative external get + + /** + * Iterate over all the matches in the order that they were found. + * + * #### Example + * + * ```kotlin + * query(tree.rootNode).matches { + * if (name != "ieq?") return@matches true + * val node = it[(args[0] as QueryPredicateArg.Capture).value].first() + * val value = (args[1] as QueryPredicateArg.Literal).value + * value.equals(node.text()?.toString(), ignoreCase = true) + * } + * ``` + * + * @param predicate A function that handles custom predicates. + */ + @JvmOverloads + actual fun matches(predicate: QueryPredicate.(QueryMatch) -> Boolean) = sequence { + var match = nextMatch(query.captureNames, node.tree) + while (match != null) { + val result = match.check(predicate) + if (result != null) yield(result) + match = nextMatch(query.captureNames, node.tree) + } + } + + /** + * Iterate over all the individual captures in the order that they appear. + * + * This is useful if you don't care about _which_ pattern matched. + * + * @param predicate A function that handles custom predicates. + */ + @JvmOverloads + actual fun captures(predicate: QueryPredicate.(QueryMatch) -> Boolean) = + sequence> { + var capture = nextCapture(query.captureNames, node.tree) + while (capture != null) { + val index = capture.first + val match = capture.second.check(predicate) + if (match != null) yield(index to match) + capture = nextCapture(query.captureNames, node.tree) + } + } + + override fun toString() = "QueryCursor(query=$query, node=$node)" + + override fun close() = delete(self) + + @FastNative + private external fun nativeSetByteRange(start: Int, end: Int): Boolean + + @FastNative + private external fun nativeSetPointRange(start: Point, end: Point): Boolean + + @FastNative + private external fun nextMatch(captureNames: List, tree: Tree): QueryMatch? + + @FastNative + private external fun nextCapture( + captureNames: List, + tree: Tree + ): Pair? + + @FastNative + private external fun exec(query: Long, node: Node, progressCallback: QueryProgressCallback?) + + private inline fun QueryMatch.check( + predicate: QueryPredicate.(QueryMatch) -> Boolean + ): QueryMatch? { + if (node.tree.text() == null) return this + val result = query.predicates[patternIndex.toInt()].all { + if (it !is QueryPredicate.Generic) it(this) else predicate(it, this) + } + return if (result) this else null + } + + private class CleanAction(private val ptr: Long) : Runnable { + override fun run() = delete(ptr) + } + + private companion object { + @JvmStatic + @CriticalNative + private external fun init(): Long + + @JvmStatic + @CriticalNative + private external fun delete(self: Long) + } +} diff --git a/ktreesitter/src/commonMain/kotlin/io/github/treesitter/ktreesitter/InputEncoding.kt b/ktreesitter/src/commonMain/kotlin/io/github/treesitter/ktreesitter/InputEncoding.kt new file mode 100644 index 0000000..4733b06 --- /dev/null +++ b/ktreesitter/src/commonMain/kotlin/io/github/treesitter/ktreesitter/InputEncoding.kt @@ -0,0 +1,8 @@ +package io.github.treesitter.ktreesitter + +/** + * The encoding of the input text. + * + * @since 0.25.0 + */ +expect enum class InputEncoding { UTF_8, UTF_16LE, UTF_16BE } diff --git a/ktreesitter/src/commonMain/kotlin/io/github/treesitter/ktreesitter/Language.kt b/ktreesitter/src/commonMain/kotlin/io/github/treesitter/ktreesitter/Language.kt index 297e6f7..19ca63c 100644 --- a/ktreesitter/src/commonMain/kotlin/io/github/treesitter/ktreesitter/Language.kt +++ b/ktreesitter/src/commonMain/kotlin/io/github/treesitter/ktreesitter/Language.kt @@ -10,7 +10,15 @@ package io.github.treesitter.ktreesitter * @throws [IllegalArgumentException] If the pointer is invalid or the [version] is incompatible. */ expect class Language @Throws(IllegalArgumentException::class) constructor(language: Any) { + /** + * The ABI version number for this language. + * + * @since 0.25.0 + */ + val abiVersion: UInt + /** The ABI version number for this language. */ + @Deprecated("version is deprecated", ReplaceWith("abiVersion"), DeprecationLevel.ERROR) val version: UInt /** The number of distinct node types in this language. */ @@ -22,6 +30,28 @@ expect class Language @Throws(IllegalArgumentException::class) constructor(langu /** The number of distinct field names in this language. */ val fieldCount: UInt + /** + * The name of the language, if available. + * + * @since 0.25.0 + */ + val name: String? + + /** + * The metadata of the language, if available. + * + * @since 0.25.0 + */ + val metadata: Metadata? + + /** + * The supertype symbols of the language. + * + * @since 0.25.0 + */ + @OptIn(ExperimentalUnsignedTypes::class) + val supertypes: UShortArray + /** * Get another reference to the language. * @@ -35,6 +65,15 @@ expect class Language @Throws(IllegalArgumentException::class) constructor(langu /** Get the numerical ID for the given node type. */ fun symbolForName(name: String, isNamed: Boolean): UShort + /** + * Get the subtype symbols for the given supertype symbol + * + * @since 0.25.0 + * @see supertypes + */ + @OptIn(ExperimentalUnsignedTypes::class) + fun subtypes(supertype: UShort): UShortArray + /** * Check if the node for the given numerical ID is named * @@ -82,14 +121,26 @@ expect class Language @Throws(IllegalArgumentException::class) constructor(langu /** * Create a new [Query] from a string containing one or more S-expression - * [patterns](https://tree-sitter.github.io/tree-sitter/using-parsers#query-syntax). + * [patterns](https://tree-sitter.github.io/tree-sitter/using-parsers/queries/1-syntax.html). * * @throws [QueryError] If any error occurred while creating the query. */ @Throws(QueryError::class) + @Deprecated("Use the Query constructor instead") fun query(source: String): Query override fun equals(other: Any?): Boolean override fun hashCode(): Int + + /** + * A class containing the [Language] metadata. + * + * @property semanticVersion The [Semantic Version](https://semver.org/) of the [Language]. + */ + class Metadata internal constructor(semanticVersion: Triple) { + val semanticVersion: Triple + + override fun toString(): String + } } diff --git a/ktreesitter/src/commonMain/kotlin/io/github/treesitter/ktreesitter/LookaheadIterator.kt b/ktreesitter/src/commonMain/kotlin/io/github/treesitter/ktreesitter/LookaheadIterator.kt index 46bb316..58b7339 100644 --- a/ktreesitter/src/commonMain/kotlin/io/github/treesitter/ktreesitter/LookaheadIterator.kt +++ b/ktreesitter/src/commonMain/kotlin/io/github/treesitter/ktreesitter/LookaheadIterator.kt @@ -42,6 +42,8 @@ expect class LookaheadIterator : AbstractIterator { /** Iterate over the symbol names. */ fun symbolNames(): Sequence + override fun computeNext() + /** A class that pairs a symbol ID with its name. */ class Symbol(id: UShort, name: String) { val id: UShort diff --git a/ktreesitter/src/commonMain/kotlin/io/github/treesitter/ktreesitter/Node.kt b/ktreesitter/src/commonMain/kotlin/io/github/treesitter/ktreesitter/Node.kt index e1f1d3a..f8f37d4 100644 --- a/ktreesitter/src/commonMain/kotlin/io/github/treesitter/ktreesitter/Node.kt +++ b/ktreesitter/src/commonMain/kotlin/io/github/treesitter/ktreesitter/Node.kt @@ -154,6 +154,22 @@ expect class Node { @Throws(IndexOutOfBoundsException::class) fun namedChild(index: UInt): Node? + /** + * Get the node's first child that contains + * or starts after the given byte offset. + * + * @since 0.25.0 + */ + fun firstChildForByte(byte: UInt): Node? + + /** + * Get the node's first _named_ child that contains + * or starts after the given byte offset. + * + * @since 0.25.0 + */ + fun firstNamedChildForByte(byte: UInt): Node? + /** * Get the node's child with the given field ID, if any. * @@ -187,13 +203,6 @@ expect class Node { @Throws(IndexOutOfBoundsException::class) fun fieldNameForNamedChild(index: UInt): String? - /** Get the child of the node that contains the given descendant, if any. */ - @Deprecated( - "This method will not return a direct descendant", - ReplaceWith("childWithDescendant(descendant)", "io.github.treesitter.ktreesitter.Node") - ) - fun childContainingDescendant(descendant: Node): Node? - /** * Get the node that contains the given descendant, if any. * diff --git a/ktreesitter/src/commonMain/kotlin/io/github/treesitter/ktreesitter/Parser.kt b/ktreesitter/src/commonMain/kotlin/io/github/treesitter/ktreesitter/Parser.kt index 02bf659..5b87bb9 100644 --- a/ktreesitter/src/commonMain/kotlin/io/github/treesitter/ktreesitter/Parser.kt +++ b/ktreesitter/src/commonMain/kotlin/io/github/treesitter/ktreesitter/Parser.kt @@ -5,7 +5,19 @@ package io.github.treesitter.ktreesitter * * The function should return `null` to indicate the end of the document. */ -typealias ParseCallback = (byte: UInt, point: Point) -> CharSequence? +typealias ParseReadCallback = (byte: UInt, point: Point) -> CharSequence? + +/** + * A function that is called during parsing. + * + * The first argument contains the current byte offset and the second + * argument indicates whether the parser has encountered an error. + * + * If the function returns `false`, parsing will halt early. + * + * @since 0.25.0 + */ +typealias ParseProgressCallback = (currentByteOffset: UInt, hasError: Boolean) -> Boolean /** * A function that logs parsing results. @@ -45,14 +57,13 @@ expect class Parser() { * The maximum duration in microseconds that parsing * should be allowed to take before halting. */ + @Deprecated("Use the progressCallback in parse()") var timeoutMicros: ULong /** The logger that the parser will use during parsing. */ @get:Deprecated("The logger can't be called directly.", level = DeprecationLevel.HIDDEN) var logger: LogFunction? - // TODO: add cancellationFlag - /** * Parse a source code string and create a syntax tree. * @@ -63,11 +74,14 @@ expect class Parser() { * [Tree.edit] method in a way that exactly matches the source code changes. * * @throws [IllegalStateException] - * If the parser does not have a [language] assigned or - * if parsing was cancelled due to a [timeout][timeoutMicros]. + * If the parser does not have a [language] assigned or if parsing was halted. */ @Throws(IllegalStateException::class) - fun parse(source: String, oldTree: Tree? = null): Tree + fun parse( + source: String, + encoding: InputEncoding = InputEncoding.UTF_8, + oldTree: Tree? = null + ): Tree /** * Parse source code from a callback and create a syntax tree. @@ -79,19 +93,22 @@ expect class Parser() { * [Tree.edit] method in a way that exactly matches the source code changes. * * @throws [IllegalStateException] - * If the parser does not have a [language] assigned or - * if parsing was cancelled due to a [timeout][timeoutMicros]. + * If the parser does not have a [language] assigned or if parsing was halted. */ @Throws(IllegalStateException::class) - fun parse(oldTree: Tree? = null, callback: ParseCallback): Tree + fun parse( + encoding: InputEncoding = InputEncoding.UTF_8, + oldTree: Tree? = null, + progressCallback: ParseProgressCallback? = null, + readCallback: ParseReadCallback + ): Tree /** * Instruct the parser to start the next [parse] from the beginning. * - * If the parser previously failed because of a [timeout][timeoutMicros], - * then by default, it will resume where it left off. If you don't - * want to resume, and instead intend to use this parser to parse - * some other document, you must call this method first. + * If parsing was previously halted, then by default, it will resume where + * it left off. If you don't want to resume, and instead intend to use this + * parser to parse some other document, you must call this method first. */ fun reset() diff --git a/ktreesitter/src/commonMain/kotlin/io/github/treesitter/ktreesitter/Query.kt b/ktreesitter/src/commonMain/kotlin/io/github/treesitter/ktreesitter/Query.kt index e6e7e25..9c739ee 100644 --- a/ktreesitter/src/commonMain/kotlin/io/github/treesitter/ktreesitter/Query.kt +++ b/ktreesitter/src/commonMain/kotlin/io/github/treesitter/ktreesitter/Query.kt @@ -1,5 +1,16 @@ package io.github.treesitter.ktreesitter +/** + * A function that is called while executing a query. + * + * The argument contains the current byte offset. + * + * If the function returns `false`, the execution will halt early. + * + * @since 0.25.0 + */ +typealias QueryProgressCallback = (currentByteOffset: UInt) -> Boolean + /** * A class that represents a set of patterns which match nodes in a syntax tree. * @@ -13,91 +24,29 @@ expect class Query @Throws(QueryError::class) constructor(language: Language, so val patternCount: UInt /** The number of captures in the query. */ + @Deprecated("captureCount is deprecated.", ReplaceWith("captureNames.size")) val captureCount: UInt /** - * The maximum duration in microseconds that query - * execution should be allowed to take before halting. - * - * Default: `0` + * The capture names used in the query. * - * @since 0.23.0 + * @since 0.25.0 */ - var timeoutMicros: ULong + val captureNames: List /** - * The maximum number of in-progress matches. - * - * Default: `UInt.MAX_VALUE` + * The string literals used in the query. * - * @throws [IllegalArgumentException] If the match limit is set to `0`. + * @since 0.25.0 */ - var matchLimit: UInt + val stringValues: List /** - * The maximum start depth for the query. + * Execute the query on the given [Node]. * - * This prevents cursors from exploring children nodes at a certain depth. - * Note that if a pattern includes many children, then they will still be checked. - * - * Default: `UInt.MAX_VALUE` - */ - var maxStartDepth: UInt - - /** - * The range of bytes in which the query will be executed. - * - * Default: `UInt.MIN_VALUE..UInt.MAX_VALUE` + * @since 0.25.0 */ - var byteRange: UIntRange - - /** - * The range of points in which the query will be executed. - * - * Default: `Point.MIN..Point.MAX` - */ - var pointRange: ClosedRange - - /** - * Check if the query exceeded its maximum number of - * in-progress matches during its last execution. - */ - val didExceedMatchLimit: Boolean - - /** - * Iterate over all the matches in the order that they were found. - * - * #### Example - * - * ```kotlin - * query.matches(tree.rootNode) { - * if (name != "ieq?") return@matches true - * val node = it[(args[0] as QueryPredicateArg.Capture).value].first() - * val value = (args[1] as QueryPredicateArg.Literal).value - * value.equals(node.text()?.toString(), ignoreCase = true) - * } - * ``` - * - * @param node The node that the query will run on. - * @param predicate A function that handles custom predicates. - */ - fun matches( - node: Node, - predicate: QueryPredicate.(QueryMatch) -> Boolean = { true } - ): Sequence - - /** - * Iterate over all the individual captures in the order that they appear. - * - * This is useful if you don't care about _which_ pattern matched. - * - * @param node The node that the query will run on. - * @param predicate A function that handles custom predicates. - */ - fun captures( - node: Node, - predicate: QueryPredicate.(QueryMatch) -> Boolean = { true } - ): Sequence> + operator fun invoke(node: Node, progressCallback: QueryProgressCallback? = null): QueryCursor /** * Get the property settings for the given pattern index. @@ -142,10 +91,7 @@ expect class Query @Throws(QueryError::class) constructor(language: Language, so * This prevents the capture from being returned in matches, * and also avoids most resource usage associated with recording * the capture. Currently, there is no way to undo this. - * - * @throws [NoSuchElementException] If the capture does not exist. */ - @Throws(NoSuchElementException::class) fun disableCapture(name: String) /** diff --git a/ktreesitter/src/commonMain/kotlin/io/github/treesitter/ktreesitter/QueryCapture.kt b/ktreesitter/src/commonMain/kotlin/io/github/treesitter/ktreesitter/QueryCapture.kt index a11578f..fb618ac 100644 --- a/ktreesitter/src/commonMain/kotlin/io/github/treesitter/ktreesitter/QueryCapture.kt +++ b/ktreesitter/src/commonMain/kotlin/io/github/treesitter/ktreesitter/QueryCapture.kt @@ -8,6 +8,7 @@ import kotlin.jvm.JvmName * @property node The captured node. * @property name The name of the capture. */ +@ConsistentCopyVisibility data class QueryCapture internal constructor( @get:JvmName("node") val node: Node, @get:JvmName("name") val name: String diff --git a/ktreesitter/src/commonMain/kotlin/io/github/treesitter/ktreesitter/QueryCursor.kt b/ktreesitter/src/commonMain/kotlin/io/github/treesitter/ktreesitter/QueryCursor.kt new file mode 100644 index 0000000..9b80910 --- /dev/null +++ b/ktreesitter/src/commonMain/kotlin/io/github/treesitter/ktreesitter/QueryCursor.kt @@ -0,0 +1,103 @@ +package io.github.treesitter.ktreesitter + +/** + * A class that is used for executing a query. + * + * @since 0.25.0 + */ +expect class QueryCursor { + /** + * The maximum duration in microseconds that query + * execution should be allowed to take before halting. + * + * Default: `0` + * + * @since 0.23.0 + */ + @Deprecated("Use the progressCallback in Query.invoke()") + var timeoutMicros: ULong + + /** + * The maximum number of in-progress matches. + * + * Default: `UInt.MAX_VALUE` + * + * @throws [IllegalArgumentException] If the match limit is set to `0`. + */ + var matchLimit: UInt + + /** + * The maximum start depth for the query. + * + * This prevents cursors from exploring children nodes at a certain depth. + * Note that if a pattern includes many children, then they will still be checked. + * + * Default: `UInt.MAX_VALUE` + */ + var maxStartDepth: UInt + + /** + * The range of bytes in which the query will be executed. + * + * The query cursor will return matches that intersect with + * the given range. This means that a match may be returned + * even if some of its captures fall outside the specified range, + * as long as at least part of the match overlaps with the range. + * + * Default: `UInt.MIN_VALUE..UInt.MAX_VALUE` + * + * @throws [IllegalArgumentException] If set to an invalid range. + */ + var byteRange: UIntRange + + /** + * The range of points in which the query will be executed. + * + * The query cursor will return matches that intersect with + * the given range. This means that a match may be returned + * even if some of its captures fall outside the specified range, + * as long as at least part of the match overlaps with the range. + * + * Default: `Point.MIN..Point.MAX` + * + * @throws [IllegalArgumentException] If set to an invalid range. + */ + var pointRange: ClosedRange + + /** + * Check if the cursor exceeded its maximum number of + * in-progress matches during its last execution. + * + * @see matchLimit + */ + val didExceedMatchLimit: Boolean + + /** + * Iterate over all the matches in the order that they were found. + * + * #### Example + * + * ```kotlin + * query(tree.rootNode).matches { + * if (name != "ieq?") return@matches true + * val node = it[(args[0] as QueryPredicateArg.Capture).value].first() + * val value = (args[1] as QueryPredicateArg.Literal).value + * value.equals(node.text()?.toString(), ignoreCase = true) + * } + * ``` + * + * @param predicate A function that handles custom predicates. + */ + fun matches(predicate: QueryPredicate.(QueryMatch) -> Boolean = { true }): Sequence + + /** + * Iterate over all the individual captures in the order that they appear. + * + * This is useful if you don't care about _which_ pattern matched. + * + * @param predicate A function that handles custom predicates. + */ + fun captures( + predicate: QueryPredicate.(QueryMatch) -> Boolean = { true } + ): Sequence> +} diff --git a/ktreesitter/src/commonMain/kotlin/io/github/treesitter/ktreesitter/Range.kt b/ktreesitter/src/commonMain/kotlin/io/github/treesitter/ktreesitter/Range.kt index 5df68b3..281494e 100644 --- a/ktreesitter/src/commonMain/kotlin/io/github/treesitter/ktreesitter/Range.kt +++ b/ktreesitter/src/commonMain/kotlin/io/github/treesitter/ktreesitter/Range.kt @@ -18,7 +18,7 @@ data class Range @Throws(IllegalArgumentException::class) constructor( @get:JvmName("endByte") val endByte: UInt ) { init { - require(startPoint <= endPoint) { "Invalid point range: $startPoint to $endPoint" } - require(startByte <= endByte) { "Invalid byte range: $startByte to $endByte" } + require(startPoint <= endPoint) { "Invalid point range: [$startPoint, $endPoint]" } + require(startByte <= endByte) { "Invalid byte range: [$startByte, $endByte]" } } } diff --git a/ktreesitter/src/commonTest/kotlin/io/github/treesitter/ktreesitter/LanguageTest.kt b/ktreesitter/src/commonTest/kotlin/io/github/treesitter/ktreesitter/LanguageTest.kt index dd36a8a..f98a076 100644 --- a/ktreesitter/src/commonTest/kotlin/io/github/treesitter/ktreesitter/LanguageTest.kt +++ b/ktreesitter/src/commonTest/kotlin/io/github/treesitter/ktreesitter/LanguageTest.kt @@ -1,9 +1,9 @@ package io.github.treesitter.ktreesitter import io.github.treesitter.ktreesitter.java.TreeSitterJava -import io.kotest.assertions.throwables.shouldNotThrowAny import io.kotest.core.spec.style.FunSpec import io.kotest.matchers.* +import io.kotest.matchers.collections.shouldBeEmpty import io.kotest.matchers.comparables.* import io.kotest.matchers.nulls.* import io.kotest.matchers.string.* @@ -12,8 +12,8 @@ import io.kotest.matchers.types.* class LanguageTest : FunSpec({ val language = Language(TreeSitterJava.language()) - test("version") { - language.version shouldBe 14U + test("abiVersion") { + language.abiVersion shouldBe 14U } test("symbolCount") { @@ -28,6 +28,19 @@ class LanguageTest : FunSpec({ language.fieldCount shouldBeGreaterThan 1U } + test("name") { + language.name.shouldBeNull() + } + + test("metadata") { + language.metadata.shouldBeNull() + } + + @OptIn(ExperimentalUnsignedTypes::class) + test("supertypes") { + language.supertypes.shouldBeEmpty() + } + test("symbolName()") { language.symbolName(1U) shouldBe "identifier" } @@ -37,6 +50,11 @@ class LanguageTest : FunSpec({ language.symbolForName("program", true) shouldBeGreaterThan 0U } + @OptIn(ExperimentalUnsignedTypes::class) + test("subtypes") { + language.subtypes(1U).shouldBeEmpty() + } + test("isNamed()") { language.isNamed(1U) shouldBe true } @@ -69,10 +87,6 @@ class LanguageTest : FunSpec({ lookahead.language shouldBe language } - test("query()") { - shouldNotThrowAny { language.query("(program) @root") } - } - test("equals()") { Language(TreeSitterJava.language()) shouldBe language.copy() } @@ -82,6 +96,6 @@ class LanguageTest : FunSpec({ } test("toString()") { - language.toString() shouldMatch Regex("""Language\(id=0x[0-9a-f]+, version=14\)""") + language.toString() shouldMatch Regex("""Language\(id=0x[0-9a-f]+, abiVersion=14\)""") } }) diff --git a/ktreesitter/src/commonTest/kotlin/io/github/treesitter/ktreesitter/NodeTest.kt b/ktreesitter/src/commonTest/kotlin/io/github/treesitter/ktreesitter/NodeTest.kt index e866bc5..01a401d 100644 --- a/ktreesitter/src/commonTest/kotlin/io/github/treesitter/ktreesitter/NodeTest.kt +++ b/ktreesitter/src/commonTest/kotlin/io/github/treesitter/ktreesitter/NodeTest.kt @@ -146,6 +146,14 @@ class NodeTest : FunSpec({ shouldThrow { rootNode.namedChild(1U) } } + test("firstChildForByte()") { + rootNode.firstChildForByte(10U)!!.type shouldBe "class_declaration" + } + + test("firstNamedChildForByte()") { + rootNode.firstNamedChildForByte(10U)!!.type shouldBe "class_declaration" + } + test("childByFieldId()") { rootNode.childByFieldId(0U).shouldBeNull() } @@ -174,13 +182,6 @@ class NodeTest : FunSpec({ rootNode.child(0U)!!.fieldNameForNamedChild(2U).shouldBeNull() } - @Suppress("DEPRECATION") - test("childContainingDescendant()") { - val descendant = rootNode.child(0U)!!.child(0U)!! - val child = rootNode.childContainingDescendant(descendant) - child?.type shouldBe "class_declaration" - } - test("childWithDescendant()") { val descendant = rootNode.child(0U)!! val child = rootNode.childWithDescendant(descendant) diff --git a/ktreesitter/src/commonTest/kotlin/io/github/treesitter/ktreesitter/ParserTest.kt b/ktreesitter/src/commonTest/kotlin/io/github/treesitter/ktreesitter/ParserTest.kt index 4d668fb..777f5b4 100644 --- a/ktreesitter/src/commonTest/kotlin/io/github/treesitter/ktreesitter/ParserTest.kt +++ b/ktreesitter/src/commonTest/kotlin/io/github/treesitter/ktreesitter/ParserTest.kt @@ -27,12 +27,6 @@ class ParserTest : FunSpec({ parser.includedRanges shouldHaveSingleElement range } - test("timeoutMicros") { - parser.timeoutMicros shouldBe 0UL - parser.timeoutMicros = 10000UL - parser.timeoutMicros shouldBe 10000UL - } - test("logger") { shouldNotThrowAnyUnit { parser.logger = { _, _ -> @@ -58,12 +52,12 @@ class ParserTest : FunSpec({ } // UTF-16 - source = "var java = \"💩\"" - tree = parser.parse(source) - tree.text()?.subSequence(12, 14) shouldBe "\uD83D\uDCA9" + source = "\uFEFFvar java = \"💩\"" + tree = parser.parse(source, encoding = InputEncoding.UTF_16BE) + tree.text()?.subSequence(13, 15) shouldBe "\uD83D\uDCA9" } - test("parse(callback)") { + test("parse(readCallback)") { val source = "class Foo {}" val tree = parser.parse { byte, _ -> val end = minOf(byte.toInt() * 2, source.length) @@ -74,9 +68,8 @@ class ParserTest : FunSpec({ } afterTest { (test, _) -> - when (test.name.testName) { + when (test.name.name) { "includedRanges" -> parser.includedRanges = emptyList() - "timeoutMicros" -> parser.timeoutMicros = 0UL "logger" -> parser.logger = null } } diff --git a/ktreesitter/src/commonTest/kotlin/io/github/treesitter/ktreesitter/QueryCursorTest.kt b/ktreesitter/src/commonTest/kotlin/io/github/treesitter/ktreesitter/QueryCursorTest.kt new file mode 100644 index 0000000..dae039c --- /dev/null +++ b/ktreesitter/src/commonTest/kotlin/io/github/treesitter/ktreesitter/QueryCursorTest.kt @@ -0,0 +1,160 @@ +package io.github.treesitter.ktreesitter + +import io.github.treesitter.ktreesitter.java.TreeSitterJava +import io.kotest.core.spec.style.FunSpec +import io.kotest.inspectors.forAll +import io.kotest.inspectors.forSingle +import io.kotest.matchers.* +import io.kotest.matchers.collections.* + +class QueryCursorTest : + FunSpec({ + val language = Language(TreeSitterJava.language()) + val parser = Parser(language) + val source = """ + (identifier) @identifier + + (class_declaration + name: (identifier) @class + (class_body) @body) + """.trimIndent() + val query = Query(language, source) + val tree = parser.parse("class Foo {}") + + @Suppress("DEPRECATION") + test("timeoutMicros") { + val cursor = query(tree.rootNode) + cursor.timeoutMicros shouldBe 0UL + cursor.timeoutMicros = 10UL + cursor.timeoutMicros shouldBe 10UL + } + + test("matchLimit") { + val cursor = query(tree.rootNode) + cursor.matchLimit shouldBe UInt.MAX_VALUE + cursor.matchLimit = 10U + cursor.matchLimit shouldBe 10U + } + + test("maxStartDepth") { + val cursor = query(tree.rootNode) + cursor.maxStartDepth = 10U + cursor.maxStartDepth shouldBe 10U + } + + test("byteRange") { + val cursor = query(tree.rootNode) + cursor.byteRange = 0U..10U + cursor.byteRange.last shouldBe 10U + } + + test("pointRange") { + val cursor = query(tree.rootNode) + cursor.pointRange = Point(0U, 10U)..Point.MAX + cursor.pointRange.start shouldBe Point(0U, 10U) + } + + test("didExceedMatchLimit") { + val cursor = query(tree.rootNode) + cursor.didExceedMatchLimit shouldBe false + } + + test("matches()") { + var cursor = query(tree.rootNode) + var matches = cursor.matches().toList() + matches.shouldHaveSize(2).shouldBeMonotonicallyIncreasingWith { a, b -> + a.patternIndex.compareTo(b.patternIndex) + } + + var tree = parser.parse("int y = x + 1;") + var query = Query( + language, + """ + ((variable_declarator + (identifier) @y + (binary_expression + (identifier) @x)) + (#not-eq? @y @x)) + """.trimIndent() + ) + cursor = query(tree.rootNode) + matches = cursor.matches().toList() + matches.forSingle { + it.captures[0].node.text() shouldBe "y" + } + + tree = parser.parse( + """ + class Foo {} + class Bar {} + """.trimIndent() + ) + query = Query( + language, + """ + ((identifier) @foo + (#eq? @foo "Foo")) + """.trimIndent() + ) + cursor = query(tree.rootNode) + matches = cursor.matches().toList() + matches.forSingle { + it.captures[0].node.text() shouldBe "Foo" + } + + query = Query( + language, + """ + ((identifier) @name + (#not-any-of? @name "Foo" "Bar")) + """.trimIndent() + ) + cursor = query(tree.rootNode) + matches = cursor.matches().toList() + matches.shouldBeEmpty() + + query = Query( + language, + """ + ((identifier) @foo + (#ieq? @foo "foo")) + """.trimIndent() + ) + cursor = query(tree.rootNode) + matches = cursor.matches { + if (name != "ieq?") return@matches true + val node = it[(args[0] as QueryPredicateArg.Capture).value].single() + (args[1] as QueryPredicateArg.Literal).value.equals(node.text().toString(), true) + }.toList() + matches.forSingle { + it.captures[0].node.text() shouldBe "Foo" + } + } + + test("captures()") { + var cursor = query(tree.rootNode) + var captures = cursor.captures().toList() + captures.shouldHaveSize(3).take(2).forAll { + it.second.captures[0].node.type shouldBe "identifier" + } + + var tree = parser.parse( + """ + /// foo + /// bar + """.trimIndent() + ) + var query = Query( + language, + """ + ((line_comment)+ @foo + (#any-match? @foo "foo")) + """.trimIndent() + ) + cursor = query(tree.rootNode) + captures = cursor.captures().toList() + captures.shouldHaveSize(2).forAll { + it.second.captures[0].name shouldBe "foo" + } + } + }) diff --git a/ktreesitter/src/commonTest/kotlin/io/github/treesitter/ktreesitter/QueryTest.kt b/ktreesitter/src/commonTest/kotlin/io/github/treesitter/ktreesitter/QueryTest.kt index 18a509e..15c7092 100644 --- a/ktreesitter/src/commonTest/kotlin/io/github/treesitter/ktreesitter/QueryTest.kt +++ b/ktreesitter/src/commonTest/kotlin/io/github/treesitter/ktreesitter/QueryTest.kt @@ -5,16 +5,12 @@ import io.kotest.assertions.throwables.shouldNotThrowAny import io.kotest.assertions.throwables.shouldThrow import io.kotest.assertions.throwables.shouldThrowWithMessage import io.kotest.core.spec.style.FunSpec -import io.kotest.inspectors.forAll import io.kotest.inspectors.forOne -import io.kotest.inspectors.forSingle import io.kotest.matchers.* -import io.kotest.matchers.collections.* class QueryTest : FunSpec({ val language = Language(TreeSitterJava.language()) - val parser = Parser(language) val source = """ (identifier) @identifier @@ -65,144 +61,6 @@ class QueryTest : query.patternCount shouldBe 2U } - test("captureCount") { - val query = Query(language, source) - query.captureCount shouldBe 3U - } - - test("timeoutMicros") { - val query = Query(language, source) - query.timeoutMicros shouldBe 0UL - query.timeoutMicros = 10UL - query.timeoutMicros shouldBe 10UL - } - - test("matchLimit") { - val query = Query(language, source) - query.matchLimit shouldBe UInt.MAX_VALUE - query.matchLimit = 10U - query.matchLimit shouldBe 10U - } - - test("maxStartDepth") { - val query = Query(language, source) - query.maxStartDepth = 10U - query.maxStartDepth shouldBe 10U - } - - test("byteRange") { - val query = Query(language, source) - query.byteRange = 0U..10U - query.byteRange.last shouldBe 10U - } - - test("pointRange") { - val query = Query(language, source) - query.pointRange = Point(0U, 10U)..Point.MAX - query.pointRange.start shouldBe Point(0U, 10U) - } - - test("didExceedMatchLimit") { - val query = Query(language, source) - query.didExceedMatchLimit shouldBe false - } - - test("matches()") { - var tree = parser.parse("class Foo {}") - var query = Query(language, source) - var matches = query.matches(tree.rootNode).toList() - matches.shouldHaveSize(2).shouldBeMonotonicallyIncreasingWith { a, b -> - a.patternIndex.compareTo(b.patternIndex) - } - - tree = parser.parse("int y = x + 1;") - query = Query( - language, - """ - ((variable_declarator - (identifier) @y - (binary_expression - (identifier) @x)) - (#not-eq? @y @x)) - """.trimIndent() - ) - matches = query.matches(tree.rootNode).toList() - matches.forSingle { - it.captures[0].node.text() shouldBe "y" - } - - tree = parser.parse( - """ - class Foo {} - class Bar {} - """.trimIndent() - ) - query = Query( - language, - """ - ((identifier) @foo - (#eq? @foo "Foo")) - """.trimIndent() - ) - matches = query.matches(tree.rootNode).toList() - matches.forSingle { - it.captures[0].node.text() shouldBe "Foo" - } - - query = Query( - language, - """ - ((identifier) @name - (#not-any-of? @name "Foo" "Bar")) - """.trimIndent() - ) - matches = query.matches(tree.rootNode).toList() - matches.shouldBeEmpty() - - query = Query( - language, - """ - ((identifier) @foo - (#ieq? @foo "foo")) - """.trimIndent() - ) - matches = query.matches(tree.rootNode) { - if (name != "ieq?") return@matches true - val node = it[(args[0] as QueryPredicateArg.Capture).value].single() - (args[1] as QueryPredicateArg.Literal).value.equals(node.text().toString(), true) - }.toList() - matches.forSingle { - it.captures[0].node.text() shouldBe "Foo" - } - } - - test("captures()") { - var tree = parser.parse("class Foo {}") - var query = Query(language, source) - var captures = query.captures(tree.rootNode).toList() - captures.shouldHaveSize(3).take(2).forAll { - it.second.captures[0].node.type shouldBe "identifier" - } - - tree = parser.parse( - """ - /// foo - /// bar - """.trimIndent() - ) - query = Query( - language, - """ - ((line_comment)+ @foo - (#any-match? @foo "foo")) - """.trimIndent() - ) - captures = query.captures(tree.rootNode).toList() - captures.shouldHaveSize(2).forAll { - it.second.captures[0].name shouldBe "foo" - } - } - test("settings()") { var query = Query( language, @@ -267,34 +125,6 @@ class QueryTest : } } - test("disablePattern()") { - val query = Query(language, source) - query.disablePattern(1U) - val tree = parser.parse("class Foo {}") - val matches = query.captures(tree.rootNode).toList() - matches.forSingle { - it.second.captures[0].node.type shouldBe "identifier" - } - - shouldThrow { - query.disablePattern(2U) - } - } - - test("disableCapture()") { - val query = Query(language, source) - query.disableCapture("body") - val tree = parser.parse("class Foo {}") - val matches = query.captures(tree.rootNode).toList() - matches.shouldHaveSize(2).forAll { - it.second.captures[0].node.type shouldBe "identifier" - } - - shouldThrow { - query.disableCapture("none") - } - } - test("startByteForPattern()") { val query = Query(language, source) query.startByteForPattern(1U) shouldBe 26U diff --git a/ktreesitter/src/commonTest/kotlin/io/github/treesitter/ktreesitter/TreeTest.kt b/ktreesitter/src/commonTest/kotlin/io/github/treesitter/ktreesitter/TreeTest.kt index 43cac43..4d7aeda 100644 --- a/ktreesitter/src/commonTest/kotlin/io/github/treesitter/ktreesitter/TreeTest.kt +++ b/ktreesitter/src/commonTest/kotlin/io/github/treesitter/ktreesitter/TreeTest.kt @@ -41,7 +41,7 @@ class TreeTest : FunSpec({ source = "class Foo2 {}" tree.edit(edit) tree.text().shouldBeNull() - tree = parser.parse(source, tree) + tree = parser.parse(source, oldTree = tree) tree.text() shouldBe source } @@ -53,7 +53,7 @@ class TreeTest : FunSpec({ test("changedRanges()") { val edit = InputEdit(0U, 0U, 7U, Point(0U, 0U), Point(0U, 0U), Point(0U, 7U)) tree.edit(edit) - val newTree = parser.parse("public $source", tree) + val newTree = parser.parse("public $source", oldTree = tree) tree.changedRanges(newTree).shouldHaveSingleElement { it.endByte == 7U && it.endPoint.column == 7U } diff --git a/ktreesitter/src/jni/language.c b/ktreesitter/src/jni/language.c index bc57e17..9783ff9 100644 --- a/ktreesitter/src/jni/language.c +++ b/ktreesitter/src/jni/language.c @@ -4,9 +4,14 @@ jlong JNICALL language_copy CRITICAL_ARGS(jlong self) { return (jlong)ts_language_copy((TSLanguage *)self); } +jint JNICALL language_get_abi_version(JNIEnv *env, jobject this) { + TSLanguage *self = GET_POINTER(TSLanguage, this, Language_self); + return (jint)ts_language_abi_version(self); +} + jint JNICALL language_get_version(JNIEnv *env, jobject this) { TSLanguage *self = GET_POINTER(TSLanguage, this, Language_self); - return (jint)ts_language_version(self); + return (jint)ts_language_abi_version(self); } jint JNICALL language_get_symbol_count(JNIEnv *env, jobject this) { @@ -24,10 +29,46 @@ jint JNICALL language_get_field_count(JNIEnv *env, jobject this) { return (jint)ts_language_field_count(self); } +jstring JNICALL language_get_name(JNIEnv *env, jobject this) { + TSLanguage *self = GET_POINTER(TSLanguage, this, Language_self); + const char *name = ts_language_name(self); + return name ? (*env)->NewStringUTF(env, name) : NULL; +} + +jobject JNICALL language_get_metadata(JNIEnv *env, jobject this) { + TSLanguage *self = GET_POINTER(TSLanguage, this, Language_self); + const TSLanguageMetadata *metadata = ts_language_metadata(self); + if (metadata == NULL) + return NULL; + + jobject major = (*env)->AllocObject(env, global_class_cache.UShort); + (*env)->SetShortField(env, major, global_field_cache.UShort_data, + (jshort)metadata->major_version); + jobject minor = (*env)->AllocObject(env, global_class_cache.UShort); + (*env)->SetShortField(env, minor, global_field_cache.UShort_data, + (jshort)metadata->minor_version); + jobject patch = (*env)->AllocObject(env, global_class_cache.UShort); + (*env)->SetShortField(env, patch, global_field_cache.UShort_data, + (jshort)metadata->patch_version); + jobject version = NEW_OBJECT(Triple, major, minor, patch); + return NEW_OBJECT(Language$Metadata, version); +} + +jshortArray JNICALL language_get_supertypes(JNIEnv *env, jobject this) { + TSLanguage *self = GET_POINTER(TSLanguage, this, Language_self); + uint32_t length; + const TSSymbol *supertypes = ts_language_supertypes(self, &length); + jshortArray result = (*env)->NewShortArray(env, length); + if (length > 0) { + (*env)->SetShortArrayRegion(env, result, 0, length, (const jshort *)supertypes); + } + return result; +} + jstring JNICALL language_symbol_name(JNIEnv *env, jobject this, jshort symbol) { TSLanguage *self = GET_POINTER(TSLanguage, this, Language_self); const char *name = ts_language_symbol_name(self, (uint16_t)symbol); - return (*env)->NewStringUTF(env, name); + return name ? (*env)->NewStringUTF(env, name) : NULL; } jshort JNICALL language_symbol_for_name(JNIEnv *env, jobject this, jstring name, @@ -40,6 +81,17 @@ jshort JNICALL language_symbol_for_name(JNIEnv *env, jobject this, jstring name, return (jshort)symbol; } +jshortArray JNICALL language_subtypes(JNIEnv *env, jobject this, jshort supertype) { + TSLanguage *self = GET_POINTER(TSLanguage, this, Language_self); + uint32_t length; + const TSSymbol *subtypes = ts_language_subtypes(self, supertype, &length); + jshortArray result = (*env)->NewShortArray(env, length); + if (length > 0) { + (*env)->SetShortArrayRegion(env, result, 0, length, (const jshort *)subtypes); + } + return result; +} + jboolean JNICALL language_is_named(JNIEnv *env, jobject this, jshort symbol) { TSLanguage *self = GET_POINTER(TSLanguage, this, Language_self); TSSymbolType symbol_type = ts_language_symbol_type(self, symbol); @@ -93,12 +145,17 @@ void JNICALL language_check_version(JNIEnv *env, jobject this) { const JNINativeMethod Language_methods[] = { {"copy", "(J)J", (void *)&language_copy}, + {"getAbiVersion", "()I", (void *)&language_get_abi_version}, {"getVersion", "()I", (void *)&language_get_version}, {"getSymbolCount", "()I", (void *)&language_get_symbol_count}, {"getStateCount", "()I", (void *)&language_get_state_count}, {"getFieldCount", "()I", (void *)&language_get_field_count}, + {"getName", "()Ljava/lang/String;", (void *)&language_get_name}, + {"getMetadata", "()L" PACKAGE "Language$Metadata;", (void *)&language_get_metadata}, + {"getSupertypes", "()[S", (void *)&language_get_supertypes}, {"symbolName", "(S)Ljava/lang/String;", (void *)&language_symbol_name}, {"symbolForName", "(Ljava/lang/String;Z)S", (void *)&language_symbol_for_name}, + {"subtypes", "(S)[S", (void *)&language_subtypes}, {"isNamed", "(S)Z", (void *)&language_is_named}, {"isVisible", "(S)Z", (void *)&language_is_visible}, {"isSupertype", "(S)Z", (void *)&language_is_supertype}, diff --git a/ktreesitter/src/jni/module.c b/ktreesitter/src/jni/module.c index 1f5efde..ab67e36 100644 --- a/ktreesitter/src/jni/module.c +++ b/ktreesitter/src/jni/module.c @@ -21,6 +21,9 @@ extern const size_t Parser_methods_size; extern const JNINativeMethod Query_methods[]; extern const size_t Query_methods_size; +extern const JNINativeMethod QueryCursor_methods[]; +extern const size_t QueryCursor_methods_size; + FieldCache global_field_cache = {0}; MethodCache global_method_cache = {0}; ClassCache global_class_cache = {0}; @@ -100,13 +103,15 @@ JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *_reserved) { REGISTER_CLASS(Query); CACHE_FIELD(Query, self, "J"); - CACHE_FIELD(Query, cursor, "J"); - CACHE_FIELD(Query, matchLimit, "I"); - CACHE_FIELD(Query, maxStartDepth, "I"); CACHE_FIELD(Query, language, "L" PACKAGE "Language;"); - CACHE_FIELD(Query, captureNames, "Ljava/util/List;"); CACHE_FIELD(Query, source, "Ljava/lang/String;"); + REGISTER_CLASS(QueryCursor); + CACHE_FIELD(QueryCursor, self, "J"); + CACHE_FIELD(QueryCursor, matchLimit, "I"); + CACHE_FIELD(QueryCursor, maxStartDepth, "I"); + CACHE_FIELD(QueryCursor, timeoutMicros, "I"); + REGISTER_CLASS(Parser); CACHE_FIELD(Parser, self, "J"); CACHE_FIELD(Parser, timeoutMicros, "J"); @@ -134,6 +139,9 @@ JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *_reserved) { CACHE_FIELD(InputEdit, oldEndPoint, "L" PACKAGE "Point;"); CACHE_FIELD(InputEdit, newEndPoint, "L" PACKAGE "Point;"); + CACHE_CLASS(PACKAGE, Language$Metadata); + CACHE_METHOD(Language$Metadata, init, "", "(Lkotlin/Triple;)V"); + CACHE_CLASS(PACKAGE, QueryCapture); CACHE_METHOD(QueryCapture, init, "", "(L" PACKAGE "Node;Ljava/lang/String;)V"); @@ -144,6 +152,11 @@ JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *_reserved) { CACHE_STATIC_FIELD(Parser$LogType, LEX, "L" PACKAGE "Parser$LogType;"); CACHE_STATIC_FIELD(Parser$LogType, PARSE, "L" PACKAGE "Parser$LogType;"); + CACHE_CLASS(PACKAGE, InputEncoding); + CACHE_STATIC_FIELD(InputEncoding, UTF_8, "L" PACKAGE "InputEncoding;"); + CACHE_STATIC_FIELD(InputEncoding, UTF_16LE, "L" PACKAGE "InputEncoding;"); + CACHE_STATIC_FIELD(InputEncoding, UTF_16BE, "L" PACKAGE "InputEncoding;"); + CACHE_CLASS(PACKAGE, QueryError$Capture); CACHE_METHOD(QueryError$Capture, init, "", "(IILjava/lang/String;)V"); @@ -159,6 +172,10 @@ JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *_reserved) { CACHE_CLASS(PACKAGE, QueryError$Structure); CACHE_METHOD(QueryError$Structure, init, "", "(II)V"); + CACHE_CLASS("java/lang/", Boolean); + CACHE_FIELD(Boolean, value, "Z"); + CACHE_METHOD(Boolean, init, "", "(Z)V"); + CACHE_CLASS("java/lang/", CharSequence); CACHE_METHOD(CharSequence, toString, "toString", "()Ljava/lang/String;"); @@ -173,9 +190,20 @@ JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *_reserved) { CACHE_CLASS("kotlin/", Pair); CACHE_METHOD(Pair, init, "", "(Ljava/lang/Object;Ljava/lang/Object;)V"); + CACHE_CLASS("kotlin/", Triple); + CACHE_METHOD(Triple, init, "", + "(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)V"); + CACHE_CLASS("kotlin/", UInt); CACHE_FIELD(UInt, data, "I"); + CACHE_CLASS("kotlin/", UShort); + CACHE_FIELD(UShort, data, "S"); + + CACHE_CLASS("kotlin/jvm/functions/", Function1); + CACHE_METHOD(Function2, invoke, "invoke", + "(Ljava/lang/Object;)Ljava/lang/Object;"); + CACHE_CLASS("kotlin/jvm/functions/", Function2); CACHE_METHOD(Function2, invoke, "invoke", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"); @@ -197,12 +225,17 @@ JNIEXPORT void JNI_OnUnload(JavaVM *vm, void *_reserved) { return; (*env)->DeleteGlobalRef(env, global_class_cache.ArrayList); + (*env)->DeleteGlobalRef(env, global_class_cache.Boolean); (*env)->DeleteGlobalRef(env, global_class_cache.CharSequence); + (*env)->DeleteGlobalRef(env, global_class_cache.Function1); + (*env)->DeleteGlobalRef(env, global_class_cache.Function2); (*env)->DeleteGlobalRef(env, global_class_cache.IllegalArgumentException); (*env)->DeleteGlobalRef(env, global_class_cache.IllegalStateException); (*env)->DeleteGlobalRef(env, global_class_cache.IndexOutOfBoundsException); (*env)->DeleteGlobalRef(env, global_class_cache.InputEdit); + (*env)->DeleteGlobalRef(env, global_class_cache.InputEncoding); (*env)->DeleteGlobalRef(env, global_class_cache.Language); + (*env)->DeleteGlobalRef(env, global_class_cache.Language$Metadata); (*env)->DeleteGlobalRef(env, global_class_cache.List); (*env)->DeleteGlobalRef(env, global_class_cache.LookaheadIterator); (*env)->DeleteGlobalRef(env, global_class_cache.Node); @@ -210,6 +243,7 @@ JNIEXPORT void JNI_OnUnload(JavaVM *vm, void *_reserved) { (*env)->DeleteGlobalRef(env, global_class_cache.Parser); (*env)->DeleteGlobalRef(env, global_class_cache.Point); (*env)->DeleteGlobalRef(env, global_class_cache.Query); + (*env)->DeleteGlobalRef(env, global_class_cache.QueryCursor); (*env)->DeleteGlobalRef(env, global_class_cache.QueryError$Capture); (*env)->DeleteGlobalRef(env, global_class_cache.QueryError$Field); (*env)->DeleteGlobalRef(env, global_class_cache.QueryError$NodeType); @@ -220,5 +254,7 @@ JNIEXPORT void JNI_OnUnload(JavaVM *vm, void *_reserved) { (*env)->DeleteGlobalRef(env, global_class_cache.Range); (*env)->DeleteGlobalRef(env, global_class_cache.Tree); (*env)->DeleteGlobalRef(env, global_class_cache.TreeCursor); + (*env)->DeleteGlobalRef(env, global_class_cache.Triple); (*env)->DeleteGlobalRef(env, global_class_cache.UInt); + (*env)->DeleteGlobalRef(env, global_class_cache.UShort); } diff --git a/ktreesitter/src/jni/node.c b/ktreesitter/src/jni/node.c index af42f7e..fef28df 100644 --- a/ktreesitter/src/jni/node.c +++ b/ktreesitter/src/jni/node.c @@ -247,6 +247,24 @@ jobject JNICALL node_children_by_field_id(JNIEnv *env, jobject this, jshort id) return children; } +jobject JNICALL node_first_child_for_byte(JNIEnv *env, jobject this, jint byte) { + TSNode self = unmarshal_node(env, this); + TSNode result = ts_node_first_child_for_byte(self, byte); + if (ts_node_is_null(result)) + return NULL; + jobject tree = GET_FIELD(Object, this, Node_tree); + return marshal_node(env, result, tree); +} + +jobject JNICALL node_first_named_child_for_byte(JNIEnv *env, jobject this, jint byte) { + TSNode self = unmarshal_node(env, this); + TSNode result = ts_node_first_named_child_for_byte(self, byte); + if (ts_node_is_null(result)) + return NULL; + jobject tree = GET_FIELD(Object, this, Node_tree); + return marshal_node(env, result, tree); +} + jstring JNICALL node_field_name_for_child(JNIEnv *env, jobject this, jint index) { TSNode self = unmarshal_node(env, this); if (ts_node_child_count(self) <= (uint32_t)index) { @@ -275,16 +293,6 @@ jstring JNICALL node_field_name_for_named_child(JNIEnv *env, jobject this, jint return field_name ? (*env)->NewStringUTF(env, field_name) : NULL; } -jobject JNICALL node_child_containing_descendant(JNIEnv *env, jobject this, jobject descendant) { - TSNode self = unmarshal_node(env, this); - TSNode other = unmarshal_node(env, descendant); - TSNode result = ts_node_child_containing_descendant(self, other); - if (ts_node_is_null(result)) - return NULL; - jobject tree = GET_FIELD(Object, this, Node_tree); - return marshal_node(env, result, tree); -} - jobject JNICALL node_child_with_descendant(JNIEnv *env, jobject this, jobject descendant) { TSNode self = unmarshal_node(env, this); TSNode other = unmarshal_node(env, descendant); @@ -393,14 +401,14 @@ const JNINativeMethod Node_methods[] = { {"getChildren", "()Ljava/util/List;", (void *)&node_get_children}, {"child", "(I)L" PACKAGE "Node;", (void *)&node_child}, {"namedChild", "(I)L" PACKAGE "Node;", (void *)&node_named_child}, + {"firstChildForByte", "(I)L" PACKAGE "Node;", (void *)&node_first_child_for_byte}, + {"firstNamedChildForByte", "(I)L" PACKAGE "Node;", (void *)&node_first_named_child_for_byte}, {"childByFieldId", "(S)L" PACKAGE "Node;", (void *)&node_child_by_field_id}, {"childByFieldName", "(Ljava/lang/String;)L" PACKAGE "Node;", (void *)&node_child_by_field_name}, {"childrenByFieldId", "(S)Ljava/util/List;", (void *)&node_children_by_field_id}, {"fieldNameForChild", "(I)Ljava/lang/String;", (void *)&node_field_name_for_child}, {"fieldNameForNamedChild", "(I)Ljava/lang/String;", (void *)&node_field_name_for_named_child}, - {"childContainingDescendant", "(L" PACKAGE "Node;)L" PACKAGE "Node;", - (void *)&node_child_containing_descendant}, {"childWithDescendant", "(L" PACKAGE "Node;)L" PACKAGE "Node;", (void *)&node_child_with_descendant}, {"descendant", "(II)L" PACKAGE "Node;", (void *)&node_descendant__bytes}, diff --git a/ktreesitter/src/jni/parser.c b/ktreesitter/src/jni/parser.c index c40cfdb..d7306b1 100644 --- a/ktreesitter/src/jni/parser.c +++ b/ktreesitter/src/jni/parser.c @@ -11,6 +11,22 @@ typedef struct { } last_result; } ReadPayload; +static inline TSInputEncoding get_encoding(JNIEnv *env, jobject encoding) { + jobject UTF_8 = GET_STATIC_FIELD(Object, InputEncoding, InputEncoding_UTF_8); + if (encoding == NULL || (*env)->IsSameObject(env, encoding, UTF_8)) { + return TSInputEncodingUTF8; + } + jobject UTF_16LE = GET_STATIC_FIELD(Object, InputEncoding, InputEncoding_UTF_16LE); + if ((*env)->IsSameObject(env, encoding, UTF_16LE)) { + return TSInputEncodingUTF16BE; + } + jobject UTF_16BE = GET_STATIC_FIELD(Object, InputEncoding, InputEncoding_UTF_16BE); + if ((*env)->IsSameObject(env, encoding, UTF_16BE)) { + return TSInputEncodingUTF16LE; + } + UNREACHABLE(); +} + static void log_function(void *payload, TSLogType log_type, const char *buffer) { JNIEnv *env; int rc = (*java_vm)->GetEnv(java_vm, (void **)&env, JNI_VERSION_1_6); @@ -38,8 +54,8 @@ static void log_function(void *payload, TSLogType log_type, const char *buffer) CALL_METHOD(Object, (jobject)payload, Function2_invoke, log_type_value, message); } -static const char *parse_callback(void *payload, uint32_t byte_index, TSPoint position, - uint32_t *bytes_read) { +static const char *parse_read_callback(void *payload, uint32_t byte_index, TSPoint position, + uint32_t *bytes_read) { ReadPayload *read_payload = (ReadPayload *)payload; JNIEnv *env = read_payload->env; jstring last_string = read_payload->last_result.string; @@ -72,6 +88,20 @@ static const char *parse_callback(void *payload, uint32_t byte_index, TSPoint po return result; } +static bool parse_progress_callback(TSParseState *state) { + ProgressPayload *progress_payload = (ProgressPayload *)state->payload; + JNIEnv *env = progress_payload->env; + jobject offset = (*env)->AllocObject(env, global_class_cache.UInt); + (*env)->SetIntField(env, offset, global_field_cache.UInt_data, + (jint)state->current_byte_offset); + jobject error = NEW_OBJECT(Boolean, (jboolean)state->has_error); + jobject result = + CALL_METHOD(Object, progress_payload->callback, Function2_invoke, offset, error); + (*env)->DeleteLocalRef(env, offset); + (*env)->DeleteLocalRef(env, error); + return (bool)(*env)->GetBooleanField(env, result, global_field_cache.Boolean_value); +} + jlong JNICALL parser_init CRITICAL_NO_ARGS() { return (jlong)ts_parser_new(); } void JNICALL parser_delete(JNIEnv *env, jclass _class, jlong self) { @@ -140,7 +170,8 @@ void JNICALL parser_set_logger(JNIEnv *env, jobject this, jobject value) { (*env)->SetObjectField(env, this, global_field_cache.Parser_logger, value); } -jobject JNICALL parser_parse__string(JNIEnv *env, jobject this, jstring source, jobject old_tree) { +jobject JNICALL parser_parse__string(JNIEnv *env, jobject this, jstring source, jobject encoding, + jobject old_tree) { TSParser *self = GET_POINTER(TSParser, this, Parser_self); jobject language = GET_FIELD(Object, this, Parser_language); if (language == NULL) { @@ -148,12 +179,14 @@ jobject JNICALL parser_parse__string(JNIEnv *env, jobject this, jstring source, (*env)->ThrowNew(env, global_class_cache.IllegalStateException, error); return NULL; } - TSTree *old_ts_tree = old_tree ? GET_POINTER(TSTree, old_tree, Tree_self) : NULL; + TSTree *old_ts_tree = old_tree ? GET_POINTER(TSTree, old_tree, Tree_self) : NULL; uint32_t length; const char *string = (*env)->GetStringUTFChars(env, source, NULL); length = (uint32_t)(*env)->GetStringUTFLength(env, source); - TSTree *ts_tree = ts_parser_parse_string(self, old_ts_tree, string, length); + TSInputEncoding input_encoding = get_encoding(env, encoding); + TSTree *ts_tree = + ts_parser_parse_string_encoding(self, old_ts_tree, string, length, input_encoding); (*env)->ReleaseStringUTFChars(env, source, string); if (ts_tree == NULL) { @@ -164,8 +197,9 @@ jobject JNICALL parser_parse__string(JNIEnv *env, jobject this, jstring source, return NEW_OBJECT(Tree, (jlong)ts_tree, source, language); } -jobject JNICALL parser_parse__function(JNIEnv *env, jobject this, jobject old_tree, - jobject callback) { +jobject JNICALL parser_parse__function(JNIEnv *env, jobject this, jobject encoding, + jobject old_tree, jobject progress_callback, + jobject read_callback) { TSParser *self = GET_POINTER(TSParser, this, Parser_self); jobject language = GET_FIELD(Object, this, Parser_language); if (language == NULL) { @@ -175,13 +209,24 @@ jobject JNICALL parser_parse__function(JNIEnv *env, jobject this, jobject old_tr } TSTree *old_ts_tree = old_tree ? GET_POINTER(TSTree, old_tree, Tree_self) : NULL; - ReadPayload payload = {.env = env, .callback = callback}; + ReadPayload read_payload = {.env = env, .callback = read_callback}; + TSInputEncoding input_encoding = get_encoding(env, encoding); TSInput input = { - .payload = (void *)&payload, - .read = parse_callback, - .encoding = TSInputEncodingUTF8, + .payload = (void *)&read_payload, + .read = parse_read_callback, + .encoding = input_encoding, }; - TSTree *ts_tree = ts_parser_parse(self, old_ts_tree, input); + TSTree *ts_tree; + if (progress_callback == NULL) { + ts_tree = ts_parser_parse(self, old_ts_tree, input); + } else { + ProgressPayload progress_payload = {.env = env, .callback = progress_callback}; + TSParseOptions options = { + .payload = (void *)&progress_payload, + .progress_callback = parse_progress_callback, + }; + ts_tree = ts_parser_parse_with_options(self, old_ts_tree, input, options); + } if ((*env)->ExceptionCheck(env)) { (*env)->Throw(env, (*env)->ExceptionOccurred(env)); @@ -208,9 +253,11 @@ const JNINativeMethod Parser_methods[] = { {"getTimeoutMicros", "()J", (void *)&parser_get_timeout_micros}, {"setTimeoutMicros", "(J)V", (void *)&parser_set_timeout_micros}, {"setLogger", "(Lkotlin/jvm/functions/Function2;)V", (void *)&parser_set_logger}, - {"parse", "(Ljava/lang/String;L" PACKAGE "Tree;)L" PACKAGE "Tree;", + {"parse", "(Ljava/lang/String;L" PACKAGE "InputEncoding;L" PACKAGE "Tree;)L" PACKAGE "Tree;", (void *)&parser_parse__string}, - {"parse", "(L" PACKAGE "Tree;Lkotlin/jvm/functions/Function2;)L" PACKAGE "Tree;", + {"parse", + "(L" PACKAGE "InputEncoding;L" PACKAGE "Tree;Lkotlin/jvm/functions/Function2;" + "Lkotlin/jvm/functions/Function2;)L" PACKAGE "Tree;", (void *)&parser_parse__function}, {"reset", "()V", (void *)&parser_reset}, }; diff --git a/ktreesitter/src/jni/query.c b/ktreesitter/src/jni/query.c index 684a4d0..a8b8b03 100644 --- a/ktreesitter/src/jni/query.c +++ b/ktreesitter/src/jni/query.c @@ -104,67 +104,21 @@ jlong query_init(JNIEnv *env, jclass _class, jlong language, jstring source) { return -1; } -jlong query_cursor CRITICAL_NO_ARGS() { return (jlong)ts_query_cursor_new(); } - void query_delete CRITICAL_ARGS(jlong query, jlong cursor) { ts_query_delete((TSQuery *)query); ts_query_cursor_delete((TSQueryCursor *)cursor); } -jint query_get_pattern_count(JNIEnv *env, jobject this) { +jint query_native_pattern_count(JNIEnv *env, jobject this) { TSQuery *self = GET_POINTER(TSQuery, this, Query_self); return (jint)ts_query_pattern_count(self); } -jint query_get_capture_count(JNIEnv *env, jobject this) { +jint query_native_capture_count(JNIEnv *env, jobject this) { TSQuery *self = GET_POINTER(TSQuery, this, Query_self); return (jint)ts_query_capture_count(self); } -jlong query_get_timeout_micros(JNIEnv *env, jobject this) { - TSQueryCursor *cursor = GET_POINTER(TSQueryCursor, this, Query_cursor); - return (jlong)ts_query_cursor_timeout_micros(cursor); -} - -void query_set_timeout_micros(JNIEnv *env, jobject this, jlong value) { - TSQueryCursor *cursor = GET_POINTER(TSQueryCursor, this, Query_cursor); - ts_query_cursor_set_timeout_micros(cursor, (uint64_t)value); - (*env)->SetLongField(env, this, global_field_cache.Query_timeoutMicros, value); -} - -jint query_get_match_limit(JNIEnv *env, jobject this) { - TSQueryCursor *cursor = GET_POINTER(TSQueryCursor, this, Query_cursor); - return (jint)ts_query_cursor_match_limit(cursor); -} - -void query_set_match_limit(JNIEnv *env, jobject this, jint value) { - TSQueryCursor *cursor = GET_POINTER(TSQueryCursor, this, Query_cursor); - ts_query_cursor_set_match_limit(cursor, (uint32_t)value); - (*env)->SetIntField(env, this, global_field_cache.Query_matchLimit, value); -} - -void query_set_max_start_depth(JNIEnv *env, jobject this, jint value) { - TSQueryCursor *cursor = GET_POINTER(TSQueryCursor, this, Query_cursor); - ts_query_cursor_set_max_start_depth(cursor, (uint32_t)value); - (*env)->SetIntField(env, this, global_field_cache.Query_maxStartDepth, value); -} - -void query_native_set_byte_range(JNIEnv *env, jobject this, jint start, jint end) { - TSQueryCursor *cursor = GET_POINTER(TSQueryCursor, this, Query_cursor); - ts_query_cursor_set_byte_range(cursor, (uint32_t)start, (uint32_t)end); -} - -void query_native_set_point_range(JNIEnv *env, jobject this, jobject start, jobject end) { - TSQueryCursor *cursor = GET_POINTER(TSQueryCursor, this, Query_cursor); - TSPoint start_point = unmarshal_point(env, start), end_point = unmarshal_point(env, end); - ts_query_cursor_set_point_range(cursor, start_point, end_point); -} - -jboolean query_did_exceed_match_limit(JNIEnv *env, jobject this) { - TSQueryCursor *cursor = GET_POINTER(TSQueryCursor, this, Query_cursor); - return (jboolean)ts_query_cursor_did_exceed_match_limit(cursor); -} - void query_disable_pattern(JNIEnv *env, jobject this, jint index) { TSQuery *self = GET_POINTER(TSQuery, this, Query_self); if (ts_query_pattern_count(self) > (uint32_t)index) { @@ -177,7 +131,7 @@ void query_disable_pattern(JNIEnv *env, jobject this, jint index) { } } -void query_native_disable_capture(JNIEnv *env, jobject this, jstring capture) { +void query_disable_capture(JNIEnv *env, jobject this, jstring capture) { TSQuery *self = GET_POINTER(TSQuery, this, Query_self); const char *capture_chars = (*env)->GetStringUTFChars(env, capture, NULL); uint32_t length = (uint32_t)(*env)->GetStringUTFLength(env, capture); @@ -247,13 +201,6 @@ jint query_string_count(JNIEnv *env, jobject this) { return (jint)ts_query_string_count(self); } -void query_exec(JNIEnv *env, jobject this, jobject node) { - TSQuery *query = GET_POINTER(TSQuery, this, Query_self); - TSQueryCursor *cursor = GET_POINTER(TSQueryCursor, this, Query_cursor); - TSNode ts_node = unmarshal_node(env, node); - ts_query_cursor_exec(cursor, query, ts_node); -} - jstring query_capture_name_for_id(JNIEnv *env, jobject this, jint index) { TSQuery *self = GET_POINTER(TSQuery, this, Query_self); uint32_t length; @@ -287,89 +234,20 @@ jobject query_predicates_for_pattern(JNIEnv *env, jobject this, jint index) { return predicates; } -jobject query_next_match(JNIEnv *env, jobject this, jobject tree) { - TSQueryCursor *cursor = GET_POINTER(TSQueryCursor, this, Query_cursor); - TSQueryMatch match; - if (!ts_query_cursor_next_match(cursor, &match)) - return NULL; - - jobject capture_names = GET_FIELD(Object, this, Query_captureNames); - jobject captures = NEW_OBJECT(ArrayList, (jint)match.capture_count); - for (uint16_t i = 0; i < match.capture_count; ++i) { - TSQueryCapture capture = match.captures[i]; - jobject node = marshal_node(env, capture.node, tree); - jobject name = CALL_METHOD(Object, capture_names, List_get, capture.index); - if ((*env)->ExceptionCheck(env)) - return NULL; - - jobject capture_obj = NEW_OBJECT(QueryCapture, node, name); - CALL_METHOD(Boolean, captures, ArrayList_add, capture_obj); - (*env)->DeleteLocalRef(env, capture_obj); - (*env)->DeleteLocalRef(env, node); - (*env)->DeleteLocalRef(env, name); - if ((*env)->ExceptionCheck(env)) - return NULL; - } - return NEW_OBJECT(QueryMatch, (jint)match.pattern_index, captures); -} - -jobject query_next_capture(JNIEnv *env, jobject this, jobject tree) { - TSQueryCursor *cursor = GET_POINTER(TSQueryCursor, this, Query_cursor); - uint32_t capture_index; - TSQueryMatch match; - if (!ts_query_cursor_next_capture(cursor, &match, &capture_index)) - return NULL; - - jobject capture_names = GET_FIELD(Object, this, Query_captureNames); - jobject captures = NEW_OBJECT(ArrayList, (jint)match.capture_count); - for (uint16_t i = 0; i < match.capture_count; ++i) { - TSQueryCapture capture = match.captures[i]; - jobject node = marshal_node(env, capture.node, tree); - jobject name = CALL_METHOD(Object, capture_names, List_get, capture.index); - if ((*env)->ExceptionCheck(env)) - return NULL; - - jobject capture_obj = NEW_OBJECT(QueryCapture, node, name); - CALL_METHOD(Boolean, captures, ArrayList_add, capture_obj); - (*env)->DeleteLocalRef(env, capture_obj); - (*env)->DeleteLocalRef(env, node); - (*env)->DeleteLocalRef(env, name); - if ((*env)->ExceptionCheck(env)) - return NULL; - } - jobject match_obj = NEW_OBJECT(QueryMatch, (jint)match.pattern_index, captures); - jobject index = (*env)->AllocObject(env, global_class_cache.UInt); - (*env)->SetIntField(env, index, global_field_cache.UInt_data, (jint)capture_index); - return NEW_OBJECT(Pair, index, match_obj); -} - const JNINativeMethod Query_methods[] = { {"init", "(JLjava/lang/String;)J", (void *)&query_init}, - {"cursor", "()J", (void *)&query_cursor}, - {"delete", "(JJ)V", (void *)&query_delete}, - {"getPatternCount", "()I", (void *)&query_get_pattern_count}, - {"getCaptureCount", "()I", (void *)&query_get_capture_count}, - {"getTimeoutMicros", "()J", (void *)&query_get_timeout_micros}, - {"setTimeoutMicros", "(J)V", (void *)&query_set_timeout_micros}, - {"getMatchLimit", "()I", (void *)&query_get_match_limit}, - {"setMatchLimit", "(I)V", (void *)&query_set_match_limit}, - {"setMaxStartDepth", "(I)V", (void *)&query_set_max_start_depth}, - {"didExceedMatchLimit", "()Z", (void *)&query_did_exceed_match_limit}, + {"delete", "(J)V", (void *)&query_delete}, + {"nativePatternCount", "()I", (void *)&query_native_pattern_count}, + {"nativeCaptureCount", "()I", (void *)&query_native_capture_count}, {"disablePattern", "(I)V", (void *)&query_disable_pattern}, + {"disableCapture", "(Ljava/lang/String;)V", (void *)&query_disable_capture}, {"startByteForPattern", "(I)I", (void *)&query_start_byte_for_pattern}, {"endByteForPattern", "(I)I", (void *)&query_end_byte_for_pattern}, {"isPatternRooted", "(I)Z", (void *)&query_is_pattern_rooted}, {"isPatternNonLocal", "(I)Z", (void *)&query_is_pattern_non_local}, {"stringCount", "()I", (void *)&query_string_count}, - {"exec", "(L" PACKAGE "Node;)V", (void *)&query_exec}, - {"nextMatch", "(L" PACKAGE "Tree;)L" PACKAGE "QueryMatch;", (void *)&query_next_match}, - {"nextCapture", "(L" PACKAGE "Tree;)Lkotlin/Pair;", (void *)&query_next_capture}, {"captureNameForId", "(I)Ljava/lang/String;", (void *)&query_capture_name_for_id}, {"stringValueForId", "(I)Ljava/lang/String;", (void *)&query_string_value_for_id}, - {"nativeSetByteRange", "(II)V", (void *)&query_native_set_byte_range}, - {"nativeSetPointRange", "(L" PACKAGE "Point;L" PACKAGE "Point;)V", - (void *)&query_native_set_point_range}, - {"nativeDisableCapture", "(Ljava/lang/String;)V", (void *)&query_native_disable_capture}, {"nativeIsPatternGuaranteedAtStep", "(I)Z", (void *)&query_native_is_pattern_guaranteed_at_step}, {"predicatesForPattern", "(I)Ljava/util/List;", (void *)&query_predicates_for_pattern}, diff --git a/ktreesitter/src/jni/query_cursor.c b/ktreesitter/src/jni/query_cursor.c new file mode 100644 index 0000000..18ff72a --- /dev/null +++ b/ktreesitter/src/jni/query_cursor.c @@ -0,0 +1,151 @@ +#include "utils.h" + +static bool query_progress_callback(TSQueryCursorState *state) { + ProgressPayload *progress_payload = (ProgressPayload *)state->payload; + JNIEnv *env = progress_payload->env; + jobject offset = (*env)->AllocObject(env, global_class_cache.UInt); + (*env)->SetIntField(env, offset, global_field_cache.UInt_data, + (jint)state->current_byte_offset); + jobject result = CALL_METHOD(Object, progress_payload->callback, Function1_invoke, offset); + (*env)->DeleteLocalRef(env, offset); + return (bool)(*env)->GetBooleanField(env, result, global_field_cache.Boolean_value); +} + +jlong query_cursor_init CRITICAL_NO_ARGS() { return (jlong)ts_query_cursor_new(); } + +void query_cursor_delete CRITICAL_ARGS(jlong query) { ts_query_delete((TSQuery *)query); } + +jlong query_cursor_get_timeout_micros(JNIEnv *env, jobject this) { + TSQueryCursor *cursor = GET_POINTER(TSQueryCursor, this, QueryCursor_self); + return (jlong)ts_query_cursor_timeout_micros(cursor); +} + +void query_cursor_set_timeout_micros(JNIEnv *env, jobject this, jlong value) { + TSQueryCursor *cursor = GET_POINTER(TSQueryCursor, this, QueryCursor_self); + ts_query_cursor_set_timeout_micros(cursor, (uint64_t)value); + (*env)->SetLongField(env, this, global_field_cache.QueryCursor_timeoutMicros, value); +} + +jint query_cursor_get_match_limit(JNIEnv *env, jobject this) { + TSQueryCursor *cursor = GET_POINTER(TSQueryCursor, this, QueryCursor_self); + return (jint)ts_query_cursor_match_limit(cursor); +} + +void query_cursor_set_match_limit(JNIEnv *env, jobject this, jint value) { + TSQueryCursor *cursor = GET_POINTER(TSQueryCursor, this, QueryCursor_self); + ts_query_cursor_set_match_limit(cursor, (uint32_t)value); + (*env)->SetIntField(env, this, global_field_cache.QueryCursor_matchLimit, value); +} + +void query_cursor_set_max_start_depth(JNIEnv *env, jobject this, jint value) { + TSQueryCursor *cursor = GET_POINTER(TSQueryCursor, this, QueryCursor_self); + ts_query_cursor_set_max_start_depth(cursor, (uint32_t)value); + (*env)->SetIntField(env, this, global_field_cache.QueryCursor_maxStartDepth, value); +} + +jboolean query_cursor_did_exceed_match_limit(JNIEnv *env, jobject this) { + TSQueryCursor *cursor = GET_POINTER(TSQueryCursor, this, QueryCursor_self); + return (jboolean)ts_query_cursor_did_exceed_match_limit(cursor); +} + +jboolean query_cursor_native_set_byte_range(JNIEnv *env, jobject this, jint start, jint end) { + TSQueryCursor *cursor = GET_POINTER(TSQueryCursor, this, QueryCursor_self); + return (jboolean)ts_query_cursor_set_byte_range(cursor, (uint32_t)start, (uint32_t)end); +} + +jboolean query_cursor_native_set_point_range(JNIEnv *env, jobject this, jobject start, + jobject end) { + TSQueryCursor *cursor = GET_POINTER(TSQueryCursor, this, QueryCursor_self); + TSPoint start_point = unmarshal_point(env, start), end_point = unmarshal_point(env, end); + return (jboolean)ts_query_cursor_set_point_range(cursor, start_point, end_point); +} + +void query_cursor_exec(JNIEnv *env, jobject this, jlong query, jobject node, + jobject progress_callback) { + TSQueryCursor *cursor = GET_POINTER(TSQueryCursor, this, QueryCursor_self); + TSNode ts_node = unmarshal_node(env, node); + if (progress_callback == NULL) { + ts_query_cursor_exec(cursor, (TSQuery *)query, ts_node); + } else { + ProgressPayload progress_payload = {.env = env, .callback = progress_callback}; + TSQueryCursorOptions options = { + .payload = (void *)&progress_payload, + .progress_callback = query_progress_callback, + }; + ts_query_cursor_exec_with_options(cursor, (TSQuery *)query, ts_node, &options); + } +} + +jobject query_cursor_next_capture(JNIEnv *env, jobject this, jobject capture_names, jobject tree) { + TSQueryCursor *cursor = GET_POINTER(TSQueryCursor, this, QueryCursor_self); + uint32_t capture_index; + TSQueryMatch match; + if (!ts_query_cursor_next_capture(cursor, &match, &capture_index)) + return NULL; + + jobject captures = NEW_OBJECT(ArrayList, (jint)match.capture_count); + for (uint16_t i = 0; i < match.capture_count; ++i) { + TSQueryCapture capture = match.captures[i]; + jobject node = marshal_node(env, capture.node, tree); + jobject name = CALL_METHOD(Object, capture_names, List_get, capture.index); + if ((*env)->ExceptionCheck(env)) + return NULL; + + jobject capture_obj = NEW_OBJECT(QueryCapture, node, name); + CALL_METHOD(Boolean, captures, ArrayList_add, capture_obj); + (*env)->DeleteLocalRef(env, capture_obj); + (*env)->DeleteLocalRef(env, node); + (*env)->DeleteLocalRef(env, name); + if ((*env)->ExceptionCheck(env)) + return NULL; + } + jobject match_obj = NEW_OBJECT(QueryMatch, (jint)match.pattern_index, captures); + jobject index = (*env)->AllocObject(env, global_class_cache.UInt); + (*env)->SetIntField(env, index, global_field_cache.UInt_data, (jint)capture_index); + return NEW_OBJECT(Pair, index, match_obj); +} + +jobject query_cursor_next_match(JNIEnv *env, jobject this, jobject capture_names, jobject tree) { + TSQueryCursor *cursor = GET_POINTER(TSQueryCursor, this, QueryCursor_self); + TSQueryMatch match; + if (!ts_query_cursor_next_match(cursor, &match)) + return NULL; + + jobject captures = NEW_OBJECT(ArrayList, (jint)match.capture_count); + for (uint16_t i = 0; i < match.capture_count; ++i) { + TSQueryCapture capture = match.captures[i]; + jobject node = marshal_node(env, capture.node, tree); + jobject name = CALL_METHOD(Object, capture_names, List_get, capture.index); + if ((*env)->ExceptionCheck(env)) + return NULL; + + jobject capture_obj = NEW_OBJECT(QueryCapture, node, name); + CALL_METHOD(Boolean, captures, ArrayList_add, capture_obj); + (*env)->DeleteLocalRef(env, capture_obj); + (*env)->DeleteLocalRef(env, node); + (*env)->DeleteLocalRef(env, name); + if ((*env)->ExceptionCheck(env)) + return NULL; + } + return NEW_OBJECT(QueryMatch, (jint)match.pattern_index, captures); +} + +const JNINativeMethod QueryCursor_methods[] = { + {"init", "()J", (void *)&query_cursor_init}, + {"delete", "(J)V", (void *)&query_cursor_delete}, + {"getTimeoutMicros", "()J", (void *)&query_cursor_get_timeout_micros}, + {"setTimeoutMicros", "(J)V", (void *)&query_cursor_set_timeout_micros}, + {"getMatchLimit", "()I", (void *)&query_cursor_get_match_limit}, + {"setMatchLimit", "(I)V", (void *)&query_cursor_set_match_limit}, + {"setMaxStartDepth", "(I)V", (void *)&query_cursor_set_max_start_depth}, + {"didExceedMatchLimit", "()Z", (void *)&query_cursor_did_exceed_match_limit}, + {"nativeSetByteRange", "(II)Z", (void *)&query_cursor_native_set_byte_range}, + {"nativeSetPointRange", "(L" PACKAGE "Point;L" PACKAGE "Point;)Z", + (void *)&query_cursor_native_set_point_range}, + {"nextMatch", "(Ljava/util/List;L" PACKAGE "Tree;)L" PACKAGE "QueryMatch;", + (void *)&query_cursor_next_match}, + {"nextCapture", "(Ljava/util/List;L" PACKAGE "Tree;)Lkotlin/Pair;", + (void *)&query_cursor_next_capture}, +}; + +const size_t QueryCursor_methods_size = sizeof QueryCursor_methods / sizeof(JNINativeMethod); diff --git a/ktreesitter/src/jni/utils.h b/ktreesitter/src/jni/utils.h index c6718cb..c27a19f 100644 --- a/ktreesitter/src/jni/utils.h +++ b/ktreesitter/src/jni/utils.h @@ -54,12 +54,21 @@ #endif typedef struct { + JNIEnv *env; + jobject callback; +} ProgressPayload; + +typedef struct { + jfieldID Boolean_value; jfieldID InputEdit_newEndByte; jfieldID InputEdit_newEndPoint; jfieldID InputEdit_oldEndByte; jfieldID InputEdit_oldEndPoint; jfieldID InputEdit_startByte; jfieldID InputEdit_startPoint; + jfieldID InputEncoding_UTF_8; + jfieldID InputEncoding_UTF_16LE; + jfieldID InputEncoding_UTF_16BE; jfieldID Language_self; jfieldID LookaheadIterator_self; jfieldID Node_context; @@ -75,14 +84,13 @@ typedef struct { jfieldID Parser_timeoutMicros; jfieldID Point_column; jfieldID Point_row; - jfieldID Query_captureNames; - jfieldID Query_cursor; + jfieldID QueryCursor_matchLimit; + jfieldID QueryCursor_maxStartDepth; + jfieldID QueryCursor_self; + jfieldID QueryCursor_timeoutMicros; jfieldID Query_language; - jfieldID Query_matchLimit; - jfieldID Query_maxStartDepth; jfieldID Query_self; jfieldID Query_source; - jfieldID Query_timeoutMicros; jfieldID Range_endByte; jfieldID Range_endPoint; jfieldID Range_startByte; @@ -93,20 +101,25 @@ typedef struct { jfieldID Tree_self; jfieldID Tree_source; jfieldID UInt_data; + jfieldID UShort_data; } FieldCache; typedef struct { jmethodID ArrayList_add; jmethodID ArrayList_init; + jmethodID Boolean_init; jmethodID CharSequence_toString; + jmethodID Function1_invoke; jmethodID Function2_invoke; jmethodID Language_init; + jmethodID Language$Metadata_init; jmethodID List_get; jmethodID List_size; jmethodID Node_init; jmethodID Pair_init; jmethodID Point_init; jmethodID QueryCapture_init; + jmethodID QueryCursor_init; jmethodID QueryError$Capture_init; jmethodID QueryError$Field_init; jmethodID QueryError$NodeType_init; @@ -115,19 +128,22 @@ typedef struct { jmethodID QueryMatch_init; jmethodID Range_init; jmethodID Tree_init; - jmethodID UInt_constructor; - jmethodID UInt_box; + jmethodID Triple_init; } MethodCache; typedef struct { jclass ArrayList; + jclass Boolean; jclass CharSequence; + jclass Function1; jclass Function2; jclass IllegalArgumentException; jclass IllegalStateException; jclass IndexOutOfBoundsException; jclass InputEdit; + jclass InputEncoding; jclass Language; + jclass Language$Metadata; jclass List; jclass LookaheadIterator; jclass Node; @@ -137,6 +153,7 @@ typedef struct { jclass Point; jclass Query; jclass QueryCapture; + jclass QueryCursor; jclass QueryError$Capture; jclass QueryError$Field; jclass QueryError$NodeType; @@ -146,7 +163,9 @@ typedef struct { jclass Range; jclass Tree; jclass TreeCursor; + jclass Triple; jclass UInt; + jclass UShort; } ClassCache; extern FieldCache global_field_cache; diff --git a/ktreesitter/src/jvmMain/kotlin/io/github/treesitter/ktreesitter/InputEncoding.kt b/ktreesitter/src/jvmMain/kotlin/io/github/treesitter/ktreesitter/InputEncoding.kt new file mode 100644 index 0000000..f927ec4 --- /dev/null +++ b/ktreesitter/src/jvmMain/kotlin/io/github/treesitter/ktreesitter/InputEncoding.kt @@ -0,0 +1,14 @@ +package io.github.treesitter.ktreesitter + +import java.nio.charset.Charset + +/** + * The encoding of the input text. + * + * @since 0.25.0 + */ +actual enum class InputEncoding(val charset: Charset) { + UTF_8(Charsets.UTF_8), + UTF_16LE(Charsets.UTF_16LE), + UTF_16BE(Charsets.UTF_16BE) +} diff --git a/ktreesitter/src/jvmMain/kotlin/io/github/treesitter/ktreesitter/Language.kt b/ktreesitter/src/jvmMain/kotlin/io/github/treesitter/ktreesitter/Language.kt index 4cc4037..539c13f 100644 --- a/ktreesitter/src/jvmMain/kotlin/io/github/treesitter/ktreesitter/Language.kt +++ b/ktreesitter/src/jvmMain/kotlin/io/github/treesitter/ktreesitter/Language.kt @@ -3,12 +3,13 @@ package io.github.treesitter.ktreesitter /** * A class that defines how to parse a particular language. * - * When a [Language] is generated by the Tree-sitter CLI, it is assigned - * an ABI [version] number that corresponds to the current CLI version. + * When a [Language] is generated by the Tree-sitter CLI, it is assigned an + * [ABI version][abiVersion] number that corresponds to the current CLI version. * * @constructor Create a new instance from the given language pointer. * @param language A pointer to a `TSLanguage` cast to [Long]. - * @throws [IllegalArgumentException] If the pointer is invalid or the [version] is incompatible. + * @throws [IllegalArgumentException] + * If the pointer is invalid or the [version][abiVersion] is incompatible. */ actual class Language @Throws(IllegalArgumentException::class) actual constructor(language: Any) { @JvmField @@ -19,7 +20,17 @@ actual class Language @Throws(IllegalArgumentException::class) actual constructo checkVersion() } + /** + * The ABI version number for this language. + * + * @since 0.25.0 + */ + @get:JvmName("getAbiVersion") + actual val abiVersion: UInt + external get + /** The ABI version number for this language. */ + @Deprecated("version is deprecated", ReplaceWith("abiVersion"), DeprecationLevel.ERROR) @get:JvmName("getVersion") actual val version: UInt external get @@ -39,6 +50,32 @@ actual class Language @Throws(IllegalArgumentException::class) actual constructo actual val fieldCount: UInt external get + /** + * The name of the language, if available. + * + * @since 0.25.0 + */ + actual val name: String? + external get + + /** + * The metadata of the language, if available. + * + * @since 0.25.0 + */ + actual val metadata: Metadata? + external get + + /** + * The supertype symbols of the language. + * + * @since 0.25.0 + */ + @OptIn(ExperimentalUnsignedTypes::class) + @get:JvmName("getSupertypes") + actual val supertypes: UShortArray + external get + /** * Get another reference to the language. * @@ -54,6 +91,16 @@ actual class Language @Throws(IllegalArgumentException::class) actual constructo @JvmName("symbolForName") actual external fun symbolForName(name: String, isNamed: Boolean): UShort + /** + * Get the subtype symbols for the given supertype symbol + * + * @since 0.25.0 + * @see supertypes + */ + @JvmName("subtypes") + @OptIn(ExperimentalUnsignedTypes::class) + actual external fun subtypes(supertype: UShort): UShortArray + /** * Check if the node for the given numerical ID is named * @@ -108,11 +155,12 @@ actual class Language @Throws(IllegalArgumentException::class) actual constructo /** * Create a new [Query] from a string containing one or more S-expression - * [patterns](https://tree-sitter.github.io/tree-sitter/using-parsers#query-syntax). + * [patterns](https://tree-sitter.github.io/tree-sitter/using-parsers/queries/1-syntax.html). * * @throws [QueryError] If any error occurred while creating the query. */ @Throws(QueryError::class) + @Deprecated("Use the Query constructor instead") actual fun query(source: String) = Query(this, source) actual override fun equals(other: Any?) = @@ -120,11 +168,32 @@ actual class Language @Throws(IllegalArgumentException::class) actual constructo actual override fun hashCode() = self.hashCode() - override fun toString() = "Language(id=0x${self.toString(16)}, version=$version)" + override fun toString() = "Language(id=0x${self.toString(16)}, abiVersion=$abiVersion)" @Throws(IllegalArgumentException::class) private external fun checkVersion() + /** + * A class containing the [Language] metadata. + * + * @property semanticVersion The [Semantic Version](https://semver.org/) of the [Language]. + */ + @ConsistentCopyVisibility + actual data class Metadata internal actual constructor( + @get:JvmName("getSemanticVersion") + actual val semanticVersion: Triple + ) { + actual override fun toString() = buildString { + append("Metadata(semanticVersion=\"") + append(semanticVersion.first) + append('.') + append(semanticVersion.second) + append('.') + append(semanticVersion.third) + append("\")") + } + } + private companion object { @JvmStatic private external fun copy(self: Long): Long diff --git a/ktreesitter/src/jvmMain/kotlin/io/github/treesitter/ktreesitter/LookaheadIterator.kt b/ktreesitter/src/jvmMain/kotlin/io/github/treesitter/ktreesitter/LookaheadIterator.kt index 496caf3..51692a2 100644 --- a/ktreesitter/src/jvmMain/kotlin/io/github/treesitter/ktreesitter/LookaheadIterator.kt +++ b/ktreesitter/src/jvmMain/kotlin/io/github/treesitter/ktreesitter/LookaheadIterator.kt @@ -71,7 +71,7 @@ actual class LookaheadIterator @Throws(IllegalArgumentException::class) internal } } - override fun computeNext() = if (nativeNext()) { + actual override fun computeNext() = if (nativeNext()) { setNext(Symbol(currentSymbol, currentSymbolName)) } else { done() diff --git a/ktreesitter/src/jvmMain/kotlin/io/github/treesitter/ktreesitter/Node.kt b/ktreesitter/src/jvmMain/kotlin/io/github/treesitter/ktreesitter/Node.kt index 86e2b72..210af13 100644 --- a/ktreesitter/src/jvmMain/kotlin/io/github/treesitter/ktreesitter/Node.kt +++ b/ktreesitter/src/jvmMain/kotlin/io/github/treesitter/ktreesitter/Node.kt @@ -205,6 +205,24 @@ actual class Node internal constructor( @Throws(IndexOutOfBoundsException::class) actual external fun namedChild(index: UInt): Node? + /** + * Get the node's first child that contains + * or starts after the given byte offset. + * + * @since 0.25.0 + */ + @JvmName("firstChildForByte") + actual external fun firstChildForByte(byte: UInt): Node? + + /** + * Get the node's first _named_ child that contains + * or starts after the given byte offset. + * + * @since 0.25.0 + */ + @JvmName("firstNamedChildForByte") + actual external fun firstNamedChildForByte(byte: UInt): Node? + /** * Get the node's child with the given field ID, if any. * @@ -244,13 +262,6 @@ actual class Node internal constructor( @Throws(IndexOutOfBoundsException::class) actual external fun fieldNameForNamedChild(index: UInt): String? - /** Get the child of the node that contains the given descendant, if any. */ - @Deprecated( - "This method will not return a direct descendant", - ReplaceWith("childWithDescendant(descendant)", "io.github.treesitter.ktreesitter.Node") - ) - actual external fun childContainingDescendant(descendant: Node): Node? - /** * Get the node that contains the given descendant, if any. * diff --git a/ktreesitter/src/jvmMain/kotlin/io/github/treesitter/ktreesitter/Parser.kt b/ktreesitter/src/jvmMain/kotlin/io/github/treesitter/ktreesitter/Parser.kt index fe32fe7..6ef25ef 100644 --- a/ktreesitter/src/jvmMain/kotlin/io/github/treesitter/ktreesitter/Parser.kt +++ b/ktreesitter/src/jvmMain/kotlin/io/github/treesitter/ktreesitter/Parser.kt @@ -44,6 +44,7 @@ actual class Parser actual constructor() { */ @get:JvmName("getTimeoutMicros") @set:JvmName("setTimeoutMicros") + @Deprecated("Use the progressCallback in parse()") actual var timeoutMicros: ULong external get external set @@ -84,11 +85,10 @@ actual class Parser actual constructor() { * [Tree.edit] method in a way that exactly matches the source code changes. * * @throws [IllegalStateException] - * If the parser does not have a [language] assigned or - * if parsing was cancelled due to a [timeout][timeoutMicros]. + * If the parser does not have a [language] assigned or if parsing was halted. */ @Throws(IllegalStateException::class) - actual external fun parse(source: String, oldTree: Tree?): Tree + actual external fun parse(source: String, encoding: InputEncoding, oldTree: Tree?): Tree /** * Parse source code from a callback and create a syntax tree. @@ -100,19 +100,22 @@ actual class Parser actual constructor() { * [Tree.edit] method in a way that exactly matches the source code changes. * * @throws [IllegalStateException] - * If the parser does not have a [language] assigned or - * if parsing was cancelled due to a [timeout][timeoutMicros]. + * If the parser does not have a [language] assigned or if parsing was halted. */ @Throws(IllegalStateException::class) - actual external fun parse(oldTree: Tree?, callback: ParseCallback): Tree + actual external fun parse( + encoding: InputEncoding, + oldTree: Tree?, + progressCallback: ParseProgressCallback?, + readCallback: ParseReadCallback + ): Tree /** * Instruct the parser to start the next [parse] from the beginning. * - * If the parser previously failed because of a [timeout][timeoutMicros], - * then by default, it will resume where it left off. If you don't - * want to resume, and instead intend to use this parser to parse - * some other document, you must call this method first. + * If parsing was previously halted, then by default, it will resume where + * it left off. If you don't want to resume, and instead intend to use this + * parser to parse some other document, you must call this method first. */ actual external fun reset() diff --git a/ktreesitter/src/jvmMain/kotlin/io/github/treesitter/ktreesitter/Query.kt b/ktreesitter/src/jvmMain/kotlin/io/github/treesitter/ktreesitter/Query.kt index e073be7..0cef67b 100644 --- a/ktreesitter/src/jvmMain/kotlin/io/github/treesitter/ktreesitter/Query.kt +++ b/ktreesitter/src/jvmMain/kotlin/io/github/treesitter/ktreesitter/Query.kt @@ -1,24 +1,12 @@ package io.github.treesitter.ktreesitter -/** - * A class that represents a set of patterns which match nodes in a syntax tree. - * - * @constructor - * Create a new query from a particular language and a - * string containing one or more S-expression patterns. - * @throws [QueryError] If any error occurred while creating the query. - */ actual class Query @Throws(QueryError::class) actual constructor( private val language: Language, private val source: String ) { - private val self: Long = init(language.self, source) + internal val self: Long = init(language.self, source) - private val cursor: Long = cursor() - - private val captureNames: MutableList - - private val predicates: List> + internal val predicates: List> private val settingList: List> @@ -27,25 +15,40 @@ actual class Query @Throws(QueryError::class) actual constructor( /** The number of patterns in the query. */ @get:JvmName("getPatternCount") actual val patternCount: UInt - external get + get() = nativePatternCount().toUInt() /** The number of captures in the query. */ @get:JvmName("getCaptureCount") + @Deprecated("captureCount is deprecated.", ReplaceWith("captureNames.size")) actual val captureCount: UInt - external get + get() = nativeCaptureCount().toUInt() + + /** + * The capture names used in the query. + * + * @since 0.25.0 + */ + actual val captureNames: List + + /** + * The string literals used in the query. + * + * @since 0.25.0 + */ + actual val stringValues: List init { - RefCleaner(this, CleanAction(self, cursor)) + RefCleaner(this, CleanAction(self)) - predicates = List(patternCount.toInt()) { mutableListOf() } - settingList = List(patternCount.toInt()) { mutableMapOf() } - assertionList = List(patternCount.toInt()) { mutableMapOf() } - captureNames = MutableList(captureCount.toInt()) { + predicates = List(nativePatternCount()) { mutableListOf() } + settingList = List(nativePatternCount()) { mutableMapOf() } + assertionList = List(nativePatternCount()) { mutableMapOf() } + captureNames = List(nativeCaptureCount()) { checkNotNull(captureNameForId(it)) { "Failed to get capture name at index $it" } } - val stringValues = List(stringCount()) { + stringValues = List(stringCount()) { checkNotNull(stringValueForId(it)) { "Failed to get string value at index $it" } @@ -262,132 +265,14 @@ actual class Query @Throws(QueryError::class) actual constructor( } /** - * The maximum duration in microseconds that query - * execution should be allowed to take before halting. - * - * Default: `0` - * - * @since 0.23.0 - */ - @get:JvmName("getTimeoutMicros") - @set:JvmName("setTimeoutMicros") - actual var timeoutMicros: ULong - external get - external set - - /** - * The maximum number of in-progress matches. - * - * Default: `UInt.MAX_VALUE` - * - * @throws [IllegalArgumentException] If the match limit is set to `0`. - */ - @get:JvmName("getMatchLimit") - @set:JvmName("setMatchLimit") - actual var matchLimit: UInt - external get - external set - - /** - * The maximum start depth for the query. - * - * This prevents cursors from exploring children nodes at a certain depth. - * Note that if a pattern includes many children, then they will still be checked. - * - * Default: `UInt.MAX_VALUE` - */ - @get:JvmName("getMaxStartDepth") - @set:JvmName("setMaxStartDepth") - actual var maxStartDepth: UInt = UInt.MAX_VALUE - external set - - /** - * The range of bytes in which the query will be executed. - * - * Default: `UInt.MIN_VALUE..UInt.MAX_VALUE` - */ - actual var byteRange: UIntRange = UInt.MIN_VALUE..UInt.MAX_VALUE - set(value) { - nativeSetByteRange(value.first.toInt(), value.last.toInt()) - field = value - } - - /** - * The range of points in which the query will be executed. - * - * Default: `Point.MIN..Point.MAX` - */ - actual var pointRange: ClosedRange = Point.MIN..Point.MAX - set(value) { - nativeSetPointRange(value.start, value.endInclusive) - field = value - } - - /** - * Check if the query exceeded its maximum number of - * in-progress matches during its last execution. - */ - @get:JvmName("didExceedMatchLimit") - actual val didExceedMatchLimit: Boolean - external get - - /** - * Iterate over all the matches in the order that they were found. - * - * #### Example - * - * ```kotlin - * query.matches(tree.rootNode) { - * if (name != "ieq?") return@matches true - * val node = it[(args[0] as QueryPredicateArg.Capture).value].first() - * val value = (args[1] as QueryPredicateArg.Literal).value - * value.equals(node.text()?.toString(), ignoreCase = true) - * } - * ``` - * - * @param node The node that the query will run on. - * @param predicate A function that handles custom predicates. - */ - @JvmOverloads - actual fun matches( - node: Node, - predicate: QueryPredicate.(QueryMatch) -> Boolean - ): Sequence { - exec(node) - return sequence { - var match = nextMatch(node.tree) - while (match != null) { - val result = match.check(node.tree, predicate) - if (result != null) yield(result) - match = nextMatch(node.tree) - } - } - } - - /** - * Iterate over all the individual captures in the order that they appear. - * - * This is useful if you don't care about _which_ pattern matched. + * Execute the query on the given [Node]. * - * @param node The node that the query will run on. - * @param predicate A function that handles custom predicates. + * @since 0.25.0 */ @JvmOverloads - actual fun captures( - node: Node, - predicate: QueryPredicate.(QueryMatch) -> Boolean - ): Sequence> { - exec(node) - return sequence { - var capture = nextCapture(node.tree) - while (capture != null) { - val index = capture.first - val match = capture.second.check(node.tree, predicate) - if (match != null) yield(index to match) - capture = nextCapture(node.tree) - } - } - } + @JvmName("exec") + actual operator fun invoke(node: Node, progressCallback: QueryProgressCallback?) = + QueryCursor(this, node, progressCallback) /** * Get the property settings for the given pattern index. @@ -444,15 +329,8 @@ actual class Query @Throws(QueryError::class) actual constructor( * This prevents the capture from being returned in matches, * and also avoids most resource usage associated with recording * the capture. Currently, there is no way to undo this. - * - * @throws [NoSuchElementException] If the capture does not exist. */ - @Throws(NoSuchElementException::class) - actual fun disableCapture(name: String) { - if (!captureNames.remove(name)) - throw NoSuchElementException("Capture @$name does not exist") - nativeDisableCapture(name) - } + actual external fun disableCapture(name: String) /** * Get the byte offset where the given pattern starts in the query's source. @@ -514,39 +392,20 @@ actual class Query @Throws(QueryError::class) actual constructor( override fun toString() = "Query(language=$language, source=$source)" - private external fun stringCount(): Int - - private external fun exec(node: Node) + private external fun nativePatternCount(): Int - private external fun nextMatch(tree: Tree): QueryMatch? + private external fun nativeCaptureCount(): Int - private external fun nextCapture(tree: Tree): Pair? + private external fun stringCount(): Int private external fun captureNameForId(index: Int): String? private external fun stringValueForId(index: Int): String? - private external fun nativeSetByteRange(start: Int, end: Int) - - private external fun nativeSetPointRange(start: Point, end: Point) - - private external fun nativeDisableCapture(name: String) - private external fun nativeIsPatternGuaranteedAtStep(index: Int): Boolean private external fun predicatesForPattern(index: Int): List? - private inline fun QueryMatch.check( - tree: Tree, - predicate: QueryPredicate.(QueryMatch) -> Boolean - ): QueryMatch? { - if (tree.text() == null) return this - val result = predicates[patternIndex].all { - if (it !is QueryPredicate.Generic) it(this) else predicate(it, this) - } - return if (result) this else null - } - @Suppress("NOTHING_TO_INLINE") private inline operator fun List.get(index: UInt) = get(index.toInt()) @@ -556,8 +415,8 @@ actual class Query @Throws(QueryError::class) actual constructor( private inline val IntArray.type: Int inline get() = get(1) - private class CleanAction(private val query: Long, private val cursor: Long) : Runnable { - override fun run() = delete(query, cursor) + private class CleanAction(private val ptr: Long) : Runnable { + override fun run() = delete(ptr) } @Suppress("ConstPropertyName") @@ -573,9 +432,6 @@ actual class Query @Throws(QueryError::class) actual constructor( private external fun init(language: Long, query: String): Long @JvmStatic - private external fun cursor(): Long - - @JvmStatic - private external fun delete(query: Long, cursor: Long) + private external fun delete(self: Long) } } diff --git a/ktreesitter/src/jvmMain/kotlin/io/github/treesitter/ktreesitter/QueryCursor.kt b/ktreesitter/src/jvmMain/kotlin/io/github/treesitter/ktreesitter/QueryCursor.kt new file mode 100644 index 0000000..5c4b185 --- /dev/null +++ b/ktreesitter/src/jvmMain/kotlin/io/github/treesitter/ktreesitter/QueryCursor.kt @@ -0,0 +1,194 @@ +package io.github.treesitter.ktreesitter + +/** + * A class that is used for executing a query. + * + * @since 0.25.0 + */ +actual class QueryCursor internal constructor( + private val query: Query, + private val node: Node, + progressCallback: QueryProgressCallback? = null +) { + private val self: Long = init() + + init { + RefCleaner(this, CleanAction(self)) + + exec(query.self, node, progressCallback) + } + + /** + * The maximum duration in microseconds that query + * execution should be allowed to take before halting. + * + * Default: `0` + * + * @since 0.23.0 + */ + @get:JvmName("getTimeoutMicros") + @set:JvmName("setTimeoutMicros") + @Deprecated("Use the progressCallback in Query.invoke()") + actual var timeoutMicros: ULong + external get + + external set + + /** + * The maximum number of in-progress matches. + * + * Default: `UInt.MAX_VALUE` + * + * @throws [IllegalArgumentException] If the match limit is set to `0`. + */ + @get:JvmName("getMatchLimit") + @set:JvmName("setMatchLimit") + @set:Throws(IllegalArgumentException::class) + actual var matchLimit: UInt + external get + + external set + + /** + * The maximum start depth for the query. + * + * This prevents cursors from exploring children nodes at a certain depth. + * Note that if a pattern includes many children, then they will still be checked. + * + * Default: `UInt.MAX_VALUE` + */ + @get:JvmName("getMaxStartDepth") + @set:JvmName("setMaxStartDepth") + actual var maxStartDepth: UInt = UInt.MAX_VALUE + external set + + /** + * The range of bytes in which the query will be executed. + * + * The query cursor will return matches that intersect with + * the given range. This means that a match may be returned + * even if some of its captures fall outside the specified range, + * as long as at least part of the match overlaps with the range. + * + * Default: `UInt.MIN_VALUE..UInt.MAX_VALUE` + * + * @throws [IllegalArgumentException] If set to an invalid range. + */ + actual var byteRange: UIntRange = UInt.MIN_VALUE..UInt.MAX_VALUE + set(value) { + require(nativeSetByteRange(value.first.toInt(), value.last.toInt())) { + "Invalid byte range: [${value.first}, ${value.last}]" + } + field = value + } + + /** + * The range of points in which the query will be executed. + * + * The query cursor will return matches that intersect with + * the given range. This means that a match may be returned + * even if some of its captures fall outside the specified range, + * as long as at least part of the match overlaps with the range. + * + * Default: `Point.MIN..Point.MAX` + */ + actual var pointRange: ClosedRange = Point.MIN..Point.MAX + set(value) { + require(nativeSetPointRange(value.start, value.endInclusive)) { + "Invalid point range: [${value.start}, ${value.endInclusive}]" + } + field = value + } + + /** + * Check if the query exceeded its maximum number of + * in-progress matches during its last execution. + * + * @see matchLimit + */ + @get:JvmName("didExceedMatchLimit") + actual val didExceedMatchLimit: Boolean + external get + + /** + * Iterate over all the matches in the order that they were found. + * + * #### Example + * + * ```kotlin + * query(tree.rootNode).matches { + * if (name != "ieq?") return@matches true + * val node = it[(args[0] as QueryPredicateArg.Capture).value].first() + * val value = (args[1] as QueryPredicateArg.Literal).value + * value.equals(node.text()?.toString(), ignoreCase = true) + * } + * ``` + * + * @param predicate A function that handles custom predicates. + */ + @JvmOverloads + actual fun matches(predicate: QueryPredicate.(QueryMatch) -> Boolean) = sequence { + var match = nextMatch(query.captureNames, node.tree) + while (match != null) { + val result = match.check(predicate) + if (result != null) yield(result) + match = nextMatch(query.captureNames, node.tree) + } + } + + /** + * Iterate over all the individual captures in the order that they appear. + * + * This is useful if you don't care about _which_ pattern matched. + * + * @param predicate A function that handles custom predicates. + */ + @JvmOverloads + actual fun captures(predicate: QueryPredicate.(QueryMatch) -> Boolean) = + sequence> { + var capture = nextCapture(query.captureNames, node.tree) + while (capture != null) { + val index = capture.first + val match = capture.second.check(predicate) + if (match != null) yield(index to match) + capture = nextCapture(query.captureNames, node.tree) + } + } + + override fun toString() = "QueryCursor(query=$query, node=$node)" + + private external fun nativeSetByteRange(start: Int, end: Int): Boolean + + private external fun nativeSetPointRange(start: Point, end: Point): Boolean + + private external fun nextMatch(captureNames: List, tree: Tree): QueryMatch? + + private external fun nextCapture( + captureNames: List, + tree: Tree + ): Pair? + + private external fun exec(query: Long, node: Node, progressCallback: QueryProgressCallback?) + + private inline fun QueryMatch.check( + predicate: QueryPredicate.(QueryMatch) -> Boolean + ): QueryMatch? { + if (node.tree.text() == null) return this + val result = query.predicates[patternIndex.toInt()].all { + if (it !is QueryPredicate.Generic) it(this) else predicate(it, this) + } + return if (result) this else null + } + + private class CleanAction(private val ptr: Long) : Runnable { + override fun run() = delete(ptr) + } + + private companion object { + @JvmStatic + private external fun init(): Long + + @JvmStatic + private external fun delete(self: Long) + } +} diff --git a/ktreesitter/src/nativeInterop/cinterop/treesitter.def b/ktreesitter/src/nativeInterop/cinterop/treesitter.def index 3e2a4fc..c7f5608 100644 --- a/ktreesitter/src/nativeInterop/cinterop/treesitter.def +++ b/ktreesitter/src/nativeInterop/cinterop/treesitter.def @@ -1,14 +1,14 @@ package = io.github.treesitter.ktreesitter.internal headers = tree_sitter/api.h alloc.h headerFilter = tree_sitter/api.h -compilerOpts = -DTREE_SITTER_HIDE_SYMBOLS +compilerOpts = -DTREE_SITTER_HIDE_SYMBOLS -D_DEFAULT_SOURCE -D_POSIX_C_SOURCE=200112L staticLibraries = libtree-sitter.a strictEnums = \ + TSInputEncoding \ TSLogType \ TSQuantifier \ TSQueryError nonStrictEnums = \ - TSInputEncoding \ TSQueryPredicateStepType \ TSSymbolType excludedFunctions = \ diff --git a/ktreesitter/src/nativeMain/kotlin/io/github/treesitter/ktreesitter/InputEncoding.kt b/ktreesitter/src/nativeMain/kotlin/io/github/treesitter/ktreesitter/InputEncoding.kt new file mode 100644 index 0000000..15d1d02 --- /dev/null +++ b/ktreesitter/src/nativeMain/kotlin/io/github/treesitter/ktreesitter/InputEncoding.kt @@ -0,0 +1,16 @@ +package io.github.treesitter.ktreesitter + +import io.github.treesitter.ktreesitter.internal.TSInputEncoding +import kotlinx.cinterop.ExperimentalForeignApi + +/** + * The encoding of the input text. + * + * @since 0.25.0 + */ +@OptIn(ExperimentalForeignApi::class) +actual enum class InputEncoding(internal val value: TSInputEncoding) { + UTF_8(TSInputEncoding.TSInputEncodingUTF8), + UTF_16LE(TSInputEncoding.TSInputEncodingUTF16LE), + UTF_16BE(TSInputEncoding.TSInputEncodingUTF16BE) +} diff --git a/ktreesitter/src/nativeMain/kotlin/io/github/treesitter/ktreesitter/Language.kt b/ktreesitter/src/nativeMain/kotlin/io/github/treesitter/ktreesitter/Language.kt index 56b7595..9663142 100644 --- a/ktreesitter/src/nativeMain/kotlin/io/github/treesitter/ktreesitter/Language.kt +++ b/ktreesitter/src/nativeMain/kotlin/io/github/treesitter/ktreesitter/Language.kt @@ -7,8 +7,8 @@ import kotlinx.cinterop.* /** * A class that defines how to parse a particular language. * - * When a [Language] is generated by the Tree-sitter CLI, it is assigned - * an ABI [version] number that corresponds to the current CLI version. + * When a [Language] is generated by the Tree-sitter CLI, it is assigned an + * [ABI version][abiVersion] number that corresponds to the current CLI version. */ @OptIn(ExperimentalForeignApi::class) actual class Language internal constructor( internal val self: CPointer @@ -18,7 +18,7 @@ import kotlinx.cinterop.* * * @param language A [CPointer] to a `TSLanguage`. * @throws [IllegalArgumentException] - * If the pointer is invalid or the [version] is incompatible. + * If the pointer is invalid or the [version][abiVersion] is incompatible. */ @Throws(IllegalArgumentException::class) actual constructor(language: Any) : this( @@ -26,16 +26,24 @@ import kotlinx.cinterop.* ?: throw IllegalArgumentException("Invalid language: $language") ) - /** The ABI version number for this language. */ - actual val version: UInt = ts_language_version(self) + /** + * The ABI version number for this language. + * + * @since 0.25.0 + */ + actual val abiVersion: UInt = ts_language_abi_version(self) init { - require(version in MIN_COMPATIBLE_LANGUAGE_VERSION..LANGUAGE_VERSION) { - "Incompatible language version $version. " + + require(abiVersion in MIN_COMPATIBLE_LANGUAGE_VERSION..LANGUAGE_VERSION) { + "Incompatible language version $abiVersion. " + "Must be between $MIN_COMPATIBLE_LANGUAGE_VERSION and $LANGUAGE_VERSION." } } + /** The ABI version number for this language. */ + @Deprecated("version is deprecated", ReplaceWith("abiVersion"), DeprecationLevel.ERROR) + actual val version = abiVersion + /** The number of distinct node types in this language. */ actual val symbolCount: UInt = ts_language_symbol_count(self) @@ -45,6 +53,42 @@ import kotlinx.cinterop.* /** The number of distinct field names in this language. */ actual val fieldCount: UInt = ts_language_field_count(self) + /** + * The name of the language, if available. + * + * @since 0.25.0 + */ + actual val name: String? = ts_language_name(self)?.toKString() + + /** + * The metadata of the language, if available. + * + * @since 0.25.0 + */ + actual val metadata: Metadata? + get() = ts_language_metadata(self)?.pointed?.run { + Metadata( + Triple( + major_version.convert(), + minor_version.convert(), + patch_version.convert() + ) + ) + } + + /** + * The supertype symbols of the language. + * + * @since 0.25.0 + */ + @OptIn(ExperimentalUnsignedTypes::class) + actual val supertypes: UShortArray + get() = memScoped { + val length = alloc() + val supertypes = ts_language_supertypes(self, length.ptr) ?: return ushortArrayOf() + return UShortArray(length.value.convert()) { supertypes[it] } + } + /** * Get another reference to the language. * @@ -59,6 +103,19 @@ import kotlinx.cinterop.* actual fun symbolForName(name: String, isNamed: Boolean): UShort = ts_language_symbol_for_name(self, name, name.length.convert(), isNamed) + /** + * Get the subtype symbols for the given supertype symbol + * + * @since 0.25.0 + * @see supertypes + */ + @OptIn(ExperimentalUnsignedTypes::class) + actual fun subtypes(supertype: UShort): UShortArray = memScoped { + val length = alloc() + val supertypes = ts_language_subtypes(self, supertype, length.ptr) ?: return ushortArrayOf() + return UShortArray(length.value.convert()) { supertypes[it] } + } + /** * Check if the node for the given numerical ID is named * @@ -106,22 +163,43 @@ import kotlinx.cinterop.* * * @throws [IllegalArgumentException] If the state is invalid for this language. */ - @Throws( - IllegalArgumentException::class - ) actual fun lookaheadIterator(state: UShort) = LookaheadIterator(this, state) + @Throws(IllegalArgumentException::class) + actual fun lookaheadIterator(state: UShort) = LookaheadIterator(this, state) /** * Create a new [Query] from a string containing one or more S-expression - * [patterns](https://tree-sitter.github.io/tree-sitter/using-parsers#query-syntax). + * [patterns](https://tree-sitter.github.io/tree-sitter/using-parsers/queries/1-syntax.html). * * @throws [QueryError] If any error occurred while creating the query. */ - @Throws(QueryError::class) actual fun query(source: String) = Query(this, source) + @Throws(QueryError::class) + @Deprecated("Use the Query constructor instead") + actual fun query(source: String) = Query(this, source) actual override fun equals(other: Any?) = this === other || (other is Language && self == other.self) actual override fun hashCode() = self.hashCode() - override fun toString() = "Language(id=${self.rawValue}, version=$version)" + override fun toString() = "Language(id=${self.rawValue}, abiVersion=$abiVersion)" + + /** + * A class containing the [Language] metadata. + * + * @property semanticVersion The [Semantic Version](https://semver.org/) of the [Language]. + */ + @ConsistentCopyVisibility + actual data class Metadata internal actual constructor( + actual val semanticVersion: Triple + ) { + actual override fun toString() = buildString { + append("Metadata(semanticVersion=\"") + append(semanticVersion.first) + append('.') + append(semanticVersion.second) + append('.') + append(semanticVersion.third) + append("\")") + } + } } diff --git a/ktreesitter/src/nativeMain/kotlin/io/github/treesitter/ktreesitter/LookaheadIterator.kt b/ktreesitter/src/nativeMain/kotlin/io/github/treesitter/ktreesitter/LookaheadIterator.kt index 1b1c8ec..b542d5e 100644 --- a/ktreesitter/src/nativeMain/kotlin/io/github/treesitter/ktreesitter/LookaheadIterator.kt +++ b/ktreesitter/src/nativeMain/kotlin/io/github/treesitter/ktreesitter/LookaheadIterator.kt @@ -79,7 +79,7 @@ actual class LookaheadIterator @Throws(IllegalArgumentException::class) internal } } - override fun computeNext() = if (ts_lookahead_iterator_next(self)) { + actual override fun computeNext() = if (ts_lookahead_iterator_next(self)) { val id = ts_lookahead_iterator_current_symbol(self) val name = ts_lookahead_iterator_current_symbol_name(self) setNext(Symbol(id, name!!.toKString())) diff --git a/ktreesitter/src/nativeMain/kotlin/io/github/treesitter/ktreesitter/Node.kt b/ktreesitter/src/nativeMain/kotlin/io/github/treesitter/ktreesitter/Node.kt index 9300596..c5b5f8a 100644 --- a/ktreesitter/src/nativeMain/kotlin/io/github/treesitter/ktreesitter/Node.kt +++ b/ktreesitter/src/nativeMain/kotlin/io/github/treesitter/ktreesitter/Node.kt @@ -212,6 +212,24 @@ actual class Node internal constructor( throw IndexOutOfBoundsException("Child index $index is out of bounds") } + /** + * Get the node's first child that contains + * or starts after the given byte offset. + * + * @since 0.25.0 + */ + actual fun firstChildForByte(byte: UInt) = + ts_node_first_child_for_byte(self, byte).convert(tree) + + /** + * Get the node's first _named_ child that contains + * or starts after the given byte offset. + * + * @since 0.25.0 + */ + actual fun firstNamedChildForByte(byte: UInt) = + ts_node_first_named_child_for_byte(self, byte).convert(tree) + /** * Get the node's child with the given field ID, if any. * @@ -268,14 +286,6 @@ actual class Node internal constructor( throw IndexOutOfBoundsException("Child index $index is out of bounds") } - /** Get the child of the node that contains the given descendant, if any. */ - @Deprecated( - "This method will not return a direct descendant", - ReplaceWith("childWithDescendant(descendant)", "io.github.treesitter.ktreesitter.Node") - ) - actual fun childContainingDescendant(descendant: Node) = - ts_node_child_containing_descendant(self, descendant.self).convert(tree) - /** * Get the node that contains the given descendant, if any. * diff --git a/ktreesitter/src/nativeMain/kotlin/io/github/treesitter/ktreesitter/Parser.kt b/ktreesitter/src/nativeMain/kotlin/io/github/treesitter/ktreesitter/Parser.kt index 654707b..c2fdd04 100644 --- a/ktreesitter/src/nativeMain/kotlin/io/github/treesitter/ktreesitter/Parser.kt +++ b/ktreesitter/src/nativeMain/kotlin/io/github/treesitter/ktreesitter/Parser.kt @@ -69,6 +69,7 @@ actual class Parser actual constructor() { * The maximum duration in microseconds that parsing * should be allowed to take before halting. */ + @Deprecated("Use the progressCallback in parse()") actual var timeoutMicros: ULong get() = ts_parser_timeout_micros(self) set(value) = ts_parser_set_timeout_micros(self, value) @@ -106,19 +107,19 @@ actual class Parser actual constructor() { * [Tree.edit] method in a way that exactly matches the source code changes. * * @throws [IllegalStateException] - * If the parser does not have a [language] assigned or - * if parsing was canceled due to a [timeout][timeoutMicros]. + * If the parser does not have a [language] assigned or if parsing was halted. */ @Throws(IllegalStateException::class) - actual fun parse(source: String, oldTree: Tree?): Tree { + actual fun parse(source: String, encoding: InputEncoding, oldTree: Tree?): Tree { val language = checkNotNull(language) { "The parser has no language assigned" } - val tree = ts_parser_parse_string( + val tree = ts_parser_parse_string_encoding( self, oldTree?.self, source, - source.length.convert() + source.length.convert(), + encoding.value ) checkNotNull(tree) { "Parsing failed" } return Tree(tree, source, language) @@ -134,19 +135,23 @@ actual class Parser actual constructor() { * [Tree.edit] method in a way that exactly matches the source code changes. * * @throws [IllegalStateException] - * If the parser does not have a [language] assigned or - * if parsing was cancelled due to a [timeout][timeoutMicros]. + * If the parser does not have a [language] assigned or if parsing was halted. */ @Throws(IllegalStateException::class) - actual fun parse(oldTree: Tree?, callback: ParseCallback): Tree { + actual fun parse( + encoding: InputEncoding, + oldTree: Tree?, + progressCallback: ParseProgressCallback?, + readCallback: ParseReadCallback + ): Tree { val language = checkNotNull(language) { "The parser has no language assigned" } val arena = Arena() - val payloadRef = StableRef.create(ParsePayload(arena, callback)) + val payloadRef = StableRef.create(ParsePayload(arena, readCallback)) val input = cValue { payload = payloadRef.asCPointer() - encoding = TSInputEncodingUTF8 + this.encoding = encoding.value read = staticCFunction { payload, index, point, bytes -> val data = payload!!.asStableRef().get() val result = data.callback(index, point.useContents { convert() }) @@ -154,9 +159,24 @@ actual class Parser actual constructor() { result?.toString()?.cstr?.getPointer(data.memScope) } } - val tree = ts_parser_parse(self, oldTree?.self, input) + var progressRef: StableRef? = null + val tree = if (progressCallback == null) { + ts_parser_parse(self, oldTree?.self, input) + } else { + progressRef = StableRef.create(progressCallback) + val options = cValue { + payload = progressRef.asCPointer() + progress_callback = staticCFunction { state -> + val callback = state!!.pointed.payload!! + .asStableRef().get() + callback(state.pointed.current_byte_offset, state.pointed.has_error) + } + } + ts_parser_parse_with_options(self, oldTree?.self, input, options) + } arena.clear() payloadRef.dispose() + progressRef?.dispose() checkNotNull(tree) { "Parsing failed" } return Tree(tree, null, language) } @@ -164,10 +184,9 @@ actual class Parser actual constructor() { /** * Instruct the parser to start the next [parse] from the beginning. * - * If the parser previously failed because of a [timeout][timeoutMicros], - * then by default, it will resume where it left off. If you don't - * want to resume, and instead intend to use this parser to parse - * some other document, you must call this method first. + * If parsing was previously halted, then by default, it will resume where + * it left off. If you don't want to resume, and instead intend to use this + * parser to parse some other document, you must call this method first. */ actual fun reset() = ts_parser_reset(self) @@ -178,11 +197,11 @@ actual class Parser actual constructor() { private class ParsePayload( val memScope: AutofreeScope, - val callback: ParseCallback + val callback: ParseReadCallback ) private companion object { - private inline fun freeLogger(logger: CValue) { + private fun freeLogger(logger: CValue) { val arena = Arena() interpretNullablePointed( arena.alloc(logger.size, logger.align).rawPtr diff --git a/ktreesitter/src/nativeMain/kotlin/io/github/treesitter/ktreesitter/Query.kt b/ktreesitter/src/nativeMain/kotlin/io/github/treesitter/ktreesitter/Query.kt index bd860de..10b8891 100644 --- a/ktreesitter/src/nativeMain/kotlin/io/github/treesitter/ktreesitter/Query.kt +++ b/ktreesitter/src/nativeMain/kotlin/io/github/treesitter/ktreesitter/Query.kt @@ -1,7 +1,5 @@ package io.github.treesitter.ktreesitter -import cnames.structs.TSQuery -import cnames.structs.TSQueryCursor import io.github.treesitter.ktreesitter.internal.* import kotlin.experimental.ExperimentalNativeApi import kotlin.native.ref.createCleaner @@ -20,109 +18,55 @@ actual class Query @Throws(QueryError::class) actual constructor( private val language: Language, private val source: String ) { - private val self: CPointer - - private val cursor: CPointer - - private val captureNames: MutableList - - private val predicates: List> - - private val settings: List> - - private val assertions: List>> + internal val self = init(language, source) /** The number of patterns in the query. */ - actual val patternCount: UInt + actual val patternCount: UInt = ts_query_pattern_count(self) /** The number of captures in the query. */ + @Deprecated("captureCount is deprecated", ReplaceWith("captureNames.size")) actual val captureCount: UInt + get() = ts_query_capture_count(self) - init { - val arena = Arena() - val errorOffset = arena.alloc() - val errorType = arena.alloc() - val query = ts_query_new( - language.self, - source, - source.length.convert(), - errorOffset.ptr, - errorType.ptr - ) - - if (query == null) { - var start = 0U - var row = 0U - val offset = errorOffset.value - for (line in source.splitToSequence('\n')) { - val lineEnd = start + line.length.toUInt() + 1U - if (lineEnd > offset) break - start = lineEnd - row += 1U - } - val column = offset - start + internal val predicates = List(patternCount.toInt()) { mutableListOf() } - val exception = when (errorType.value) { - TSQueryError.TSQueryErrorSyntax -> { - if (offset < source.length.toUInt()) { - QueryError.Syntax(row.toLong(), column.toLong()) - } else { - QueryError.Syntax(-1, -1) - } - } - TSQueryError.TSQueryErrorCapture -> { - val suffix = source.subSequence(offset.toInt(), source.length) - val end = suffix.indexOfFirst { !kts_is_valid_predicate_char(it.code) } - val error = suffix.subSequence(0, end.takeIf { it > -1 } ?: suffix.length) - QueryError.Capture(row, column, error.toString()) - } - TSQueryError.TSQueryErrorNodeType -> { - val suffix = source.subSequence(offset.toInt(), source.length) - val end = suffix.indexOfFirst { !kts_is_valid_identifier_char(it.code) } - val error = suffix.subSequence(0, end.takeIf { it > -1 } ?: suffix.length) - QueryError.NodeType(row, column, error.toString()) - } - TSQueryError.TSQueryErrorField -> { - val suffix = source.subSequence(offset.toInt(), source.length) - val end = suffix.indexOfFirst { !kts_is_valid_identifier_char(it.code) } - val error = suffix.subSequence(0, end.takeIf { it > -1 } ?: suffix.length) - QueryError.Field(row, column, error.toString()) - } - TSQueryError.TSQueryErrorStructure -> QueryError.Structure(row, column) - // language errors are handled in the Language class - else -> IllegalStateException("Unexpected query error") - } - arena.clear() - throw exception - } - arena.clear() - - self = query - cursor = ts_query_cursor_new()!! - patternCount = ts_query_pattern_count(self) - captureCount = ts_query_capture_count(self) - predicates = List(patternCount.toInt()) { mutableListOf() } - settings = List(patternCount.toInt()) { mutableMapOf() } - assertions = List(patternCount.toInt()) { mutableMapOf() } - captureNames = MutableList(captureCount.toInt()) { - memScoped { - val length = alloc() - val name = ts_query_capture_name_for_id(self, it.convert(), length.ptr) - if (name == null || length.value == 0U) - error("Failed to get capture name at index $it") - name.toKString() - } + private val settings = List(patternCount.toInt()) { mutableMapOf() } + + private val assertions = List(patternCount.toInt()) { + mutableMapOf>() + } + + /** + * The capture names used in the query. + * + * @since 0.25.0 + */ + actual val captureNames = List(ts_query_capture_count(self).convert()) { + memScoped { + val length = alloc() + val name = ts_query_capture_name_for_id(self, it.convert(), length.ptr) + if (name == null || length.value == 0U) + error("Failed to get capture name at index $it") + name.toKString() } - val stringValues = List(ts_query_string_count(self).convert()) { - memScoped { - val length = alloc() - val value = ts_query_string_value_for_id(self, it.convert(), length.ptr) - if (value == null || length.value == 0U) - error("Failed to get string value at index $it") - value.toKString() - } + } + + /** + * The string literals used in the query. + * + * @since 0.25.0 + */ + actual val stringValues = List(ts_query_string_count(self).convert()) { + memScoped { + val length = alloc() + val value = ts_query_string_value_for_id(self, it.convert(), length.ptr) + if (value == null || length.value == 0U) + error("Failed to get string value at index $it") + value.toKString() } + } + init { for (i in 0U.. 0U) { "The match limit cannot be 0" } - ts_query_cursor_set_match_limit(cursor, value) - } - - /** - * The maximum start depth for the query. - * - * This prevents cursors from exploring children nodes at a certain depth. - * Note that if a pattern includes many children, then they will still be checked. - * - * Default: `UInt.MAX_VALUE` - */ - actual var maxStartDepth: UInt = UInt.MAX_VALUE - set(value) { - ts_query_cursor_set_max_start_depth(cursor, value) - field = value - } - - /** - * The range of bytes in which the query will be executed. - * - * Default: `UInt.MIN_VALUE..UInt.MAX_VALUE` - */ - actual var byteRange: UIntRange = UInt.MIN_VALUE..UInt.MAX_VALUE - set(value) { - ts_query_cursor_set_byte_range(cursor, value.first, value.last) - field = value - } - - /** - * The range of points in which the query will be executed. - * - * Default: `Point.MIN..Point.MAX` - */ - actual var pointRange: ClosedRange = Point.MIN..Point.MAX - set(value) { - val start = cValue { from(value.start) } - val end = cValue { from(value.endInclusive) } - ts_query_cursor_set_point_range(cursor, start, end) - field = value - } - - /** - * Check if the query exceeded its maximum number of - * in-progress matches during its last execution. - */ - actual val didExceedMatchLimit: Boolean - get() = ts_query_cursor_did_exceed_match_limit(cursor) - - /** - * Iterate over all the matches in the order that they were found. - * - * #### Example - * - * ```kotlin - * query.matches(tree.rootNode) { - * if (name != "ieq?") return@matches true - * val node = it[(args[0] as QueryPredicateArg.Capture).value].first() - * val value = (args[1] as QueryPredicateArg.Literal).value - * value.equals(node.text()?.toString(), ignoreCase = true) - * } - * ``` - * - * @param node The node that the query will run on. - * @param predicate A function that handles custom predicates. - */ - @Suppress("ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS") - actual fun matches( - node: Node, - predicate: QueryPredicate.(QueryMatch) -> Boolean = { true } - ): Sequence { - ts_query_cursor_exec(cursor, self, node.self) - return sequence { - memScoped { - val match = alloc() - while (ts_query_cursor_next_match(cursor, match.ptr)) { - match.convert(node.tree, predicate)?.let { yield(it) } - } - } - } - } - - /** - * Iterate over all the individual captures in the order that they appear. - * - * This is useful if you don't care about _which_ pattern matched. - * - * @param node The node that the query will run on. - * @param predicate A function that handles custom predicates. - */ - @Suppress("ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS") - actual fun captures( - node: Node, - predicate: QueryPredicate.(QueryMatch) -> Boolean = { true } - ): Sequence> { - ts_query_cursor_exec(cursor, self, node.self) - return sequence { - memScoped { - val match = alloc() - val index = alloc() - while (ts_query_cursor_next_capture(cursor, match.ptr, index.ptr)) { - match.convert(node.tree, predicate)?.let { yield(index.value to it) } - } - } - } - } + actual operator fun invoke(node: Node, progressCallback: QueryProgressCallback?) = + QueryCursor(this, node, progressCallback) /** * Get the property settings for the given pattern index. @@ -535,13 +352,8 @@ actual class Query @Throws(QueryError::class) actual constructor( * This prevents the capture from being returned in matches, * and also avoids most resource usage associated with recording * the capture. Currently, there is no way to undo this. - * - * @throws [NoSuchElementException] If the capture does not exist. */ - @Throws(NoSuchElementException::class) actual fun disableCapture(name: String) { - if (!captureNames.remove(name)) - throw NoSuchElementException("Capture @$name does not exist") ts_query_disable_capture(self, name, name.length.convert()) } @@ -617,25 +429,65 @@ actual class Query @Throws(QueryError::class) actual constructor( override fun toString() = "Query(language=$language, source=$source)" - private fun TSQueryMatch.convert( - tree: Tree, - predicate: QueryPredicate.(QueryMatch) -> Boolean - ): QueryMatch? { - val index = pattern_index.convert() - val captures = (UShort.MIN_VALUE..()] - QueryCapture( - Node(c.node.readValue(), tree), - this@Query.captureNames[c.index] + private companion object { + private fun init(language: Language, source: String) = memScoped { + val errorOffset = alloc() + val errorType = alloc() + val query = ts_query_new( + language.self, + source, + source.length.convert(), + errorOffset.ptr, + errorType.ptr ) - } - return QueryMatch(index, captures).takeIf { match -> - tree.text() == null || - predicates[index].all { - if (it !is QueryPredicate.Generic) it(match) else predicate(it, match) + if (query != null) + return@memScoped query + + var start = 0U + var row = 0U + val offset = errorOffset.value + for (line in source.splitToSequence('\n')) { + val lineEnd = start + line.length.toUInt() + 1U + if (lineEnd > offset) break + start = lineEnd + row += 1U + } + val column = offset - start + + val exception = when (errorType.value) { + TSQueryError.TSQueryErrorSyntax -> { + if (offset < source.length.toUInt()) { + QueryError.Syntax(row.toLong(), column.toLong()) + } else { + QueryError.Syntax(-1, -1) + } + } + TSQueryError.TSQueryErrorCapture -> { + val suffix = source.subSequence(offset.toInt(), source.length) + val end = suffix.indexOfFirst { !kts_is_valid_predicate_char(it.code) } + val error = suffix.subSequence(0, end.takeIf { it > -1 } ?: suffix.length) + QueryError.Capture(row, column, error.toString()) } + TSQueryError.TSQueryErrorNodeType -> { + val suffix = source.subSequence(offset.toInt(), source.length) + val end = suffix.indexOfFirst { !kts_is_valid_identifier_char(it.code) } + val error = suffix.subSequence(0, end.takeIf { it > -1 } ?: suffix.length) + QueryError.NodeType(row, column, error.toString()) + } + TSQueryError.TSQueryErrorField -> { + val suffix = source.subSequence(offset.toInt(), source.length) + val end = suffix.indexOfFirst { !kts_is_valid_identifier_char(it.code) } + val error = suffix.subSequence(0, end.takeIf { it > -1 } ?: suffix.length) + QueryError.Field(row, column, error.toString()) + } + TSQueryError.TSQueryErrorStructure -> QueryError.Structure(row, column) + // language errors are handled in the Language class + else -> IllegalStateException("Unexpected query error") + } + throw exception } - } - private inline operator fun List.get(index: UInt) = get(index.toInt()) + @Suppress("NOTHING_TO_INLINE") + private inline operator fun List.get(index: UInt) = get(index.toInt()) + } } diff --git a/ktreesitter/src/nativeMain/kotlin/io/github/treesitter/ktreesitter/QueryCursor.kt b/ktreesitter/src/nativeMain/kotlin/io/github/treesitter/ktreesitter/QueryCursor.kt new file mode 100644 index 0000000..34c06de --- /dev/null +++ b/ktreesitter/src/nativeMain/kotlin/io/github/treesitter/ktreesitter/QueryCursor.kt @@ -0,0 +1,200 @@ +package io.github.treesitter.ktreesitter + +import io.github.treesitter.ktreesitter.internal.* +import kotlin.experimental.ExperimentalNativeApi +import kotlin.native.ref.createCleaner +import kotlinx.cinterop.* + +/** + * A class that is used for executing a query. + * + * @since 0.25.0 + */ +@OptIn(ExperimentalForeignApi::class) +actual class QueryCursor internal constructor( + private val query: Query, + private val node: Node, + progressCallback: QueryProgressCallback? = null +) { + internal val self = ts_query_cursor_new()!! + + init { + if (progressCallback == null) { + ts_query_cursor_exec(self, query.self, node.self) + } else { + val progressRef = StableRef.create(progressCallback) + val options = cValue { + payload = progressRef.asCPointer() + progress_callback = staticCFunction { state -> + val callback = state!!.pointed.payload!! + .asStableRef().get() + callback(state.pointed.current_byte_offset) + } + } + ts_query_cursor_exec_with_options(self, query.self, node.self, options) + progressRef.dispose() + } + } + + @Suppress("unused") + @OptIn(ExperimentalNativeApi::class) + private val cleaner = createCleaner(self, ::ts_query_cursor_delete) + + /** + * The maximum duration in microseconds that query + * execution should be allowed to take before halting. + * + * Default: `0` + * + * @since 0.23.0 + */ + @Deprecated("Use the progressCallback in Query.invoke()") + actual var timeoutMicros: ULong + get() = ts_query_cursor_timeout_micros(self) + set(value) { + ts_query_cursor_set_timeout_micros(self, value) + } + + /** + * The maximum number of in-progress matches. + * + * Default: `UInt.MAX_VALUE` + * + * @throws [IllegalArgumentException] If the match limit is set to `0`. + */ + actual var matchLimit: UInt + get() = ts_query_cursor_match_limit(self) + set(value) { + require(value > 0U) { "The match limit cannot be 0" } + ts_query_cursor_set_match_limit(self, value) + } + + /** + * The maximum start depth for the query. + * + * This prevents cursors from exploring children nodes at a certain depth. + * Note that if a pattern includes many children, then they will still be checked. + * + * Default: `UInt.MAX_VALUE` + */ + actual var maxStartDepth: UInt = UInt.MAX_VALUE + set(value) { + ts_query_cursor_set_max_start_depth(self, value) + field = value + } + + /** + * The range of bytes in which the query will be executed. + * + * The query cursor will return matches that intersect with + * the given range. This means that a match may be returned + * even if some of its captures fall outside the specified range, + * as long as at least part of the match overlaps with the range. + * + * Default: `UInt.MIN_VALUE..UInt.MAX_VALUE` + * + * @throws [IllegalArgumentException] If set to an invalid range. + */ + actual var byteRange: UIntRange = UInt.MIN_VALUE..UInt.MAX_VALUE + set(value) { + require(ts_query_cursor_set_byte_range(self, value.first, value.last)) { + "Invalid byte range: [${value.first}, ${value.last}]" + } + field = value + } + + /** + * The range of points in which the query will be executed. + * + * The query cursor will return matches that intersect with + * the given range. This means that a match may be returned + * even if some of its captures fall outside the specified range, + * as long as at least part of the match overlaps with the range. + * + * Default: `Point.MIN..Point.MAX` + * + * @throws [IllegalArgumentException] If set to an invalid range. + */ + actual var pointRange: ClosedRange = Point.MIN..Point.MAX + set(value) { + val start = cValue { from(value.start) } + val end = cValue { from(value.endInclusive) } + require(ts_query_cursor_set_point_range(self, start, end)) { + "Invalid point range: [${value.start}, ${value.endInclusive}]" + } + field = value + } + + /** + * Check if the query exceeded its maximum number of + * in-progress matches during its last execution. + * + * @see matchLimit + */ + actual val didExceedMatchLimit: Boolean + get() = ts_query_cursor_did_exceed_match_limit(self) + + /** + * Iterate over all the matches in the order that they were found. + * + * #### Example + * + * ```kotlin + * query(tree.rootNode).matches { + * if (name != "ieq?") return@matches true + * val node = it[(args[0] as QueryPredicateArg.Capture).value].first() + * val value = (args[1] as QueryPredicateArg.Literal).value + * value.equals(node.text()?.toString(), ignoreCase = true) + * } + * ``` + * + * @param predicate A function that handles custom predicates. + */ + actual fun matches(predicate: QueryPredicate.(QueryMatch) -> Boolean) = sequence { + memScoped { + val match = alloc() + while (ts_query_cursor_next_match(self, match.ptr)) { + match.convert(predicate)?.let { yield(it) } + } + } + } + + /** + * Iterate over all the individual captures in the order that they appear. + * + * This is useful if you don't care about _which_ pattern matched. + * + * @param predicate A function that handles custom predicates. + */ + actual fun captures(predicate: QueryPredicate.(QueryMatch) -> Boolean) = + sequence> { + memScoped { + val match = alloc() + val index = alloc() + while (ts_query_cursor_next_capture(self, match.ptr, index.ptr)) { + match.convert(predicate)?.let { yield(index.value to it) } + } + } + } + + override fun toString() = "QueryCursor(query=$query, node=$node)" + + private fun TSQueryMatch.convert( + predicate: QueryPredicate.(QueryMatch) -> Boolean + ): QueryMatch? { + val index = pattern_index.convert() + val captures = (UShort.MIN_VALUE..()] + QueryCapture( + Node(c.node.readValue(), node.tree), + query.captureNames[c.index.toInt()] + ) + } + return QueryMatch(index, captures).takeIf { match -> + node.tree.text() == null || + query.predicates[index.toInt()].all { + if (it !is QueryPredicate.Generic) it(match) else predicate(it, match) + } + } + } +} diff --git a/ktreesitter/src/nativeMain/kotlin/io/github/treesitter/ktreesitter/Utils.kt b/ktreesitter/src/nativeMain/kotlin/io/github/treesitter/ktreesitter/Utils.kt index 44e3fc7..79d640b 100644 --- a/ktreesitter/src/nativeMain/kotlin/io/github/treesitter/ktreesitter/Utils.kt +++ b/ktreesitter/src/nativeMain/kotlin/io/github/treesitter/ktreesitter/Utils.kt @@ -1,3 +1,5 @@ +@file:Suppress("NOTHING_TO_INLINE") + package io.github.treesitter.ktreesitter import io.github.treesitter.ktreesitter.internal.* diff --git a/languages/java/build.gradle.kts b/languages/java/build.gradle.kts index e90ae26..3243130 100644 --- a/languages/java/build.gradle.kts +++ b/languages/java/build.gradle.kts @@ -2,12 +2,23 @@ import java.io.OutputStream.nullOutputStream import org.gradle.internal.os.OperatingSystem import org.gradle.kotlin.dsl.support.useToRun import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi +import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget import org.jetbrains.kotlin.gradle.tasks.CInteropProcess -import org.jetbrains.kotlin.konan.target.PlatformManager inline val File.unixPath: String get() = if (!os.isWindows) path else path.replace("\\", "/") +fun KotlinNativeTarget.treesitterJava() { + compilations.configureEach { + cinterops.create("treesitterJava") { + definitionFile.set(generateTask.interopFile) + includeDirs.allHeaders(grammarDir.resolve("bindings/c")) + extraOpts("-libraryPath", libsDir.dir(konanTarget.name)) + tasks.getByName(interopProcessingTaskName).mustRunAfter(generateTask) + } + } +} + val os: OperatingSystem = OperatingSystem.current() val libsDir = layout.buildDirectory.get().dir("libs") val grammarDir = projectDir.resolve("tree-sitter-java") @@ -28,10 +39,6 @@ grammar { grammarName = project.name className = "TreeSitterJava" packageName = "io.github.treesitter.ktreesitter.java" - files = arrayOf( - // grammarDir.resolve("src/scanner.c"), - grammarDir.resolve("src/parser.c") - ) } val generateTask = tasks.generateGrammarFiles.get() @@ -44,29 +51,15 @@ kotlin { publishLibraryVariants("release") } - when { - os.isLinux -> listOf(linuxX64(), linuxArm64()) - os.isWindows -> listOf(mingwX64()) - os.isMacOsX -> listOf( - macosArm64(), - macosX64(), - iosArm64(), - iosSimulatorArm64() - ) - else -> { - val arch = System.getProperty("os.arch") - throw GradleException("Unsupported platform: $os ($arch)") - } - }.forEach { target -> - target.compilations.configureEach { - cinterops.create(grammar.interopName.get()) { - defFileProperty.set(generateTask.interopFile.asFile) - includeDirs.allHeaders(grammarDir.resolve("bindings/c")) - extraOpts("-libraryPath", libsDir.dir(konanTarget.name)) - tasks.getByName(interopProcessingTaskName).mustRunAfter(generateTask) - } - } - } + linuxX64 { treesitterJava() } + linuxArm64 { treesitterJava() } + mingwX64 { treesitterJava() } + macosArm64 { treesitterJava() } + macosX64 { treesitterJava() } + iosArm64 { treesitterJava() } + iosSimulatorArm64 { treesitterJava() } + + applyDefaultHierarchyTemplate() jvmToolchain(17) @@ -102,7 +95,6 @@ android { defaultConfig { minSdk = (property("sdk.version.min") as String).toInt() ndk { - moduleName = grammar.libraryName.get() //noinspection ChromeOsAbiSupport abiFilters += setOf("x86_64", "arm64-v8a", "armeabi-v7a") } @@ -121,26 +113,28 @@ android { } } +// TODO: replace with cmake +@Suppress("DEPRECATION") tasks.withType().configureEach { if (name.startsWith("cinteropTest")) return@configureEach - val grammarFiles = grammar.files.get() + val srcDir = grammarDir.resolve("src") + val grammarFiles = + if (!srcDir.resolve("scanner.c").isFile) arrayOf(srcDir.resolve("parser.c")) + else arrayOf(srcDir.resolve("parser.c"), srcDir.resolve("scanner.c")) val grammarName = grammar.grammarName.get() val runKonan = File(konanHome.get()).resolve("bin") .resolve(if (os.isWindows) "run_konan.bat" else "run_konan").path val libFile = libsDir.dir(konanTarget.name).file("libtree-sitter-$grammarName.a").asFile val objectFiles = grammarFiles.map { - grammarDir.resolve(it.nameWithoutExtension + ".o").path + srcDir.resolve(it.nameWithoutExtension + ".o").path }.toTypedArray() - val loader = PlatformManager(konanHome.get(), false, konanDataDir.orNull).loader(konanTarget) doFirst { - if (!File(loader.absoluteTargetToolchain).isDirectory) loader.downloadDependencies() - val argsFile = File.createTempFile("args", null) argsFile.deleteOnExit() argsFile.writer().useToRun { - write("-I" + grammarDir.resolve("src").unixPath + "\n") + write("-I" + srcDir.unixPath + "\n") write("-DTREE_SITTER_HIDE_SYMBOLS\n") write("-fvisibility=hidden\n") write("-std=c11\n") diff --git a/languages/java/tree-sitter-java b/languages/java/tree-sitter-java index 94703d5..a7db522 160000 --- a/languages/java/tree-sitter-java +++ b/languages/java/tree-sitter-java @@ -1 +1 @@ -Subproject commit 94703d5a6bed02b98e438d7cad1136c01a60ba2c +Subproject commit a7db5227ec40fcfe94489559d8c9bc7c8181e25a diff --git a/tree-sitter b/tree-sitter index 5e8760b..4fcf78c 160000 --- a/tree-sitter +++ b/tree-sitter @@ -1 +1 @@ -Subproject commit 5e8760bf462ce7b19b3d2396d5b7860f3906a297 +Subproject commit 4fcf78cfec32532b5e74e21cbb135b25127444eb