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 | |
parent | 8d9961b75377a7bd2656b5aa1451710de8c86f60 (diff) |
Introduce red-green syntax tree
24 files changed, 660 insertions, 63 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 | } | ||
diff --git a/tests/data/parser/err/0000_struct_field_missing_comma.txt b/tests/data/parser/err/0000_struct_field_missing_comma.txt index 5196fd718..2bb3ee6ec 100644 --- a/tests/data/parser/err/0000_struct_field_missing_comma.txt +++ b/tests/data/parser/err/0000_struct_field_missing_comma.txt | |||
@@ -18,7 +18,7 @@ FILE@[0; 34) | |||
18 | WHITESPACE@[17; 18) | 18 | WHITESPACE@[17; 18) |
19 | IDENT@[18; 21) "u32" | 19 | IDENT@[18; 21) "u32" |
20 | WHITESPACE@[21; 26) | 20 | WHITESPACE@[21; 26) |
21 | err: `expected COMMA` | 21 | err: `expected COMMA` |
22 | NAMED_FIELD@[26; 33) | 22 | NAMED_FIELD@[26; 33) |
23 | NAME@[26; 27) | 23 | NAME@[26; 27) |
24 | IDENT@[26; 27) "b" | 24 | IDENT@[26; 27) "b" |
diff --git a/tests/data/parser/err/0001_item_recovery_in_file.txt b/tests/data/parser/err/0001_item_recovery_in_file.txt index e41ddc009..01bd2abe6 100644 --- a/tests/data/parser/err/0001_item_recovery_in_file.txt +++ b/tests/data/parser/err/0001_item_recovery_in_file.txt | |||
@@ -1,10 +1,10 @@ | |||
1 | FILE@[0; 21) | 1 | FILE@[0; 21) |
2 | err: `expected item` | ||
2 | ERROR@[0; 3) | 3 | ERROR@[0; 3) |
3 | err: `expected item` | ||
4 | IF_KW@[0; 2) | 4 | IF_KW@[0; 2) |
5 | WHITESPACE@[2; 3) | 5 | WHITESPACE@[2; 3) |
6 | err: `expected item` | ||
6 | ERROR@[3; 10) | 7 | ERROR@[3; 10) |
7 | err: `expected item` | ||
8 | MATCH_KW@[3; 8) | 8 | MATCH_KW@[3; 8) |
9 | WHITESPACE@[8; 10) | 9 | WHITESPACE@[8; 10) |
10 | STRUCT_ITEM@[10; 21) | 10 | STRUCT_ITEM@[10; 21) |
diff --git a/tests/data/parser/err/0002_duplicate_shebang.txt b/tests/data/parser/err/0002_duplicate_shebang.txt index e7cf7187d..1a4b37da8 100644 --- a/tests/data/parser/err/0002_duplicate_shebang.txt +++ b/tests/data/parser/err/0002_duplicate_shebang.txt | |||
@@ -1,7 +1,7 @@ | |||
1 | FILE@[0; 42) | 1 | FILE@[0; 42) |
2 | SHEBANG@[0; 20) | 2 | SHEBANG@[0; 20) |
3 | ERROR@[20; 42) | ||
4 | err: `expected item` | 3 | err: `expected item` |
4 | ERROR@[20; 42) | ||
5 | WHITESPACE@[20; 21) | 5 | WHITESPACE@[20; 21) |
6 | SHEBANG@[21; 41) | 6 | SHEBANG@[21; 41) |
7 | WHITESPACE@[41; 42) | 7 | WHITESPACE@[41; 42) |
diff --git a/tests/data/parser/err/0003_C++_semicolon.txt b/tests/data/parser/err/0003_C++_semicolon.txt index affe8fd09..dc3cf6c73 100644 --- a/tests/data/parser/err/0003_C++_semicolon.txt +++ b/tests/data/parser/err/0003_C++_semicolon.txt | |||
@@ -32,7 +32,7 @@ FILE@[0; 40) | |||
32 | COMMA@[36; 37) | 32 | COMMA@[36; 37) |
33 | WHITESPACE@[37; 38) | 33 | WHITESPACE@[37; 38) |
34 | R_CURLY@[38; 39) | 34 | R_CURLY@[38; 39) |
35 | ERROR@[39; 40) | 35 | err: `expected item, found `;` |
36 | err: `expected item, found `;` | ||
37 | consider removing this semicolon` | 36 | consider removing this semicolon` |
37 | ERROR@[39; 40) | ||
38 | SEMI@[39; 40) | 38 | SEMI@[39; 40) |
diff --git a/tests/data/parser/err/0004_use_path_bad_segment.txt b/tests/data/parser/err/0004_use_path_bad_segment.txt index 0a67002ac..d9ff79ebe 100644 --- a/tests/data/parser/err/0004_use_path_bad_segment.txt +++ b/tests/data/parser/err/0004_use_path_bad_segment.txt | |||
@@ -9,13 +9,13 @@ FILE@[0; 12) | |||
9 | WHITESPACE@[3; 4) | 9 | WHITESPACE@[3; 4) |
10 | IDENT@[4; 7) "foo" | 10 | IDENT@[4; 7) "foo" |
11 | COLONCOLON@[7; 9) | 11 | COLONCOLON@[7; 9) |
12 | PATH_SEGMENT@[9; 9) | 12 | err: `expected SEMI` |
13 | err: `expected identifier` | 13 | err: `expected identifier` |
14 | err: `expected SEMI` | 14 | err: `expected item` |
15 | PATH_SEGMENT@[9; 9) | ||
15 | ERROR@[9; 11) | 16 | ERROR@[9; 11) |
16 | err: `expected item` | ||
17 | INT_NUMBER@[9; 11) | 17 | INT_NUMBER@[9; 11) |
18 | ERROR@[11; 12) | 18 | err: `expected item, found `;` |
19 | err: `expected item, found `;` | ||
20 | consider removing this semicolon` | 19 | consider removing this semicolon` |
20 | ERROR@[11; 12) | ||
21 | SEMI@[11; 12) | 21 | SEMI@[11; 12) |
diff --git a/tests/data/parser/err/0005_attribute_recover.txt b/tests/data/parser/err/0005_attribute_recover.txt index 731f5f2f8..74dd38959 100644 --- a/tests/data/parser/err/0005_attribute_recover.txt +++ b/tests/data/parser/err/0005_attribute_recover.txt | |||
@@ -9,12 +9,12 @@ FILE@[0; 54) | |||
9 | META_ITEM@[6; 9) | 9 | META_ITEM@[6; 9) |
10 | IDENT@[6; 9) "foo" | 10 | IDENT@[6; 9) "foo" |
11 | COMMA@[9; 10) | 11 | COMMA@[9; 10) |
12 | ERROR@[10; 12) | ||
13 | err: `expected attribute` | 12 | err: `expected attribute` |
13 | ERROR@[10; 12) | ||
14 | WHITESPACE@[10; 11) | 14 | WHITESPACE@[10; 11) |
15 | PLUS@[11; 12) | 15 | PLUS@[11; 12) |
16 | err: `expected attribute` | ||
16 | ERROR@[12; 14) | 17 | ERROR@[12; 14) |
17 | err: `expected attribute` | ||
18 | COMMA@[12; 13) | 18 | COMMA@[12; 13) |
19 | WHITESPACE@[13; 14) | 19 | WHITESPACE@[13; 14) |
20 | LITERAL@[14; 16) | 20 | LITERAL@[14; 16) |
@@ -43,7 +43,7 @@ FILE@[0; 54) | |||
43 | L_PAREN@[39; 40) | 43 | L_PAREN@[39; 40) |
44 | err: `expected attribute` | 44 | err: `expected attribute` |
45 | WHITESPACE@[40; 41) | 45 | WHITESPACE@[40; 41) |
46 | err: `expected R_BRACK` | 46 | err: `expected R_BRACK` |
47 | FN_KW@[41; 43) | 47 | FN_KW@[41; 43) |
48 | NAME@[43; 47) | 48 | NAME@[43; 47) |
49 | WHITESPACE@[43; 44) | 49 | WHITESPACE@[43; 44) |
diff --git a/tests/data/parser/err/0006_named_field_recovery.txt b/tests/data/parser/err/0006_named_field_recovery.txt index 2dec74866..cb5a9c32c 100644 --- a/tests/data/parser/err/0006_named_field_recovery.txt +++ b/tests/data/parser/err/0006_named_field_recovery.txt | |||
@@ -22,23 +22,26 @@ FILE@[0; 74) | |||
22 | WHITESPACE@[22; 27) | 22 | WHITESPACE@[22; 27) |
23 | PUB_KW@[27; 30) | 23 | PUB_KW@[27; 30) |
24 | WHITESPACE@[30; 31) | 24 | WHITESPACE@[30; 31) |
25 | err: `expected field declaration` | ||
25 | ERROR@[31; 38) | 26 | ERROR@[31; 38) |
26 | err: `expected field declaration` | ||
27 | INT_NUMBER@[31; 33) | 27 | INT_NUMBER@[31; 33) |
28 | WHITESPACE@[33; 38) | 28 | WHITESPACE@[33; 38) |
29 | err: `expected COMMA` | 29 | err: `expected COMMA` |
30 | err: `expected field declaration` | ||
30 | ERROR@[38; 40) | 31 | ERROR@[38; 40) |
31 | err: `expected field declaration` | ||
32 | PLUS@[38; 39) | 32 | PLUS@[38; 39) |
33 | WHITESPACE@[39; 40) | 33 | WHITESPACE@[39; 40) |
34 | err: `expected COMMA` | ||
35 | err: `expected field declaration` | ||
34 | ERROR@[40; 42) | 36 | ERROR@[40; 42) |
35 | err: `expected field declaration` | ||
36 | MINUS@[40; 41) | 37 | MINUS@[40; 41) |
37 | WHITESPACE@[41; 42) | 38 | WHITESPACE@[41; 42) |
39 | err: `expected COMMA` | ||
40 | err: `expected field declaration` | ||
38 | ERROR@[42; 48) | 41 | ERROR@[42; 48) |
39 | err: `expected field declaration` | ||
40 | STAR@[42; 43) | 42 | STAR@[42; 43) |
41 | WHITESPACE@[43; 48) | 43 | WHITESPACE@[43; 48) |
44 | err: `expected COMMA` | ||
42 | NAMED_FIELD@[48; 58) | 45 | NAMED_FIELD@[48; 58) |
43 | VISIBILITY@[48; 52) | 46 | VISIBILITY@[48; 52) |
44 | PUB_KW@[48; 51) | 47 | PUB_KW@[48; 51) |
diff --git a/tests/data/parser/err/0007_stray_curly_in_file.txt b/tests/data/parser/err/0007_stray_curly_in_file.txt index 8a3cb5096..cfc714cc6 100644 --- a/tests/data/parser/err/0007_stray_curly_in_file.txt +++ b/tests/data/parser/err/0007_stray_curly_in_file.txt | |||
@@ -1,6 +1,6 @@ | |||
1 | FILE@[0; 31) | 1 | FILE@[0; 31) |
2 | err: `expected item` | ||
2 | ERROR@[0; 3) | 3 | ERROR@[0; 3) |
3 | err: `expected item` | ||
4 | R_CURLY@[0; 1) | 4 | R_CURLY@[0; 1) |
5 | WHITESPACE@[1; 3) | 5 | WHITESPACE@[1; 3) |
6 | STRUCT_ITEM@[3; 14) | 6 | STRUCT_ITEM@[3; 14) |
@@ -10,8 +10,8 @@ FILE@[0; 31) | |||
10 | IDENT@[10; 11) "S" | 10 | IDENT@[10; 11) "S" |
11 | SEMI@[11; 12) | 11 | SEMI@[11; 12) |
12 | WHITESPACE@[12; 14) | 12 | WHITESPACE@[12; 14) |
13 | err: `expected item` | ||
13 | ERROR@[14; 17) | 14 | ERROR@[14; 17) |
14 | err: `expected item` | ||
15 | R_CURLY@[14; 15) | 15 | R_CURLY@[14; 15) |
16 | WHITESPACE@[15; 17) | 16 | WHITESPACE@[15; 17) |
17 | FN_ITEM@[17; 29) | 17 | FN_ITEM@[17; 29) |
@@ -25,7 +25,7 @@ FILE@[0; 31) | |||
25 | L_CURLY@[25; 26) | 25 | L_CURLY@[25; 26) |
26 | R_CURLY@[26; 27) | 26 | R_CURLY@[26; 27) |
27 | WHITESPACE@[27; 29) | 27 | WHITESPACE@[27; 29) |
28 | err: `expected item` | ||
28 | ERROR@[29; 31) | 29 | ERROR@[29; 31) |
29 | err: `expected item` | ||
30 | R_CURLY@[29; 30) | 30 | R_CURLY@[29; 30) |
31 | WHITESPACE@[30; 31) | 31 | WHITESPACE@[30; 31) |
diff --git a/tests/data/parser/err/0008_item_block_recovery.txt b/tests/data/parser/err/0008_item_block_recovery.txt index 0e2aae7cc..ca332bcf0 100644 --- a/tests/data/parser/err/0008_item_block_recovery.txt +++ b/tests/data/parser/err/0008_item_block_recovery.txt | |||
@@ -12,18 +12,18 @@ FILE@[0; 95) | |||
12 | WHITESPACE@[10; 11) | 12 | WHITESPACE@[10; 11) |
13 | R_CURLY@[11; 12) | 13 | R_CURLY@[11; 12) |
14 | WHITESPACE@[12; 14) | 14 | WHITESPACE@[12; 14) |
15 | err: `expected item` | ||
15 | ERROR@[14; 17) | 16 | ERROR@[14; 17) |
16 | err: `expected item` | ||
17 | IDENT@[14; 17) "bar" | 17 | IDENT@[14; 17) "bar" |
18 | err: `expected item` | ||
18 | ERROR@[17; 18) | 19 | ERROR@[17; 18) |
19 | err: `expected item` | ||
20 | L_PAREN@[17; 18) | 20 | L_PAREN@[17; 18) |
21 | err: `expected item` | ||
21 | ERROR@[18; 20) | 22 | ERROR@[18; 20) |
22 | err: `expected item` | ||
23 | R_PAREN@[18; 19) | 23 | R_PAREN@[18; 19) |
24 | WHITESPACE@[19; 20) | 24 | WHITESPACE@[19; 20) |
25 | err: `expected item` | ||
25 | ERROR@[20; 82) | 26 | ERROR@[20; 82) |
26 | err: `expected item` | ||
27 | L_CURLY@[20; 21) | 27 | L_CURLY@[20; 21) |
28 | WHITESPACE@[21; 26) | 28 | WHITESPACE@[21; 26) |
29 | IF_KW@[26; 28) | 29 | IF_KW@[26; 28) |
diff --git a/tests/data/parser/err/0009_broken_struct_type_parameter.txt b/tests/data/parser/err/0009_broken_struct_type_parameter.txt index 9434a764a..c16c6dffe 100644 --- a/tests/data/parser/err/0009_broken_struct_type_parameter.txt +++ b/tests/data/parser/err/0009_broken_struct_type_parameter.txt | |||
@@ -6,26 +6,26 @@ FILE@[0; 43) | |||
6 | IDENT@[7; 8) "S" | 6 | IDENT@[7; 8) "S" |
7 | TYPE_PARAM_LIST@[8; 12) | 7 | TYPE_PARAM_LIST@[8; 12) |
8 | L_ANGLE@[8; 9) | 8 | L_ANGLE@[8; 9) |
9 | ERROR@[9; 12) | ||
10 | err: `expected type parameter` | 9 | err: `expected type parameter` |
10 | ERROR@[9; 12) | ||
11 | INT_NUMBER@[9; 11) | 11 | INT_NUMBER@[9; 11) |
12 | WHITESPACE@[11; 12) | 12 | WHITESPACE@[11; 12) |
13 | err: `expected COMMA` | 13 | err: `expected COMMA` |
14 | err: `expected R_ANGLE` | 14 | err: `expected R_ANGLE` |
15 | err: `expected `;`, `{`, or `(`` | 15 | err: `expected `;`, `{`, or `(`` |
16 | err: `expected item` | ||
16 | ERROR@[12; 14) | 17 | ERROR@[12; 14) |
17 | err: `expected item` | ||
18 | PLUS@[12; 13) | 18 | PLUS@[12; 13) |
19 | WHITESPACE@[13; 14) | 19 | WHITESPACE@[13; 14) |
20 | err: `expected item` | ||
20 | ERROR@[14; 15) | 21 | ERROR@[14; 15) |
21 | err: `expected item` | ||
22 | INT_NUMBER@[14; 15) | 22 | INT_NUMBER@[14; 15) |
23 | err: `expected item` | ||
23 | ERROR@[15; 17) | 24 | ERROR@[15; 17) |
24 | err: `expected item` | ||
25 | R_ANGLE@[15; 16) | 25 | R_ANGLE@[15; 16) |
26 | WHITESPACE@[16; 17) | 26 | WHITESPACE@[16; 17) |
27 | err: `expected item` | ||
27 | ERROR@[17; 33) | 28 | ERROR@[17; 33) |
28 | err: `expected item` | ||
29 | L_CURLY@[17; 18) | 29 | L_CURLY@[17; 18) |
30 | WHITESPACE@[18; 23) | 30 | WHITESPACE@[18; 23) |
31 | IDENT@[23; 24) "f" | 31 | IDENT@[23; 24) "f" |
diff --git a/tests/data/parser/inline/0006_extern_struct.txt b/tests/data/parser/inline/0006_extern_struct.txt index 93a5b0477..f310e1225 100644 --- a/tests/data/parser/inline/0006_extern_struct.txt +++ b/tests/data/parser/inline/0006_extern_struct.txt | |||
@@ -2,7 +2,7 @@ FILE@[0; 19) | |||
2 | ABI@[0; 7) | 2 | ABI@[0; 7) |
3 | EXTERN_KW@[0; 6) | 3 | EXTERN_KW@[0; 6) |
4 | WHITESPACE@[6; 7) | 4 | WHITESPACE@[6; 7) |
5 | err: `expected `fn` or `{`` | 5 | err: `expected `fn` or `{`` |
6 | STRUCT_ITEM@[7; 19) | 6 | STRUCT_ITEM@[7; 19) |
7 | STRUCT_KW@[7; 13) | 7 | STRUCT_KW@[7; 13) |
8 | NAME@[13; 17) | 8 | NAME@[13; 17) |
diff --git a/tests/data/parser/inline/0013_unsafe_block_in_mod.txt b/tests/data/parser/inline/0013_unsafe_block_in_mod.txt index 5ddc1736c..3b56378a3 100644 --- a/tests/data/parser/inline/0013_unsafe_block_in_mod.txt +++ b/tests/data/parser/inline/0013_unsafe_block_in_mod.txt | |||
@@ -11,8 +11,8 @@ FILE@[0; 33) | |||
11 | R_CURLY@[9; 10) | 11 | R_CURLY@[9; 10) |
12 | WHITESPACE@[10; 11) | 12 | WHITESPACE@[10; 11) |
13 | UNSAFE_KW@[11; 17) | 13 | UNSAFE_KW@[11; 17) |
14 | ERROR@[17; 22) | ||
15 | err: `expected `trait`, `impl` or `fn`` | 14 | err: `expected `trait`, `impl` or `fn`` |
15 | ERROR@[17; 22) | ||
16 | WHITESPACE@[17; 18) | 16 | WHITESPACE@[17; 18) |
17 | L_CURLY@[18; 19) | 17 | L_CURLY@[18; 19) |
18 | WHITESPACE@[19; 20) | 18 | WHITESPACE@[19; 20) |
diff --git a/tests/data/parser/inline/0023_array_type_missing_semi.txt b/tests/data/parser/inline/0023_array_type_missing_semi.txt index bb30a2a2a..cc280d5a7 100644 --- a/tests/data/parser/inline/0023_array_type_missing_semi.txt +++ b/tests/data/parser/inline/0023_array_type_missing_semi.txt | |||
@@ -13,16 +13,16 @@ FILE@[0; 18) | |||
13 | L_PAREN@[10; 11) | 13 | L_PAREN@[10; 11) |
14 | R_PAREN@[11; 12) | 14 | R_PAREN@[11; 12) |
15 | WHITESPACE@[12; 13) | 15 | WHITESPACE@[12; 13) |
16 | err: `expected `;` or `]`` | 16 | err: `expected SEMI` |
17 | err: `expected SEMI` | 17 | err: `expected `;` or `]`` |
18 | err: `expected item` | ||
18 | ERROR@[13; 15) | 19 | ERROR@[13; 15) |
19 | err: `expected item` | ||
20 | INT_NUMBER@[13; 15) | 20 | INT_NUMBER@[13; 15) |
21 | err: `expected item` | ||
21 | ERROR@[15; 16) | 22 | ERROR@[15; 16) |
22 | err: `expected item` | ||
23 | R_BRACK@[15; 16) | 23 | R_BRACK@[15; 16) |
24 | ERROR@[16; 18) | 24 | err: `expected item, found `;` |
25 | err: `expected item, found `;` | ||
26 | consider removing this semicolon` | 25 | consider removing this semicolon` |
26 | ERROR@[16; 18) | ||
27 | SEMI@[16; 17) | 27 | SEMI@[16; 17) |
28 | WHITESPACE@[17; 18) | 28 | WHITESPACE@[17; 18) |
diff --git a/tests/data/parser/inline/0029_fn_pointer_type_missing_fn.txt b/tests/data/parser/inline/0029_fn_pointer_type_missing_fn.txt index dd6e24096..d6c27cf58 100644 --- a/tests/data/parser/inline/0029_fn_pointer_type_missing_fn.txt +++ b/tests/data/parser/inline/0029_fn_pointer_type_missing_fn.txt | |||
@@ -8,17 +8,17 @@ FILE@[0; 20) | |||
8 | EQ@[7; 8) | 8 | EQ@[7; 8) |
9 | WHITESPACE@[8; 9) | 9 | WHITESPACE@[8; 9) |
10 | UNSAFE_KW@[9; 15) | 10 | UNSAFE_KW@[9; 15) |
11 | err: `expected `fn`` | ||
12 | err: `expected SEMI` | 11 | err: `expected SEMI` |
12 | err: `expected `fn`` | ||
13 | WHITESPACE@[15; 16) | 13 | WHITESPACE@[15; 16) |
14 | err: `expected item` | ||
14 | ERROR@[16; 17) | 15 | ERROR@[16; 17) |
15 | err: `expected item` | ||
16 | L_PAREN@[16; 17) | 16 | L_PAREN@[16; 17) |
17 | err: `expected item` | ||
17 | ERROR@[17; 18) | 18 | ERROR@[17; 18) |
18 | err: `expected item` | ||
19 | R_PAREN@[17; 18) | 19 | R_PAREN@[17; 18) |
20 | ERROR@[18; 20) | 20 | err: `expected item, found `;` |
21 | err: `expected item, found `;` | ||
22 | consider removing this semicolon` | 21 | consider removing this semicolon` |
22 | ERROR@[18; 20) | ||
23 | SEMI@[18; 19) | 23 | SEMI@[18; 19) |
24 | WHITESPACE@[19; 20) | 24 | WHITESPACE@[19; 20) |
diff --git a/tests/parser.rs b/tests/parser.rs index 68a6434be..35b91436a 100644 --- a/tests/parser.rs +++ b/tests/parser.rs | |||
@@ -1,15 +1,15 @@ | |||
1 | extern crate libsyntax2; | 1 | extern crate libsyntax2; |
2 | extern crate testutils; | 2 | extern crate testutils; |
3 | 3 | ||
4 | use libsyntax2::{parse, tokenize}; | 4 | use libsyntax2::{parse, tokenize, parse_green}; |
5 | use libsyntax2::utils::dump_tree; | 5 | use libsyntax2::utils::{dump_tree, dump_tree_green}; |
6 | use testutils::dir_tests; | 6 | use testutils::dir_tests; |
7 | 7 | ||
8 | #[test] | 8 | #[test] |
9 | fn parser_tests() { | 9 | fn parser_tests() { |
10 | dir_tests(&["parser/inline", "parser/ok", "parser/err"], |text| { | 10 | dir_tests(&["parser/inline", "parser/ok", "parser/err"], |text| { |
11 | let tokens = tokenize(text); | 11 | let tokens = tokenize(text); |
12 | let file = parse(text.to_string(), &tokens); | 12 | let file = parse_green(text.to_string(), &tokens); |
13 | dump_tree(&file) | 13 | dump_tree_green(&file) |
14 | }) | 14 | }) |
15 | } | 15 | } |