Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 22 additions & 4 deletions src/main/java/io/github/treesitter/jtreesitter/Query.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import io.github.treesitter.jtreesitter.internal.*;
import java.lang.foreign.Arena;
import java.lang.foreign.MemorySegment;
import java.lang.foreign.SegmentAllocator;
import java.util.*;
import java.util.function.BiPredicate;
import java.util.function.Consumer;
Expand Down Expand Up @@ -480,10 +481,12 @@ public Map<String, Optional<String>> getPatternAssertions(@Unsigned int index, b
/**
* Iterate over all the matches in the order that they were found.
*
* @implNote The lifetime of the matches is bound to that of the query.
*
* @param node The node that the query will run on.
*/
public Stream<QueryMatch> findMatches(Node node) {
return findMatches(node, null);
return findMatches(node, arena, null);
}

/**
Expand All @@ -500,14 +503,26 @@ public Stream<QueryMatch> findMatches(Node node) {
* });
* }
*
* @implNote The lifetime of the matches is bound to that of the query.
*
* @param node The node that the query will run on.
* @param predicate A function that handles custom predicates.
*/
public Stream<QueryMatch> findMatches(Node node, @Nullable BiPredicate<QueryPredicate, QueryMatch> predicate) {
return findMatches(node, arena, predicate);
}

/**
* Iterate over all the matches in the order that they were found, using the given allocator.
*
* @see #findMatches(Node, BiPredicate)
*/
public Stream<QueryMatch> findMatches(
Node node, SegmentAllocator allocator, @Nullable BiPredicate<QueryPredicate, QueryMatch> predicate) {
try (var alloc = Arena.ofConfined()) {
ts_query_cursor_exec(cursor, query, node.copy(alloc));
}
return StreamSupport.stream(new MatchesIterator(node.getTree(), predicate), false);
return StreamSupport.stream(new MatchesIterator(node.getTree(), allocator, predicate), false);
}

@Override
Expand Down Expand Up @@ -537,11 +552,14 @@ private void checkIndex(@Unsigned int index) throws IndexOutOfBoundsException {
private final class MatchesIterator extends Spliterators.AbstractSpliterator<QueryMatch> {
private final @Nullable BiPredicate<QueryPredicate, QueryMatch> predicate;
private final Tree tree;
private final SegmentAllocator allocator;

public MatchesIterator(Tree tree, @Nullable BiPredicate<QueryPredicate, QueryMatch> predicate) {
public MatchesIterator(
Tree tree, SegmentAllocator allocator, @Nullable BiPredicate<QueryPredicate, QueryMatch> predicate) {
super(Long.MAX_VALUE, Spliterator.IMMUTABLE | Spliterator.NONNULL);
this.predicate = predicate;
this.tree = tree;
this.allocator = allocator;
}

@Override
Expand All @@ -555,7 +573,7 @@ public boolean tryAdvance(Consumer<? super QueryMatch> action) {
for (int i = 0; i < count; ++i) {
var capture = TSQueryCapture.asSlice(matchCaptures, i);
var name = captureNames.get(TSQueryCapture.index(capture));
var node = TSNode.allocate(arena).copyFrom(TSQueryCapture.node(capture));
var node = TSNode.allocate(allocator).copyFrom(TSQueryCapture.node(capture));
captureList.add(new QueryCapture(name, new Node(node, tree)));
}
var patternIndex = TSQueryMatch.pattern_index(match);
Expand Down
17 changes: 16 additions & 1 deletion src/main/java/io/github/treesitter/jtreesitter/TreeCursor.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import java.lang.foreign.Arena;
import java.lang.foreign.MemorySegment;
import java.lang.foreign.SegmentAllocator;
import java.util.OptionalInt;
import org.jspecify.annotations.NullMarked;
import org.jspecify.annotations.Nullable;
Expand Down Expand Up @@ -36,7 +37,11 @@ private TreeCursor(TreeCursor cursor) {
node = cursor.node;
}

/** Get the current node of the cursor. */
/**
* Get the current node of the cursor.
*
* @implNote The node will become invalid once the cursor is closed.
*/
public Node getCurrentNode() {
if (this.node == null) {
var node = ts_tree_cursor_current_node(arena, self);
Expand All @@ -45,6 +50,16 @@ public Node getCurrentNode() {
return this.node;
}

/**
* Get the current node of the cursor using the given allocator.
*
* @since 0.25.0
*/
public Node getCurrentNode(SegmentAllocator allocator) {
var node = ts_tree_cursor_current_node(allocator, self);
return new Node(node, tree);
}

/**
* Get the depth of the cursor's current node relative to
* the original node that the cursor was constructed with.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,13 @@
import static org.junit.jupiter.api.Assertions.*;

import io.github.treesitter.jtreesitter.languages.TreeSitterJava;
import org.junit.jupiter.api.*;
import java.lang.foreign.Arena;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

class TreeCursorTest {
private static Tree tree;
Expand Down Expand Up @@ -37,6 +43,15 @@ void getCurrentNode() {
var node = cursor.getCurrentNode();
assertEquals(tree.getRootNode(), node);
assertSame(node, cursor.getCurrentNode());

try (var arena = Arena.ofConfined()) {
try (var copy = cursor.clone()) {
node = copy.getCurrentNode(arena);
assertEquals(node, tree.getRootNode());
}
// can still access node after cursor was closed
assertEquals(node, tree.getRootNode());
}
}

@Test
Expand Down