Skip to content

Commit ddb12dc

Browse files
committed
query: Return error on unclosed tree pattern in alternation
Fixes tree-sitter#1436
1 parent e784138 commit ddb12dc

File tree

2 files changed

+57
-28
lines changed

2 files changed

+57
-28
lines changed

cli/src/tests/query_test.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ fn test_query_errors_on_invalid_syntax() {
7878
.join("\n")
7979
);
8080

81+
// Empty tree pattern
8182
assert_eq!(
8283
Query::new(language, r#"((identifier) ()"#)
8384
.unwrap_err()
@@ -88,6 +89,8 @@ fn test_query_errors_on_invalid_syntax() {
8889
]
8990
.join("\n")
9091
);
92+
93+
// Empty alternation
9194
assert_eq!(
9295
Query::new(language, r#"((identifier) [])"#)
9396
.unwrap_err()
@@ -98,6 +101,8 @@ fn test_query_errors_on_invalid_syntax() {
98101
]
99102
.join("\n")
100103
);
104+
105+
// Unclosed sibling expression with predicate
101106
assert_eq!(
102107
Query::new(language, r#"((identifier) (#a)"#)
103108
.unwrap_err()
@@ -108,6 +113,8 @@ fn test_query_errors_on_invalid_syntax() {
108113
]
109114
.join("\n")
110115
);
116+
117+
// Unclosed predicate
111118
assert_eq!(
112119
Query::new(language, r#"((identifier) @x (#eq? @x a"#)
113120
.unwrap_err()
@@ -144,6 +151,7 @@ fn test_query_errors_on_invalid_syntax() {
144151
.join("\n")
145152
);
146153

154+
// Unclosed alternation within a tree
147155
// tree-sitter/tree-sitter/issues/968
148156
assert_eq!(
149157
Query::new(get_language("c"), r#"(parameter_list [ ")" @foo)"#)
@@ -155,6 +163,22 @@ fn test_query_errors_on_invalid_syntax() {
155163
]
156164
.join("\n")
157165
);
166+
167+
// Unclosed tree within an alternation
168+
// tree-sitter/tree-sitter/issues/1436
169+
assert_eq!(
170+
Query::new(
171+
get_language("python"),
172+
r#"[(unary_operator (_) @operand) (not_operator (_) @operand]"#
173+
)
174+
.unwrap_err()
175+
.message,
176+
[
177+
r#"[(unary_operator (_) @operand) (not_operator (_) @operand]"#,
178+
r#" ^"#
179+
]
180+
.join("\n")
181+
);
158182
});
159183
}
160184

lib/src/query.c

Lines changed: 33 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1655,11 +1655,14 @@ static TSQueryError ts_query__parse_pattern(
16551655
is_immediate
16561656
);
16571657

1658-
if (e == PARENT_DONE && stream->next == ']' && branch_step_indices.size > 0) {
1659-
stream_advance(stream);
1660-
break;
1661-
} else if (e) {
1662-
if (e == PARENT_DONE) e = TSQueryErrorSyntax;
1658+
if (e == PARENT_DONE) {
1659+
if (stream->next == ']' && branch_step_indices.size > 0) {
1660+
stream_advance(stream);
1661+
break;
1662+
}
1663+
e = TSQueryErrorSyntax;
1664+
}
1665+
if (e) {
16631666
array_delete(&branch_step_indices);
16641667
return e;
16651668
}
@@ -1707,12 +1710,14 @@ static TSQueryError ts_query__parse_pattern(
17071710
depth,
17081711
child_is_immediate
17091712
);
1710-
if (e == PARENT_DONE && stream->next == ')') {
1711-
stream_advance(stream);
1712-
break;
1713-
} else if (e) {
1714-
return e;
1713+
if (e == PARENT_DONE) {
1714+
if (stream->next == ')') {
1715+
stream_advance(stream);
1716+
break;
1717+
}
1718+
e = TSQueryErrorSyntax;
17151719
}
1720+
if (e) return e;
17161721

17171722
child_is_immediate = false;
17181723
}
@@ -1853,28 +1858,28 @@ static TSQueryError ts_query__parse_pattern(
18531858
depth + 1,
18541859
child_is_immediate
18551860
);
1856-
if (e == PARENT_DONE && stream->next == ')') {
1857-
if (child_is_immediate) {
1858-
if (last_child_step_index == 0) {
1859-
return TSQueryErrorSyntax;
1861+
if (e == PARENT_DONE) {
1862+
if (stream->next == ')') {
1863+
if (child_is_immediate) {
1864+
if (last_child_step_index == 0) return TSQueryErrorSyntax;
1865+
self->steps.contents[last_child_step_index].is_last_child = true;
18601866
}
1861-
self->steps.contents[last_child_step_index].is_last_child = true;
1862-
}
18631867

1864-
if (negated_field_count) {
1865-
ts_query__add_negated_fields(
1866-
self,
1867-
starting_step_index,
1868-
negated_field_ids,
1869-
negated_field_count
1870-
);
1871-
}
1868+
if (negated_field_count) {
1869+
ts_query__add_negated_fields(
1870+
self,
1871+
starting_step_index,
1872+
negated_field_ids,
1873+
negated_field_count
1874+
);
1875+
}
18721876

1873-
stream_advance(stream);
1874-
break;
1875-
} else if (e) {
1876-
return e;
1877+
stream_advance(stream);
1878+
break;
1879+
}
1880+
e = TSQueryErrorSyntax;
18771881
}
1882+
if (e) return e;
18781883

18791884
last_child_step_index = step_index;
18801885
child_is_immediate = false;

0 commit comments

Comments
 (0)