use crate::regcomp::{
SIZE_INC, add_op, compile_cclass_node, compile_length_cclass_node, compile_length_tree,
compile_tree, detect_cclass_ascii_fast,
};
use crate::regint::*;
use crate::regparse_types::*;
fn possessive_ascii_class_repeat(bag: &BagNode, status: u32) -> Option<&CClassNode> {
if status & ND_ST_POSSESSIVE_CLASS_REPEAT == 0 || bag.bag_type != BagType::StopBacktrack {
return None;
}
let NodeInner::Quant(q) = &bag.body.as_deref()?.inner else {
return None;
};
if !q.greedy || q.lower != 1 || !is_infinite_repeat(q.upper) {
return None;
}
let NodeInner::CClass(class) = &q.body.as_deref()?.inner else {
return None;
};
(!class.is_not()
&& class.mbuf.is_none()
&& (128..SINGLE_BYTE_SIZE).all(|byte| !bitset_at(&class.bs, byte)))
.then_some(class)
}
fn decimal_tail_prefix(bag: &BagNode, status: u32) -> Option<(&Node, &Node)> {
if status & ND_ST_DECIMAL_TAIL_PREFIX == 0 || bag.bag_type != BagType::StopBacktrack {
return None;
}
super::ast::deterministic_tail_parts(bag.body.as_deref()?)
}
pub(crate) fn compile_length(
bag: &BagNode,
node_status: u32,
reg: &RegexType,
env: &ParseEnv,
) -> Option<i32> {
if let Some((_, tail)) = decimal_tail_prefix(bag, node_status) {
let tail_len = compile_length_tree(tail, reg, env);
return Some(if tail_len < 0 {
tail_len
} else {
SIZE_INC + tail_len
});
}
if let Some(class) = possessive_ascii_class_repeat(bag, node_status) {
return Some(compile_length_cclass_node(class, reg) + SIZE_INC);
}
None
}
pub(crate) fn compile(
bag: &BagNode,
node_status: u32,
reg: &mut RegexType,
env: &ParseEnv,
) -> Option<i32> {
if let Some((mut body, tail)) = decimal_tail_prefix(bag, node_status) {
let mut captures = Vec::new();
while let NodeInner::Bag(memory) = &body.inner {
let BagData::Memory { regnum, .. } = memory.bag_data else {
unreachable!("decimal prefix admits only memory wrappers");
};
captures.push(regnum);
body = memory.body.as_deref().expect("checked decimal prefix body");
}
add_op(
reg,
OpCode::DecimalTailPrefix,
OperationPayload::DecimalTailPrefix { captures },
);
return Some(compile_tree(tail, reg, env));
}
if let Some(class) = possessive_ascii_class_repeat(bag, node_status) {
let result = compile_cclass_node(class, reg);
if result != 0 {
return Some(result);
}
add_op(
reg,
OpCode::CClassPossessiveStar,
OperationPayload::CClass {
bsp: Box::new(class.bs),
ascii_fast: detect_cclass_ascii_fast(&class.bs),
},
);
return Some(0);
}
None
}