use seq_core::seqstring::global_string;
use seq_core::stack::{Stack, pop, push};
use seq_core::value::{Value, VariantData};
use regex::Regex;
use std::sync::Arc;
fn make_list(items: Vec<Value>) -> Value {
Value::Variant(Arc::new(VariantData::new(
global_string("List".to_string()),
items,
)))
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn patch_seq_regex_match(stack: Stack) -> Stack {
assert!(!stack.is_null(), "regex.match?: stack is empty");
let (stack, pattern_val) = unsafe { pop(stack) };
let (stack, text_val) = unsafe { pop(stack) };
match (text_val, pattern_val) {
(Value::String(text), Value::String(pattern)) => {
let result = match Regex::new(pattern.as_str()) {
Ok(re) => re.is_match(text.as_str()),
Err(_) => false, };
unsafe { push(stack, Value::Bool(result)) }
}
_ => panic!("regex.match?: expected two Strings on stack"),
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn patch_seq_regex_find(stack: Stack) -> Stack {
assert!(!stack.is_null(), "regex.find: stack is empty");
let (stack, pattern_val) = unsafe { pop(stack) };
let (stack, text_val) = unsafe { pop(stack) };
match (text_val, pattern_val) {
(Value::String(text), Value::String(pattern)) => {
match Regex::new(pattern.as_str()) {
Ok(re) => match re.find(text.as_str()) {
Some(m) => {
let stack = unsafe {
push(stack, Value::String(global_string(m.as_str().to_string())))
};
unsafe { push(stack, Value::Bool(true)) }
}
None => {
let stack =
unsafe { push(stack, Value::String(global_string(String::new()))) };
unsafe { push(stack, Value::Bool(false)) }
}
},
Err(_) => {
let stack = unsafe { push(stack, Value::String(global_string(String::new()))) };
unsafe { push(stack, Value::Bool(false)) }
}
}
}
_ => panic!("regex.find: expected two Strings on stack"),
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn patch_seq_regex_find_all(stack: Stack) -> Stack {
assert!(!stack.is_null(), "regex.find-all: stack is empty");
let (stack, pattern_val) = unsafe { pop(stack) };
let (stack, text_val) = unsafe { pop(stack) };
match (text_val, pattern_val) {
(Value::String(text), Value::String(pattern)) => match Regex::new(pattern.as_str()) {
Ok(re) => {
let matches: Vec<Value> = re
.find_iter(text.as_str())
.map(|m| Value::String(global_string(m.as_str().to_string())))
.collect();
let stack = unsafe { push(stack, make_list(matches)) };
unsafe { push(stack, Value::Bool(true)) }
}
Err(_) => {
let stack = unsafe { push(stack, make_list(vec![])) };
unsafe { push(stack, Value::Bool(false)) }
}
},
_ => panic!("regex.find-all: expected two Strings on stack"),
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn patch_seq_regex_replace(stack: Stack) -> Stack {
assert!(!stack.is_null(), "regex.replace: stack is empty");
let (stack, replacement_val) = unsafe { pop(stack) };
let (stack, pattern_val) = unsafe { pop(stack) };
let (stack, text_val) = unsafe { pop(stack) };
match (text_val, pattern_val, replacement_val) {
(Value::String(text), Value::String(pattern), Value::String(replacement)) => {
match Regex::new(pattern.as_str()) {
Ok(re) => {
let result = re.replace(text.as_str(), replacement.as_str()).into_owned();
let stack = unsafe { push(stack, Value::String(global_string(result))) };
unsafe { push(stack, Value::Bool(true)) }
}
Err(_) => {
let stack = unsafe {
push(
stack,
Value::String(global_string(text.as_str().to_string())),
)
};
unsafe { push(stack, Value::Bool(false)) }
}
}
}
_ => panic!("regex.replace: expected three Strings on stack"),
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn patch_seq_regex_replace_all(stack: Stack) -> Stack {
assert!(!stack.is_null(), "regex.replace-all: stack is empty");
let (stack, replacement_val) = unsafe { pop(stack) };
let (stack, pattern_val) = unsafe { pop(stack) };
let (stack, text_val) = unsafe { pop(stack) };
match (text_val, pattern_val, replacement_val) {
(Value::String(text), Value::String(pattern), Value::String(replacement)) => {
match Regex::new(pattern.as_str()) {
Ok(re) => {
let result = re
.replace_all(text.as_str(), replacement.as_str())
.into_owned();
let stack = unsafe { push(stack, Value::String(global_string(result))) };
unsafe { push(stack, Value::Bool(true)) }
}
Err(_) => {
let stack = unsafe {
push(
stack,
Value::String(global_string(text.as_str().to_string())),
)
};
unsafe { push(stack, Value::Bool(false)) }
}
}
}
_ => panic!("regex.replace-all: expected three Strings on stack"),
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn patch_seq_regex_captures(stack: Stack) -> Stack {
assert!(!stack.is_null(), "regex.captures: stack is empty");
let (stack, pattern_val) = unsafe { pop(stack) };
let (stack, text_val) = unsafe { pop(stack) };
match (text_val, pattern_val) {
(Value::String(text), Value::String(pattern)) => {
match Regex::new(pattern.as_str()) {
Ok(re) => match re.captures(text.as_str()) {
Some(caps) => {
let groups: Vec<Value> = caps
.iter()
.skip(1)
.map(|m| match m {
Some(m) => Value::String(global_string(m.as_str().to_string())),
None => Value::String(global_string(String::new())),
})
.collect();
let stack = unsafe { push(stack, make_list(groups)) };
unsafe { push(stack, Value::Bool(true)) }
}
None => {
let stack = unsafe { push(stack, make_list(vec![])) };
unsafe { push(stack, Value::Bool(false)) }
}
},
Err(_) => {
let stack = unsafe { push(stack, make_list(vec![])) };
unsafe { push(stack, Value::Bool(false)) }
}
}
}
_ => panic!("regex.captures: expected two Strings on stack"),
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn patch_seq_regex_split(stack: Stack) -> Stack {
assert!(!stack.is_null(), "regex.split: stack is empty");
let (stack, pattern_val) = unsafe { pop(stack) };
let (stack, text_val) = unsafe { pop(stack) };
match (text_val, pattern_val) {
(Value::String(text), Value::String(pattern)) => match Regex::new(pattern.as_str()) {
Ok(re) => {
let parts: Vec<Value> = re
.split(text.as_str())
.map(|s| Value::String(global_string(s.to_string())))
.collect();
let stack = unsafe { push(stack, make_list(parts)) };
unsafe { push(stack, Value::Bool(true)) }
}
Err(_) => {
let parts = vec![Value::String(global_string(text.as_str().to_string()))];
let stack = unsafe { push(stack, make_list(parts)) };
unsafe { push(stack, Value::Bool(false)) }
}
},
_ => panic!("regex.split: expected two Strings on stack"),
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn patch_seq_regex_valid(stack: Stack) -> Stack {
assert!(!stack.is_null(), "regex.valid?: stack is empty");
let (stack, pattern_val) = unsafe { pop(stack) };
match pattern_val {
Value::String(pattern) => {
let is_valid = Regex::new(pattern.as_str()).is_ok();
unsafe { push(stack, Value::Bool(is_valid)) }
}
_ => panic!("regex.valid?: expected String on stack"),
}
}
#[cfg(test)]
mod tests;