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 908a42c..80672c8 100644 --- a/ktreesitter/src/androidInstrumentedTest/kotlin/io/github/treesitter/ktreesitter/LanguageTest.kt +++ b/ktreesitter/src/androidInstrumentedTest/kotlin/io/github/treesitter/ktreesitter/LanguageTest.kt @@ -77,7 +77,7 @@ class LanguageTest : FunSpec({ } test("equals()") { - Language(TreeSitterJava.language()) shouldBe Language(TreeSitterJava.language()) + Language(TreeSitterJava.language()) shouldBe language.copy() } test("hashCode()") { @@ -85,6 +85,6 @@ class LanguageTest : FunSpec({ } test("toString()") { - language.toString() shouldMatch Regex("""Language\(id=0x[0-9a-z]+, version=14\)""") + language.toString() shouldMatch Regex("""Language\(id=0x[0-9a-f]+, version=14\)""") } }) 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 b8f6bda..4000182 100644 --- a/ktreesitter/src/androidMain/kotlin/io/github/treesitter/ktreesitter/Language.kt +++ b/ktreesitter/src/androidMain/kotlin/io/github/treesitter/ktreesitter/Language.kt @@ -1,5 +1,6 @@ package io.github.treesitter.ktreesitter +import dalvik.annotation.optimization.CriticalNative import dalvik.annotation.optimization.FastNative /** @@ -41,6 +42,13 @@ actual class Language @Throws(IllegalArgumentException::class) actual constructo actual val fieldCount: UInt @FastNative external get + /** + * Get another reference to the language. + * + * @since 0.24.0 + */ + actual fun copy() = Language(copy(self)) + /** Get the node type for the given numerical ID. */ @FastNative @JvmName("symbolName") @@ -130,6 +138,10 @@ actual class Language @Throws(IllegalArgumentException::class) actual constructo private external fun checkVersion() private companion object { + @JvmStatic + @CriticalNative + private external fun copy(self: Long): Long + init { System.loadLibrary("ktreesitter") } 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 412e80d..297e6f7 100644 --- a/ktreesitter/src/commonMain/kotlin/io/github/treesitter/ktreesitter/Language.kt +++ b/ktreesitter/src/commonMain/kotlin/io/github/treesitter/ktreesitter/Language.kt @@ -22,6 +22,13 @@ expect class Language @Throws(IllegalArgumentException::class) constructor(langu /** The number of distinct field names in this language. */ val fieldCount: UInt + /** + * Get another reference to the language. + * + * @since 0.24.0 + */ + fun copy(): Language + /** Get the node type for the given numerical ID. */ fun symbolName(symbol: UShort): String? 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 91957df..dd36a8a 100644 --- a/ktreesitter/src/commonTest/kotlin/io/github/treesitter/ktreesitter/LanguageTest.kt +++ b/ktreesitter/src/commonTest/kotlin/io/github/treesitter/ktreesitter/LanguageTest.kt @@ -74,7 +74,7 @@ class LanguageTest : FunSpec({ } test("equals()") { - Language(TreeSitterJava.language()) shouldBe Language(TreeSitterJava.language()) + Language(TreeSitterJava.language()) shouldBe language.copy() } test("hashCode()") { @@ -82,6 +82,6 @@ class LanguageTest : FunSpec({ } test("toString()") { - language.toString() shouldMatch Regex("""Language\(id=0x[0-9a-z]+, version=14\)""") + language.toString() shouldMatch Regex("""Language\(id=0x[0-9a-f]+, version=14\)""") } }) diff --git a/ktreesitter/src/jni/language.c b/ktreesitter/src/jni/language.c index b177092..bc57e17 100644 --- a/ktreesitter/src/jni/language.c +++ b/ktreesitter/src/jni/language.c @@ -1,5 +1,9 @@ #include "utils.h" +jlong JNICALL language_copy CRITICAL_ARGS(jlong self) { + return (jlong)ts_language_copy((TSLanguage *)self); +} + jint JNICALL language_get_version(JNIEnv *env, jobject this) { TSLanguage *self = GET_POINTER(TSLanguage, this, Language_self); return (jint)ts_language_version(self); @@ -88,6 +92,7 @@ void JNICALL language_check_version(JNIEnv *env, jobject this) { } const JNINativeMethod Language_methods[] = { + {"copy", "(J)J", (void *)&language_copy}, {"getVersion", "()I", (void *)&language_get_version}, {"getSymbolCount", "()I", (void *)&language_get_symbol_count}, {"getStateCount", "()I", (void *)&language_get_state_count}, 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 3be87d7..4cc4037 100644 --- a/ktreesitter/src/jvmMain/kotlin/io/github/treesitter/ktreesitter/Language.kt +++ b/ktreesitter/src/jvmMain/kotlin/io/github/treesitter/ktreesitter/Language.kt @@ -39,6 +39,13 @@ actual class Language @Throws(IllegalArgumentException::class) actual constructo actual val fieldCount: UInt external get + /** + * Get another reference to the language. + * + * @since 0.24.0 + */ + actual fun copy() = Language(copy(self)) + /** Get the node type for the given numerical ID. */ @JvmName("symbolName") actual external fun symbolName(symbol: UShort): String? @@ -119,6 +126,9 @@ actual class Language @Throws(IllegalArgumentException::class) actual constructo private external fun checkVersion() private companion object { + @JvmStatic + private external fun copy(self: Long): Long + init { NativeUtils.loadLibrary() } 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 d76ba8a..56b7595 100644 --- a/ktreesitter/src/nativeMain/kotlin/io/github/treesitter/ktreesitter/Language.kt +++ b/ktreesitter/src/nativeMain/kotlin/io/github/treesitter/ktreesitter/Language.kt @@ -9,16 +9,22 @@ import kotlinx.cinterop.* * * When a [Language] is generated by the Tree-sitter CLI, it is assigned * an ABI [version] number that corresponds to the current CLI version. - * - * @constructor Create a new instance from the given language pointer. - * @param language A [CPointer] to a `TSLanguage`. - * @throws [IllegalArgumentException] If the pointer is invalid or the [version] is incompatible. */ -@OptIn(ExperimentalForeignApi::class) -actual class Language @Throws(IllegalArgumentException::class) actual constructor(language: Any) { - internal val self: CPointer = +@OptIn(ExperimentalForeignApi::class) actual class Language internal constructor( + internal val self: CPointer +) { + /** + * Create a new instance from the given language pointer. + * + * @param language A [CPointer] to a `TSLanguage`. + * @throws [IllegalArgumentException] + * If the pointer is invalid or the [version] is incompatible. + */ + @Throws(IllegalArgumentException::class) + actual constructor(language: Any) : this( (language as? CPointer<*>)?.rawValue?.let(::interpretCPointer) ?: throw IllegalArgumentException("Invalid language: $language") + ) /** The ABI version number for this language. */ actual val version: UInt = ts_language_version(self) @@ -39,6 +45,13 @@ actual class Language @Throws(IllegalArgumentException::class) actual constructo /** The number of distinct field names in this language. */ actual val fieldCount: UInt = ts_language_field_count(self) + /** + * Get another reference to the language. + * + * @since 0.24.0 + */ + actual fun copy() = Language(ts_language_copy(self)!!) + /** Get the node type for the given numerical ID. */ actual fun symbolName(symbol: UShort) = ts_language_symbol_name(self, symbol)?.toKString() @@ -93,8 +106,9 @@ actual class Language @Throws(IllegalArgumentException::class) actual constructo * * @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 @@ -102,8 +116,7 @@ actual class Language @Throws(IllegalArgumentException::class) actual constructo * * @throws [QueryError] If any error occurred while creating the query. */ - @Throws(QueryError::class) - actual fun query(source: String) = Query(this, source) + @Throws(QueryError::class) actual fun query(source: String) = Query(this, source) actual override fun equals(other: Any?) = this === other || (other is Language && self == other.self)