Skip to content

Commit 356a15a

Browse files
committed
Support customizing SymbolLookup for tree-sitter native library
Motivation: - Enable clients to customize the SymbolLookup used for the tree-sitter native library. For example, clients can use this capability to embed the tree-sitter native library in their JAR, which is a common way to solve the native library distribution problem. Changes: - Add interface NativeLibraryLookup. - Add class ChainedLibraryLookup, which loads NativeLibraryLookup implementations using java.util.ServiceLoader and chains the SymbolLookup's returned by them. - Change TreeSitter.java patch to delegate to ChainedLibraryLookup. - Update build instructions in README. - Fix execution of jextract.ps1 script in Windows build. Result: - Clients that need to customize the SymbolLookup used for the tree-sitter native library no longer need to patch and build java-tree-sitter from source.
1 parent f1f42c1 commit 356a15a

File tree

5 files changed

+61
-16
lines changed

5 files changed

+61
-16
lines changed

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ Java bindings to the [tree-sitter] parsing library.
1515
git clone https://github.com/tree-sitter/java-tree-sitter
1616
cd java-tree-sitter
1717
git submodule init
18+
git submodule update
19+
# build tree-sitter and tree-sitter-java native libraries,
20+
# for example by replicating the steps in .github/workflows/ci.yml
1821
mvn test
1922
```
2023

pom.xml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,8 @@
8181
<skip>${jextract.skip}</skip>
8282
<target name="jextract">
8383
<echo level="info">Generating sources using jextract</echo>
84-
<exec osfamily="windows" executable="${project.basedir}/scripts/jextract.ps1" failonerror="true">
84+
<exec osfamily="windows" executable="powershell" failonerror="true">
85+
<arg value="${project.basedir}/scripts/jextract.ps1"/>
8586
<arg value="${project.basedir}"/>
8687
<arg value="${project.build.directory}"/>
8788
</exec>

scripts/TreeSitter_java.patch

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,13 @@
1-
--- a/generated-sources/jextract/io/github/treesitter/jtreesitter/internal/TreeSitter.java
2-
+++ b/generated-sources/jextract/io/github/treesitter/jtreesitter/internal/TreeSitter.java
3-
@@ -55,9 +55,16 @@ public class TreeSitter {
1+
--- a/target/generated-sources/jextract/io/github/treesitter/jtreesitter/internal/TreeSitter.java
2+
+++ b/target/generated-sources/jextract/io/github/treesitter/jtreesitter/internal/TreeSitter.java
3+
@@ -55,9 +55,7 @@
44
};
55
}
6-
6+
77
- static final SymbolLookup SYMBOL_LOOKUP = SymbolLookup.libraryLookup(System.mapLibraryName("tree-sitter"), LIBRARY_ARENA)
88
- .or(SymbolLookup.loaderLookup())
99
- .or(Linker.nativeLinker().defaultLookup());
10-
+ static final SymbolLookup SYMBOL_LOOKUP = findLibrary().or(Linker.nativeLinker().defaultLookup());
11-
+
12-
+ private static final SymbolLookup findLibrary() {
13-
+ try {
14-
+ String library = System.mapLibraryName("tree-sitter");
15-
+ return SymbolLookup.libraryLookup(library, LIBRARY_ARENA);
16-
+ } catch (IllegalArgumentException e) {
17-
+ return SymbolLookup.loaderLookup();
18-
+ }
19-
+ }
20-
10+
+ static final SymbolLookup SYMBOL_LOOKUP = new ChainedLibraryLookup().get(LIBRARY_ARENA);
11+
2112
public static final ValueLayout.OfBoolean C_BOOL = ValueLayout.JAVA_BOOLEAN;
2213
public static final ValueLayout.OfByte C_CHAR = ValueLayout.JAVA_BYTE;
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package io.github.treesitter.jtreesitter;
2+
3+
import java.lang.foreign.Arena;
4+
import java.lang.foreign.SymbolLookup;
5+
6+
/**
7+
* An interface implemented by clients that wish to customize the {@link SymbolLookup} used for the tree-sitter
8+
* native library. Implementation classes must be registered by listing their fully qualified class name
9+
* in a resource file named {@code META-INF/services/io.github.treesitter.jtreesitter.NativeLibraryLookup}.
10+
*
11+
* @see java.util.ServiceLoader
12+
*/
13+
public interface NativeLibraryLookup {
14+
/**
15+
* Returns the {@link SymbolLookup} to be used for the tree-sitter native library.
16+
*
17+
* @param arena an arena for the symbol lookup
18+
* @return the {@link SymbolLookup} to be used for the tree-sitter native library
19+
*/
20+
SymbolLookup get(Arena arena);
21+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package io.github.treesitter.jtreesitter.internal;
2+
3+
import io.github.treesitter.jtreesitter.NativeLibraryLookup;
4+
import java.lang.foreign.Arena;
5+
import java.lang.foreign.Linker;
6+
import java.lang.foreign.SymbolLookup;
7+
import java.util.Optional;
8+
import java.util.ServiceLoader;
9+
10+
final class ChainedLibraryLookup implements NativeLibraryLookup {
11+
@Override
12+
public SymbolLookup get(Arena arena) {
13+
var serviceLoader = ServiceLoader.load(NativeLibraryLookup.class);
14+
SymbolLookup lookup = (name) -> Optional.empty();
15+
for (var libraryLookup : serviceLoader) {
16+
lookup = lookup.or(libraryLookup.get(arena));
17+
}
18+
return lookup.or(findLibrary(arena)).or(Linker.nativeLinker().defaultLookup());
19+
}
20+
21+
private SymbolLookup findLibrary(Arena arena) {
22+
try {
23+
String library = System.mapLibraryName("tree-sitter");
24+
return SymbolLookup.libraryLookup(library, arena);
25+
} catch (IllegalArgumentException e) {
26+
return SymbolLookup.loaderLookup();
27+
}
28+
}
29+
}

0 commit comments

Comments
 (0)