pomsky/exprs/
lookaround.rs1use 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}