Skip to content

Commit 956a0a4

Browse files
committed
feat(TreeCursor) : added method to retrieve current node with custom allocator
1 parent 06d6e87 commit 956a0a4

File tree

2 files changed

+42
-31
lines changed

2 files changed

+42
-31
lines changed

src/main/java/io/github/treesitter/jtreesitter/TreeCursor.java

Lines changed: 23 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
import java.lang.foreign.Arena;
66
import java.lang.foreign.MemorySegment;
7+
import java.lang.foreign.SegmentAllocator;
78
import java.util.OptionalInt;
89
import org.jspecify.annotations.NullMarked;
910
import org.jspecify.annotations.Nullable;
@@ -14,7 +15,6 @@ public final class TreeCursor implements AutoCloseable, Cloneable {
1415
private final MemorySegment self;
1516
private final Arena arena;
1617
private final Tree tree;
17-
private @Nullable Node node;
1818

1919
TreeCursor(Node node, Tree tree) {
2020
arena = Arena.ofShared();
@@ -33,16 +33,25 @@ private TreeCursor(TreeCursor cursor) {
3333
arena = Arena.ofShared();
3434
self = ts_tree_cursor_copy(arena, cursor.self);
3535
tree = cursor.tree.clone();
36-
node = cursor.node;
3736
}
3837

39-
/** Get the current node of the cursor. */
38+
/**
39+
* Get the current node of the cursor. Its native memory will be managed by the cursor. It will become invalid
40+
* once the cursor is closed by calling {@link #close()}.
41+
* @return the current node
42+
*/
4043
public Node getCurrentNode() {
41-
if (this.node == null) {
42-
var node = ts_tree_cursor_current_node(arena, self);
43-
this.node = new Node(node, tree);
44-
}
45-
return this.node;
44+
return getCurrentNode(arena);
45+
}
46+
47+
/**
48+
* Get the current node of the cursor. Its native memory will be managed by the given allocator.
49+
* @param allocator the allocator to use for managing the native memory of the node
50+
* @return the current node
51+
*/
52+
public Node getCurrentNode(SegmentAllocator allocator) {
53+
var node = ts_tree_cursor_current_node(allocator, self);
54+
return new Node(node, tree);
4655
}
4756

4857
/**
@@ -88,9 +97,7 @@ public Node getCurrentNode() {
8897
* {@code false} if there were no children.
8998
*/
9099
public boolean gotoFirstChild() {
91-
var result = ts_tree_cursor_goto_first_child(self);
92-
if (result) node = null;
93-
return result;
100+
return ts_tree_cursor_goto_first_child(self);
94101
}
95102

96103
/**
@@ -100,9 +107,7 @@ public boolean gotoFirstChild() {
100107
* {@code false} if there were no children.
101108
*/
102109
public boolean gotoLastChild() {
103-
var result = ts_tree_cursor_goto_last_child(self);
104-
if (result) node = null;
105-
return result;
110+
return ts_tree_cursor_goto_last_child(self);
106111
}
107112

108113
/**
@@ -112,9 +117,7 @@ public boolean gotoLastChild() {
112117
* {@code false} if there was no parent node.
113118
*/
114119
public boolean gotoParent() {
115-
var result = ts_tree_cursor_goto_parent(self);
116-
if (result) node = null;
117-
return result;
120+
return ts_tree_cursor_goto_parent(self);
118121
}
119122

120123
/**
@@ -124,9 +127,7 @@ public boolean gotoParent() {
124127
* {@code false} if there was no next sibling node.
125128
*/
126129
public boolean gotoNextSibling() {
127-
var result = ts_tree_cursor_goto_next_sibling(self);
128-
if (result) node = null;
129-
return result;
130+
return ts_tree_cursor_goto_next_sibling(self);
130131
}
131132

132133
/**
@@ -136,9 +137,7 @@ public boolean gotoNextSibling() {
136137
* {@code false} if there was no previous sibling node.
137138
*/
138139
public boolean gotoPreviousSibling() {
139-
var result = ts_tree_cursor_goto_previous_sibling(self);
140-
if (result) node = null;
141-
return result;
140+
return ts_tree_cursor_goto_previous_sibling(self);
142141
}
143142

144143
/**
@@ -149,7 +148,7 @@ public boolean gotoPreviousSibling() {
149148
*/
150149
public void gotoDescendant(@Unsigned int index) {
151150
ts_tree_cursor_goto_descendant(self, index);
152-
node = null;
151+
153152
}
154153

155154
/**
@@ -161,7 +160,6 @@ public void gotoDescendant(@Unsigned int index) {
161160
public @Unsigned OptionalInt gotoFirstChildForByte(@Unsigned int offset) {
162161
var index = ts_tree_cursor_goto_first_child_for_byte(self, offset);
163162
if (index == -1L) return OptionalInt.empty();
164-
node = null;
165163
return OptionalInt.of((int) index);
166164
}
167165

@@ -176,7 +174,6 @@ public void gotoDescendant(@Unsigned int index) {
176174
var goal = point.into(arena);
177175
var index = ts_tree_cursor_goto_first_child_for_point(self, goal);
178176
if (index == -1L) return OptionalInt.empty();
179-
node = null;
180177
return OptionalInt.of((int) index);
181178
}
182179
}
@@ -185,15 +182,12 @@ public void gotoDescendant(@Unsigned int index) {
185182
public void reset(Node node) {
186183
try (var arena = Arena.ofConfined()) {
187184
ts_tree_cursor_reset(self, node.copy(arena));
188-
} finally {
189-
this.node = null;
190185
}
191186
}
192187

193188
/** Reset the cursor to start at the same position as another cursor. */
194189
public void reset(TreeCursor cursor) {
195190
ts_tree_cursor_reset_to(self, cursor.self);
196-
this.node = null;
197191
}
198192

199193
/** Create a shallow copy of the tree cursor. */

src/test/java/io/github/treesitter/jtreesitter/TreeCursorTest.java

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
import io.github.treesitter.jtreesitter.languages.TreeSitterJava;
66
import org.junit.jupiter.api.*;
77

8+
import java.lang.foreign.Arena;
9+
810
class TreeCursorTest {
911
private static Tree tree;
1012
private TreeCursor cursor;
@@ -29,14 +31,29 @@ void setUp() {
2931

3032
@AfterEach
3133
void tearDown() {
32-
cursor.close();
34+
if(cursor != null){
35+
cursor.close();
36+
}
3337
}
3438

3539
@Test
3640
void getCurrentNode() {
3741
var node = cursor.getCurrentNode();
3842
assertEquals(tree.getRootNode(), node);
39-
assertSame(node, cursor.getCurrentNode());
43+
}
44+
45+
@Test
46+
void getCurrentNodeWithCustomAllocator() {
47+
48+
try(var arena = Arena.ofConfined()){
49+
var node = cursor.getCurrentNode(arena);
50+
assertEquals(tree.getRootNode(), node);
51+
cursor.close();
52+
cursor = null; // avoid double close
53+
// can still access node after cursor was closed
54+
assertEquals(tree.getRootNode(), node);
55+
}
56+
4057
}
4158

4259
@Test

0 commit comments

Comments
 (0)