use {Node, NodeType, TextUnit, TextRange}; use ::visitor::{visitor, process_subtree_bottom_up}; pub fn child_of_type(node: Node, ty: NodeType) -> Option { node.children().find(|n| n.ty() == ty) } pub fn children_of_type<'f>(node: Node<'f>, ty: NodeType) -> Box> + 'f> { Box::new(node.children().filter(move |n| n.ty() == ty)) } pub fn subtree<'f>(node: Node<'f>) -> Box> + 'f> { Box::new(node.children().flat_map(subtree).chain(::std::iter::once(node))) } pub fn descendants_of_type<'f>(node: Node<'f>, ty: NodeType) -> Vec> { process_subtree_bottom_up( node, visitor(Vec::new()) .visit_nodes(&[ty], |node, nodes| nodes.push(node)) ) } pub fn child_of_type_exn(node: Node, ty: NodeType) -> Node { child_of_type(node, ty).unwrap_or_else(|| { panic!("No child of type {:?} for {:?}\ ----\ {}\ ----", ty, node.ty(), node.text()) }) } pub fn ancestors(node: Node) -> Ancestors { Ancestors(Some(node)) } pub struct Ancestors<'f>(Option>); impl<'f> Iterator for Ancestors<'f> { type Item = Node<'f>; fn next(&mut self) -> Option { let current = self.0; self.0 = current.and_then(|n| n.parent()); current } } pub fn is_leaf(node: Node) -> bool { node.children().next().is_none() && !node.range().is_empty() } #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] pub enum Direction { Left, Right } pub fn sibling(node: Node, dir: Direction) -> Option { let (parent, idx) = child_position(node)?; let idx = match dir { Direction::Left => idx.checked_sub(1)?, Direction::Right => idx + 1, }; parent.children().nth(idx) } pub mod ast { use {Node, AstNode, TextUnit, AstChildren}; use visitor::{visitor, process_subtree_bottom_up}; use super::{ancestors, find_leaf_at_offset, LeafAtOffset}; pub fn ancestor<'f, T: AstNode<'f>>(node: Node<'f>) -> Option { ancestors(node) .filter_map(T::wrap) .next() } pub fn ancestor_exn<'f, T: AstNode<'f>>(node: Node<'f>) -> T { ancestor(node).unwrap() } pub fn children_of_type<'f, N: AstNode<'f>>(node: Node<'f>) -> AstChildren { AstChildren::new(node.children()) } pub fn descendants_of_type<'f, N: AstNode<'f>>(node: Node<'f>) -> Vec { process_subtree_bottom_up( node, visitor(Vec::new()) .visit::(|node, acc| acc.push(node)) ) } pub fn node_at_offset<'f, T: AstNode<'f>>(node: Node<'f>, offset: TextUnit) -> Option { match find_leaf_at_offset(node, offset) { LeafAtOffset::None => None, LeafAtOffset::Single(node) => ancestor(node), LeafAtOffset::Between(left, right) => ancestor(left).or_else(|| ancestor(right)), } } } pub mod traversal { use {Node}; pub fn bottom_up<'f, F: FnMut(Node<'f>)>(node: Node<'f>, mut f: F) { go(node, &mut f); fn go<'f, F: FnMut(Node<'f>)>(node: Node<'f>, f: &mut F) { for child in node.children() { go(child, f) } f(node); } } } fn child_position(child: Node) -> Option<(Node, usize)> { child.parent() .map(|parent| { (parent, parent.children().position(|n| n == child).unwrap()) }) } fn common_ancestor<'f>(n1: Node<'f>, n2: Node<'f>) -> Node<'f> { for p in ancestors(n1) { if ancestors(n2).any(|a| a == p) { return p; } } panic!("Can't find common ancestor of {:?} and {:?}", n1, n2) }