From 60f4d7bd8c0ecb9f23557464e824140a2be8f41a Mon Sep 17 00:00:00 2001 From: Luca Barbieri Date: Fri, 3 Apr 2020 21:12:09 +0200 Subject: [PATCH] Provide more complete AST accessors to support usage in rustc --- crates/ra_assists/src/handlers/add_impl.rs | 4 +- crates/ra_assists/src/handlers/add_new.rs | 5 +- .../src/handlers/introduce_variable.rs | 4 +- .../ra_assists/src/handlers/merge_imports.rs | 4 +- crates/ra_fmt/src/lib.rs | 6 +- crates/ra_hir_def/src/body/lower.rs | 10 +- crates/ra_hir_def/src/nameres/raw.rs | 4 + crates/ra_hir_def/src/path/lower.rs | 2 +- crates/ra_hir_def/src/path/lower/lower_use.rs | 2 +- crates/ra_hir_def/src/visibility.rs | 4 + crates/ra_hir_ty/src/tests.rs | 4 +- crates/ra_parser/src/syntax_kind/generated.rs | 6 +- crates/ra_syntax/src/ast.rs | 2 +- crates/ra_syntax/src/ast/edit.rs | 26 +- crates/ra_syntax/src/ast/expr_extensions.rs | 4 + crates/ra_syntax/src/ast/extensions.rs | 148 +++---- crates/ra_syntax/src/ast/traits.rs | 32 +- xtask/src/ast_src.rs | 377 ++++++++++++++---- 18 files changed, 433 insertions(+), 211 deletions(-) diff --git a/crates/ra_assists/src/handlers/add_impl.rs b/crates/ra_assists/src/handlers/add_impl.rs index 6622eadb2da..72a201b6d2e 100644 --- a/crates/ra_assists/src/handlers/add_impl.rs +++ b/crates/ra_assists/src/handlers/add_impl.rs @@ -1,5 +1,5 @@ use ra_syntax::{ - ast::{self, AstNode, NameOwner, TypeParamsOwner}, + ast::{self, AstNode, AstToken, NameOwner, TypeParamsOwner}, TextUnit, }; use stdx::{format_to, SepBy}; @@ -42,7 +42,7 @@ pub(crate) fn add_impl(ctx: AssistCtx) -> Option { if let Some(type_params) = type_params { let lifetime_params = type_params .lifetime_params() - .filter_map(|it| it.lifetime_token()) + .filter_map(|it| it.lifetime()) .map(|it| it.text().clone()); let type_params = type_params.type_params().filter_map(|it| it.name()).map(|it| it.text().clone()); diff --git a/crates/ra_assists/src/handlers/add_new.rs b/crates/ra_assists/src/handlers/add_new.rs index 240b19fa378..c10397249fd 100644 --- a/crates/ra_assists/src/handlers/add_new.rs +++ b/crates/ra_assists/src/handlers/add_new.rs @@ -1,7 +1,8 @@ use hir::Adt; use ra_syntax::{ ast::{ - self, AstNode, NameOwner, StructKind, TypeAscriptionOwner, TypeParamsOwner, VisibilityOwner, + self, AstNode, AstToken, NameOwner, StructKind, TypeAscriptionOwner, TypeParamsOwner, + VisibilityOwner, }, TextUnit, T, }; @@ -105,7 +106,7 @@ fn generate_impl_text(strukt: &ast::StructDef, code: &str) -> String { if let Some(type_params) = type_params { let lifetime_params = type_params .lifetime_params() - .filter_map(|it| it.lifetime_token()) + .filter_map(|it| it.lifetime()) .map(|it| it.text().clone()); let type_params = type_params.type_params().filter_map(|it| it.name()).map(|it| it.text().clone()); diff --git a/crates/ra_assists/src/handlers/introduce_variable.rs b/crates/ra_assists/src/handlers/introduce_variable.rs index 1edbdc14c74..9963f884bb1 100644 --- a/crates/ra_assists/src/handlers/introduce_variable.rs +++ b/crates/ra_assists/src/handlers/introduce_variable.rs @@ -1,5 +1,5 @@ use ra_syntax::{ - ast::{self, AstNode}, + ast::{self, AstElement, AstNode}, SyntaxKind::{ BLOCK_EXPR, BREAK_EXPR, COMMENT, LAMBDA_EXPR, LOOP_EXPR, MATCH_ARM, PATH_EXPR, RETURN_EXPR, WHITESPACE, @@ -124,7 +124,7 @@ fn anchor_stmt(expr: ast::Expr) -> Option<(SyntaxNode, bool)> { } } - if ast::Stmt::cast(node.clone()).is_some() { + if ast::Stmt::cast_element(node.clone().into()).is_some() { return Some((node, false)); } diff --git a/crates/ra_assists/src/handlers/merge_imports.rs b/crates/ra_assists/src/handlers/merge_imports.rs index 5d4b74e567a..f8b3ddb4e18 100644 --- a/crates/ra_assists/src/handlers/merge_imports.rs +++ b/crates/ra_assists/src/handlers/merge_imports.rs @@ -3,7 +3,7 @@ use ra_syntax::{ algo::{neighbor, SyntaxRewriter}, ast::{self, edit::AstNodeEdit, make}, - AstNode, Direction, InsertPosition, SyntaxElement, T, + AstNode, AstToken, Direction, InsertPosition, SyntaxElement, T, }; use crate::{Assist, AssistCtx, AssistId}; @@ -82,7 +82,7 @@ fn try_merge_trees(old: &ast::UseTree, new: &ast::UseTree) -> Option Option { } else { // Unwrap `{ continue; }` let (stmt,) = block.statements().next_tuple()?; - if has_anything_else(stmt.syntax()) { - return None; - } if let ast::Stmt::ExprStmt(expr_stmt) = stmt { + if has_anything_else(expr_stmt.syntax()) { + return None; + } let expr = expr_stmt.expr()?; match expr.syntax().kind() { CONTINUE_EXPR | BREAK_EXPR | RETURN_EXPR => return Some(expr), diff --git a/crates/ra_hir_def/src/body/lower.rs b/crates/ra_hir_def/src/body/lower.rs index 8d4b8b0f0fb..8338414faac 100644 --- a/crates/ra_hir_def/src/body/lower.rs +++ b/crates/ra_hir_def/src/body/lower.rs @@ -482,14 +482,17 @@ fn collect_block(&mut self, expr: ast::BlockExpr) -> ExprId { self.collect_block_items(&block); let statements = block .statements() - .map(|s| match s { + .filter_map(|s| match s { ast::Stmt::LetStmt(stmt) => { let pat = self.collect_pat_opt(stmt.pat()); let type_ref = stmt.ascribed_type().map(TypeRef::from_ast); let initializer = stmt.initializer().map(|e| self.collect_expr(e)); - Statement::Let { pat, type_ref, initializer } + Some(Statement::Let { pat, type_ref, initializer }) } - ast::Stmt::ExprStmt(stmt) => Statement::Expr(self.collect_expr_opt(stmt.expr())), + ast::Stmt::ExprStmt(stmt) => { + Some(Statement::Expr(self.collect_expr_opt(stmt.expr()))) + } + ast::Stmt::ModuleItem(_) => None, }) .collect(); let tail = block.expr().map(|e| self.collect_expr(e)); @@ -541,6 +544,7 @@ fn collect_block_items(&mut self, block: &ast::Block) { let ast_id = self.expander.ast_id(&def); (TraitLoc { container, ast_id }.intern(self.db).into(), def.name()) } + ast::ModuleItem::ExternBlock(_) => continue, // FIXME: collect from extern blocks ast::ModuleItem::ImplDef(_) | ast::ModuleItem::UseItem(_) | ast::ModuleItem::ExternCrateItem(_) diff --git a/crates/ra_hir_def/src/nameres/raw.rs b/crates/ra_hir_def/src/nameres/raw.rs index 8f190e7f917..a9dff3a5d5a 100644 --- a/crates/ra_hir_def/src/nameres/raw.rs +++ b/crates/ra_hir_def/src/nameres/raw.rs @@ -266,6 +266,10 @@ fn add_item(&mut self, current_module: Option>, item: ast::Modul self.add_macro(current_module, it); return; } + ast::ModuleItem::ExternBlock(_) => { + // FIXME: add extern block + return; + } }; if let Some(name) = name { let name = name.as_name(); diff --git a/crates/ra_hir_def/src/path/lower.rs b/crates/ra_hir_def/src/path/lower.rs index 4900000fe49..3c13cb2c788 100644 --- a/crates/ra_hir_def/src/path/lower.rs +++ b/crates/ra_hir_def/src/path/lower.rs @@ -28,7 +28,7 @@ pub(super) fn lower_path(mut path: ast::Path, hygiene: &Hygiene) -> Option loop { let segment = path.segment()?; - if segment.has_colon_colon() { + if segment.coloncolon().is_some() { kind = PathKind::Abs; } diff --git a/crates/ra_hir_def/src/path/lower/lower_use.rs b/crates/ra_hir_def/src/path/lower/lower_use.rs index 278d5196e7b..6ec944228cf 100644 --- a/crates/ra_hir_def/src/path/lower/lower_use.rs +++ b/crates/ra_hir_def/src/path/lower/lower_use.rs @@ -34,7 +34,7 @@ pub(crate) fn lower_use_tree( let alias = tree.alias().map(|a| { a.name().map(|it| it.as_name()).map_or(ImportAlias::Underscore, ImportAlias::Alias) }); - let is_glob = tree.has_star(); + let is_glob = tree.star().is_some(); if let Some(ast_path) = tree.path() { // Handle self in a path. // E.g. `use something::{self, <...>}` diff --git a/crates/ra_hir_def/src/visibility.rs b/crates/ra_hir_def/src/visibility.rs index 62513873ef5..1482d3be04d 100644 --- a/crates/ra_hir_def/src/visibility.rs +++ b/crates/ra_hir_def/src/visibility.rs @@ -84,6 +84,10 @@ pub(crate) fn from_ast_with_hygiene_and_default( let path = ModPath { kind: PathKind::Super(1), segments: Vec::new() }; RawVisibility::Module(path) } + ast::VisibilityKind::PubSelf => { + let path = ModPath { kind: PathKind::Plain, segments: Vec::new() }; + RawVisibility::Module(path) + } ast::VisibilityKind::Pub => RawVisibility::Public, } } diff --git a/crates/ra_hir_ty/src/tests.rs b/crates/ra_hir_ty/src/tests.rs index 608408d88c2..ac096623682 100644 --- a/crates/ra_hir_ty/src/tests.rs +++ b/crates/ra_hir_ty/src/tests.rs @@ -23,7 +23,7 @@ use ra_db::{fixture::WithFixture, salsa::Database, FilePosition, SourceDatabase}; use ra_syntax::{ algo, - ast::{self, AstNode}, + ast::{self, AstNode, AstToken}, }; use stdx::format_to; @@ -101,7 +101,7 @@ fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String { let node = src_ptr.value.to_node(&src_ptr.file_syntax(&db)); let (range, text) = if let Some(self_param) = ast::SelfParam::cast(node.clone()) { - (self_param.self_kw_token().text_range(), "self".to_string()) + (self_param.self_kw().unwrap().syntax().text_range(), "self".to_string()) } else { (src_ptr.value.range(), node.text().to_string().replace("\n", " ")) }; diff --git a/crates/ra_parser/src/syntax_kind/generated.rs b/crates/ra_parser/src/syntax_kind/generated.rs index 4c16cf1cd9a..004f4e56431 100644 --- a/crates/ra_parser/src/syntax_kind/generated.rs +++ b/crates/ra_parser/src/syntax_kind/generated.rs @@ -105,6 +105,7 @@ pub enum SyntaxKind { DEFAULT_KW, EXISTENTIAL_KW, UNION_KW, + RAW_KW, INT_NUMBER, FLOAT_NUMBER, CHAR, @@ -258,7 +259,7 @@ pub fn is_keyword(self) -> bool { | IMPL_KW | IN_KW | LET_KW | LOOP_KW | MACRO_KW | MATCH_KW | MOD_KW | MOVE_KW | MUT_KW | PUB_KW | REF_KW | RETURN_KW | SELF_KW | STATIC_KW | STRUCT_KW | SUPER_KW | TRAIT_KW | TRUE_KW | TRY_KW | TYPE_KW | UNSAFE_KW | USE_KW | WHERE_KW | WHILE_KW - | AUTO_KW | DEFAULT_KW | EXISTENTIAL_KW | UNION_KW => true, + | AUTO_KW | DEFAULT_KW | EXISTENTIAL_KW | UNION_KW | RAW_KW => true, _ => false, } } @@ -651,4 +652,7 @@ macro_rules! T { ( union ) => { $crate::SyntaxKind::UNION_KW }; + ( raw ) => { + $crate::SyntaxKind::RAW_KW + }; } diff --git a/crates/ra_syntax/src/ast.rs b/crates/ra_syntax/src/ast.rs index ab0f44dd2e0..c81b68d3e29 100644 --- a/crates/ra_syntax/src/ast.rs +++ b/crates/ra_syntax/src/ast.rs @@ -271,7 +271,7 @@ fn foo() let pred = predicates.next().unwrap(); let mut bounds = pred.type_bound_list().unwrap().bounds(); - assert_eq!("'a", pred.lifetime_token().unwrap().text()); + assert_eq!("'a", pred.lifetime().unwrap().text()); assert_bound("'b", bounds.next()); assert_bound("'c", bounds.next()); diff --git a/crates/ra_syntax/src/ast/edit.rs b/crates/ra_syntax/src/ast/edit.rs index b69cae234cf..d7931099535 100644 --- a/crates/ra_syntax/src/ast/edit.rs +++ b/crates/ra_syntax/src/ast/edit.rs @@ -99,7 +99,7 @@ pub fn append_item(&self, item: ast::ImplItem) -> ast::ItemList { None => match self.l_curly() { Some(it) => ( " ".to_string() + &leading_indent(self.syntax()).unwrap_or_default(), - InsertPosition::After(it), + InsertPosition::After(it.syntax().clone().into()), ), None => return self.clone(), }, @@ -109,10 +109,6 @@ pub fn append_item(&self, item: ast::ImplItem) -> ast::ItemList { [ws.ws().into(), item.syntax().clone().into()].into(); self.insert_children(position, to_insert) } - - fn l_curly(&self) -> Option { - self.syntax().children_with_tokens().find(|it| it.kind() == T!['{']) - } } impl ast::RecordFieldList { @@ -147,7 +143,7 @@ pub fn insert_field( macro_rules! after_l_curly { () => {{ let anchor = match self.l_curly() { - Some(it) => it, + Some(it) => it.syntax().clone().into(), None => return self.clone(), }; InsertPosition::After(anchor) @@ -189,24 +185,20 @@ macro_rules! after_field { self.insert_children(position, to_insert) } - - fn l_curly(&self) -> Option { - self.syntax().children_with_tokens().find(|it| it.kind() == T!['{']) - } } impl ast::TypeParam { #[must_use] pub fn remove_bounds(&self) -> ast::TypeParam { - let colon = match self.colon_token() { + let colon = match self.colon() { Some(it) => it, None => return self.clone(), }; let end = match self.type_bound_list() { Some(it) => it.syntax().clone().into(), - None => colon.clone().into(), + None => colon.syntax().clone().into(), }; - self.replace_children(colon.into()..=end, iter::empty()) + self.replace_children(colon.syntax().clone().into()..=end, iter::empty()) } } @@ -305,8 +297,12 @@ pub fn split_prefix(&self, prefix: &ast::Path) -> ast::UseTree { Some(it) => it, None => return self.clone(), }; - let use_tree = - make::use_tree(suffix.clone(), self.use_tree_list(), self.alias(), self.has_star()); + let use_tree = make::use_tree( + suffix.clone(), + self.use_tree_list(), + self.alias(), + self.star().is_some(), + ); let nested = make::use_tree_list(iter::once(use_tree)); return make::use_tree(prefix.clone(), Some(nested), None, false); diff --git a/crates/ra_syntax/src/ast/expr_extensions.rs b/crates/ra_syntax/src/ast/expr_extensions.rs index 8bbd946c071..40c8fca3be3 100644 --- a/crates/ra_syntax/src/ast/expr_extensions.rs +++ b/crates/ra_syntax/src/ast/expr_extensions.rs @@ -52,6 +52,10 @@ impl ast::RefExpr { pub fn is_mut(&self) -> bool { self.syntax().children_with_tokens().any(|n| n.kind() == T![mut]) } + + pub fn raw_token(&self) -> Option { + None // FIXME: implement &raw + } } #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] diff --git a/crates/ra_syntax/src/ast/extensions.rs b/crates/ra_syntax/src/ast/extensions.rs index bf7d137be7d..400eba210af 100644 --- a/crates/ra_syntax/src/ast/extensions.rs +++ b/crates/ra_syntax/src/ast/extensions.rs @@ -4,7 +4,10 @@ use itertools::Itertools; use crate::{ - ast::{self, child_opt, children, AstNode, AttrInput, NameOwner, SyntaxNode}, + ast::{ + self, child_opt, child_token_opt, children, AstElement, AstNode, AstToken, AttrInput, + NameOwner, SyntaxNode, + }, SmolStr, SyntaxElement, SyntaxKind::*, SyntaxToken, T, @@ -130,13 +133,6 @@ pub fn kind(&self) -> Option { }; Some(res) } - - pub fn has_colon_colon(&self) -> bool { - match self.syntax.first_child_or_token().map(|s| s.kind()) { - Some(T![::]) => true, - _ => false, - } - } } impl ast::Path { @@ -154,12 +150,6 @@ pub fn has_semi(&self) -> bool { } } -impl ast::UseTree { - pub fn has_star(&self) -> bool { - self.syntax().children_with_tokens().any(|it| it.kind() == T![*]) - } -} - impl ast::UseTreeList { pub fn parent_use_tree(&self) -> ast::UseTree { self.syntax() @@ -167,20 +157,6 @@ pub fn parent_use_tree(&self) -> ast::UseTree { .and_then(ast::UseTree::cast) .expect("UseTreeLists are always nested in UseTrees") } - pub fn l_curly(&self) -> Option { - self.token(T!['{']) - } - - pub fn r_curly(&self) -> Option { - self.token(T!['}']) - } - - fn token(&self, kind: SyntaxKind) -> Option { - self.syntax() - .children_with_tokens() - .filter_map(|it| it.into_token()) - .find(|it| it.kind() == kind) - } } impl ast::ImplDef { @@ -387,24 +363,9 @@ pub enum SelfParamKind { } impl ast::SelfParam { - pub fn self_kw_token(&self) -> SyntaxToken { - self.syntax() - .children_with_tokens() - .filter_map(|it| it.into_token()) - .find(|it| it.kind() == T![self]) - .expect("invalid tree: self param must have self") - } - pub fn kind(&self) -> SelfParamKind { - let borrowed = self.syntax().children_with_tokens().any(|n| n.kind() == T![&]); - if borrowed { - // check for a `mut` coming after the & -- `mut &self` != `&mut self` - if self - .syntax() - .children_with_tokens() - .skip_while(|n| n.kind() != T![&]) - .any(|n| n.kind() == T![mut]) - { + if self.amp().is_some() { + if self.amp_mut_kw().is_some() { SelfParamKind::MutRef } else { SelfParamKind::Ref @@ -413,32 +374,23 @@ pub fn kind(&self) -> SelfParamKind { SelfParamKind::Owned } } -} -impl ast::LifetimeParam { - pub fn lifetime_token(&self) -> Option { + /// the "mut" in "mut self", not the one in "&mut self" + pub fn mut_kw(&self) -> Option { self.syntax() .children_with_tokens() .filter_map(|it| it.into_token()) - .find(|it| it.kind() == LIFETIME) + .take_while(|it| it.kind() != T![&]) + .find_map(ast::MutKw::cast) } -} -impl ast::TypeParam { - pub fn colon_token(&self) -> Option { + /// the "mut" in "&mut self", not the one in "mut self" + pub fn amp_mut_kw(&self) -> Option { self.syntax() .children_with_tokens() .filter_map(|it| it.into_token()) - .find(|it| it.kind() == T![:]) - } -} - -impl ast::WherePred { - pub fn lifetime_token(&self) -> Option { - self.syntax() - .children_with_tokens() - .filter_map(|it| it.into_token()) - .find(|it| it.kind() == LIFETIME) + .skip_while(|it| it.kind() != T![&]) + .find_map(ast::MutKw::cast) } } @@ -449,7 +401,7 @@ pub enum TypeBoundKind { /// for<'a> ... ForType(ast::ForType), /// 'a - Lifetime(ast::SyntaxToken), + Lifetime(ast::Lifetime), } impl ast::TypeBound { @@ -465,21 +417,28 @@ pub fn kind(&self) -> TypeBoundKind { } } - fn lifetime(&self) -> Option { - self.syntax() - .children_with_tokens() - .filter_map(|it| it.into_token()) - .find(|it| it.kind() == LIFETIME) + pub fn has_question_mark(&self) -> bool { + self.question().is_some() } - pub fn question_mark_token(&self) -> Option { + pub fn const_question(&self) -> Option { self.syntax() .children_with_tokens() .filter_map(|it| it.into_token()) - .find(|it| it.kind() == T![?]) + .take_while(|it| it.kind() != T![const]) + .find_map(ast::Question::cast) } - pub fn has_question_mark(&self) -> bool { - self.question_mark_token().is_some() + + pub fn question(&self) -> Option { + if self.const_kw().is_some() { + self.syntax() + .children_with_tokens() + .filter_map(|it| it.into_token()) + .skip_while(|it| it.kind() != T![const]) + .find_map(ast::Question::cast) + } else { + child_token_opt(self) + } } } @@ -493,6 +452,7 @@ pub enum VisibilityKind { In(ast::Path), PubCrate, PubSuper, + PubSelf, Pub, } @@ -504,6 +464,8 @@ pub fn kind(&self) -> VisibilityKind { VisibilityKind::PubCrate } else if self.is_pub_super() { VisibilityKind::PubSuper + } else if self.is_pub_self() { + VisibilityKind::PubSuper } else { VisibilityKind::Pub } @@ -516,6 +478,10 @@ fn is_pub_crate(&self) -> bool { fn is_pub_super(&self) -> bool { self.syntax().children_with_tokens().any(|it| it.kind() == T![super]) } + + fn is_pub_self(&self) -> bool { + self.syntax().children_with_tokens().any(|it| it.kind() == T![self]) + } } impl ast::MacroCall { @@ -528,3 +494,41 @@ pub fn is_macro_rules(&self) -> Option { } } } + +impl ast::LifetimeParam { + pub fn lifetime_bounds(&self) -> impl Iterator { + self.syntax() + .children_with_tokens() + .filter_map(|it| it.into_token()) + .skip_while(|x| x.kind() != T![:]) + .filter_map(ast::Lifetime::cast) + } +} + +impl ast::RangePat { + pub fn start(&self) -> Option { + self.syntax() + .children_with_tokens() + .take_while(|it| !ast::RangeSeparator::can_cast_element(it.kind())) + .filter_map(|it| it.into_node()) + .find_map(ast::Pat::cast) + } + + pub fn end(&self) -> Option { + self.syntax() + .children_with_tokens() + .skip_while(|it| !ast::RangeSeparator::can_cast_element(it.kind())) + .filter_map(|it| it.into_node()) + .find_map(ast::Pat::cast) + } +} + +impl ast::TokenTree { + pub fn left_delimiter(&self) -> Option { + self.syntax().first_child_or_token().and_then(ast::LeftDelimiter::cast_element) + } + + pub fn right_delimiter(&self) -> Option { + self.syntax().last_child_or_token().and_then(ast::RightDelimiter::cast_element) + } +} diff --git a/crates/ra_syntax/src/ast/traits.rs b/crates/ra_syntax/src/ast/traits.rs index 576378306f4..e6f3a4ebb7c 100644 --- a/crates/ra_syntax/src/ast/traits.rs +++ b/crates/ra_syntax/src/ast/traits.rs @@ -4,9 +4,9 @@ use itertools::Itertools; -use crate::{ - ast::{self, child_opt, children, AstChildren, AstNode, AstToken}, - syntax_node::SyntaxElementChildren, +use crate::ast::{ + self, child_elements, child_opt, child_token_opt, child_tokens, children, AstChildElements, + AstChildTokens, AstChildren, AstNode, AstToken, }; pub trait TypeAscriptionOwner: AstNode { @@ -31,6 +31,10 @@ pub trait LoopBodyOwner: AstNode { fn loop_body(&self) -> Option { child_opt(self) } + + fn label(&self) -> Option { + child_opt(self) + } } pub trait ArgListOwner: AstNode { @@ -65,6 +69,10 @@ pub trait TypeBoundsOwner: AstNode { fn type_bound_list(&self) -> Option { child_opt(self) } + + fn colon(&self) -> Option { + child_token_opt(self) + } } pub trait AttrsOwner: AstNode { @@ -74,11 +82,14 @@ fn attrs(&self) -> AstChildren { fn has_atom_attr(&self, atom: &str) -> bool { self.attrs().filter_map(|x| x.as_simple_atom()).any(|x| x == atom) } + fn attr_or_comments(&self) -> AstChildElements { + child_elements(self) + } } pub trait DocCommentsOwner: AstNode { - fn doc_comments(&self) -> CommentIter { - CommentIter { iter: self.syntax().children_with_tokens() } + fn doc_comments(&self) -> AstChildTokens { + child_tokens(self) } /// Returns the textual content of a doc comment block as a single string. @@ -123,14 +134,3 @@ fn doc_comment_text(&self) -> Option { } } } - -pub struct CommentIter { - iter: SyntaxElementChildren, -} - -impl Iterator for CommentIter { - type Item = ast::Comment; - fn next(&mut self) -> Option { - self.iter.by_ref().find_map(|el| el.into_token().and_then(ast::Comment::cast)) - } -} diff --git a/xtask/src/ast_src.rs b/xtask/src/ast_src.rs index d9f51ec3994..3200acc8676 100644 --- a/xtask/src/ast_src.rs +++ b/xtask/src/ast_src.rs @@ -70,7 +70,7 @@ pub(crate) struct KindsSrc<'a> { "match", "mod", "move", "mut", "pub", "ref", "return", "self", "static", "struct", "super", "trait", "true", "try", "type", "unsafe", "use", "where", "while", ], - contextual_keywords: &["auto", "default", "existential", "union"], + contextual_keywords: &["auto", "default", "existential", "union", "raw"], literals: &[ "INT_NUMBER", "FLOAT_NUMBER", @@ -297,235 +297,311 @@ enum $name:ident $(: $($trait:ident),*)? { pub(crate) const AST_SRC: AstSrc = AstSrc { nodes: &ast_nodes! { - struct SourceFile: ModuleItemOwner, FnDefOwner { + struct SourceFile: ModuleItemOwner, FnDefOwner, AttrsOwner { modules: [Module], } struct FnDef: VisibilityOwner, NameOwner, TypeParamsOwner, DocCommentsOwner, AttrsOwner { + Abi, + ConstKw, + DefaultKw, + AsyncKw, + UnsafeKw, + FnKw, ParamList, RetType, body: BlockExpr, + Semi } - struct RetType { TypeRef } + struct RetType { ThinArrow, TypeRef } struct StructDef: VisibilityOwner, NameOwner, TypeParamsOwner, AttrsOwner, DocCommentsOwner { + StructKw, + FieldDefList, + Semi } struct UnionDef: VisibilityOwner, NameOwner, TypeParamsOwner, AttrsOwner, DocCommentsOwner { + UnionKw, RecordFieldDefList, } - struct RecordFieldDefList { fields: [RecordFieldDef] } + struct RecordFieldDefList { LCurly, fields: [RecordFieldDef], RCurly } struct RecordFieldDef: VisibilityOwner, NameOwner, AttrsOwner, DocCommentsOwner, TypeAscriptionOwner { } - struct TupleFieldDefList { fields: [TupleFieldDef] } + struct TupleFieldDefList { LParen, fields: [TupleFieldDef], RParen } struct TupleFieldDef: VisibilityOwner, AttrsOwner { TypeRef, } struct EnumDef: VisibilityOwner, NameOwner, TypeParamsOwner, AttrsOwner, DocCommentsOwner { + EnumKw, variant_list: EnumVariantList, } struct EnumVariantList { + LCurly, variants: [EnumVariant], + RCurly } - struct EnumVariant: NameOwner, DocCommentsOwner, AttrsOwner { + struct EnumVariant: VisibilityOwner, NameOwner, DocCommentsOwner, AttrsOwner { + FieldDefList, + Eq, Expr } struct TraitDef: VisibilityOwner, NameOwner, AttrsOwner, DocCommentsOwner, TypeParamsOwner, TypeBoundsOwner { + UnsafeKw, + AutoKw, + TraitKw, ItemList, } struct Module: VisibilityOwner, NameOwner, AttrsOwner, DocCommentsOwner { + ModKw, ItemList, + Semi } struct ItemList: FnDefOwner, ModuleItemOwner { + LCurly, impl_items: [ImplItem], + RCurly } struct ConstDef: VisibilityOwner, NameOwner, TypeParamsOwner, AttrsOwner, DocCommentsOwner, TypeAscriptionOwner { + DefaultKw, + ConstKw, + Eq, body: Expr, + Semi } struct StaticDef: VisibilityOwner, NameOwner, TypeParamsOwner, AttrsOwner, DocCommentsOwner, TypeAscriptionOwner { + StaticKw, + MutKw, + Eq, body: Expr, + Semi } struct TypeAliasDef: VisibilityOwner, NameOwner, TypeParamsOwner, AttrsOwner, DocCommentsOwner, TypeBoundsOwner { + DefaultKw, + TypeKw, + Eq, TypeRef, + Semi } struct ImplDef: TypeParamsOwner, AttrsOwner { + DefaultKw, + ConstKw, + UnsafeKw, + ImplKw, + Excl, + ForKw, ItemList, } - struct ParenType { TypeRef } - struct TupleType { fields: [TypeRef] } - struct NeverType { } + struct ParenType { LParen, TypeRef, RParen } + struct TupleType { LParen, fields: [TypeRef], RParen } + struct NeverType { Excl } struct PathType { Path } - struct PointerType { TypeRef } - struct ArrayType { TypeRef, Expr } - struct SliceType { TypeRef } - struct ReferenceType { TypeRef } - struct PlaceholderType { } - struct FnPointerType { ParamList, RetType } - struct ForType { TypeRef } - struct ImplTraitType: TypeBoundsOwner {} - struct DynTraitType: TypeBoundsOwner {} + struct PointerType { Star, ConstKw, TypeRef } + struct ArrayType { LBrack, TypeRef, Semi, Expr, RBrack } + struct SliceType { LBrack, TypeRef, RBrack } + struct ReferenceType { Amp, Lifetime, MutKw, TypeRef } + struct PlaceholderType { Underscore } + struct FnPointerType { Abi, UnsafeKw, FnKw, ParamList, RetType } + struct ForType { ForKw, TypeParamList, TypeRef } + struct ImplTraitType: TypeBoundsOwner { ImplKw } + struct DynTraitType: TypeBoundsOwner { DynKw } - struct TupleExpr { exprs: [Expr] } - struct ArrayExpr { exprs: [Expr] } - struct ParenExpr { Expr } + struct TupleExpr: AttrsOwner { LParen, exprs: [Expr], RParen } + struct ArrayExpr: AttrsOwner { LBrack, exprs: [Expr], Semi, RBrack } + struct ParenExpr: AttrsOwner { LParen, Expr, RParen } struct PathExpr { Path } - struct LambdaExpr { + struct LambdaExpr: AttrsOwner { + StaticKw, + AsyncKw, + MoveKw, ParamList, RetType, body: Expr, } - struct IfExpr { Condition } - struct LoopExpr: LoopBodyOwner { } - struct TryBlockExpr { body: BlockExpr } - struct ForExpr: LoopBodyOwner { + struct IfExpr: AttrsOwner { IfKw, Condition } + struct LoopExpr: AttrsOwner, LoopBodyOwner { LoopKw } + struct TryBlockExpr: AttrsOwner { TryKw, body: BlockExpr } + struct ForExpr: AttrsOwner, LoopBodyOwner { + ForKw, Pat, + InKw, iterable: Expr, } - struct WhileExpr: LoopBodyOwner { Condition } - struct ContinueExpr {} - struct BreakExpr { Expr } - struct Label {} - struct BlockExpr { Block } - struct ReturnExpr { Expr } + struct WhileExpr: AttrsOwner, LoopBodyOwner { WhileKw, Condition } + struct ContinueExpr: AttrsOwner { ContinueKw, Lifetime } + struct BreakExpr: AttrsOwner { BreakKw, Lifetime, Expr } + struct Label { Lifetime } + struct BlockExpr: AttrsOwner { Label, UnsafeKw, Block } + struct ReturnExpr: AttrsOwner { Expr } struct CallExpr: ArgListOwner { Expr } - struct MethodCallExpr: ArgListOwner { - Expr, NameRef, TypeArgList, + struct MethodCallExpr: AttrsOwner, ArgListOwner { + Expr, Dot, NameRef, TypeArgList, } - struct IndexExpr {} - struct FieldExpr { Expr, NameRef } - struct AwaitExpr { Expr } - struct TryExpr { Expr } - struct CastExpr { Expr, TypeRef } - struct RefExpr { Expr } - struct PrefixExpr { Expr } - struct BoxExpr { Expr } - struct RangeExpr {} - struct BinExpr {} - struct Literal {} + struct IndexExpr: AttrsOwner { LBrack, RBrack } + struct FieldExpr: AttrsOwner { Expr, Dot, NameRef } + struct AwaitExpr: AttrsOwner { Expr, Dot, AwaitKw } + struct TryExpr: AttrsOwner { TryKw, Expr } + struct CastExpr: AttrsOwner { Expr, AsKw, TypeRef } + struct RefExpr: AttrsOwner { Amp, RawKw, MutKw, Expr } + struct PrefixExpr: AttrsOwner { PrefixOp, Expr } + struct BoxExpr: AttrsOwner { BoxKw, Expr } + struct RangeExpr: AttrsOwner { RangeOp } + struct BinExpr: AttrsOwner { BinOp } + struct Literal { LiteralToken } - struct MatchExpr { Expr, MatchArmList } - struct MatchArmList: AttrsOwner { arms: [MatchArm] } + struct MatchExpr: AttrsOwner { MatchKw, Expr, MatchArmList } + struct MatchArmList: AttrsOwner { LCurly, arms: [MatchArm], RCurly } struct MatchArm: AttrsOwner { pat: Pat, guard: MatchGuard, + FatArrow, Expr, } - struct MatchGuard { Expr } + struct MatchGuard { IfKw, Expr } - struct RecordLit { Path, RecordFieldList } + struct RecordLit { Path, RecordFieldList} struct RecordFieldList { + LCurly, fields: [RecordField], + Dotdot, spread: Expr, + RCurly } - struct RecordField { NameRef, Expr } + struct RecordField: AttrsOwner { NameRef, Colon, Expr } struct OrPat { pats: [Pat] } - struct ParenPat { Pat } - struct RefPat { Pat } - struct BoxPat { Pat } - struct BindPat: NameOwner { Pat } - struct PlaceholderPat { } - struct DotDotPat { } + struct ParenPat { LParen, Pat, RParen } + struct RefPat { Amp, MutKw, Pat } + struct BoxPat { BoxKw, Pat } + struct BindPat: AttrsOwner, NameOwner { RefKw, MutKw, Pat } + struct PlaceholderPat { Underscore } + struct DotDotPat { Dotdot } struct PathPat { Path } - struct SlicePat { args: [Pat] } - struct RangePat {} + struct SlicePat { LBrack, args: [Pat], RBrack } + struct RangePat { RangeSeparator } struct LiteralPat { Literal } struct MacroPat { MacroCall } struct RecordPat { RecordFieldPatList, Path } struct RecordFieldPatList { + LCurly, + pats: [RecordInnerPat], record_field_pats: [RecordFieldPat], bind_pats: [BindPat], + Dotdot, + RCurly } - struct RecordFieldPat: NameOwner { Pat } + struct RecordFieldPat: AttrsOwner, NameOwner { Colon, Pat } - struct TupleStructPat { Path, args: [Pat] } - struct TuplePat { args: [Pat] } + struct TupleStructPat { Path, LParen, args: [Pat], RParen } + struct TuplePat { LParen, args: [Pat], RParen } - struct Visibility {} - struct Name {} - struct NameRef {} + struct Visibility { PubKw, SuperKw, SelfKw, CrateKw } + struct Name { Ident } + struct NameRef { NameRefToken } struct MacroCall: NameOwner, AttrsOwner,DocCommentsOwner { - TokenTree, Path + Path, Excl, TokenTree, Semi } - struct Attr { Path, input: AttrInput } + struct Attr { Pound, Excl, LBrack, Path, Eq, input: AttrInput, RBrack } struct TokenTree {} struct TypeParamList { + LAngle, + generic_params: [GenericParam], type_params: [TypeParam], lifetime_params: [LifetimeParam], + const_params: [ConstParam], + RAngle } struct TypeParam: NameOwner, AttrsOwner, TypeBoundsOwner { + Eq, default_type: TypeRef, } struct ConstParam: NameOwner, AttrsOwner, TypeAscriptionOwner { + Eq, default_val: Expr, } - struct LifetimeParam: AttrsOwner { } - struct TypeBound { TypeRef} + struct LifetimeParam: AttrsOwner { Lifetime} + struct TypeBound { Lifetime, /* Question, */ ConstKw, /* Question, */ TypeRef} struct TypeBoundList { bounds: [TypeBound] } - struct WherePred: TypeBoundsOwner { TypeRef } - struct WhereClause { predicates: [WherePred] } - struct ExprStmt { Expr } - struct LetStmt: TypeAscriptionOwner { + struct WherePred: TypeBoundsOwner { Lifetime, TypeRef } + struct WhereClause { WhereKw, predicates: [WherePred] } + struct Abi { String } + struct ExprStmt: AttrsOwner { Expr, Semi } + struct LetStmt: AttrsOwner, TypeAscriptionOwner { + LetKw, Pat, + Eq, initializer: Expr, } - struct Condition { Pat, Expr } + struct Condition { LetKw, Pat, Eq, Expr } struct Block: AttrsOwner, ModuleItemOwner { + LCurly, statements: [Stmt], + statements_or_semi: [StmtOrSemi], Expr, + RCurly, } struct ParamList { + LParen, SelfParam, params: [Param], + RParen } - struct SelfParam: TypeAscriptionOwner, AttrsOwner { } + struct SelfParam: TypeAscriptionOwner, AttrsOwner { Amp, Lifetime, SelfKw } struct Param: TypeAscriptionOwner, AttrsOwner { Pat, + Dotdotdot } struct UseItem: AttrsOwner, VisibilityOwner { + UseKw, UseTree, } struct UseTree { - Path, UseTreeList, Alias + Path, Star, UseTreeList, Alias } - struct Alias: NameOwner { } - struct UseTreeList { use_trees: [UseTree] } + struct Alias: NameOwner { AsKw } + struct UseTreeList { LCurly, use_trees: [UseTree], RCurly } struct ExternCrateItem: AttrsOwner, VisibilityOwner { - NameRef, Alias, + ExternKw, CrateKw, NameRef, Alias, } struct ArgList { + LParen, args: [Expr], + RParen } struct Path { segment: PathSegment, qualifier: Path, } struct PathSegment { - NameRef, TypeArgList, ParamList, RetType, PathType, + Coloncolon, LAngle, NameRef, TypeArgList, ParamList, RetType, PathType, RAngle } struct TypeArgList { + Coloncolon, + LAngle, + generic_args: [GenericArg], type_args: [TypeArg], lifetime_args: [LifetimeArg], assoc_type_args: [AssocTypeArg], - const_arg: [ConstArg], + const_args: [ConstArg], + RAngle } struct TypeArg { TypeRef } - struct AssocTypeArg { NameRef, TypeRef } - struct LifetimeArg {} - struct ConstArg { Literal, BlockExpr } + struct AssocTypeArg : TypeBoundsOwner { NameRef, Eq, TypeRef } + struct LifetimeArg { Lifetime } + struct ConstArg { Literal, Eq, BlockExpr } struct MacroItems: ModuleItemOwner, FnDefOwner { } @@ -533,12 +609,44 @@ struct MacroStmts { statements: [Stmt], Expr, } + + struct ExternItemList: FnDefOwner, ModuleItemOwner { + LCurly, + extern_items: [ExternItem], + RCurly + } + + struct ExternBlock { + Abi, + ExternItemList + } + + struct MetaItem { + Path, Eq, AttrInput, nested_meta_items: [MetaItem] + } + + struct MacroDef { + Name, TokenTree + } }, enums: &ast_enums! { enum NominalDef: NameOwner, TypeParamsOwner, AttrsOwner { StructDef, EnumDef, UnionDef, } + enum GenericParam { + LifetimeParam, + TypeParam, + ConstParam + } + + enum GenericArg { + LifetimeArg, + TypeArg, + ConstArg, + AssocTypeArg + } + enum TypeRef { ParenType, TupleType, @@ -555,7 +663,7 @@ enum TypeRef { DynTraitType, } - enum ModuleItem: AttrsOwner, VisibilityOwner { + enum ModuleItem: NameOwner, AttrsOwner, VisibilityOwner { StructDef, UnionDef, EnumDef, @@ -569,13 +677,20 @@ enum ModuleItem: AttrsOwner, VisibilityOwner { StaticDef, Module, MacroCall, + ExternBlock } - enum ImplItem: AttrsOwner { - FnDef, TypeAliasDef, ConstDef, + /* impl blocks can also contain MacroCall */ + enum ImplItem: NameOwner, AttrsOwner { + FnDef, TypeAliasDef, ConstDef } - enum Expr { + /* extern blocks can also contain MacroCall */ + enum ExternItem: NameOwner, AttrsOwner, VisibilityOwner { + FnDef, StaticDef + } + + enum Expr: AttrsOwner { TupleExpr, ArrayExpr, ParenExpr, @@ -627,7 +742,93 @@ enum Pat { MacroPat, } + enum RecordInnerPat { + RecordFieldPat, + BindPat + } + enum AttrInput { Literal, TokenTree } - enum Stmt { ExprStmt, LetStmt } + enum Stmt { + ModuleItem, + LetStmt, + ExprStmt, + // macro calls are parsed as expression statements */ + } + enum StmtOrSemi {Stmt, Semi} + + enum LeftDelimiter { LParen, LBrack, LCurly } + enum RightDelimiter { RParen, RBrack, RCurly } + enum RangeSeparator { Dotdot, Dotdotdot, Dotdoteq} + + enum BinOp { + Pipepipe, + Ampamp, + Eqeq, + Neq, + Lteq, + Gteq, + LAngle, + RAngle, + Plus, + Star, + Minus, + Slash, + Percent, + Shl, + Shr, + Caret, + Pipe, + Amp, + Eq, + Pluseq, + Slasheq, + Stareq, + Percenteq, + Shreq, + Shleq, + Minuseq, + Pipeeq, + Ampeq, + Careteq, + } + + enum PrefixOp { + Minus, + Excl, + Star + } + + enum RangeOp { + Dotdot, + Dotdoteq + } + + enum LiteralToken { + IntNumber, + FloatNumber, + String, + RawString, + TrueKw, + FalseKw, + ByteString, + RawByteString, + Char, + Byte + } + + enum NameRefToken { + Ident, + IntNumber + } + + enum FieldDefList { + RecordFieldDefList, + TupleFieldDefList, + } + + enum AttrOrComment { + Attr, + Comment + } }, };