pd-vm 0.22.5

RustScript bytecode compiler and VM
Documentation
use regex::Regex;

use super::VmArray;
use crate::vm::{Value, VmError, VmResult};
use pd_host_function::pd_host_function;

/// Returns whether a regular expression matches the input text.
#[pd_host_function(name = "re::match")]
pub(super) fn builtin_re_match(pattern: &str, text: &str) -> VmResult<bool> {
    let regex = Regex::new(pattern)
        .map_err(|err| VmError::HostError(format!("re_match invalid pattern: {err}")))?;
    Ok(regex.is_match(text))
}

/// Returns the first substring matched by a regular expression.
#[pd_host_function(name = "re::find")]
pub(super) fn builtin_re_find(pattern: &str, text: &str) -> VmResult<Option<String>> {
    let regex = Regex::new(pattern)
        .map_err(|err| VmError::HostError(format!("re_find invalid pattern: {err}")))?;
    Ok(regex.find(text).map(|matched| matched.as_str().to_string()))
}

/// Replaces all regular-expression matches in a string.
#[pd_host_function(name = "re::replace")]
pub(super) fn builtin_re_replace(pattern: &str, text: &str, replacement: &str) -> VmResult<String> {
    let regex = Regex::new(pattern)
        .map_err(|err| VmError::HostError(format!("re_replace invalid pattern: {err}")))?;
    Ok(regex.replace_all(text, replacement).into_owned())
}

/// Splits a string on regular-expression matches.
#[pd_host_function(name = "re::split")]
pub(super) fn builtin_re_split(pattern: &str, text: &str) -> VmResult<VmArray> {
    let regex = Regex::new(pattern)
        .map_err(|err| VmError::HostError(format!("re_split invalid pattern: {err}")))?;
    Ok(regex
        .split(text)
        .map(|part| Value::string(part.to_string()))
        .collect::<Vec<_>>())
}

/// Returns the capture groups produced by the first regular-expression match.
#[pd_host_function(name = "re::captures")]
pub(super) fn builtin_re_captures(pattern: &str, text: &str) -> VmResult<VmArray> {
    let regex = Regex::new(pattern)
        .map_err(|err| VmError::HostError(format!("re_captures invalid pattern: {err}")))?;
    let Some(captures) = regex.captures(text) else {
        return Ok(Vec::new());
    };

    let mut groups = Vec::with_capacity(captures.len());
    for index in 0..captures.len() {
        let group_value = match captures.get(index) {
            Some(group) => Value::string(group.as_str().to_string()),
            None => Value::Null,
        };
        groups.push(group_value);
    }
    Ok(groups)
}