online-dsl-forge 0.3.3

A bounded parser and runtime for in-memory DSL expressions.
Documentation
use regex::Regex;

use crate::parser::SourceSpan;
use crate::sema::{CompiledRegexCache, RegexFlavor, RegexPolicy, SecurityProfile};

use super::EvalError;

#[derive(Clone, Copy)]
pub struct RuntimeCallContext<'a> {
  profile: &'a SecurityProfile,
  regex_cache: &'a CompiledRegexCache,
  span: SourceSpan,
}

impl<'a> RuntimeCallContext<'a> {
  pub(crate) fn new(
    profile: &'a SecurityProfile,
    regex_cache: &'a CompiledRegexCache,
    span: SourceSpan,
  ) -> Self {
    Self {
      profile,
      regex_cache,
      span,
    }
  }

  pub fn profile(&self) -> &'a SecurityProfile {
    self.profile
  }

  pub fn regex_policy(&self) -> RegexPolicy {
    self.profile.default_regex_policy
  }

  pub fn regex_cache(&self) -> &'a CompiledRegexCache {
    self.regex_cache
  }

  pub fn span(&self) -> SourceSpan {
    self.span
  }

  pub fn precompiled_regex(&self, flavor: RegexFlavor, pattern: &str) -> Option<&'a Regex> {
    self.regex_cache.get(flavor, pattern)
  }

  pub fn require_precompiled_regex(
    &self,
    flavor: RegexFlavor,
    pattern: &str,
  ) -> Result<&'a Regex, EvalError> {
    self.precompiled_regex(flavor, pattern).ok_or_else(|| {
      EvalError::new(
        format!(
          "precompiled {} regex is missing",
          regex_flavor_label(flavor)
        ),
        self.span,
      )
    })
  }

  pub fn precompiled_regex_is_match(
    &self,
    flavor: RegexFlavor,
    pattern: &str,
    haystack: &str,
  ) -> Result<bool, EvalError> {
    self
      .require_precompiled_regex(flavor, pattern)
      .map(|regex| regex.is_match(haystack))
  }
}

fn regex_flavor_label(flavor: RegexFlavor) -> &'static str {
  match flavor {
    RegexFlavor::Default => "default",
    RegexFlavor::HeaderName => "header_name",
  }
}