Skip to content
This repository was archived by the owner on Oct 18, 2024. It is now read-only.

Commit 92c1b11

Browse files
committed
feat: add support for basic predicates
1 parent 2a1931b commit 92c1b11

File tree

8 files changed

+586
-5
lines changed

8 files changed

+586
-5
lines changed

android-tree-sitter/src/main/java/com/itsaky/androidide/treesitter/DefaultObjectFactory.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ public TSQueryCapture createQueryCapture(TSNode node, int index
102102

103103
@Override
104104
public TSQueryMatch createQueryMatch(int id, int patternIndex, TSQueryCapture[] captures) {
105-
return new TSQueryMatch(id, patternIndex, captures);
105+
return new TSQueryMatch(id, patternIndex, captures, null);
106106
}
107107

108108
@Override

android-tree-sitter/src/main/java/com/itsaky/androidide/treesitter/TSQueryCursor.java

Lines changed: 78 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,21 +18,28 @@
1818
package com.itsaky.androidide.treesitter;
1919

2020
import com.itsaky.androidide.treesitter.annotations.GenerateNativeHeaders;
21+
import com.itsaky.androidide.treesitter.predicate.TSPredicateHandler;
22+
import com.itsaky.androidide.treesitter.predicate.TSPredicateHandler.PredicateStep;
23+
import com.itsaky.androidide.treesitter.predicate.TSPredicateHandler.Result;
2124
import com.itsaky.androidide.treesitter.util.TSObjectFactoryProvider;
2225
import dalvik.annotation.optimization.FastNative;
26+
import java.util.ArrayList;
27+
import java.util.HashSet;
2328
import java.util.Iterator;
2429
import java.util.NoSuchElementException;
2530
import java.util.Objects;
31+
import java.util.Set;
2632

2733
/**
2834
* @author Akash Yadav
2935
*/
3036
public class TSQueryCursor extends TSNativeObject implements Iterable<TSQueryMatch> {
3137

3238
protected boolean isExecuted = false;
33-
protected TSNode targetNode = null;
34-
3539
private boolean allowChangedNodes = false;
40+
protected TSNode targetNode = null;
41+
protected TSQuery execQuery = null;
42+
protected final Set<TSPredicateHandler> predicateHandlers = new HashSet<>();
3643

3744
protected TSQueryCursor() {
3845
this(Native.newCursor());
@@ -74,6 +81,33 @@ public boolean isAllowChangedNodes() {
7481
return allowChangedNodes;
7582
}
7683

84+
/**
85+
* Add the given predicate handler. Predicate handlers are applied to every query match while
86+
* iterating.
87+
*
88+
* @param handler The predicate handler to add.
89+
*/
90+
public void addPredicateHandler(TSPredicateHandler handler) {
91+
if (handler == null) {
92+
return;
93+
}
94+
95+
predicateHandlers.add(handler);
96+
}
97+
98+
/**
99+
* Remove the given predicate handler.
100+
*
101+
* @param handler The predicate handler to remove.
102+
*/
103+
public void removePredicateHandler(TSPredicateHandler handler) {
104+
if (handler == null) {
105+
return;
106+
}
107+
108+
predicateHandlers.remove(handler);
109+
}
110+
77111
/**
78112
* Start running the given query on the given node.
79113
*/
@@ -91,9 +125,12 @@ public void exec(TSQuery query, TSNode node) {
91125

92126
throw new IllegalArgumentException(msg);
93127
}
128+
94129
Native.exec(getNativeObject(), query.getNativeObject(), node);
130+
95131
isExecuted = true;
96132
targetNode = node;
133+
execQuery = query;
97134
}
98135

99136
/**
@@ -180,7 +217,45 @@ public void setPointRange(TSPoint start, TSPoint end) {
180217
public TSQueryMatch nextMatch() {
181218
checkAccess();
182219
checkExecuted("nextMatch");
183-
return Native.nextMatch(getNativeObject());
220+
final var match = Native.nextMatch(getNativeObject());
221+
if (match != null) {
222+
applyPredicates(match);
223+
}
224+
return match;
225+
}
226+
227+
private void applyPredicates(TSQueryMatch match) {
228+
if (match == null || execQuery == null) {
229+
return;
230+
}
231+
232+
final var predicates = execQuery.getPredicatesForPattern(match.getPatternIndex());
233+
final var steps = new ArrayList<PredicateStep>(predicates.length);
234+
235+
for (final var predicate : predicates) {
236+
final PredicateStep step;
237+
switch (predicate.getType()) {
238+
case Capture:
239+
step = new PredicateStep(predicate.getType(),
240+
execQuery.getCaptureNameForId(predicate.getValueId()));
241+
break;
242+
case String:
243+
step = new PredicateStep(predicate.getType(),
244+
execQuery.getStringValueForId(predicate.getValueId()));
245+
break;
246+
default:
247+
step = new PredicateStep(predicate.getType(), "");
248+
break;
249+
}
250+
251+
steps.add(step);
252+
}
253+
254+
for (final var handler : predicateHandlers) {
255+
if (handler.handle(execQuery, match, steps) == Result.OK) {
256+
break;
257+
}
258+
}
184259
}
185260

186261
public void removeMatch(int id) {

android-tree-sitter/src/main/java/com/itsaky/androidide/treesitter/TSQueryMatch.java

Lines changed: 92 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
package com.itsaky.androidide.treesitter;
1919

2020
import com.itsaky.androidide.treesitter.util.TSObjectFactoryProvider;
21+
import java.util.HashMap;
22+
import java.util.Map;
2123

2224
/**
2325
* @author Akash Yadav
@@ -28,13 +30,22 @@ public class TSQueryMatch {
2830
protected int patternIndex;
2931
protected TSQueryCapture[] captures;
3032

33+
protected final Metadata metadata;
34+
3135
protected TSQueryMatch() {
36+
this.metadata = new Metadata();
3237
}
3338

34-
protected TSQueryMatch(int id, int patternIndex, TSQueryCapture[] captures) {
39+
protected TSQueryMatch(int id, int patternIndex, TSQueryCapture[] captures, Metadata metadata) {
3540
this.id = id;
3641
this.patternIndex = patternIndex;
3742
this.captures = captures;
43+
44+
if (metadata == null) {
45+
metadata = new Metadata();
46+
}
47+
48+
this.metadata = metadata;
3849
}
3950

4051
public static TSQueryMatch create(int id, int patternIndex, TSQueryCapture[] captures) {
@@ -56,4 +67,84 @@ public TSQueryCapture[] getCaptures() {
5667
public TSQueryCapture getCapture(int index) {
5768
return captures[index];
5869
}
70+
71+
public Metadata getMetadata() {
72+
return metadata;
73+
}
74+
75+
/**
76+
* Metadata associated with a {@link TSQueryMatch}.
77+
*/
78+
public static class Metadata {
79+
80+
private final Map<Object, Object> data = new HashMap<>(0);
81+
82+
/**
83+
* Check if the map contains the given key.
84+
*
85+
* @param key The key.
86+
* @return <code>true</code> if the map contains the key, <code>false</code> otherwise.
87+
*/
88+
public boolean containsKey(Object key) {
89+
return data.containsKey(key);
90+
}
91+
92+
/**
93+
* Generic getter for the given key.
94+
*/
95+
public <T> T get(Object key) {
96+
//noinspection unchecked
97+
return (T) data.get(key);
98+
}
99+
100+
/**
101+
* Generic setter for the given key.
102+
*/
103+
public <T> T put(Object key, T value) {
104+
//noinspection unchecked
105+
return (T) data.put(key, value);
106+
}
107+
108+
/**
109+
* Get the value associated with the given key. This will return the value as a {@link String}.
110+
*
111+
* @param key The key.
112+
* @return The string value, or <code>null</code>.
113+
*/
114+
public String getString(String key) {
115+
return get(key);
116+
}
117+
118+
/**
119+
* Put a string value with the given key.
120+
*
121+
* @param key The key.
122+
* @param value The value.
123+
* @return The previous value associated with the key, or <code>null</code>.
124+
*/
125+
public String putString(String key, String value) {
126+
return put(key, value);
127+
}
128+
129+
/**
130+
* Get metadata specific to the given capture ID.
131+
*
132+
* @param captureId The capture ID.
133+
* @return The metadata associated with the capture ID, or <code>null</code>.
134+
*/
135+
public Metadata getCaptureMetadata(String captureId) {
136+
return get(captureId);
137+
}
138+
139+
/**
140+
* Put metadata specific to the given capture ID.
141+
*
142+
* @param captureId The capture ID.
143+
* @param metadata The metadata.
144+
* @return The previous metadata associated with the capture ID, or <code>null</code>.
145+
*/
146+
public Metadata putCaptureMetadata(String captureId, Metadata metadata) {
147+
return put(captureId, metadata);
148+
}
149+
}
59150
}
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
/*
2+
* This file is part of android-tree-sitter.
3+
*
4+
* android-tree-sitter library is free software; you can redistribute it and/or
5+
* modify it under the terms of the GNU Lesser General Public
6+
* License as published by the Free Software Foundation; either
7+
* version 2.1 of the License, or (at your option) any later version.
8+
*
9+
* android-tree-sitter library is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12+
* Lesser General Public License for more details.
13+
*
14+
* You should have received a copy of the GNU General Public License
15+
* along with android-tree-sitter. If not, see <https://www.gnu.org/licenses/>.
16+
*/
17+
18+
package com.itsaky.androidide.treesitter.predicate;
19+
20+
import com.itsaky.androidide.treesitter.TSQuery;
21+
import com.itsaky.androidide.treesitter.TSQueryMatch;
22+
import com.itsaky.androidide.treesitter.TSQueryMatch.Metadata;
23+
import com.itsaky.androidide.treesitter.TSQueryPredicateStep;
24+
import com.itsaky.androidide.treesitter.TSQueryPredicateStep.Type;
25+
import com.itsaky.androidide.treesitter.util.PredicateUtils;
26+
import java.util.List;
27+
28+
/**
29+
* Handles the <code>#set!</code> directive in queries.
30+
*
31+
* @author Akash Yadav
32+
*/
33+
public class SetDirectiveHandler implements TSPredicateHandler {
34+
35+
public static final String DIRECTIVE = "set!";
36+
public static final String[] SUPPORTED_PREDICATES = {DIRECTIVE};
37+
38+
public static final TSQueryPredicateStep.Type[] PARAMETERS_1 = {Type.String, // set!
39+
Type.String, // key
40+
Type.String, // value
41+
Type.Done};
42+
43+
public static final TSQueryPredicateStep.Type[] PARAMETERS_2 = {Type.String, // set!
44+
Type.Capture, // @capture
45+
Type.String, // key
46+
Type.String, // value
47+
Type.Done};
48+
49+
@Override
50+
public String[] getSupportedPredicates() {
51+
return SUPPORTED_PREDICATES;
52+
}
53+
54+
@Override
55+
public Result handle(TSQuery query, TSQueryMatch match, List<PredicateStep> args
56+
) {
57+
if (!DIRECTIVE.equals(args.get(0).value)) {
58+
return Result.UNHANDLED;
59+
}
60+
61+
final var matchMetadata = match.getMetadata();
62+
if (PredicateUtils.matchesArgTypes(PARAMETERS_1, args)) {
63+
final var key = args.get(1).value;
64+
final var value = args.get(2).value;
65+
if (key != null) {
66+
matchMetadata.putString(key, value);
67+
return Result.OK;
68+
}
69+
70+
return Result.ERR;
71+
}
72+
73+
if (PredicateUtils.matchesArgTypes(PARAMETERS_2, args)) {
74+
final var capture = args.get(1).value;
75+
final var key = args.get(2).value;
76+
final var value = args.get(3).value;
77+
if (capture != null && key != null) {
78+
var captureMeta = matchMetadata.getCaptureMetadata(capture);
79+
if (captureMeta == null) {
80+
captureMeta = new Metadata();
81+
}
82+
captureMeta.putString(key, value);
83+
matchMetadata.putCaptureMetadata(capture, captureMeta);
84+
return Result.OK;
85+
}
86+
87+
return Result.ERR;
88+
}
89+
90+
return Result.UNHANDLED;
91+
}
92+
}

0 commit comments

Comments
 (0)