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()
}
}