organizize

This commit is contained in:
Aleksey Kladov
2018-08-10 22:33:29 +03:00
parent 26262aaf05
commit 7c67612b8a
376 changed files with 27 additions and 145 deletions

View File

@@ -0,0 +1,123 @@
pub mod walk;
use {SyntaxNodeRef, TextUnit, TextRange};
pub fn find_leaf_at_offset(node: SyntaxNodeRef, offset: TextUnit) -> LeafAtOffset {
let range = node.range();
assert!(
contains_offset_nonstrict(range, offset),
"Bad offset: range {:?} offset {:?}", range, offset
);
if range.is_empty() {
return LeafAtOffset::None;
}
if node.is_leaf() {
return LeafAtOffset::Single(node);
}
let mut children = node.children()
.filter(|child| {
let child_range = child.range();
!child_range.is_empty() && contains_offset_nonstrict(child_range, offset)
});
let left = children.next().unwrap();
let right = children.next();
assert!(children.next().is_none());
return if let Some(right) = right {
match (find_leaf_at_offset(left, offset), find_leaf_at_offset(right, offset)) {
(LeafAtOffset::Single(left), LeafAtOffset::Single(right)) =>
LeafAtOffset::Between(left, right),
_ => unreachable!()
}
} else {
find_leaf_at_offset(left, offset)
};
}
#[derive(Clone, Copy, Debug)]
pub enum LeafAtOffset<'a> {
None,
Single(SyntaxNodeRef<'a>),
Between(SyntaxNodeRef<'a>, SyntaxNodeRef<'a>)
}
impl<'a> LeafAtOffset<'a> {
pub fn right_biased(self) -> Option<SyntaxNodeRef<'a>> {
match self {
LeafAtOffset::None => None,
LeafAtOffset::Single(node) => Some(node),
LeafAtOffset::Between(_, right) => Some(right)
}
}
pub fn left_biased(self) -> Option<SyntaxNodeRef<'a>> {
match self {
LeafAtOffset::None => None,
LeafAtOffset::Single(node) => Some(node),
LeafAtOffset::Between(left, _) => Some(left)
}
}
}
impl<'f> Iterator for LeafAtOffset<'f> {
type Item = SyntaxNodeRef<'f>;
fn next(&mut self) -> Option<SyntaxNodeRef<'f>> {
match *self {
LeafAtOffset::None => None,
LeafAtOffset::Single(node) => { *self = LeafAtOffset::None; Some(node) }
LeafAtOffset::Between(left, right) => { *self = LeafAtOffset::Single(right); Some(left) }
}
}
}
pub fn find_covering_node(root: SyntaxNodeRef, range: TextRange) -> SyntaxNodeRef {
assert!(is_subrange(root.range(), range));
let (left, right) = match (
find_leaf_at_offset(root, range.start()).right_biased(),
find_leaf_at_offset(root, range.end()).left_biased()
) {
(Some(l), Some(r)) => (l, r),
_ => return root
};
common_ancestor(left, right)
}
fn common_ancestor<'a>(n1: SyntaxNodeRef<'a>, n2: SyntaxNodeRef<'a>) -> SyntaxNodeRef<'a> {
for p in ancestors(n1) {
if ancestors(n2).any(|a| a == p) {
return p;
}
}
panic!("Can't find common ancestor of {:?} and {:?}", n1, n2)
}
pub fn ancestors<'a>(node: SyntaxNodeRef<'a>) -> impl Iterator<Item=SyntaxNodeRef<'a>> {
Ancestors(Some(node))
}
#[derive(Debug)]
struct Ancestors<'a>(Option<SyntaxNodeRef<'a>>);
impl<'a> Iterator for Ancestors<'a> {
type Item = SyntaxNodeRef<'a>;
fn next(&mut self) -> Option<Self::Item> {
self.0.take().map(|n| {
self.0 = n.parent();
n
})
}
}
fn contains_offset_nonstrict(range: TextRange, offset: TextUnit) -> bool {
range.start() <= offset && offset <= range.end()
}
fn is_subrange(range: TextRange, subrange: TextRange) -> bool {
range.start() <= subrange.start() && subrange.end() <= range.end()
}

View File

@@ -0,0 +1,136 @@
use {Node, NodeType, TextUnit, TextRange};
use ::visitor::{visitor, process_subtree_bottom_up};
pub fn child_of_type(node: Node, ty: NodeType) -> Option<Node> {
node.children().find(|n| n.ty() == ty)
}
pub fn children_of_type<'f>(node: Node<'f>, ty: NodeType) -> Box<Iterator<Item=Node<'f>> + 'f> {
Box::new(node.children().filter(move |n| n.ty() == ty))
}
pub fn subtree<'f>(node: Node<'f>) -> Box<Iterator<Item=Node<'f>> + '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<Node<'f>> {
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<Node<'f>>);
impl<'f> Iterator for Ancestors<'f> {
type Item = Node<'f>;
fn next(&mut self) -> Option<Self::Item> {
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<Node> {
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<T> {
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<N> {
AstChildren::new(node.children())
}
pub fn descendants_of_type<'f, N: AstNode<'f>>(node: Node<'f>) -> Vec<N> {
process_subtree_bottom_up(
node,
visitor(Vec::new())
.visit::<N, _>(|node, acc| acc.push(node))
)
}
pub fn node_at_offset<'f, T: AstNode<'f>>(node: Node<'f>, offset: TextUnit) -> Option<T> {
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)
}

View File

@@ -0,0 +1,45 @@
use SyntaxNodeRef;
pub fn preorder<'a>(root: SyntaxNodeRef<'a>) -> impl Iterator<Item = SyntaxNodeRef<'a>> {
walk(root).filter_map(|event| match event {
WalkEvent::Enter(node) => Some(node),
WalkEvent::Exit(_) => None,
})
}
#[derive(Debug, Copy, Clone)]
pub enum WalkEvent<'a> {
Enter(SyntaxNodeRef<'a>),
Exit(SyntaxNodeRef<'a>),
}
pub fn walk<'a>(root: SyntaxNodeRef<'a>) -> impl Iterator<Item = WalkEvent<'a>> {
let mut done = false;
::itertools::unfold(WalkEvent::Enter(root), move |pos| {
if done {
return None;
}
let res = *pos;
*pos = match *pos {
WalkEvent::Enter(node) => match node.first_child() {
Some(child) => WalkEvent::Enter(child),
None => WalkEvent::Exit(node),
},
WalkEvent::Exit(node) => {
if node == root {
done = true;
WalkEvent::Exit(node)
} else {
match node.next_sibling() {
Some(sibling) => WalkEvent::Enter(sibling),
None => match node.parent() {
Some(node) => WalkEvent::Exit(node),
None => WalkEvent::Exit(node),
},
}
}
}
};
Some(res)
})
}