Skip to content

Commit 89dc1fc

Browse files
committed
improved tests and documentation of QueryCursor
1 parent 2172b24 commit 89dc1fc

File tree

6 files changed

+442
-155
lines changed

6 files changed

+442
-155
lines changed

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

Lines changed: 32 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
import java.util.regex.Pattern;
1313
import java.util.regex.PatternSyntaxException;
1414
import java.util.stream.Stream;
15-
1615
import org.jspecify.annotations.NullMarked;
1716
import org.jspecify.annotations.Nullable;
1817

@@ -25,7 +24,7 @@
2524
@NullMarked
2625
public final class Query implements AutoCloseable {
2726
private final MemorySegment query;
28-
private final QueryCursorOptions cursorOptions = new QueryCursorOptions();
27+
private final QueryCursorConfig cursorConfig = new QueryCursorConfig();
2928
private final Arena arena;
3029
private final Language language;
3130
private final String source;
@@ -261,7 +260,7 @@ private static boolean invalidPredicateChar(char c) {
261260
return !(Character.isLetterOrDigit(c) || c == '_' || c == '-' || c == '.' || c == '?' || c == '!');
262261
}
263262

264-
MemorySegment self(){
263+
MemorySegment self() {
265264
return query;
266265
}
267266

@@ -275,30 +274,30 @@ MemorySegment self(){
275274
return ts_query_capture_count(query);
276275
}
277276

278-
public List<List<QueryPredicate>> getPredicates(){
277+
public List<List<QueryPredicate>> getPredicates() {
279278
return predicates.stream().map(Collections::unmodifiableList).toList();
280279
}
281280

282-
public List<String> getCaptureNames(){
281+
public List<String> getCaptureNames() {
283282
return Collections.unmodifiableList(captureNames);
284283
}
285284

286285
/**
287-
* Get the maximum number of in-progress matches.
286+
* Get the maximum number of in-progress matches of the default {@link QueryCursorConfig}
288287
*
289288
* @apiNote Defaults to {@code -1} (unlimited).
290289
*/
291290
public @Unsigned int getMatchLimit() {
292-
return cursorOptions.getMatchLimit();
291+
return cursorConfig.getMatchLimit();
293292
}
294293

295294
/**
296-
* Get the maximum number of in-progress matches.
295+
* Set the maximum number of in-progress matches of the default {@link QueryCursorConfig}
297296
*
298297
* @throws IllegalArgumentException If {@code matchLimit == 0}.
299298
*/
300299
public Query setMatchLimit(@Unsigned int matchLimit) throws IllegalArgumentException {
301-
cursorOptions.setMatchLimit(matchLimit);
300+
cursorConfig.setMatchLimit(matchLimit);
302301
return this;
303302
}
304303

@@ -308,19 +307,23 @@ public Query setMatchLimit(@Unsigned int matchLimit) throws IllegalArgumentExcep
308307
*
309308
* @apiNote Defaults to {@code 0} (unlimited).
310309
* @since 0.23.1
310+
* @deprecated
311311
*/
312+
@Deprecated(forRemoval = true)
312313
public @Unsigned long getTimeoutMicros() {
313-
return cursorOptions.getTimeoutMicros();
314+
return cursorConfig.getTimeoutMicros();
314315
}
315316

316317
/**
317318
* Set the maximum duration in microseconds that query
318319
* execution should be allowed to take before halting.
319320
*
320321
* @since 0.23.1
322+
* @deprecated
321323
*/
324+
@Deprecated(forRemoval = true)
322325
public Query setTimeoutMicros(@Unsigned long timeoutMicros) {
323-
cursorOptions.setTimeoutMicros(timeoutMicros);
326+
cursorConfig.setTimeoutMicros(timeoutMicros);
324327
return this;
325328
}
326329

@@ -331,25 +334,22 @@ public Query setTimeoutMicros(@Unsigned long timeoutMicros) {
331334
* <br>Note that if a pattern includes many children, then they will still be checked.
332335
*/
333336
public Query setMaxStartDepth(@Unsigned int maxStartDepth) {
334-
cursorOptions.setMaxStartDepth(maxStartDepth);
337+
cursorConfig.setMaxStartDepth(maxStartDepth);
335338
return this;
336339
}
337340

338341
/** Set the range of bytes in which the query will be executed. */
339342
public Query setByteRange(@Unsigned int startByte, @Unsigned int endByte) {
340-
cursorOptions.setStartByte(startByte);
341-
cursorOptions.setEndByte(endByte);
343+
cursorConfig.setByteRange(startByte, endByte);
342344
return this;
343345
}
344346

345347
/** Set the range of points in which the query will be executed. */
346348
public Query setPointRange(Point startPoint, Point endPoint) {
347-
cursorOptions.setStartPoint(startPoint);
348-
cursorOptions.setEndPoint(endPoint);
349+
cursorConfig.setPointRange(startPoint, endPoint);
349350
return this;
350351
}
351352

352-
353353
/**
354354
* Disable a certain pattern within a query.
355355
*
@@ -477,14 +477,13 @@ public Map<String, Optional<String>> getPatternAssertions(@Unsigned int index, b
477477
return Collections.unmodifiableMap(assertions.get(index));
478478
}
479479

480-
481480
/**
482-
* Execute the query on a given node.
481+
* Execute the query on a given node with the default {@link QueryCursorConfig}.
483482
* @param node The node that the query will run on.
484483
* @return A cursor that can be used to iterate over the matches.
485484
*/
486-
public QueryCursor execute(Node node){
487-
return new QueryCursor(this, node, cursorOptions);
485+
public QueryCursor execute(Node node) {
486+
return new QueryCursor(this, node, cursorConfig);
488487
}
489488

490489
/**
@@ -493,22 +492,22 @@ public QueryCursor execute(Node node){
493492
* @param options The options that will be used for this query.
494493
* @return A cursor that can be used to iterate over the matches.
495494
*/
496-
public QueryCursor execute(Node node, QueryCursorOptions options){
495+
public QueryCursor execute(Node node, QueryCursorConfig options) {
497496
return new QueryCursor(this, node, options);
498497
}
499498

500-
501499
/**
502500
* Iterate over all the matches in the order that they were found. The lifetime of the native memory of the returned
503501
* matches is bound to the lifetime of this query object.
504502
*
505503
* @param node The node that the query will run on.
504+
* @implNote The stream is not created lazily such that there is no open {@link QueryCursor} instance left behind.
505+
* For creating a lazy stream use {@link #execute(Node)} and {@link QueryCursor#matchStream()}.
506506
*/
507507
public Stream<QueryMatch> findMatches(Node node) {
508508
return findMatches(node, arena, null);
509509
}
510510

511-
512511
/**
513512
* Iterate over all the matches in the order that they were found. The lifetime of the native memory of the returned
514513
* matches is bound to the lifetime of this query object.
@@ -526,26 +525,29 @@ public Stream<QueryMatch> findMatches(Node node) {
526525
*
527526
* @param node The node that the query will run on.
528527
* @param predicate A function that handles custom predicates.
529-
* @implNote The stream is not created lazily such that there is no open {@link QueryCursor} instance left behind. For creating a lazy stream use {@link #execute(Node)} and {@link QueryCursor#stream(BiPredicate)}.
528+
* @implNote The stream is not created lazily such that there is no open {@link QueryCursor} instance left behind.
529+
* For creating a lazy stream use {@link #execute(Node)} and {@link QueryCursor#matchStream(BiPredicate)}.
530530
*/
531531
public Stream<QueryMatch> findMatches(Node node, @Nullable BiPredicate<QueryPredicate, QueryMatch> predicate) {
532532
return findMatches(node, arena, predicate);
533533
}
534534

535-
536535
/**
537536
* Like {@link #findMatches(Node, BiPredicate)} but the native memory of the returned matches is created using the
538537
* given allocator.
539538
*
540539
* @param node The node that the query will run on.
541540
* @param allocator The allocator that is used to allocate the native memory of the returned matches.
542541
* @param predicate A function that handles custom predicates.
542+
* @implNote The stream is not created lazily such that there is no open {@link QueryCursor} instance left behind.
543+
* For creating a lazy stream use {@link #execute(Node)} and {@link QueryCursor#matchStream(SegmentAllocator, BiPredicate)}.
543544
*/
544-
public Stream<QueryMatch> findMatches(Node node, SegmentAllocator allocator, @Nullable BiPredicate<QueryPredicate, QueryMatch> predicate) {
545-
try(QueryCursor cursor = this.execute(node)){
545+
public Stream<QueryMatch> findMatches(
546+
Node node, SegmentAllocator allocator, @Nullable BiPredicate<QueryPredicate, QueryMatch> predicate) {
547+
try (QueryCursor cursor = this.execute(node)) {
546548
// make sure to load the entire stream into memory before closing the cursor.
547-
// Otherwise, we call for nextMatch after closing the cursor which leads to undefined behavior.
548-
return cursor.stream(allocator, predicate).toList().stream();
549+
// Otherwise, we call for nextMatch after closing the cursor which leads to an exception.
550+
return cursor.matchStream(allocator, predicate).toList().stream();
549551
}
550552
}
551553

@@ -559,13 +561,10 @@ public String toString() {
559561
return "Query{language=%s, source=%s}".formatted(language, source);
560562
}
561563

562-
563564
private void checkIndex(@Unsigned int index) throws IndexOutOfBoundsException {
564565
if (Integer.compareUnsigned(index, getPatternCount()) >= 0) {
565566
throw new IndexOutOfBoundsException(
566567
"Pattern index %s is out of bounds".formatted(Integer.toUnsignedString(index)));
567568
}
568569
}
569-
570-
571570
}

0 commit comments

Comments
 (0)