use std::collections::hash_map::Entry;
use std::collections::HashMap;
use std::sync::Arc;
use std::vec;
use cairo_lang_filesystem::span::TextOffset;
use crate::node::db::SyntaxGroup;
use crate::node::ids::GreenId;
use crate::node::key_fields::get_key_fields;
use crate::node::kind::SyntaxKind;
use crate::node::stable_ptr::SyntaxStablePtr;
use crate::node::{SyntaxNode, SyntaxNodeInner};
pub struct SyntaxNodeChildIterator<'db> {
db: &'db dyn SyntaxGroup,
node: SyntaxNode,
green_iterator: vec::IntoIter<GreenId>,
offset: TextOffset,
key_map: HashMap<(SyntaxKind, Vec<GreenId>), usize>,
}
impl<'db> Iterator for SyntaxNodeChildIterator<'db> {
type Item = SyntaxNode;
fn next(&mut self) -> Option<Self::Item> {
let green_id = self.green_iterator.next()?;
self.next_inner(green_id)
}
}
impl<'db> DoubleEndedIterator for SyntaxNodeChildIterator<'db> {
fn next_back(&mut self) -> Option<<SyntaxNodeChildIterator<'db> as Iterator>::Item> {
let green_id = self.green_iterator.next_back()?;
self.next_inner(green_id)
}
}
impl<'db> ExactSizeIterator for SyntaxNodeChildIterator<'db> {
fn len(&self) -> usize {
self.green_iterator.len()
}
}
impl<'db> SyntaxNodeChildIterator<'db> {
pub(super) fn new(node: &SyntaxNode, db: &'db dyn SyntaxGroup) -> Self {
SyntaxNodeChildIterator {
db,
node: node.clone(),
green_iterator: node.green_node(db).children().into_iter(),
offset: node.offset(),
key_map: HashMap::new(),
}
}
fn next_inner(
&mut self,
green_id: GreenId,
) -> Option<<SyntaxNodeChildIterator<'db> as Iterator>::Item> {
let green = self.db.lookup_intern_green(green_id);
let width = green.width();
let kind = green.kind;
let key_fields: Vec<GreenId> = get_key_fields(kind, green.children());
let index = match self.key_map.entry((kind, key_fields.clone())) {
Entry::Occupied(mut entry) => entry.insert(entry.get() + 1),
Entry::Vacant(entry) => {
entry.insert(1);
0
}
};
let stable_ptr = self.db.intern_stable_ptr(SyntaxStablePtr::Child {
parent: self.node.0.stable_ptr,
kind,
key_fields,
index,
});
let res = SyntaxNode(Arc::new(SyntaxNodeInner {
green: green_id,
offset: self.offset,
parent: Some(self.node.clone()),
stable_ptr,
}));
self.offset = self.offset.add_width(width);
Some(res)
}
}
#[derive(Debug, Copy, Clone)]
pub enum WalkEvent<T> {
Enter(T),
Leave(T),
}
impl<T> WalkEvent<T> {
pub fn map<U>(self, f: impl FnOnce(T) -> U) -> WalkEvent<U> {
match self {
WalkEvent::Enter(it) => WalkEvent::Enter(f(it)),
WalkEvent::Leave(it) => WalkEvent::Leave(f(it)),
}
}
}
pub struct Preorder<'a> {
db: &'a dyn SyntaxGroup,
layers: Vec<PreorderLayer<'a>>,
}
struct PreorderLayer<'a> {
start: SyntaxNode,
children: Option<SyntaxNodeChildIterator<'a>>,
}
impl<'a> Preorder<'a> {
pub(super) fn new(start: SyntaxNode, db: &'a dyn SyntaxGroup) -> Self {
let initial_layer = PreorderLayer::<'a> { start, children: None };
let mut layers = Vec::with_capacity(32);
layers.push(initial_layer);
Self { db, layers }
}
}
impl<'a> Iterator for Preorder<'a> {
type Item = WalkEvent<SyntaxNode>;
fn next(&mut self) -> Option<Self::Item> {
let mut layer = self.layers.pop()?;
match layer.children.take() {
None => {
let event = WalkEvent::Enter(layer.start.clone());
layer.children = Some(layer.start.children(self.db));
self.layers.push(layer);
Some(event)
}
Some(mut iter) => match iter.next() {
None => {
Some(WalkEvent::Leave(layer.start.clone()))
}
Some(start) => {
let event = WalkEvent::Enter(start.clone());
let new_layer =
PreorderLayer { children: Some(start.children(self.db)), start };
layer.children = Some(iter);
self.layers.extend([layer, new_layer]);
Some(event)
}
},
}
}
}