diff options
author | Aleksey Kladov <[email protected]> | 2018-07-29 11:51:55 +0100 |
---|---|---|
committer | Aleksey Kladov <[email protected]> | 2018-07-29 11:51:55 +0100 |
commit | c12450fb4e30c3418555e47d045bb9fd4318a10a (patch) | |
tree | e2dc508e1e415388392657cda3dfb00175cdabf2 /src/yellow/syntax.rs | |
parent | 8d9961b75377a7bd2656b5aa1451710de8c86f60 (diff) |
Introduce red-green syntax tree
Diffstat (limited to 'src/yellow/syntax.rs')
-rw-r--r-- | src/yellow/syntax.rs | 132 |
1 files changed, 132 insertions, 0 deletions
diff --git a/src/yellow/syntax.rs b/src/yellow/syntax.rs new file mode 100644 index 000000000..0c9ffeb14 --- /dev/null +++ b/src/yellow/syntax.rs | |||
@@ -0,0 +1,132 @@ | |||
1 | use std::{ | ||
2 | fmt, | ||
3 | sync::Arc, | ||
4 | }; | ||
5 | |||
6 | use { | ||
7 | TextRange, TextUnit, SyntaxKind, | ||
8 | yellow::{Ptr, RedNode, GreenNode, TextLen}, | ||
9 | }; | ||
10 | use yellow::green::GreenTrivia; | ||
11 | |||
12 | #[derive(Clone)] | ||
13 | pub struct SyntaxNode { | ||
14 | pub(crate) root: SyntaxRoot, | ||
15 | red: Ptr<RedNode>, | ||
16 | trivia_pos: Option<(usize, usize)>, | ||
17 | } | ||
18 | |||
19 | #[derive(Clone)] | ||
20 | pub struct SyntaxRoot { | ||
21 | red: Arc<RedNode>, | ||
22 | pub(crate) errors: Arc<Vec<SError>>, | ||
23 | } | ||
24 | |||
25 | #[derive(Debug, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)] | ||
26 | pub(crate) struct SError { | ||
27 | pub(crate) message: String, | ||
28 | pub(crate) offset: TextUnit, | ||
29 | } | ||
30 | |||
31 | impl SyntaxNode { | ||
32 | pub(crate) fn new(root: Arc<GreenNode>, errors: Vec<SError>) -> SyntaxNode { | ||
33 | let root = Arc::new(RedNode::new_root(root)); | ||
34 | let red = Ptr::new(&root); | ||
35 | let root = SyntaxRoot { red: root, errors: Arc::new(errors) }; | ||
36 | SyntaxNode { root, red, trivia_pos: None } | ||
37 | } | ||
38 | |||
39 | pub fn kind(&self) -> SyntaxKind { | ||
40 | let green = self.red().green(); | ||
41 | match self.trivia_pos { | ||
42 | None => green.kind(), | ||
43 | Some((i, j)) => green.nth_trivias(i)[j].kind | ||
44 | } | ||
45 | } | ||
46 | |||
47 | pub fn range(&self) -> TextRange { | ||
48 | let red = self.red(); | ||
49 | let green = red.green(); | ||
50 | match self.trivia_pos { | ||
51 | None => TextRange::offset_len(red.start_offset(), red.green().text_len()), | ||
52 | Some((i, j)) => { | ||
53 | let trivias = green.nth_trivias(i); | ||
54 | let offset = if i == 0 { | ||
55 | red.start_offset() | ||
56 | } else { | ||
57 | let prev_child = red.nth_child(Ptr::clone(&self.red), i - 1); | ||
58 | let mut offset = prev_child.start_offset() + prev_child.green().text_len(); | ||
59 | for k in 0..j { | ||
60 | offset += &trivias[k].text_len(); | ||
61 | } | ||
62 | offset | ||
63 | }; | ||
64 | TextRange::offset_len(offset, trivias[j].text_len()) | ||
65 | } | ||
66 | } | ||
67 | } | ||
68 | |||
69 | pub fn text(&self) -> String { | ||
70 | let green = self.red().green(); | ||
71 | match self.trivia_pos { | ||
72 | None => green.text(), | ||
73 | Some((i, j)) => green.nth_trivias(i)[j].text.clone() | ||
74 | } | ||
75 | } | ||
76 | |||
77 | pub fn children(&self) -> Vec<SyntaxNode> { | ||
78 | let mut res = Vec::new(); | ||
79 | let red = self.red(); | ||
80 | let green = red.green(); | ||
81 | if green.is_leaf() || self.trivia_pos.is_some() { | ||
82 | return Vec::new(); | ||
83 | } | ||
84 | for (j, _) in green.nth_trivias(0).iter().enumerate() { | ||
85 | res.push(SyntaxNode { | ||
86 | root: self.root.clone(), | ||
87 | red: Ptr::clone(&self.red), | ||
88 | trivia_pos: Some((0, j)), | ||
89 | }) | ||
90 | } | ||
91 | |||
92 | let n_children = red.n_children(); | ||
93 | for i in 0..n_children { | ||
94 | res.push(SyntaxNode { | ||
95 | root: self.root.clone(), | ||
96 | red: Ptr::new(&red.nth_child(Ptr::clone(&self.red), i)), | ||
97 | trivia_pos: None, | ||
98 | }); | ||
99 | for (j, _) in green.nth_trivias(i + 1).iter().enumerate() { | ||
100 | res.push(SyntaxNode { | ||
101 | root: self.root.clone(), | ||
102 | red: self.red.clone(), | ||
103 | trivia_pos: Some((i + 1, j)), | ||
104 | }) | ||
105 | } | ||
106 | } | ||
107 | res | ||
108 | } | ||
109 | |||
110 | fn red(&self) -> &RedNode { | ||
111 | // Safe b/c root ptr keeps red alive | ||
112 | unsafe { self.red.get() } | ||
113 | } | ||
114 | } | ||
115 | |||
116 | impl fmt::Debug for SyntaxNode { | ||
117 | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { | ||
118 | write!(fmt, "{:?}@{:?}", self.kind(), self.range())?; | ||
119 | if has_short_text(self.kind()) { | ||
120 | write!(fmt, " \"{}\"", self.text())?; | ||
121 | } | ||
122 | Ok(()) | ||
123 | } | ||
124 | } | ||
125 | |||
126 | fn has_short_text(kind: SyntaxKind) -> bool { | ||
127 | use syntax_kinds::*; | ||
128 | match kind { | ||
129 | IDENT | LIFETIME => true, | ||
130 | _ => false, | ||
131 | } | ||
132 | } | ||