utterance 0.1.2

A parser library for creating readable, natural-language-inspired domain-specific languages.
Documentation
use std::cell::OnceCell;
use std::fmt;
use std::rc::Rc;

use crate::lexer::{Punctuation, Symbol};
use crate::parser::expectation::StatementKind;
use crate::parser::tree::{Child, ParseContext, ParseTree, noop_fn};

pub struct ParseTreeFactory<C>
where
    C: ParseContext,
{
    comments: OnceCell<Rc<ParseTree<C>>>,
    line_terminator: OnceCell<Rc<ParseTree<C>>>,
    statement_terminator: OnceCell<Rc<ParseTree<C>>>,
}

impl<C> ParseTreeFactory<C>
where
    C: ParseContext,
{
    pub fn new() -> Rc<Self> {
        let factory = Rc::new(Self {
            comments: OnceCell::new(),
            line_terminator: OnceCell::new(),
            statement_terminator: OnceCell::new(),
        });

        let line_terminator = Rc::new(ParseTree::new_from_children(
            Rc::clone(&factory),
            StatementKind::NewLineOrEnd,
            vec![],
            noop_fn,
        ));

        let _ = factory.line_terminator.set(Rc::clone(&line_terminator));

        let comments = Rc::new(ParseTree::new_from_children(
            Rc::clone(&factory),
            StatementKind::Comment,
            vec![Child::ByRef(Rc::clone(&line_terminator))],
            noop_fn,
        ));

        let _ = factory.comments.set(Rc::clone(&comments));

        let statement_terminator = Rc::new(ParseTree::new_from_children(
            Rc::clone(&factory),
            StatementKind::Symbol(Symbol::Punctuation(Punctuation::Point)),
            vec![
                Child::ByRef(Rc::clone(&comments)),
                Child::ByRef(Rc::clone(&line_terminator)),
            ],
            noop_fn,
        ));

        let _ = factory
            .statement_terminator
            .set(Rc::clone(&statement_terminator));

        factory
    }

    pub fn comments(&self) -> Rc<ParseTree<C>> {
        Rc::clone(self.comments.get().unwrap())
    }

    pub fn line_terminator(&self) -> Rc<ParseTree<C>> {
        Rc::clone(self.line_terminator.get().unwrap())
    }

    pub fn statement_terminator(&self) -> Rc<ParseTree<C>> {
        Rc::clone(self.statement_terminator.get().unwrap())
    }
}

impl<C> fmt::Debug for ParseTreeFactory<C>
where
    C: ParseContext,
{
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("ParseTreeFactory")
            .field("comments", &self.comments.get().map(|_| "<initialized>"))
            .field(
                "line_terminator",
                &self.line_terminator.get().map(|_| "<initialized>"),
            )
            .field(
                "statement_terminator",
                &self.statement_terminator.get().map(|_| "<initialized>"),
            )
            .finish()
    }
}