aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_syntax/src/lib.rs
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2019-07-18 17:23:05 +0100
committerAleksey Kladov <[email protected]>2019-07-19 11:16:24 +0100
commitd402974aa0af6de290245a9d2a69a5d56c4fa610 (patch)
treedf4a0e38e548f9f74592e00a2c5a7d37bab3c4c2 /crates/ra_syntax/src/lib.rs
parent58d4983ba5745975446d60f2886d96f8d2adf0f2 (diff)
migrate ra_syntax to the new rowan API
Diffstat (limited to 'crates/ra_syntax/src/lib.rs')
-rw-r--r--crates/ra_syntax/src/lib.rs122
1 files changed, 58 insertions, 64 deletions
diff --git a/crates/ra_syntax/src/lib.rs b/crates/ra_syntax/src/lib.rs
index 534c206a6..ee60c6b8c 100644
--- a/crates/ra_syntax/src/lib.rs
+++ b/crates/ra_syntax/src/lib.rs
@@ -31,7 +31,7 @@ pub mod ast;
31#[doc(hidden)] 31#[doc(hidden)]
32pub mod fuzz; 32pub mod fuzz;
33 33
34use std::{fmt::Write, sync::Arc}; 34use std::{fmt::Write, marker::PhantomData, sync::Arc};
35 35
36use ra_text_edit::AtomTextEdit; 36use ra_text_edit::AtomTextEdit;
37 37
@@ -43,8 +43,8 @@ pub use crate::{
43 ptr::{AstPtr, SyntaxNodePtr}, 43 ptr::{AstPtr, SyntaxNodePtr},
44 syntax_error::{Location, SyntaxError, SyntaxErrorKind}, 44 syntax_error::{Location, SyntaxError, SyntaxErrorKind},
45 syntax_node::{ 45 syntax_node::{
46 Direction, InsertPosition, SyntaxElement, SyntaxNode, SyntaxNodeWrapper, SyntaxToken, 46 Direction, InsertPosition, SyntaxElement, SyntaxNode, SyntaxToken, SyntaxTreeBuilder,
47 SyntaxTreeBuilder, TreeArc, WalkEvent, 47 WalkEvent,
48 }, 48 },
49 syntax_text::SyntaxText, 49 syntax_text::SyntaxText,
50}; 50};
@@ -58,48 +58,63 @@ pub use rowan::{SmolStr, TextRange, TextUnit};
58/// Note that we always produce a syntax tree, even for completely invalid 58/// Note that we always produce a syntax tree, even for completely invalid
59/// files. 59/// files.
60#[derive(Debug, PartialEq, Eq)] 60#[derive(Debug, PartialEq, Eq)]
61pub struct Parse<T: SyntaxNodeWrapper> { 61pub struct Parse<T> {
62 tree: TreeArc<T>, 62 green: GreenNode,
63 errors: Arc<Vec<SyntaxError>>, 63 errors: Arc<Vec<SyntaxError>>,
64 _ty: PhantomData<fn() -> T>,
64} 65}
65 66
66impl<T: SyntaxNodeWrapper> Clone for Parse<T> { 67impl<T> Clone for Parse<T> {
67 fn clone(&self) -> Parse<T> { 68 fn clone(&self) -> Parse<T> {
68 Parse { tree: self.tree.clone(), errors: self.errors.clone() } 69 Parse { green: self.green.clone(), errors: self.errors.clone(), _ty: PhantomData }
69 } 70 }
70} 71}
71 72
72impl<T: SyntaxNodeWrapper> Parse<T> { 73impl<T> Parse<T> {
73 fn new(tree: TreeArc<T>, errors: Vec<SyntaxError>) -> Parse<T> { 74 fn new(green: GreenNode, errors: Vec<SyntaxError>) -> Parse<T> {
74 Parse { tree, errors: Arc::new(errors) } 75 Parse { green, errors: Arc::new(errors), _ty: PhantomData }
75 } 76 }
76 77
77 pub fn tree(&self) -> &T { 78 fn syntax_node(&self) -> SyntaxNode {
78 &*self.tree 79 SyntaxNode::new(self.green.clone())
80 }
81}
82
83impl<T: AstNode> Parse<T> {
84 pub fn to_syntax(self) -> Parse<SyntaxNode> {
85 Parse { green: self.green, errors: self.errors, _ty: PhantomData }
86 }
87
88 pub fn tree(&self) -> T {
89 T::cast(self.syntax_node()).unwrap()
79 } 90 }
80 91
81 pub fn errors(&self) -> &[SyntaxError] { 92 pub fn errors(&self) -> &[SyntaxError] {
82 &*self.errors 93 &*self.errors
83 } 94 }
84 95
85 pub fn ok(self) -> Result<TreeArc<T>, Arc<Vec<SyntaxError>>> { 96 pub fn ok(self) -> Result<T, Arc<Vec<SyntaxError>>> {
86 if self.errors.is_empty() { 97 if self.errors.is_empty() {
87 Ok(self.tree) 98 Ok(self.tree())
88 } else { 99 } else {
89 Err(self.errors) 100 Err(self.errors)
90 } 101 }
91 } 102 }
92} 103}
93 104
94impl<T: AstNode> Parse<T> { 105impl Parse<SyntaxNode> {
95 pub fn to_syntax(this: Self) -> Parse<SyntaxNode> { 106 pub fn cast<N: AstNode>(self) -> Option<Parse<N>> {
96 Parse { tree: this.tree().syntax().to_owned(), errors: this.errors } 107 if N::cast(self.syntax_node()).is_some() {
108 Some(Parse { green: self.green, errors: self.errors, _ty: PhantomData })
109 } else {
110 None
111 }
97 } 112 }
98} 113}
99 114
100impl Parse<SourceFile> { 115impl Parse<SourceFile> {
101 pub fn debug_dump(&self) -> String { 116 pub fn debug_dump(&self) -> String {
102 let mut buf = self.tree.syntax().debug_dump(); 117 let mut buf = self.tree().syntax().debug_dump();
103 for err in self.errors.iter() { 118 for err in self.errors.iter() {
104 writeln!(buf, "error {:?}: {}", err.location(), err.kind()).unwrap(); 119 writeln!(buf, "error {:?}: {}", err.location(), err.kind()).unwrap();
105 } 120 }
@@ -112,45 +127,38 @@ impl Parse<SourceFile> {
112 127
113 fn incremental_reparse(&self, edit: &AtomTextEdit) -> Option<Parse<SourceFile>> { 128 fn incremental_reparse(&self, edit: &AtomTextEdit) -> Option<Parse<SourceFile>> {
114 // FIXME: validation errors are not handled here 129 // FIXME: validation errors are not handled here
115 parsing::incremental_reparse(self.tree.syntax(), edit, self.errors.to_vec()).map( 130 parsing::incremental_reparse(self.tree().syntax(), edit, self.errors.to_vec()).map(
116 |(green_node, errors, _reparsed_range)| Parse { 131 |(green_node, errors, _reparsed_range)| Parse {
117 tree: SourceFile::new(green_node), 132 green: green_node,
118 errors: Arc::new(errors), 133 errors: Arc::new(errors),
134 _ty: PhantomData,
119 }, 135 },
120 ) 136 )
121 } 137 }
122 138
123 fn full_reparse(&self, edit: &AtomTextEdit) -> Parse<SourceFile> { 139 fn full_reparse(&self, edit: &AtomTextEdit) -> Parse<SourceFile> {
124 let text = edit.apply(self.tree.syntax().text().to_string()); 140 let text = edit.apply(self.tree().syntax().text().to_string());
125 SourceFile::parse(&text) 141 SourceFile::parse(&text)
126 } 142 }
127} 143}
128 144
129impl Parse<SyntaxNode> {
130 pub fn cast<T: AstNode>(self) -> Option<Parse<T>> {
131 let node = T::cast(&self.tree)?;
132 Some(Parse { tree: node.to_owned(), errors: self.errors })
133 }
134}
135
136/// `SourceFile` represents a parse tree for a single Rust file. 145/// `SourceFile` represents a parse tree for a single Rust file.
137pub use crate::ast::SourceFile; 146pub use crate::ast::SourceFile;
138 147
139impl SourceFile { 148impl SourceFile {
140 fn new(green: GreenNode) -> TreeArc<SourceFile> { 149 fn new(green: GreenNode) -> SourceFile {
141 let root = SyntaxNode::new(green); 150 let root = SyntaxNode::new(green);
142 if cfg!(debug_assertions) { 151 if cfg!(debug_assertions) {
143 validation::validate_block_structure(&root); 152 validation::validate_block_structure(&root);
144 } 153 }
145 assert_eq!(root.kind(), SyntaxKind::SOURCE_FILE); 154 assert_eq!(root.kind(), SyntaxKind::SOURCE_FILE);
146 TreeArc::cast(root) 155 SourceFile::cast(root).unwrap()
147 } 156 }
148 157
149 pub fn parse(text: &str) -> Parse<SourceFile> { 158 pub fn parse(text: &str) -> Parse<SourceFile> {
150 let (green, mut errors) = parsing::parse_text(text); 159 let (green, mut errors) = parsing::parse_text(text);
151 let tree = SourceFile::new(green); 160 errors.extend(validation::validate(&SourceFile::new(green.clone())));
152 errors.extend(validation::validate(&tree)); 161 Parse { green, errors: Arc::new(errors), _ty: PhantomData }
153 Parse { tree, errors: Arc::new(errors) }
154 } 162 }
155} 163}
156 164
@@ -170,14 +178,14 @@ fn api_walkthrough() {
170 // The `parse` method returns a `Parse` -- a pair of syntax tree and a list 178 // The `parse` method returns a `Parse` -- a pair of syntax tree and a list
171 // of errors. That is, syntax tree is constructed even in presence of errors. 179 // of errors. That is, syntax tree is constructed even in presence of errors.
172 let parse = SourceFile::parse(source_code); 180 let parse = SourceFile::parse(source_code);
173 assert!(parse.errors.is_empty()); 181 assert!(parse.errors().is_empty());
174 182
175 // Due to the way ownership is set up, owned syntax Nodes always live behind 183 // The `tree` method returns an owned syntax node of type `SourceFile`.
176 // a `TreeArc` smart pointer. `TreeArc` is roughly an `std::sync::Arc` which 184 // Owned nodes are cheap: inside, they are `Rc` handles to the underling data.
177 // points to the whole file instead of an individual node. 185 let file: SourceFile = parse.tree();
178 let file: TreeArc<SourceFile> = parse.tree;
179 186
180 // `SourceFile` is the root of the syntax tree. We can iterate file's items: 187 // `SourceFile` is the root of the syntax tree. We can iterate file's items.
188 // Let's fetch the `foo` function.
181 let mut func = None; 189 let mut func = None;
182 for item in file.items() { 190 for item in file.items() {
183 match item.kind() { 191 match item.kind() {
@@ -185,31 +193,26 @@ fn api_walkthrough() {
185 _ => unreachable!(), 193 _ => unreachable!(),
186 } 194 }
187 } 195 }
188 // The returned items are always references. 196 let func: ast::FnDef = func.unwrap();
189 let func: &ast::FnDef = func.unwrap();
190
191 // All nodes implement `ToOwned` trait, with `Owned = TreeArc<Self>`.
192 // `to_owned` is a cheap operation: atomic increment.
193 let _owned_func: TreeArc<ast::FnDef> = func.to_owned();
194 197
195 // Each AST node has a bunch of getters for children. All getters return 198 // Each AST node has a bunch of getters for children. All getters return
196 // `Option`s though, to account for incomplete code. Some getters are common 199 // `Option`s though, to account for incomplete code. Some getters are common
197 // for several kinds of node. In this case, a trait like `ast::NameOwner` 200 // for several kinds of node. In this case, a trait like `ast::NameOwner`
198 // usually exists. By convention, all ast types should be used with `ast::` 201 // usually exists. By convention, all ast types should be used with `ast::`
199 // qualifier. 202 // qualifier.
200 let name: Option<&ast::Name> = func.name(); 203 let name: Option<ast::Name> = func.name();
201 let name = name.unwrap(); 204 let name = name.unwrap();
202 assert_eq!(name.text(), "foo"); 205 assert_eq!(name.text(), "foo");
203 206
204 // Let's get the `1 + 1` expression! 207 // Let's get the `1 + 1` expression!
205 let block: &ast::Block = func.body().unwrap(); 208 let block: ast::Block = func.body().unwrap();
206 let expr: &ast::Expr = block.expr().unwrap(); 209 let expr: ast::Expr = block.expr().unwrap();
207 210
208 // "Enum"-like nodes are represented using the "kind" pattern. It allows us 211 // "Enum"-like nodes are represented using the "kind" pattern. It allows us
209 // to match exhaustively against all flavors of nodes, while maintaining 212 // to match exhaustively against all flavors of nodes, while maintaining
210 // internal representation flexibility. The drawback is that one can't write 213 // internal representation flexibility. The drawback is that one can't write
211 // nested matches as one pattern. 214 // nested matches as one pattern.
212 let bin_expr: &ast::BinExpr = match expr.kind() { 215 let bin_expr: ast::BinExpr = match expr.kind() {
213 ast::ExprKind::BinExpr(e) => e, 216 ast::ExprKind::BinExpr(e) => e,
214 _ => unreachable!(), 217 _ => unreachable!(),
215 }; 218 };
@@ -219,23 +222,14 @@ fn api_walkthrough() {
219 let expr_syntax: &SyntaxNode = expr.syntax(); 222 let expr_syntax: &SyntaxNode = expr.syntax();
220 223
221 // Note how `expr` and `bin_expr` are in fact the same node underneath: 224 // Note how `expr` and `bin_expr` are in fact the same node underneath:
222 assert!(std::ptr::eq(expr_syntax, bin_expr.syntax())); 225 assert!(expr_syntax == bin_expr.syntax());
223 226
224 // To go from CST to AST, `AstNode::cast` function is used: 227 // To go from CST to AST, `AstNode::cast` function is used:
225 let expr = match ast::Expr::cast(expr_syntax) { 228 let _expr: ast::Expr = match ast::Expr::cast(expr_syntax.clone()) {
226 Some(e) => e, 229 Some(e) => e,
227 None => unreachable!(), 230 None => unreachable!(),
228 }; 231 };
229 232
230 // Note how expr is also a reference!
231 let expr: &ast::Expr = expr;
232
233 // This is possible because the underlying representation is the same:
234 assert_eq!(
235 expr as *const ast::Expr as *const u8,
236 expr_syntax as *const SyntaxNode as *const u8
237 );
238
239 // The two properties each syntax node has is a `SyntaxKind`: 233 // The two properties each syntax node has is a `SyntaxKind`:
240 assert_eq!(expr_syntax.kind(), SyntaxKind::BIN_EXPR); 234 assert_eq!(expr_syntax.kind(), SyntaxKind::BIN_EXPR);
241 235
@@ -248,7 +242,7 @@ fn api_walkthrough() {
248 assert_eq!(text.to_string(), "1 + 1"); 242 assert_eq!(text.to_string(), "1 + 1");
249 243
250 // There's a bunch of traversal methods on `SyntaxNode`: 244 // There's a bunch of traversal methods on `SyntaxNode`:
251 assert_eq!(expr_syntax.parent(), Some(block.syntax())); 245 assert_eq!(expr_syntax.parent().as_ref(), Some(block.syntax()));
252 assert_eq!(block.syntax().first_child_or_token().map(|it| it.kind()), Some(T!['{'])); 246 assert_eq!(block.syntax().first_child_or_token().map(|it| it.kind()), Some(T!['{']));
253 assert_eq!( 247 assert_eq!(
254 expr_syntax.next_sibling_or_token().map(|it| it.kind()), 248 expr_syntax.next_sibling_or_token().map(|it| it.kind()),
@@ -257,7 +251,7 @@ fn api_walkthrough() {
257 251
258 // As well as some iterator helpers: 252 // As well as some iterator helpers:
259 let f = expr_syntax.ancestors().find_map(ast::FnDef::cast); 253 let f = expr_syntax.ancestors().find_map(ast::FnDef::cast);
260 assert_eq!(f, Some(&*func)); 254 assert_eq!(f, Some(func));
261 assert!(expr_syntax.siblings_with_tokens(Direction::Next).any(|it| it.kind() == T!['}'])); 255 assert!(expr_syntax.siblings_with_tokens(Direction::Next).any(|it| it.kind() == T!['}']));
262 assert_eq!( 256 assert_eq!(
263 expr_syntax.descendants_with_tokens().count(), 257 expr_syntax.descendants_with_tokens().count(),
@@ -272,7 +266,7 @@ fn api_walkthrough() {
272 for event in expr_syntax.preorder_with_tokens() { 266 for event in expr_syntax.preorder_with_tokens() {
273 match event { 267 match event {
274 WalkEvent::Enter(node) => { 268 WalkEvent::Enter(node) => {
275 let text = match node { 269 let text = match &node {
276 SyntaxElement::Node(it) => it.text().to_string(), 270 SyntaxElement::Node(it) => it.text().to_string(),
277 SyntaxElement::Token(it) => it.text().to_string(), 271 SyntaxElement::Token(it) => it.text().to_string(),
278 }; 272 };
@@ -319,7 +313,7 @@ fn api_walkthrough() {
319 let mut exprs_visit = Vec::new(); 313 let mut exprs_visit = Vec::new();
320 for node in file.syntax().descendants() { 314 for node in file.syntax().descendants() {
321 if let Some(result) = 315 if let Some(result) =
322 visitor().visit::<ast::Expr, _>(|expr| expr.syntax().text().to_string()).accept(node) 316 visitor().visit::<ast::Expr, _>(|expr| expr.syntax().text().to_string()).accept(&node)
323 { 317 {
324 exprs_visit.push(result); 318 exprs_visit.push(result);
325 } 319 }