1#![deny(rust_2018_idioms)]
8
9mod ir;
10#[allow(clippy::range_plus_one)]
11mod parser;
12#[cfg(test)]
13mod tests;
14mod unicode;
15
16pub use parser::*;
17
18pub use ir::*;
19use std::ops::Range;
20pub use unicode::EcmaVersion;
21
22pub type Result<T, E = Error> = std::result::Result<T, E>;
23
24#[derive(Debug, Clone, PartialEq, Eq, Hash)]
25pub struct Span {
26 pub offset: usize,
28 pub start: usize,
30 pub end: usize,
32}
33
34impl Span {
35 pub fn new(offset: usize, start: usize, end: usize) -> Self {
37 Self { offset, start, end }
38 }
39
40 pub fn abs_start(&self) -> usize {
42 self.offset + self.start
43 }
44
45 pub fn abs_end(&self) -> usize {
47 self.offset + self.end
48 }
49
50 pub fn as_range(&self) -> Range<usize> {
51 self.abs_start()..self.abs_end()
52 }
53}
54
55impl From<Range<usize>> for Span {
56 fn from(range: Range<usize>) -> Self {
57 Span::new(0, range.start, range.end)
58 }
59}
60
61#[cfg(feature = "rslint_errors")]
62impl rslint_errors::Span for Span {
63 fn as_range(&self) -> Range<usize> {
64 self.abs_start()..self.abs_end()
65 }
66}
67
68#[derive(Debug, Clone, PartialEq, Eq, Hash)]
69pub struct Error {
70 pub span: Span,
71 pub message: String,
72}
73
74impl Error {
75 pub fn new(message: impl ToString, span: Span) -> Self {
76 Self {
77 span,
78 message: message.to_string(),
79 }
80 }
81
82 pub(crate) fn primary(self, span: impl Into<Span>, _msg: &str) -> Self {
83 Self {
84 span: span.into(),
85 message: self.message,
86 }
87 }
88}
89
90#[allow(unused_variables)]
95pub trait Visit {
96 fn visit_regex(&mut self, regex: &Regex) {
97 self.visit_node(®ex.node);
98 }
99
100 fn visit_node(&mut self, node: &Node) {
101 match node {
102 Node::Empty => self.visit_empty_node(),
103 Node::Disjunction(span, nodes) => self.visit_disjunction(span, nodes),
104 Node::Assertion(span, kind) => self.visit_assertion(span, kind),
105 Node::Alternative(span, nodes) => self.visit_alternative(span, nodes),
106 Node::Literal(span, literal, _) => self.visit_literal(span, *literal),
107 Node::PerlClass(span, kind, negated) => {
108 self.visit_perl_class(span, kind.to_owned(), *negated)
109 }
110 Node::BackReference(span, reference) => self.visit_backreference(span, *reference),
111 Node::Dot(span) => self.visit_dot(span),
112 Node::CharacterClass(span, class) => self.visit_character_class(span, class),
113 Node::Group(span, group) => self.visit_group(span, group),
114 Node::Quantifier(span, node, kind, lazy) => {
115 self.visit_quantifier(span, node, kind.to_owned(), *lazy)
116 }
117 Node::NamedBackReference(span, backreference) => {
118 self.visit_named_backreference(span, backreference)
119 }
120 }
121 }
122
123 fn visit_empty_node(&mut self) {}
124
125 fn visit_disjunction(&mut self, span: &Span, nodes: &[Node]) {
126 for node in nodes {
127 self.visit_node(node);
128 }
129 }
130
131 fn visit_assertion(&mut self, span: &Span, kind: &AssertionKind) {
132 match kind {
133 AssertionKind::Lookahead(node)
134 | AssertionKind::Lookbehind(node)
135 | AssertionKind::NegativeLookahead(node)
136 | AssertionKind::NegativeLookbehind(node) => self.visit_node(node),
137 _ => {}
138 }
139 }
140
141 fn visit_alternative(&mut self, span: &Span, nodes: &[Node]) {
142 for node in nodes {
143 self.visit_node(node);
144 }
145 }
146
147 fn visit_literal(&mut self, span: &Span, literal: char) {}
148
149 fn visit_perl_class(&mut self, span: &Span, kind: ClassPerlKind, negated: bool) {}
150
151 fn visit_backreference(&mut self, span: &Span, reference: u32) {}
152
153 fn visit_dot(&mut self, span: &Span) {}
154
155 fn visit_character_class(&mut self, span: &Span, class: &CharacterClass) {
156 for member in &class.members {
157 match member {
158 CharacterClassMember::Range(l, r) => {
159 self.visit_node(l);
160 self.visit_node(r);
161 }
162 CharacterClassMember::Single(n) => self.visit_node(n),
163 }
164 }
165 }
166
167 fn visit_group(&mut self, span: &Span, group: &Group) {
168 self.visit_node(&group.inner)
169 }
170
171 fn visit_quantifier(&mut self, span: &Span, node: &Node, kind: QuantifierKind, lazy: bool) {
172 self.visit_node(node);
173 }
174
175 fn visit_named_backreference(&mut self, span: &Span, backreference: &str) {}
176}
177
178#[allow(unused_variables)]
179pub trait VisitMut {
180 fn visit_regex(&mut self, regex: &mut Regex) {
181 self.visit_node(&mut regex.node);
182 }
183
184 fn visit_node(&mut self, node: &mut Node) {
185 match node {
186 Node::Empty => self.visit_empty_node(),
187 Node::Disjunction(span, nodes) => self.visit_disjunction(span, nodes),
188 Node::Assertion(span, kind) => self.visit_assertion(span, kind),
189 Node::Alternative(span, nodes) => self.visit_alternative(span, nodes),
190 Node::Literal(span, literal, _) => self.visit_literal(span, literal),
191 Node::PerlClass(span, kind, negated) => self.visit_perl_class(span, kind, negated),
192 Node::BackReference(span, reference) => self.visit_backreference(span, reference),
193 Node::Dot(span) => self.visit_dot(span),
194 Node::CharacterClass(span, class) => self.visit_character_class(span, class),
195 Node::Group(span, group) => self.visit_group(span, group),
196 Node::Quantifier(span, node, kind, lazy) => {
197 self.visit_quantifier(span, node, kind, lazy)
198 }
199 Node::NamedBackReference(span, backreference) => {
200 self.visit_named_backreference(span, backreference)
201 }
202 }
203 }
204
205 fn visit_empty_node(&mut self) {}
206
207 fn visit_disjunction(&mut self, span: &Span, nodes: &mut [Node]) {
208 for node in nodes {
209 self.visit_node(node);
210 }
211 }
212
213 fn visit_assertion(&mut self, span: &Span, kind: &mut AssertionKind) {
214 match kind {
215 AssertionKind::Lookahead(node)
216 | AssertionKind::Lookbehind(node)
217 | AssertionKind::NegativeLookahead(node)
218 | AssertionKind::NegativeLookbehind(node) => self.visit_node(node),
219 _ => {}
220 }
221 }
222
223 fn visit_alternative(&mut self, span: &Span, nodes: &mut [Node]) {
224 for node in nodes {
225 self.visit_node(node);
226 }
227 }
228
229 fn visit_literal(&mut self, span: &Span, literal: &mut char) {}
230
231 fn visit_perl_class(&mut self, span: &Span, kind: &mut ClassPerlKind, negated: &mut bool) {}
232
233 fn visit_backreference(&mut self, span: &Span, reference: &mut u32) {}
234
235 fn visit_dot(&mut self, span: &Span) {}
236
237 fn visit_character_class(&mut self, span: &Span, class: &mut CharacterClass) {
238 for member in &mut class.members {
239 match member {
240 CharacterClassMember::Range(l, r) => {
241 self.visit_node(l);
242 self.visit_node(r);
243 }
244 CharacterClassMember::Single(n) => self.visit_node(n),
245 }
246 }
247 }
248
249 fn visit_group(&mut self, span: &Span, group: &mut Group) {
250 self.visit_node(&mut *group.inner)
251 }
252
253 fn visit_quantifier(
254 &mut self,
255 span: &Span,
256 node: &mut Node,
257 kind: &mut QuantifierKind,
258 lazy: &mut bool,
259 ) {
260 self.visit_node(node);
261 }
262
263 fn visit_named_backreference(&mut self, span: &Span, backreference: &mut str) {}
264}
265
266#[allow(unused_variables)]
268pub trait VisitAll {
269 #[doc(hidden)]
270 fn _visit_node(&mut self, node: &Node) {
271 match node {
272 Node::Empty => self.visit_empty_node(),
273 Node::Disjunction(span, nodes) => {
274 self._visit_disjunction(span, nodes);
275 self._visit_disjunction(span, nodes)
276 }
277 Node::Assertion(span, kind) => {
278 self.visit_assertion(span, kind);
279 self._visit_assertion(span, kind)
280 }
281 Node::Alternative(span, nodes) => {
282 self.visit_alternative(span, nodes);
283 self._visit_alternative(span, nodes)
284 }
285 Node::Literal(span, literal, _) => self.visit_literal(span, *literal),
286 Node::PerlClass(span, kind, negated) => {
287 self.visit_perl_class(span, kind.to_owned(), *negated)
288 }
289 Node::BackReference(span, reference) => self.visit_backreference(span, *reference),
290 Node::Dot(span) => self.visit_dot(span),
291 Node::CharacterClass(span, class) => {
292 self.visit_character_class(span, class);
293 self._visit_character_class(span, class);
294 }
295 Node::Group(span, group) => {
296 self.visit_group(span, group);
297 self._visit_group(span, group)
298 }
299
300 Node::Quantifier(span, node, kind, lazy) => {
301 self.visit_quantifier(span, node, kind.to_owned(), *lazy);
302 self._visit_quantifier(span, node, kind.to_owned(), *lazy);
303 }
304 Node::NamedBackReference(span, backreference) => {
305 self.visit_named_backreference(span, backreference)
306 }
307 }
308 }
309
310 #[doc(hidden)]
311 fn _visit_disjunction(&mut self, span: &Span, nodes: &[Node]) {
312 for node in nodes {
313 self._visit_node(node);
314 }
315 }
316
317 #[doc(hidden)]
318 fn _visit_assertion(&mut self, span: &Span, kind: &AssertionKind) {
319 match kind {
320 AssertionKind::Lookahead(node)
321 | AssertionKind::Lookbehind(node)
322 | AssertionKind::NegativeLookahead(node)
323 | AssertionKind::NegativeLookbehind(node) => self._visit_node(node),
324 _ => {}
325 }
326 }
327
328 #[doc(hidden)]
329 fn _visit_alternative(&mut self, span: &Span, nodes: &[Node]) {
330 for node in nodes {
331 self.visit_node(node);
332 self._visit_node(node);
333 }
334 }
335
336 #[doc(hidden)]
337 fn _visit_character_class(&mut self, span: &Span, class: &CharacterClass) {
338 for member in &class.members {
339 match member {
340 CharacterClassMember::Range(l, r) => {
341 self.visit_node(l);
342 self._visit_node(l);
343 self.visit_node(r);
344 self._visit_node(r);
345 }
346 CharacterClassMember::Single(n) => {
347 self.visit_node(n);
348 self._visit_node(n)
349 }
350 }
351 }
352 }
353
354 #[doc(hidden)]
355 fn _visit_group(&mut self, span: &Span, group: &Group) {
356 self.visit_node(&group.inner);
357 self._visit_node(&group.inner)
358 }
359
360 #[doc(hidden)]
361 fn _visit_quantifier(&mut self, span: &Span, node: &Node, kind: QuantifierKind, lazy: bool) {
362 self.visit_node(node);
363 self._visit_node(node);
364 }
365
366 fn visit_regex(&mut self, regex: &Regex) {
367 self.visit_node(®ex.node);
368 self._visit_node(®ex.node);
369 }
370 fn visit_named_backreference(&mut self, span: &Span, backreference: &str) {}
371 fn visit_alternative(&mut self, span: &Span, nodes: &[Node]) {}
372 fn visit_literal(&mut self, span: &Span, literal: char) {}
373 fn visit_perl_class(&mut self, span: &Span, kind: ClassPerlKind, negated: bool) {}
374 fn visit_backreference(&mut self, span: &Span, reference: u32) {}
375 fn visit_dot(&mut self, span: &Span) {}
376 fn visit_node(&mut self, node: &Node) {}
377 fn visit_empty_node(&mut self) {}
378 fn visit_group(&mut self, span: &Span, group: &Group) {}
379 fn visit_quantifier(&mut self, span: &Span, node: &Node, kind: QuantifierKind, lazy: bool) {}
380 fn visit_character_class(&mut self, span: &Span, class: &CharacterClass) {}
381 fn visit_assertion(&mut self, span: &Span, kind: &AssertionKind) {}
382}
383
384#[allow(unused_variables)]
385pub trait VisitAllMut {
386 #[doc(hidden)]
387 fn _visit_node(&mut self, node: &mut Node) {
388 match node {
389 Node::Empty => self.visit_empty_node(),
390 Node::Disjunction(span, nodes) => {
391 self._visit_disjunction(span, nodes);
392 self._visit_disjunction(span, nodes)
393 }
394 Node::Assertion(span, kind) => {
395 self.visit_assertion(span, kind);
396 self._visit_assertion(span, kind)
397 }
398 Node::Alternative(span, nodes) => {
399 self.visit_alternative(span, nodes);
400 self._visit_alternative(span, nodes)
401 }
402 Node::Literal(span, literal, _) => self.visit_literal(span, literal),
403 Node::PerlClass(span, kind, negated) => self.visit_perl_class(span, kind, negated),
404 Node::BackReference(span, reference) => self.visit_backreference(span, reference),
405 Node::Dot(span) => self.visit_dot(span),
406 Node::CharacterClass(span, class) => {
407 self.visit_character_class(span, class);
408 self._visit_character_class(span, class);
409 }
410 Node::Group(span, group) => {
411 self.visit_group(span, group);
412 self._visit_group(span, group)
413 }
414
415 Node::Quantifier(span, node, kind, lazy) => {
416 self.visit_quantifier(span, node, kind, lazy);
417 self._visit_quantifier(span, node, kind, lazy);
418 }
419 Node::NamedBackReference(span, backreference) => {
420 self.visit_named_backreference(span, backreference)
421 }
422 }
423 }
424
425 #[doc(hidden)]
426 fn _visit_disjunction(&mut self, span: &Span, nodes: &mut [Node]) {
427 for node in nodes {
428 self._visit_node(node);
429 }
430 }
431
432 #[doc(hidden)]
433 fn _visit_assertion(&mut self, span: &Span, kind: &mut AssertionKind) {
434 match kind {
435 AssertionKind::Lookahead(node)
436 | AssertionKind::Lookbehind(node)
437 | AssertionKind::NegativeLookahead(node)
438 | AssertionKind::NegativeLookbehind(node) => self._visit_node(node),
439 _ => {}
440 }
441 }
442
443 #[doc(hidden)]
444 fn _visit_alternative(&mut self, span: &Span, nodes: &mut [Node]) {
445 for node in nodes {
446 self.visit_node(node);
447 self._visit_node(node);
448 }
449 }
450
451 #[doc(hidden)]
452 fn _visit_character_class(&mut self, span: &Span, class: &mut CharacterClass) {
453 for member in &mut class.members {
454 match member {
455 CharacterClassMember::Range(l, r) => {
456 self.visit_node(l);
457 self._visit_node(l);
458 self.visit_node(r);
459 self._visit_node(r);
460 }
461 CharacterClassMember::Single(n) => {
462 self.visit_node(n);
463 self._visit_node(n)
464 }
465 }
466 }
467 }
468
469 #[doc(hidden)]
470 fn _visit_group(&mut self, span: &Span, group: &mut Group) {
471 self.visit_node(&mut group.inner);
472 self._visit_node(&mut group.inner)
473 }
474
475 #[doc(hidden)]
476 fn _visit_quantifier(
477 &mut self,
478 span: &Span,
479 node: &mut Node,
480 kind: &mut QuantifierKind,
481 lazy: &mut bool,
482 ) {
483 self.visit_node(node);
484 self._visit_node(node);
485 }
486
487 fn visit_regex(&mut self, regex: &mut Regex) {
488 self.visit_node(&mut regex.node);
489 self._visit_node(&mut regex.node);
490 }
491 fn visit_named_backreference(&mut self, span: &Span, backreference: &mut str) {}
492 fn visit_alternative(&mut self, span: &Span, nodes: &mut [Node]) {}
493 fn visit_literal(&mut self, span: &Span, literal: &mut char) {}
494 fn visit_perl_class(&mut self, span: &Span, kind: &mut ClassPerlKind, negated: &mut bool) {}
495 fn visit_backreference(&mut self, span: &Span, reference: &mut u32) {}
496 fn visit_dot(&mut self, span: &Span) {}
497 fn visit_node(&mut self, node: &mut Node) {}
498 fn visit_empty_node(&mut self) {}
499 fn visit_group(&mut self, span: &Span, group: &mut Group) {}
500 fn visit_quantifier(
501 &mut self,
502 span: &Span,
503 node: &mut Node,
504 kind: &mut QuantifierKind,
505 lazy: &mut bool,
506 ) {
507 }
508 fn visit_character_class(&mut self, span: &Span, class: &mut CharacterClass) {}
509 fn visit_assertion(&mut self, span: &Span, kind: &mut AssertionKind) {}
510}