pomsky/exprs/
lookaround.rs

1use pomsky_syntax::exprs::{Lookaround, LookaroundKind};
2
3use crate::{
4    compile::{CompileResult, CompileState},
5    diagnose::{CompatWarning, CompileErrorKind, CompileWarningKind},
6    options::{CompileOptions, RegexFlavor},
7    regex::Regex,
8};
9
10use super::RuleExt;
11
12impl<'i> RuleExt<'i> for Lookaround<'i> {
13    fn compile<'c>(
14        &'c self,
15        options: CompileOptions,
16        state: &mut CompileState<'c, 'i>,
17    ) -> CompileResult<'i> {
18        match options.flavor {
19            RegexFlavor::JavaScript => {
20                if let LookaroundKind::Behind | LookaroundKind::BehindNegative = self.kind {
21                    state.diagnostics.push(
22                        CompileWarningKind::Compat(CompatWarning::JsLookbehind)
23                            .at(self.span)
24                            .diagnostic(),
25                    );
26                }
27            }
28            RegexFlavor::Ruby if state.in_lookbehind => {
29                if let LookaroundKind::Ahead | LookaroundKind::AheadNegative = self.kind {
30                    return Err(CompileErrorKind::RubyLookaheadInLookbehind {
31                        was_word_boundary: false,
32                    }
33                    .at(self.span));
34                }
35            }
36            _ => (),
37        }
38
39        revert_on_drop!(state.in_lookbehind);
40        if let LookaroundKind::Behind | LookaroundKind::BehindNegative = self.kind {
41            state.in_lookbehind = true;
42        }
43
44        Ok(Regex::Lookaround(Box::new(RegexLookaround {
45            content: self.rule.compile(options, &mut state)?,
46            kind: self.kind,
47        })))
48    }
49}
50
51#[cfg_attr(feature = "dbg", derive(Debug))]
52pub(crate) struct RegexLookaround<'i> {
53    pub(crate) content: Regex<'i>,
54    pub(crate) kind: LookaroundKind,
55}
56
57impl<'i> RegexLookaround<'i> {
58    pub(crate) fn codegen(&self, buf: &mut String, flavor: RegexFlavor) {
59        buf.push_str(match self.kind {
60            LookaroundKind::Ahead => "(?=",
61            LookaroundKind::Behind => "(?<=",
62            LookaroundKind::AheadNegative => "(?!",
63            LookaroundKind::BehindNegative => "(?<!",
64        });
65        self.content.codegen(buf, flavor);
66        buf.push(')');
67    }
68}