diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/lib.rs | 52 | ||||
-rw-r--r-- | src/parser/event.rs | 8 | ||||
-rw-r--r-- | src/parser/mod.rs | 29 | ||||
-rw-r--r-- | src/tree/file_builder.rs | 72 | ||||
-rw-r--r-- | src/tree/mod.rs | 2 | ||||
-rw-r--r-- | src/yellow/green.rs | 194 | ||||
-rw-r--r-- | src/yellow/mod.rs | 42 | ||||
-rw-r--r-- | src/yellow/red.rs | 87 | ||||
-rw-r--r-- | src/yellow/syntax.rs | 132 |
9 files changed, 606 insertions, 12 deletions
diff --git a/src/lib.rs b/src/lib.rs index b90b70c05..cf2e97024 100644 --- a/src/lib.rs +++ b/src/lib.rs | |||
@@ -12,7 +12,8 @@ | |||
12 | //! [RFC.md]: <https://github.com/matklad/libsyntax2/blob/master/docs/RFC.md> | 12 | //! [RFC.md]: <https://github.com/matklad/libsyntax2/blob/master/docs/RFC.md> |
13 | 13 | ||
14 | #![forbid(missing_debug_implementations, unconditional_recursion, future_incompatible)] | 14 | #![forbid(missing_debug_implementations, unconditional_recursion, future_incompatible)] |
15 | #![deny(bad_style, unsafe_code, missing_docs)] | 15 | #![deny(bad_style, missing_docs)] |
16 | #![allow(missing_docs)] | ||
16 | //#![warn(unreachable_pub)] // rust-lang/rust#47816 | 17 | //#![warn(unreachable_pub)] // rust-lang/rust#47816 |
17 | 18 | ||
18 | extern crate unicode_xid; | 19 | extern crate unicode_xid; |
@@ -21,19 +22,24 @@ extern crate text_unit; | |||
21 | mod tree; | 22 | mod tree; |
22 | mod lexer; | 23 | mod lexer; |
23 | mod parser; | 24 | mod parser; |
25 | mod yellow; | ||
24 | 26 | ||
25 | pub mod syntax_kinds; | 27 | pub mod syntax_kinds; |
26 | pub use text_unit::{TextRange, TextUnit}; | 28 | pub use text_unit::{TextRange, TextUnit}; |
27 | pub use tree::{File, Node, SyntaxKind, Token}; | 29 | pub use tree::{File, Node, SyntaxKind, Token}; |
28 | pub(crate) use tree::{ErrorMsg, FileBuilder, Sink}; | 30 | pub(crate) use tree::{ErrorMsg, FileBuilder, Sink, GreenBuilder}; |
29 | pub use lexer::{next_token, tokenize}; | 31 | pub use lexer::{next_token, tokenize}; |
30 | pub use parser::parse; | 32 | pub use yellow::SyntaxNode; |
33 | pub(crate) use yellow::SError; | ||
34 | pub use parser::{parse, parse_green}; | ||
31 | 35 | ||
32 | /// Utilities for simple uses of the parser. | 36 | /// Utilities for simple uses of the parser. |
33 | pub mod utils { | 37 | pub mod utils { |
34 | use std::fmt::Write; | 38 | use std::fmt::Write; |
35 | 39 | ||
36 | use {File, Node}; | 40 | use {File, Node, SyntaxNode}; |
41 | use std::collections::BTreeSet; | ||
42 | use SError; | ||
37 | 43 | ||
38 | /// Parse a file and create a string representation of the resulting parse tree. | 44 | /// Parse a file and create a string representation of the resulting parse tree. |
39 | pub fn dump_tree(file: &File) -> String { | 45 | pub fn dump_tree(file: &File) -> String { |
@@ -65,4 +71,42 @@ pub mod utils { | |||
65 | } | 71 | } |
66 | } | 72 | } |
67 | } | 73 | } |
74 | |||
75 | /// Parse a file and create a string representation of the resulting parse tree. | ||
76 | pub fn dump_tree_green(syntax: &SyntaxNode) -> String { | ||
77 | let mut errors: BTreeSet<_> = syntax.root.errors.iter().cloned().collect(); | ||
78 | let mut result = String::new(); | ||
79 | go(syntax, &mut result, 0, &mut errors); | ||
80 | return result; | ||
81 | |||
82 | fn go(node: &SyntaxNode, buff: &mut String, level: usize, errors: &mut BTreeSet<SError>) { | ||
83 | buff.push_str(&String::from(" ").repeat(level)); | ||
84 | write!(buff, "{:?}\n", node).unwrap(); | ||
85 | // let my_errors = node.errors().filter(|e| e.after_child().is_none()); | ||
86 | // let parent_errors = node.parent() | ||
87 | // .into_iter() | ||
88 | // .flat_map(|n| n.errors()) | ||
89 | // .filter(|e| e.after_child() == Some(node)); | ||
90 | // | ||
91 | let my_errors: Vec<_> = errors.iter().filter(|e| e.offset == node.range().start()) | ||
92 | .cloned().collect(); | ||
93 | for err in my_errors { | ||
94 | errors.remove(&err); | ||
95 | buff.push_str(&String::from(" ").repeat(level)); | ||
96 | write!(buff, "err: `{}`\n", err.message).unwrap(); | ||
97 | } | ||
98 | |||
99 | for child in node.children().iter() { | ||
100 | go(child, buff, level + 1, errors) | ||
101 | } | ||
102 | |||
103 | let my_errors: Vec<_> = errors.iter().filter(|e| e.offset == node.range().end()) | ||
104 | .cloned().collect(); | ||
105 | for err in my_errors { | ||
106 | errors.remove(&err); | ||
107 | buff.push_str(&String::from(" ").repeat(level)); | ||
108 | write!(buff, "err: `{}`\n", err.message).unwrap(); | ||
109 | } | ||
110 | } | ||
111 | } | ||
68 | } | 112 | } |
diff --git a/src/parser/event.rs b/src/parser/event.rs index ac8a55de9..0fbfaeb9f 100644 --- a/src/parser/event.rs +++ b/src/parser/event.rs | |||
@@ -1,5 +1,5 @@ | |||
1 | use { | 1 | use { |
2 | ErrorMsg, File, FileBuilder, Sink, SyntaxKind, Token, | 2 | ErrorMsg, File, FileBuilder, Sink, SyntaxKind, Token, GreenBuilder, |
3 | syntax_kinds::TOMBSTONE, | 3 | syntax_kinds::TOMBSTONE, |
4 | }; | 4 | }; |
5 | use super::is_insignificant; | 5 | use super::is_insignificant; |
@@ -69,6 +69,11 @@ pub(crate) enum Event { | |||
69 | 69 | ||
70 | pub(super) fn to_file(text: String, tokens: &[Token], events: Vec<Event>) -> File { | 70 | pub(super) fn to_file(text: String, tokens: &[Token], events: Vec<Event>) -> File { |
71 | let mut builder = FileBuilder::new(text); | 71 | let mut builder = FileBuilder::new(text); |
72 | process(&mut builder, tokens, events); | ||
73 | builder.finish() | ||
74 | } | ||
75 | |||
76 | pub(super) fn process(builder: &mut Sink, tokens: &[Token], events: Vec<Event>) { | ||
72 | let mut idx = 0; | 77 | let mut idx = 0; |
73 | 78 | ||
74 | let mut holes = Vec::new(); | 79 | let mut holes = Vec::new(); |
@@ -145,5 +150,4 @@ pub(super) fn to_file(text: String, tokens: &[Token], events: Vec<Event>) -> Fil | |||
145 | &Event::Error { ref msg } => builder.error(ErrorMsg { msg: msg.clone() }), | 150 | &Event::Error { ref msg } => builder.error(ErrorMsg { msg: msg.clone() }), |
146 | } | 151 | } |
147 | } | 152 | } |
148 | builder.finish() | ||
149 | } | 153 | } |
diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 3814837e1..26fbb6e3d 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs | |||
@@ -1,7 +1,3 @@ | |||
1 | use {File, SyntaxKind, Token}; | ||
2 | |||
3 | use syntax_kinds::*; | ||
4 | |||
5 | #[macro_use] | 1 | #[macro_use] |
6 | mod token_set; | 2 | mod token_set; |
7 | mod parser; | 3 | mod parser; |
@@ -9,6 +5,16 @@ mod input; | |||
9 | mod event; | 5 | mod event; |
10 | mod grammar; | 6 | mod grammar; |
11 | 7 | ||
8 | use std::sync::Arc; | ||
9 | use { | ||
10 | File, SyntaxKind, Token, | ||
11 | yellow::SyntaxNode, | ||
12 | syntax_kinds::* | ||
13 | }; | ||
14 | use GreenBuilder; | ||
15 | use parser::event::process; | ||
16 | |||
17 | |||
12 | /// Parse a sequence of tokens into the representative node tree | 18 | /// Parse a sequence of tokens into the representative node tree |
13 | pub fn parse(text: String, tokens: &[Token]) -> File { | 19 | pub fn parse(text: String, tokens: &[Token]) -> File { |
14 | let events = { | 20 | let events = { |
@@ -21,6 +27,21 @@ pub fn parse(text: String, tokens: &[Token]) -> File { | |||
21 | event::to_file(text, tokens, events) | 27 | event::to_file(text, tokens, events) |
22 | } | 28 | } |
23 | 29 | ||
30 | /// Parse a sequence of tokens into the representative node tree | ||
31 | pub fn parse_green(text: String, tokens: &[Token]) -> SyntaxNode { | ||
32 | let events = { | ||
33 | let input = input::ParserInput::new(&text, tokens); | ||
34 | let parser_impl = parser::imp::ParserImpl::new(&input); | ||
35 | let mut parser = parser::Parser(parser_impl); | ||
36 | grammar::file(&mut parser); | ||
37 | parser.0.into_events() | ||
38 | }; | ||
39 | let mut builder = GreenBuilder::new(text); | ||
40 | process(&mut builder, tokens, events); | ||
41 | let (green, errors) = builder.finish(); | ||
42 | SyntaxNode::new(Arc::new(green), errors) | ||
43 | } | ||
44 | |||
24 | fn is_insignificant(kind: SyntaxKind) -> bool { | 45 | fn is_insignificant(kind: SyntaxKind) -> bool { |
25 | match kind { | 46 | match kind { |
26 | WHITESPACE | COMMENT => true, | 47 | WHITESPACE | COMMENT => true, |
diff --git a/src/tree/file_builder.rs b/src/tree/file_builder.rs index 712602168..4983006cd 100644 --- a/src/tree/file_builder.rs +++ b/src/tree/file_builder.rs | |||
@@ -7,8 +7,13 @@ | |||
7 | //! tree builder: the parser produces a stream of events like | 7 | //! tree builder: the parser produces a stream of events like |
8 | //! `start node`, `finish node`, and `FileBuilder` converts | 8 | //! `start node`, `finish node`, and `FileBuilder` converts |
9 | //! this stream to a real tree. | 9 | //! this stream to a real tree. |
10 | use {SyntaxKind, TextRange, TextUnit}; | 10 | use std::sync::Arc; |
11 | use { | ||
12 | SyntaxKind, TextRange, TextUnit, | ||
13 | yellow::GreenNode | ||
14 | }; | ||
11 | use super::{File, NodeData, NodeIdx, SyntaxErrorData}; | 15 | use super::{File, NodeData, NodeIdx, SyntaxErrorData}; |
16 | use SError; | ||
12 | 17 | ||
13 | pub(crate) trait Sink { | 18 | pub(crate) trait Sink { |
14 | fn leaf(&mut self, kind: SyntaxKind, len: TextUnit); | 19 | fn leaf(&mut self, kind: SyntaxKind, len: TextUnit); |
@@ -159,3 +164,68 @@ fn grow(left: &mut TextRange, right: TextRange) { | |||
159 | pub(crate) struct ErrorMsg { | 164 | pub(crate) struct ErrorMsg { |
160 | pub(crate) msg: String, | 165 | pub(crate) msg: String, |
161 | } | 166 | } |
167 | |||
168 | pub(crate) struct GreenBuilder { | ||
169 | text: String, | ||
170 | stack: Vec<GreenNode>, | ||
171 | pos: TextUnit, | ||
172 | root: Option<GreenNode>, | ||
173 | errors: Vec<SError>, | ||
174 | } | ||
175 | |||
176 | impl GreenBuilder { | ||
177 | pub(crate) fn new(text: String) -> GreenBuilder { | ||
178 | GreenBuilder { | ||
179 | text, | ||
180 | stack: Vec::new(), | ||
181 | pos: 0.into(), | ||
182 | root: None, | ||
183 | errors: Vec::new(), | ||
184 | } | ||
185 | } | ||
186 | |||
187 | pub(crate) fn finish(self) -> (GreenNode, Vec<SError>) { | ||
188 | (self.root.unwrap(), self.errors) | ||
189 | } | ||
190 | } | ||
191 | |||
192 | impl Sink for GreenBuilder { | ||
193 | fn leaf(&mut self, kind: SyntaxKind, len: TextUnit) { | ||
194 | let range = TextRange::offset_len(self.pos, len); | ||
195 | self.pos += len; | ||
196 | let text = self.text[range].to_owned(); | ||
197 | let parent = self.stack.last_mut().unwrap(); | ||
198 | if kind.is_trivia() { | ||
199 | parent.push_trivia(kind, text); | ||
200 | } else { | ||
201 | let node = GreenNode::new_leaf(kind, text); | ||
202 | parent.push_child(Arc::new(node)); | ||
203 | } | ||
204 | } | ||
205 | |||
206 | fn start_internal(&mut self, kind: SyntaxKind) { | ||
207 | self.stack.push(GreenNode::new_branch(kind)) | ||
208 | } | ||
209 | |||
210 | fn finish_internal(&mut self) { | ||
211 | let node = self.stack.pop().unwrap(); | ||
212 | if let Some(parent) = self.stack.last_mut() { | ||
213 | parent.push_child(Arc::new(node)) | ||
214 | } else { | ||
215 | self.root = Some(node); | ||
216 | } | ||
217 | } | ||
218 | |||
219 | fn error(&mut self, err: ErrorMsg) { | ||
220 | self.errors.push(SError { message: err.msg, offset: self.pos }) | ||
221 | } | ||
222 | } | ||
223 | impl SyntaxKind { | ||
224 | fn is_trivia(self) -> bool { | ||
225 | match self { | ||
226 | SyntaxKind::WHITESPACE | SyntaxKind::DOC_COMMENT | SyntaxKind::COMMENT => true, | ||
227 | _ => false | ||
228 | } | ||
229 | } | ||
230 | } | ||
231 | |||
diff --git a/src/tree/mod.rs b/src/tree/mod.rs index f7b16d7b5..7abe17592 100644 --- a/src/tree/mod.rs +++ b/src/tree/mod.rs | |||
@@ -2,7 +2,7 @@ mod file_builder; | |||
2 | 2 | ||
3 | use ::{TextRange, TextUnit}; | 3 | use ::{TextRange, TextUnit}; |
4 | use std::{fmt, cmp}; | 4 | use std::{fmt, cmp}; |
5 | pub(crate) use self::file_builder::{ErrorMsg, FileBuilder, Sink}; | 5 | pub(crate) use self::file_builder::{ErrorMsg, FileBuilder, Sink, GreenBuilder}; |
6 | 6 | ||
7 | pub use syntax_kinds::SyntaxKind; | 7 | pub use syntax_kinds::SyntaxKind; |
8 | 8 | ||
diff --git a/src/yellow/green.rs b/src/yellow/green.rs new file mode 100644 index 000000000..ede23b719 --- /dev/null +++ b/src/yellow/green.rs | |||
@@ -0,0 +1,194 @@ | |||
1 | use std::sync::Arc; | ||
2 | use text_unit::TextUnit; | ||
3 | use SyntaxKind; | ||
4 | |||
5 | type TokenText = String; | ||
6 | |||
7 | #[derive(Debug)] | ||
8 | pub(crate) struct GreenNode { | ||
9 | kind: SyntaxKind, | ||
10 | data: GreenNodeData, | ||
11 | } | ||
12 | |||
13 | impl GreenNode { | ||
14 | pub(crate) fn new_leaf(kind: SyntaxKind, text: TokenText) -> GreenNode { | ||
15 | GreenNode { | ||
16 | kind, | ||
17 | data: GreenNodeData::Leaf(GreenLeaf { text }), | ||
18 | } | ||
19 | } | ||
20 | |||
21 | pub(crate) fn new_branch( | ||
22 | kind: SyntaxKind, | ||
23 | ) -> GreenNode { | ||
24 | let branch = GreenBranch { | ||
25 | text_len: 0.into(), | ||
26 | leading_trivia: Trivias::default(), | ||
27 | children: Vec::new(), | ||
28 | }; | ||
29 | GreenNode { | ||
30 | kind, | ||
31 | data: GreenNodeData::Branch(branch), | ||
32 | } | ||
33 | } | ||
34 | |||
35 | pub(crate) fn push_trivia(&mut self, kind: SyntaxKind, text: TokenText) { | ||
36 | let branch = match &mut self.data { | ||
37 | GreenNodeData::Branch(branch) => branch, | ||
38 | _ => panic!() | ||
39 | }; | ||
40 | branch.text_len += TextUnit::of_str(&text); | ||
41 | let leading = &mut branch.leading_trivia; | ||
42 | branch.children.last_mut().map(|(_, t)| t).unwrap_or(leading) | ||
43 | .push(Arc::new(GreenTrivia { kind, text })); | ||
44 | } | ||
45 | |||
46 | pub(crate) fn push_child(&mut self, node: Arc<GreenNode>) { | ||
47 | let branch = match &mut self.data { | ||
48 | GreenNodeData::Branch(branch) => branch, | ||
49 | _ => panic!() | ||
50 | }; | ||
51 | branch.text_len += node.text_len(); | ||
52 | branch.children.push((node, Trivias::default())); | ||
53 | } | ||
54 | |||
55 | pub(crate) fn kind(&self) -> SyntaxKind { | ||
56 | self.kind | ||
57 | } | ||
58 | |||
59 | pub(crate) fn text_len(&self) -> TextUnit { | ||
60 | match &self.data { | ||
61 | GreenNodeData::Leaf(l) => l.text_len(), | ||
62 | GreenNodeData::Branch(b) => b.text_len(), | ||
63 | } | ||
64 | } | ||
65 | |||
66 | pub(crate) fn text(&self) -> String { | ||
67 | let mut buff = String::new(); | ||
68 | go(self, &mut buff); | ||
69 | return buff; | ||
70 | fn go(node: &GreenNode, buff: &mut String) { | ||
71 | match &node.data { | ||
72 | GreenNodeData::Leaf(l) => buff.push_str(&l.text), | ||
73 | GreenNodeData::Branch(branch) => { | ||
74 | add_trivia(&branch.leading_trivia, buff); | ||
75 | branch.children.iter().for_each(|(child, trivias)| { | ||
76 | go(child, buff); | ||
77 | add_trivia(trivias, buff); | ||
78 | }) | ||
79 | } | ||
80 | } | ||
81 | } | ||
82 | |||
83 | fn add_trivia(trivias: &Trivias, buff: &mut String) { | ||
84 | trivias.iter().for_each(|t| buff.push_str(&t.text)) | ||
85 | } | ||
86 | } | ||
87 | |||
88 | pub(crate) fn n_children(&self) -> usize { | ||
89 | match &self.data { | ||
90 | GreenNodeData::Leaf(_) => 0, | ||
91 | GreenNodeData::Branch(branch) => branch.children.len(), | ||
92 | } | ||
93 | } | ||
94 | |||
95 | pub(crate) fn nth_child(&self, idx: usize) -> &Arc<GreenNode> { | ||
96 | match &self.data { | ||
97 | GreenNodeData::Leaf(_) => panic!("leaf nodes have no children"), | ||
98 | GreenNodeData::Branch(branch) => &branch.children[idx].0, | ||
99 | } | ||
100 | } | ||
101 | |||
102 | pub(crate) fn nth_trivias(&self, idx: usize) -> &Trivias { | ||
103 | match &self.data { | ||
104 | GreenNodeData::Leaf(_) => panic!("leaf nodes have no children"), | ||
105 | GreenNodeData::Branch(branch) => if idx == 0 { | ||
106 | &branch.leading_trivia | ||
107 | } else { | ||
108 | &branch.children[idx - 1].1 | ||
109 | }, | ||
110 | } | ||
111 | } | ||
112 | |||
113 | pub(crate) fn is_leaf(&self) -> bool { | ||
114 | match self.data { | ||
115 | GreenNodeData::Leaf(_) => true, | ||
116 | GreenNodeData::Branch(_) => false | ||
117 | } | ||
118 | } | ||
119 | |||
120 | pub(crate) fn leaf_text(&self) -> &str { | ||
121 | match &self.data { | ||
122 | GreenNodeData::Leaf(l) => l.text.as_str(), | ||
123 | GreenNodeData::Branch(_) => panic!("not a leaf") | ||
124 | } | ||
125 | } | ||
126 | } | ||
127 | |||
128 | #[derive(Debug)] | ||
129 | enum GreenNodeData { | ||
130 | Leaf(GreenLeaf), | ||
131 | Branch(GreenBranch), | ||
132 | } | ||
133 | |||
134 | #[derive(Debug)] | ||
135 | struct GreenLeaf { | ||
136 | text: TokenText | ||
137 | } | ||
138 | |||
139 | #[derive(Debug)] | ||
140 | struct GreenBranch { | ||
141 | text_len: TextUnit, | ||
142 | leading_trivia: Trivias, | ||
143 | children: Vec<(Arc<GreenNode>, Trivias)>, | ||
144 | } | ||
145 | |||
146 | #[derive(Debug)] | ||
147 | pub(crate) struct GreenTrivia { | ||
148 | pub(crate) kind: SyntaxKind, | ||
149 | pub(crate) text: TokenText, | ||
150 | } | ||
151 | |||
152 | type Trivias = Vec<Arc<GreenTrivia>>; | ||
153 | |||
154 | |||
155 | pub(crate) trait TextLen { | ||
156 | fn text_len(&self) -> TextUnit; | ||
157 | } | ||
158 | |||
159 | impl TextLen for GreenTrivia { | ||
160 | fn text_len(&self) -> TextUnit { | ||
161 | TextUnit::of_str(&self.text) | ||
162 | } | ||
163 | } | ||
164 | |||
165 | impl<T: TextLen> TextLen for Arc<T> { | ||
166 | fn text_len(&self) -> TextUnit { | ||
167 | let this: &T = self; | ||
168 | this.text_len() | ||
169 | } | ||
170 | } | ||
171 | |||
172 | impl TextLen for GreenNode { | ||
173 | fn text_len(&self) -> TextUnit { | ||
174 | self.text_len() | ||
175 | } | ||
176 | } | ||
177 | |||
178 | impl TextLen for GreenLeaf { | ||
179 | fn text_len(&self) -> TextUnit { | ||
180 | TextUnit::of_str(&self.text) | ||
181 | } | ||
182 | } | ||
183 | |||
184 | impl TextLen for GreenBranch { | ||
185 | fn text_len(&self) -> TextUnit { | ||
186 | self.text_len | ||
187 | } | ||
188 | } | ||
189 | |||
190 | impl<T: TextLen> TextLen for [T] { | ||
191 | fn text_len(&self) -> TextUnit { | ||
192 | self.iter().map(TextLen::text_len).sum() | ||
193 | } | ||
194 | } | ||
diff --git a/src/yellow/mod.rs b/src/yellow/mod.rs new file mode 100644 index 000000000..236328a7f --- /dev/null +++ b/src/yellow/mod.rs | |||
@@ -0,0 +1,42 @@ | |||
1 | mod green; | ||
2 | mod red; | ||
3 | mod syntax; | ||
4 | |||
5 | use std::{ | ||
6 | sync::{Arc, Weak}, | ||
7 | ops::Deref, | ||
8 | mem | ||
9 | }; | ||
10 | pub(crate) use self::{ | ||
11 | green::{GreenNode, TextLen}, | ||
12 | red::RedNode, | ||
13 | syntax::SError, | ||
14 | }; | ||
15 | pub use self::syntax::SyntaxNode; | ||
16 | |||
17 | // This could be just `*const T`, but we use `Weak` for additional checks | ||
18 | #[derive(Debug)] | ||
19 | pub(crate) struct Ptr<T>(Weak<T>); | ||
20 | |||
21 | impl<T> Clone for Ptr<T> { | ||
22 | fn clone(&self) -> Self { | ||
23 | Ptr(self.0.clone()) | ||
24 | } | ||
25 | } | ||
26 | |||
27 | impl<T> Ptr<T> { | ||
28 | fn clone(self_: &Ptr<T>) -> Ptr<T> { | ||
29 | Ptr(Weak::clone(&self_.0)) | ||
30 | } | ||
31 | |||
32 | fn new(arc: &Arc<T>) -> Ptr<T> { | ||
33 | Ptr(Arc::downgrade(arc)) | ||
34 | } | ||
35 | |||
36 | unsafe fn get(&self) -> &T { | ||
37 | let t = self.0.upgrade() | ||
38 | .expect("caller must guarantee that Ptr is not null"); | ||
39 | let t: &T = &*t; | ||
40 | mem::transmute(t) | ||
41 | } | ||
42 | } | ||
diff --git a/src/yellow/red.rs b/src/yellow/red.rs new file mode 100644 index 000000000..feba99faa --- /dev/null +++ b/src/yellow/red.rs | |||
@@ -0,0 +1,87 @@ | |||
1 | use std::sync::{Arc, Weak, RwLock}; | ||
2 | use { | ||
3 | TextUnit, SyntaxKind, TextRange, | ||
4 | yellow::{Ptr, GreenNode, TextLen} | ||
5 | }; | ||
6 | |||
7 | #[derive(Debug)] | ||
8 | pub(crate) struct RedNode { | ||
9 | green: Arc<GreenNode>, | ||
10 | parent: Option<ParentData>, | ||
11 | children: RwLock<Vec<Option<Arc<RedNode>>>>, | ||
12 | } | ||
13 | |||
14 | #[derive(Debug)] | ||
15 | struct ParentData { | ||
16 | parent: Ptr<RedNode>, | ||
17 | start_offset: TextUnit, | ||
18 | index_in_parent: usize, | ||
19 | } | ||
20 | |||
21 | impl RedNode { | ||
22 | pub fn new_root( | ||
23 | green: Arc<GreenNode>, | ||
24 | ) -> RedNode { | ||
25 | RedNode::new(green, None) | ||
26 | } | ||
27 | |||
28 | fn new_child( | ||
29 | green: Arc<GreenNode>, | ||
30 | parent: Ptr<RedNode>, | ||
31 | start_offset: TextUnit, | ||
32 | index_in_parent: usize | ||
33 | ) -> RedNode { | ||
34 | let parent_data = ParentData { | ||
35 | parent, | ||
36 | start_offset, | ||
37 | index_in_parent | ||
38 | }; | ||
39 | RedNode::new(green, Some(parent_data)) | ||
40 | } | ||
41 | |||
42 | fn new( | ||
43 | green: Arc<GreenNode>, | ||
44 | parent: Option<ParentData>, | ||
45 | ) -> RedNode { | ||
46 | let children = vec![None; green.n_children()]; | ||
47 | RedNode { green, parent, children: RwLock::new(children) } | ||
48 | } | ||
49 | |||
50 | pub(crate) fn green(&self) -> &GreenNode { | ||
51 | &self.green | ||
52 | } | ||
53 | |||
54 | pub(crate) fn start_offset(&self) -> TextUnit { | ||
55 | match &self.parent { | ||
56 | None => 0.into(), | ||
57 | Some(p) => p.start_offset, | ||
58 | } | ||
59 | } | ||
60 | |||
61 | pub(crate) fn n_children(&self) -> usize { | ||
62 | self.green.n_children() | ||
63 | } | ||
64 | |||
65 | pub(crate) fn nth_child(&self, me: Ptr<RedNode>, n: usize) -> Arc<RedNode> { | ||
66 | match &self.children.read().unwrap()[n] { | ||
67 | Some(child) => return child.clone(), | ||
68 | None => (), | ||
69 | } | ||
70 | let mut children = self.children.write().unwrap(); | ||
71 | if children[n].is_none() { | ||
72 | let start_offset = { | ||
73 | let mut acc = self.start_offset(); | ||
74 | for i in 0..n { | ||
75 | acc += self.green.nth_trivias(i).text_len(); | ||
76 | acc += self.green.nth_child(i).text_len(); | ||
77 | } | ||
78 | acc += self.green.nth_trivias(n).text_len(); | ||
79 | acc | ||
80 | }; | ||
81 | let green = self.green.nth_child(n).clone(); | ||
82 | let child = RedNode::new_child(green, me, start_offset, n); | ||
83 | children[n] = Some(Arc::new(child)) | ||
84 | } | ||
85 | children[n].as_ref().unwrap().clone() | ||
86 | } | ||
87 | } | ||
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 | } | ||