rulex 0.4.4

DEPRECATED: Use pomsky instead. A new regular expression language
Documentation
use std::collections::HashMap;

use crate::{
    compile::{CompileResult, CompileState},
    error::{CompileError, CompileErrorKind, Feature, ParseError, ParseErrorKind},
    features::RulexFeatures,
    options::{CompileOptions, ParseOptions, RegexFlavor},
    regex::Regex,
    rule::Rule,
    span::Span,
};

#[derive(Clone)]
pub(crate) struct Lookaround<'i> {
    kind: LookaroundKind,
    rule: Rule<'i>,
    pub(crate) span: Span,
}

#[cfg(feature = "dbg")]
impl core::fmt::Debug for Lookaround<'_> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.write_str("Lookaround ")?;
        f.write_str(match self.kind {
            LookaroundKind::Ahead => ">> ",
            LookaroundKind::Behind => "<< ",
            LookaroundKind::AheadNegative => "!>> ",
            LookaroundKind::BehindNegative => "!<< ",
        })?;
        self.rule.fmt(f)
    }
}

#[derive(Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "dbg", derive(Debug))]
pub(crate) enum LookaroundKind {
    Ahead,
    Behind,
    AheadNegative,
    BehindNegative,
}

impl<'i> Lookaround<'i> {
    pub(crate) fn get_capturing_groups(
        &self,
        count: &mut u32,
        map: &'i mut HashMap<String, u32>,
        within_variable: bool,
    ) -> Result<(), CompileError> {
        self.rule.get_capturing_groups(count, map, within_variable)
    }

    pub(crate) fn new(rule: Rule<'i>, kind: LookaroundKind, span: Span) -> Self {
        Lookaround { rule, kind, span }
    }

    pub(crate) fn negate(&mut self) -> Result<(), ParseErrorKind> {
        match self.kind {
            LookaroundKind::AheadNegative | LookaroundKind::BehindNegative => {
                Err(ParseErrorKind::UnallowedDoubleNot)
            }
            LookaroundKind::Ahead => {
                self.kind = LookaroundKind::AheadNegative;
                Ok(())
            }
            LookaroundKind::Behind => {
                self.kind = LookaroundKind::BehindNegative;
                Ok(())
            }
        }
    }

    pub(crate) fn compile<'c>(
        &'c self,
        options: CompileOptions,
        state: &mut CompileState<'c, 'i>,
    ) -> CompileResult<'i> {
        if options.flavor == RegexFlavor::Rust {
            return Err(
                CompileErrorKind::Unsupported(Feature::Lookaround, options.flavor).at(self.span)
            );
        }

        Ok(Regex::Lookaround(Box::new(RegexLookaround {
            content: self.rule.comp(options, state)?,
            kind: self.kind,
        })))
    }

    pub(crate) fn validate(&self, options: &ParseOptions) -> Result<(), ParseError> {
        let feature = match self.kind {
            LookaroundKind::Ahead => RulexFeatures::LOOKAHEAD,
            LookaroundKind::Behind => RulexFeatures::LOOKBEHIND,
            LookaroundKind::AheadNegative => RulexFeatures::LOOKAHEAD,
            LookaroundKind::BehindNegative => RulexFeatures::LOOKBEHIND,
        };
        options.allowed_features.require(feature, self.span)
    }
}

#[cfg_attr(feature = "dbg", derive(Debug))]
pub(crate) struct RegexLookaround<'i> {
    content: Regex<'i>,
    kind: LookaroundKind,
}

impl<'i> RegexLookaround<'i> {
    pub(crate) fn codegen(&self, buf: &mut String, flavor: RegexFlavor) {
        buf.push_str(match self.kind {
            LookaroundKind::Ahead => "(?=",
            LookaroundKind::Behind => "(?<=",
            LookaroundKind::AheadNegative => "(?!",
            LookaroundKind::BehindNegative => "(?<!",
        });
        self.content.codegen(buf, flavor);
        buf.push(')');
    }
}