From aea86d154ec5adde6adb05088a50f01380ffb8bf Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Mon, 30 Jul 2018 23:45:10 +0300 Subject: stackless traversal --- src/algo/mod.rs | 1 + src/algo/walk.rs | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+) create mode 100644 src/algo/mod.rs create mode 100644 src/algo/walk.rs (limited to 'src/algo') diff --git a/src/algo/mod.rs b/src/algo/mod.rs new file mode 100644 index 000000000..c1644d16d --- /dev/null +++ b/src/algo/mod.rs @@ -0,0 +1 @@ +pub mod walk; diff --git a/src/algo/walk.rs b/src/algo/walk.rs new file mode 100644 index 000000000..86dd82cc9 --- /dev/null +++ b/src/algo/walk.rs @@ -0,0 +1,46 @@ +use SyntaxNodeRef; + +pub fn preorder<'a>(root: SyntaxNodeRef<'a>) -> impl Iterator> { + walk(root).filter_map(|event| match event { + WalkEvent::Enter(node) => Some(node), + WalkEvent::Exit(_) => None, + }) +} + +#[derive(Debug, Copy, Clone)] +enum WalkEvent<'a> { + Enter(SyntaxNodeRef<'a>), + Exit(SyntaxNodeRef<'a>), +} + +fn walk<'a>(root: SyntaxNodeRef<'a>) -> impl Iterator> { + 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) + }) +} + -- cgit v1.2.3