Coverage Report

Created: 2026-09-06 07:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/regex-1.5.6/src/compile.rs
Line
Count
Source
1
use std::collections::HashMap;
2
use std::fmt;
3
use std::iter;
4
use std::result;
5
use std::sync::Arc;
6
7
use regex_syntax::hir::{self, Hir};
8
use regex_syntax::is_word_byte;
9
use regex_syntax::utf8::{Utf8Range, Utf8Sequence, Utf8Sequences};
10
11
use crate::prog::{
12
    EmptyLook, Inst, InstBytes, InstChar, InstEmptyLook, InstPtr, InstRanges,
13
    InstSave, InstSplit, Program,
14
};
15
16
use crate::Error;
17
18
type Result = result::Result<Patch, Error>;
19
type ResultOrEmpty = result::Result<Option<Patch>, Error>;
20
21
#[derive(Debug)]
22
struct Patch {
23
    hole: Hole,
24
    entry: InstPtr,
25
}
26
27
/// A compiler translates a regular expression AST to a sequence of
28
/// instructions. The sequence of instructions represents an NFA.
29
// `Compiler` is only public via the `internal` module, so avoid deriving
30
// `Debug`.
31
#[allow(missing_debug_implementations)]
32
pub struct Compiler {
33
    insts: Vec<MaybeInst>,
34
    compiled: Program,
35
    capture_name_idx: HashMap<String, usize>,
36
    num_exprs: usize,
37
    size_limit: usize,
38
    suffix_cache: SuffixCache,
39
    utf8_seqs: Option<Utf8Sequences>,
40
    byte_classes: ByteClassSet,
41
    // This keeps track of extra bytes allocated while compiling the regex
42
    // program. Currently, this corresponds to two things. First is the heap
43
    // memory allocated by Unicode character classes ('InstRanges'). Second is
44
    // a "fake" amount of memory used by empty sub-expressions, so that enough
45
    // empty sub-expressions will ultimately trigger the compiler to bail
46
    // because of a size limit restriction. (That empty sub-expressions don't
47
    // add to heap memory usage is more-or-less an implementation detail.) In
48
    // the second case, if we don't bail, then an excessively large repetition
49
    // on an empty sub-expression can result in the compiler using a very large
50
    // amount of CPU time.
51
    extra_inst_bytes: usize,
52
}
53
54
impl Compiler {
55
    /// Create a new regular expression compiler.
56
    ///
57
    /// Various options can be set before calling `compile` on an expression.
58
54
    pub fn new() -> Self {
59
54
        Compiler {
60
54
            insts: vec![],
61
54
            compiled: Program::new(),
62
54
            capture_name_idx: HashMap::new(),
63
54
            num_exprs: 0,
64
54
            size_limit: 10 * (1 << 20),
65
54
            suffix_cache: SuffixCache::new(1000),
66
54
            utf8_seqs: Some(Utf8Sequences::new('\x00', '\x00')),
67
54
            byte_classes: ByteClassSet::new(),
68
54
            extra_inst_bytes: 0,
69
54
        }
70
54
    }
<regex::compile::Compiler>::new
Line
Count
Source
58
27
    pub fn new() -> Self {
59
27
        Compiler {
60
27
            insts: vec![],
61
27
            compiled: Program::new(),
62
27
            capture_name_idx: HashMap::new(),
63
27
            num_exprs: 0,
64
27
            size_limit: 10 * (1 << 20),
65
27
            suffix_cache: SuffixCache::new(1000),
66
27
            utf8_seqs: Some(Utf8Sequences::new('\x00', '\x00')),
67
27
            byte_classes: ByteClassSet::new(),
68
27
            extra_inst_bytes: 0,
69
27
        }
70
27
    }
<regex::compile::Compiler>::new
Line
Count
Source
58
27
    pub fn new() -> Self {
59
27
        Compiler {
60
27
            insts: vec![],
61
27
            compiled: Program::new(),
62
27
            capture_name_idx: HashMap::new(),
63
27
            num_exprs: 0,
64
27
            size_limit: 10 * (1 << 20),
65
27
            suffix_cache: SuffixCache::new(1000),
66
27
            utf8_seqs: Some(Utf8Sequences::new('\x00', '\x00')),
67
27
            byte_classes: ByteClassSet::new(),
68
27
            extra_inst_bytes: 0,
69
27
        }
70
27
    }
71
72
    /// The size of the resulting program is limited by size_limit. If
73
    /// the program approximately exceeds the given size (in bytes), then
74
    /// compilation will stop and return an error.
75
54
    pub fn size_limit(mut self, size_limit: usize) -> Self {
76
54
        self.size_limit = size_limit;
77
54
        self
78
54
    }
<regex::compile::Compiler>::size_limit
Line
Count
Source
75
27
    pub fn size_limit(mut self, size_limit: usize) -> Self {
76
27
        self.size_limit = size_limit;
77
27
        self
78
27
    }
<regex::compile::Compiler>::size_limit
Line
Count
Source
75
27
    pub fn size_limit(mut self, size_limit: usize) -> Self {
76
27
        self.size_limit = size_limit;
77
27
        self
78
27
    }
79
80
    /// If bytes is true, then the program is compiled as a byte based
81
    /// automaton, which incorporates UTF-8 decoding into the machine. If it's
82
    /// false, then the automaton is Unicode scalar value based, e.g., an
83
    /// engine utilizing such an automaton is responsible for UTF-8 decoding.
84
    ///
85
    /// The specific invariant is that when returning a byte based machine,
86
    /// the neither the `Char` nor `Ranges` instructions are produced.
87
    /// Conversely, when producing a Unicode scalar value machine, the `Bytes`
88
    /// instruction is never produced.
89
    ///
90
    /// Note that `dfa(true)` implies `bytes(true)`.
91
18
    pub fn bytes(mut self, yes: bool) -> Self {
92
18
        self.compiled.is_bytes = yes;
93
18
        self
94
18
    }
<regex::compile::Compiler>::bytes
Line
Count
Source
91
9
    pub fn bytes(mut self, yes: bool) -> Self {
92
9
        self.compiled.is_bytes = yes;
93
9
        self
94
9
    }
<regex::compile::Compiler>::bytes
Line
Count
Source
91
9
    pub fn bytes(mut self, yes: bool) -> Self {
92
9
        self.compiled.is_bytes = yes;
93
9
        self
94
9
    }
95
96
    /// When disabled, the program compiled may match arbitrary bytes.
97
    ///
98
    /// When enabled (the default), all compiled programs exclusively match
99
    /// valid UTF-8 bytes.
100
54
    pub fn only_utf8(mut self, yes: bool) -> Self {
101
54
        self.compiled.only_utf8 = yes;
102
54
        self
103
54
    }
<regex::compile::Compiler>::only_utf8
Line
Count
Source
100
27
    pub fn only_utf8(mut self, yes: bool) -> Self {
101
27
        self.compiled.only_utf8 = yes;
102
27
        self
103
27
    }
<regex::compile::Compiler>::only_utf8
Line
Count
Source
100
27
    pub fn only_utf8(mut self, yes: bool) -> Self {
101
27
        self.compiled.only_utf8 = yes;
102
27
        self
103
27
    }
104
105
    /// When set, the machine returned is suitable for use in the DFA matching
106
    /// engine.
107
    ///
108
    /// In particular, this ensures that if the regex is not anchored in the
109
    /// beginning, then a preceding `.*?` is included in the program. (The NFA
110
    /// based engines handle the preceding `.*?` explicitly, which is difficult
111
    /// or impossible in the DFA engine.)
112
36
    pub fn dfa(mut self, yes: bool) -> Self {
113
36
        self.compiled.is_dfa = yes;
114
36
        self
115
36
    }
<regex::compile::Compiler>::dfa
Line
Count
Source
112
18
    pub fn dfa(mut self, yes: bool) -> Self {
113
18
        self.compiled.is_dfa = yes;
114
18
        self
115
18
    }
<regex::compile::Compiler>::dfa
Line
Count
Source
112
18
    pub fn dfa(mut self, yes: bool) -> Self {
113
18
        self.compiled.is_dfa = yes;
114
18
        self
115
18
    }
116
117
    /// When set, the machine returned is suitable for matching text in
118
    /// reverse. In particular, all concatenations are flipped.
119
18
    pub fn reverse(mut self, yes: bool) -> Self {
120
18
        self.compiled.is_reverse = yes;
121
18
        self
122
18
    }
<regex::compile::Compiler>::reverse
Line
Count
Source
119
9
    pub fn reverse(mut self, yes: bool) -> Self {
120
9
        self.compiled.is_reverse = yes;
121
9
        self
122
9
    }
<regex::compile::Compiler>::reverse
Line
Count
Source
119
9
    pub fn reverse(mut self, yes: bool) -> Self {
120
9
        self.compiled.is_reverse = yes;
121
9
        self
122
9
    }
123
124
    /// Compile a regular expression given its AST.
125
    ///
126
    /// The compiler is guaranteed to succeed unless the program exceeds the
127
    /// specified size limit. If the size limit is exceeded, then compilation
128
    /// stops and returns an error.
129
54
    pub fn compile(mut self, exprs: &[Hir]) -> result::Result<Program, Error> {
130
54
        debug_assert!(!exprs.is_empty());
131
54
        self.num_exprs = exprs.len();
132
54
        if exprs.len() == 1 {
133
54
            self.compile_one(&exprs[0])
134
        } else {
135
0
            self.compile_many(exprs)
136
        }
137
54
    }
<regex::compile::Compiler>::compile
Line
Count
Source
129
27
    pub fn compile(mut self, exprs: &[Hir]) -> result::Result<Program, Error> {
130
27
        debug_assert!(!exprs.is_empty());
131
27
        self.num_exprs = exprs.len();
132
27
        if exprs.len() == 1 {
133
27
            self.compile_one(&exprs[0])
134
        } else {
135
0
            self.compile_many(exprs)
136
        }
137
27
    }
<regex::compile::Compiler>::compile
Line
Count
Source
129
27
    pub fn compile(mut self, exprs: &[Hir]) -> result::Result<Program, Error> {
130
27
        debug_assert!(!exprs.is_empty());
131
27
        self.num_exprs = exprs.len();
132
27
        if exprs.len() == 1 {
133
27
            self.compile_one(&exprs[0])
134
        } else {
135
0
            self.compile_many(exprs)
136
        }
137
27
    }
138
139
54
    fn compile_one(mut self, expr: &Hir) -> result::Result<Program, Error> {
140
        // If we're compiling a forward DFA and we aren't anchored, then
141
        // add a `.*?` before the first capture group.
142
        // Other matching engines handle this by baking the logic into the
143
        // matching engine itself.
144
54
        let mut dotstar_patch = Patch { hole: Hole::None, entry: 0 };
145
54
        self.compiled.is_anchored_start = expr.is_anchored_start();
146
54
        self.compiled.is_anchored_end = expr.is_anchored_end();
147
54
        if self.compiled.needs_dotstar() {
148
0
            dotstar_patch = self.c_dotstar()?;
149
0
            self.compiled.start = dotstar_patch.entry;
150
54
        }
151
54
        self.compiled.captures = vec![None];
152
54
        let patch = self.c_capture(0, expr)?.unwrap_or(self.next_inst());
153
54
        if self.compiled.needs_dotstar() {
154
0
            self.fill(dotstar_patch.hole, patch.entry);
155
54
        } else {
156
54
            self.compiled.start = patch.entry;
157
54
        }
158
54
        self.fill_to_next(patch.hole);
159
54
        self.compiled.matches = vec![self.insts.len()];
160
54
        self.push_compiled(Inst::Match(0));
161
54
        self.compile_finish()
162
54
    }
<regex::compile::Compiler>::compile_one
Line
Count
Source
139
27
    fn compile_one(mut self, expr: &Hir) -> result::Result<Program, Error> {
140
        // If we're compiling a forward DFA and we aren't anchored, then
141
        // add a `.*?` before the first capture group.
142
        // Other matching engines handle this by baking the logic into the
143
        // matching engine itself.
144
27
        let mut dotstar_patch = Patch { hole: Hole::None, entry: 0 };
145
27
        self.compiled.is_anchored_start = expr.is_anchored_start();
146
27
        self.compiled.is_anchored_end = expr.is_anchored_end();
147
27
        if self.compiled.needs_dotstar() {
148
0
            dotstar_patch = self.c_dotstar()?;
149
0
            self.compiled.start = dotstar_patch.entry;
150
27
        }
151
27
        self.compiled.captures = vec![None];
152
27
        let patch = self.c_capture(0, expr)?.unwrap_or(self.next_inst());
153
27
        if self.compiled.needs_dotstar() {
154
0
            self.fill(dotstar_patch.hole, patch.entry);
155
27
        } else {
156
27
            self.compiled.start = patch.entry;
157
27
        }
158
27
        self.fill_to_next(patch.hole);
159
27
        self.compiled.matches = vec![self.insts.len()];
160
27
        self.push_compiled(Inst::Match(0));
161
27
        self.compile_finish()
162
27
    }
<regex::compile::Compiler>::compile_one
Line
Count
Source
139
27
    fn compile_one(mut self, expr: &Hir) -> result::Result<Program, Error> {
140
        // If we're compiling a forward DFA and we aren't anchored, then
141
        // add a `.*?` before the first capture group.
142
        // Other matching engines handle this by baking the logic into the
143
        // matching engine itself.
144
27
        let mut dotstar_patch = Patch { hole: Hole::None, entry: 0 };
145
27
        self.compiled.is_anchored_start = expr.is_anchored_start();
146
27
        self.compiled.is_anchored_end = expr.is_anchored_end();
147
27
        if self.compiled.needs_dotstar() {
148
0
            dotstar_patch = self.c_dotstar()?;
149
0
            self.compiled.start = dotstar_patch.entry;
150
27
        }
151
27
        self.compiled.captures = vec![None];
152
27
        let patch = self.c_capture(0, expr)?.unwrap_or(self.next_inst());
153
27
        if self.compiled.needs_dotstar() {
154
0
            self.fill(dotstar_patch.hole, patch.entry);
155
27
        } else {
156
27
            self.compiled.start = patch.entry;
157
27
        }
158
27
        self.fill_to_next(patch.hole);
159
27
        self.compiled.matches = vec![self.insts.len()];
160
27
        self.push_compiled(Inst::Match(0));
161
27
        self.compile_finish()
162
27
    }
163
164
0
    fn compile_many(
165
0
        mut self,
166
0
        exprs: &[Hir],
167
0
    ) -> result::Result<Program, Error> {
168
0
        debug_assert!(exprs.len() > 1);
169
170
        self.compiled.is_anchored_start =
171
0
            exprs.iter().all(|e| e.is_anchored_start());
Unexecuted instantiation: <regex::compile::Compiler>::compile_many::{closure#0}
Unexecuted instantiation: <regex::compile::Compiler>::compile_many::{closure#0}
172
        self.compiled.is_anchored_end =
173
0
            exprs.iter().all(|e| e.is_anchored_end());
Unexecuted instantiation: <regex::compile::Compiler>::compile_many::{closure#1}
Unexecuted instantiation: <regex::compile::Compiler>::compile_many::{closure#1}
174
0
        let mut dotstar_patch = Patch { hole: Hole::None, entry: 0 };
175
0
        if self.compiled.needs_dotstar() {
176
0
            dotstar_patch = self.c_dotstar()?;
177
0
            self.compiled.start = dotstar_patch.entry;
178
0
        } else {
179
0
            self.compiled.start = 0; // first instruction is always split
180
0
        }
181
0
        self.fill_to_next(dotstar_patch.hole);
182
183
0
        let mut prev_hole = Hole::None;
184
0
        for (i, expr) in exprs[0..exprs.len() - 1].iter().enumerate() {
185
0
            self.fill_to_next(prev_hole);
186
0
            let split = self.push_split_hole();
187
0
            let Patch { hole, entry } =
188
0
                self.c_capture(0, expr)?.unwrap_or(self.next_inst());
189
0
            self.fill_to_next(hole);
190
0
            self.compiled.matches.push(self.insts.len());
191
0
            self.push_compiled(Inst::Match(i));
192
0
            prev_hole = self.fill_split(split, Some(entry), None);
193
        }
194
0
        let i = exprs.len() - 1;
195
0
        let Patch { hole, entry } =
196
0
            self.c_capture(0, &exprs[i])?.unwrap_or(self.next_inst());
197
0
        self.fill(prev_hole, entry);
198
0
        self.fill_to_next(hole);
199
0
        self.compiled.matches.push(self.insts.len());
200
0
        self.push_compiled(Inst::Match(i));
201
0
        self.compile_finish()
202
0
    }
Unexecuted instantiation: <regex::compile::Compiler>::compile_many
Unexecuted instantiation: <regex::compile::Compiler>::compile_many
203
204
54
    fn compile_finish(mut self) -> result::Result<Program, Error> {
205
54
        self.compiled.insts =
206
4.62k
            self.insts.into_iter().map(|inst| inst.unwrap()).collect();
<regex::compile::Compiler>::compile_finish::{closure#0}
Line
Count
Source
206
2.31k
            self.insts.into_iter().map(|inst| inst.unwrap()).collect();
<regex::compile::Compiler>::compile_finish::{closure#0}
Line
Count
Source
206
2.31k
            self.insts.into_iter().map(|inst| inst.unwrap()).collect();
207
54
        self.compiled.byte_classes = self.byte_classes.byte_classes();
208
54
        self.compiled.capture_name_idx = Arc::new(self.capture_name_idx);
209
54
        Ok(self.compiled)
210
54
    }
<regex::compile::Compiler>::compile_finish
Line
Count
Source
204
27
    fn compile_finish(mut self) -> result::Result<Program, Error> {
205
27
        self.compiled.insts =
206
27
            self.insts.into_iter().map(|inst| inst.unwrap()).collect();
207
27
        self.compiled.byte_classes = self.byte_classes.byte_classes();
208
27
        self.compiled.capture_name_idx = Arc::new(self.capture_name_idx);
209
27
        Ok(self.compiled)
210
27
    }
<regex::compile::Compiler>::compile_finish
Line
Count
Source
204
27
    fn compile_finish(mut self) -> result::Result<Program, Error> {
205
27
        self.compiled.insts =
206
27
            self.insts.into_iter().map(|inst| inst.unwrap()).collect();
207
27
        self.compiled.byte_classes = self.byte_classes.byte_classes();
208
27
        self.compiled.capture_name_idx = Arc::new(self.capture_name_idx);
209
27
        Ok(self.compiled)
210
27
    }
211
212
    /// Compile expr into self.insts, returning a patch on success,
213
    /// or an error if we run out of memory.
214
    ///
215
    /// All of the c_* methods of the compiler share the contract outlined
216
    /// here.
217
    ///
218
    /// The main thing that a c_* method does is mutate `self.insts`
219
    /// to add a list of mostly compiled instructions required to execute
220
    /// the given expression. `self.insts` contains MaybeInsts rather than
221
    /// Insts because there is some backpatching required.
222
    ///
223
    /// The `Patch` value returned by each c_* method provides metadata
224
    /// about the compiled instructions emitted to `self.insts`. The
225
    /// `entry` member of the patch refers to the first instruction
226
    /// (the entry point), while the `hole` member contains zero or
227
    /// more offsets to partial instructions that need to be backpatched.
228
    /// The c_* routine can't know where its list of instructions are going to
229
    /// jump to after execution, so it is up to the caller to patch
230
    /// these jumps to point to the right place. So compiling some
231
    /// expression, e, we would end up with a situation that looked like:
232
    ///
233
    /// ```text
234
    /// self.insts = [ ..., i1, i2, ..., iexit1, ..., iexitn, ...]
235
    ///                     ^              ^             ^
236
    ///                     |                \         /
237
    ///                   entry                \     /
238
    ///                                         hole
239
    /// ```
240
    ///
241
    /// To compile two expressions, e1 and e2, concatenated together we
242
    /// would do:
243
    ///
244
    /// ```ignore
245
    /// let patch1 = self.c(e1);
246
    /// let patch2 = self.c(e2);
247
    /// ```
248
    ///
249
    /// while leaves us with a situation that looks like
250
    ///
251
    /// ```text
252
    /// self.insts = [ ..., i1, ..., iexit1, ..., i2, ..., iexit2 ]
253
    ///                     ^        ^            ^        ^
254
    ///                     |        |            |        |
255
    ///                entry1        hole1   entry2        hole2
256
    /// ```
257
    ///
258
    /// Then to merge the two patches together into one we would backpatch
259
    /// hole1 with entry2 and return a new patch that enters at entry1
260
    /// and has hole2 for a hole. In fact, if you look at the c_concat
261
    /// method you will see that it does exactly this, though it handles
262
    /// a list of expressions rather than just the two that we use for
263
    /// an example.
264
    ///
265
    /// Ok(None) is returned when an expression is compiled to no
266
    /// instruction, and so no patch.entry value makes sense.
267
4.03k
    fn c(&mut self, expr: &Hir) -> ResultOrEmpty {
268
        use crate::prog;
269
        use regex_syntax::hir::HirKind::*;
270
271
4.03k
        self.check_size()?;
272
4.03k
        match *expr.kind() {
273
0
            Empty => self.c_empty(),
274
1.67k
            Literal(hir::Literal::Unicode(c)) => self.c_char(c),
275
0
            Literal(hir::Literal::Byte(b)) => {
276
0
                assert!(self.compiled.uses_bytes());
277
0
                self.c_byte(b)
278
            }
279
630
            Class(hir::Class::Unicode(ref cls)) => self.c_class(cls.ranges()),
280
0
            Class(hir::Class::Bytes(ref cls)) => {
281
0
                if self.compiled.uses_bytes() {
282
0
                    self.c_class_bytes(cls.ranges())
283
                } else {
284
0
                    assert!(cls.is_all_ascii());
285
0
                    let mut char_ranges = vec![];
286
0
                    for r in cls.iter() {
287
0
                        let (s, e) = (r.start() as char, r.end() as char);
288
0
                        char_ranges.push(hir::ClassUnicodeRange::new(s, e));
289
0
                    }
290
0
                    self.c_class(&char_ranges)
291
                }
292
            }
293
0
            Anchor(hir::Anchor::StartLine) if self.compiled.is_reverse => {
294
0
                self.byte_classes.set_range(b'\n', b'\n');
295
0
                self.c_empty_look(prog::EmptyLook::EndLine)
296
            }
297
            Anchor(hir::Anchor::StartLine) => {
298
0
                self.byte_classes.set_range(b'\n', b'\n');
299
0
                self.c_empty_look(prog::EmptyLook::StartLine)
300
            }
301
0
            Anchor(hir::Anchor::EndLine) if self.compiled.is_reverse => {
302
0
                self.byte_classes.set_range(b'\n', b'\n');
303
0
                self.c_empty_look(prog::EmptyLook::StartLine)
304
            }
305
            Anchor(hir::Anchor::EndLine) => {
306
0
                self.byte_classes.set_range(b'\n', b'\n');
307
0
                self.c_empty_look(prog::EmptyLook::EndLine)
308
            }
309
18
            Anchor(hir::Anchor::StartText) if self.compiled.is_reverse => {
310
18
                self.c_empty_look(prog::EmptyLook::EndText)
311
            }
312
            Anchor(hir::Anchor::StartText) => {
313
36
                self.c_empty_look(prog::EmptyLook::StartText)
314
            }
315
18
            Anchor(hir::Anchor::EndText) if self.compiled.is_reverse => {
316
18
                self.c_empty_look(prog::EmptyLook::StartText)
317
            }
318
            Anchor(hir::Anchor::EndText) => {
319
36
                self.c_empty_look(prog::EmptyLook::EndText)
320
            }
321
            WordBoundary(hir::WordBoundary::Unicode) => {
322
0
                if !cfg!(feature = "unicode-perl") {
323
0
                    return Err(Error::Syntax(
324
0
                        "Unicode word boundaries are unavailable when \
325
0
                         the unicode-perl feature is disabled"
326
0
                            .to_string(),
327
0
                    ));
328
0
                }
329
0
                self.compiled.has_unicode_word_boundary = true;
330
0
                self.byte_classes.set_word_boundary();
331
                // We also make sure that all ASCII bytes are in a different
332
                // class from non-ASCII bytes. Otherwise, it's possible for
333
                // ASCII bytes to get lumped into the same class as non-ASCII
334
                // bytes. This in turn may cause the lazy DFA to falsely start
335
                // when it sees an ASCII byte that maps to a byte class with
336
                // non-ASCII bytes. This ensures that never happens.
337
0
                self.byte_classes.set_range(0, 0x7F);
338
0
                self.c_empty_look(prog::EmptyLook::WordBoundary)
339
            }
340
            WordBoundary(hir::WordBoundary::UnicodeNegate) => {
341
0
                if !cfg!(feature = "unicode-perl") {
342
0
                    return Err(Error::Syntax(
343
0
                        "Unicode word boundaries are unavailable when \
344
0
                         the unicode-perl feature is disabled"
345
0
                            .to_string(),
346
0
                    ));
347
0
                }
348
0
                self.compiled.has_unicode_word_boundary = true;
349
0
                self.byte_classes.set_word_boundary();
350
                // See comments above for why we set the ASCII range here.
351
0
                self.byte_classes.set_range(0, 0x7F);
352
0
                self.c_empty_look(prog::EmptyLook::NotWordBoundary)
353
            }
354
            WordBoundary(hir::WordBoundary::Ascii) => {
355
0
                self.byte_classes.set_word_boundary();
356
0
                self.c_empty_look(prog::EmptyLook::WordBoundaryAscii)
357
            }
358
            WordBoundary(hir::WordBoundary::AsciiNegate) => {
359
0
                self.byte_classes.set_word_boundary();
360
0
                self.c_empty_look(prog::EmptyLook::NotWordBoundaryAscii)
361
            }
362
324
            Group(ref g) => match g.kind {
363
126
                hir::GroupKind::NonCapturing => self.c(&g.hir),
364
198
                hir::GroupKind::CaptureIndex(index) => {
365
198
                    if index as usize >= self.compiled.captures.len() {
366
168
                        self.compiled.captures.push(None);
367
168
                    }
368
198
                    self.c_capture(2 * index as usize, &g.hir)
369
                }
370
0
                hir::GroupKind::CaptureName { index, ref name } => {
371
0
                    if index as usize >= self.compiled.captures.len() {
372
0
                        let n = name.to_string();
373
0
                        self.compiled.captures.push(Some(n.clone()));
374
0
                        self.capture_name_idx.insert(n, index as usize);
375
0
                    }
376
0
                    self.c_capture(2 * index as usize, &g.hir)
377
                }
378
            },
379
360
            Concat(ref es) => {
380
360
                if self.compiled.is_reverse {
381
120
                    self.c_concat(es.iter().rev())
382
                } else {
383
240
                    self.c_concat(es)
384
                }
385
            }
386
36
            Alternation(ref es) => self.c_alternate(&**es),
387
900
            Repetition(ref rep) => self.c_repeat(rep),
388
        }
389
4.03k
    }
<regex::compile::Compiler>::c
Line
Count
Source
267
2.01k
    fn c(&mut self, expr: &Hir) -> ResultOrEmpty {
268
        use crate::prog;
269
        use regex_syntax::hir::HirKind::*;
270
271
2.01k
        self.check_size()?;
272
2.01k
        match *expr.kind() {
273
0
            Empty => self.c_empty(),
274
837
            Literal(hir::Literal::Unicode(c)) => self.c_char(c),
275
0
            Literal(hir::Literal::Byte(b)) => {
276
0
                assert!(self.compiled.uses_bytes());
277
0
                self.c_byte(b)
278
            }
279
315
            Class(hir::Class::Unicode(ref cls)) => self.c_class(cls.ranges()),
280
0
            Class(hir::Class::Bytes(ref cls)) => {
281
0
                if self.compiled.uses_bytes() {
282
0
                    self.c_class_bytes(cls.ranges())
283
                } else {
284
0
                    assert!(cls.is_all_ascii());
285
0
                    let mut char_ranges = vec![];
286
0
                    for r in cls.iter() {
287
0
                        let (s, e) = (r.start() as char, r.end() as char);
288
0
                        char_ranges.push(hir::ClassUnicodeRange::new(s, e));
289
0
                    }
290
0
                    self.c_class(&char_ranges)
291
                }
292
            }
293
0
            Anchor(hir::Anchor::StartLine) if self.compiled.is_reverse => {
294
0
                self.byte_classes.set_range(b'\n', b'\n');
295
0
                self.c_empty_look(prog::EmptyLook::EndLine)
296
            }
297
            Anchor(hir::Anchor::StartLine) => {
298
0
                self.byte_classes.set_range(b'\n', b'\n');
299
0
                self.c_empty_look(prog::EmptyLook::StartLine)
300
            }
301
0
            Anchor(hir::Anchor::EndLine) if self.compiled.is_reverse => {
302
0
                self.byte_classes.set_range(b'\n', b'\n');
303
0
                self.c_empty_look(prog::EmptyLook::StartLine)
304
            }
305
            Anchor(hir::Anchor::EndLine) => {
306
0
                self.byte_classes.set_range(b'\n', b'\n');
307
0
                self.c_empty_look(prog::EmptyLook::EndLine)
308
            }
309
9
            Anchor(hir::Anchor::StartText) if self.compiled.is_reverse => {
310
9
                self.c_empty_look(prog::EmptyLook::EndText)
311
            }
312
            Anchor(hir::Anchor::StartText) => {
313
18
                self.c_empty_look(prog::EmptyLook::StartText)
314
            }
315
9
            Anchor(hir::Anchor::EndText) if self.compiled.is_reverse => {
316
9
                self.c_empty_look(prog::EmptyLook::StartText)
317
            }
318
            Anchor(hir::Anchor::EndText) => {
319
18
                self.c_empty_look(prog::EmptyLook::EndText)
320
            }
321
            WordBoundary(hir::WordBoundary::Unicode) => {
322
0
                if !cfg!(feature = "unicode-perl") {
323
0
                    return Err(Error::Syntax(
324
0
                        "Unicode word boundaries are unavailable when \
325
0
                         the unicode-perl feature is disabled"
326
0
                            .to_string(),
327
0
                    ));
328
0
                }
329
0
                self.compiled.has_unicode_word_boundary = true;
330
0
                self.byte_classes.set_word_boundary();
331
                // We also make sure that all ASCII bytes are in a different
332
                // class from non-ASCII bytes. Otherwise, it's possible for
333
                // ASCII bytes to get lumped into the same class as non-ASCII
334
                // bytes. This in turn may cause the lazy DFA to falsely start
335
                // when it sees an ASCII byte that maps to a byte class with
336
                // non-ASCII bytes. This ensures that never happens.
337
0
                self.byte_classes.set_range(0, 0x7F);
338
0
                self.c_empty_look(prog::EmptyLook::WordBoundary)
339
            }
340
            WordBoundary(hir::WordBoundary::UnicodeNegate) => {
341
0
                if !cfg!(feature = "unicode-perl") {
342
0
                    return Err(Error::Syntax(
343
0
                        "Unicode word boundaries are unavailable when \
344
0
                         the unicode-perl feature is disabled"
345
0
                            .to_string(),
346
0
                    ));
347
0
                }
348
0
                self.compiled.has_unicode_word_boundary = true;
349
0
                self.byte_classes.set_word_boundary();
350
                // See comments above for why we set the ASCII range here.
351
0
                self.byte_classes.set_range(0, 0x7F);
352
0
                self.c_empty_look(prog::EmptyLook::NotWordBoundary)
353
            }
354
            WordBoundary(hir::WordBoundary::Ascii) => {
355
0
                self.byte_classes.set_word_boundary();
356
0
                self.c_empty_look(prog::EmptyLook::WordBoundaryAscii)
357
            }
358
            WordBoundary(hir::WordBoundary::AsciiNegate) => {
359
0
                self.byte_classes.set_word_boundary();
360
0
                self.c_empty_look(prog::EmptyLook::NotWordBoundaryAscii)
361
            }
362
162
            Group(ref g) => match g.kind {
363
63
                hir::GroupKind::NonCapturing => self.c(&g.hir),
364
99
                hir::GroupKind::CaptureIndex(index) => {
365
99
                    if index as usize >= self.compiled.captures.len() {
366
84
                        self.compiled.captures.push(None);
367
84
                    }
368
99
                    self.c_capture(2 * index as usize, &g.hir)
369
                }
370
0
                hir::GroupKind::CaptureName { index, ref name } => {
371
0
                    if index as usize >= self.compiled.captures.len() {
372
0
                        let n = name.to_string();
373
0
                        self.compiled.captures.push(Some(n.clone()));
374
0
                        self.capture_name_idx.insert(n, index as usize);
375
0
                    }
376
0
                    self.c_capture(2 * index as usize, &g.hir)
377
                }
378
            },
379
180
            Concat(ref es) => {
380
180
                if self.compiled.is_reverse {
381
60
                    self.c_concat(es.iter().rev())
382
                } else {
383
120
                    self.c_concat(es)
384
                }
385
            }
386
18
            Alternation(ref es) => self.c_alternate(&**es),
387
450
            Repetition(ref rep) => self.c_repeat(rep),
388
        }
389
2.01k
    }
<regex::compile::Compiler>::c
Line
Count
Source
267
2.01k
    fn c(&mut self, expr: &Hir) -> ResultOrEmpty {
268
        use crate::prog;
269
        use regex_syntax::hir::HirKind::*;
270
271
2.01k
        self.check_size()?;
272
2.01k
        match *expr.kind() {
273
0
            Empty => self.c_empty(),
274
837
            Literal(hir::Literal::Unicode(c)) => self.c_char(c),
275
0
            Literal(hir::Literal::Byte(b)) => {
276
0
                assert!(self.compiled.uses_bytes());
277
0
                self.c_byte(b)
278
            }
279
315
            Class(hir::Class::Unicode(ref cls)) => self.c_class(cls.ranges()),
280
0
            Class(hir::Class::Bytes(ref cls)) => {
281
0
                if self.compiled.uses_bytes() {
282
0
                    self.c_class_bytes(cls.ranges())
283
                } else {
284
0
                    assert!(cls.is_all_ascii());
285
0
                    let mut char_ranges = vec![];
286
0
                    for r in cls.iter() {
287
0
                        let (s, e) = (r.start() as char, r.end() as char);
288
0
                        char_ranges.push(hir::ClassUnicodeRange::new(s, e));
289
0
                    }
290
0
                    self.c_class(&char_ranges)
291
                }
292
            }
293
0
            Anchor(hir::Anchor::StartLine) if self.compiled.is_reverse => {
294
0
                self.byte_classes.set_range(b'\n', b'\n');
295
0
                self.c_empty_look(prog::EmptyLook::EndLine)
296
            }
297
            Anchor(hir::Anchor::StartLine) => {
298
0
                self.byte_classes.set_range(b'\n', b'\n');
299
0
                self.c_empty_look(prog::EmptyLook::StartLine)
300
            }
301
0
            Anchor(hir::Anchor::EndLine) if self.compiled.is_reverse => {
302
0
                self.byte_classes.set_range(b'\n', b'\n');
303
0
                self.c_empty_look(prog::EmptyLook::StartLine)
304
            }
305
            Anchor(hir::Anchor::EndLine) => {
306
0
                self.byte_classes.set_range(b'\n', b'\n');
307
0
                self.c_empty_look(prog::EmptyLook::EndLine)
308
            }
309
9
            Anchor(hir::Anchor::StartText) if self.compiled.is_reverse => {
310
9
                self.c_empty_look(prog::EmptyLook::EndText)
311
            }
312
            Anchor(hir::Anchor::StartText) => {
313
18
                self.c_empty_look(prog::EmptyLook::StartText)
314
            }
315
9
            Anchor(hir::Anchor::EndText) if self.compiled.is_reverse => {
316
9
                self.c_empty_look(prog::EmptyLook::StartText)
317
            }
318
            Anchor(hir::Anchor::EndText) => {
319
18
                self.c_empty_look(prog::EmptyLook::EndText)
320
            }
321
            WordBoundary(hir::WordBoundary::Unicode) => {
322
0
                if !cfg!(feature = "unicode-perl") {
323
0
                    return Err(Error::Syntax(
324
0
                        "Unicode word boundaries are unavailable when \
325
0
                         the unicode-perl feature is disabled"
326
0
                            .to_string(),
327
0
                    ));
328
0
                }
329
0
                self.compiled.has_unicode_word_boundary = true;
330
0
                self.byte_classes.set_word_boundary();
331
                // We also make sure that all ASCII bytes are in a different
332
                // class from non-ASCII bytes. Otherwise, it's possible for
333
                // ASCII bytes to get lumped into the same class as non-ASCII
334
                // bytes. This in turn may cause the lazy DFA to falsely start
335
                // when it sees an ASCII byte that maps to a byte class with
336
                // non-ASCII bytes. This ensures that never happens.
337
0
                self.byte_classes.set_range(0, 0x7F);
338
0
                self.c_empty_look(prog::EmptyLook::WordBoundary)
339
            }
340
            WordBoundary(hir::WordBoundary::UnicodeNegate) => {
341
0
                if !cfg!(feature = "unicode-perl") {
342
0
                    return Err(Error::Syntax(
343
0
                        "Unicode word boundaries are unavailable when \
344
0
                         the unicode-perl feature is disabled"
345
0
                            .to_string(),
346
0
                    ));
347
0
                }
348
0
                self.compiled.has_unicode_word_boundary = true;
349
0
                self.byte_classes.set_word_boundary();
350
                // See comments above for why we set the ASCII range here.
351
0
                self.byte_classes.set_range(0, 0x7F);
352
0
                self.c_empty_look(prog::EmptyLook::NotWordBoundary)
353
            }
354
            WordBoundary(hir::WordBoundary::Ascii) => {
355
0
                self.byte_classes.set_word_boundary();
356
0
                self.c_empty_look(prog::EmptyLook::WordBoundaryAscii)
357
            }
358
            WordBoundary(hir::WordBoundary::AsciiNegate) => {
359
0
                self.byte_classes.set_word_boundary();
360
0
                self.c_empty_look(prog::EmptyLook::NotWordBoundaryAscii)
361
            }
362
162
            Group(ref g) => match g.kind {
363
63
                hir::GroupKind::NonCapturing => self.c(&g.hir),
364
99
                hir::GroupKind::CaptureIndex(index) => {
365
99
                    if index as usize >= self.compiled.captures.len() {
366
84
                        self.compiled.captures.push(None);
367
84
                    }
368
99
                    self.c_capture(2 * index as usize, &g.hir)
369
                }
370
0
                hir::GroupKind::CaptureName { index, ref name } => {
371
0
                    if index as usize >= self.compiled.captures.len() {
372
0
                        let n = name.to_string();
373
0
                        self.compiled.captures.push(Some(n.clone()));
374
0
                        self.capture_name_idx.insert(n, index as usize);
375
0
                    }
376
0
                    self.c_capture(2 * index as usize, &g.hir)
377
                }
378
            },
379
180
            Concat(ref es) => {
380
180
                if self.compiled.is_reverse {
381
60
                    self.c_concat(es.iter().rev())
382
                } else {
383
120
                    self.c_concat(es)
384
                }
385
            }
386
18
            Alternation(ref es) => self.c_alternate(&**es),
387
450
            Repetition(ref rep) => self.c_repeat(rep),
388
        }
389
2.01k
    }
390
391
0
    fn c_empty(&mut self) -> ResultOrEmpty {
392
        // See: https://github.com/rust-lang/regex/security/advisories/GHSA-m5pq-gvj9-9vr8
393
        // See: CVE-2022-24713
394
        //
395
        // Since 'empty' sub-expressions don't increase the size of
396
        // the actual compiled object, we "fake" an increase in its
397
        // size so that our 'check_size_limit' routine will eventually
398
        // stop compilation if there are too many empty sub-expressions
399
        // (e.g., via a large repetition).
400
0
        self.extra_inst_bytes += std::mem::size_of::<Inst>();
401
0
        Ok(None)
402
0
    }
Unexecuted instantiation: <regex::compile::Compiler>::c_empty
Unexecuted instantiation: <regex::compile::Compiler>::c_empty
403
404
252
    fn c_capture(&mut self, first_slot: usize, expr: &Hir) -> ResultOrEmpty {
405
252
        if self.num_exprs > 1 || self.compiled.is_dfa {
406
            // Don't ever compile Save instructions for regex sets because
407
            // they are never used. They are also never used in DFA programs
408
            // because DFAs can't handle captures.
409
168
            self.c(expr)
410
        } else {
411
84
            let entry = self.insts.len();
412
84
            let hole = self.push_hole(InstHole::Save { slot: first_slot });
413
84
            let patch = self.c(expr)?.unwrap_or(self.next_inst());
414
84
            self.fill(hole, patch.entry);
415
84
            self.fill_to_next(patch.hole);
416
84
            let hole = self.push_hole(InstHole::Save { slot: first_slot + 1 });
417
84
            Ok(Some(Patch { hole: hole, entry: entry }))
418
        }
419
252
    }
<regex::compile::Compiler>::c_capture
Line
Count
Source
404
126
    fn c_capture(&mut self, first_slot: usize, expr: &Hir) -> ResultOrEmpty {
405
126
        if self.num_exprs > 1 || self.compiled.is_dfa {
406
            // Don't ever compile Save instructions for regex sets because
407
            // they are never used. They are also never used in DFA programs
408
            // because DFAs can't handle captures.
409
84
            self.c(expr)
410
        } else {
411
42
            let entry = self.insts.len();
412
42
            let hole = self.push_hole(InstHole::Save { slot: first_slot });
413
42
            let patch = self.c(expr)?.unwrap_or(self.next_inst());
414
42
            self.fill(hole, patch.entry);
415
42
            self.fill_to_next(patch.hole);
416
42
            let hole = self.push_hole(InstHole::Save { slot: first_slot + 1 });
417
42
            Ok(Some(Patch { hole: hole, entry: entry }))
418
        }
419
126
    }
<regex::compile::Compiler>::c_capture
Line
Count
Source
404
126
    fn c_capture(&mut self, first_slot: usize, expr: &Hir) -> ResultOrEmpty {
405
126
        if self.num_exprs > 1 || self.compiled.is_dfa {
406
            // Don't ever compile Save instructions for regex sets because
407
            // they are never used. They are also never used in DFA programs
408
            // because DFAs can't handle captures.
409
84
            self.c(expr)
410
        } else {
411
42
            let entry = self.insts.len();
412
42
            let hole = self.push_hole(InstHole::Save { slot: first_slot });
413
42
            let patch = self.c(expr)?.unwrap_or(self.next_inst());
414
42
            self.fill(hole, patch.entry);
415
42
            self.fill_to_next(patch.hole);
416
42
            let hole = self.push_hole(InstHole::Save { slot: first_slot + 1 });
417
42
            Ok(Some(Patch { hole: hole, entry: entry }))
418
        }
419
126
    }
420
421
0
    fn c_dotstar(&mut self) -> Result {
422
0
        Ok(if !self.compiled.only_utf8() {
423
0
            self.c(&Hir::repetition(hir::Repetition {
424
0
                kind: hir::RepetitionKind::ZeroOrMore,
425
0
                greedy: false,
426
0
                hir: Box::new(Hir::any(true)),
427
0
            }))?
428
0
            .unwrap()
429
        } else {
430
0
            self.c(&Hir::repetition(hir::Repetition {
431
0
                kind: hir::RepetitionKind::ZeroOrMore,
432
0
                greedy: false,
433
0
                hir: Box::new(Hir::any(false)),
434
0
            }))?
435
0
            .unwrap()
436
        })
437
0
    }
Unexecuted instantiation: <regex::compile::Compiler>::c_dotstar
Unexecuted instantiation: <regex::compile::Compiler>::c_dotstar
438
439
1.67k
    fn c_char(&mut self, c: char) -> ResultOrEmpty {
440
1.67k
        if self.compiled.uses_bytes() {
441
1.11k
            if c.is_ascii() {
442
1.11k
                let b = c as u8;
443
1.11k
                let hole =
444
1.11k
                    self.push_hole(InstHole::Bytes { start: b, end: b });
445
1.11k
                self.byte_classes.set_range(b, b);
446
1.11k
                Ok(Some(Patch { hole, entry: self.insts.len() - 1 }))
447
            } else {
448
0
                self.c_class(&[hir::ClassUnicodeRange::new(c, c)])
449
            }
450
        } else {
451
558
            let hole = self.push_hole(InstHole::Char { c: c });
452
558
            Ok(Some(Patch { hole, entry: self.insts.len() - 1 }))
453
        }
454
1.67k
    }
<regex::compile::Compiler>::c_char
Line
Count
Source
439
837
    fn c_char(&mut self, c: char) -> ResultOrEmpty {
440
837
        if self.compiled.uses_bytes() {
441
558
            if c.is_ascii() {
442
558
                let b = c as u8;
443
558
                let hole =
444
558
                    self.push_hole(InstHole::Bytes { start: b, end: b });
445
558
                self.byte_classes.set_range(b, b);
446
558
                Ok(Some(Patch { hole, entry: self.insts.len() - 1 }))
447
            } else {
448
0
                self.c_class(&[hir::ClassUnicodeRange::new(c, c)])
449
            }
450
        } else {
451
279
            let hole = self.push_hole(InstHole::Char { c: c });
452
279
            Ok(Some(Patch { hole, entry: self.insts.len() - 1 }))
453
        }
454
837
    }
<regex::compile::Compiler>::c_char
Line
Count
Source
439
837
    fn c_char(&mut self, c: char) -> ResultOrEmpty {
440
837
        if self.compiled.uses_bytes() {
441
558
            if c.is_ascii() {
442
558
                let b = c as u8;
443
558
                let hole =
444
558
                    self.push_hole(InstHole::Bytes { start: b, end: b });
445
558
                self.byte_classes.set_range(b, b);
446
558
                Ok(Some(Patch { hole, entry: self.insts.len() - 1 }))
447
            } else {
448
0
                self.c_class(&[hir::ClassUnicodeRange::new(c, c)])
449
            }
450
        } else {
451
279
            let hole = self.push_hole(InstHole::Char { c: c });
452
279
            Ok(Some(Patch { hole, entry: self.insts.len() - 1 }))
453
        }
454
837
    }
455
456
630
    fn c_class(&mut self, ranges: &[hir::ClassUnicodeRange]) -> ResultOrEmpty {
457
        use std::mem::size_of;
458
459
630
        assert!(!ranges.is_empty());
460
630
        if self.compiled.uses_bytes() {
461
420
            Ok(Some(CompileClass { c: self, ranges: ranges }.compile()?))
462
        } else {
463
210
            let ranges: Vec<(char, char)> =
464
378
                ranges.iter().map(|r| (r.start(), r.end())).collect();
<regex::compile::Compiler>::c_class::{closure#0}
Line
Count
Source
464
189
                ranges.iter().map(|r| (r.start(), r.end())).collect();
<regex::compile::Compiler>::c_class::{closure#0}
Line
Count
Source
464
189
                ranges.iter().map(|r| (r.start(), r.end())).collect();
465
210
            let hole = if ranges.len() == 1 && ranges[0].0 == ranges[0].1 {
466
0
                self.push_hole(InstHole::Char { c: ranges[0].0 })
467
            } else {
468
210
                self.extra_inst_bytes +=
469
210
                    ranges.len() * (size_of::<char>() * 2);
470
210
                self.push_hole(InstHole::Ranges { ranges: ranges })
471
            };
472
210
            Ok(Some(Patch { hole: hole, entry: self.insts.len() - 1 }))
473
        }
474
630
    }
<regex::compile::Compiler>::c_class
Line
Count
Source
456
315
    fn c_class(&mut self, ranges: &[hir::ClassUnicodeRange]) -> ResultOrEmpty {
457
        use std::mem::size_of;
458
459
315
        assert!(!ranges.is_empty());
460
315
        if self.compiled.uses_bytes() {
461
210
            Ok(Some(CompileClass { c: self, ranges: ranges }.compile()?))
462
        } else {
463
105
            let ranges: Vec<(char, char)> =
464
105
                ranges.iter().map(|r| (r.start(), r.end())).collect();
465
105
            let hole = if ranges.len() == 1 && ranges[0].0 == ranges[0].1 {
466
0
                self.push_hole(InstHole::Char { c: ranges[0].0 })
467
            } else {
468
105
                self.extra_inst_bytes +=
469
105
                    ranges.len() * (size_of::<char>() * 2);
470
105
                self.push_hole(InstHole::Ranges { ranges: ranges })
471
            };
472
105
            Ok(Some(Patch { hole: hole, entry: self.insts.len() - 1 }))
473
        }
474
315
    }
<regex::compile::Compiler>::c_class
Line
Count
Source
456
315
    fn c_class(&mut self, ranges: &[hir::ClassUnicodeRange]) -> ResultOrEmpty {
457
        use std::mem::size_of;
458
459
315
        assert!(!ranges.is_empty());
460
315
        if self.compiled.uses_bytes() {
461
210
            Ok(Some(CompileClass { c: self, ranges: ranges }.compile()?))
462
        } else {
463
105
            let ranges: Vec<(char, char)> =
464
105
                ranges.iter().map(|r| (r.start(), r.end())).collect();
465
105
            let hole = if ranges.len() == 1 && ranges[0].0 == ranges[0].1 {
466
0
                self.push_hole(InstHole::Char { c: ranges[0].0 })
467
            } else {
468
105
                self.extra_inst_bytes +=
469
105
                    ranges.len() * (size_of::<char>() * 2);
470
105
                self.push_hole(InstHole::Ranges { ranges: ranges })
471
            };
472
105
            Ok(Some(Patch { hole: hole, entry: self.insts.len() - 1 }))
473
        }
474
315
    }
475
476
0
    fn c_byte(&mut self, b: u8) -> ResultOrEmpty {
477
0
        self.c_class_bytes(&[hir::ClassBytesRange::new(b, b)])
478
0
    }
Unexecuted instantiation: <regex::compile::Compiler>::c_byte
Unexecuted instantiation: <regex::compile::Compiler>::c_byte
479
480
0
    fn c_class_bytes(
481
0
        &mut self,
482
0
        ranges: &[hir::ClassBytesRange],
483
0
    ) -> ResultOrEmpty {
484
0
        debug_assert!(!ranges.is_empty());
485
486
0
        let first_split_entry = self.insts.len();
487
0
        let mut holes = vec![];
488
0
        let mut prev_hole = Hole::None;
489
0
        for r in &ranges[0..ranges.len() - 1] {
490
0
            self.fill_to_next(prev_hole);
491
0
            let split = self.push_split_hole();
492
0
            let next = self.insts.len();
493
0
            self.byte_classes.set_range(r.start(), r.end());
494
0
            holes.push(self.push_hole(InstHole::Bytes {
495
0
                start: r.start(),
496
0
                end: r.end(),
497
0
            }));
498
0
            prev_hole = self.fill_split(split, Some(next), None);
499
0
        }
500
0
        let next = self.insts.len();
501
0
        let r = &ranges[ranges.len() - 1];
502
0
        self.byte_classes.set_range(r.start(), r.end());
503
0
        holes.push(
504
0
            self.push_hole(InstHole::Bytes { start: r.start(), end: r.end() }),
505
        );
506
0
        self.fill(prev_hole, next);
507
0
        Ok(Some(Patch { hole: Hole::Many(holes), entry: first_split_entry }))
508
0
    }
Unexecuted instantiation: <regex::compile::Compiler>::c_class_bytes
Unexecuted instantiation: <regex::compile::Compiler>::c_class_bytes
509
510
108
    fn c_empty_look(&mut self, look: EmptyLook) -> ResultOrEmpty {
511
108
        let hole = self.push_hole(InstHole::EmptyLook { look: look });
512
108
        Ok(Some(Patch { hole: hole, entry: self.insts.len() - 1 }))
513
108
    }
<regex::compile::Compiler>::c_empty_look
Line
Count
Source
510
54
    fn c_empty_look(&mut self, look: EmptyLook) -> ResultOrEmpty {
511
54
        let hole = self.push_hole(InstHole::EmptyLook { look: look });
512
54
        Ok(Some(Patch { hole: hole, entry: self.insts.len() - 1 }))
513
54
    }
<regex::compile::Compiler>::c_empty_look
Line
Count
Source
510
54
    fn c_empty_look(&mut self, look: EmptyLook) -> ResultOrEmpty {
511
54
        let hole = self.push_hole(InstHole::EmptyLook { look: look });
512
54
        Ok(Some(Patch { hole: hole, entry: self.insts.len() - 1 }))
513
54
    }
514
515
360
    fn c_concat<'a, I>(&mut self, exprs: I) -> ResultOrEmpty
516
360
    where
517
360
        I: IntoIterator<Item = &'a Hir>,
518
    {
519
360
        let mut exprs = exprs.into_iter();
520
360
        let Patch { mut hole, entry } = loop {
521
360
            match exprs.next() {
522
0
                None => return self.c_empty(),
523
360
                Some(e) => {
524
360
                    if let Some(p) = self.c(e)? {
525
360
                        break p;
526
0
                    }
527
                }
528
            }
529
        };
530
2.64k
        for e in exprs {
531
2.28k
            if let Some(p) = self.c(e)? {
532
2.28k
                self.fill(hole, p.entry);
533
2.28k
                hole = p.hole;
534
2.28k
            }
535
        }
536
360
        Ok(Some(Patch { hole: hole, entry: entry }))
537
360
    }
<regex::compile::Compiler>::c_concat::<core::iter::adapters::rev::Rev<core::slice::iter::Iter<regex_syntax::hir::Hir>>>
Line
Count
Source
515
60
    fn c_concat<'a, I>(&mut self, exprs: I) -> ResultOrEmpty
516
60
    where
517
60
        I: IntoIterator<Item = &'a Hir>,
518
    {
519
60
        let mut exprs = exprs.into_iter();
520
60
        let Patch { mut hole, entry } = loop {
521
60
            match exprs.next() {
522
0
                None => return self.c_empty(),
523
60
                Some(e) => {
524
60
                    if let Some(p) = self.c(e)? {
525
60
                        break p;
526
0
                    }
527
                }
528
            }
529
        };
530
441
        for e in exprs {
531
381
            if let Some(p) = self.c(e)? {
532
381
                self.fill(hole, p.entry);
533
381
                hole = p.hole;
534
381
            }
535
        }
536
60
        Ok(Some(Patch { hole: hole, entry: entry }))
537
60
    }
Unexecuted instantiation: <regex::compile::Compiler>::c_concat::<core::iter::adapters::take::Take<core::iter::sources::repeat::Repeat<&regex_syntax::hir::Hir>>>
<regex::compile::Compiler>::c_concat::<&alloc::vec::Vec<regex_syntax::hir::Hir>>
Line
Count
Source
515
120
    fn c_concat<'a, I>(&mut self, exprs: I) -> ResultOrEmpty
516
120
    where
517
120
        I: IntoIterator<Item = &'a Hir>,
518
    {
519
120
        let mut exprs = exprs.into_iter();
520
120
        let Patch { mut hole, entry } = loop {
521
120
            match exprs.next() {
522
0
                None => return self.c_empty(),
523
120
                Some(e) => {
524
120
                    if let Some(p) = self.c(e)? {
525
120
                        break p;
526
0
                    }
527
                }
528
            }
529
        };
530
882
        for e in exprs {
531
762
            if let Some(p) = self.c(e)? {
532
762
                self.fill(hole, p.entry);
533
762
                hole = p.hole;
534
762
            }
535
        }
536
120
        Ok(Some(Patch { hole: hole, entry: entry }))
537
120
    }
<regex::compile::Compiler>::c_concat::<core::iter::adapters::rev::Rev<core::slice::iter::Iter<regex_syntax::hir::Hir>>>
Line
Count
Source
515
60
    fn c_concat<'a, I>(&mut self, exprs: I) -> ResultOrEmpty
516
60
    where
517
60
        I: IntoIterator<Item = &'a Hir>,
518
    {
519
60
        let mut exprs = exprs.into_iter();
520
60
        let Patch { mut hole, entry } = loop {
521
60
            match exprs.next() {
522
0
                None => return self.c_empty(),
523
60
                Some(e) => {
524
60
                    if let Some(p) = self.c(e)? {
525
60
                        break p;
526
0
                    }
527
                }
528
            }
529
        };
530
441
        for e in exprs {
531
381
            if let Some(p) = self.c(e)? {
532
381
                self.fill(hole, p.entry);
533
381
                hole = p.hole;
534
381
            }
535
        }
536
60
        Ok(Some(Patch { hole: hole, entry: entry }))
537
60
    }
Unexecuted instantiation: <regex::compile::Compiler>::c_concat::<core::iter::adapters::take::Take<core::iter::sources::repeat::Repeat<&regex_syntax::hir::Hir>>>
<regex::compile::Compiler>::c_concat::<&alloc::vec::Vec<regex_syntax::hir::Hir>>
Line
Count
Source
515
120
    fn c_concat<'a, I>(&mut self, exprs: I) -> ResultOrEmpty
516
120
    where
517
120
        I: IntoIterator<Item = &'a Hir>,
518
    {
519
120
        let mut exprs = exprs.into_iter();
520
120
        let Patch { mut hole, entry } = loop {
521
120
            match exprs.next() {
522
0
                None => return self.c_empty(),
523
120
                Some(e) => {
524
120
                    if let Some(p) = self.c(e)? {
525
120
                        break p;
526
0
                    }
527
                }
528
            }
529
        };
530
882
        for e in exprs {
531
762
            if let Some(p) = self.c(e)? {
532
762
                self.fill(hole, p.entry);
533
762
                hole = p.hole;
534
762
            }
535
        }
536
120
        Ok(Some(Patch { hole: hole, entry: entry }))
537
120
    }
538
539
36
    fn c_alternate(&mut self, exprs: &[Hir]) -> ResultOrEmpty {
540
36
        debug_assert!(
541
0
            exprs.len() >= 2,
542
            "alternates must have at least 2 exprs"
543
        );
544
545
        // Initial entry point is always the first split.
546
36
        let first_split_entry = self.insts.len();
547
548
        // Save up all of the holes from each alternate. They will all get
549
        // patched to point to the same location.
550
36
        let mut holes = vec![];
551
552
        // true indicates that the hole is a split where we want to fill
553
        // the second branch.
554
36
        let mut prev_hole = (Hole::None, false);
555
72
        for e in &exprs[0..exprs.len() - 1] {
556
72
            if prev_hole.1 {
557
0
                let next = self.insts.len();
558
0
                self.fill_split(prev_hole.0, None, Some(next));
559
72
            } else {
560
72
                self.fill_to_next(prev_hole.0);
561
72
            }
562
72
            let split = self.push_split_hole();
563
72
            if let Some(Patch { hole, entry }) = self.c(e)? {
564
72
                holes.push(hole);
565
72
                prev_hole = (self.fill_split(split, Some(entry), None), false);
566
72
            } else {
567
0
                let (split1, split2) = split.dup_one();
568
0
                holes.push(split1);
569
0
                prev_hole = (split2, true);
570
0
            }
571
        }
572
36
        if let Some(Patch { hole, entry }) = self.c(&exprs[exprs.len() - 1])? {
573
36
            holes.push(hole);
574
36
            if prev_hole.1 {
575
0
                self.fill_split(prev_hole.0, None, Some(entry));
576
36
            } else {
577
36
                self.fill(prev_hole.0, entry);
578
36
            }
579
0
        } else {
580
0
            // We ignore prev_hole.1. When it's true, it means we have two
581
0
            // empty branches both pushing prev_hole.0 into holes, so both
582
0
            // branches will go to the same place anyway.
583
0
            holes.push(prev_hole.0);
584
0
        }
585
36
        Ok(Some(Patch { hole: Hole::Many(holes), entry: first_split_entry }))
586
36
    }
<regex::compile::Compiler>::c_alternate
Line
Count
Source
539
18
    fn c_alternate(&mut self, exprs: &[Hir]) -> ResultOrEmpty {
540
18
        debug_assert!(
541
0
            exprs.len() >= 2,
542
            "alternates must have at least 2 exprs"
543
        );
544
545
        // Initial entry point is always the first split.
546
18
        let first_split_entry = self.insts.len();
547
548
        // Save up all of the holes from each alternate. They will all get
549
        // patched to point to the same location.
550
18
        let mut holes = vec![];
551
552
        // true indicates that the hole is a split where we want to fill
553
        // the second branch.
554
18
        let mut prev_hole = (Hole::None, false);
555
36
        for e in &exprs[0..exprs.len() - 1] {
556
36
            if prev_hole.1 {
557
0
                let next = self.insts.len();
558
0
                self.fill_split(prev_hole.0, None, Some(next));
559
36
            } else {
560
36
                self.fill_to_next(prev_hole.0);
561
36
            }
562
36
            let split = self.push_split_hole();
563
36
            if let Some(Patch { hole, entry }) = self.c(e)? {
564
36
                holes.push(hole);
565
36
                prev_hole = (self.fill_split(split, Some(entry), None), false);
566
36
            } else {
567
0
                let (split1, split2) = split.dup_one();
568
0
                holes.push(split1);
569
0
                prev_hole = (split2, true);
570
0
            }
571
        }
572
18
        if let Some(Patch { hole, entry }) = self.c(&exprs[exprs.len() - 1])? {
573
18
            holes.push(hole);
574
18
            if prev_hole.1 {
575
0
                self.fill_split(prev_hole.0, None, Some(entry));
576
18
            } else {
577
18
                self.fill(prev_hole.0, entry);
578
18
            }
579
0
        } else {
580
0
            // We ignore prev_hole.1. When it's true, it means we have two
581
0
            // empty branches both pushing prev_hole.0 into holes, so both
582
0
            // branches will go to the same place anyway.
583
0
            holes.push(prev_hole.0);
584
0
        }
585
18
        Ok(Some(Patch { hole: Hole::Many(holes), entry: first_split_entry }))
586
18
    }
<regex::compile::Compiler>::c_alternate
Line
Count
Source
539
18
    fn c_alternate(&mut self, exprs: &[Hir]) -> ResultOrEmpty {
540
18
        debug_assert!(
541
0
            exprs.len() >= 2,
542
            "alternates must have at least 2 exprs"
543
        );
544
545
        // Initial entry point is always the first split.
546
18
        let first_split_entry = self.insts.len();
547
548
        // Save up all of the holes from each alternate. They will all get
549
        // patched to point to the same location.
550
18
        let mut holes = vec![];
551
552
        // true indicates that the hole is a split where we want to fill
553
        // the second branch.
554
18
        let mut prev_hole = (Hole::None, false);
555
36
        for e in &exprs[0..exprs.len() - 1] {
556
36
            if prev_hole.1 {
557
0
                let next = self.insts.len();
558
0
                self.fill_split(prev_hole.0, None, Some(next));
559
36
            } else {
560
36
                self.fill_to_next(prev_hole.0);
561
36
            }
562
36
            let split = self.push_split_hole();
563
36
            if let Some(Patch { hole, entry }) = self.c(e)? {
564
36
                holes.push(hole);
565
36
                prev_hole = (self.fill_split(split, Some(entry), None), false);
566
36
            } else {
567
0
                let (split1, split2) = split.dup_one();
568
0
                holes.push(split1);
569
0
                prev_hole = (split2, true);
570
0
            }
571
        }
572
18
        if let Some(Patch { hole, entry }) = self.c(&exprs[exprs.len() - 1])? {
573
18
            holes.push(hole);
574
18
            if prev_hole.1 {
575
0
                self.fill_split(prev_hole.0, None, Some(entry));
576
18
            } else {
577
18
                self.fill(prev_hole.0, entry);
578
18
            }
579
0
        } else {
580
0
            // We ignore prev_hole.1. When it's true, it means we have two
581
0
            // empty branches both pushing prev_hole.0 into holes, so both
582
0
            // branches will go to the same place anyway.
583
0
            holes.push(prev_hole.0);
584
0
        }
585
18
        Ok(Some(Patch { hole: Hole::Many(holes), entry: first_split_entry }))
586
18
    }
587
588
900
    fn c_repeat(&mut self, rep: &hir::Repetition) -> ResultOrEmpty {
589
        use regex_syntax::hir::RepetitionKind::*;
590
0
        match rep.kind {
591
324
            ZeroOrOne => self.c_repeat_zero_or_one(&rep.hir, rep.greedy),
592
360
            ZeroOrMore => self.c_repeat_zero_or_more(&rep.hir, rep.greedy),
593
216
            OneOrMore => self.c_repeat_one_or_more(&rep.hir, rep.greedy),
594
0
            Range(hir::RepetitionRange::Exactly(min_max)) => {
595
0
                self.c_repeat_range(&rep.hir, rep.greedy, min_max, min_max)
596
            }
597
0
            Range(hir::RepetitionRange::AtLeast(min)) => {
598
0
                self.c_repeat_range_min_or_more(&rep.hir, rep.greedy, min)
599
            }
600
0
            Range(hir::RepetitionRange::Bounded(min, max)) => {
601
0
                self.c_repeat_range(&rep.hir, rep.greedy, min, max)
602
            }
603
        }
604
900
    }
<regex::compile::Compiler>::c_repeat
Line
Count
Source
588
450
    fn c_repeat(&mut self, rep: &hir::Repetition) -> ResultOrEmpty {
589
        use regex_syntax::hir::RepetitionKind::*;
590
0
        match rep.kind {
591
162
            ZeroOrOne => self.c_repeat_zero_or_one(&rep.hir, rep.greedy),
592
180
            ZeroOrMore => self.c_repeat_zero_or_more(&rep.hir, rep.greedy),
593
108
            OneOrMore => self.c_repeat_one_or_more(&rep.hir, rep.greedy),
594
0
            Range(hir::RepetitionRange::Exactly(min_max)) => {
595
0
                self.c_repeat_range(&rep.hir, rep.greedy, min_max, min_max)
596
            }
597
0
            Range(hir::RepetitionRange::AtLeast(min)) => {
598
0
                self.c_repeat_range_min_or_more(&rep.hir, rep.greedy, min)
599
            }
600
0
            Range(hir::RepetitionRange::Bounded(min, max)) => {
601
0
                self.c_repeat_range(&rep.hir, rep.greedy, min, max)
602
            }
603
        }
604
450
    }
<regex::compile::Compiler>::c_repeat
Line
Count
Source
588
450
    fn c_repeat(&mut self, rep: &hir::Repetition) -> ResultOrEmpty {
589
        use regex_syntax::hir::RepetitionKind::*;
590
0
        match rep.kind {
591
162
            ZeroOrOne => self.c_repeat_zero_or_one(&rep.hir, rep.greedy),
592
180
            ZeroOrMore => self.c_repeat_zero_or_more(&rep.hir, rep.greedy),
593
108
            OneOrMore => self.c_repeat_one_or_more(&rep.hir, rep.greedy),
594
0
            Range(hir::RepetitionRange::Exactly(min_max)) => {
595
0
                self.c_repeat_range(&rep.hir, rep.greedy, min_max, min_max)
596
            }
597
0
            Range(hir::RepetitionRange::AtLeast(min)) => {
598
0
                self.c_repeat_range_min_or_more(&rep.hir, rep.greedy, min)
599
            }
600
0
            Range(hir::RepetitionRange::Bounded(min, max)) => {
601
0
                self.c_repeat_range(&rep.hir, rep.greedy, min, max)
602
            }
603
        }
604
450
    }
605
606
324
    fn c_repeat_zero_or_one(
607
324
        &mut self,
608
324
        expr: &Hir,
609
324
        greedy: bool,
610
324
    ) -> ResultOrEmpty {
611
324
        let split_entry = self.insts.len();
612
324
        let split = self.push_split_hole();
613
324
        let Patch { hole: hole_rep, entry: entry_rep } = match self.c(expr)? {
614
324
            Some(p) => p,
615
0
            None => return self.pop_split_hole(),
616
        };
617
324
        let split_hole = if greedy {
618
324
            self.fill_split(split, Some(entry_rep), None)
619
        } else {
620
0
            self.fill_split(split, None, Some(entry_rep))
621
        };
622
324
        let holes = vec![hole_rep, split_hole];
623
324
        Ok(Some(Patch { hole: Hole::Many(holes), entry: split_entry }))
624
324
    }
<regex::compile::Compiler>::c_repeat_zero_or_one
Line
Count
Source
606
162
    fn c_repeat_zero_or_one(
607
162
        &mut self,
608
162
        expr: &Hir,
609
162
        greedy: bool,
610
162
    ) -> ResultOrEmpty {
611
162
        let split_entry = self.insts.len();
612
162
        let split = self.push_split_hole();
613
162
        let Patch { hole: hole_rep, entry: entry_rep } = match self.c(expr)? {
614
162
            Some(p) => p,
615
0
            None => return self.pop_split_hole(),
616
        };
617
162
        let split_hole = if greedy {
618
162
            self.fill_split(split, Some(entry_rep), None)
619
        } else {
620
0
            self.fill_split(split, None, Some(entry_rep))
621
        };
622
162
        let holes = vec![hole_rep, split_hole];
623
162
        Ok(Some(Patch { hole: Hole::Many(holes), entry: split_entry }))
624
162
    }
<regex::compile::Compiler>::c_repeat_zero_or_one
Line
Count
Source
606
162
    fn c_repeat_zero_or_one(
607
162
        &mut self,
608
162
        expr: &Hir,
609
162
        greedy: bool,
610
162
    ) -> ResultOrEmpty {
611
162
        let split_entry = self.insts.len();
612
162
        let split = self.push_split_hole();
613
162
        let Patch { hole: hole_rep, entry: entry_rep } = match self.c(expr)? {
614
162
            Some(p) => p,
615
0
            None => return self.pop_split_hole(),
616
        };
617
162
        let split_hole = if greedy {
618
162
            self.fill_split(split, Some(entry_rep), None)
619
        } else {
620
0
            self.fill_split(split, None, Some(entry_rep))
621
        };
622
162
        let holes = vec![hole_rep, split_hole];
623
162
        Ok(Some(Patch { hole: Hole::Many(holes), entry: split_entry }))
624
162
    }
625
626
360
    fn c_repeat_zero_or_more(
627
360
        &mut self,
628
360
        expr: &Hir,
629
360
        greedy: bool,
630
360
    ) -> ResultOrEmpty {
631
360
        let split_entry = self.insts.len();
632
360
        let split = self.push_split_hole();
633
360
        let Patch { hole: hole_rep, entry: entry_rep } = match self.c(expr)? {
634
360
            Some(p) => p,
635
0
            None => return self.pop_split_hole(),
636
        };
637
638
360
        self.fill(hole_rep, split_entry);
639
360
        let split_hole = if greedy {
640
360
            self.fill_split(split, Some(entry_rep), None)
641
        } else {
642
0
            self.fill_split(split, None, Some(entry_rep))
643
        };
644
360
        Ok(Some(Patch { hole: split_hole, entry: split_entry }))
645
360
    }
<regex::compile::Compiler>::c_repeat_zero_or_more
Line
Count
Source
626
180
    fn c_repeat_zero_or_more(
627
180
        &mut self,
628
180
        expr: &Hir,
629
180
        greedy: bool,
630
180
    ) -> ResultOrEmpty {
631
180
        let split_entry = self.insts.len();
632
180
        let split = self.push_split_hole();
633
180
        let Patch { hole: hole_rep, entry: entry_rep } = match self.c(expr)? {
634
180
            Some(p) => p,
635
0
            None => return self.pop_split_hole(),
636
        };
637
638
180
        self.fill(hole_rep, split_entry);
639
180
        let split_hole = if greedy {
640
180
            self.fill_split(split, Some(entry_rep), None)
641
        } else {
642
0
            self.fill_split(split, None, Some(entry_rep))
643
        };
644
180
        Ok(Some(Patch { hole: split_hole, entry: split_entry }))
645
180
    }
<regex::compile::Compiler>::c_repeat_zero_or_more
Line
Count
Source
626
180
    fn c_repeat_zero_or_more(
627
180
        &mut self,
628
180
        expr: &Hir,
629
180
        greedy: bool,
630
180
    ) -> ResultOrEmpty {
631
180
        let split_entry = self.insts.len();
632
180
        let split = self.push_split_hole();
633
180
        let Patch { hole: hole_rep, entry: entry_rep } = match self.c(expr)? {
634
180
            Some(p) => p,
635
0
            None => return self.pop_split_hole(),
636
        };
637
638
180
        self.fill(hole_rep, split_entry);
639
180
        let split_hole = if greedy {
640
180
            self.fill_split(split, Some(entry_rep), None)
641
        } else {
642
0
            self.fill_split(split, None, Some(entry_rep))
643
        };
644
180
        Ok(Some(Patch { hole: split_hole, entry: split_entry }))
645
180
    }
646
647
216
    fn c_repeat_one_or_more(
648
216
        &mut self,
649
216
        expr: &Hir,
650
216
        greedy: bool,
651
216
    ) -> ResultOrEmpty {
652
216
        let Patch { hole: hole_rep, entry: entry_rep } = match self.c(expr)? {
653
216
            Some(p) => p,
654
0
            None => return Ok(None),
655
        };
656
216
        self.fill_to_next(hole_rep);
657
216
        let split = self.push_split_hole();
658
659
216
        let split_hole = if greedy {
660
216
            self.fill_split(split, Some(entry_rep), None)
661
        } else {
662
0
            self.fill_split(split, None, Some(entry_rep))
663
        };
664
216
        Ok(Some(Patch { hole: split_hole, entry: entry_rep }))
665
216
    }
<regex::compile::Compiler>::c_repeat_one_or_more
Line
Count
Source
647
108
    fn c_repeat_one_or_more(
648
108
        &mut self,
649
108
        expr: &Hir,
650
108
        greedy: bool,
651
108
    ) -> ResultOrEmpty {
652
108
        let Patch { hole: hole_rep, entry: entry_rep } = match self.c(expr)? {
653
108
            Some(p) => p,
654
0
            None => return Ok(None),
655
        };
656
108
        self.fill_to_next(hole_rep);
657
108
        let split = self.push_split_hole();
658
659
108
        let split_hole = if greedy {
660
108
            self.fill_split(split, Some(entry_rep), None)
661
        } else {
662
0
            self.fill_split(split, None, Some(entry_rep))
663
        };
664
108
        Ok(Some(Patch { hole: split_hole, entry: entry_rep }))
665
108
    }
<regex::compile::Compiler>::c_repeat_one_or_more
Line
Count
Source
647
108
    fn c_repeat_one_or_more(
648
108
        &mut self,
649
108
        expr: &Hir,
650
108
        greedy: bool,
651
108
    ) -> ResultOrEmpty {
652
108
        let Patch { hole: hole_rep, entry: entry_rep } = match self.c(expr)? {
653
108
            Some(p) => p,
654
0
            None => return Ok(None),
655
        };
656
108
        self.fill_to_next(hole_rep);
657
108
        let split = self.push_split_hole();
658
659
108
        let split_hole = if greedy {
660
108
            self.fill_split(split, Some(entry_rep), None)
661
        } else {
662
0
            self.fill_split(split, None, Some(entry_rep))
663
        };
664
108
        Ok(Some(Patch { hole: split_hole, entry: entry_rep }))
665
108
    }
666
667
0
    fn c_repeat_range_min_or_more(
668
0
        &mut self,
669
0
        expr: &Hir,
670
0
        greedy: bool,
671
0
        min: u32,
672
0
    ) -> ResultOrEmpty {
673
0
        let min = u32_to_usize(min);
674
        // Using next_inst() is ok, because we can't return it (concat would
675
        // have to return Some(_) while c_repeat_range_min_or_more returns
676
        // None).
677
0
        let patch_concat = self
678
0
            .c_concat(iter::repeat(expr).take(min))?
679
0
            .unwrap_or(self.next_inst());
680
0
        if let Some(patch_rep) = self.c_repeat_zero_or_more(expr, greedy)? {
681
0
            self.fill(patch_concat.hole, patch_rep.entry);
682
0
            Ok(Some(Patch { hole: patch_rep.hole, entry: patch_concat.entry }))
683
        } else {
684
0
            Ok(None)
685
        }
686
0
    }
Unexecuted instantiation: <regex::compile::Compiler>::c_repeat_range_min_or_more
Unexecuted instantiation: <regex::compile::Compiler>::c_repeat_range_min_or_more
687
688
0
    fn c_repeat_range(
689
0
        &mut self,
690
0
        expr: &Hir,
691
0
        greedy: bool,
692
0
        min: u32,
693
0
        max: u32,
694
0
    ) -> ResultOrEmpty {
695
0
        let (min, max) = (u32_to_usize(min), u32_to_usize(max));
696
0
        debug_assert!(min <= max);
697
0
        let patch_concat = self.c_concat(iter::repeat(expr).take(min))?;
698
0
        if min == max {
699
0
            return Ok(patch_concat);
700
0
        }
701
        // Same reasoning as in c_repeat_range_min_or_more (we know that min <
702
        // max at this point).
703
0
        let patch_concat = patch_concat.unwrap_or(self.next_inst());
704
0
        let initial_entry = patch_concat.entry;
705
        // It is much simpler to compile, e.g., `a{2,5}` as:
706
        //
707
        //     aaa?a?a?
708
        //
709
        // But you end up with a sequence of instructions like this:
710
        //
711
        //     0: 'a'
712
        //     1: 'a',
713
        //     2: split(3, 4)
714
        //     3: 'a'
715
        //     4: split(5, 6)
716
        //     5: 'a'
717
        //     6: split(7, 8)
718
        //     7: 'a'
719
        //     8: MATCH
720
        //
721
        // This is *incredibly* inefficient because the splits end
722
        // up forming a chain, which has to be resolved everything a
723
        // transition is followed.
724
0
        let mut holes = vec![];
725
0
        let mut prev_hole = patch_concat.hole;
726
0
        for _ in min..max {
727
0
            self.fill_to_next(prev_hole);
728
0
            let split = self.push_split_hole();
729
0
            let Patch { hole, entry } = match self.c(expr)? {
730
0
                Some(p) => p,
731
0
                None => return self.pop_split_hole(),
732
            };
733
0
            prev_hole = hole;
734
0
            if greedy {
735
0
                holes.push(self.fill_split(split, Some(entry), None));
736
0
            } else {
737
0
                holes.push(self.fill_split(split, None, Some(entry)));
738
0
            }
739
        }
740
0
        holes.push(prev_hole);
741
0
        Ok(Some(Patch { hole: Hole::Many(holes), entry: initial_entry }))
742
0
    }
Unexecuted instantiation: <regex::compile::Compiler>::c_repeat_range
Unexecuted instantiation: <regex::compile::Compiler>::c_repeat_range
743
744
    /// Can be used as a default value for the c_* functions when the call to
745
    /// c_function is followed by inserting at least one instruction that is
746
    /// always executed after the ones written by the c* function.
747
138
    fn next_inst(&self) -> Patch {
748
138
        Patch { hole: Hole::None, entry: self.insts.len() }
749
138
    }
<regex::compile::Compiler>::next_inst
Line
Count
Source
747
69
    fn next_inst(&self) -> Patch {
748
69
        Patch { hole: Hole::None, entry: self.insts.len() }
749
69
    }
<regex::compile::Compiler>::next_inst
Line
Count
Source
747
69
    fn next_inst(&self) -> Patch {
748
69
        Patch { hole: Hole::None, entry: self.insts.len() }
749
69
    }
750
751
5.65k
    fn fill(&mut self, hole: Hole, goto: InstPtr) {
752
5.65k
        match hole {
753
498
            Hole::None => {}
754
4.37k
            Hole::One(pc) => {
755
4.37k
                self.insts[pc].fill(goto);
756
4.37k
            }
757
780
            Hole::Many(holes) => {
758
2.38k
                for hole in holes {
759
1.60k
                    self.fill(hole, goto);
760
1.60k
                }
761
            }
762
        }
763
5.65k
    }
<regex::compile::Compiler>::fill
Line
Count
Source
751
2.82k
    fn fill(&mut self, hole: Hole, goto: InstPtr) {
752
2.82k
        match hole {
753
249
            Hole::None => {}
754
2.18k
            Hole::One(pc) => {
755
2.18k
                self.insts[pc].fill(goto);
756
2.18k
            }
757
390
            Hole::Many(holes) => {
758
1.19k
                for hole in holes {
759
804
                    self.fill(hole, goto);
760
804
                }
761
            }
762
        }
763
2.82k
    }
<regex::compile::Compiler>::fill
Line
Count
Source
751
2.82k
    fn fill(&mut self, hole: Hole, goto: InstPtr) {
752
2.82k
        match hole {
753
249
            Hole::None => {}
754
2.18k
            Hole::One(pc) => {
755
2.18k
                self.insts[pc].fill(goto);
756
2.18k
            }
757
390
            Hole::Many(holes) => {
758
1.19k
                for hole in holes {
759
804
                    self.fill(hole, goto);
760
804
                }
761
            }
762
        }
763
2.82k
    }
764
765
858
    fn fill_to_next(&mut self, hole: Hole) {
766
858
        let next = self.insts.len();
767
858
        self.fill(hole, next);
768
858
    }
<regex::compile::Compiler>::fill_to_next
Line
Count
Source
765
429
    fn fill_to_next(&mut self, hole: Hole) {
766
429
        let next = self.insts.len();
767
429
        self.fill(hole, next);
768
429
    }
<regex::compile::Compiler>::fill_to_next
Line
Count
Source
765
429
    fn fill_to_next(&mut self, hole: Hole) {
766
429
        let next = self.insts.len();
767
429
        self.fill(hole, next);
768
429
    }
769
770
1.40k
    fn fill_split(
771
1.40k
        &mut self,
772
1.40k
        hole: Hole,
773
1.40k
        goto1: Option<InstPtr>,
774
1.40k
        goto2: Option<InstPtr>,
775
1.40k
    ) -> Hole {
776
1.40k
        match hole {
777
0
            Hole::None => Hole::None,
778
1.40k
            Hole::One(pc) => match (goto1, goto2) {
779
0
                (Some(goto1), Some(goto2)) => {
780
0
                    self.insts[pc].fill_split(goto1, goto2);
781
0
                    Hole::None
782
                }
783
1.40k
                (Some(goto1), None) => {
784
1.40k
                    self.insts[pc].half_fill_split_goto1(goto1);
785
1.40k
                    Hole::One(pc)
786
                }
787
0
                (None, Some(goto2)) => {
788
0
                    self.insts[pc].half_fill_split_goto2(goto2);
789
0
                    Hole::One(pc)
790
                }
791
0
                (None, None) => unreachable!(
792
                    "at least one of the split \
793
                     holes must be filled"
794
                ),
795
            },
796
0
            Hole::Many(holes) => {
797
0
                let mut new_holes = vec![];
798
0
                for hole in holes {
799
0
                    new_holes.push(self.fill_split(hole, goto1, goto2));
800
0
                }
801
0
                if new_holes.is_empty() {
802
0
                    Hole::None
803
0
                } else if new_holes.len() == 1 {
804
0
                    new_holes.pop().unwrap()
805
                } else {
806
0
                    Hole::Many(new_holes)
807
                }
808
            }
809
        }
810
1.40k
    }
<regex::compile::Compiler>::fill_split
Line
Count
Source
770
702
    fn fill_split(
771
702
        &mut self,
772
702
        hole: Hole,
773
702
        goto1: Option<InstPtr>,
774
702
        goto2: Option<InstPtr>,
775
702
    ) -> Hole {
776
702
        match hole {
777
0
            Hole::None => Hole::None,
778
702
            Hole::One(pc) => match (goto1, goto2) {
779
0
                (Some(goto1), Some(goto2)) => {
780
0
                    self.insts[pc].fill_split(goto1, goto2);
781
0
                    Hole::None
782
                }
783
702
                (Some(goto1), None) => {
784
702
                    self.insts[pc].half_fill_split_goto1(goto1);
785
702
                    Hole::One(pc)
786
                }
787
0
                (None, Some(goto2)) => {
788
0
                    self.insts[pc].half_fill_split_goto2(goto2);
789
0
                    Hole::One(pc)
790
                }
791
0
                (None, None) => unreachable!(
792
                    "at least one of the split \
793
                     holes must be filled"
794
                ),
795
            },
796
0
            Hole::Many(holes) => {
797
0
                let mut new_holes = vec![];
798
0
                for hole in holes {
799
0
                    new_holes.push(self.fill_split(hole, goto1, goto2));
800
0
                }
801
0
                if new_holes.is_empty() {
802
0
                    Hole::None
803
0
                } else if new_holes.len() == 1 {
804
0
                    new_holes.pop().unwrap()
805
                } else {
806
0
                    Hole::Many(new_holes)
807
                }
808
            }
809
        }
810
702
    }
<regex::compile::Compiler>::fill_split
Line
Count
Source
770
702
    fn fill_split(
771
702
        &mut self,
772
702
        hole: Hole,
773
702
        goto1: Option<InstPtr>,
774
702
        goto2: Option<InstPtr>,
775
702
    ) -> Hole {
776
702
        match hole {
777
0
            Hole::None => Hole::None,
778
702
            Hole::One(pc) => match (goto1, goto2) {
779
0
                (Some(goto1), Some(goto2)) => {
780
0
                    self.insts[pc].fill_split(goto1, goto2);
781
0
                    Hole::None
782
                }
783
702
                (Some(goto1), None) => {
784
702
                    self.insts[pc].half_fill_split_goto1(goto1);
785
702
                    Hole::One(pc)
786
                }
787
0
                (None, Some(goto2)) => {
788
0
                    self.insts[pc].half_fill_split_goto2(goto2);
789
0
                    Hole::One(pc)
790
                }
791
0
                (None, None) => unreachable!(
792
                    "at least one of the split \
793
                     holes must be filled"
794
                ),
795
            },
796
0
            Hole::Many(holes) => {
797
0
                let mut new_holes = vec![];
798
0
                for hole in holes {
799
0
                    new_holes.push(self.fill_split(hole, goto1, goto2));
800
0
                }
801
0
                if new_holes.is_empty() {
802
0
                    Hole::None
803
0
                } else if new_holes.len() == 1 {
804
0
                    new_holes.pop().unwrap()
805
                } else {
806
0
                    Hole::Many(new_holes)
807
                }
808
            }
809
        }
810
702
    }
811
812
246
    fn push_compiled(&mut self, inst: Inst) {
813
246
        self.insts.push(MaybeInst::Compiled(inst));
814
246
    }
<regex::compile::Compiler>::push_compiled
Line
Count
Source
812
123
    fn push_compiled(&mut self, inst: Inst) {
813
123
        self.insts.push(MaybeInst::Compiled(inst));
814
123
    }
<regex::compile::Compiler>::push_compiled
Line
Count
Source
812
123
    fn push_compiled(&mut self, inst: Inst) {
813
123
        self.insts.push(MaybeInst::Compiled(inst));
814
123
    }
815
816
2.97k
    fn push_hole(&mut self, inst: InstHole) -> Hole {
817
2.97k
        let hole = self.insts.len();
818
2.97k
        self.insts.push(MaybeInst::Uncompiled(inst));
819
2.97k
        Hole::One(hole)
820
2.97k
    }
<regex::compile::Compiler>::push_hole
Line
Count
Source
816
1.48k
    fn push_hole(&mut self, inst: InstHole) -> Hole {
817
1.48k
        let hole = self.insts.len();
818
1.48k
        self.insts.push(MaybeInst::Uncompiled(inst));
819
1.48k
        Hole::One(hole)
820
1.48k
    }
<regex::compile::Compiler>::push_hole
Line
Count
Source
816
1.48k
    fn push_hole(&mut self, inst: InstHole) -> Hole {
817
1.48k
        let hole = self.insts.len();
818
1.48k
        self.insts.push(MaybeInst::Uncompiled(inst));
819
1.48k
        Hole::One(hole)
820
1.48k
    }
821
822
1.40k
    fn push_split_hole(&mut self) -> Hole {
823
1.40k
        let hole = self.insts.len();
824
1.40k
        self.insts.push(MaybeInst::Split);
825
1.40k
        Hole::One(hole)
826
1.40k
    }
<regex::compile::Compiler>::push_split_hole
Line
Count
Source
822
702
    fn push_split_hole(&mut self) -> Hole {
823
702
        let hole = self.insts.len();
824
702
        self.insts.push(MaybeInst::Split);
825
702
        Hole::One(hole)
826
702
    }
<regex::compile::Compiler>::push_split_hole
Line
Count
Source
822
702
    fn push_split_hole(&mut self) -> Hole {
823
702
        let hole = self.insts.len();
824
702
        self.insts.push(MaybeInst::Split);
825
702
        Hole::One(hole)
826
702
    }
827
828
0
    fn pop_split_hole(&mut self) -> ResultOrEmpty {
829
0
        self.insts.pop();
830
0
        Ok(None)
831
0
    }
Unexecuted instantiation: <regex::compile::Compiler>::pop_split_hole
Unexecuted instantiation: <regex::compile::Compiler>::pop_split_hole
832
833
4.03k
    fn check_size(&self) -> result::Result<(), Error> {
834
        use std::mem::size_of;
835
836
4.03k
        let size =
837
4.03k
            self.extra_inst_bytes + (self.insts.len() * size_of::<Inst>());
838
4.03k
        if size > self.size_limit {
839
0
            Err(Error::CompiledTooBig(self.size_limit))
840
        } else {
841
4.03k
            Ok(())
842
        }
843
4.03k
    }
<regex::compile::Compiler>::check_size
Line
Count
Source
833
2.01k
    fn check_size(&self) -> result::Result<(), Error> {
834
        use std::mem::size_of;
835
836
2.01k
        let size =
837
2.01k
            self.extra_inst_bytes + (self.insts.len() * size_of::<Inst>());
838
2.01k
        if size > self.size_limit {
839
0
            Err(Error::CompiledTooBig(self.size_limit))
840
        } else {
841
2.01k
            Ok(())
842
        }
843
2.01k
    }
<regex::compile::Compiler>::check_size
Line
Count
Source
833
2.01k
    fn check_size(&self) -> result::Result<(), Error> {
834
        use std::mem::size_of;
835
836
2.01k
        let size =
837
2.01k
            self.extra_inst_bytes + (self.insts.len() * size_of::<Inst>());
838
2.01k
        if size > self.size_limit {
839
0
            Err(Error::CompiledTooBig(self.size_limit))
840
        } else {
841
2.01k
            Ok(())
842
        }
843
2.01k
    }
844
}
845
846
#[derive(Debug)]
847
enum Hole {
848
    None,
849
    One(InstPtr),
850
    Many(Vec<Hole>),
851
}
852
853
impl Hole {
854
0
    fn dup_one(self) -> (Self, Self) {
855
0
        match self {
856
0
            Hole::One(pc) => (Hole::One(pc), Hole::One(pc)),
857
            Hole::None | Hole::Many(_) => {
858
0
                unreachable!("must be called on single hole")
859
            }
860
        }
861
0
    }
Unexecuted instantiation: <regex::compile::Hole>::dup_one
Unexecuted instantiation: <regex::compile::Hole>::dup_one
862
}
863
864
#[derive(Clone, Debug)]
865
enum MaybeInst {
866
    Compiled(Inst),
867
    Uncompiled(InstHole),
868
    Split,
869
    Split1(InstPtr),
870
    Split2(InstPtr),
871
}
872
873
impl MaybeInst {
874
4.37k
    fn fill(&mut self, goto: InstPtr) {
875
4.37k
        let maybeinst = match *self {
876
0
            MaybeInst::Split => MaybeInst::Split1(goto),
877
2.97k
            MaybeInst::Uncompiled(ref inst) => {
878
2.97k
                MaybeInst::Compiled(inst.fill(goto))
879
            }
880
1.40k
            MaybeInst::Split1(goto1) => {
881
1.40k
                MaybeInst::Compiled(Inst::Split(InstSplit {
882
1.40k
                    goto1: goto1,
883
1.40k
                    goto2: goto,
884
1.40k
                }))
885
            }
886
0
            MaybeInst::Split2(goto2) => {
887
0
                MaybeInst::Compiled(Inst::Split(InstSplit {
888
0
                    goto1: goto,
889
0
                    goto2: goto2,
890
0
                }))
891
            }
892
0
            _ => unreachable!(
893
                "not all instructions were compiled! \
894
                 found uncompiled instruction: {:?}",
895
                self
896
            ),
897
        };
898
4.37k
        *self = maybeinst;
899
4.37k
    }
<regex::compile::MaybeInst>::fill
Line
Count
Source
874
2.18k
    fn fill(&mut self, goto: InstPtr) {
875
2.18k
        let maybeinst = match *self {
876
0
            MaybeInst::Split => MaybeInst::Split1(goto),
877
1.48k
            MaybeInst::Uncompiled(ref inst) => {
878
1.48k
                MaybeInst::Compiled(inst.fill(goto))
879
            }
880
702
            MaybeInst::Split1(goto1) => {
881
702
                MaybeInst::Compiled(Inst::Split(InstSplit {
882
702
                    goto1: goto1,
883
702
                    goto2: goto,
884
702
                }))
885
            }
886
0
            MaybeInst::Split2(goto2) => {
887
0
                MaybeInst::Compiled(Inst::Split(InstSplit {
888
0
                    goto1: goto,
889
0
                    goto2: goto2,
890
0
                }))
891
            }
892
0
            _ => unreachable!(
893
                "not all instructions were compiled! \
894
                 found uncompiled instruction: {:?}",
895
                self
896
            ),
897
        };
898
2.18k
        *self = maybeinst;
899
2.18k
    }
<regex::compile::MaybeInst>::fill
Line
Count
Source
874
2.18k
    fn fill(&mut self, goto: InstPtr) {
875
2.18k
        let maybeinst = match *self {
876
0
            MaybeInst::Split => MaybeInst::Split1(goto),
877
1.48k
            MaybeInst::Uncompiled(ref inst) => {
878
1.48k
                MaybeInst::Compiled(inst.fill(goto))
879
            }
880
702
            MaybeInst::Split1(goto1) => {
881
702
                MaybeInst::Compiled(Inst::Split(InstSplit {
882
702
                    goto1: goto1,
883
702
                    goto2: goto,
884
702
                }))
885
            }
886
0
            MaybeInst::Split2(goto2) => {
887
0
                MaybeInst::Compiled(Inst::Split(InstSplit {
888
0
                    goto1: goto,
889
0
                    goto2: goto2,
890
0
                }))
891
            }
892
0
            _ => unreachable!(
893
                "not all instructions were compiled! \
894
                 found uncompiled instruction: {:?}",
895
                self
896
            ),
897
        };
898
2.18k
        *self = maybeinst;
899
2.18k
    }
900
901
0
    fn fill_split(&mut self, goto1: InstPtr, goto2: InstPtr) {
902
0
        let filled = match *self {
903
            MaybeInst::Split => {
904
0
                Inst::Split(InstSplit { goto1: goto1, goto2: goto2 })
905
            }
906
0
            _ => unreachable!(
907
                "must be called on Split instruction, \
908
                 instead it was called on: {:?}",
909
                self
910
            ),
911
        };
912
0
        *self = MaybeInst::Compiled(filled);
913
0
    }
Unexecuted instantiation: <regex::compile::MaybeInst>::fill_split
Unexecuted instantiation: <regex::compile::MaybeInst>::fill_split
914
915
1.40k
    fn half_fill_split_goto1(&mut self, goto1: InstPtr) {
916
1.40k
        let half_filled = match *self {
917
1.40k
            MaybeInst::Split => goto1,
918
0
            _ => unreachable!(
919
                "must be called on Split instruction, \
920
                 instead it was called on: {:?}",
921
                self
922
            ),
923
        };
924
1.40k
        *self = MaybeInst::Split1(half_filled);
925
1.40k
    }
<regex::compile::MaybeInst>::half_fill_split_goto1
Line
Count
Source
915
702
    fn half_fill_split_goto1(&mut self, goto1: InstPtr) {
916
702
        let half_filled = match *self {
917
702
            MaybeInst::Split => goto1,
918
0
            _ => unreachable!(
919
                "must be called on Split instruction, \
920
                 instead it was called on: {:?}",
921
                self
922
            ),
923
        };
924
702
        *self = MaybeInst::Split1(half_filled);
925
702
    }
<regex::compile::MaybeInst>::half_fill_split_goto1
Line
Count
Source
915
702
    fn half_fill_split_goto1(&mut self, goto1: InstPtr) {
916
702
        let half_filled = match *self {
917
702
            MaybeInst::Split => goto1,
918
0
            _ => unreachable!(
919
                "must be called on Split instruction, \
920
                 instead it was called on: {:?}",
921
                self
922
            ),
923
        };
924
702
        *self = MaybeInst::Split1(half_filled);
925
702
    }
926
927
0
    fn half_fill_split_goto2(&mut self, goto2: InstPtr) {
928
0
        let half_filled = match *self {
929
0
            MaybeInst::Split => goto2,
930
0
            _ => unreachable!(
931
                "must be called on Split instruction, \
932
                 instead it was called on: {:?}",
933
                self
934
            ),
935
        };
936
0
        *self = MaybeInst::Split2(half_filled);
937
0
    }
Unexecuted instantiation: <regex::compile::MaybeInst>::half_fill_split_goto2
Unexecuted instantiation: <regex::compile::MaybeInst>::half_fill_split_goto2
938
939
4.62k
    fn unwrap(self) -> Inst {
940
4.62k
        match self {
941
4.62k
            MaybeInst::Compiled(inst) => inst,
942
0
            _ => unreachable!(
943
                "must be called on a compiled instruction, \
944
                 instead it was called on: {:?}",
945
                self
946
            ),
947
        }
948
4.62k
    }
<regex::compile::MaybeInst>::unwrap
Line
Count
Source
939
2.31k
    fn unwrap(self) -> Inst {
940
2.31k
        match self {
941
2.31k
            MaybeInst::Compiled(inst) => inst,
942
0
            _ => unreachable!(
943
                "must be called on a compiled instruction, \
944
                 instead it was called on: {:?}",
945
                self
946
            ),
947
        }
948
2.31k
    }
<regex::compile::MaybeInst>::unwrap
Line
Count
Source
939
2.31k
    fn unwrap(self) -> Inst {
940
2.31k
        match self {
941
2.31k
            MaybeInst::Compiled(inst) => inst,
942
0
            _ => unreachable!(
943
                "must be called on a compiled instruction, \
944
                 instead it was called on: {:?}",
945
                self
946
            ),
947
        }
948
2.31k
    }
949
}
950
951
#[derive(Clone, Debug)]
952
enum InstHole {
953
    Save { slot: usize },
954
    EmptyLook { look: EmptyLook },
955
    Char { c: char },
956
    Ranges { ranges: Vec<(char, char)> },
957
    Bytes { start: u8, end: u8 },
958
}
959
960
impl InstHole {
961
2.97k
    fn fill(&self, goto: InstPtr) -> Inst {
962
2.97k
        match *self {
963
168
            InstHole::Save { slot } => {
964
168
                Inst::Save(InstSave { goto: goto, slot: slot })
965
            }
966
108
            InstHole::EmptyLook { look } => {
967
108
                Inst::EmptyLook(InstEmptyLook { goto: goto, look: look })
968
            }
969
558
            InstHole::Char { c } => Inst::Char(InstChar { goto: goto, c: c }),
970
210
            InstHole::Ranges { ref ranges } => Inst::Ranges(InstRanges {
971
210
                goto: goto,
972
210
                ranges: ranges.clone().into_boxed_slice(),
973
210
            }),
974
1.92k
            InstHole::Bytes { start, end } => {
975
1.92k
                Inst::Bytes(InstBytes { goto: goto, start: start, end: end })
976
            }
977
        }
978
2.97k
    }
<regex::compile::InstHole>::fill
Line
Count
Source
961
1.48k
    fn fill(&self, goto: InstPtr) -> Inst {
962
1.48k
        match *self {
963
84
            InstHole::Save { slot } => {
964
84
                Inst::Save(InstSave { goto: goto, slot: slot })
965
            }
966
54
            InstHole::EmptyLook { look } => {
967
54
                Inst::EmptyLook(InstEmptyLook { goto: goto, look: look })
968
            }
969
279
            InstHole::Char { c } => Inst::Char(InstChar { goto: goto, c: c }),
970
105
            InstHole::Ranges { ref ranges } => Inst::Ranges(InstRanges {
971
105
                goto: goto,
972
105
                ranges: ranges.clone().into_boxed_slice(),
973
105
            }),
974
963
            InstHole::Bytes { start, end } => {
975
963
                Inst::Bytes(InstBytes { goto: goto, start: start, end: end })
976
            }
977
        }
978
1.48k
    }
<regex::compile::InstHole>::fill
Line
Count
Source
961
1.48k
    fn fill(&self, goto: InstPtr) -> Inst {
962
1.48k
        match *self {
963
84
            InstHole::Save { slot } => {
964
84
                Inst::Save(InstSave { goto: goto, slot: slot })
965
            }
966
54
            InstHole::EmptyLook { look } => {
967
54
                Inst::EmptyLook(InstEmptyLook { goto: goto, look: look })
968
            }
969
279
            InstHole::Char { c } => Inst::Char(InstChar { goto: goto, c: c }),
970
105
            InstHole::Ranges { ref ranges } => Inst::Ranges(InstRanges {
971
105
                goto: goto,
972
105
                ranges: ranges.clone().into_boxed_slice(),
973
105
            }),
974
963
            InstHole::Bytes { start, end } => {
975
963
                Inst::Bytes(InstBytes { goto: goto, start: start, end: end })
976
            }
977
        }
978
1.48k
    }
979
}
980
981
struct CompileClass<'a, 'b> {
982
    c: &'a mut Compiler,
983
    ranges: &'b [hir::ClassUnicodeRange],
984
}
985
986
impl<'a, 'b> CompileClass<'a, 'b> {
987
420
    fn compile(mut self) -> Result {
988
420
        let mut holes = vec![];
989
420
        let mut initial_entry = None;
990
420
        let mut last_split = Hole::None;
991
420
        let mut utf8_seqs = self.c.utf8_seqs.take().unwrap();
992
420
        self.c.suffix_cache.clear();
993
994
756
        for (i, range) in self.ranges.iter().enumerate() {
995
756
            let is_last_range = i + 1 == self.ranges.len();
996
756
            utf8_seqs.reset(range.start(), range.end());
997
756
            let mut it = (&mut utf8_seqs).peekable();
998
            loop {
999
1.60k
                let utf8_seq = match it.next() {
1000
756
                    None => break,
1001
852
                    Some(utf8_seq) => utf8_seq,
1002
                };
1003
852
                if is_last_range && it.peek().is_none() {
1004
420
                    let Patch { hole, entry } = self.c_utf8_seq(&utf8_seq)?;
1005
420
                    holes.push(hole);
1006
420
                    self.c.fill(last_split, entry);
1007
420
                    last_split = Hole::None;
1008
420
                    if initial_entry.is_none() {
1009
84
                        initial_entry = Some(entry);
1010
336
                    }
1011
                } else {
1012
432
                    if initial_entry.is_none() {
1013
336
                        initial_entry = Some(self.c.insts.len());
1014
336
                    }
1015
432
                    self.c.fill_to_next(last_split);
1016
432
                    last_split = self.c.push_split_hole();
1017
432
                    let Patch { hole, entry } = self.c_utf8_seq(&utf8_seq)?;
1018
432
                    holes.push(hole);
1019
432
                    last_split =
1020
432
                        self.c.fill_split(last_split, Some(entry), None);
1021
                }
1022
            }
1023
        }
1024
420
        self.c.utf8_seqs = Some(utf8_seqs);
1025
420
        Ok(Patch { hole: Hole::Many(holes), entry: initial_entry.unwrap() })
1026
420
    }
<regex::compile::CompileClass>::compile
Line
Count
Source
987
210
    fn compile(mut self) -> Result {
988
210
        let mut holes = vec![];
989
210
        let mut initial_entry = None;
990
210
        let mut last_split = Hole::None;
991
210
        let mut utf8_seqs = self.c.utf8_seqs.take().unwrap();
992
210
        self.c.suffix_cache.clear();
993
994
378
        for (i, range) in self.ranges.iter().enumerate() {
995
378
            let is_last_range = i + 1 == self.ranges.len();
996
378
            utf8_seqs.reset(range.start(), range.end());
997
378
            let mut it = (&mut utf8_seqs).peekable();
998
            loop {
999
804
                let utf8_seq = match it.next() {
1000
378
                    None => break,
1001
426
                    Some(utf8_seq) => utf8_seq,
1002
                };
1003
426
                if is_last_range && it.peek().is_none() {
1004
210
                    let Patch { hole, entry } = self.c_utf8_seq(&utf8_seq)?;
1005
210
                    holes.push(hole);
1006
210
                    self.c.fill(last_split, entry);
1007
210
                    last_split = Hole::None;
1008
210
                    if initial_entry.is_none() {
1009
42
                        initial_entry = Some(entry);
1010
168
                    }
1011
                } else {
1012
216
                    if initial_entry.is_none() {
1013
168
                        initial_entry = Some(self.c.insts.len());
1014
168
                    }
1015
216
                    self.c.fill_to_next(last_split);
1016
216
                    last_split = self.c.push_split_hole();
1017
216
                    let Patch { hole, entry } = self.c_utf8_seq(&utf8_seq)?;
1018
216
                    holes.push(hole);
1019
216
                    last_split =
1020
216
                        self.c.fill_split(last_split, Some(entry), None);
1021
                }
1022
            }
1023
        }
1024
210
        self.c.utf8_seqs = Some(utf8_seqs);
1025
210
        Ok(Patch { hole: Hole::Many(holes), entry: initial_entry.unwrap() })
1026
210
    }
<regex::compile::CompileClass>::compile
Line
Count
Source
987
210
    fn compile(mut self) -> Result {
988
210
        let mut holes = vec![];
989
210
        let mut initial_entry = None;
990
210
        let mut last_split = Hole::None;
991
210
        let mut utf8_seqs = self.c.utf8_seqs.take().unwrap();
992
210
        self.c.suffix_cache.clear();
993
994
378
        for (i, range) in self.ranges.iter().enumerate() {
995
378
            let is_last_range = i + 1 == self.ranges.len();
996
378
            utf8_seqs.reset(range.start(), range.end());
997
378
            let mut it = (&mut utf8_seqs).peekable();
998
            loop {
999
804
                let utf8_seq = match it.next() {
1000
378
                    None => break,
1001
426
                    Some(utf8_seq) => utf8_seq,
1002
                };
1003
426
                if is_last_range && it.peek().is_none() {
1004
210
                    let Patch { hole, entry } = self.c_utf8_seq(&utf8_seq)?;
1005
210
                    holes.push(hole);
1006
210
                    self.c.fill(last_split, entry);
1007
210
                    last_split = Hole::None;
1008
210
                    if initial_entry.is_none() {
1009
42
                        initial_entry = Some(entry);
1010
168
                    }
1011
                } else {
1012
216
                    if initial_entry.is_none() {
1013
168
                        initial_entry = Some(self.c.insts.len());
1014
168
                    }
1015
216
                    self.c.fill_to_next(last_split);
1016
216
                    last_split = self.c.push_split_hole();
1017
216
                    let Patch { hole, entry } = self.c_utf8_seq(&utf8_seq)?;
1018
216
                    holes.push(hole);
1019
216
                    last_split =
1020
216
                        self.c.fill_split(last_split, Some(entry), None);
1021
                }
1022
            }
1023
        }
1024
210
        self.c.utf8_seqs = Some(utf8_seqs);
1025
210
        Ok(Patch { hole: Hole::Many(holes), entry: initial_entry.unwrap() })
1026
210
    }
1027
1028
852
    fn c_utf8_seq(&mut self, seq: &Utf8Sequence) -> Result {
1029
852
        if self.c.compiled.is_reverse {
1030
426
            self.c_utf8_seq_(seq)
1031
        } else {
1032
426
            self.c_utf8_seq_(seq.into_iter().rev())
1033
        }
1034
852
    }
<regex::compile::CompileClass>::c_utf8_seq
Line
Count
Source
1028
426
    fn c_utf8_seq(&mut self, seq: &Utf8Sequence) -> Result {
1029
426
        if self.c.compiled.is_reverse {
1030
213
            self.c_utf8_seq_(seq)
1031
        } else {
1032
213
            self.c_utf8_seq_(seq.into_iter().rev())
1033
        }
1034
426
    }
<regex::compile::CompileClass>::c_utf8_seq
Line
Count
Source
1028
426
    fn c_utf8_seq(&mut self, seq: &Utf8Sequence) -> Result {
1029
426
        if self.c.compiled.is_reverse {
1030
213
            self.c_utf8_seq_(seq)
1031
        } else {
1032
213
            self.c_utf8_seq_(seq.into_iter().rev())
1033
        }
1034
426
    }
1035
1036
852
    fn c_utf8_seq_<'r, I>(&mut self, seq: I) -> Result
1037
852
    where
1038
852
        I: IntoIterator<Item = &'r Utf8Range>,
1039
    {
1040
        // The initial instruction for each UTF-8 sequence should be the same.
1041
852
        let mut from_inst = ::std::usize::MAX;
1042
852
        let mut last_hole = Hole::None;
1043
1.92k
        for byte_range in seq {
1044
1.06k
            let key = SuffixCacheKey {
1045
1.06k
                from_inst: from_inst,
1046
1.06k
                start: byte_range.start,
1047
1.06k
                end: byte_range.end,
1048
1.06k
            };
1049
            {
1050
1.06k
                let pc = self.c.insts.len();
1051
1.06k
                if let Some(cached_pc) = self.c.suffix_cache.get(key, pc) {
1052
66
                    from_inst = cached_pc;
1053
66
                    continue;
1054
1.00k
                }
1055
            }
1056
1.00k
            self.c.byte_classes.set_range(byte_range.start, byte_range.end);
1057
1.00k
            if from_inst == ::std::usize::MAX {
1058
810
                last_hole = self.c.push_hole(InstHole::Bytes {
1059
810
                    start: byte_range.start,
1060
810
                    end: byte_range.end,
1061
810
                });
1062
810
            } else {
1063
192
                self.c.push_compiled(Inst::Bytes(InstBytes {
1064
192
                    goto: from_inst,
1065
192
                    start: byte_range.start,
1066
192
                    end: byte_range.end,
1067
192
                }));
1068
192
            }
1069
1.00k
            from_inst = self.c.insts.len().checked_sub(1).unwrap();
1070
1.00k
            debug_assert!(from_inst < ::std::usize::MAX);
1071
        }
1072
852
        debug_assert!(from_inst < ::std::usize::MAX);
1073
852
        Ok(Patch { hole: last_hole, entry: from_inst })
1074
852
    }
<regex::compile::CompileClass>::c_utf8_seq_::<core::iter::adapters::rev::Rev<core::slice::iter::Iter<regex_syntax::utf8::Utf8Range>>>
Line
Count
Source
1036
213
    fn c_utf8_seq_<'r, I>(&mut self, seq: I) -> Result
1037
213
    where
1038
213
        I: IntoIterator<Item = &'r Utf8Range>,
1039
    {
1040
        // The initial instruction for each UTF-8 sequence should be the same.
1041
213
        let mut from_inst = ::std::usize::MAX;
1042
213
        let mut last_hole = Hole::None;
1043
480
        for byte_range in seq {
1044
267
            let key = SuffixCacheKey {
1045
267
                from_inst: from_inst,
1046
267
                start: byte_range.start,
1047
267
                end: byte_range.end,
1048
267
            };
1049
            {
1050
267
                let pc = self.c.insts.len();
1051
267
                if let Some(cached_pc) = self.c.suffix_cache.get(key, pc) {
1052
33
                    from_inst = cached_pc;
1053
33
                    continue;
1054
234
                }
1055
            }
1056
234
            self.c.byte_classes.set_range(byte_range.start, byte_range.end);
1057
234
            if from_inst == ::std::usize::MAX {
1058
192
                last_hole = self.c.push_hole(InstHole::Bytes {
1059
192
                    start: byte_range.start,
1060
192
                    end: byte_range.end,
1061
192
                });
1062
192
            } else {
1063
42
                self.c.push_compiled(Inst::Bytes(InstBytes {
1064
42
                    goto: from_inst,
1065
42
                    start: byte_range.start,
1066
42
                    end: byte_range.end,
1067
42
                }));
1068
42
            }
1069
234
            from_inst = self.c.insts.len().checked_sub(1).unwrap();
1070
234
            debug_assert!(from_inst < ::std::usize::MAX);
1071
        }
1072
213
        debug_assert!(from_inst < ::std::usize::MAX);
1073
213
        Ok(Patch { hole: last_hole, entry: from_inst })
1074
213
    }
<regex::compile::CompileClass>::c_utf8_seq_::<&regex_syntax::utf8::Utf8Sequence>
Line
Count
Source
1036
213
    fn c_utf8_seq_<'r, I>(&mut self, seq: I) -> Result
1037
213
    where
1038
213
        I: IntoIterator<Item = &'r Utf8Range>,
1039
    {
1040
        // The initial instruction for each UTF-8 sequence should be the same.
1041
213
        let mut from_inst = ::std::usize::MAX;
1042
213
        let mut last_hole = Hole::None;
1043
480
        for byte_range in seq {
1044
267
            let key = SuffixCacheKey {
1045
267
                from_inst: from_inst,
1046
267
                start: byte_range.start,
1047
267
                end: byte_range.end,
1048
267
            };
1049
            {
1050
267
                let pc = self.c.insts.len();
1051
267
                if let Some(cached_pc) = self.c.suffix_cache.get(key, pc) {
1052
0
                    from_inst = cached_pc;
1053
0
                    continue;
1054
267
                }
1055
            }
1056
267
            self.c.byte_classes.set_range(byte_range.start, byte_range.end);
1057
267
            if from_inst == ::std::usize::MAX {
1058
213
                last_hole = self.c.push_hole(InstHole::Bytes {
1059
213
                    start: byte_range.start,
1060
213
                    end: byte_range.end,
1061
213
                });
1062
213
            } else {
1063
54
                self.c.push_compiled(Inst::Bytes(InstBytes {
1064
54
                    goto: from_inst,
1065
54
                    start: byte_range.start,
1066
54
                    end: byte_range.end,
1067
54
                }));
1068
54
            }
1069
267
            from_inst = self.c.insts.len().checked_sub(1).unwrap();
1070
267
            debug_assert!(from_inst < ::std::usize::MAX);
1071
        }
1072
213
        debug_assert!(from_inst < ::std::usize::MAX);
1073
213
        Ok(Patch { hole: last_hole, entry: from_inst })
1074
213
    }
<regex::compile::CompileClass>::c_utf8_seq_::<core::iter::adapters::rev::Rev<core::slice::iter::Iter<regex_syntax::utf8::Utf8Range>>>
Line
Count
Source
1036
213
    fn c_utf8_seq_<'r, I>(&mut self, seq: I) -> Result
1037
213
    where
1038
213
        I: IntoIterator<Item = &'r Utf8Range>,
1039
    {
1040
        // The initial instruction for each UTF-8 sequence should be the same.
1041
213
        let mut from_inst = ::std::usize::MAX;
1042
213
        let mut last_hole = Hole::None;
1043
480
        for byte_range in seq {
1044
267
            let key = SuffixCacheKey {
1045
267
                from_inst: from_inst,
1046
267
                start: byte_range.start,
1047
267
                end: byte_range.end,
1048
267
            };
1049
            {
1050
267
                let pc = self.c.insts.len();
1051
267
                if let Some(cached_pc) = self.c.suffix_cache.get(key, pc) {
1052
33
                    from_inst = cached_pc;
1053
33
                    continue;
1054
234
                }
1055
            }
1056
234
            self.c.byte_classes.set_range(byte_range.start, byte_range.end);
1057
234
            if from_inst == ::std::usize::MAX {
1058
192
                last_hole = self.c.push_hole(InstHole::Bytes {
1059
192
                    start: byte_range.start,
1060
192
                    end: byte_range.end,
1061
192
                });
1062
192
            } else {
1063
42
                self.c.push_compiled(Inst::Bytes(InstBytes {
1064
42
                    goto: from_inst,
1065
42
                    start: byte_range.start,
1066
42
                    end: byte_range.end,
1067
42
                }));
1068
42
            }
1069
234
            from_inst = self.c.insts.len().checked_sub(1).unwrap();
1070
234
            debug_assert!(from_inst < ::std::usize::MAX);
1071
        }
1072
213
        debug_assert!(from_inst < ::std::usize::MAX);
1073
213
        Ok(Patch { hole: last_hole, entry: from_inst })
1074
213
    }
<regex::compile::CompileClass>::c_utf8_seq_::<&regex_syntax::utf8::Utf8Sequence>
Line
Count
Source
1036
213
    fn c_utf8_seq_<'r, I>(&mut self, seq: I) -> Result
1037
213
    where
1038
213
        I: IntoIterator<Item = &'r Utf8Range>,
1039
    {
1040
        // The initial instruction for each UTF-8 sequence should be the same.
1041
213
        let mut from_inst = ::std::usize::MAX;
1042
213
        let mut last_hole = Hole::None;
1043
480
        for byte_range in seq {
1044
267
            let key = SuffixCacheKey {
1045
267
                from_inst: from_inst,
1046
267
                start: byte_range.start,
1047
267
                end: byte_range.end,
1048
267
            };
1049
            {
1050
267
                let pc = self.c.insts.len();
1051
267
                if let Some(cached_pc) = self.c.suffix_cache.get(key, pc) {
1052
0
                    from_inst = cached_pc;
1053
0
                    continue;
1054
267
                }
1055
            }
1056
267
            self.c.byte_classes.set_range(byte_range.start, byte_range.end);
1057
267
            if from_inst == ::std::usize::MAX {
1058
213
                last_hole = self.c.push_hole(InstHole::Bytes {
1059
213
                    start: byte_range.start,
1060
213
                    end: byte_range.end,
1061
213
                });
1062
213
            } else {
1063
54
                self.c.push_compiled(Inst::Bytes(InstBytes {
1064
54
                    goto: from_inst,
1065
54
                    start: byte_range.start,
1066
54
                    end: byte_range.end,
1067
54
                }));
1068
54
            }
1069
267
            from_inst = self.c.insts.len().checked_sub(1).unwrap();
1070
267
            debug_assert!(from_inst < ::std::usize::MAX);
1071
        }
1072
213
        debug_assert!(from_inst < ::std::usize::MAX);
1073
213
        Ok(Patch { hole: last_hole, entry: from_inst })
1074
213
    }
1075
}
1076
1077
/// `SuffixCache` is a simple bounded hash map for caching suffix entries in
1078
/// UTF-8 automata. For example, consider the Unicode range \u{0}-\u{FFFF}.
1079
/// The set of byte ranges looks like this:
1080
///
1081
/// [0-7F]
1082
/// [C2-DF][80-BF]
1083
/// [E0][A0-BF][80-BF]
1084
/// [E1-EC][80-BF][80-BF]
1085
/// [ED][80-9F][80-BF]
1086
/// [EE-EF][80-BF][80-BF]
1087
///
1088
/// Each line above translates to one alternate in the compiled regex program.
1089
/// However, all but one of the alternates end in the same suffix, which is
1090
/// a waste of an instruction. The suffix cache facilitates reusing them across
1091
/// alternates.
1092
///
1093
/// Note that a HashMap could be trivially used for this, but we don't need its
1094
/// overhead. Some small bounded space (LRU style) is more than enough.
1095
///
1096
/// This uses similar idea to [`SparseSet`](../sparse/struct.SparseSet.html),
1097
/// except it uses hashes as original indices and then compares full keys for
1098
/// validation against `dense` array.
1099
#[derive(Debug)]
1100
struct SuffixCache {
1101
    sparse: Box<[usize]>,
1102
    dense: Vec<SuffixCacheEntry>,
1103
}
1104
1105
#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
1106
struct SuffixCacheEntry {
1107
    key: SuffixCacheKey,
1108
    pc: InstPtr,
1109
}
1110
1111
#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
1112
struct SuffixCacheKey {
1113
    from_inst: InstPtr,
1114
    start: u8,
1115
    end: u8,
1116
}
1117
1118
impl SuffixCache {
1119
54
    fn new(size: usize) -> Self {
1120
54
        SuffixCache {
1121
54
            sparse: vec![0usize; size].into(),
1122
54
            dense: Vec::with_capacity(size),
1123
54
        }
1124
54
    }
<regex::compile::SuffixCache>::new
Line
Count
Source
1119
27
    fn new(size: usize) -> Self {
1120
27
        SuffixCache {
1121
27
            sparse: vec![0usize; size].into(),
1122
27
            dense: Vec::with_capacity(size),
1123
27
        }
1124
27
    }
<regex::compile::SuffixCache>::new
Line
Count
Source
1119
27
    fn new(size: usize) -> Self {
1120
27
        SuffixCache {
1121
27
            sparse: vec![0usize; size].into(),
1122
27
            dense: Vec::with_capacity(size),
1123
27
        }
1124
27
    }
1125
1126
1.06k
    fn get(&mut self, key: SuffixCacheKey, pc: InstPtr) -> Option<InstPtr> {
1127
1.06k
        let hash = self.hash(&key);
1128
1.06k
        let pos = &mut self.sparse[hash];
1129
1.06k
        if let Some(entry) = self.dense.get(*pos) {
1130
396
            if entry.key == key {
1131
66
                return Some(entry.pc);
1132
330
            }
1133
672
        }
1134
1.00k
        *pos = self.dense.len();
1135
1.00k
        self.dense.push(SuffixCacheEntry { key: key, pc: pc });
1136
1.00k
        None
1137
1.06k
    }
<regex::compile::SuffixCache>::get
Line
Count
Source
1126
534
    fn get(&mut self, key: SuffixCacheKey, pc: InstPtr) -> Option<InstPtr> {
1127
534
        let hash = self.hash(&key);
1128
534
        let pos = &mut self.sparse[hash];
1129
534
        if let Some(entry) = self.dense.get(*pos) {
1130
198
            if entry.key == key {
1131
33
                return Some(entry.pc);
1132
165
            }
1133
336
        }
1134
501
        *pos = self.dense.len();
1135
501
        self.dense.push(SuffixCacheEntry { key: key, pc: pc });
1136
501
        None
1137
534
    }
<regex::compile::SuffixCache>::get
Line
Count
Source
1126
534
    fn get(&mut self, key: SuffixCacheKey, pc: InstPtr) -> Option<InstPtr> {
1127
534
        let hash = self.hash(&key);
1128
534
        let pos = &mut self.sparse[hash];
1129
534
        if let Some(entry) = self.dense.get(*pos) {
1130
198
            if entry.key == key {
1131
33
                return Some(entry.pc);
1132
165
            }
1133
336
        }
1134
501
        *pos = self.dense.len();
1135
501
        self.dense.push(SuffixCacheEntry { key: key, pc: pc });
1136
501
        None
1137
534
    }
1138
1139
420
    fn clear(&mut self) {
1140
420
        self.dense.clear();
1141
420
    }
<regex::compile::SuffixCache>::clear
Line
Count
Source
1139
210
    fn clear(&mut self) {
1140
210
        self.dense.clear();
1141
210
    }
<regex::compile::SuffixCache>::clear
Line
Count
Source
1139
210
    fn clear(&mut self) {
1140
210
        self.dense.clear();
1141
210
    }
1142
1143
1.06k
    fn hash(&self, suffix: &SuffixCacheKey) -> usize {
1144
        // Basic FNV-1a hash as described:
1145
        // https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function
1146
        const FNV_PRIME: u64 = 1099511628211;
1147
1.06k
        let mut h = 14695981039346656037;
1148
1.06k
        h = (h ^ (suffix.from_inst as u64)).wrapping_mul(FNV_PRIME);
1149
1.06k
        h = (h ^ (suffix.start as u64)).wrapping_mul(FNV_PRIME);
1150
1.06k
        h = (h ^ (suffix.end as u64)).wrapping_mul(FNV_PRIME);
1151
1.06k
        (h as usize) % self.sparse.len()
1152
1.06k
    }
<regex::compile::SuffixCache>::hash
Line
Count
Source
1143
534
    fn hash(&self, suffix: &SuffixCacheKey) -> usize {
1144
        // Basic FNV-1a hash as described:
1145
        // https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function
1146
        const FNV_PRIME: u64 = 1099511628211;
1147
534
        let mut h = 14695981039346656037;
1148
534
        h = (h ^ (suffix.from_inst as u64)).wrapping_mul(FNV_PRIME);
1149
534
        h = (h ^ (suffix.start as u64)).wrapping_mul(FNV_PRIME);
1150
534
        h = (h ^ (suffix.end as u64)).wrapping_mul(FNV_PRIME);
1151
534
        (h as usize) % self.sparse.len()
1152
534
    }
<regex::compile::SuffixCache>::hash
Line
Count
Source
1143
534
    fn hash(&self, suffix: &SuffixCacheKey) -> usize {
1144
        // Basic FNV-1a hash as described:
1145
        // https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function
1146
        const FNV_PRIME: u64 = 1099511628211;
1147
534
        let mut h = 14695981039346656037;
1148
534
        h = (h ^ (suffix.from_inst as u64)).wrapping_mul(FNV_PRIME);
1149
534
        h = (h ^ (suffix.start as u64)).wrapping_mul(FNV_PRIME);
1150
534
        h = (h ^ (suffix.end as u64)).wrapping_mul(FNV_PRIME);
1151
534
        (h as usize) % self.sparse.len()
1152
534
    }
1153
}
1154
1155
struct ByteClassSet([bool; 256]);
1156
1157
impl ByteClassSet {
1158
54
    fn new() -> Self {
1159
54
        ByteClassSet([false; 256])
1160
54
    }
<regex::compile::ByteClassSet>::new
Line
Count
Source
1158
27
    fn new() -> Self {
1159
27
        ByteClassSet([false; 256])
1160
27
    }
<regex::compile::ByteClassSet>::new
Line
Count
Source
1158
27
    fn new() -> Self {
1159
27
        ByteClassSet([false; 256])
1160
27
    }
1161
1162
2.11k
    fn set_range(&mut self, start: u8, end: u8) {
1163
2.11k
        debug_assert!(start <= end);
1164
2.11k
        if start > 0 {
1165
2.10k
            self.0[start as usize - 1] = true;
1166
2.10k
        }
1167
2.11k
        self.0[end as usize] = true;
1168
2.11k
    }
<regex::compile::ByteClassSet>::set_range
Line
Count
Source
1162
1.05k
    fn set_range(&mut self, start: u8, end: u8) {
1163
1.05k
        debug_assert!(start <= end);
1164
1.05k
        if start > 0 {
1165
1.05k
            self.0[start as usize - 1] = true;
1166
1.05k
        }
1167
1.05k
        self.0[end as usize] = true;
1168
1.05k
    }
<regex::compile::ByteClassSet>::set_range
Line
Count
Source
1162
1.05k
    fn set_range(&mut self, start: u8, end: u8) {
1163
1.05k
        debug_assert!(start <= end);
1164
1.05k
        if start > 0 {
1165
1.05k
            self.0[start as usize - 1] = true;
1166
1.05k
        }
1167
1.05k
        self.0[end as usize] = true;
1168
1.05k
    }
1169
1170
0
    fn set_word_boundary(&mut self) {
1171
        // We need to mark all ranges of bytes whose pairs result in
1172
        // evaluating \b differently.
1173
0
        let iswb = is_word_byte;
1174
0
        let mut b1: u16 = 0;
1175
        let mut b2: u16;
1176
0
        while b1 <= 255 {
1177
0
            b2 = b1 + 1;
1178
0
            while b2 <= 255 && iswb(b1 as u8) == iswb(b2 as u8) {
1179
0
                b2 += 1;
1180
0
            }
1181
0
            self.set_range(b1 as u8, (b2 - 1) as u8);
1182
0
            b1 = b2;
1183
        }
1184
0
    }
Unexecuted instantiation: <regex::compile::ByteClassSet>::set_word_boundary
Unexecuted instantiation: <regex::compile::ByteClassSet>::set_word_boundary
1185
1186
54
    fn byte_classes(&self) -> Vec<u8> {
1187
        // N.B. If you're debugging the DFA, it's useful to simply return
1188
        // `(0..256).collect()`, which effectively removes the byte classes
1189
        // and makes the transitions easier to read.
1190
        // (0usize..256).map(|x| x as u8).collect()
1191
54
        let mut byte_classes = vec![0; 256];
1192
54
        let mut class = 0u8;
1193
54
        let mut i = 0;
1194
        loop {
1195
13.8k
            byte_classes[i] = class as u8;
1196
13.8k
            if i >= 255 {
1197
54
                break;
1198
13.7k
            }
1199
13.7k
            if self.0[i] {
1200
1.18k
                class = class.checked_add(1).unwrap();
1201
12.5k
            }
1202
13.7k
            i += 1;
1203
        }
1204
54
        byte_classes
1205
54
    }
<regex::compile::ByteClassSet>::byte_classes
Line
Count
Source
1186
27
    fn byte_classes(&self) -> Vec<u8> {
1187
        // N.B. If you're debugging the DFA, it's useful to simply return
1188
        // `(0..256).collect()`, which effectively removes the byte classes
1189
        // and makes the transitions easier to read.
1190
        // (0usize..256).map(|x| x as u8).collect()
1191
27
        let mut byte_classes = vec![0; 256];
1192
27
        let mut class = 0u8;
1193
27
        let mut i = 0;
1194
        loop {
1195
6.91k
            byte_classes[i] = class as u8;
1196
6.91k
            if i >= 255 {
1197
27
                break;
1198
6.88k
            }
1199
6.88k
            if self.0[i] {
1200
594
                class = class.checked_add(1).unwrap();
1201
6.29k
            }
1202
6.88k
            i += 1;
1203
        }
1204
27
        byte_classes
1205
27
    }
<regex::compile::ByteClassSet>::byte_classes
Line
Count
Source
1186
27
    fn byte_classes(&self) -> Vec<u8> {
1187
        // N.B. If you're debugging the DFA, it's useful to simply return
1188
        // `(0..256).collect()`, which effectively removes the byte classes
1189
        // and makes the transitions easier to read.
1190
        // (0usize..256).map(|x| x as u8).collect()
1191
27
        let mut byte_classes = vec![0; 256];
1192
27
        let mut class = 0u8;
1193
27
        let mut i = 0;
1194
        loop {
1195
6.91k
            byte_classes[i] = class as u8;
1196
6.91k
            if i >= 255 {
1197
27
                break;
1198
6.88k
            }
1199
6.88k
            if self.0[i] {
1200
594
                class = class.checked_add(1).unwrap();
1201
6.29k
            }
1202
6.88k
            i += 1;
1203
        }
1204
27
        byte_classes
1205
27
    }
1206
}
1207
1208
impl fmt::Debug for ByteClassSet {
1209
0
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1210
0
        f.debug_tuple("ByteClassSet").field(&&self.0[..]).finish()
1211
0
    }
Unexecuted instantiation: <regex::compile::ByteClassSet as core::fmt::Debug>::fmt
Unexecuted instantiation: <regex::compile::ByteClassSet as core::fmt::Debug>::fmt
1212
}
1213
1214
0
fn u32_to_usize(n: u32) -> usize {
1215
    // In case usize is less than 32 bits, we need to guard against overflow.
1216
    // On most platforms this compiles to nothing.
1217
    // TODO Use `std::convert::TryFrom` once it's stable.
1218
0
    if (n as u64) > (::std::usize::MAX as u64) {
1219
0
        panic!("BUG: {} is too big to be pointer sized", n)
1220
0
    }
1221
0
    n as usize
1222
0
}
Unexecuted instantiation: regex::compile::u32_to_usize
Unexecuted instantiation: regex::compile::u32_to_usize
1223
1224
#[cfg(test)]
1225
mod tests {
1226
    use super::ByteClassSet;
1227
1228
    #[test]
1229
    fn byte_classes() {
1230
        let mut set = ByteClassSet::new();
1231
        set.set_range(b'a', b'z');
1232
        let classes = set.byte_classes();
1233
        assert_eq!(classes[0], 0);
1234
        assert_eq!(classes[1], 0);
1235
        assert_eq!(classes[2], 0);
1236
        assert_eq!(classes[b'a' as usize - 1], 0);
1237
        assert_eq!(classes[b'a' as usize], 1);
1238
        assert_eq!(classes[b'm' as usize], 1);
1239
        assert_eq!(classes[b'z' as usize], 1);
1240
        assert_eq!(classes[b'z' as usize + 1], 2);
1241
        assert_eq!(classes[254], 2);
1242
        assert_eq!(classes[255], 2);
1243
1244
        let mut set = ByteClassSet::new();
1245
        set.set_range(0, 2);
1246
        set.set_range(4, 6);
1247
        let classes = set.byte_classes();
1248
        assert_eq!(classes[0], 0);
1249
        assert_eq!(classes[1], 0);
1250
        assert_eq!(classes[2], 0);
1251
        assert_eq!(classes[3], 1);
1252
        assert_eq!(classes[4], 2);
1253
        assert_eq!(classes[5], 2);
1254
        assert_eq!(classes[6], 2);
1255
        assert_eq!(classes[7], 3);
1256
        assert_eq!(classes[255], 3);
1257
    }
1258
1259
    #[test]
1260
    fn full_byte_classes() {
1261
        let mut set = ByteClassSet::new();
1262
        for i in 0..256u16 {
1263
            set.set_range(i as u8, i as u8);
1264
        }
1265
        assert_eq!(set.byte_classes().len(), 256);
1266
    }
1267
}