online_dsl_forge/runtime/
context.rs1use regex::Regex;
2
3use crate::parser::SourceSpan;
4use crate::sema::{CompiledRegexCache, RegexFlavor, RegexPolicy, SecurityProfile};
5
6use super::EvalError;
7
8#[derive(Clone, Copy)]
9pub struct RuntimeCallContext<'a> {
10 profile: &'a SecurityProfile,
11 regex_cache: &'a CompiledRegexCache,
12 span: SourceSpan,
13}
14
15impl<'a> RuntimeCallContext<'a> {
16 pub(crate) fn new(
17 profile: &'a SecurityProfile,
18 regex_cache: &'a CompiledRegexCache,
19 span: SourceSpan,
20 ) -> Self {
21 Self {
22 profile,
23 regex_cache,
24 span,
25 }
26 }
27
28 pub fn profile(&self) -> &'a SecurityProfile {
29 self.profile
30 }
31
32 pub fn regex_policy(&self) -> RegexPolicy {
33 self.profile.default_regex_policy
34 }
35
36 pub fn regex_cache(&self) -> &'a CompiledRegexCache {
37 self.regex_cache
38 }
39
40 pub fn span(&self) -> SourceSpan {
41 self.span
42 }
43
44 pub fn precompiled_regex(&self, flavor: RegexFlavor, pattern: &str) -> Option<&'a Regex> {
45 self.regex_cache.get(flavor, pattern)
46 }
47
48 pub fn require_precompiled_regex(
49 &self,
50 flavor: RegexFlavor,
51 pattern: &str,
52 ) -> Result<&'a Regex, EvalError> {
53 self.precompiled_regex(flavor, pattern).ok_or_else(|| {
54 EvalError::new(
55 format!(
56 "precompiled {} regex is missing",
57 regex_flavor_label(flavor)
58 ),
59 self.span,
60 )
61 })
62 }
63
64 pub fn precompiled_regex_is_match(
65 &self,
66 flavor: RegexFlavor,
67 pattern: &str,
68 haystack: &str,
69 ) -> Result<bool, EvalError> {
70 self
71 .require_precompiled_regex(flavor, pattern)
72 .map(|regex| regex.is_match(haystack))
73 }
74}
75
76fn regex_flavor_label(flavor: RegexFlavor) -> &'static str {
77 match flavor {
78 RegexFlavor::Default => "default",
79 RegexFlavor::HeaderName => "header_name",
80 }
81}