]> git.lizzy.rs Git - rust.git/blob - crates/syntax/src/lib.rs
:arrow_up: rowan
[rust.git] / crates / syntax / src / lib.rs
1 //! Syntax Tree library used throughout the rust analyzer.
2 //!
3 //! Properties:
4 //!   - easy and fast incremental re-parsing
5 //!   - graceful handling of errors
6 //!   - full-fidelity representation (*any* text can be precisely represented as
7 //!     a syntax tree)
8 //!
9 //! For more information, see the [RFC]. Current implementation is inspired by
10 //! the [Swift] one.
11 //!
12 //! The most interesting modules here are `syntax_node` (which defines concrete
13 //! syntax tree) and `ast` (which defines abstract syntax tree on top of the
14 //! CST). The actual parser live in a separate `parser` crate, though the
15 //! lexer lives in this crate.
16 //!
17 //! See `api_walkthrough` test in this file for a quick API tour!
18 //!
19 //! [RFC]: <https://github.com/rust-lang/rfcs/pull/2256>
20 //! [Swift]: <https://github.com/apple/swift/blob/13d593df6f359d0cb2fc81cfaac273297c539455/lib/Syntax/README.md>
21
22 #[allow(unused)]
23 macro_rules! eprintln {
24     ($($tt:tt)*) => { stdx::eprintln!($($tt)*) };
25 }
26
27 mod syntax_node;
28 mod syntax_error;
29 mod parsing;
30 mod validation;
31 mod ptr;
32 #[cfg(test)]
33 mod tests;
34
35 pub mod display;
36 pub mod algo;
37 pub mod ast;
38 #[doc(hidden)]
39 pub mod fuzz;
40
41 use std::{marker::PhantomData, sync::Arc};
42
43 use stdx::format_to;
44 use text_edit::Indel;
45
46 pub use crate::{
47     algo::InsertPosition,
48     ast::{AstNode, AstToken},
49     parsing::lexer::{lex_single_syntax_kind, lex_single_valid_syntax_kind, tokenize, Token},
50     ptr::{AstPtr, SyntaxNodePtr},
51     syntax_error::SyntaxError,
52     syntax_node::{
53         SyntaxElement, SyntaxElementChildren, SyntaxNode, SyntaxNodeChildren, SyntaxToken,
54         SyntaxTreeBuilder,
55     },
56 };
57 pub use parser::{SyntaxKind, T};
58 pub use rowan::{
59     Direction, GreenNode, NodeOrToken, SyntaxText, TextRange, TextSize, TokenAtOffset, WalkEvent,
60 };
61 pub use smol_str::SmolStr;
62
63 /// `Parse` is the result of the parsing: a syntax tree and a collection of
64 /// errors.
65 ///
66 /// Note that we always produce a syntax tree, even for completely invalid
67 /// files.
68 #[derive(Debug, PartialEq, Eq)]
69 pub struct Parse<T> {
70     green: GreenNode,
71     errors: Arc<Vec<SyntaxError>>,
72     _ty: PhantomData<fn() -> T>,
73 }
74
75 impl<T> Clone for Parse<T> {
76     fn clone(&self) -> Parse<T> {
77         Parse { green: self.green.clone(), errors: self.errors.clone(), _ty: PhantomData }
78     }
79 }
80
81 impl<T> Parse<T> {
82     fn new(green: GreenNode, errors: Vec<SyntaxError>) -> Parse<T> {
83         Parse { green, errors: Arc::new(errors), _ty: PhantomData }
84     }
85
86     pub fn syntax_node(&self) -> SyntaxNode {
87         SyntaxNode::new_root(self.green.clone())
88     }
89 }
90
91 impl<T: AstNode> Parse<T> {
92     pub fn to_syntax(self) -> Parse<SyntaxNode> {
93         Parse { green: self.green, errors: self.errors, _ty: PhantomData }
94     }
95
96     pub fn tree(&self) -> T {
97         T::cast(self.syntax_node()).unwrap()
98     }
99
100     pub fn errors(&self) -> &[SyntaxError] {
101         &*self.errors
102     }
103
104     pub fn ok(self) -> Result<T, Arc<Vec<SyntaxError>>> {
105         if self.errors.is_empty() {
106             Ok(self.tree())
107         } else {
108             Err(self.errors)
109         }
110     }
111 }
112
113 impl Parse<SyntaxNode> {
114     pub fn cast<N: AstNode>(self) -> Option<Parse<N>> {
115         if N::cast(self.syntax_node()).is_some() {
116             Some(Parse { green: self.green, errors: self.errors, _ty: PhantomData })
117         } else {
118             None
119         }
120     }
121 }
122
123 impl Parse<SourceFile> {
124     pub fn debug_dump(&self) -> String {
125         let mut buf = format!("{:#?}", self.tree().syntax());
126         for err in self.errors.iter() {
127             format_to!(buf, "error {:?}: {}\n", err.range(), err);
128         }
129         buf
130     }
131
132     pub fn reparse(&self, indel: &Indel) -> Parse<SourceFile> {
133         self.incremental_reparse(indel).unwrap_or_else(|| self.full_reparse(indel))
134     }
135
136     fn incremental_reparse(&self, indel: &Indel) -> Option<Parse<SourceFile>> {
137         // FIXME: validation errors are not handled here
138         parsing::incremental_reparse(self.tree().syntax(), indel, self.errors.to_vec()).map(
139             |(green_node, errors, _reparsed_range)| Parse {
140                 green: green_node,
141                 errors: Arc::new(errors),
142                 _ty: PhantomData,
143             },
144         )
145     }
146
147     fn full_reparse(&self, indel: &Indel) -> Parse<SourceFile> {
148         let mut text = self.tree().syntax().text().to_string();
149         indel.apply(&mut text);
150         SourceFile::parse(&text)
151     }
152 }
153
154 /// `SourceFile` represents a parse tree for a single Rust file.
155 pub use crate::ast::SourceFile;
156
157 impl SourceFile {
158     pub fn parse(text: &str) -> Parse<SourceFile> {
159         let (green, mut errors) = parsing::parse_text(text);
160         let root = SyntaxNode::new_root(green.clone());
161
162         if cfg!(debug_assertions) {
163             validation::validate_block_structure(&root);
164         }
165
166         errors.extend(validation::validate(&root));
167
168         assert_eq!(root.kind(), SyntaxKind::SOURCE_FILE);
169         Parse { green, errors: Arc::new(errors), _ty: PhantomData }
170     }
171 }
172
173 impl ast::Path {
174     /// Returns `text`, parsed as a path, but only if it has no errors.
175     pub fn parse(text: &str) -> Result<Self, ()> {
176         parsing::parse_text_fragment(text, parser::FragmentKind::Path)
177     }
178 }
179
180 impl ast::Pat {
181     /// Returns `text`, parsed as a pattern, but only if it has no errors.
182     pub fn parse(text: &str) -> Result<Self, ()> {
183         parsing::parse_text_fragment(text, parser::FragmentKind::Pattern)
184     }
185 }
186
187 impl ast::Expr {
188     /// Returns `text`, parsed as an expression, but only if it has no errors.
189     pub fn parse(text: &str) -> Result<Self, ()> {
190         parsing::parse_text_fragment(text, parser::FragmentKind::Expr)
191     }
192 }
193
194 impl ast::Item {
195     /// Returns `text`, parsed as an item, but only if it has no errors.
196     pub fn parse(text: &str) -> Result<Self, ()> {
197         parsing::parse_text_fragment(text, parser::FragmentKind::Item)
198     }
199 }
200
201 impl ast::Type {
202     /// Returns `text`, parsed as an type reference, but only if it has no errors.
203     pub fn parse(text: &str) -> Result<Self, ()> {
204         parsing::parse_text_fragment(text, parser::FragmentKind::Type)
205     }
206 }
207
208 impl ast::Attr {
209     /// Returns `text`, parsed as an attribute, but only if it has no errors.
210     pub fn parse(text: &str) -> Result<Self, ()> {
211         parsing::parse_text_fragment(text, parser::FragmentKind::Attr)
212     }
213 }
214
215 impl ast::Stmt {
216     /// Returns `text`, parsed as statement, but only if it has no errors.
217     pub fn parse(text: &str) -> Result<Self, ()> {
218         parsing::parse_text_fragment(text, parser::FragmentKind::StatementOptionalSemi)
219     }
220 }
221
222 /// Matches a `SyntaxNode` against an `ast` type.
223 ///
224 /// # Example:
225 ///
226 /// ```ignore
227 /// match_ast! {
228 ///     match node {
229 ///         ast::CallExpr(it) => { ... },
230 ///         ast::MethodCallExpr(it) => { ... },
231 ///         ast::MacroCall(it) => { ... },
232 ///         _ => None,
233 ///     }
234 /// }
235 /// ```
236 #[macro_export]
237 macro_rules! match_ast {
238     (match $node:ident { $($tt:tt)* }) => { match_ast!(match ($node) { $($tt)* }) };
239
240     (match ($node:expr) {
241         $( ast::$ast:ident($it:ident) => $res:expr, )*
242         _ => $catch_all:expr $(,)?
243     }) => {{
244         $( if let Some($it) = ast::$ast::cast($node.clone()) { $res } else )*
245         { $catch_all }
246     }};
247 }
248
249 /// This test does not assert anything and instead just shows off the crate's
250 /// API.
251 #[test]
252 fn api_walkthrough() {
253     use ast::{ModuleItemOwner, NameOwner};
254
255     let source_code = "
256         fn foo() {
257             1 + 1
258         }
259     ";
260     // `SourceFile` is the main entry point.
261     //
262     // The `parse` method returns a `Parse` -- a pair of syntax tree and a list
263     // of errors. That is, syntax tree is constructed even in presence of errors.
264     let parse = SourceFile::parse(source_code);
265     assert!(parse.errors().is_empty());
266
267     // The `tree` method returns an owned syntax node of type `SourceFile`.
268     // Owned nodes are cheap: inside, they are `Rc` handles to the underling data.
269     let file: SourceFile = parse.tree();
270
271     // `SourceFile` is the root of the syntax tree. We can iterate file's items.
272     // Let's fetch the `foo` function.
273     let mut func = None;
274     for item in file.items() {
275         match item {
276             ast::Item::Fn(f) => func = Some(f),
277             _ => unreachable!(),
278         }
279     }
280     let func: ast::Fn = func.unwrap();
281
282     // Each AST node has a bunch of getters for children. All getters return
283     // `Option`s though, to account for incomplete code. Some getters are common
284     // for several kinds of node. In this case, a trait like `ast::NameOwner`
285     // usually exists. By convention, all ast types should be used with `ast::`
286     // qualifier.
287     let name: Option<ast::Name> = func.name();
288     let name = name.unwrap();
289     assert_eq!(name.text(), "foo");
290
291     // Let's get the `1 + 1` expression!
292     let body: ast::BlockExpr = func.body().unwrap();
293     let expr: ast::Expr = body.tail_expr().unwrap();
294
295     // Enums are used to group related ast nodes together, and can be used for
296     // matching. However, because there are no public fields, it's possible to
297     // match only the top level enum: that is the price we pay for increased API
298     // flexibility
299     let bin_expr: &ast::BinExpr = match &expr {
300         ast::Expr::BinExpr(e) => e,
301         _ => unreachable!(),
302     };
303
304     // Besides the "typed" AST API, there's an untyped CST one as well.
305     // To switch from AST to CST, call `.syntax()` method:
306     let expr_syntax: &SyntaxNode = expr.syntax();
307
308     // Note how `expr` and `bin_expr` are in fact the same node underneath:
309     assert!(expr_syntax == bin_expr.syntax());
310
311     // To go from CST to AST, `AstNode::cast` function is used:
312     let _expr: ast::Expr = match ast::Expr::cast(expr_syntax.clone()) {
313         Some(e) => e,
314         None => unreachable!(),
315     };
316
317     // The two properties each syntax node has is a `SyntaxKind`:
318     assert_eq!(expr_syntax.kind(), SyntaxKind::BIN_EXPR);
319
320     // And text range:
321     assert_eq!(expr_syntax.text_range(), TextRange::new(32.into(), 37.into()));
322
323     // You can get node's text as a `SyntaxText` object, which will traverse the
324     // tree collecting token's text:
325     let text: SyntaxText = expr_syntax.text();
326     assert_eq!(text.to_string(), "1 + 1");
327
328     // There's a bunch of traversal methods on `SyntaxNode`:
329     assert_eq!(expr_syntax.parent().as_ref(), Some(body.syntax()));
330     assert_eq!(body.syntax().first_child_or_token().map(|it| it.kind()), Some(T!['{']));
331     assert_eq!(
332         expr_syntax.next_sibling_or_token().map(|it| it.kind()),
333         Some(SyntaxKind::WHITESPACE)
334     );
335
336     // As well as some iterator helpers:
337     let f = expr_syntax.ancestors().find_map(ast::Fn::cast);
338     assert_eq!(f, Some(func));
339     assert!(expr_syntax.siblings_with_tokens(Direction::Next).any(|it| it.kind() == T!['}']));
340     assert_eq!(
341         expr_syntax.descendants_with_tokens().count(),
342         8, // 5 tokens `1`, ` `, `+`, ` `, `!`
343            // 2 child literal expressions: `1`, `1`
344            // 1 the node itself: `1 + 1`
345     );
346
347     // There's also a `preorder` method with a more fine-grained iteration control:
348     let mut buf = String::new();
349     let mut indent = 0;
350     for event in expr_syntax.preorder_with_tokens() {
351         match event {
352             WalkEvent::Enter(node) => {
353                 let text = match &node {
354                     NodeOrToken::Node(it) => it.text().to_string(),
355                     NodeOrToken::Token(it) => it.text().to_string(),
356                 };
357                 format_to!(buf, "{:indent$}{:?} {:?}\n", " ", text, node.kind(), indent = indent);
358                 indent += 2;
359             }
360             WalkEvent::Leave(_) => indent -= 2,
361         }
362     }
363     assert_eq!(indent, 0);
364     assert_eq!(
365         buf.trim(),
366         r#"
367 "1 + 1" BIN_EXPR
368   "1" LITERAL
369     "1" INT_NUMBER
370   " " WHITESPACE
371   "+" PLUS
372   " " WHITESPACE
373   "1" LITERAL
374     "1" INT_NUMBER
375 "#
376         .trim()
377     );
378
379     // To recursively process the tree, there are three approaches:
380     // 1. explicitly call getter methods on AST nodes.
381     // 2. use descendants and `AstNode::cast`.
382     // 3. use descendants and `match_ast!`.
383     //
384     // Here's how the first one looks like:
385     let exprs_cast: Vec<String> = file
386         .syntax()
387         .descendants()
388         .filter_map(ast::Expr::cast)
389         .map(|expr| expr.syntax().text().to_string())
390         .collect();
391
392     // An alternative is to use a macro.
393     let mut exprs_visit = Vec::new();
394     for node in file.syntax().descendants() {
395         match_ast! {
396             match node {
397                 ast::Expr(it) => {
398                     let res = it.syntax().text().to_string();
399                     exprs_visit.push(res);
400                 },
401                 _ => (),
402             }
403         }
404     }
405     assert_eq!(exprs_cast, exprs_visit);
406 }