rulex/
lookaround.rs

1use std::collections::HashMap;
2
3use crate::{
4    compile::{CompileResult, CompileState},
5    error::{CompileError, CompileErrorKind, Feature, ParseError, ParseErrorKind},
6    features::RulexFeatures,
7    options::{CompileOptions, ParseOptions, RegexFlavor},
8    regex::Regex,
9    rule::Rule,
10    span::Span,
11};
12
13#[derive(Clone)]
14pub(crate) struct Lookaround<'i> {
15    kind: LookaroundKind,
16    rule: Rule<'i>,
17    pub(crate) span: Span,
18}
19
20#[cfg(feature = "dbg")]
21impl core::fmt::Debug for Lookaround<'_> {
22    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
23        f.write_str("Lookaround ")?;
24        f.write_str(match self.kind {
25            LookaroundKind::Ahead => ">> ",
26            LookaroundKind::Behind => "<< ",
27            LookaroundKind::AheadNegative => "!>> ",
28            LookaroundKind::BehindNegative => "!<< ",
29        })?;
30        self.rule.fmt(f)
31    }
32}
33
34#[derive(Clone, Copy, PartialEq, Eq)]
35#[cfg_attr(feature = "dbg", derive(Debug))]
36pub(crate) enum LookaroundKind {
37    Ahead,
38    Behind,
39    AheadNegative,
40    BehindNegative,
41}
42
43impl<'i> Lookaround<'i> {
44    pub(crate) fn get_capturing_groups(
45        &self,
46        count: &mut u32,
47        map: &'i mut HashMap<String, u32>,
48        within_variable: bool,
49    ) -> Result<(), CompileError> {
50        self.rule.get_capturing_groups(count, map, within_variable)
51    }
52
53    pub(crate) fn new(rule: Rule<'i>, kind: LookaroundKind, span: Span) -> Self {
54        Lookaround { rule, kind, span }
55    }
56
57    pub(crate) fn negate(&mut self) -> Result<(), ParseErrorKind> {
58        match self.kind {
59            LookaroundKind::AheadNegative | LookaroundKind::BehindNegative => {
60                Err(ParseErrorKind::UnallowedDoubleNot)
61            }
62            LookaroundKind::Ahead => {
63                self.kind = LookaroundKind::AheadNegative;
64                Ok(())
65            }
66            LookaroundKind::Behind => {
67                self.kind = LookaroundKind::BehindNegative;
68                Ok(())
69            }
70        }
71    }
72
73    pub(crate) fn compile<'c>(
74        &'c self,
75        options: CompileOptions,
76        state: &mut CompileState<'c, 'i>,
77    ) -> CompileResult<'i> {
78        if options.flavor == RegexFlavor::Rust {
79            return Err(
80                CompileErrorKind::Unsupported(Feature::Lookaround, options.flavor).at(self.span)
81            );
82        }
83
84        Ok(Regex::Lookaround(Box::new(RegexLookaround {
85            content: self.rule.comp(options, state)?,
86            kind: self.kind,
87        })))
88    }
89
90    pub(crate) fn validate(&self, options: &ParseOptions) -> Result<(), ParseError> {
91        let feature = match self.kind {
92            LookaroundKind::Ahead => RulexFeatures::LOOKAHEAD,
93            LookaroundKind::Behind => RulexFeatures::LOOKBEHIND,
94            LookaroundKind::AheadNegative => RulexFeatures::LOOKAHEAD,
95            LookaroundKind::BehindNegative => RulexFeatures::LOOKBEHIND,
96        };
97        options.allowed_features.require(feature, self.span)
98    }
99}
100
101#[cfg_attr(feature = "dbg", derive(Debug))]
102pub(crate) struct RegexLookaround<'i> {
103    content: Regex<'i>,
104    kind: LookaroundKind,
105}
106
107impl<'i> RegexLookaround<'i> {
108    pub(crate) fn codegen(&self, buf: &mut String, flavor: RegexFlavor) {
109        buf.push_str(match self.kind {
110            LookaroundKind::Ahead => "(?=",
111            LookaroundKind::Behind => "(?<=",
112            LookaroundKind::AheadNegative => "(?!",
113            LookaroundKind::BehindNegative => "(?<!",
114        });
115        self.content.codegen(buf, flavor);
116        buf.push(')');
117    }
118}