diff options
-rw-r--r-- | src/text.rs | 6 | ||||
-rw-r--r-- | src/tree/file_builder.rs | 111 | ||||
-rw-r--r-- | src/tree/mod.rs | 3 |
3 files changed, 120 insertions, 0 deletions
diff --git a/src/text.rs b/src/text.rs index ee0dc8398..af0a4a9e7 100644 --- a/src/text.rs +++ b/src/text.rs | |||
@@ -32,6 +32,12 @@ impl From<TextUnit> for u32 { | |||
32 | } | 32 | } |
33 | } | 33 | } |
34 | 34 | ||
35 | impl From<u32> for TextUnit { | ||
36 | fn from(tu: u32) -> TextUnit { | ||
37 | TextUnit::new(tu) | ||
38 | } | ||
39 | } | ||
40 | |||
35 | impl ops::Add<TextUnit> for TextUnit { | 41 | impl ops::Add<TextUnit> for TextUnit { |
36 | type Output = TextUnit; | 42 | type Output = TextUnit; |
37 | fn add(self, rhs: TextUnit) -> TextUnit { | 43 | fn add(self, rhs: TextUnit) -> TextUnit { |
diff --git a/src/tree/file_builder.rs b/src/tree/file_builder.rs new file mode 100644 index 000000000..c977b254c --- /dev/null +++ b/src/tree/file_builder.rs | |||
@@ -0,0 +1,111 @@ | |||
1 | use {SyntaxKind, TextUnit, TextRange}; | ||
2 | use super::{NodeData, NodeIdx, File}; | ||
3 | |||
4 | pub struct FileBuilder { | ||
5 | text: String, | ||
6 | nodes: Vec<NodeData>, | ||
7 | in_progress: Vec<(NodeIdx, Option<NodeIdx>)>, // (parent, last_child) | ||
8 | pos: TextUnit, | ||
9 | } | ||
10 | |||
11 | impl FileBuilder { | ||
12 | pub fn new(text: String) -> FileBuilder { | ||
13 | FileBuilder { | ||
14 | text, | ||
15 | nodes: Vec::new(), | ||
16 | in_progress: Vec::new(), | ||
17 | pos: TextUnit::new(0), | ||
18 | } | ||
19 | } | ||
20 | |||
21 | pub fn finish(self) -> File { | ||
22 | assert!(self.in_progress.is_empty()); | ||
23 | assert!(self.pos == (self.text.len() as u32).into()); | ||
24 | File { | ||
25 | text: self.text, | ||
26 | nodes: self.nodes, | ||
27 | } | ||
28 | } | ||
29 | |||
30 | pub fn leaf(&mut self, kind: SyntaxKind, len: TextUnit) { | ||
31 | let leaf = NodeData { | ||
32 | kind, | ||
33 | range: TextRange::from_len(self.pos, len), | ||
34 | parent: None, | ||
35 | first_child: None, | ||
36 | next_sibling: None, | ||
37 | }; | ||
38 | self.pos += len; | ||
39 | let id = self.push_child(leaf); | ||
40 | self.add_len(id); | ||
41 | } | ||
42 | |||
43 | pub fn start_internal(&mut self, kind: SyntaxKind) { | ||
44 | let node = NodeData { | ||
45 | kind, | ||
46 | range: TextRange::from_len(self.pos, 0.into()), | ||
47 | parent: None, | ||
48 | first_child: None, | ||
49 | next_sibling: None, | ||
50 | }; | ||
51 | let id = if self.in_progress.is_empty() { | ||
52 | self.new_node(node) | ||
53 | } else { | ||
54 | self.push_child(node) | ||
55 | }; | ||
56 | self.in_progress.push((id, None)) | ||
57 | } | ||
58 | |||
59 | pub fn finish_internal(&mut self) { | ||
60 | let (id, _) = self.in_progress.pop().unwrap(); | ||
61 | if !self.in_progress.is_empty() { | ||
62 | self.add_len(id); | ||
63 | } | ||
64 | } | ||
65 | |||
66 | fn new_node(&mut self, data: NodeData) -> NodeIdx { | ||
67 | let id = NodeIdx(self.nodes.len() as u32); | ||
68 | self.nodes.push(data); | ||
69 | id | ||
70 | } | ||
71 | |||
72 | fn push_child(&mut self, mut child: NodeData) -> NodeIdx { | ||
73 | child.parent = Some(self.current_id()); | ||
74 | let id = self.new_node(child); | ||
75 | if let Some(sibling) = self.current_sibling() { | ||
76 | fill(&mut sibling.next_sibling, id); | ||
77 | return id | ||
78 | } | ||
79 | fill(&mut self.current_parent().first_child, id); | ||
80 | id | ||
81 | } | ||
82 | |||
83 | fn add_len(&mut self, child: NodeIdx) { | ||
84 | let range = self.nodes[child.0 as usize].range; | ||
85 | grow(&mut self.current_parent().range, range); | ||
86 | } | ||
87 | |||
88 | fn current_id(&self) -> NodeIdx { | ||
89 | self.in_progress.last().unwrap().0 | ||
90 | } | ||
91 | |||
92 | fn current_parent(&mut self) -> &mut NodeData { | ||
93 | let NodeIdx(idx) = self.current_id(); | ||
94 | &mut self.nodes[idx as usize] | ||
95 | } | ||
96 | |||
97 | fn current_sibling(&mut self) -> Option<&mut NodeData> { | ||
98 | let NodeIdx(idx) = self.in_progress.last().unwrap().1?; | ||
99 | Some(&mut self.nodes[idx as usize]) | ||
100 | } | ||
101 | } | ||
102 | |||
103 | fn fill<T>(slot: &mut Option<T>, value: T) { | ||
104 | assert!(slot.is_none()); | ||
105 | *slot = Some(value); | ||
106 | } | ||
107 | |||
108 | fn grow(left: &mut TextRange, right: TextRange) { | ||
109 | assert_eq!(left.end(), right.start()); | ||
110 | *left = TextRange::from_to(left.start(), right.end()) | ||
111 | } \ No newline at end of file | ||
diff --git a/src/tree/mod.rs b/src/tree/mod.rs index 2ac25e795..b90a5d7d3 100644 --- a/src/tree/mod.rs +++ b/src/tree/mod.rs | |||
@@ -3,6 +3,9 @@ use syntax_kinds::syntax_info; | |||
3 | 3 | ||
4 | use std::fmt; | 4 | use std::fmt; |
5 | 5 | ||
6 | mod file_builder; | ||
7 | pub use self::file_builder::FileBuilder; | ||
8 | |||
6 | #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] | 9 | #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] |
7 | pub struct SyntaxKind(pub(crate) u32); | 10 | pub struct SyntaxKind(pub(crate) u32); |
8 | 11 | ||