aboutsummaryrefslogtreecommitdiff
path: root/src/tree
diff options
context:
space:
mode:
Diffstat (limited to 'src/tree')
-rw-r--r--src/tree/file_builder.rs111
-rw-r--r--src/tree/mod.rs3
2 files changed, 114 insertions, 0 deletions
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 @@
1use {SyntaxKind, TextUnit, TextRange};
2use super::{NodeData, NodeIdx, File};
3
4pub struct FileBuilder {
5 text: String,
6 nodes: Vec<NodeData>,
7 in_progress: Vec<(NodeIdx, Option<NodeIdx>)>, // (parent, last_child)
8 pos: TextUnit,
9}
10
11impl 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
103fn fill<T>(slot: &mut Option<T>, value: T) {
104 assert!(slot.is_none());
105 *slot = Some(value);
106}
107
108fn 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
4use std::fmt; 4use std::fmt;
5 5
6mod file_builder;
7pub use self::file_builder::FileBuilder;
8
6#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] 9#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
7pub struct SyntaxKind(pub(crate) u32); 10pub struct SyntaxKind(pub(crate) u32);
8 11