1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
//! Separator text: a run of the grammar's extras that are no rule, as
//! `separatorText` in `js/src/grammar-runtime/executor.js` reads it.
use super::program::{Expr, Trivia};
/// Whether the text of `[start, end)` is separators alone, each the longest
/// match of an extra of no kind that ends within it. An extra the matcher
/// cannot read without the executor (a rule reference) matches nothing.
pub(super) fn separator_text(trivia: &[Trivia], bytes: &[u8], start: usize, end: usize) -> bool {
if start >= end {
return false;
}
let mut at = start;
while at < end {
let mut next = at;
for item in trivia.iter().filter(|item| item.kind.is_none()) {
if let Some(reach) = ends(&item.expression, bytes, at).into_iter().max()
&& reach > next
&& reach <= end
{
next = reach;
}
}
if next == at {
return false;
}
at = next;
}
true
}
/// The ends of the matches of the lexical `expr` at `position`.
fn ends(expr: &Expr, bytes: &[u8], position: usize) -> Vec<usize> {
match expr {
Expr::Empty => vec![position],
Expr::Terminal { matcher, .. } => matcher
.matches(bytes, position, bytes.len())
.into_iter()
.collect(),
Expr::Seq(items) => items.iter().fold(vec![position], |starts, item| {
let mut found = Vec::new();
for start in starts {
for reach in ends(item, bytes, start) {
if !found.contains(&reach) {
found.push(reach);
}
}
}
found
}),
Expr::Choice { items, .. } | Expr::Longest(items) => {
let mut found = Vec::new();
for item in items {
for reach in ends(item, bytes, position) {
if !found.contains(&reach) {
found.push(reach);
}
}
}
found
}
Expr::Repeat { item, min, max } => {
let mut found = Vec::new();
let mut frontier = vec![position];
let mut count = 0;
while !frontier.is_empty() {
if count >= *min {
for &reach in &frontier {
if !found.contains(&reach) {
found.push(reach);
}
}
}
if max.is_some_and(|max| count >= max) {
break;
}
let mut next = Vec::new();
for start in frontier {
for reach in ends(item, bytes, start) {
// An iteration of no width ends the repetition.
if reach > start && !next.contains(&reach) {
next.push(reach);
}
}
}
frontier = next;
count += 1;
}
found
}
Expr::And(item) => {
if ends(item, bytes, position).is_empty() {
Vec::new()
} else {
vec![position]
}
}
Expr::Not(item) => {
if ends(item, bytes, position).is_empty() {
vec![position]
} else {
Vec::new()
}
}
Expr::Capture { item, .. }
| Expr::Alias { item, .. }
| Expr::Precedence { item, .. }
| Expr::DynamicPrecedence { item, .. }
| Expr::LexicalPrecedence { item, .. }
| Expr::Token(item)
| Expr::ImmediateToken(item) => ends(item, bytes, position),
_ => Vec::new(),
}
}