1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
//! Escapes a bare literal line into the engine's always-verbose dialect.
//!
//! The forbidden-regex engine is always in verbose mode,
//! so unescaped whitespace
//! is swallowed and a `#` at a line start begins a comment.
//! A literal rule must
//! therefore be rewritten so every byte matches itself and nothing else:
//! the
//! escapable metacharacters and every whitespace byte gain a leading backslash,
//! and every other byte passes through as a one-byte literal.
//! This is a
//! syntax-boundary transformer (literal text into pattern syntax),
//! so its one job
//! is that the compiled pattern matches exactly the input literal.
/// Reports whether a character must be backslash-escaped in the verbose dialect.
///
/// The set is exactly the bytes the engine's escape parser accepts as a literal
/// byte (`parse_escape`):
/// the metacharacters below plus every ASCII whitespace
/// byte.
/// Every other byte is a plain literal in atom position,
/// so escaping it is
/// unnecessary and (for non-listed bytes) would be an "unsupported escape".
/// The
/// whitespace test uses `is_ascii_whitespace`,
/// matching the engine's own cursor
/// and escape parser (space,
/// tab,
/// newline,
/// form feed,
/// carriage return;
/// not the
/// vertical tab,
/// which the engine treats as a plain literal byte).
/// Escapes one literal line into a verbose-dialect pattern matching it exactly.
///
/// Each escapable metacharacter and whitespace byte gains a leading backslash;
/// every other character (ordinary ASCII,
/// and every byte of a multi-byte UTF-8
/// character,
/// all of which are non-ASCII and never in the escape set) is emitted
/// unchanged.
/// Only ASCII backslashes are inserted,
/// always before an ASCII byte,
/// so the result stays valid UTF-8 without a fallible reassembly step.
///
/// Declared `pub` (not `pub(super)`) so the frx module can re-export it under the
/// `fuzzing` feature for the `fuzz_literal_roundtrip` target;
/// the `rule` module is
/// private,
/// so this never widens the production public surface.
/// Exclusive byte-length ceiling below which a bare literal is matched only at word
/// boundaries.
///
/// A short run of word bytes collides with substrings of longer tokens far more
/// often than a long one:
/// a three-byte run like `ABC` turns up inside base64 blobs,
/// hex dumps,
/// and identifiers by chance,
/// and a bare literal otherwise matches every
/// such coincidence.
/// Gating a short literal on a word boundary at each word-byte end
/// confines it to whole-token matches,
/// while longer literals,
/// which rarely collide,
/// stay plain substring rules.
/// Eight is the smallest ceiling that still treats the
/// common short acronyms as whole words.
const WORD_BOUNDARY_MAX_LEN: usize = 8;
/// The `\b` word-boundary assertion inserted at a word-byte end of a short literal.
const WORD_BOUNDARY: &str = "\\b";
/// Reports whether a byte is an ASCII word byte (`[0-9A-Za-z_]`).
///
/// A `\b` boundary is defined only between a word byte and a non-word byte,
/// so it is
/// meaningful only next to one of these.
/// Every byte of a multi-byte UTF-8 character
/// is non-word,
/// which is why a CJK literal takes no boundary:
/// a `\b` there would
/// assert an ASCII boundary the surrounding CJK text never provides,
/// silencing the
/// rule.
/// Escapes a bare literal,
/// gating a short one behind word boundaries.
///
/// Delegates to [`escape_literal`] for the exact-match body,
/// then,
/// when the literal
/// is under [`WORD_BOUNDARY_MAX_LEN`] bytes,
/// prepends a boundary when its first byte
/// is a word byte and appends one when its last byte is a word byte.
/// So `ABC`
/// compiles to `\bABC\b` and no longer matches inside a base64 run,
/// while a literal
/// ending in a non-word byte (trailing punctuation,
/// or any byte of a CJK character)
/// keeps a plain end there.
/// A literal at or above the ceiling is escaped unchanged.
pub
/// Registers the round-trip and adversarial escaping tests (sidecar,
/// lint-exempt).