Skip to content

Commit

Permalink
more wip
Browse files Browse the repository at this point in the history
  • Loading branch information
kubukoz committed Oct 30, 2024
1 parent df755d6 commit b296bb0
Show file tree
Hide file tree
Showing 6 changed files with 65 additions and 36 deletions.
2 changes: 1 addition & 1 deletion build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ lazy val core = crossProject(JVMPlatform)
.jvmSettings(
commonJVMSettings,
libraryDependencies ++= Seq(
"net.java.dev.jna" % "jna" % "5.14.0"
"net.java.dev.jna" % "jna" % "5.15.0"
),
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ import com.sun.jna.*
import org.polyvariant.treesitter4s.internal.TreeSitterLibrary

import java.util.concurrent.ConcurrentHashMap
import scala.jdk.CollectionConverters.*
import java.io.Closeable

object TreeSitterPlatform {

Expand All @@ -33,7 +35,7 @@ object TreeSitterPlatform {
case e: UnsatisfiedLinkError => throw new Exception("Couldn't load tree-sitter", e)
}

val instance: TreeSitter =
def instance(): TreeSitter =
new TreeSitter {
type Parser = TreeSitterLibrary.Parser
type Tree = TreeSitterLibrary.Tree
Expand All @@ -43,24 +45,42 @@ object TreeSitterPlatform {
val NullTree: Tree = null
}

type Language = org.polyvariant.treesitter4s.Language
trait CC extends Closeable {
def lang: org.polyvariant.treesitter4s.Language
}

private val languageMap = new ConcurrentHashMap[String, Language]
type Language = CC

/* private */
// val languages = new ConcurrentHashMap[String, (NativeLibrary, Language)]

// def close(): Unit = {
// languages.values().asScala.foreach(_._1.close())
// languages.clear()
// }
def close(): Unit = ()

val Language: LanguageMethods =
new {

def apply(
languageName: String
): Language = languageMap.computeIfAbsent(
languageName,
_ => {
val library = NativeLibrary.getInstance("tree-sitter-python")
): Language = {
val library = NativeLibrary.getInstance(s"tree-sitter-$languageName")

val function = library.getFunction(s"tree_sitter_$languageName");

val langg = function
.invoke(classOf[org.polyvariant.treesitter4s.Language], Array())
.asInstanceOf[org.polyvariant.treesitter4s.Language]

val function = library.getFunction("tree_sitter_python");
function.invoke(classOf[Language], Array()).asInstanceOf[Language]
},
)
// We need to keep all references to the libraries in a map
// otherwise they get GC'd and the app segfaults! Fun times.
new CC {
def lang: org.polyvariant.treesitter4s.Language = langg
def close() = library.close()
}
}

}

Expand All @@ -72,7 +92,7 @@ object TreeSitterPlatform {
def tsParserSetLanguage(
parser: Parser,
language: Language,
): Boolean = LIBRARY.ts_parser_set_language(parser, language)
): Boolean = LIBRARY.ts_parser_set_language(parser, language.lang)

def tsParserParseString(
parser: Parser,
Expand All @@ -83,9 +103,9 @@ object TreeSitterPlatform {

def tsLanguageSymbolCount(
language: Language
): Long = LIBRARY.ts_language_symbol_count(language)
): Long = LIBRARY.ts_language_symbol_count(language.lang)

def tsLanguageVersion(language: Language): Long = LIBRARY.ts_language_version(language)
def tsLanguageVersion(language: Language): Long = LIBRARY.ts_language_version(language.lang)

def tsNodeChild(node: Node, index: Long): Node = LIBRARY.ts_node_child(node, index)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ package org.polyvariant.treesitter4s

import org.polyvariant.treesitter4s.lowlevel.TreeSitter

import scala.util.Using

// High-level Tree Sitter API.
// For the lower-level one, see TreeSitter in the lowlevel package.
trait TreeSitterAPI {
Expand All @@ -28,11 +30,15 @@ trait TreeSitterAPI {

object TreeSitterAPI {

def make(language: (ts: TreeSitter) => ts.Language): TreeSitterAPI = {
val ts = TreeSitter.instance

internal.Facade.make(ts, language(ts))
}
// hm what's interesting is that the committed version segfaults on
// a different function (ts_node_string) and here we crash at ts_parser_set_language.
// strange things
def make(language: (ts: TreeSitter) => ts.Language): TreeSitterAPI =
Using.resource(TreeSitter.instance()) { ts =>
Using.resource(language(ts)) { lang =>
internal.Facade.make(ts, lang)
}
}

}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@

package org.polyvariant.treesitter4s.internal

import org.polyvariant.treesitter4s.lowlevel.TreeSitter
import org.polyvariant.treesitter4s.TreeSitterAPI
import org.polyvariant.treesitter4s.Tree
import org.polyvariant.treesitter4s.Node
import org.polyvariant.treesitter4s.Tree
import org.polyvariant.treesitter4s.TreeSitterAPI
import org.polyvariant.treesitter4s.lowlevel.TreeSitter

private[treesitter4s] object Facade {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@

package org.polyvariant.treesitter4s.lowlevel

trait TreeSitter {
import java.io.Closeable

trait TreeSitter extends AutoCloseable {
type Parser
type Tree

Expand All @@ -26,7 +28,7 @@ trait TreeSitter {

val Tree: TreeMethods

type Language
type Language <: Closeable

trait LanguageMethods {
def apply(libraryName: String): Language
Expand Down Expand Up @@ -57,5 +59,6 @@ trait TreeSitter {
}

object TreeSitter {
val instance: TreeSitter = TreeSitterPlatform.instance
// remember to close!
def instance(): TreeSitter = TreeSitterPlatform.instance()
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,20 +33,20 @@ object BindingTests extends FunSuite {
assert.eql(rootNode.map(_.children.length), Some(2))
}

// test("root node child type") {
// val tree = parseExample("class Hello {}")
// val rootNode = tree.rootNode
test("root node child type") {
val tree = parseExample("class Hello {}")
val rootNode = tree.rootNode

// assert.eql(rootNode.map(_.tpe), Some("compilation_unit"))
// }
assert.eql(rootNode.map(_.tpe), Some("compilation_unit"))
}

// test("root node child by index (in range)") {
// val tree = parseExample("class Hello {}")
test("root node child by index (in range)") {
val tree = parseExample("class Hello {}")

// val rootNode = tree.rootNode.getOrElse(sys.error("missing root node"))
val rootNode = tree.rootNode.getOrElse(sys.error("missing root node"))

// assert.eql(rootNode.children.lift(0).isDefined, true)
// }
assert.eql(rootNode.children.lift(0).isDefined, true)
}

// test("root node child by index (out of range)") {
// val tree = parseExample("class Hello {}")
Expand Down

0 comments on commit b296bb0

Please sign in to comment.