+91
-26
src/checker.rs
+91
-26
src/checker.rs
···
46
46
UndefinedSyntaxCapture(String, Location),
47
47
#[error("Undefined variable {0} at {1}")]
48
48
UndefinedVariable(String, Location),
49
+
#[error("Unused capture(s) {0} at {1}. Remove or prefix with _.")]
50
+
UnusedCaptures(String, Location),
49
51
#[error("{0}: {1} at {2}")]
50
52
Variable(VariableError, String, Location),
51
53
}
···
82
84
CheckError::NullableRegex(_, location) => *location,
83
85
CheckError::UndefinedSyntaxCapture(_, location) => *location,
84
86
CheckError::UndefinedVariable(_, location) => *location,
87
+
CheckError::UnusedCaptures(_, location) => *location,
85
88
CheckError::Variable(_, _, location) => *location,
86
89
};
87
90
writeln!(f, "{}", self.error)?;
···
163
166
ctx.file_query
164
167
.capture_index_for_name(FULL_MATCH)
165
168
.expect("missing capture index for full match") as usize;
169
+
170
+
let mut used_captures = HashSet::new();
166
171
for statement in &mut self.statements {
167
-
statement.check(&mut ctx)?;
172
+
let stmt_result = statement.check(&mut ctx)?;
173
+
used_captures.extend(stmt_result.used_captures);
174
+
}
175
+
176
+
let all_captures = self
177
+
.query
178
+
.capture_names()
179
+
.into_iter()
180
+
.filter(|cn| {
181
+
self.query
182
+
.capture_index_for_name(cn)
183
+
.expect("capture should have index")
184
+
!= self.full_match_stanza_capture_index as u32
185
+
})
186
+
.map(|cn| Identifier::from(cn.as_str()))
187
+
.collect::<HashSet<_>>();
188
+
let unused_captures = all_captures
189
+
.difference(&used_captures)
190
+
.filter(|i| !i.starts_with("_"))
191
+
.map(|i| format!("@{}", i))
192
+
.collect::<Vec<_>>();
193
+
if !unused_captures.is_empty() {
194
+
return Err(CheckError::UnusedCaptures(
195
+
unused_captures.join(" "),
196
+
self.location,
197
+
));
168
198
}
199
+
169
200
Ok(())
170
201
}
171
202
}
···
198
229
199
230
impl ast::DeclareImmutable {
200
231
fn check(&mut self, ctx: &mut CheckContext) -> Result<StatementResult, CheckError> {
232
+
let mut used_captures = HashSet::new();
201
233
let value = self.value.check(ctx)?;
202
-
let used_captures = value.used_captures.clone();
203
-
self.variable.check_add(ctx, value, false)?;
234
+
used_captures.extend(value.used_captures.iter().cloned());
235
+
let var_result = self.variable.check_add(ctx, value, false)?;
236
+
used_captures.extend(var_result.used_captures);
204
237
Ok(StatementResult { used_captures })
205
238
}
206
239
}
207
240
208
241
impl ast::DeclareMutable {
209
242
fn check(&mut self, ctx: &mut CheckContext) -> Result<StatementResult, CheckError> {
243
+
let mut used_captures = HashSet::new();
210
244
let value = self.value.check(ctx)?;
211
-
let used_captures = value.used_captures.clone();
212
-
self.variable.check_add(ctx, value, true)?;
245
+
used_captures.extend(value.used_captures.iter().cloned());
246
+
let var_result = self.variable.check_add(ctx, value, true)?;
247
+
used_captures.extend(var_result.used_captures);
213
248
Ok(StatementResult { used_captures })
214
249
}
215
250
}
216
251
217
252
impl ast::Assign {
218
253
fn check(&mut self, ctx: &mut CheckContext) -> Result<StatementResult, CheckError> {
254
+
let mut used_captures = HashSet::new();
219
255
let value = self.value.check(ctx)?;
220
-
let used_captures = value.used_captures.clone();
221
-
self.variable.check_set(ctx, value)?;
256
+
used_captures.extend(value.used_captures.iter().cloned());
257
+
let var_result = self.variable.check_set(ctx, value)?;
258
+
used_captures.extend(var_result.used_captures);
222
259
Ok(StatementResult { used_captures })
223
260
}
224
261
}
225
262
226
263
impl ast::CreateGraphNode {
227
264
fn check(&mut self, ctx: &mut CheckContext) -> Result<StatementResult, CheckError> {
228
-
self.node.check_add(
265
+
let node_result = self.node.check_add(
229
266
ctx,
230
267
ExpressionResult {
231
268
is_local: true,
···
235
272
false,
236
273
)?;
237
274
Ok(StatementResult {
238
-
used_captures: HashSet::default(),
275
+
used_captures: node_result.used_captures,
239
276
})
240
277
}
241
278
}
···
406
443
stanza_query: ctx.stanza_query,
407
444
locals: &mut loop_locals,
408
445
};
409
-
self.variable
446
+
let var_result = self
447
+
.variable
410
448
.check_add(&mut loop_ctx, value_result, false)?;
449
+
used_captures.extend(var_result.used_captures);
450
+
411
451
for statement in &mut self.statements {
412
452
let stmt_result = statement.check(&mut loop_ctx)?;
413
453
used_captures.extend(stmt_result.used_captures);
···
535
575
stanza_query: ctx.stanza_query,
536
576
locals: &mut loop_locals,
537
577
};
538
-
self.variable
578
+
let var_result = self
579
+
.variable
539
580
.check_add(&mut loop_ctx, value_result, false)?;
581
+
used_captures.extend(var_result.used_captures);
540
582
541
583
let element_result = self.element.check(&mut loop_ctx)?;
542
584
used_captures.extend(element_result.used_captures);
···
570
612
stanza_query: ctx.stanza_query,
571
613
locals: &mut loop_locals,
572
614
};
573
-
self.variable
615
+
let var_result = self
616
+
.variable
574
617
.check_add(&mut loop_ctx, value_result, false)?;
618
+
used_captures.extend(var_result.used_captures);
575
619
576
620
let element_result = self.element.check(&mut loop_ctx)?;
577
621
used_captures.extend(element_result.used_captures);
···
636
680
//-----------------------------------------------------------------------------
637
681
// Variables
638
682
683
+
#[derive(Clone, Debug)]
684
+
struct VariableResult {
685
+
used_captures: HashSet<Identifier>,
686
+
}
687
+
639
688
impl ast::Variable {
640
689
fn check_add(
641
690
&mut self,
642
691
ctx: &mut CheckContext,
643
692
value: ExpressionResult,
644
693
mutable: bool,
645
-
) -> Result<(), CheckError> {
694
+
) -> Result<VariableResult, CheckError> {
646
695
match self {
647
696
Self::Unscoped(v) => v.check_add(ctx, value, mutable),
648
697
Self::Scoped(v) => v.check_add(ctx, value, mutable),
···
653
702
&mut self,
654
703
ctx: &mut CheckContext,
655
704
value: ExpressionResult,
656
-
) -> Result<(), CheckError> {
705
+
) -> Result<VariableResult, CheckError> {
657
706
match self {
658
707
Self::Unscoped(v) => v.check_set(ctx, value),
659
708
Self::Scoped(v) => v.check_set(ctx, value),
···
674
723
ctx: &mut CheckContext,
675
724
value: ExpressionResult,
676
725
mutable: bool,
677
-
) -> Result<(), CheckError> {
726
+
) -> Result<VariableResult, CheckError> {
678
727
if ctx.globals.get(&self.name).is_some() {
679
728
return Err(CheckError::CannotHideGlobalVariable(
680
729
self.name.as_str().to_string(),
···
689
738
if mutable {
690
739
value.is_local = false;
691
740
}
741
+
let used_captures = value.used_captures.clone();
742
+
value.used_captures.clear(); // prevent used captures from escaping
743
+
// we may want to separate quantifier/is_local from
744
+
// the used_captures and only store the former in the
745
+
// future for a cleaner solution
692
746
ctx.locals
693
747
.add(self.name.clone(), value, mutable)
694
-
.map_err(|e| CheckError::Variable(e, format!("{}", self.name), self.location))
748
+
.map_err(|e| CheckError::Variable(e, format!("{}", self.name), self.location))?;
749
+
Ok(VariableResult { used_captures })
695
750
}
696
751
697
752
fn check_set(
698
753
&mut self,
699
754
ctx: &mut CheckContext,
700
755
value: ExpressionResult,
701
-
) -> Result<(), CheckError> {
756
+
) -> Result<VariableResult, CheckError> {
702
757
if ctx.globals.get(&self.name).is_some() {
703
758
return Err(CheckError::CannotSetGlobalVariable(
704
759
self.name.as_str().to_string(),
···
711
766
// Since we process all statement in order, we don't have info on later
712
767
// assignments, and can assume non-local to be sound.
713
768
value.is_local = false;
769
+
let used_captures = value.used_captures.clone();
770
+
value.used_captures.clear(); // prevent used captures from escaping
771
+
// we may want to separate quantifier/is_local from
772
+
// the used_captures and only store the former in the
773
+
// future for a cleaner solution
714
774
ctx.locals
715
775
.set(self.name.clone(), value)
716
-
.map_err(|e| CheckError::Variable(e, format!("{}", self.name), self.location))
776
+
.map_err(|e| CheckError::Variable(e, format!("{}", self.name), self.location))?;
777
+
Ok(VariableResult { used_captures })
717
778
}
718
779
719
780
fn check_get(&mut self, ctx: &mut CheckContext) -> Result<ExpressionResult, CheckError> {
···
733
794
ctx: &mut CheckContext,
734
795
_value: ExpressionResult,
735
796
_mutable: bool,
736
-
) -> Result<(), CheckError> {
737
-
self.scope.check(ctx)?;
738
-
Ok(())
797
+
) -> Result<VariableResult, CheckError> {
798
+
let scope_result = self.scope.check(ctx)?;
799
+
Ok(VariableResult {
800
+
used_captures: scope_result.used_captures,
801
+
})
739
802
}
740
803
741
804
fn check_set(
742
805
&mut self,
743
806
ctx: &mut CheckContext,
744
807
_value: ExpressionResult,
745
-
) -> Result<(), CheckError> {
746
-
self.scope.check(ctx)?;
747
-
Ok(())
808
+
) -> Result<VariableResult, CheckError> {
809
+
let scope_result = self.scope.check(ctx)?;
810
+
Ok(VariableResult {
811
+
used_captures: scope_result.used_captures,
812
+
})
748
813
}
749
814
750
815
fn check_get(&mut self, ctx: &mut CheckContext) -> Result<ExpressionResult, CheckError> {
751
-
self.scope.check(ctx)?;
816
+
let scope_result = self.scope.check(ctx)?;
752
817
Ok(ExpressionResult {
753
818
is_local: false,
754
819
quantifier: One, // FIXME we don't really know
755
-
used_captures: HashSet::new(),
820
+
used_captures: scope_result.used_captures,
756
821
})
757
822
}
758
823
}
+3
src/reference/mod.rs
+3
src/reference/mod.rs
···
197
197
//! example stanza, whose query is `(identifier) @id`, `@id` would refer to the `identifier` syntax
198
198
//! node that the stanza matched against.
199
199
//!
200
+
//! Unused query captures are considered errors, unless they start with an underscode. For example,
201
+
//! a capture `@id` must be used within the stanza, but `@_id` does not.
202
+
//!
200
203
//! # Variables
201
204
//!
202
205
//! You can use variables to pass information between different stanzas and statements in a graph
+25
-25
tests/it/execution.rs
+25
-25
tests/it/execution.rs
···
92
92
check_execution(
93
93
"pass",
94
94
indoc! {r#"
95
-
(module) @root
95
+
(module)
96
96
{
97
97
var new_node = #null
98
98
var current_node = (node)
···
138
138
check_execution(
139
139
"pass",
140
140
indoc! {r#"
141
-
(module) @root
141
+
(module)
142
142
{
143
143
var current_node = (node)
144
144
···
257
257
indoc! {r#"
258
258
global filename
259
259
260
-
(module) @root
260
+
(module)
261
261
{
262
262
node n
263
263
attr (n) filename = filename
···
277
277
indoc! {r#"
278
278
global pkgname = ""
279
279
280
-
(module) @root
280
+
(module)
281
281
{
282
282
node n
283
283
attr (n) pkgname = pkgname
···
320
320
check_execution(
321
321
"pass",
322
322
indoc! {r#"
323
-
(module) @root
323
+
(module)
324
324
{
325
325
let x = (node)
326
326
let y = x
···
338
338
check_execution(
339
339
"pass",
340
340
indoc! {r#"
341
-
(module) @root
341
+
(module)
342
342
{
343
343
node node0
344
344
attr (node0) val = (replace "accacc" (replace "abc" "b" "c") (replace "abc" "a" "b"))
···
356
356
fail_execution(
357
357
"pass",
358
358
indoc! {r#"
359
-
(module) @root
359
+
(module)
360
360
{
361
361
scan "abc" {
362
362
"^\\b" {
···
450
450
check_execution(
451
451
"pass",
452
452
indoc! {r#"
453
-
(module (pass_statement)? @x) @root
453
+
(module (pass_statement)? @x)
454
454
{
455
455
node node0
456
456
if some @x {
···
472
472
check_execution(
473
473
"pass",
474
474
indoc! {r#"
475
-
(module (import_statement)? @x) @root
475
+
(module (import_statement)? @x)
476
476
{
477
477
node node0
478
478
if none @x {
···
494
494
check_execution(
495
495
"pass",
496
496
indoc! {r#"
497
-
(module (import_statement)? @x (pass_statement)? @y) @root
497
+
(module (import_statement)? @x (pass_statement)? @y)
498
498
{
499
499
node node0
500
500
if none @x, some @y {
···
516
516
check_execution(
517
517
"pass",
518
518
indoc! {r#"
519
-
(module (import_statement)? @x (pass_statement)? @y) @root
519
+
(module (import_statement)? @x (pass_statement)? @y)
520
520
{
521
521
node node0
522
522
if some @x {
···
538
538
check_execution(
539
539
"pass",
540
540
indoc! {r#"
541
-
(module (import_statement)? @x) @root
541
+
(module (import_statement)? @x)
542
542
{
543
543
node node0
544
544
if some @x {
···
560
560
check_execution(
561
561
"pass",
562
562
indoc! {r#"
563
-
(module (import_statement)? @x) @root
563
+
(module (import_statement)?)
564
564
{
565
565
node node0
566
566
if #true {
···
582
582
check_execution(
583
583
"pass",
584
584
indoc! {r#"
585
-
(module (import_statement)? @x (import_statement)? @y) @root
585
+
(module (import_statement)? @x (import_statement)? @y)
586
586
{
587
587
node node0
588
588
if some @x {
···
605
605
pass
606
606
"#,
607
607
indoc! {r#"
608
-
(module (pass_statement)? @x) @root
608
+
(module (pass_statement)? @x)
609
609
{
610
610
let n = 1
611
611
if some @x {
···
629
629
pass
630
630
"#,
631
631
indoc! {r#"
632
-
(module (pass_statement)? @x) @root
632
+
(module (pass_statement)? @x)
633
633
{
634
634
var n = 1
635
635
if some @x {
···
653
653
pass
654
654
"#,
655
655
indoc! {r#"
656
-
(module (pass_statement)? @x) @root
656
+
(module (pass_statement)? @x)
657
657
{
658
658
var n = 1
659
659
if some @x {
···
679
679
pass
680
680
"#,
681
681
indoc! {r#"
682
-
(module (pass_statement)* @xs) @root
682
+
(module (pass_statement)* @xs)
683
683
{
684
684
var n = 0
685
685
for x in @xs {
···
703
703
pass
704
704
"#,
705
705
indoc! {r#"
706
-
(module (import_statement)* @xs) @root
706
+
(module (import_statement)* @xs)
707
707
{
708
708
var n = 0
709
709
for x in @xs {
···
727
727
pass
728
728
"#,
729
729
indoc! {r#"
730
-
(module) @root
730
+
(module)
731
731
{
732
732
var n = 0
733
733
for x in [#null, #null, #null] {
···
751
751
pass
752
752
"#,
753
753
indoc! {r#"
754
-
(module (pass_statement)* @xs) @root
754
+
(module (pass_statement)* @xs)
755
755
{
756
756
let n = 1
757
757
for x in @xs {
···
775
775
pass
776
776
"#,
777
777
indoc! {r#"
778
-
(module (pass_statement)* @xs) @root
778
+
(module (pass_statement)* @xs)
779
779
{
780
780
var n = 1
781
781
for x in @xs {
···
801
801
pass
802
802
"#,
803
803
indoc! {r#"
804
-
(module (pass_statement)+ @xs) @root
804
+
(module (pass_statement)+ @xs)
805
805
{
806
806
var n = 0
807
807
for x in @xs {
···
827
827
pass
828
828
"#,
829
829
indoc! {r#"
830
-
(module (pass_statement)* @xs) @root
830
+
(module (pass_statement)* @xs)
831
831
{
832
832
node node0
833
833
attr (node0) val = [ (named-child-index x) for x in @xs ]
···
849
849
pass
850
850
"#,
851
851
indoc! {r#"
852
-
(module (pass_statement)* @xs) @root
852
+
(module (pass_statement)* @xs)
853
853
{
854
854
node node0
855
855
attr (node0) val = { (source-text x) for x in @xs }
+11
-11
tests/it/functions.rs
+11
-11
tests/it/functions.rs
···
60
60
check_execution(
61
61
"pass",
62
62
indoc! {r#"
63
-
(module) @root
63
+
(module)
64
64
{
65
65
node n
66
66
attr (n) eq = (eq #true #true)
···
78
78
check_execution(
79
79
"pass",
80
80
indoc! {r#"
81
-
(module) @root
81
+
(module)
82
82
{
83
83
node n
84
84
attr (n) eq = (eq #true #false)
···
96
96
fail_execution(
97
97
"pass",
98
98
indoc! {r#"
99
-
(module) @root
99
+
(module)
100
100
{
101
101
node n
102
102
attr (n) eq = (eq #true "false")
···
110
110
check_execution(
111
111
"pass",
112
112
indoc! {r#"
113
-
(module) @root
113
+
(module)
114
114
{
115
115
node n
116
116
attr (n) str = (format "{} : {{ {} }}" "foo" #null)
···
128
128
fail_execution(
129
129
"pass",
130
130
indoc! {r#"
131
-
(module) @root
131
+
(module)
132
132
{
133
133
node n
134
134
attr (n) str = (format "{} : {{ {} }}" "foo")
···
142
142
fail_execution(
143
143
"pass",
144
144
indoc! {r#"
145
-
(module) @root
145
+
(module)
146
146
{
147
147
node n
148
148
attr (n) str = (format "{} : {{ {} }}" "foo" #null 42)
···
156
156
fail_execution(
157
157
"pass",
158
158
indoc! {r#"
159
-
(module) @root
159
+
(module)
160
160
{
161
161
node n
162
162
attr (n) str = (format "{} : { {} }}" "foo" #null)
···
170
170
fail_execution(
171
171
"pass",
172
172
indoc! {r#"
173
-
(module) @root
173
+
(module)
174
174
{
175
175
node n
176
176
attr (n) str = (format "{} : {{ {} }" "foo" #null)
···
184
184
check_execution(
185
185
"pass",
186
186
indoc! {r#"
187
-
(module) @root
187
+
(module)
188
188
{
189
189
node n
190
190
attr (n) xs = (concat [1, 2] [] [3, 4, 5])
···
202
202
check_execution(
203
203
"pass",
204
204
indoc! {r#"
205
-
(module) @root
205
+
(module)
206
206
{
207
207
node n
208
208
attr (n) str = (join [1, 2, 3] ".")
···
220
220
check_execution(
221
221
"pass",
222
222
indoc! {r#"
223
-
(module) @root
223
+
(module)
224
224
{
225
225
node n
226
226
attr (n) str = (join [1, 2, 3])
+41
-41
tests/it/lazy_execution.rs
+41
-41
tests/it/lazy_execution.rs
···
91
91
check_execution(
92
92
"pass",
93
93
indoc! {r#"
94
-
(module) @root
94
+
(module)
95
95
{
96
96
var new_node = #null
97
97
var current_node = (node)
···
137
137
check_execution(
138
138
"pass",
139
139
indoc! {r#"
140
-
(module) @root
140
+
(module)
141
141
{
142
142
var current_node = (node)
143
143
···
258
258
indoc! {r#"
259
259
global filename
260
260
261
-
(module) @root
261
+
(module)
262
262
{
263
263
node n
264
264
attr (n) filename = filename
···
278
278
indoc! {r#"
279
279
global pkgname = ""
280
280
281
-
(module) @root
281
+
(module)
282
282
{
283
283
node n
284
284
attr (n) pkgname = pkgname
···
311
311
check_execution(
312
312
"pass",
313
313
indoc! {r#"
314
-
(module) @root
314
+
(module)
315
315
{
316
316
let x = (node)
317
317
let y = x
···
334
334
check_execution(
335
335
"pass",
336
336
indoc! {r#"
337
-
(module) @root
337
+
(module)
338
338
{
339
339
node node0
340
340
attr (node0) val = (replace "accacc" (replace "abc" "b" "c") (replace "abc" "a" "b"))
···
352
352
fail_execution(
353
353
"pass",
354
354
indoc! {r#"
355
-
(module) @root
355
+
(module)
356
356
{
357
357
scan "abc" {
358
358
"^\\b" {
···
446
446
check_execution(
447
447
"pass",
448
448
indoc! {r#"
449
-
(module (pass_statement)? @x) @root
449
+
(module (pass_statement)? @x)
450
450
{
451
451
node node0
452
452
if some @x {
···
468
468
check_execution(
469
469
"pass",
470
470
indoc! {r#"
471
-
(module (import_statement)? @x) @root
471
+
(module (import_statement)? @x)
472
472
{
473
473
node node0
474
474
if none @x {
···
490
490
check_execution(
491
491
"pass",
492
492
indoc! {r#"
493
-
(module (import_statement)? @x (pass_statement)? @y) @root
493
+
(module (import_statement)? @x (pass_statement)? @y)
494
494
{
495
495
node node0
496
496
if none @x, some @y {
···
512
512
check_execution(
513
513
"pass",
514
514
indoc! {r#"
515
-
(module (import_statement)? @x (pass_statement)? @y) @root
515
+
(module (import_statement)? @x (pass_statement)? @y)
516
516
{
517
517
node node0
518
518
if some @x {
···
534
534
check_execution(
535
535
"pass",
536
536
indoc! {r#"
537
-
(module (import_statement)? @x) @root
537
+
(module (import_statement)? @x)
538
538
{
539
539
node node0
540
540
if some @x {
···
556
556
check_execution(
557
557
"pass",
558
558
indoc! {r#"
559
-
(module (import_statement)? @x) @root
559
+
(module (import_statement)?)
560
560
{
561
561
node node0
562
562
if #true {
···
578
578
check_execution(
579
579
"pass",
580
580
indoc! {r#"
581
-
(module (import_statement)? @x (import_statement)? @y) @root
581
+
(module (import_statement)? @x (import_statement)? @y)
582
582
{
583
583
node node0
584
584
if some @x {
···
601
601
pass
602
602
"#,
603
603
indoc! {r#"
604
-
(module (pass_statement)? @x) @root
604
+
(module (pass_statement)? @x)
605
605
{
606
606
let n = 1
607
607
if some @x {
···
625
625
pass
626
626
"#,
627
627
indoc! {r#"
628
-
(module (pass_statement)? @x) @root
628
+
(module (pass_statement)? @x)
629
629
{
630
630
var n = 1
631
631
if some @x {
···
649
649
pass
650
650
"#,
651
651
indoc! {r#"
652
-
(module (pass_statement)? @x) @root
652
+
(module (pass_statement)? @x)
653
653
{
654
654
var n = 1
655
655
if some @x {
···
675
675
pass
676
676
"#,
677
677
indoc! {r#"
678
-
(module (pass_statement)* @xs) @root
678
+
(module (pass_statement)* @xs)
679
679
{
680
680
var n = 0
681
681
for x in @xs {
···
699
699
pass
700
700
"#,
701
701
indoc! {r#"
702
-
(module (import_statement)* @xs) @root
702
+
(module (import_statement)* @xs)
703
703
{
704
704
var n = 0
705
705
for x in @xs {
···
723
723
pass
724
724
"#,
725
725
indoc! {r#"
726
-
(module) @root
726
+
(module)
727
727
{
728
728
var n = 0
729
729
for x in [#null, #null, #null] {
···
747
747
pass
748
748
"#,
749
749
indoc! {r#"
750
-
(module (pass_statement)* @xs) @root
750
+
(module (pass_statement)* @xs)
751
751
{
752
752
let n = 1
753
753
for x in @xs {
···
771
771
pass
772
772
"#,
773
773
indoc! {r#"
774
-
(module (pass_statement)* @xs) @root
774
+
(module (pass_statement)* @xs)
775
775
{
776
776
var n = 1
777
777
for x in @xs {
···
797
797
pass
798
798
"#,
799
799
indoc! {r#"
800
-
(module (pass_statement)+ @xs) @root
800
+
(module (pass_statement)+ @xs)
801
801
{
802
802
var n = 0
803
803
for x in @xs {
···
823
823
pass
824
824
"#,
825
825
indoc! {r#"
826
-
(module (pass_statement)* @xs) @root
826
+
(module (pass_statement)* @xs)
827
827
{
828
828
node node0
829
829
attr (node0) val = [ (named-child-index x) for x in @xs ]
···
845
845
pass
846
846
"#,
847
847
indoc! {r#"
848
-
(module (pass_statement)* @xs) @root
848
+
(module (pass_statement)* @xs)
849
849
{
850
850
node node0
851
851
attr (node0) val = { (source-text x) for x in @xs }
···
916
916
check_execution(
917
917
"pass",
918
918
indoc! {r#"
919
-
(module) @root
919
+
(module)
920
920
{
921
921
node node0
922
922
}
···
951
951
check_execution(
952
952
"pass",
953
953
indoc! {r#"
954
-
(module) @root
954
+
(module)
955
955
{
956
956
node node0
957
957
node node1
···
971
971
check_execution(
972
972
"pass",
973
973
indoc! {r#"
974
-
(module) @root
974
+
(module)
975
975
{
976
976
node node0
977
977
node node1
···
997
997
check_execution(
998
998
"pass",
999
999
indoc! {r#"
1000
-
(module) @root
1000
+
(module)
1001
1001
{
1002
1002
var node = #null
1003
1003
···
1063
1063
print(a.d.f)
1064
1064
"#},
1065
1065
indoc! {r#"
1066
-
(call function:(_)@fun arguments: (argument_list (_)@arg)) {
1066
+
(call function:(_) arguments: (argument_list (_)@arg)) {
1067
1067
; let @arg.no_object.lala = 3 ; error
1068
1068
let @arg.object.lala = 3
1069
1069
let @arg.object.object.lala = 12
···
1083
1083
check_execution(
1084
1084
"pass",
1085
1085
indoc! {r#"
1086
-
(module) @root
1086
+
(module)
1087
1087
{
1088
1088
node n
1089
1089
···
1110
1110
check_execution(
1111
1111
"pass",
1112
1112
indoc! {r#"
1113
-
(module) @root
1113
+
(module)
1114
1114
{
1115
1115
node n
1116
1116
···
1137
1137
check_execution(
1138
1138
"pass",
1139
1139
indoc! {r#"
1140
-
(module) @root
1140
+
(module)
1141
1141
{
1142
1142
node n
1143
1143
···
1177
1177
check_execution(
1178
1178
"pass",
1179
1179
indoc! {r#"
1180
-
(module) @root
1180
+
(module)
1181
1181
{
1182
1182
node n
1183
1183
···
1217
1217
check_execution(
1218
1218
"pass",
1219
1219
indoc! {r#"
1220
-
(module) @root
1220
+
(module)
1221
1221
{
1222
1222
node n
1223
1223
···
1256
1256
check_execution(
1257
1257
"pass",
1258
1258
indoc! {r#"
1259
-
(module) @root
1259
+
(module)
1260
1260
{
1261
1261
var x = 0
1262
1262
var y = 0
···
1286
1286
check_execution(
1287
1287
"pass",
1288
1288
indoc! {r#"
1289
-
(module) @root
1289
+
(module)
1290
1290
{
1291
1291
var x = 0
1292
1292
var y = 0
···
1322
1322
check_execution(
1323
1323
"pass",
1324
1324
indoc! {r#"
1325
-
(module) @root
1325
+
(module)
1326
1326
{
1327
1327
var x = 0
1328
1328
···
1353
1353
check_execution(
1354
1354
"pass",
1355
1355
indoc! {r#"
1356
-
(module) @root
1356
+
(module)
1357
1357
{
1358
1358
var x = 0
1359
1359
var y = 0
···
1394
1394
check_execution(
1395
1395
"pass",
1396
1396
indoc! {r#"
1397
-
(module) @root
1397
+
(module)
1398
1398
{
1399
1399
let x = (node)
1400
1400
attr ((node)) ref = x
···
1416
1416
check_execution(
1417
1417
"pass",
1418
1418
indoc! {r#"
1419
-
(module) @root
1419
+
(module)
1420
1420
{
1421
1421
var x = #null
1422
1422
set x = (node)
+23
-3
tests/it/parser.rs
+23
-3
tests/it/parser.rs
···
16
16
fn can_parse_blocks() {
17
17
let source = r#"
18
18
(function_definition
19
-
name: (identifier) @cap1) @cap2
19
+
name: (identifier) @_cap1) @cap2
20
20
{
21
21
node loc1
22
22
node @cap2.prop1
···
1079
1079
#[test]
1080
1080
fn can_parse_list_comprehension() {
1081
1081
let source = r#"
1082
-
(module (_)* @xs)@mod
1082
+
(module (_)* @xs)
1083
1083
{
1084
1084
print [ (named-child-index x) for x in @xs ]
1085
1085
}
···
1132
1132
#[test]
1133
1133
fn can_parse_set_comprehension() {
1134
1134
let source = r#"
1135
-
(module (_)* @xs)@mod
1135
+
(module (_)* @xs)
1136
1136
{
1137
1137
print { (named-child-index x) for x in @xs }
1138
1138
}
···
1579
1579
assert_eq!(err.column, 13, "expected column 13, got {}", err.column);
1580
1580
assert_eq!(err.offset, 112, "expected offset 112, got {}", err.offset);
1581
1581
}
1582
+
1583
+
#[test]
1584
+
fn cannot_parse_unused_capture() {
1585
+
let source = r#"
1586
+
(function_definition name: (identifier) @name) {
1587
+
}
1588
+
"#;
1589
+
if let Ok(_) = File::from_str(tree_sitter_python::language(), source) {
1590
+
panic!("Parse succeeded unexpectedly");
1591
+
}
1592
+
}
1593
+
1594
+
#[test]
1595
+
fn can_parse_explicitly_unused_capture() {
1596
+
let source = r#"
1597
+
(function_definition name: (identifier) @_name) {
1598
+
}
1599
+
"#;
1600
+
File::from_str(tree_sitter_python::language(), source).expect("parse to succeed");
1601
+
}