diff options
author | Aleksey Kladov <[email protected]> | 2018-07-30 21:45:10 +0100 |
---|---|---|
committer | Aleksey Kladov <[email protected]> | 2018-07-30 21:45:10 +0100 |
commit | aea86d154ec5adde6adb05088a50f01380ffb8bf (patch) | |
tree | fd10ec3e5379e24e40f3eff78cb1e035f4bb5c89 | |
parent | 70b337292117a9bb90e85056dcb4069f8bbc6c0a (diff) |
stackless traversal
-rw-r--r-- | Cargo.toml | 1 | ||||
-rw-r--r-- | code/native/src/lib.rs | 6 | ||||
-rw-r--r-- | src/algo/mod.rs | 1 | ||||
-rw-r--r-- | src/algo/walk.rs | 46 | ||||
-rw-r--r-- | src/ast.rs | 13 | ||||
-rw-r--r-- | src/lib.rs | 2 | ||||
-rw-r--r-- | src/utils.rs | 2 | ||||
-rw-r--r-- | src/yellow/red.rs | 3 | ||||
-rw-r--r-- | src/yellow/syntax.rs | 28 |
9 files changed, 86 insertions, 16 deletions
diff --git a/Cargo.toml b/Cargo.toml index b89573e2b..e0c1ce0a4 100644 --- a/Cargo.toml +++ b/Cargo.toml | |||
@@ -10,6 +10,7 @@ members = [ "tools", "cli" ] | |||
10 | [dependencies] | 10 | [dependencies] |
11 | unicode-xid = "0.1.0" | 11 | unicode-xid = "0.1.0" |
12 | text_unit = "0.1.1" | 12 | text_unit = "0.1.1" |
13 | itertools = "0.7.5" | ||
13 | 14 | ||
14 | [dev-dependencies] | 15 | [dev-dependencies] |
15 | testutils = { path = "./tests/testutils" } | 16 | testutils = { path = "./tests/testutils" } |
diff --git a/code/native/src/lib.rs b/code/native/src/lib.rs index dcf478cf5..068767fab 100644 --- a/code/native/src/lib.rs +++ b/code/native/src/lib.rs | |||
@@ -7,6 +7,7 @@ use libsyntax2::{ | |||
7 | File, | 7 | File, |
8 | utils::dump_tree, | 8 | utils::dump_tree, |
9 | SyntaxKind::*, | 9 | SyntaxKind::*, |
10 | algo, | ||
10 | }; | 11 | }; |
11 | use neon::prelude::*; | 12 | use neon::prelude::*; |
12 | 13 | ||
@@ -17,11 +18,12 @@ pub struct Wrapper { | |||
17 | impl Wrapper { | 18 | impl Wrapper { |
18 | fn highlight(&self) -> Vec<(TextRange, &'static str)> { | 19 | fn highlight(&self) -> Vec<(TextRange, &'static str)> { |
19 | let mut res = Vec::new(); | 20 | let mut res = Vec::new(); |
20 | self.inner.for_each_node(|node| { | 21 | let syntax = self.inner.syntax(); |
22 | for node in algo::walk::preorder(syntax.as_ref()) { | ||
21 | if node.kind() == ERROR { | 23 | if node.kind() == ERROR { |
22 | res.push((node.range(), "error")) | 24 | res.push((node.range(), "error")) |
23 | } | 25 | } |
24 | }); | 26 | } |
25 | res | 27 | res |
26 | } | 28 | } |
27 | } | 29 | } |
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 @@ | |||
1 | use SyntaxNodeRef; | ||
2 | |||
3 | pub fn preorder<'a>(root: SyntaxNodeRef<'a>) -> impl Iterator<Item=SyntaxNodeRef<'a>> { | ||
4 | walk(root).filter_map(|event| match event { | ||
5 | WalkEvent::Enter(node) => Some(node), | ||
6 | WalkEvent::Exit(_) => None, | ||
7 | }) | ||
8 | } | ||
9 | |||
10 | #[derive(Debug, Copy, Clone)] | ||
11 | enum WalkEvent<'a> { | ||
12 | Enter(SyntaxNodeRef<'a>), | ||
13 | Exit(SyntaxNodeRef<'a>), | ||
14 | } | ||
15 | |||
16 | fn walk<'a>(root: SyntaxNodeRef<'a>) -> impl Iterator<Item=WalkEvent<'a>> { | ||
17 | let mut done = false; | ||
18 | ::itertools::unfold(WalkEvent::Enter(root), move |pos| { | ||
19 | if done { | ||
20 | return None; | ||
21 | } | ||
22 | let res = *pos; | ||
23 | *pos = match *pos { | ||
24 | WalkEvent::Enter(node) => match node.first_child() { | ||
25 | Some(child) => WalkEvent::Enter(child), | ||
26 | None => WalkEvent::Exit(node), | ||
27 | }, | ||
28 | WalkEvent::Exit(node) => { | ||
29 | if node == root { | ||
30 | done = true; | ||
31 | WalkEvent::Exit(node) | ||
32 | } else { | ||
33 | match node.next_sibling() { | ||
34 | Some(sibling) => WalkEvent::Enter(sibling), | ||
35 | None => match node.parent() { | ||
36 | Some(node) => WalkEvent::Exit(node), | ||
37 | None => WalkEvent::Exit(node), | ||
38 | } | ||
39 | } | ||
40 | } | ||
41 | } | ||
42 | }; | ||
43 | Some(res) | ||
44 | }) | ||
45 | } | ||
46 | |||
diff --git a/src/ast.rs b/src/ast.rs index 3a9287466..b513eb13e 100644 --- a/src/ast.rs +++ b/src/ast.rs | |||
@@ -1,5 +1,5 @@ | |||
1 | use std::sync::Arc; | 1 | use std::sync::Arc; |
2 | use {SyntaxNode, TreeRoot, SyntaxRoot, SyntaxNodeRef}; | 2 | use {SyntaxNode, TreeRoot, SyntaxRoot}; |
3 | 3 | ||
4 | #[derive(Debug)] | 4 | #[derive(Debug)] |
5 | pub struct File<R: TreeRoot = Arc<SyntaxRoot>> { | 5 | pub struct File<R: TreeRoot = Arc<SyntaxRoot>> { |
@@ -16,15 +16,4 @@ impl<R: TreeRoot> File<R> { | |||
16 | pub fn syntax(&self) -> SyntaxNode<R> { | 16 | pub fn syntax(&self) -> SyntaxNode<R> { |
17 | self.syntax.clone() | 17 | self.syntax.clone() |
18 | } | 18 | } |
19 | |||
20 | pub fn for_each_node(&self, mut f: impl FnMut(SyntaxNodeRef)) { | ||
21 | let syntax = self.syntax(); | ||
22 | let syntax = syntax.borrow(); | ||
23 | go(syntax, &mut f); | ||
24 | |||
25 | fn go(syntax: SyntaxNodeRef, f: &mut FnMut(SyntaxNodeRef)) { | ||
26 | f(syntax); | ||
27 | syntax.children().into_iter().for_each(f) | ||
28 | } | ||
29 | } | ||
30 | } | 19 | } |
diff --git a/src/lib.rs b/src/lib.rs index 3a8e6fa64..9049beb29 100644 --- a/src/lib.rs +++ b/src/lib.rs | |||
@@ -22,6 +22,7 @@ | |||
22 | 22 | ||
23 | extern crate text_unit; | 23 | extern crate text_unit; |
24 | extern crate unicode_xid; | 24 | extern crate unicode_xid; |
25 | extern crate itertools; | ||
25 | 26 | ||
26 | mod lexer; | 27 | mod lexer; |
27 | mod parser; | 28 | mod parser; |
@@ -30,6 +31,7 @@ mod yellow; | |||
30 | /// Utilities for simple uses of the parser. | 31 | /// Utilities for simple uses of the parser. |
31 | pub mod utils; | 32 | pub mod utils; |
32 | pub mod ast; | 33 | pub mod ast; |
34 | pub mod algo; | ||
33 | 35 | ||
34 | pub use { | 36 | pub use { |
35 | lexer::{tokenize, Token}, | 37 | lexer::{tokenize, Token}, |
diff --git a/src/utils.rs b/src/utils.rs index 20991659a..826a7d60b 100644 --- a/src/utils.rs +++ b/src/utils.rs | |||
@@ -3,7 +3,7 @@ use {SyntaxError, SyntaxNode, SyntaxNodeRef}; | |||
3 | 3 | ||
4 | /// Parse a file and create a string representation of the resulting parse tree. | 4 | /// Parse a file and create a string representation of the resulting parse tree. |
5 | pub fn dump_tree(syntax: &SyntaxNode) -> String { | 5 | pub fn dump_tree(syntax: &SyntaxNode) -> String { |
6 | let syntax = syntax.borrow(); | 6 | let syntax = syntax.as_ref(); |
7 | let mut errors: BTreeSet<_> = syntax.root.errors.iter().cloned().collect(); | 7 | let mut errors: BTreeSet<_> = syntax.root.errors.iter().cloned().collect(); |
8 | let mut result = String::new(); | 8 | let mut result = String::new(); |
9 | go(syntax, &mut result, 0, &mut errors); | 9 | go(syntax, &mut result, 0, &mut errors); |
diff --git a/src/yellow/red.rs b/src/yellow/red.rs index bffb72510..8329ec5b2 100644 --- a/src/yellow/red.rs +++ b/src/yellow/red.rs | |||
@@ -84,4 +84,7 @@ impl RedNode { | |||
84 | pub(crate) fn parent(&self) -> Option<ptr::NonNull<RedNode>> { | 84 | pub(crate) fn parent(&self) -> Option<ptr::NonNull<RedNode>> { |
85 | Some(self.parent.as_ref()?.parent) | 85 | Some(self.parent.as_ref()?.parent) |
86 | } | 86 | } |
87 | pub(crate) fn index_in_parent(&self) -> Option<usize> { | ||
88 | Some(self.parent.as_ref()?.index_in_parent) | ||
89 | } | ||
87 | } | 90 | } |
diff --git a/src/yellow/syntax.rs b/src/yellow/syntax.rs index 5c31a3f35..65ce647c7 100644 --- a/src/yellow/syntax.rs +++ b/src/yellow/syntax.rs | |||
@@ -18,6 +18,15 @@ pub struct SyntaxNode<R: TreeRoot = Arc<SyntaxRoot>> { | |||
18 | red: ptr::NonNull<RedNode>, | 18 | red: ptr::NonNull<RedNode>, |
19 | } | 19 | } |
20 | 20 | ||
21 | impl <R1: TreeRoot, R2: TreeRoot> PartialEq<SyntaxNode<R1>> for SyntaxNode<R2> { | ||
22 | fn eq(&self, other: &SyntaxNode<R1>) -> bool { | ||
23 | self.red == other.red | ||
24 | } | ||
25 | } | ||
26 | |||
27 | impl <R: TreeRoot> Eq for SyntaxNode<R> { | ||
28 | } | ||
29 | |||
21 | pub type SyntaxNodeRef<'a> = SyntaxNode<&'a SyntaxRoot>; | 30 | pub type SyntaxNodeRef<'a> = SyntaxNode<&'a SyntaxRoot>; |
22 | 31 | ||
23 | #[derive(Debug)] | 32 | #[derive(Debug)] |
@@ -53,7 +62,7 @@ impl SyntaxNode<Arc<SyntaxRoot>> { | |||
53 | } | 62 | } |
54 | 63 | ||
55 | impl<R: TreeRoot> SyntaxNode<R> { | 64 | impl<R: TreeRoot> SyntaxNode<R> { |
56 | pub fn borrow<'a>(&'a self) -> SyntaxNode<&'a SyntaxRoot> { | 65 | pub fn as_ref<'a>(&'a self) -> SyntaxNode<&'a SyntaxRoot> { |
57 | SyntaxNode { | 66 | SyntaxNode { |
58 | root: &*self.root, | 67 | root: &*self.root, |
59 | red: ptr::NonNull::clone(&self.red), | 68 | red: ptr::NonNull::clone(&self.red), |
@@ -92,6 +101,23 @@ impl<R: TreeRoot> SyntaxNode<R> { | |||
92 | }) | 101 | }) |
93 | } | 102 | } |
94 | 103 | ||
104 | pub fn first_child(&self) -> Option<SyntaxNode<R>> { | ||
105 | self.children().next() | ||
106 | } | ||
107 | |||
108 | pub fn next_sibling(&self) -> Option<SyntaxNode<R>> { | ||
109 | let red = self.red(); | ||
110 | let parent = self.parent()?; | ||
111 | let next_sibling_idx = red.index_in_parent()? + 1; | ||
112 | if next_sibling_idx == red.n_children() { | ||
113 | return None; | ||
114 | } | ||
115 | Some(SyntaxNode { | ||
116 | root: self.root.clone(), | ||
117 | red: parent.red().nth_child(next_sibling_idx), | ||
118 | }) | ||
119 | } | ||
120 | |||
95 | fn red(&self) -> &RedNode { | 121 | fn red(&self) -> &RedNode { |
96 | unsafe { self.red.as_ref() } | 122 | unsafe { self.red.as_ref() } |
97 | } | 123 | } |