1 //! Syntax Tree library used throughout the rust analyzer.
4 //! - easy and fast incremental re-parsing
5 //! - graceful handling of errors
6 //! - full-fidelity representation (*any* text can be precisely represented as
9 //! For more information, see the [RFC]. Current implementation is inspired by
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.
17 //! See `api_walkthrough` test in this file for a quick API tour!
19 //! [RFC]: <https://github.com/rust-lang/rfcs/pull/2256>
20 //! [Swift]: <https://github.com/apple/swift/blob/13d593df6f359d0cb2fc81cfaac273297c539455/lib/Syntax/README.md>
23 macro_rules! eprintln {
24 ($($tt:tt)*) => { stdx::eprintln!($($tt)*) };
41 use std::{marker::PhantomData, sync::Arc};
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,
53 SyntaxElement, SyntaxElementChildren, SyntaxNode, SyntaxNodeChildren, SyntaxToken,
57 pub use parser::{SyntaxKind, T};
59 Direction, GreenNode, NodeOrToken, SyntaxText, TextRange, TextSize, TokenAtOffset, WalkEvent,
61 pub use smol_str::SmolStr;
63 /// `Parse` is the result of the parsing: a syntax tree and a collection of
66 /// Note that we always produce a syntax tree, even for completely invalid
68 #[derive(Debug, PartialEq, Eq)]
71 errors: Arc<Vec<SyntaxError>>,
72 _ty: PhantomData<fn() -> T>,
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 }
82 fn new(green: GreenNode, errors: Vec<SyntaxError>) -> Parse<T> {
83 Parse { green, errors: Arc::new(errors), _ty: PhantomData }
86 pub fn syntax_node(&self) -> SyntaxNode {
87 SyntaxNode::new_root(self.green.clone())
91 impl<T: AstNode> Parse<T> {
92 pub fn to_syntax(self) -> Parse<SyntaxNode> {
93 Parse { green: self.green, errors: self.errors, _ty: PhantomData }
96 pub fn tree(&self) -> T {
97 T::cast(self.syntax_node()).unwrap()
100 pub fn errors(&self) -> &[SyntaxError] {
104 pub fn ok(self) -> Result<T, Arc<Vec<SyntaxError>>> {
105 if self.errors.is_empty() {
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 })
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);
132 pub fn reparse(&self, indel: &Indel) -> Parse<SourceFile> {
133 self.incremental_reparse(indel).unwrap_or_else(|| self.full_reparse(indel))
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 {
141 errors: Arc::new(errors),
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)
154 /// `SourceFile` represents a parse tree for a single Rust file.
155 pub use crate::ast::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());
162 if cfg!(debug_assertions) {
163 validation::validate_block_structure(&root);
166 errors.extend(validation::validate(&root));
168 assert_eq!(root.kind(), SyntaxKind::SOURCE_FILE);
169 Parse { green, errors: Arc::new(errors), _ty: PhantomData }
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)
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)
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)
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)
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)
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)
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)
222 /// Matches a `SyntaxNode` against an `ast` type.
229 /// ast::CallExpr(it) => { ... },
230 /// ast::MethodCallExpr(it) => { ... },
231 /// ast::MacroCall(it) => { ... },
237 macro_rules! match_ast {
238 (match $node:ident { $($tt:tt)* }) => { match_ast!(match ($node) { $($tt)* }) };
240 (match ($node:expr) {
241 $( ast::$ast:ident($it:ident) => $res:expr, )*
242 _ => $catch_all:expr $(,)?
244 $( if let Some($it) = ast::$ast::cast($node.clone()) { $res } else )*
249 /// This test does not assert anything and instead just shows off the crate's
252 fn api_walkthrough() {
253 use ast::{ModuleItemOwner, NameOwner};
260 // `SourceFile` is the main entry point.
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());
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();
271 // `SourceFile` is the root of the syntax tree. We can iterate file's items.
272 // Let's fetch the `foo` function.
274 for item in file.items() {
276 ast::Item::Fn(f) => func = Some(f),
280 let func: ast::Fn = func.unwrap();
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::`
287 let name: Option<ast::Name> = func.name();
288 let name = name.unwrap();
289 assert_eq!(name.text(), "foo");
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();
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
299 let bin_expr: &ast::BinExpr = match &expr {
300 ast::Expr::BinExpr(e) => e,
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();
308 // Note how `expr` and `bin_expr` are in fact the same node underneath:
309 assert!(expr_syntax == bin_expr.syntax());
311 // To go from CST to AST, `AstNode::cast` function is used:
312 let _expr: ast::Expr = match ast::Expr::cast(expr_syntax.clone()) {
314 None => unreachable!(),
317 // The two properties each syntax node has is a `SyntaxKind`:
318 assert_eq!(expr_syntax.kind(), SyntaxKind::BIN_EXPR);
321 assert_eq!(expr_syntax.text_range(), TextRange::new(32.into(), 37.into()));
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");
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!['{']));
332 expr_syntax.next_sibling_or_token().map(|it| it.kind()),
333 Some(SyntaxKind::WHITESPACE)
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!['}']));
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`
347 // There's also a `preorder` method with a more fine-grained iteration control:
348 let mut buf = String::new();
350 for event in expr_syntax.preorder_with_tokens() {
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(),
357 format_to!(buf, "{:indent$}{:?} {:?}\n", " ", text, node.kind(), indent = indent);
360 WalkEvent::Leave(_) => indent -= 2,
363 assert_eq!(indent, 0);
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!`.
384 // Here's how the first one looks like:
385 let exprs_cast: Vec<String> = file
388 .filter_map(ast::Expr::cast)
389 .map(|expr| expr.syntax().text().to_string())
392 // An alternative is to use a macro.
393 let mut exprs_visit = Vec::new();
394 for node in file.syntax().descendants() {
398 let res = it.syntax().text().to_string();
399 exprs_visit.push(res);
405 assert_eq!(exprs_cast, exprs_visit);