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)*) };
44 use std::{marker::PhantomData, sync::Arc};
50 ast::{AstNode, AstToken},
51 parsing::lexer::{lex_single_syntax_kind, lex_single_valid_syntax_kind, tokenize, Token},
52 ptr::{AstPtr, SyntaxNodePtr},
53 syntax_error::SyntaxError,
55 SyntaxElement, SyntaxElementChildren, SyntaxNode, SyntaxNodeChildren, SyntaxToken,
58 token_text::TokenText,
60 pub use parser::{SyntaxKind, T};
62 Direction, GreenNode, NodeOrToken, SyntaxText, TextRange, TextSize, TokenAtOffset, WalkEvent,
64 pub use smol_str::SmolStr;
66 /// `Parse` is the result of the parsing: a syntax tree and a collection of
69 /// Note that we always produce a syntax tree, even for completely invalid
71 #[derive(Debug, PartialEq, Eq)]
74 errors: Arc<Vec<SyntaxError>>,
75 _ty: PhantomData<fn() -> T>,
78 impl<T> Clone for Parse<T> {
79 fn clone(&self) -> Parse<T> {
80 Parse { green: self.green.clone(), errors: self.errors.clone(), _ty: PhantomData }
85 fn new(green: GreenNode, errors: Vec<SyntaxError>) -> Parse<T> {
86 Parse { green, errors: Arc::new(errors), _ty: PhantomData }
89 pub fn syntax_node(&self) -> SyntaxNode {
90 SyntaxNode::new_root(self.green.clone())
94 impl<T: AstNode> Parse<T> {
95 pub fn to_syntax(self) -> Parse<SyntaxNode> {
96 Parse { green: self.green, errors: self.errors, _ty: PhantomData }
99 pub fn tree(&self) -> T {
100 T::cast(self.syntax_node()).unwrap()
103 pub fn errors(&self) -> &[SyntaxError] {
107 pub fn ok(self) -> Result<T, Arc<Vec<SyntaxError>>> {
108 if self.errors.is_empty() {
116 impl Parse<SyntaxNode> {
117 pub fn cast<N: AstNode>(self) -> Option<Parse<N>> {
118 if N::cast(self.syntax_node()).is_some() {
119 Some(Parse { green: self.green, errors: self.errors, _ty: PhantomData })
126 impl Parse<SourceFile> {
127 pub fn debug_dump(&self) -> String {
128 let mut buf = format!("{:#?}", self.tree().syntax());
129 for err in self.errors.iter() {
130 format_to!(buf, "error {:?}: {}\n", err.range(), err);
135 pub fn reparse(&self, indel: &Indel) -> Parse<SourceFile> {
136 self.incremental_reparse(indel).unwrap_or_else(|| self.full_reparse(indel))
139 fn incremental_reparse(&self, indel: &Indel) -> Option<Parse<SourceFile>> {
140 // FIXME: validation errors are not handled here
141 parsing::incremental_reparse(self.tree().syntax(), indel, self.errors.to_vec()).map(
142 |(green_node, errors, _reparsed_range)| Parse {
144 errors: Arc::new(errors),
150 fn full_reparse(&self, indel: &Indel) -> Parse<SourceFile> {
151 let mut text = self.tree().syntax().text().to_string();
152 indel.apply(&mut text);
153 SourceFile::parse(&text)
157 /// `SourceFile` represents a parse tree for a single Rust file.
158 pub use crate::ast::SourceFile;
161 pub fn parse(text: &str) -> Parse<SourceFile> {
162 let (green, mut errors) = parsing::parse_text(text);
163 let root = SyntaxNode::new_root(green.clone());
165 if cfg!(debug_assertions) {
166 validation::validate_block_structure(&root);
169 errors.extend(validation::validate(&root));
171 assert_eq!(root.kind(), SyntaxKind::SOURCE_FILE);
172 Parse { green, errors: Arc::new(errors), _ty: PhantomData }
176 // FIXME: `parse` functions shouldn't hang directly from AST nodes, and they
177 // shouldn't return `Result`.
179 // We need a dedicated module for parser entry points, and they should always
183 /// Returns `text`, parsed as a path, but only if it has no errors.
184 pub fn parse(text: &str) -> Result<Self, ()> {
185 parsing::parse_text_as(text, parser::ParserEntryPoint::Path)
190 /// Returns `text`, parsed as a pattern, but only if it has no errors.
191 pub fn parse(text: &str) -> Result<Self, ()> {
192 parsing::parse_text_as(text, parser::ParserEntryPoint::Pattern)
197 /// Returns `text`, parsed as an expression, but only if it has no errors.
198 pub fn parse(text: &str) -> Result<Self, ()> {
199 parsing::parse_text_as(text, parser::ParserEntryPoint::Expr)
204 /// Returns `text`, parsed as an item, but only if it has no errors.
205 pub fn parse(text: &str) -> Result<Self, ()> {
206 parsing::parse_text_as(text, parser::ParserEntryPoint::Item)
211 /// Returns `text`, parsed as an type reference, but only if it has no errors.
212 pub fn parse(text: &str) -> Result<Self, ()> {
213 parsing::parse_text_as(text, parser::ParserEntryPoint::Type)
218 /// Returns `text`, parsed as an attribute, but only if it has no errors.
219 pub fn parse(text: &str) -> Result<Self, ()> {
220 parsing::parse_text_as(text, parser::ParserEntryPoint::Attr)
225 /// Returns `text`, parsed as statement, but only if it has no errors.
226 pub fn parse(text: &str) -> Result<Self, ()> {
227 parsing::parse_text_as(text, parser::ParserEntryPoint::StatementOptionalSemi)
231 /// Matches a `SyntaxNode` against an `ast` type.
238 /// ast::CallExpr(it) => { ... },
239 /// ast::MethodCallExpr(it) => { ... },
240 /// ast::MacroCall(it) => { ... },
246 macro_rules! match_ast {
247 (match $node:ident { $($tt:tt)* }) => { match_ast!(match ($node) { $($tt)* }) };
249 (match ($node:expr) {
250 $( ast::$ast:ident($it:ident) => $res:expr, )*
251 _ => $catch_all:expr $(,)?
253 $( if let Some($it) = ast::$ast::cast($node.clone()) { $res } else )*
258 /// This test does not assert anything and instead just shows off the crate's
261 fn api_walkthrough() {
262 use ast::{ModuleItemOwner, NameOwner};
269 // `SourceFile` is the main entry point.
271 // The `parse` method returns a `Parse` -- a pair of syntax tree and a list
272 // of errors. That is, syntax tree is constructed even in presence of errors.
273 let parse = SourceFile::parse(source_code);
274 assert!(parse.errors().is_empty());
276 // The `tree` method returns an owned syntax node of type `SourceFile`.
277 // Owned nodes are cheap: inside, they are `Rc` handles to the underling data.
278 let file: SourceFile = parse.tree();
280 // `SourceFile` is the root of the syntax tree. We can iterate file's items.
281 // Let's fetch the `foo` function.
283 for item in file.items() {
285 ast::Item::Fn(f) => func = Some(f),
289 let func: ast::Fn = func.unwrap();
291 // Each AST node has a bunch of getters for children. All getters return
292 // `Option`s though, to account for incomplete code. Some getters are common
293 // for several kinds of node. In this case, a trait like `ast::NameOwner`
294 // usually exists. By convention, all ast types should be used with `ast::`
296 let name: Option<ast::Name> = func.name();
297 let name = name.unwrap();
298 assert_eq!(name.text(), "foo");
300 // Let's get the `1 + 1` expression!
301 let body: ast::BlockExpr = func.body().unwrap();
302 let expr: ast::Expr = body.tail_expr().unwrap();
304 // Enums are used to group related ast nodes together, and can be used for
305 // matching. However, because there are no public fields, it's possible to
306 // match only the top level enum: that is the price we pay for increased API
308 let bin_expr: &ast::BinExpr = match &expr {
309 ast::Expr::BinExpr(e) => e,
313 // Besides the "typed" AST API, there's an untyped CST one as well.
314 // To switch from AST to CST, call `.syntax()` method:
315 let expr_syntax: &SyntaxNode = expr.syntax();
317 // Note how `expr` and `bin_expr` are in fact the same node underneath:
318 assert!(expr_syntax == bin_expr.syntax());
320 // To go from CST to AST, `AstNode::cast` function is used:
321 let _expr: ast::Expr = match ast::Expr::cast(expr_syntax.clone()) {
323 None => unreachable!(),
326 // The two properties each syntax node has is a `SyntaxKind`:
327 assert_eq!(expr_syntax.kind(), SyntaxKind::BIN_EXPR);
330 assert_eq!(expr_syntax.text_range(), TextRange::new(32.into(), 37.into()));
332 // You can get node's text as a `SyntaxText` object, which will traverse the
333 // tree collecting token's text:
334 let text: SyntaxText = expr_syntax.text();
335 assert_eq!(text.to_string(), "1 + 1");
337 // There's a bunch of traversal methods on `SyntaxNode`:
338 assert_eq!(expr_syntax.parent().as_ref(), Some(body.syntax()));
339 assert_eq!(body.syntax().first_child_or_token().map(|it| it.kind()), Some(T!['{']));
341 expr_syntax.next_sibling_or_token().map(|it| it.kind()),
342 Some(SyntaxKind::WHITESPACE)
345 // As well as some iterator helpers:
346 let f = expr_syntax.ancestors().find_map(ast::Fn::cast);
347 assert_eq!(f, Some(func));
348 assert!(expr_syntax.siblings_with_tokens(Direction::Next).any(|it| it.kind() == T!['}']));
350 expr_syntax.descendants_with_tokens().count(),
351 8, // 5 tokens `1`, ` `, `+`, ` `, `!`
352 // 2 child literal expressions: `1`, `1`
353 // 1 the node itself: `1 + 1`
356 // There's also a `preorder` method with a more fine-grained iteration control:
357 let mut buf = String::new();
359 for event in expr_syntax.preorder_with_tokens() {
361 WalkEvent::Enter(node) => {
362 let text = match &node {
363 NodeOrToken::Node(it) => it.text().to_string(),
364 NodeOrToken::Token(it) => it.text().to_string(),
366 format_to!(buf, "{:indent$}{:?} {:?}\n", " ", text, node.kind(), indent = indent);
369 WalkEvent::Leave(_) => indent -= 2,
372 assert_eq!(indent, 0);
388 // To recursively process the tree, there are three approaches:
389 // 1. explicitly call getter methods on AST nodes.
390 // 2. use descendants and `AstNode::cast`.
391 // 3. use descendants and `match_ast!`.
393 // Here's how the first one looks like:
394 let exprs_cast: Vec<String> = file
397 .filter_map(ast::Expr::cast)
398 .map(|expr| expr.syntax().text().to_string())
401 // An alternative is to use a macro.
402 let mut exprs_visit = Vec::new();
403 for node in file.syntax().descendants() {
407 let res = it.syntax().text().to_string();
408 exprs_visit.push(res);
414 assert_eq!(exprs_cast, exprs_visit);