use crate::core::ast::AstNodeId;
use crate::core::errors::ParseErrorAccumulator;
use crate::core::{ast::AstNode, errors::AstError};
use salsa::Accumulator;
use std::ops::ControlFlow;
use tree_sitter::{Node, TreeCursor};
pub type TryFromParams<'from> = (
&'from Node<'from>, &'from dyn salsa::Database, &'from mut Builder, usize, Option<usize>, );
#[derive(Default)]
pub struct Builder {
id_ctr: usize,
nodes: Vec<Box<dyn AstNode>>,
}
impl Builder {
pub fn len(&self) -> usize {
self.nodes.len()
}
pub fn is_empty(&self) -> bool {
self.nodes.is_empty()
}
pub fn take_nodes(self) -> Vec<Box<dyn AstNode>> {
self.nodes
}
fn create<'db, T: AstNode + for<'from> TryFrom<TryFromParams<'from>, Error = AstError>>(
&mut self,
db: &'db dyn salsa::Database,
cursor: &TreeCursor,
parent_id: Option<usize>,
) -> Result<AstNodeId<T>, AstError> {
let node = cursor.node();
let start_len = self.nodes.len();
let start_id_ctr = self.id_ctr;
let id = self.id_ctr + 1;
self.id_ctr = id;
match T::try_from((&node, db, self, id, parent_id)).map(Box::new) {
Ok(result) => {
self.nodes.push(result);
Ok(AstNodeId::new(id))
}
Err(e) => {
self.id_ctr = start_id_ctr;
self.nodes.truncate(start_len);
Err(e)
}
}
}
pub fn builder<'cursor, F>(
&'cursor mut self,
db: &'cursor dyn salsa::Database,
node: &'cursor Node<'cursor>,
parent: Option<usize>,
mut f: F,
) where
F: for<'cb> FnMut(
&'cb mut TreeWalk<'cursor>,
) -> ControlFlow<(), &'cb mut TreeWalk<'cursor>>,
{
TreeWalk::new(self, db, node, parent).walk(&mut f);
}
}
pub struct TreeWalk<'cursor> {
db: &'cursor dyn salsa::Database,
builder: &'cursor mut Builder, cursor: TreeCursor<'cursor>, parent: Option<usize>,
}
impl<'cursor> TreeWalk<'cursor> {
fn new(
builder: &'cursor mut Builder,
db: &'cursor dyn salsa::Database,
node: &'cursor Node<'cursor>,
parent: Option<usize>,
) -> Self {
let cursor = node.walk();
Self {
builder,
db,
cursor,
parent,
}
}
fn walk<F>(&mut self, mut f: F)
where
F: FnMut(&mut Self) -> ControlFlow<(), &mut Self>,
{
if self.cursor.goto_first_child() {
let _ = f(self);
while self.cursor.goto_next_sibling() {
let _ = f(self);
}
}
}
pub fn on_field_id<
T: AstNode + for<'from> TryFrom<TryFromParams<'from>, Error = AstError>,
const FIELD_ID: u16,
>(
&mut self,
result: &mut Result<Option<AstNodeId<T>>, AstError>,
) -> ControlFlow<(), &mut Self> {
if let Some(field) = self.cursor.field_id() {
if field == std::num::NonZero::new(FIELD_ID).expect("FIELD_ID should be non-zero") {
*result = self
.builder
.create(self.db, &self.cursor, self.parent)
.map(Some);
return ControlFlow::Break(());
}
}
ControlFlow::Continue(self)
}
pub fn on_vec_field_id<
T: AstNode + for<'from> TryFrom<TryFromParams<'from>, Error = AstError>,
const FIELD_ID: u16,
>(
&mut self,
result: &mut Vec<AstNodeId<T>>,
) -> ControlFlow<(), &mut Self> {
if let Some(field) = self.cursor.field_id() {
if field == std::num::NonZero::new(FIELD_ID).expect("FIELD_ID should be non-zero") {
match self.builder.create(self.db, &self.cursor, self.parent) {
Ok(node) => result.push(node),
Err(e) => ParseErrorAccumulator::accumulate(e.into(), self.db),
};
return ControlFlow::Break(());
}
}
ControlFlow::Continue(self)
}
pub fn on_children_id<
T: AstNode + for<'from> TryFrom<TryFromParams<'from>, Error = AstError>,
>(
&mut self,
result: &mut Result<Option<AstNodeId<T>>, AstError>,
) -> ControlFlow<(), &mut Self> {
let node = self.cursor.node();
if T::contains(&node) {
*result = self
.builder
.create(self.db, &self.cursor, self.parent)
.map(Some);
return ControlFlow::Break(());
}
ControlFlow::Continue(self)
}
pub fn on_vec_children_id<
T: AstNode + for<'from> TryFrom<TryFromParams<'from>, Error = AstError>,
>(
&mut self,
result: &mut Vec<AstNodeId<T>>,
) -> ControlFlow<(), &mut Self> {
if T::contains(&self.cursor.node()) {
match self.builder.create(self.db, &self.cursor, self.parent) {
Ok(node) => result.push(node),
Err(e) => ParseErrorAccumulator::accumulate(e.into(), self.db),
};
return ControlFlow::Break(());
}
ControlFlow::Continue(self)
}
}