@konomanoasa/tree-sitter-query 0.3.0 → 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Cargo.toml +2 -2
- package/README.md +4 -0
- package/grammar.js +17 -30
- package/package.json +5 -5
- package/src/grammar.json +75 -86
- package/src/parser.c +78 -85
- package/test/bindings.test.rs +129 -278
- package/tree-sitter.json +1 -1
package/test/bindings.test.rs
CHANGED
|
@@ -25,22 +25,12 @@ fn parses_valid_source() {
|
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
#[test]
|
|
28
|
-
fn
|
|
29
|
-
let mut parser = parser();
|
|
30
|
-
let source = "; query\n";
|
|
31
|
-
let tree = parser.parse(source, None).unwrap();
|
|
32
|
-
let root = tree.root_node();
|
|
33
|
-
assert!(!root.has_error());
|
|
34
|
-
assert_eq!(root.kind(), "query");
|
|
35
|
-
assert_eq!(root.to_sexp(), "(query (comment))");
|
|
36
|
-
assert_eq!(root.named_child(0).unwrap().byte_range(), 0..7);
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
#[test]
|
|
40
|
-
fn missing_node_forms_follow_public_query_api_syntax() {
|
|
28
|
+
fn node_designators_follow_public_query_api_syntax() {
|
|
41
29
|
let language = grammar::LANGUAGE.into();
|
|
42
30
|
let mut parser = parser();
|
|
43
31
|
for (source, valid) in [
|
|
32
|
+
("(_ @x)", false),
|
|
33
|
+
("(_+ _)", false),
|
|
44
34
|
("(MISSING)", true),
|
|
45
35
|
("(MISSING ; comment\n)", true),
|
|
46
36
|
("(MISSING identifier)", true),
|
|
@@ -68,6 +58,72 @@ fn missing_node_forms_follow_public_query_api_syntax() {
|
|
|
68
58
|
}
|
|
69
59
|
}
|
|
70
60
|
|
|
61
|
+
#[test]
|
|
62
|
+
fn call_placement_and_arguments_follow_public_query_api_syntax() {
|
|
63
|
+
let language = grammar::LANGUAGE.into();
|
|
64
|
+
let mut parser = parser();
|
|
65
|
+
for (source, valid) in [
|
|
66
|
+
("(#custom?)", true),
|
|
67
|
+
("[(#custom?)]", true),
|
|
68
|
+
("((#custom?))", true),
|
|
69
|
+
("(node_pattern (#custom?))", true),
|
|
70
|
+
("(#custom? 42 -1 0.5 _ MISSING)", true),
|
|
71
|
+
("(#_call? _arg)", true),
|
|
72
|
+
("(_) @_cap (#_call? _arg @_cap)", true),
|
|
73
|
+
("(#custom)", false),
|
|
74
|
+
("(#custom?) @capture", false),
|
|
75
|
+
("(#custom!)?", false),
|
|
76
|
+
("(# custom?)", false),
|
|
77
|
+
("(#custom ?)", false),
|
|
78
|
+
("(identifier) @ name", false),
|
|
79
|
+
] {
|
|
80
|
+
match Query::new(&language, source) {
|
|
81
|
+
Ok(_) => assert!(valid, "{source:?}"),
|
|
82
|
+
Err(error) => {
|
|
83
|
+
assert!(!valid, "{source:?}: {error:?}");
|
|
84
|
+
assert_eq!(error.kind, QueryErrorKind::Syntax, "{source:?}");
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
assert_eq!(
|
|
88
|
+
parser.parse(source, None).unwrap().root_node().has_error(),
|
|
89
|
+
!valid,
|
|
90
|
+
"{source:?}"
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
#[test]
|
|
96
|
+
fn documented_call_prefix_overrides_the_public_query_api_extension() {
|
|
97
|
+
let language = grammar::LANGUAGE.into();
|
|
98
|
+
let mut parser = parser();
|
|
99
|
+
for (source, valid) in [
|
|
100
|
+
("(#custom?)", true),
|
|
101
|
+
("(#custom! key value)", true),
|
|
102
|
+
("(.custom?)", false),
|
|
103
|
+
("(.custom! key value)", false),
|
|
104
|
+
] {
|
|
105
|
+
assert!(Query::new(&language, source).is_ok(), "{source:?}");
|
|
106
|
+
assert_eq!(
|
|
107
|
+
parser.parse(source, None).unwrap().root_node().has_error(),
|
|
108
|
+
!valid,
|
|
109
|
+
"{source:?}"
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
#[test]
|
|
115
|
+
fn postfix_order_and_repetition_follow_public_query_api_syntax() {
|
|
116
|
+
let language = grammar::LANGUAGE.into();
|
|
117
|
+
let mut parser = parser();
|
|
118
|
+
for source in ["(identifier) @x? @y+", "(identifier) +*?"] {
|
|
119
|
+
let query = Query::new(&language, source).unwrap();
|
|
120
|
+
assert_eq!(query.pattern_count(), 1, "{source:?}");
|
|
121
|
+
let tree = parser.parse(source, None).unwrap();
|
|
122
|
+
assert!(!tree.root_node().has_error(), "{source:?}");
|
|
123
|
+
assert_eq!(tree.root_node().named_child_count(), 1, "{source:?}");
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
71
127
|
#[test]
|
|
72
128
|
fn field_constraints_and_call_anchors_follow_public_query_api_syntax() {
|
|
73
129
|
let language = grammar::LANGUAGE.into();
|
|
@@ -159,173 +215,76 @@ fn adjacent_bare_wildcards_follow_public_query_api_pattern_and_capture_counts()
|
|
|
159
215
|
}
|
|
160
216
|
|
|
161
217
|
#[test]
|
|
162
|
-
fn
|
|
163
|
-
{
|
|
218
|
+
fn underscored_names_reach_semantic_validation_without_wildcard_splitting() {
|
|
164
219
|
let language = grammar::LANGUAGE.into();
|
|
165
|
-
let query = Query::new(&language, "[(wildcard) (identifier)] @leaf").unwrap();
|
|
166
220
|
let mut parser = parser();
|
|
167
|
-
for (source,
|
|
168
|
-
(
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
),
|
|
172
|
-
(
|
|
173
|
-
"_field: (x)",
|
|
174
|
-
vec![
|
|
175
|
-
("wildcard", 0..1),
|
|
176
|
-
("identifier", 1..6),
|
|
177
|
-
("identifier", 9..10),
|
|
178
|
-
],
|
|
179
|
-
),
|
|
180
|
-
(
|
|
181
|
-
"(_x !_field) @_cap",
|
|
182
|
-
vec![
|
|
183
|
-
("identifier", 1..3),
|
|
184
|
-
("identifier", 5..11),
|
|
185
|
-
("identifier", 14..18),
|
|
186
|
-
],
|
|
187
|
-
),
|
|
188
|
-
(
|
|
189
|
-
"(#_call? _arg @_cap)",
|
|
190
|
-
vec![
|
|
191
|
-
("identifier", 2..7),
|
|
192
|
-
("identifier", 9..13),
|
|
193
|
-
("identifier", 15..19),
|
|
194
|
-
],
|
|
195
|
-
),
|
|
196
|
-
(
|
|
197
|
-
"(MISSING _type) (_super/_sub)",
|
|
198
|
-
vec![
|
|
199
|
-
("identifier", 9..14),
|
|
200
|
-
("identifier", 17..23),
|
|
201
|
-
("identifier", 24..28),
|
|
202
|
-
],
|
|
203
|
-
),
|
|
221
|
+
for (source, error) in [
|
|
222
|
+
("(_x)", QueryErrorKind::NodeType),
|
|
223
|
+
("(_ !_x)", QueryErrorKind::Field),
|
|
224
|
+
("(node_pattern !_)", QueryErrorKind::Field),
|
|
204
225
|
] {
|
|
226
|
+
assert_eq!(
|
|
227
|
+
Query::new(&language, source).unwrap_err().kind,
|
|
228
|
+
error,
|
|
229
|
+
"{source:?}"
|
|
230
|
+
);
|
|
205
231
|
let tree = parser.parse(source, None).unwrap();
|
|
206
232
|
assert!(!tree.root_node().has_error(), "{source:?}");
|
|
207
|
-
|
|
208
|
-
let mut matches =
|
|
209
|
-
cursor.matches(&query, tree.root_node(), source.as_bytes());
|
|
210
|
-
let mut actual = Vec::new();
|
|
211
|
-
while let Some(item) = matches.next() {
|
|
212
|
-
let node = item.captures()[0].node;
|
|
213
|
-
assert_eq!(node.child_count(), 0);
|
|
214
|
-
actual.push((node.kind(), node.byte_range()));
|
|
215
|
-
}
|
|
216
|
-
assert_eq!(actual, expected, "{source:?}");
|
|
233
|
+
assert_eq!(tree.root_node().byte_range(), 0..source.len());
|
|
217
234
|
}
|
|
218
235
|
}
|
|
219
236
|
|
|
220
237
|
#[test]
|
|
221
|
-
fn
|
|
222
|
-
let
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
let child = target.child_by_field_name(field).unwrap();
|
|
251
|
-
assert_eq!(child.kind(), kind);
|
|
252
|
-
assert_eq!(child.byte_range(), range);
|
|
238
|
+
fn field_lookup_matches_cursor_ownership() {
|
|
239
|
+
let mut parser = parser();
|
|
240
|
+
for source in ["left: right: (_)+ @x", "(node . child: (_)+ @x !absent)"] {
|
|
241
|
+
let tree = parser.parse(source, None).unwrap();
|
|
242
|
+
let mut pending = vec![tree.root_node()];
|
|
243
|
+
let mut fields = 0;
|
|
244
|
+
while let Some(owner) = pending.pop() {
|
|
245
|
+
let mut cursor = owner.walk();
|
|
246
|
+
if !cursor.goto_first_child() {
|
|
247
|
+
continue;
|
|
248
|
+
}
|
|
249
|
+
loop {
|
|
250
|
+
let child = cursor.node();
|
|
251
|
+
if let Some(field) = cursor.field_name() {
|
|
252
|
+
assert_eq!(
|
|
253
|
+
owner.child_by_field_name(field),
|
|
254
|
+
Some(child),
|
|
255
|
+
"{source:?}: {field}"
|
|
256
|
+
);
|
|
257
|
+
assert_eq!(child.parent(), Some(owner));
|
|
258
|
+
fields += 1;
|
|
259
|
+
}
|
|
260
|
+
pending.push(child);
|
|
261
|
+
if !cursor.goto_next_sibling() {
|
|
262
|
+
break;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
assert!(fields > 0, "{source:?}: no fields");
|
|
253
267
|
}
|
|
254
268
|
}
|
|
255
269
|
|
|
256
270
|
#[test]
|
|
257
|
-
fn
|
|
271
|
+
fn string_arguments_follow_public_query_api_syntax() {
|
|
258
272
|
let language = grammar::LANGUAGE.into();
|
|
259
273
|
let mut parser = parser();
|
|
260
|
-
for
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
),
|
|
271
|
-
(
|
|
272
|
-
"\";x\0\"",
|
|
273
|
-
vec![("\"", 0..1), ("string_content", 1..4), ("\"", 4..5)],
|
|
274
|
-
),
|
|
275
|
-
(
|
|
276
|
-
"\"\\\n;x\0\"",
|
|
277
|
-
vec![
|
|
278
|
-
("\"", 0..1),
|
|
279
|
-
("escape_sequence", 1..3),
|
|
280
|
-
("string_content", 3..6),
|
|
281
|
-
("\"", 6..7),
|
|
282
|
-
],
|
|
283
|
-
),
|
|
284
|
-
(
|
|
285
|
-
"\"a\0b\0\0c\"",
|
|
286
|
-
vec![("\"", 0..1), ("string_content", 1..7), ("\"", 7..8)],
|
|
287
|
-
),
|
|
288
|
-
(
|
|
289
|
-
"\"\0\"",
|
|
290
|
-
vec![("\"", 0..1), ("string_content", 1..2), ("\"", 2..3)],
|
|
291
|
-
),
|
|
292
|
-
(
|
|
293
|
-
"\"a\\\0b\"",
|
|
294
|
-
vec![
|
|
295
|
-
("\"", 0..1),
|
|
296
|
-
("string_content", 1..2),
|
|
297
|
-
("escape_sequence", 2..4),
|
|
298
|
-
("string_content", 4..5),
|
|
299
|
-
("\"", 5..6),
|
|
300
|
-
],
|
|
301
|
-
),
|
|
302
|
-
(
|
|
303
|
-
"\"\\\0\"",
|
|
304
|
-
vec![("\"", 0..1), ("escape_sequence", 1..3), ("\"", 3..4)],
|
|
305
|
-
),
|
|
274
|
+
for source in [
|
|
275
|
+
"\"日\\\"本\"",
|
|
276
|
+
"\";x\0\"",
|
|
277
|
+
"\"\\\n;x\0\"",
|
|
278
|
+
"\"a\0b\0\0c\"",
|
|
279
|
+
"\"\0\"",
|
|
280
|
+
"\"a\\\0b\"",
|
|
281
|
+
"\"\\\0\"",
|
|
282
|
+
r#""\q""#,
|
|
283
|
+
"\"\r\"",
|
|
306
284
|
] {
|
|
307
285
|
assert!(Query::new(&language, &format!("(#custom? {source})")).is_ok());
|
|
308
|
-
let tree = parser.parse(source, None).unwrap();
|
|
309
|
-
assert!(!tree.root_node().has_error(), "{source:?}");
|
|
310
|
-
let string = tree
|
|
311
|
-
.root_node()
|
|
312
|
-
.named_child(0)
|
|
313
|
-
.unwrap()
|
|
314
|
-
.child_by_field_name("body")
|
|
315
|
-
.unwrap();
|
|
316
|
-
let mut cursor = string.walk();
|
|
317
|
-
let actual: Vec<_> = string
|
|
318
|
-
.children(&mut cursor)
|
|
319
|
-
.map(|node| {
|
|
320
|
-
assert_eq!(node.child_count(), 0);
|
|
321
|
-
(node.kind(), node.byte_range())
|
|
322
|
-
})
|
|
323
|
-
.collect();
|
|
324
|
-
assert_eq!(actual, expected, "{source:?}");
|
|
325
|
-
}
|
|
326
|
-
for source in ["\"a\0", "\"\\\0", "\"a\\", "\"\0\n\""] {
|
|
327
286
|
assert!(
|
|
328
|
-
parser.parse(source, None).unwrap().root_node().has_error(),
|
|
287
|
+
!parser.parse(source, None).unwrap().root_node().has_error(),
|
|
329
288
|
"{source:?}"
|
|
330
289
|
);
|
|
331
290
|
}
|
|
@@ -353,20 +312,15 @@ fn string_newlines_cannot_skip_comments_before_nul() {
|
|
|
353
312
|
}
|
|
354
313
|
|
|
355
314
|
#[test]
|
|
356
|
-
fn
|
|
315
|
+
fn comments_with_carriage_returns_follow_public_query_api_syntax() {
|
|
357
316
|
let language = grammar::LANGUAGE.into();
|
|
358
317
|
let mut parser = parser();
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
root.to_sexp(),
|
|
366
|
-
"(query (comment) (pattern body: (node_pattern node: (wildcard))))"
|
|
367
|
-
);
|
|
368
|
-
assert_eq!(root.named_child(0).unwrap().byte_range(), 0..4);
|
|
369
|
-
assert_eq!(root.named_child(1).unwrap().byte_range(), 6..9);
|
|
318
|
+
for (source, patterns) in [(";a\rb\r\n(_)", 1), (";x\r(_)", 0)] {
|
|
319
|
+
let query = Query::new(&language, source).unwrap();
|
|
320
|
+
assert_eq!(query.pattern_count(), patterns, "{source:?}");
|
|
321
|
+
let tree = parser.parse(source, None).unwrap();
|
|
322
|
+
assert!(!tree.root_node().has_error(), "{source:?}");
|
|
323
|
+
}
|
|
370
324
|
}
|
|
371
325
|
|
|
372
326
|
#[test]
|
|
@@ -425,96 +379,8 @@ fn highlight_captures_use_leaf_ranges_even_during_recovery() {
|
|
|
425
379
|
}
|
|
426
380
|
|
|
427
381
|
#[test]
|
|
428
|
-
fn
|
|
429
|
-
let source = "(node . child: (_)+ @x !absent)";
|
|
430
|
-
let tree = parser().parse(source, None).unwrap();
|
|
431
|
-
assert!(!tree.root_node().has_error());
|
|
432
|
-
let mut cursor = tree.walk();
|
|
433
|
-
let mut depth = 0;
|
|
434
|
-
let mut actual = Vec::new();
|
|
435
|
-
'walk: loop {
|
|
436
|
-
let node = cursor.node();
|
|
437
|
-
actual.push((
|
|
438
|
-
depth,
|
|
439
|
-
node.kind(),
|
|
440
|
-
cursor.field_name(),
|
|
441
|
-
node.is_named(),
|
|
442
|
-
node.byte_range(),
|
|
443
|
-
));
|
|
444
|
-
assert_eq!(
|
|
445
|
-
node.start_position(),
|
|
446
|
-
Point {
|
|
447
|
-
row: 0,
|
|
448
|
-
column: node.start_byte()
|
|
449
|
-
}
|
|
450
|
-
);
|
|
451
|
-
assert_eq!(
|
|
452
|
-
node.end_position(),
|
|
453
|
-
Point {
|
|
454
|
-
row: 0,
|
|
455
|
-
column: node.end_byte()
|
|
456
|
-
}
|
|
457
|
-
);
|
|
458
|
-
if cursor.goto_first_child() {
|
|
459
|
-
depth += 1;
|
|
460
|
-
continue;
|
|
461
|
-
}
|
|
462
|
-
while !cursor.goto_next_sibling() {
|
|
463
|
-
if !cursor.goto_parent() {
|
|
464
|
-
break 'walk;
|
|
465
|
-
}
|
|
466
|
-
depth -= 1;
|
|
467
|
-
}
|
|
468
|
-
}
|
|
469
|
-
assert_eq!(
|
|
470
|
-
actual,
|
|
471
|
-
vec![
|
|
472
|
-
(0, "query", None, true, 0..31),
|
|
473
|
-
(1, "pattern", None, true, 0..31),
|
|
474
|
-
(2, "node_pattern", Some("body"), true, 0..31),
|
|
475
|
-
(3, "(", None, false, 0..1),
|
|
476
|
-
(3, "identifier", Some("node"), true, 1..5),
|
|
477
|
-
(3, "anchor", None, true, 6..7),
|
|
478
|
-
(3, "field_constraint", None, true, 8..22),
|
|
479
|
-
(4, "identifier", Some("name"), true, 8..13),
|
|
480
|
-
(4, ":", None, false, 13..14),
|
|
481
|
-
(4, "pattern", Some("pattern"), true, 15..22),
|
|
482
|
-
(5, "node_pattern", Some("body"), true, 15..18),
|
|
483
|
-
(6, "(", None, false, 15..16),
|
|
484
|
-
(6, "wildcard", Some("node"), true, 16..17),
|
|
485
|
-
(6, ")", None, false, 17..18),
|
|
486
|
-
(5, "quantifier", Some("quantifier"), true, 18..19),
|
|
487
|
-
(5, "capture", Some("capture"), true, 20..22),
|
|
488
|
-
(6, "@", None, false, 20..21),
|
|
489
|
-
(6, "identifier", Some("name"), true, 21..22),
|
|
490
|
-
(3, "negated_field", None, true, 23..30),
|
|
491
|
-
(4, "!", None, false, 23..24),
|
|
492
|
-
(4, "identifier", Some("name"), true, 24..30),
|
|
493
|
-
(3, ")", None, false, 30..31),
|
|
494
|
-
]
|
|
495
|
-
);
|
|
496
|
-
}
|
|
497
|
-
|
|
498
|
-
#[test]
|
|
499
|
-
fn bom_is_ignored_only_once_at_source_byte_zero() {
|
|
382
|
+
fn bom_at_an_included_range_start_is_not_a_source_bom() {
|
|
500
383
|
let mut parser = parser();
|
|
501
|
-
let source = "\u{feff}(node)\r\n";
|
|
502
|
-
let tree = parser.parse(source, None).unwrap();
|
|
503
|
-
assert!(!tree.root_node().has_error());
|
|
504
|
-
let pattern = tree.root_node().named_child(0).unwrap();
|
|
505
|
-
assert_eq!(pattern.byte_range(), 3..9);
|
|
506
|
-
assert_eq!(pattern.start_position(), Point { row: 0, column: 3 });
|
|
507
|
-
assert_eq!(tree.root_node().end_position(), Point { row: 1, column: 0 });
|
|
508
|
-
for invalid in [
|
|
509
|
-
" \u{feff}(node)",
|
|
510
|
-
"\u{feff}\u{feff}(node)",
|
|
511
|
-
"(node)\u{feff}",
|
|
512
|
-
] {
|
|
513
|
-
assert!(
|
|
514
|
-
parser.parse(invalid, None).unwrap().root_node().has_error(),
|
|
515
|
-
"{invalid:?}"
|
|
516
|
-
);
|
|
517
|
-
}
|
|
518
384
|
let embedded = "x\u{feff}(node)";
|
|
519
385
|
parser
|
|
520
386
|
.set_included_ranges(&[Range {
|
|
@@ -535,18 +401,3 @@ fn bom_is_ignored_only_once_at_source_byte_zero() {
|
|
|
535
401
|
.has_error()
|
|
536
402
|
);
|
|
537
403
|
}
|
|
538
|
-
|
|
539
|
-
#[test]
|
|
540
|
-
fn crlf_and_multibyte_comment_ranges_keep_source_coordinates() {
|
|
541
|
-
let mut parser = parser();
|
|
542
|
-
let source = "; 日\r\n(node)";
|
|
543
|
-
let tree = parser.parse(source, None).unwrap();
|
|
544
|
-
let root = tree.root_node();
|
|
545
|
-
assert!(!root.has_error());
|
|
546
|
-
let comment = root.named_child(0).unwrap();
|
|
547
|
-
assert_eq!(comment.byte_range(), 0..5);
|
|
548
|
-
assert_eq!(comment.end_position(), Point { row: 0, column: 5 });
|
|
549
|
-
let pattern = root.named_child(1).unwrap();
|
|
550
|
-
assert_eq!(pattern.byte_range(), 7..13);
|
|
551
|
-
assert_eq!(pattern.start_position(), Point { row: 1, column: 0 });
|
|
552
|
-
}
|