use crate::{IrId, IrKind, IrPool};
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Value {
Empty,
Char(char),
Seq(Box<Self>, Box<Self>),
Left(Box<Self>),
Right(Box<Self>),
Stars(Vec<Self>),
}
impl Value {
#[must_use]
pub(crate) fn byte_len(&self) -> usize {
match self {
Self::Empty => 0,
Self::Char(c) => c.len_utf8(),
Self::Seq(left, right) => left.byte_len() + right.byte_len(),
Self::Left(value) | Self::Right(value) => value.byte_len(),
Self::Stars(values) => values.iter().map(Self::byte_len).sum(),
}
}
#[must_use]
pub fn flatten(&self) -> String {
let mut output = String::new();
self.flatten_into(&mut output);
output
}
pub fn flatten_into(&self, output: &mut String) {
match self {
Self::Empty => {}
Self::Char(c) => output.push(*c),
Self::Seq(left, right) => {
left.flatten_into(output);
right.flatten_into(output);
}
Self::Left(value) | Self::Right(value) => value.flatten_into(output),
Self::Stars(values) => {
for value in values {
value.flatten_into(output);
}
}
}
}
#[must_use]
pub fn typed_by(&self, pool: &IrPool, root: IrId) -> bool {
match (self, pool.kind(root)) {
(Self::Empty, IrKind::One | IrKind::Anchor(..)) => true,
(Self::Char(c), IrKind::Class(set, _)) => pool.get_class_set(*set).contains(*c),
(Self::Seq(left_value, right_value), IrKind::Seq(left, right, _)) => {
left_value.typed_by(pool, *left) && right_value.typed_by(pool, *right)
}
(Self::Left(value), IrKind::Alt(left, _, _, _)) => value.typed_by(pool, *left),
(Self::Right(value), IrKind::Alt(_, right, _, _)) => value.typed_by(pool, *right),
(Self::Stars(values), IrKind::Star(inner, _, _)) => {
values.iter().all(|value| value.typed_by(pool, *inner))
}
_ => false,
}
}
}