regast-core 0.1.0

Parse-tree matching backends for regast
Documentation
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,
        }
    }
}