1mod parsing;
23mod ptr;
24mod syntax_error;
25mod syntax_node;
26#[cfg(test)]
27mod tests;
28mod token_text;
29mod validation;
30
31pub mod algo;
32pub mod ast;
33#[doc(hidden)]
34pub mod fuzz;
35pub mod hacks;
36pub mod syntax_editor;
37pub mod ted;
38pub mod utils;
39
40use std::{marker::PhantomData, ops::Range};
41
42use stdx::format_to;
43use triomphe::Arc;
44
45pub use crate::{
46 ast::{AstNode, AstToken},
47 ptr::{AstPtr, SyntaxNodePtr},
48 syntax_error::SyntaxError,
49 syntax_node::{
50 PreorderWithTokens, RustLanguage, SyntaxElement, SyntaxElementChildren, SyntaxNode,
51 SyntaxNodeChildren, SyntaxToken, SyntaxTreeBuilder,
52 },
53 token_text::TokenText,
54};
55pub use parser::{Edition, SyntaxKind, T};
56pub use rowan::{
57 Direction, GreenNode, NodeOrToken, SyntaxText, TextRange, TextSize, TokenAtOffset, WalkEvent,
58 api::Preorder,
59};
60pub use rustc_literal_escaper as unescape;
61pub use smol_str::{SmolStr, SmolStrBuilder, ToSmolStr, format_smolstr};
62
63#[derive(Debug, PartialEq, Eq)]
69pub struct Parse<T> {
70 green: GreenNode,
71 errors: Option<Arc<[SyntaxError]>>,
72 _ty: PhantomData<fn() -> T>,
73}
74
75impl<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
81impl<T> Parse<T> {
82 fn new(green: GreenNode, errors: Vec<SyntaxError>) -> Parse<T> {
83 Parse {
84 green,
85 errors: if errors.is_empty() { None } else { Some(errors.into()) },
86 _ty: PhantomData,
87 }
88 }
89
90 pub fn syntax_node(&self) -> SyntaxNode {
91 SyntaxNode::new_root(self.green.clone())
92 }
93
94 pub fn errors(&self) -> Vec<SyntaxError> {
95 let mut errors = if let Some(e) = self.errors.as_deref() { e.to_vec() } else { vec![] };
96 validation::validate(&self.syntax_node(), &mut errors);
97 errors
98 }
99}
100
101impl<T: AstNode> Parse<T> {
102 pub fn to_syntax(self) -> Parse<SyntaxNode> {
104 Parse { green: self.green, errors: self.errors, _ty: PhantomData }
105 }
106
107 pub fn tree(&self) -> T {
114 T::cast(self.syntax_node()).unwrap()
115 }
116
117 pub fn ok(self) -> Result<T, Vec<SyntaxError>> {
119 match self.errors() {
120 errors if !errors.is_empty() => Err(errors),
121 _ => Ok(self.tree()),
122 }
123 }
124}
125
126impl Parse<SyntaxNode> {
127 pub fn cast<N: AstNode>(self) -> Option<Parse<N>> {
128 if N::cast(self.syntax_node()).is_some() {
129 Some(Parse { green: self.green, errors: self.errors, _ty: PhantomData })
130 } else {
131 None
132 }
133 }
134}
135
136impl Parse<SourceFile> {
137 pub fn debug_dump(&self) -> String {
138 let mut buf = format!("{:#?}", self.tree().syntax());
139 for err in self.errors() {
140 format_to!(buf, "error {:?}: {}\n", err.range(), err);
141 }
142 buf
143 }
144
145 pub fn reparse(&self, delete: TextRange, insert: &str, edition: Edition) -> Parse<SourceFile> {
146 self.incremental_reparse(delete, insert, edition)
147 .unwrap_or_else(|| self.full_reparse(delete, insert, edition))
148 }
149
150 fn incremental_reparse(
151 &self,
152 delete: TextRange,
153 insert: &str,
154 edition: Edition,
155 ) -> Option<Parse<SourceFile>> {
156 parsing::incremental_reparse(
158 self.tree().syntax(),
159 delete,
160 insert,
161 self.errors.as_deref().unwrap_or_default().iter().cloned(),
162 edition,
163 )
164 .map(|(green_node, errors, _reparsed_range)| Parse {
165 green: green_node,
166 errors: if errors.is_empty() { None } else { Some(errors.into()) },
167 _ty: PhantomData,
168 })
169 }
170
171 fn full_reparse(&self, delete: TextRange, insert: &str, edition: Edition) -> Parse<SourceFile> {
172 let mut text = self.tree().syntax().text().to_string();
173 text.replace_range(Range::<usize>::from(delete), insert);
174 SourceFile::parse(&text, edition)
175 }
176}
177
178impl ast::Expr {
179 pub fn parse(text: &str, edition: Edition) -> Parse<ast::Expr> {
188 let _p = tracing::info_span!("Expr::parse").entered();
189 let (green, errors) = parsing::parse_text_at(text, parser::TopEntryPoint::Expr, edition);
190 let root = SyntaxNode::new_root(green.clone());
191
192 assert!(
193 ast::Expr::can_cast(root.kind()) || root.kind() == SyntaxKind::ERROR,
194 "{:?} isn't an expression",
195 root.kind()
196 );
197 Parse::new(green, errors)
198 }
199}
200
201pub use crate::ast::SourceFile;
203
204impl SourceFile {
205 pub fn parse(text: &str, edition: Edition) -> Parse<SourceFile> {
206 let _p = tracing::info_span!("SourceFile::parse").entered();
207 let (green, errors) = parsing::parse_text(text, edition);
208 let root = SyntaxNode::new_root(green.clone());
209
210 assert_eq!(root.kind(), SyntaxKind::SOURCE_FILE);
211 Parse::new(green, errors)
212 }
213}
214
215#[macro_export]
230macro_rules! match_ast {
231 (match $node:ident { $($tt:tt)* }) => { $crate::match_ast!(match ($node) { $($tt)* }) };
232
233 (match ($node:expr) {
234 $( $( $path:ident )::+ ($it:pat) => $res:expr, )*
235 _ => $catch_all:expr $(,)?
236 }) => {{
237 $( if let Some($it) = $($path::)+cast($node.clone()) { $res } else )*
238 { $catch_all }
239 }};
240}
241
242#[test]
245fn api_walkthrough() {
246 use ast::{HasModuleItem, HasName};
247
248 let source_code = "
249 fn foo() {
250 1 + 1
251 }
252 ";
253 let parse = SourceFile::parse(source_code, parser::Edition::CURRENT);
258 assert!(parse.errors().is_empty());
259
260 let file: SourceFile = parse.tree();
263
264 let mut func = None;
267 for item in file.items() {
268 match item {
269 ast::Item::Fn(f) => func = Some(f),
270 _ => unreachable!(),
271 }
272 }
273 let func: ast::Fn = func.unwrap();
274
275 let name: Option<ast::Name> = func.name();
281 let name = name.unwrap();
282 assert_eq!(name.text(), "foo");
283
284 let body: ast::BlockExpr = func.body().unwrap();
286 let stmt_list: ast::StmtList = body.stmt_list().unwrap();
287 let expr: ast::Expr = stmt_list.tail_expr().unwrap();
288
289 let bin_expr: &ast::BinExpr = match &expr {
294 ast::Expr::BinExpr(e) => e,
295 _ => unreachable!(),
296 };
297
298 let expr_syntax: &SyntaxNode = expr.syntax();
301
302 assert!(expr_syntax == bin_expr.syntax());
304
305 let _expr: ast::Expr = match ast::Expr::cast(expr_syntax.clone()) {
307 Some(e) => e,
308 None => unreachable!(),
309 };
310
311 assert_eq!(expr_syntax.kind(), SyntaxKind::BIN_EXPR);
313
314 assert_eq!(expr_syntax.text_range(), TextRange::new(32.into(), 37.into()));
316
317 let text: SyntaxText = expr_syntax.text();
320 assert_eq!(text.to_string(), "1 + 1");
321
322 assert_eq!(expr_syntax.parent().as_ref(), Some(stmt_list.syntax()));
324 assert_eq!(stmt_list.syntax().first_child_or_token().map(|it| it.kind()), Some(T!['{']));
325 assert_eq!(
326 expr_syntax.next_sibling_or_token().map(|it| it.kind()),
327 Some(SyntaxKind::WHITESPACE)
328 );
329
330 let f = expr_syntax.ancestors().find_map(ast::Fn::cast);
332 assert_eq!(f, Some(func));
333 assert!(expr_syntax.siblings_with_tokens(Direction::Next).any(|it| it.kind() == T!['}']));
334 assert_eq!(
335 expr_syntax.descendants_with_tokens().count(),
336 8, );
340
341 let mut buf = String::new();
343 let mut indent = 0;
344 for event in expr_syntax.preorder_with_tokens() {
345 match event {
346 WalkEvent::Enter(node) => {
347 let text = match &node {
348 NodeOrToken::Node(it) => it.text().to_string(),
349 NodeOrToken::Token(it) => it.text().to_owned(),
350 };
351 format_to!(buf, "{:indent$}{:?} {:?}\n", " ", text, node.kind(), indent = indent);
352 indent += 2;
353 }
354 WalkEvent::Leave(_) => indent -= 2,
355 }
356 }
357 assert_eq!(indent, 0);
358 assert_eq!(
359 buf.trim(),
360 r#"
361"1 + 1" BIN_EXPR
362 "1" LITERAL
363 "1" INT_NUMBER
364 " " WHITESPACE
365 "+" PLUS
366 " " WHITESPACE
367 "1" LITERAL
368 "1" INT_NUMBER
369"#
370 .trim()
371 );
372
373 let exprs_cast: Vec<String> = file
380 .syntax()
381 .descendants()
382 .filter_map(ast::Expr::cast)
383 .map(|expr| expr.syntax().text().to_string())
384 .collect();
385
386 let mut exprs_visit = Vec::new();
388 for node in file.syntax().descendants() {
389 match_ast! {
390 match node {
391 ast::Expr(it) => {
392 let res = it.syntax().text().to_string();
393 exprs_visit.push(res);
394 },
395 _ => (),
396 }
397 }
398 }
399 assert_eq!(exprs_cast, exprs_visit);
400}