use std::ptr::fn_addr_eq;
use std::rc::Rc;
use crate::lexer::Lexer;
use crate::parser::expectation::{Expectation, ExpectationError, Statement, StatementKind};
use crate::parser::tree::factory::ParseTreeFactory;
use crate::parser::tree::{Child, ParseContext};
use crate::parser::{CustomParseError, ParseError};
use crate::syntax::{Highlight, HighlightKind, Highlights};
pub fn noop_fn<C>(_: &mut C, _: &Statement) -> Result<(), CustomParseError>
where
C: ParseContext,
{
Ok(())
}
pub type TreeFn<T> = fn(&mut T, &Statement) -> Result<(), CustomParseError>;
#[derive(Debug, Clone)]
pub struct ParseTree<C>
where
C: ParseContext,
{
tree_factory: Rc<ParseTreeFactory<C>>,
statement_expectation: StatementKind,
function: TreeFn<C>,
children: Vec<Child<C>>,
}
impl<C> ParseTree<C>
where
C: ParseContext,
{
pub fn new(
tree_factory: Rc<ParseTreeFactory<C>>,
statement_expectation: StatementKind,
children: Vec<ParseTree<C>>,
function: TreeFn<C>,
) -> Self {
let children = children.into_iter().map(Child::Contains).collect();
Self::new_from_children(tree_factory, statement_expectation, children, function)
}
pub fn tree_factory(&self) -> Rc<ParseTreeFactory<C>> {
self.tree_factory.clone()
}
pub(crate) fn new_from_children(
tree_factory: Rc<ParseTreeFactory<C>>,
statement_expectation: StatementKind,
children: Vec<Child<C>>,
function: TreeFn<C>,
) -> Self {
Self {
tree_factory,
statement_expectation,
children,
function,
}
}
fn check<'a, const P: usize>(
&self,
lexer: &'a mut Lexer<P>,
) -> Result<Expectation<'a>, ExpectationError> {
self.statement_expectation.expect(lexer)
}
fn do_function(
&self,
context: &mut C,
statement: &Statement,
depth: usize,
) -> Result<(), ParseError> {
(self.function)(context, statement)
.map_err(|err| ParseError::custom(depth, err.to_string()))
}
pub(crate) fn try_match<const H: usize, const P: usize>(
&self,
lexer: &mut Lexer<P>,
highlights: &mut Highlights<H>,
context: &mut C,
depth: usize,
) -> Result<(), ParseError> {
let expectation = self
.check(lexer)
.map_err(|err| err.into_parse_error(depth))?;
if let Err(err) = self.do_function(context, expectation.statement(), depth) {
for span in expectation.span() {
highlights.push(Highlight::new(HighlightKind::Error, span));
}
return Err(err);
}
let highlight_kind = expectation.statement().highlight_kind();
for span in expectation.span() {
highlights.push(Highlight::new(highlight_kind, span));
}
Ok(())
}
pub fn expectation(&self) -> &StatementKind {
&self.statement_expectation
}
pub fn function(&self) -> &TreeFn<C> {
&self.function
}
pub(crate) fn is_end(&self) -> bool {
self.children.is_empty()
}
pub fn push_child(&mut self, child: ParseTree<C>) {
self.children.push(Child::Contains(child));
}
pub fn push_child_ref(&mut self, child: Rc<ParseTree<C>>) {
self.children.push(Child::ByRef(child));
}
pub fn push_child_to_leaves(&mut self, child: ParseTree<C>) {
if self.is_end() {
self.push_child(child);
return;
}
for c in self.children_mut() {
c.push_child_to_leaves(child.clone());
}
}
pub fn push_child_ref_to_leaves(&mut self, child: Rc<ParseTree<C>>) {
if self.is_end() {
self.push_child_ref(child);
return;
}
for c in self.children_mut() {
c.push_child_ref_to_leaves(child.clone());
}
}
pub fn push_child_to_leaves_mut(&mut self, child: ParseTree<C>) {
if self.children_mut().next().is_none() {
self.push_child(child);
return;
}
for c in self.children_mut() {
c.push_child_to_leaves_mut(child.clone());
}
}
pub fn push_child_ref_to_leaves_mut(&mut self, child: Rc<ParseTree<C>>) {
if self.children_mut().next().is_none() {
self.push_child_ref(child);
return;
}
for c in self.children_mut() {
c.push_child_ref_to_leaves_mut(child.clone());
}
}
pub(crate) fn set_children<I>(&mut self, children: I)
where
I: IntoIterator<Item = Child<C>>,
{
self.children = children.into_iter().collect();
}
pub(crate) fn children(&self) -> impl Iterator<Item = &ParseTree<C>> {
self.children.iter().map(|child| child.as_tree())
}
pub(crate) fn children_mut(&mut self) -> impl Iterator<Item = &mut ParseTree<C>> {
self.children
.iter_mut()
.filter_map(|child| child.as_tree_mut())
}
fn same_kind(&self, other: &Self) -> bool {
self.statement_expectation == other.statement_expectation
&& fn_addr_eq(self.function, other.function)
}
pub fn merge(&mut self, other: Self) {
if !self.same_kind(&other) {
*self = ParseTree::noop(
self.tree_factory.clone(),
vec![
std::mem::replace(self, ParseTree::noop(self.tree_factory.clone(), Vec::new())),
other,
],
);
return;
}
for other_child in other.children {
let other_tree = match other_child.into_owned() {
Ok(tree) => tree,
Err(child) => {
self.children.push(child);
continue;
}
};
if let Some(self_tree) = self.children.iter_mut().find_map(|child| {
child
.as_tree_mut()
.filter(|tree| tree.same_kind(&other_tree))
}) {
self_tree.merge(other_tree);
} else {
self.children.push(Child::Contains(other_tree));
}
}
}
pub fn root(tree_factory: Rc<ParseTreeFactory<C>>, children: Vec<ParseTree<C>>) -> Self {
let mut noop = Self::noop(tree_factory.clone(), children);
noop.push_child_ref(tree_factory.comments());
noop.push_child_ref(tree_factory.line_terminator());
noop
}
pub fn noop(tree_factory: Rc<ParseTreeFactory<C>>, children: Vec<ParseTree<C>>) -> Self {
ParseTree::new(tree_factory, StatementKind::Noop, children, noop_fn)
}
pub fn add_end_of_line_fn(&mut self) {
if self.is_end() {
self.push_child_ref(self.tree_factory.statement_terminator());
return;
}
for child in self.children_mut() {
child.add_end_of_line_fn();
}
}
pub fn into_line(mut self) -> Self {
self.add_end_of_line_fn();
Self::new(
self.tree_factory.clone(),
StatementKind::CapitalizeWord,
vec![self],
noop_fn,
)
}
}
#[macro_export]
macro_rules! expect_words {
($factory:expr; $($word:expr),+; $children:expr; $callback:expr $(,)?) => {{
expect_words!(@build $factory, $callback, $children; $($word),+)
}};
(@build $factory:expr, $callback:expr, $children:expr; $last:expr) => {
ParseTree::new(
$factory,
StatementKind::ExactWord($last),
$children,
$callback,
)
};
(@build $factory:expr, $callback:expr, $children:expr; $head:expr, $($tail:expr),+) => {
ParseTree::new(
$factory.clone(),
StatementKind::ExactWord($head),
vec![
expect_words!(@build $factory, $callback, $children; $($tail),+)
],
noop_fn,
)
};
}
#[macro_export]
macro_rules! merge_trees {
($tree:expr $(,)?) => {
$tree
};
($first:expr, $($rest:expr),+ $(,)?) => {{
let mut tree = $first;
$(
tree.merge($rest);
)+
tree
}};
}
pub use expect_words;
pub use merge_trees;