corvus_json_schema 0.1.3 → 0.1.4
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.
- checksums.yaml +4 -4
- data/Cargo.lock +2 -12
- data/README.md +10 -1
- data/THIRD-PARTY-NOTICES.txt +95 -0
- data/VERSIONHISTORY.md +24 -0
- data/ext/corvus_json_schema/Cargo.toml +2 -2
- data/ext/corvus_json_schema/clippy.toml +3 -4
- data/ext/corvus_json_schema/src/lib.rs +42 -19
- data/ext/corvus_json_schema/vendor/corvus-json-schema/Cargo.toml +9 -4
- data/ext/corvus_json_schema/vendor/corvus-json-schema/README.md +87 -4
- data/ext/corvus_json_schema/vendor/corvus-json-schema/THIRD-PARTY-NOTICES.txt +93 -0
- data/ext/corvus_json_schema/vendor/corvus-json-schema/src/compiler.rs +88 -96
- data/ext/corvus_json_schema/vendor/corvus-json-schema/src/document.rs +2 -2
- data/ext/corvus_json_schema/vendor/corvus-json-schema/src/ecmaregex/charset.rs +271 -0
- data/ext/corvus_json_schema/vendor/corvus-json-schema/src/ecmaregex/compile.rs +941 -0
- data/ext/corvus_json_schema/vendor/corvus-json-schema/src/ecmaregex/dfa.rs +366 -0
- data/ext/corvus_json_schema/vendor/corvus-json-schema/src/ecmaregex/fold.rs +138 -0
- data/ext/corvus_json_schema/vendor/corvus-json-schema/src/ecmaregex/mod.rs +329 -0
- data/ext/corvus_json_schema/vendor/corvus-json-schema/src/ecmaregex/parse.rs +1128 -0
- data/ext/corvus_json_schema/vendor/corvus-json-schema/src/ecmaregex/re2.rs +129 -0
- data/ext/corvus_json_schema/vendor/corvus-json-schema/src/ecmaregex/tables_gen.rs +6685 -0
- data/ext/corvus_json_schema/vendor/corvus-json-schema/src/ecmaregex/tests.rs +1672 -0
- data/ext/corvus_json_schema/vendor/corvus-json-schema/src/ecmaregex/ucd.rs +309 -0
- data/ext/corvus_json_schema/vendor/corvus-json-schema/src/ecmaregex/units.rs +165 -0
- data/ext/corvus_json_schema/vendor/corvus-json-schema/src/ecmaregex/vm.rs +981 -0
- data/ext/corvus_json_schema/vendor/corvus-json-schema/src/eval/plan/fused.rs +13 -9
- data/ext/corvus_json_schema/vendor/corvus-json-schema/src/eval/plan.rs +12 -11
- data/ext/corvus_json_schema/vendor/corvus-json-schema/src/eval.rs +105 -73
- data/ext/corvus_json_schema/vendor/corvus-json-schema/src/formats.rs +95 -1
- data/ext/corvus_json_schema/vendor/corvus-json-schema/src/lib.rs +165 -30
- data/ext/corvus_json_schema/vendor/corvus-json-schema/src/loader.rs +19 -21
- data/ext/corvus_json_schema/vendor/corvus-json-schema/src/numbers.rs +1 -1
- data/ext/corvus_json_schema/vendor/corvus-json-schema/src/options.rs +199 -4
- data/ext/corvus_json_schema/vendor/corvus-json-schema/src/pattern.rs +758 -79
- data/ext/corvus_json_schema/vendor/corvus-json-schema/src/uri.rs +4 -4
- data/lib/corvus_json_schema/version.rb +1 -1
- data/lib/corvus_json_schema.rb +13 -3
- metadata +16 -2
|
@@ -0,0 +1,1128 @@
|
|
|
1
|
+
//! The parser: a pattern to its syntax tree, in either grammar, with the limits of size (`parse.go`).
|
|
2
|
+
|
|
3
|
+
use std::collections::HashMap;
|
|
4
|
+
use std::fmt;
|
|
5
|
+
use std::sync::{Arc, LazyLock};
|
|
6
|
+
|
|
7
|
+
use super::Rune;
|
|
8
|
+
use super::charset::{CharSet, DIGIT_PAIRS, DOT_SET, MAX_RUNE, SPACE_PAIRS, WORD_PAIRS, property_set};
|
|
9
|
+
use super::fold::{FOLD_WORD_SET, NOT_FOLD_WORD_SET, fold_closure};
|
|
10
|
+
use super::ucd;
|
|
11
|
+
use super::units::{high_surrogate, low_surrogate};
|
|
12
|
+
|
|
13
|
+
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
|
14
|
+
pub(crate) enum NodeKind {
|
|
15
|
+
Empty,
|
|
16
|
+
Char,
|
|
17
|
+
Set,
|
|
18
|
+
Cat,
|
|
19
|
+
Alt,
|
|
20
|
+
Group,
|
|
21
|
+
Repeat,
|
|
22
|
+
Bol,
|
|
23
|
+
Eol,
|
|
24
|
+
/// `LineStart` and `LineEnd` are `^` and `$` inside a group with the m modifier.
|
|
25
|
+
LineStart,
|
|
26
|
+
LineEnd,
|
|
27
|
+
WordBoundary,
|
|
28
|
+
NotWordBoundary,
|
|
29
|
+
Look,
|
|
30
|
+
Backref,
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/// The max of a quantifier with no upper bound.
|
|
34
|
+
pub(crate) const UNBOUNDED: i32 = -1;
|
|
35
|
+
|
|
36
|
+
/// Caps the bounds of a counted quantifier. No text that fits in memory reaches a larger count.
|
|
37
|
+
const MAX_COUNT: i64 = i32::MAX as i64;
|
|
38
|
+
|
|
39
|
+
// The limits on the size of one pattern. A pattern may come from outside, so reading and compiling one must take
|
|
40
|
+
// bounded time and memory whatever it holds. A pattern over a limit is refused with a `TooLargeError`, which is not
|
|
41
|
+
// the error of a pattern that is not valid.
|
|
42
|
+
|
|
43
|
+
/// The longest pattern that is read, in bytes of UTF-8.
|
|
44
|
+
pub const MAX_PATTERN_LENGTH: usize = 1 << 20;
|
|
45
|
+
/// Caps the depth of groups, which bounds the recursion of the parser and of the compilers.
|
|
46
|
+
pub const MAX_NESTING: usize = 1000;
|
|
47
|
+
/// The largest size a pattern may have, in the bytes the parser counts for it: `NODE_SIZE` for each node of its
|
|
48
|
+
/// syntax tree, and `RANGE_SIZE` for each range of a class as its members are read, for each range a case
|
|
49
|
+
/// insensitive group or a negated property adds, for each alternative that encloses a named group and for each
|
|
50
|
+
/// group that shares its name. The tree, the program compiled from it and the time to make both are proportional to
|
|
51
|
+
/// that size, so it bounds them all: a pattern at the limit takes a few milliseconds and a few megabytes.
|
|
52
|
+
pub const MAX_SIZE: usize = 1 << 20;
|
|
53
|
+
const NODE_SIZE: usize = 32;
|
|
54
|
+
const RANGE_SIZE: usize = 8;
|
|
55
|
+
|
|
56
|
+
/// Which limit of size a pattern is over.
|
|
57
|
+
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
|
58
|
+
pub enum Limit {
|
|
59
|
+
/// [`MAX_PATTERN_LENGTH`].
|
|
60
|
+
Length,
|
|
61
|
+
/// [`MAX_NESTING`].
|
|
62
|
+
Nesting,
|
|
63
|
+
/// [`MAX_SIZE`].
|
|
64
|
+
Size,
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
impl Limit {
|
|
68
|
+
/// The name of the limit: "length", "nesting" or "size".
|
|
69
|
+
pub fn name(self) -> &'static str {
|
|
70
|
+
match self {
|
|
71
|
+
Limit::Length => "length",
|
|
72
|
+
Limit::Nesting => "nesting",
|
|
73
|
+
Limit::Size => "size",
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/// Reports a pattern over one of the limits of size. `limit` names the limit and `value` is its value. The pattern
|
|
79
|
+
/// was not read to its end, so the error says nothing of whether it is valid.
|
|
80
|
+
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
|
81
|
+
pub struct TooLargeError {
|
|
82
|
+
pub limit: Limit,
|
|
83
|
+
pub value: usize,
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
impl fmt::Display for TooLargeError {
|
|
87
|
+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
88
|
+
match self.limit {
|
|
89
|
+
Limit::Length => write!(f, "the pattern is longer than {} bytes", self.value),
|
|
90
|
+
Limit::Nesting => write!(f, "the groups of the pattern nest more than {} deep", self.value),
|
|
91
|
+
Limit::Size => write!(f, "the pattern has a size of more than {} bytes when it is read", self.value),
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/// Why a pattern was not read: it is over a limit of size, or it is not valid under the chosen grammar.
|
|
97
|
+
#[derive(Clone, Debug, PartialEq, Eq)]
|
|
98
|
+
pub(crate) enum ParseError {
|
|
99
|
+
TooLarge(TooLargeError),
|
|
100
|
+
/// The reason, and the offset in the pattern's characters.
|
|
101
|
+
Syntax(&'static str, usize),
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
type Parse<T> = Result<T, ParseError>;
|
|
105
|
+
|
|
106
|
+
/// One element of the syntax tree of a pattern.
|
|
107
|
+
#[derive(Clone, Debug)]
|
|
108
|
+
pub(crate) struct Node {
|
|
109
|
+
pub kind: NodeKind,
|
|
110
|
+
/// The code point of a `Char`.
|
|
111
|
+
pub r: Rune,
|
|
112
|
+
/// The class of a `Set`.
|
|
113
|
+
pub set: Option<Arc<CharSet>>,
|
|
114
|
+
/// The children of `Cat` and `Alt`, and the one child of `Group`, `Repeat` and `Look`.
|
|
115
|
+
pub subs: Vec<Node>,
|
|
116
|
+
/// `min`, `max` and `lazy` describe a `Repeat`.
|
|
117
|
+
pub min: i32,
|
|
118
|
+
pub max: i32,
|
|
119
|
+
pub lazy: bool,
|
|
120
|
+
/// The number of the capturing group of a `Group`, counted from 1.
|
|
121
|
+
pub group: i32,
|
|
122
|
+
/// The groups a `Backref` names. A name can belong to several groups in separate alternatives, of which at most
|
|
123
|
+
/// one has taken part at any time.
|
|
124
|
+
pub groups: Vec<i32>,
|
|
125
|
+
/// The group name of a named backreference until it is resolved.
|
|
126
|
+
pub name: Vec<Rune>,
|
|
127
|
+
/// Marks a `Backref`, `WordBoundary` or `NotWordBoundary` inside a case-insensitive group.
|
|
128
|
+
pub fold: bool,
|
|
129
|
+
/// `behind` and `negative` describe a `Look`.
|
|
130
|
+
pub behind: bool,
|
|
131
|
+
pub negative: bool,
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
impl Node {
|
|
135
|
+
pub(crate) fn new(kind: NodeKind) -> Node {
|
|
136
|
+
Node {
|
|
137
|
+
kind,
|
|
138
|
+
r: 0,
|
|
139
|
+
set: None,
|
|
140
|
+
subs: Vec::new(),
|
|
141
|
+
min: 0,
|
|
142
|
+
max: 0,
|
|
143
|
+
lazy: false,
|
|
144
|
+
group: 0,
|
|
145
|
+
groups: Vec::new(),
|
|
146
|
+
name: Vec::new(),
|
|
147
|
+
fold: false,
|
|
148
|
+
behind: false,
|
|
149
|
+
negative: false,
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
fn with_subs(kind: NodeKind, subs: Vec<Node>) -> Node {
|
|
154
|
+
Node { subs, ..Node::new(kind) }
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
fn char(r: Rune) -> Node {
|
|
158
|
+
Node { r, ..Node::new(NodeKind::Char) }
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
fn set(set: Arc<CharSet>) -> Node {
|
|
162
|
+
Node { set: Some(set), ..Node::new(NodeKind::Set) }
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/// The class of a `Set`.
|
|
166
|
+
pub(crate) fn class(&self) -> &Arc<CharSet> {
|
|
167
|
+
self.set.as_ref().expect("a set node has a class")
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/// Names one alternative of one disjunction.
|
|
172
|
+
#[derive(Clone, Copy)]
|
|
173
|
+
struct Branch {
|
|
174
|
+
disjunction: usize,
|
|
175
|
+
alternative: usize,
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/// A capturing group with a name, and the alternatives that enclose it.
|
|
179
|
+
struct NamedGroup {
|
|
180
|
+
group: i32,
|
|
181
|
+
path: Vec<Branch>,
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/// Reads a pattern by recursive descent. With `unicode` set it applies the grammar of the u flag. Without it, it
|
|
185
|
+
/// applies the Annex B grammar of patterns with no flag.
|
|
186
|
+
pub(crate) struct Parser {
|
|
187
|
+
/// The pattern as code points with the u flag, and as UTF-16 code units without it (see `code_units`).
|
|
188
|
+
p: Vec<Rune>,
|
|
189
|
+
i: usize,
|
|
190
|
+
unicode: bool,
|
|
191
|
+
depth: usize,
|
|
192
|
+
/// `group_count` and `has_names` come from a scan of the whole pattern before parsing, because the meaning of
|
|
193
|
+
/// `\1` and `\k` depends on groups that may follow them.
|
|
194
|
+
group_count: i64,
|
|
195
|
+
has_names: bool,
|
|
196
|
+
groups: i32,
|
|
197
|
+
names: HashMap<Vec<Rune>, Vec<NamedGroup>>,
|
|
198
|
+
named_refs: bool,
|
|
199
|
+
/// The alternatives that enclose the current position, innermost last.
|
|
200
|
+
path: Vec<Branch>,
|
|
201
|
+
disjunctions: usize,
|
|
202
|
+
/// The modifiers in force, which only a group such as `(?i:...)` changes.
|
|
203
|
+
icase: bool,
|
|
204
|
+
multiline: bool,
|
|
205
|
+
dot_all: bool,
|
|
206
|
+
/// Records that the pattern has a construct only the backtracking matcher can run.
|
|
207
|
+
pub(crate) needs_backtracking: bool,
|
|
208
|
+
/// The size of what has been read so far (see [`MAX_SIZE`]).
|
|
209
|
+
pub(crate) size: usize,
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
static ANY_SET: LazyLock<Arc<CharSet>> = LazyLock::new(|| CharSet::shared(&[0, MAX_RUNE], false));
|
|
213
|
+
static DIGIT_SET: LazyLock<Arc<CharSet>> = LazyLock::new(|| CharSet::shared(DIGIT_PAIRS, false));
|
|
214
|
+
static NOT_DIGIT_SET: LazyLock<Arc<CharSet>> = LazyLock::new(|| CharSet::shared(DIGIT_PAIRS, true));
|
|
215
|
+
static WORD_SET: LazyLock<Arc<CharSet>> = LazyLock::new(|| CharSet::shared(WORD_PAIRS, false));
|
|
216
|
+
static NOT_WORD_SET: LazyLock<Arc<CharSet>> = LazyLock::new(|| CharSet::shared(WORD_PAIRS, true));
|
|
217
|
+
static SPACE_SET: LazyLock<Arc<CharSet>> = LazyLock::new(|| CharSet::shared(SPACE_PAIRS, false));
|
|
218
|
+
static NOT_SPACE_SET: LazyLock<Arc<CharSet>> = LazyLock::new(|| CharSet::shared(SPACE_PAIRS, true));
|
|
219
|
+
|
|
220
|
+
/// Reads the pattern. It returns an error for a pattern that is not valid under the chosen grammar, and a
|
|
221
|
+
/// `TooLargeError` for a pattern over a limit of size, which it stops reading at the limit.
|
|
222
|
+
pub(crate) fn parse(pattern: &str, unicode: bool) -> Parse<(Node, Parser)> {
|
|
223
|
+
if pattern.len() > MAX_PATTERN_LENGTH {
|
|
224
|
+
return Err(ParseError::TooLarge(TooLargeError { limit: Limit::Length, value: MAX_PATTERN_LENGTH }));
|
|
225
|
+
}
|
|
226
|
+
let mut p: Vec<Rune> = pattern.chars().map(|c| c as Rune).collect();
|
|
227
|
+
if !unicode {
|
|
228
|
+
p = code_units(p);
|
|
229
|
+
}
|
|
230
|
+
let mut ps = Parser {
|
|
231
|
+
p,
|
|
232
|
+
i: 0,
|
|
233
|
+
unicode,
|
|
234
|
+
depth: 0,
|
|
235
|
+
group_count: 0,
|
|
236
|
+
has_names: false,
|
|
237
|
+
groups: 0,
|
|
238
|
+
names: HashMap::new(),
|
|
239
|
+
named_refs: false,
|
|
240
|
+
path: Vec::new(),
|
|
241
|
+
disjunctions: 0,
|
|
242
|
+
icase: false,
|
|
243
|
+
multiline: false,
|
|
244
|
+
dot_all: false,
|
|
245
|
+
needs_backtracking: false,
|
|
246
|
+
size: 0,
|
|
247
|
+
};
|
|
248
|
+
ps.scan_groups();
|
|
249
|
+
let mut root = ps.disjunction()?;
|
|
250
|
+
if ps.i < ps.p.len() {
|
|
251
|
+
if ps.p[ps.i] == ')' as Rune {
|
|
252
|
+
return ps.fail("unmatched ')'");
|
|
253
|
+
}
|
|
254
|
+
return ps.fail("unexpected character");
|
|
255
|
+
}
|
|
256
|
+
if ps.named_refs {
|
|
257
|
+
ps.resolve(&mut root)?;
|
|
258
|
+
}
|
|
259
|
+
Ok((root, ps))
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/// The UTF-16 code units of a pattern. Without the u flag ECMA-262 reads a pattern, and matches a text, a code unit
|
|
263
|
+
/// at a time. A character beyond the Basic Multilingual Plane is then two atoms, a quantifier after it repeats the
|
|
264
|
+
/// second, and in a class it is two members, so a range between two such characters runs from a low surrogate to a
|
|
265
|
+
/// high one and is an error.
|
|
266
|
+
fn code_units(p: Vec<Rune>) -> Vec<Rune> {
|
|
267
|
+
let n = p.iter().filter(|&&c| c > 0xFFFF).count();
|
|
268
|
+
if n == 0 {
|
|
269
|
+
return p;
|
|
270
|
+
}
|
|
271
|
+
let mut units = Vec::with_capacity(p.len() + n);
|
|
272
|
+
for c in p {
|
|
273
|
+
if c > 0xFFFF {
|
|
274
|
+
units.push(high_surrogate(c));
|
|
275
|
+
units.push(low_surrogate(c));
|
|
276
|
+
} else {
|
|
277
|
+
units.push(c);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
units
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
const fn ch(c: char) -> Rune {
|
|
284
|
+
c as Rune
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
fn is_digit(c: Rune) -> bool {
|
|
288
|
+
(ch('0')..=ch('9')).contains(&c)
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
/// Whether the first of two runs of decimal digits is the greater number. The runs are compared as written, because
|
|
292
|
+
/// a count has no limit of size in the grammar and `number` stops at `MAX_COUNT`.
|
|
293
|
+
fn greater_as_written(mut a: &[Rune], mut b: &[Rune]) -> bool {
|
|
294
|
+
while a.first() == Some(&ch('0')) {
|
|
295
|
+
a = &a[1..];
|
|
296
|
+
}
|
|
297
|
+
while b.first() == Some(&ch('0')) {
|
|
298
|
+
b = &b[1..];
|
|
299
|
+
}
|
|
300
|
+
if a.len() != b.len() {
|
|
301
|
+
return a.len() > b.len();
|
|
302
|
+
}
|
|
303
|
+
for (x, y) in a.iter().zip(b) {
|
|
304
|
+
if x != y {
|
|
305
|
+
return x > y;
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
false
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
/// Whether two positions lie in different alternatives of some disjunction.
|
|
312
|
+
fn separate_alternatives(a: &[Branch], b: &[Branch]) -> bool {
|
|
313
|
+
for (x, y) in a.iter().zip(b) {
|
|
314
|
+
if x.disjunction != y.disjunction {
|
|
315
|
+
break;
|
|
316
|
+
}
|
|
317
|
+
if x.alternative != y.alternative {
|
|
318
|
+
return true;
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
false
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
fn hex_value(c: Rune) -> i32 {
|
|
325
|
+
match c {
|
|
326
|
+
0x30..=0x39 => c - 0x30,
|
|
327
|
+
0x61..=0x66 => c - 0x61 + 10,
|
|
328
|
+
0x41..=0x46 => c - 0x41 + 10,
|
|
329
|
+
_ => -1,
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
fn is_ascii_letter(c: Rune) -> bool {
|
|
334
|
+
(ch('a')..=ch('z')).contains(&c) || (ch('A')..=ch('Z')).contains(&c)
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
/// Whether `c` is one of the characters the u flag lets an identity escape name.
|
|
338
|
+
fn syntax_character(c: Rune) -> bool {
|
|
339
|
+
u8::try_from(c).is_ok_and(|c| b"^$\\.*+?()[]{}|/".contains(&c))
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
static ID_START: LazyLock<&'static ucd::Table> =
|
|
343
|
+
LazyLock::new(|| ucd::binary_table("ID_Start").expect("the tables have ID_Start"));
|
|
344
|
+
static ID_CONTINUE: LazyLock<&'static ucd::Table> =
|
|
345
|
+
LazyLock::new(|| ucd::binary_table("ID_Continue").expect("the tables have ID_Continue"));
|
|
346
|
+
|
|
347
|
+
fn append_class_atom(pairs: &mut Vec<Rune>, c: Rune, set: Option<&Arc<CharSet>>) {
|
|
348
|
+
match set {
|
|
349
|
+
Some(set) => pairs.extend_from_slice(&set.ranges),
|
|
350
|
+
None => {
|
|
351
|
+
pairs.push(c);
|
|
352
|
+
pairs.push(c);
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
impl Parser {
|
|
358
|
+
/// Adds to the size of the pattern, and stops the parser when the size is over its limit.
|
|
359
|
+
fn charge(&mut self, bytes: usize) -> Parse<()> {
|
|
360
|
+
self.size += bytes;
|
|
361
|
+
if self.size > MAX_SIZE {
|
|
362
|
+
return Err(ParseError::TooLarge(TooLargeError { limit: Limit::Size, value: MAX_SIZE }));
|
|
363
|
+
}
|
|
364
|
+
Ok(())
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
fn fail<T>(&self, msg: &'static str) -> Parse<T> {
|
|
368
|
+
Err(ParseError::Syntax(msg, self.i))
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
/// Gives every named backreference the groups of its name. A name no group has is an error.
|
|
372
|
+
fn resolve(&self, n: &mut Node) -> Parse<()> {
|
|
373
|
+
if n.kind == NodeKind::Backref && !n.name.is_empty() {
|
|
374
|
+
let Some(named) = self.names.get(&n.name) else {
|
|
375
|
+
return self.fail("reference to an unknown group name");
|
|
376
|
+
};
|
|
377
|
+
n.groups.extend(named.iter().map(|g| g.group));
|
|
378
|
+
}
|
|
379
|
+
for sub in &mut n.subs {
|
|
380
|
+
self.resolve(sub)?;
|
|
381
|
+
}
|
|
382
|
+
Ok(())
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
/// Counts the capturing groups of the pattern and notes whether any is named.
|
|
386
|
+
fn scan_groups(&mut self) {
|
|
387
|
+
let mut in_class = false;
|
|
388
|
+
let s = &self.p;
|
|
389
|
+
let mut k = 0;
|
|
390
|
+
while k < s.len() {
|
|
391
|
+
let c = s[k];
|
|
392
|
+
if c == ch('\\') {
|
|
393
|
+
k += 1;
|
|
394
|
+
} else if c == ch('[') {
|
|
395
|
+
in_class = true;
|
|
396
|
+
} else if c == ch(']') {
|
|
397
|
+
in_class = false;
|
|
398
|
+
} else if c == ch('(') && !in_class {
|
|
399
|
+
if k + 1 >= s.len() || s[k + 1] != ch('?') {
|
|
400
|
+
self.group_count += 1;
|
|
401
|
+
} else if k + 3 < s.len() && s[k + 2] == ch('<') && s[k + 3] != ch('=') && s[k + 3] != ch('!') {
|
|
402
|
+
self.group_count += 1;
|
|
403
|
+
self.has_names = true;
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
k += 1;
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
fn more(&self) -> bool {
|
|
411
|
+
self.i < self.p.len()
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
fn peek(&self) -> Rune {
|
|
415
|
+
self.p.get(self.i).copied().unwrap_or(-1)
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
fn eat(&mut self, c: char) -> bool {
|
|
419
|
+
if self.i < self.p.len() && self.p[self.i] == c as Rune {
|
|
420
|
+
self.i += 1;
|
|
421
|
+
return true;
|
|
422
|
+
}
|
|
423
|
+
false
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
fn disjunction(&mut self) -> Parse<Node> {
|
|
427
|
+
self.depth += 1;
|
|
428
|
+
if self.depth > MAX_NESTING {
|
|
429
|
+
return Err(ParseError::TooLarge(TooLargeError { limit: Limit::Nesting, value: MAX_NESTING }));
|
|
430
|
+
}
|
|
431
|
+
self.disjunctions += 1;
|
|
432
|
+
self.path.push(Branch { disjunction: self.disjunctions, alternative: 0 });
|
|
433
|
+
let last = self.path.len() - 1;
|
|
434
|
+
let first = self.alternative()?;
|
|
435
|
+
if self.peek() != ch('|') {
|
|
436
|
+
self.path.truncate(last);
|
|
437
|
+
self.depth -= 1;
|
|
438
|
+
return Ok(first);
|
|
439
|
+
}
|
|
440
|
+
let mut alt = Node::with_subs(NodeKind::Alt, vec![first]);
|
|
441
|
+
while self.eat('|') {
|
|
442
|
+
self.charge(NODE_SIZE)?;
|
|
443
|
+
self.path[last].alternative += 1;
|
|
444
|
+
let sub = self.alternative()?;
|
|
445
|
+
alt.subs.push(sub);
|
|
446
|
+
}
|
|
447
|
+
self.path.truncate(last);
|
|
448
|
+
self.depth -= 1;
|
|
449
|
+
Ok(alt)
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
fn alternative(&mut self) -> Parse<Node> {
|
|
453
|
+
let mut terms = Vec::new();
|
|
454
|
+
while self.more() && self.peek() != ch('|') && self.peek() != ch(')') {
|
|
455
|
+
terms.push(self.term()?);
|
|
456
|
+
}
|
|
457
|
+
Ok(match terms.len() {
|
|
458
|
+
0 => Node::new(NodeKind::Empty),
|
|
459
|
+
1 => terms.pop().expect("one term"),
|
|
460
|
+
_ => Node::with_subs(NodeKind::Cat, terms),
|
|
461
|
+
})
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
/// The node for one literal character. Inside a case-insensitive group that is the class of the characters
|
|
465
|
+
/// equivalent to it.
|
|
466
|
+
fn char_node(&mut self, c: Rune) -> Node {
|
|
467
|
+
if self.icase {
|
|
468
|
+
let (set, _) = fold_closure(&CharSet::shared(&[c, c], false), self.unicode);
|
|
469
|
+
if set.ranges.len() != 2 || set.ranges[0] != set.ranges[1] {
|
|
470
|
+
return Node::set(set);
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
Node::char(c)
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
/// The node for a class. Inside a case-insensitive group the class also takes every character equivalent to one
|
|
477
|
+
/// of its members.
|
|
478
|
+
fn set_node(&mut self, set: Arc<CharSet>) -> Parse<Node> {
|
|
479
|
+
let set = if self.icase { self.fold(&set)? } else { set };
|
|
480
|
+
Ok(Node::set(set))
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
/// The set with every character equivalent to one of its members. It charges the pattern for the work and for
|
|
484
|
+
/// the set: a byte for each character with a case variant that the set holds, and its ranges.
|
|
485
|
+
fn fold(&mut self, set: &Arc<CharSet>) -> Parse<Arc<CharSet>> {
|
|
486
|
+
let (closed, variants) = fold_closure(set, self.unicode);
|
|
487
|
+
self.charge(variants + RANGE_SIZE * closed.ranges.len() / 2)?;
|
|
488
|
+
Ok(closed)
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
fn term(&mut self) -> Parse<Node> {
|
|
492
|
+
// The atom, and the repetition or the group around it.
|
|
493
|
+
self.charge(2 * NODE_SIZE)?;
|
|
494
|
+
let c = self.peek();
|
|
495
|
+
let mut quantifiable = true;
|
|
496
|
+
let atom = match u8::try_from(c).unwrap_or(0) {
|
|
497
|
+
b'^' => {
|
|
498
|
+
self.i += 1;
|
|
499
|
+
quantifiable = false;
|
|
500
|
+
if self.multiline {
|
|
501
|
+
self.needs_backtracking = true;
|
|
502
|
+
Node::new(NodeKind::LineStart)
|
|
503
|
+
} else {
|
|
504
|
+
Node::new(NodeKind::Bol)
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
b'$' => {
|
|
508
|
+
self.i += 1;
|
|
509
|
+
quantifiable = false;
|
|
510
|
+
if self.multiline {
|
|
511
|
+
self.needs_backtracking = true;
|
|
512
|
+
Node::new(NodeKind::LineEnd)
|
|
513
|
+
} else {
|
|
514
|
+
Node::new(NodeKind::Eol)
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
b'(' => {
|
|
518
|
+
let (atom, q) = self.group()?;
|
|
519
|
+
quantifiable = q;
|
|
520
|
+
atom
|
|
521
|
+
}
|
|
522
|
+
b'.' => {
|
|
523
|
+
self.i += 1;
|
|
524
|
+
Node::set(if self.dot_all { ANY_SET.clone() } else { DOT_SET.clone() })
|
|
525
|
+
}
|
|
526
|
+
b'[' => self.class()?,
|
|
527
|
+
b'\\' => {
|
|
528
|
+
let (atom, q) = self.atom_escape()?;
|
|
529
|
+
quantifiable = q;
|
|
530
|
+
atom
|
|
531
|
+
}
|
|
532
|
+
b'*' | b'+' | b'?' => return self.fail("nothing to repeat"),
|
|
533
|
+
b'{' => {
|
|
534
|
+
if self.unicode || self.looks_like_quantifier() {
|
|
535
|
+
return self.fail("nothing to repeat");
|
|
536
|
+
}
|
|
537
|
+
self.i += 1;
|
|
538
|
+
self.char_node(ch('{'))
|
|
539
|
+
}
|
|
540
|
+
b']' | b'}' => {
|
|
541
|
+
if self.unicode {
|
|
542
|
+
return self.fail("lone bracket");
|
|
543
|
+
}
|
|
544
|
+
self.i += 1;
|
|
545
|
+
self.char_node(c)
|
|
546
|
+
}
|
|
547
|
+
_ => {
|
|
548
|
+
self.i += 1;
|
|
549
|
+
self.char_node(c)
|
|
550
|
+
}
|
|
551
|
+
};
|
|
552
|
+
let Some((min, max, lazy)) = self.quantifier()? else { return Ok(atom) };
|
|
553
|
+
if !quantifiable {
|
|
554
|
+
return self.fail("nothing to repeat");
|
|
555
|
+
}
|
|
556
|
+
Ok(Node { min, max, lazy, ..Node::with_subs(NodeKind::Repeat, vec![atom]) })
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
/// Whether the text at the current `{` reads as `{n}`, `{n,}` or `{n,m}`.
|
|
560
|
+
fn looks_like_quantifier(&self) -> bool {
|
|
561
|
+
let s = &self.p;
|
|
562
|
+
let mut k = self.i + 1;
|
|
563
|
+
let start = k;
|
|
564
|
+
while k < s.len() && is_digit(s[k]) {
|
|
565
|
+
k += 1;
|
|
566
|
+
}
|
|
567
|
+
if k == start || k >= s.len() {
|
|
568
|
+
return false;
|
|
569
|
+
}
|
|
570
|
+
if s[k] == ch('}') {
|
|
571
|
+
return true;
|
|
572
|
+
}
|
|
573
|
+
if s[k] != ch(',') {
|
|
574
|
+
return false;
|
|
575
|
+
}
|
|
576
|
+
k += 1;
|
|
577
|
+
while k < s.len() && is_digit(s[k]) {
|
|
578
|
+
k += 1;
|
|
579
|
+
}
|
|
580
|
+
k < s.len() && s[k] == ch('}')
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
/// Reads a run of decimal digits, saturating at `MAX_COUNT`.
|
|
584
|
+
fn number(&mut self) -> Parse<i64> {
|
|
585
|
+
let start = self.i;
|
|
586
|
+
let mut v: i64 = 0;
|
|
587
|
+
while self.i < self.p.len() && is_digit(self.p[self.i]) {
|
|
588
|
+
if v < MAX_COUNT {
|
|
589
|
+
v = v * 10 + (self.p[self.i] - ch('0')) as i64;
|
|
590
|
+
if v > MAX_COUNT {
|
|
591
|
+
v = MAX_COUNT;
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
self.i += 1;
|
|
595
|
+
}
|
|
596
|
+
if start == self.i {
|
|
597
|
+
return self.fail("expected a number");
|
|
598
|
+
}
|
|
599
|
+
Ok(v)
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
/// Reads a quantifier, when one is here: its bounds, and whether it is lazy.
|
|
603
|
+
fn quantifier(&mut self) -> Parse<Option<(i32, i32, bool)>> {
|
|
604
|
+
let c = self.peek();
|
|
605
|
+
let (min, max);
|
|
606
|
+
if c == ch('*') {
|
|
607
|
+
self.i += 1;
|
|
608
|
+
(min, max) = (0, UNBOUNDED);
|
|
609
|
+
} else if c == ch('+') {
|
|
610
|
+
self.i += 1;
|
|
611
|
+
(min, max) = (1, UNBOUNDED);
|
|
612
|
+
} else if c == ch('?') {
|
|
613
|
+
self.i += 1;
|
|
614
|
+
(min, max) = (0, 1);
|
|
615
|
+
} else if c == ch('{') && self.looks_like_quantifier() {
|
|
616
|
+
self.i += 1;
|
|
617
|
+
let first = self.i;
|
|
618
|
+
let lo = self.number()? as i32;
|
|
619
|
+
let mut hi = lo;
|
|
620
|
+
let first_end = self.i;
|
|
621
|
+
if self.eat(',') {
|
|
622
|
+
if self.peek() == ch('}') {
|
|
623
|
+
hi = UNBOUNDED;
|
|
624
|
+
} else {
|
|
625
|
+
let second = self.i;
|
|
626
|
+
hi = self.number()? as i32;
|
|
627
|
+
// Both counts stop at MAX_COUNT, so the numbers are compared as they are written.
|
|
628
|
+
if greater_as_written(&self.p[first..first_end], &self.p[second..self.i]) {
|
|
629
|
+
return self.fail("numbers out of order in quantifier");
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
if !self.eat('}') {
|
|
634
|
+
return self.fail("malformed quantifier");
|
|
635
|
+
}
|
|
636
|
+
(min, max) = (lo, hi);
|
|
637
|
+
} else {
|
|
638
|
+
return Ok(None);
|
|
639
|
+
}
|
|
640
|
+
Ok(Some((min, max, self.eat('?'))))
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
/// Reads a group or a lookaround. It also reports whether a quantifier may follow.
|
|
644
|
+
fn group(&mut self) -> Parse<(Node, bool)> {
|
|
645
|
+
self.i += 1;
|
|
646
|
+
if !self.eat('?') {
|
|
647
|
+
return Ok((self.capture(None)?, true));
|
|
648
|
+
}
|
|
649
|
+
if self.eat(':') {
|
|
650
|
+
let body = self.disjunction()?;
|
|
651
|
+
self.close()?;
|
|
652
|
+
return Ok((Node::with_subs(NodeKind::Group, vec![body]), true));
|
|
653
|
+
}
|
|
654
|
+
let c = self.peek();
|
|
655
|
+
if c == ch('i') || c == ch('m') || c == ch('s') || c == ch('-') {
|
|
656
|
+
return Ok((self.modifier_group()?, true));
|
|
657
|
+
}
|
|
658
|
+
if self.eat('=') || self.eat('!') {
|
|
659
|
+
let negative = self.p[self.i - 1] == ch('!');
|
|
660
|
+
let body = self.disjunction()?;
|
|
661
|
+
self.close()?;
|
|
662
|
+
self.needs_backtracking = true;
|
|
663
|
+
// Annex B lets a quantifier follow a lookahead. The u flag does not.
|
|
664
|
+
return Ok((Node { negative, ..Node::with_subs(NodeKind::Look, vec![body]) }, !self.unicode));
|
|
665
|
+
}
|
|
666
|
+
if self.eat('<') {
|
|
667
|
+
if self.eat('=') || self.eat('!') {
|
|
668
|
+
let negative = self.p[self.i - 1] == ch('!');
|
|
669
|
+
let body = self.disjunction()?;
|
|
670
|
+
self.close()?;
|
|
671
|
+
self.needs_backtracking = true;
|
|
672
|
+
return Ok((Node { negative, behind: true, ..Node::with_subs(NodeKind::Look, vec![body]) }, false));
|
|
673
|
+
}
|
|
674
|
+
let name = self.group_name()?;
|
|
675
|
+
// Two groups may share a name only when they are in separate alternatives of one disjunction, so that
|
|
676
|
+
// no match can go through both.
|
|
677
|
+
if let Some(others) = self.names.get(&name) {
|
|
678
|
+
for other in others {
|
|
679
|
+
if !separate_alternatives(&other.path, &self.path) {
|
|
680
|
+
return self.fail("duplicate group name");
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
return Ok((self.capture(Some(name))?, true));
|
|
685
|
+
}
|
|
686
|
+
self.fail("invalid group")
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
/// Reads a group that turns modifiers on or off for its body, such as `(?i:...)` or `(?s-i:...)`. The position
|
|
690
|
+
/// is after the `(?`.
|
|
691
|
+
fn modifier_group(&mut self) -> Parse<Node> {
|
|
692
|
+
let (icase, multiline, dot_all) = (self.icase, self.multiline, self.dot_all);
|
|
693
|
+
let mut seen = [false; 3];
|
|
694
|
+
let (mut removing, mut count) = (false, 0);
|
|
695
|
+
while !self.eat(':') {
|
|
696
|
+
let c = self.peek();
|
|
697
|
+
self.i += 1;
|
|
698
|
+
let flag;
|
|
699
|
+
if c == ch('i') {
|
|
700
|
+
(flag, self.icase) = (0, !removing);
|
|
701
|
+
} else if c == ch('m') {
|
|
702
|
+
(flag, self.multiline) = (1, !removing);
|
|
703
|
+
} else if c == ch('s') {
|
|
704
|
+
(flag, self.dot_all) = (2, !removing);
|
|
705
|
+
} else if c == ch('-') {
|
|
706
|
+
if removing {
|
|
707
|
+
return self.fail("invalid group modifier");
|
|
708
|
+
}
|
|
709
|
+
removing = true;
|
|
710
|
+
continue;
|
|
711
|
+
} else {
|
|
712
|
+
return self.fail("invalid group modifier");
|
|
713
|
+
}
|
|
714
|
+
if seen[flag] {
|
|
715
|
+
return self.fail("repeated group modifier");
|
|
716
|
+
}
|
|
717
|
+
seen[flag] = true;
|
|
718
|
+
count += 1;
|
|
719
|
+
}
|
|
720
|
+
if count == 0 {
|
|
721
|
+
return self.fail("invalid group modifier");
|
|
722
|
+
}
|
|
723
|
+
let body = self.disjunction()?;
|
|
724
|
+
self.close()?;
|
|
725
|
+
(self.icase, self.multiline, self.dot_all) = (icase, multiline, dot_all);
|
|
726
|
+
Ok(Node::with_subs(NodeKind::Group, vec![body]))
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
fn capture(&mut self, name: Option<Vec<Rune>>) -> Parse<Node> {
|
|
730
|
+
self.groups += 1;
|
|
731
|
+
let group = self.groups;
|
|
732
|
+
if let Some(name) = name {
|
|
733
|
+
// The path is kept, and every group of the same name is compared with it.
|
|
734
|
+
let same = self.names.get(&name).map_or(0, Vec::len);
|
|
735
|
+
self.charge(RANGE_SIZE * (self.path.len() + same))?;
|
|
736
|
+
let path = self.path.clone();
|
|
737
|
+
self.names.entry(name).or_default().push(NamedGroup { group, path });
|
|
738
|
+
}
|
|
739
|
+
let body = self.disjunction()?;
|
|
740
|
+
self.close()?;
|
|
741
|
+
Ok(Node { group, ..Node::with_subs(NodeKind::Group, vec![body]) })
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
fn close(&mut self) -> Parse<()> {
|
|
745
|
+
if !self.eat(')') {
|
|
746
|
+
return self.fail("unterminated group");
|
|
747
|
+
}
|
|
748
|
+
Ok(())
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
/// Reads a group name up to and including its `>`. A character of the name may be written as a `\u` escape.
|
|
752
|
+
fn group_name(&mut self) -> Parse<Vec<Rune>> {
|
|
753
|
+
let mut name: Vec<Rune> = Vec::new();
|
|
754
|
+
while !self.eat('>') {
|
|
755
|
+
if !self.more() {
|
|
756
|
+
return self.fail("invalid group name");
|
|
757
|
+
}
|
|
758
|
+
let mut c = self.peek();
|
|
759
|
+
self.i += 1;
|
|
760
|
+
if c == ch('\\') {
|
|
761
|
+
if !self.eat('u') {
|
|
762
|
+
return self.fail("invalid group name");
|
|
763
|
+
}
|
|
764
|
+
c = self.unicode_escape(true);
|
|
765
|
+
if c < 0 {
|
|
766
|
+
return self.fail("invalid group name");
|
|
767
|
+
}
|
|
768
|
+
} else if (0xD800..=0xDBFF).contains(&c) && (0xDC00..=0xDFFF).contains(&self.peek()) {
|
|
769
|
+
// Without the u flag the pattern is code units, and a name still takes a surrogate pair as one
|
|
770
|
+
// character.
|
|
771
|
+
c = 0x10000 + ((c - 0xD800) << 10) + (self.peek() - 0xDC00);
|
|
772
|
+
self.i += 1;
|
|
773
|
+
}
|
|
774
|
+
if name.is_empty() {
|
|
775
|
+
if !(c == ch('$') || c == ch('_') || ID_START.contains(c)) {
|
|
776
|
+
return self.fail("invalid group name");
|
|
777
|
+
}
|
|
778
|
+
} else if !(c == ch('$') || c == 0x200C || c == 0x200D || ID_CONTINUE.contains(c)) {
|
|
779
|
+
return self.fail("invalid group name");
|
|
780
|
+
}
|
|
781
|
+
name.push(c);
|
|
782
|
+
}
|
|
783
|
+
if name.is_empty() {
|
|
784
|
+
return self.fail("invalid group name");
|
|
785
|
+
}
|
|
786
|
+
Ok(name)
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
/// Reads an escape outside a class. It also reports whether a quantifier may follow.
|
|
790
|
+
fn atom_escape(&mut self) -> Parse<(Node, bool)> {
|
|
791
|
+
self.i += 1;
|
|
792
|
+
if !self.more() {
|
|
793
|
+
return self.fail("\\ at end of pattern");
|
|
794
|
+
}
|
|
795
|
+
let c = self.peek();
|
|
796
|
+
if c == ch('b') || c == ch('B') {
|
|
797
|
+
self.i += 1;
|
|
798
|
+
let mut boundary = Node::new(if c == ch('B') { NodeKind::NotWordBoundary } else { NodeKind::WordBoundary });
|
|
799
|
+
// With the u flag, a case-insensitive word boundary counts two more characters as word characters.
|
|
800
|
+
if self.unicode && self.icase {
|
|
801
|
+
boundary.fold = true;
|
|
802
|
+
self.needs_backtracking = true;
|
|
803
|
+
}
|
|
804
|
+
return Ok((boundary, false));
|
|
805
|
+
}
|
|
806
|
+
if c == ch('k') {
|
|
807
|
+
// Annex B reads \k as the letter k in a pattern with no named group.
|
|
808
|
+
if self.unicode || self.has_names {
|
|
809
|
+
self.i += 1;
|
|
810
|
+
if !self.eat('<') {
|
|
811
|
+
return self.fail("invalid named reference");
|
|
812
|
+
}
|
|
813
|
+
let name = self.group_name()?;
|
|
814
|
+
self.named_refs = true;
|
|
815
|
+
self.needs_backtracking = true;
|
|
816
|
+
return Ok((Node { name, fold: self.icase, ..Node::new(NodeKind::Backref) }, true));
|
|
817
|
+
}
|
|
818
|
+
self.i += 1;
|
|
819
|
+
return Ok((self.char_node(ch('k')), true));
|
|
820
|
+
}
|
|
821
|
+
if (ch('1')..=ch('9')).contains(&c) {
|
|
822
|
+
let start = self.i;
|
|
823
|
+
let n = self.number()?;
|
|
824
|
+
if n <= self.group_count {
|
|
825
|
+
self.needs_backtracking = true;
|
|
826
|
+
return Ok((Node { groups: vec![n as i32], fold: self.icase, ..Node::new(NodeKind::Backref) }, true));
|
|
827
|
+
}
|
|
828
|
+
if self.unicode {
|
|
829
|
+
return self.fail("reference to a group that does not exist");
|
|
830
|
+
}
|
|
831
|
+
// Annex B reads it as an octal escape, or as the digit itself.
|
|
832
|
+
self.i = start;
|
|
833
|
+
let octal = self.legacy_octal();
|
|
834
|
+
return Ok((self.char_node(octal), true));
|
|
835
|
+
}
|
|
836
|
+
if let Some(set) = self.class_escape(c)? {
|
|
837
|
+
return Ok((self.set_node(set)?, true));
|
|
838
|
+
}
|
|
839
|
+
let escaped = self.character_escape(false)?;
|
|
840
|
+
Ok((self.char_node(escaped), true))
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
/// Reads an Annex B octal escape of up to three digits with a value below 256. A digit that cannot start one (8
|
|
844
|
+
/// or 9) stands for itself.
|
|
845
|
+
fn legacy_octal(&mut self) -> Rune {
|
|
846
|
+
let mut v: Rune = 0;
|
|
847
|
+
let mut k = 0;
|
|
848
|
+
while k < 3
|
|
849
|
+
&& self.more()
|
|
850
|
+
&& (ch('0')..=ch('7')).contains(&self.peek())
|
|
851
|
+
&& v * 8 + (self.peek() - ch('0')) <= 0o377
|
|
852
|
+
{
|
|
853
|
+
v = v * 8 + (self.peek() - ch('0'));
|
|
854
|
+
self.i += 1;
|
|
855
|
+
k += 1;
|
|
856
|
+
}
|
|
857
|
+
if k == 0 {
|
|
858
|
+
let d = self.peek();
|
|
859
|
+
self.i += 1;
|
|
860
|
+
return d;
|
|
861
|
+
}
|
|
862
|
+
v
|
|
863
|
+
}
|
|
864
|
+
|
|
865
|
+
/// Reads a class escape such as `\d` or `\p{...}` whose letter is `c`. It returns `None`, consuming nothing,
|
|
866
|
+
/// when `c` does not start one.
|
|
867
|
+
fn class_escape(&mut self, c: Rune) -> Parse<Option<Arc<CharSet>>> {
|
|
868
|
+
let set = match u8::try_from(c).unwrap_or(0) {
|
|
869
|
+
b'd' => &DIGIT_SET,
|
|
870
|
+
b'D' => &NOT_DIGIT_SET,
|
|
871
|
+
b'w' => {
|
|
872
|
+
if self.unicode && self.icase {
|
|
873
|
+
&FOLD_WORD_SET
|
|
874
|
+
} else {
|
|
875
|
+
&WORD_SET
|
|
876
|
+
}
|
|
877
|
+
}
|
|
878
|
+
b'W' => {
|
|
879
|
+
if self.unicode && self.icase {
|
|
880
|
+
&NOT_FOLD_WORD_SET
|
|
881
|
+
} else {
|
|
882
|
+
&NOT_WORD_SET
|
|
883
|
+
}
|
|
884
|
+
}
|
|
885
|
+
b's' => &SPACE_SET,
|
|
886
|
+
b'S' => &NOT_SPACE_SET,
|
|
887
|
+
b'p' | b'P' => {
|
|
888
|
+
// Without the u flag \p is the letter p.
|
|
889
|
+
if !self.unicode {
|
|
890
|
+
return Ok(None);
|
|
891
|
+
}
|
|
892
|
+
self.i += 1;
|
|
893
|
+
if !self.eat('{') {
|
|
894
|
+
return self.fail("invalid property name");
|
|
895
|
+
}
|
|
896
|
+
let start = self.i;
|
|
897
|
+
while self.more() && self.peek() != ch('}') {
|
|
898
|
+
self.i += 1;
|
|
899
|
+
}
|
|
900
|
+
// A name ECMA-262 defines is ASCII. Any other character makes a name no table has.
|
|
901
|
+
let expr: String =
|
|
902
|
+
self.p[start..self.i].iter().map(|&r| char::from_u32(r as u32).unwrap_or('\u{FFFD}')).collect();
|
|
903
|
+
if !self.eat('}') {
|
|
904
|
+
return self.fail("invalid property name");
|
|
905
|
+
}
|
|
906
|
+
let Some(set) = property_set(&expr) else {
|
|
907
|
+
return self.fail("invalid property name");
|
|
908
|
+
};
|
|
909
|
+
if c == ch('P') {
|
|
910
|
+
self.charge(RANGE_SIZE * set.ranges.len() / 2)?;
|
|
911
|
+
return Ok(Some(CharSet::shared(&set.ranges, true)));
|
|
912
|
+
}
|
|
913
|
+
return Ok(Some(set));
|
|
914
|
+
}
|
|
915
|
+
_ => return Ok(None),
|
|
916
|
+
};
|
|
917
|
+
self.i += 1;
|
|
918
|
+
Ok(Some((**set).clone()))
|
|
919
|
+
}
|
|
920
|
+
|
|
921
|
+
/// Reads exactly `n` hexadecimal digits. It returns -1, consuming nothing, when they are not there.
|
|
922
|
+
fn hex(&mut self, n: usize) -> Rune {
|
|
923
|
+
if self.i + n > self.p.len() {
|
|
924
|
+
return -1;
|
|
925
|
+
}
|
|
926
|
+
let mut v: Rune = 0;
|
|
927
|
+
for k in 0..n {
|
|
928
|
+
let d = hex_value(self.p[self.i + k]);
|
|
929
|
+
if d < 0 {
|
|
930
|
+
return -1;
|
|
931
|
+
}
|
|
932
|
+
v = v * 16 + d;
|
|
933
|
+
}
|
|
934
|
+
self.i += n;
|
|
935
|
+
v
|
|
936
|
+
}
|
|
937
|
+
|
|
938
|
+
/// Reads the escape after a backslash, in or out of a class, and returns the code point it names.
|
|
939
|
+
fn character_escape(&mut self, in_class: bool) -> Parse<Rune> {
|
|
940
|
+
let c = self.peek();
|
|
941
|
+
self.i += 1;
|
|
942
|
+
match u8::try_from(c).unwrap_or(0) {
|
|
943
|
+
b'f' => return Ok(0x0C),
|
|
944
|
+
b'n' => return Ok(0x0A),
|
|
945
|
+
b'r' => return Ok(0x0D),
|
|
946
|
+
b't' => return Ok(0x09),
|
|
947
|
+
b'v' => return Ok(0x0B),
|
|
948
|
+
b'c' => {
|
|
949
|
+
let l = self.peek();
|
|
950
|
+
if is_ascii_letter(l) {
|
|
951
|
+
self.i += 1;
|
|
952
|
+
return Ok(l % 32);
|
|
953
|
+
}
|
|
954
|
+
if !self.unicode && in_class && (is_digit(l) || l == ch('_')) {
|
|
955
|
+
self.i += 1;
|
|
956
|
+
return Ok(l % 32);
|
|
957
|
+
}
|
|
958
|
+
if self.unicode {
|
|
959
|
+
return self.fail("invalid control escape");
|
|
960
|
+
}
|
|
961
|
+
// Annex B reads a \c that is not a control escape as a backslash followed by the letter c.
|
|
962
|
+
self.i -= 1;
|
|
963
|
+
return Ok(ch('\\'));
|
|
964
|
+
}
|
|
965
|
+
b'0' => {
|
|
966
|
+
if self.more() && is_digit(self.peek()) {
|
|
967
|
+
if self.unicode {
|
|
968
|
+
return self.fail("invalid decimal escape");
|
|
969
|
+
}
|
|
970
|
+
self.i -= 1;
|
|
971
|
+
return Ok(self.legacy_octal());
|
|
972
|
+
}
|
|
973
|
+
return Ok(0);
|
|
974
|
+
}
|
|
975
|
+
b'x' => {
|
|
976
|
+
let h = self.hex(2);
|
|
977
|
+
if h < 0 {
|
|
978
|
+
if self.unicode {
|
|
979
|
+
return self.fail("invalid \\x escape");
|
|
980
|
+
}
|
|
981
|
+
return Ok(ch('x'));
|
|
982
|
+
}
|
|
983
|
+
return Ok(h);
|
|
984
|
+
}
|
|
985
|
+
b'u' => {
|
|
986
|
+
let u = self.unicode_escape(self.unicode);
|
|
987
|
+
if u < 0 {
|
|
988
|
+
if self.unicode {
|
|
989
|
+
return self.fail("invalid \\u escape");
|
|
990
|
+
}
|
|
991
|
+
return Ok(ch('u'));
|
|
992
|
+
}
|
|
993
|
+
return Ok(u);
|
|
994
|
+
}
|
|
995
|
+
_ => {}
|
|
996
|
+
}
|
|
997
|
+
if (ch('1')..=ch('9')).contains(&c) && !self.unicode && in_class {
|
|
998
|
+
self.i -= 1;
|
|
999
|
+
return Ok(self.legacy_octal());
|
|
1000
|
+
}
|
|
1001
|
+
// Identity escapes. The u flag allows only the syntax characters and '/', and '-' in a class. Annex B allows
|
|
1002
|
+
// any character, except k in a pattern with a named group. Outside a class atom_escape reads \k before this
|
|
1003
|
+
// is reached, so here the \k of such a pattern is in a class, where it is not a reference either.
|
|
1004
|
+
if self.unicode && !syntax_character(c) && !(in_class && c == ch('-')) {
|
|
1005
|
+
return self.fail("invalid escape");
|
|
1006
|
+
}
|
|
1007
|
+
if c == ch('k') && self.has_names {
|
|
1008
|
+
return self.fail("invalid escape");
|
|
1009
|
+
}
|
|
1010
|
+
Ok(c)
|
|
1011
|
+
}
|
|
1012
|
+
|
|
1013
|
+
/// Reads what follows a `\u` and returns the code point, or -1, consuming nothing, when it is not a well-formed
|
|
1014
|
+
/// escape. With `unicode_mode` set, as it is with the u flag and always in a group name, it accepts the
|
|
1015
|
+
/// `\u{...}` form and reads a surrogate pair written as two escapes as one code point. Without it each escape
|
|
1016
|
+
/// is one code unit.
|
|
1017
|
+
fn unicode_escape(&mut self, unicode_mode: bool) -> Rune {
|
|
1018
|
+
let start = self.i;
|
|
1019
|
+
if unicode_mode && self.eat('{') {
|
|
1020
|
+
let digits = self.i;
|
|
1021
|
+
let mut v: Rune = 0;
|
|
1022
|
+
while self.more() && hex_value(self.peek()) >= 0 {
|
|
1023
|
+
if v <= MAX_RUNE {
|
|
1024
|
+
v = v * 16 + hex_value(self.peek());
|
|
1025
|
+
}
|
|
1026
|
+
self.i += 1;
|
|
1027
|
+
}
|
|
1028
|
+
if digits == self.i || !self.eat('}') || v > MAX_RUNE {
|
|
1029
|
+
self.i = start;
|
|
1030
|
+
return -1;
|
|
1031
|
+
}
|
|
1032
|
+
return v;
|
|
1033
|
+
}
|
|
1034
|
+
let u = self.hex(4);
|
|
1035
|
+
if u < 0 {
|
|
1036
|
+
return -1;
|
|
1037
|
+
}
|
|
1038
|
+
if unicode_mode
|
|
1039
|
+
&& (0xD800..=0xDBFF).contains(&u)
|
|
1040
|
+
&& self.i + 6 <= self.p.len()
|
|
1041
|
+
&& self.p[self.i] == ch('\\')
|
|
1042
|
+
&& self.p[self.i + 1] == ch('u')
|
|
1043
|
+
{
|
|
1044
|
+
let save = self.i;
|
|
1045
|
+
self.i += 2;
|
|
1046
|
+
let low = self.hex(4);
|
|
1047
|
+
if (0xDC00..=0xDFFF).contains(&low) {
|
|
1048
|
+
return 0x10000 + ((u - 0xD800) << 10) + (low - 0xDC00);
|
|
1049
|
+
}
|
|
1050
|
+
self.i = save;
|
|
1051
|
+
}
|
|
1052
|
+
u
|
|
1053
|
+
}
|
|
1054
|
+
|
|
1055
|
+
/// Reads a character class from its `[` to its `]`.
|
|
1056
|
+
fn class(&mut self) -> Parse<Node> {
|
|
1057
|
+
self.i += 1;
|
|
1058
|
+
let negated = self.eat('^');
|
|
1059
|
+
let mut pairs: Vec<Rune> = Vec::new();
|
|
1060
|
+
// The ranges read so far that the size of the pattern has been charged for.
|
|
1061
|
+
let mut charged = 0;
|
|
1062
|
+
loop {
|
|
1063
|
+
if !self.more() {
|
|
1064
|
+
return self.fail("unterminated character class");
|
|
1065
|
+
}
|
|
1066
|
+
if self.eat(']') {
|
|
1067
|
+
break;
|
|
1068
|
+
}
|
|
1069
|
+
self.charge(RANGE_SIZE * (pairs.len() / 2 - charged))?;
|
|
1070
|
+
charged = pairs.len() / 2;
|
|
1071
|
+
let (first, first_set) = self.class_atom()?;
|
|
1072
|
+
if self.peek() == ch('-') && self.i + 1 < self.p.len() && self.p[self.i + 1] != ch(']') {
|
|
1073
|
+
self.i += 1;
|
|
1074
|
+
let (second, second_set) = self.class_atom()?;
|
|
1075
|
+
if first_set.is_some() || second_set.is_some() {
|
|
1076
|
+
if self.unicode {
|
|
1077
|
+
return self.fail("invalid character class range");
|
|
1078
|
+
}
|
|
1079
|
+
// Annex B reads the '-' as itself when a class escape is at either end.
|
|
1080
|
+
append_class_atom(&mut pairs, first, first_set.as_ref());
|
|
1081
|
+
pairs.push(ch('-'));
|
|
1082
|
+
pairs.push(ch('-'));
|
|
1083
|
+
append_class_atom(&mut pairs, second, second_set.as_ref());
|
|
1084
|
+
continue;
|
|
1085
|
+
}
|
|
1086
|
+
if second < first {
|
|
1087
|
+
return self.fail("range out of order in character class");
|
|
1088
|
+
}
|
|
1089
|
+
pairs.push(first);
|
|
1090
|
+
pairs.push(second);
|
|
1091
|
+
continue;
|
|
1092
|
+
}
|
|
1093
|
+
append_class_atom(&mut pairs, first, first_set.as_ref());
|
|
1094
|
+
}
|
|
1095
|
+
// Inside a case-insensitive group a character matches the class when it is equivalent to a member, and a
|
|
1096
|
+
// negated class excludes exactly those characters.
|
|
1097
|
+
self.charge(RANGE_SIZE * (pairs.len() / 2 - charged))?;
|
|
1098
|
+
let mut set = CharSet::shared(&pairs, false);
|
|
1099
|
+
if self.icase {
|
|
1100
|
+
set = self.fold(&set)?;
|
|
1101
|
+
}
|
|
1102
|
+
if negated {
|
|
1103
|
+
set = CharSet::shared(&set.ranges, true);
|
|
1104
|
+
}
|
|
1105
|
+
Ok(Node::set(set))
|
|
1106
|
+
}
|
|
1107
|
+
|
|
1108
|
+
/// Reads one member of a class. It returns a code point, or a set for a class escape.
|
|
1109
|
+
fn class_atom(&mut self) -> Parse<(Rune, Option<Arc<CharSet>>)> {
|
|
1110
|
+
let c = self.peek();
|
|
1111
|
+
self.i += 1;
|
|
1112
|
+
if c != ch('\\') {
|
|
1113
|
+
return Ok((c, None));
|
|
1114
|
+
}
|
|
1115
|
+
if !self.more() {
|
|
1116
|
+
return self.fail("\\ at end of pattern");
|
|
1117
|
+
}
|
|
1118
|
+
let e = self.peek();
|
|
1119
|
+
if e == ch('b') {
|
|
1120
|
+
self.i += 1;
|
|
1121
|
+
return Ok((0x08, None));
|
|
1122
|
+
}
|
|
1123
|
+
if let Some(set) = self.class_escape(e)? {
|
|
1124
|
+
return Ok((0, Some(set)));
|
|
1125
|
+
}
|
|
1126
|
+
Ok((self.character_escape(true)?, None))
|
|
1127
|
+
}
|
|
1128
|
+
}
|