regast-syntax 0.1.0

Lossless syntax tree for the regast regular expression engine
Documentation
use std::sync::Arc;

use serde::{Deserialize, Serialize};

use crate::{ClassItem, ClassSet, Cursor, NodeId, ParseError, Span};

#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct Node {
    pub kind: AstKind,
    pub span: Span,
    pub parent: Option<NodeId>,
}

#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum AstKind {
    Empty,
    Anchor {
        kind: AnchorKind,
    },
    Literal {
        c: char,
        escaped: bool,
    },
    Dot,
    Class {
        negated: bool,
        items: Vec<ClassItem>,
        set: ClassSet,
    },
    Group {
        kind: GroupKind,
        inner: NodeId,
    },
    Alt {
        arms: Vec<NodeId>,
    },
    Concat {
        parts: Vec<NodeId>,
    },
    Repeat {
        inner: NodeId,
        kind: RepKind,
        greedy: bool,
    },
}

impl AstKind {
    #[must_use]
    pub fn children(&self) -> &[NodeId] {
        match self {
            Self::Group { inner, .. } | Self::Repeat { inner, .. } => std::slice::from_ref(inner),
            Self::Alt { arms } => arms,
            Self::Concat { parts } => parts,
            Self::Empty
            | Self::Anchor { .. }
            | Self::Literal { .. }
            | Self::Dot
            | Self::Class { .. } => &[],
        }
    }
}

#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum AnchorKind {
    Start,
    End,
}

#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(tag = "kind", rename_all = "snake_case")]
pub enum GroupKind {
    Capture { index: u32, name: Option<Box<str>> },
    NonCapture,
}

#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(tag = "kind", rename_all = "snake_case")]
pub enum RepKind {
    ZeroOrOne,
    ZeroOrMore,
    OneOrMore,
    Range { min: u32, max: Option<u32> },
}

#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct GroupInfo {
    pub index: u32,
    pub name: Option<Box<str>>,
    pub node: NodeId,
}

/// An immutable, lossless pattern syntax tree backed by a flat arena.
#[derive(Clone, Debug)]
pub struct Pattern {
    pub(crate) src: Arc<str>,
    pub(crate) nodes: Vec<Node>,
    pub(crate) groups: Vec<GroupInfo>,
    pub(crate) root: NodeId,
}

impl Pattern {
    /// Parse a pattern into its lossless syntax tree.
    ///
    /// # Errors
    ///
    /// Returns [`ParseError`] when `src` is malformed or uses an unsupported feature.
    pub fn parse(src: &str) -> Result<Self, ParseError> {
        crate::parse(src)
    }

    #[must_use]
    pub fn source(&self) -> &str {
        &self.src
    }

    #[must_use]
    pub const fn root_id(&self) -> NodeId {
        self.root
    }

    #[must_use]
    pub fn root(&self) -> Cursor<'_> {
        Cursor::new(self, self.root)
    }

    #[must_use]
    pub fn node(&self, id: NodeId) -> &Node {
        &self.nodes[id.0 as usize]
    }

    #[must_use]
    pub fn nodes(&self) -> &[Node] {
        &self.nodes
    }

    #[must_use]
    pub fn groups(&self) -> &[GroupInfo] {
        &self.groups
    }

    #[must_use]
    pub fn len(&self) -> usize {
        self.nodes.len()
    }

    #[must_use]
    pub fn is_empty(&self) -> bool {
        self.nodes.is_empty()
    }

    #[must_use]
    pub fn text(&self, span: Span) -> &str {
        &self.src[span.start as usize..span.end as usize]
    }
}