feat: add support for feature attributes in struct literal

Signed-off-by: Benjamin Coenen <5719034+bnjjj@users.noreply.github.com>
This commit is contained in:
Benjamin Coenen 2020-04-09 18:37:34 +02:00
commit c1317d6923
28 changed files with 7648 additions and 8155 deletions

View file

@ -1,5 +1,5 @@
use ra_syntax::{ use ra_syntax::{
ast::{self, AstNode, NameOwner, TypeParamsOwner}, ast::{self, AstNode, AstToken, NameOwner, TypeParamsOwner},
TextUnit, TextUnit,
}; };
use stdx::{format_to, SepBy}; use stdx::{format_to, SepBy};
@ -42,7 +42,7 @@ pub(crate) fn add_impl(ctx: AssistCtx) -> Option<Assist> {
if let Some(type_params) = type_params { if let Some(type_params) = type_params {
let lifetime_params = type_params let lifetime_params = type_params
.lifetime_params() .lifetime_params()
.filter_map(|it| it.lifetime_token()) .filter_map(|it| it.lifetime())
.map(|it| it.text().clone()); .map(|it| it.text().clone());
let type_params = let type_params =
type_params.type_params().filter_map(|it| it.name()).map(|it| it.text().clone()); type_params.type_params().filter_map(|it| it.name()).map(|it| it.text().clone());

View file

@ -1,7 +1,8 @@
use hir::Adt; use hir::Adt;
use ra_syntax::{ use ra_syntax::{
ast::{ ast::{
self, AstNode, NameOwner, StructKind, TypeAscriptionOwner, TypeParamsOwner, VisibilityOwner, self, AstNode, AstToken, NameOwner, StructKind, TypeAscriptionOwner, TypeParamsOwner,
VisibilityOwner,
}, },
TextUnit, T, TextUnit, T,
}; };
@ -105,7 +106,7 @@ fn generate_impl_text(strukt: &ast::StructDef, code: &str) -> String {
if let Some(type_params) = type_params { if let Some(type_params) = type_params {
let lifetime_params = type_params let lifetime_params = type_params
.lifetime_params() .lifetime_params()
.filter_map(|it| it.lifetime_token()) .filter_map(|it| it.lifetime())
.map(|it| it.text().clone()); .map(|it| it.text().clone());
let type_params = let type_params =
type_params.type_params().filter_map(|it| it.name()).map(|it| it.text().clone()); type_params.type_params().filter_map(|it| it.name()).map(|it| it.text().clone());

View file

@ -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(node.clone().into()).is_some() {
return Some((node, false)); return Some((node, false));
} }

View file

@ -3,7 +3,7 @@ use std::iter::successors;
use ra_syntax::{ use ra_syntax::{
algo::{neighbor, SyntaxRewriter}, algo::{neighbor, SyntaxRewriter},
ast::{self, edit::AstNodeEdit, make}, ast::{self, edit::AstNodeEdit, make},
AstNode, Direction, InsertPosition, SyntaxElement, T, AstNode, AstToken, Direction, InsertPosition, SyntaxElement, T,
}; };
use crate::{Assist, AssistCtx, AssistId}; use crate::{Assist, AssistCtx, AssistId};
@ -82,7 +82,7 @@ fn try_merge_trees(old: &ast::UseTree, new: &ast::UseTree) -> Option<ast::UseTre
.filter(|it| it.kind() != T!['{'] && it.kind() != T!['}']), .filter(|it| it.kind() != T!['{'] && it.kind() != T!['}']),
); );
let use_tree_list = lhs.use_tree_list()?; let use_tree_list = lhs.use_tree_list()?;
let pos = InsertPosition::Before(use_tree_list.r_curly()?.into()); let pos = InsertPosition::Before(use_tree_list.r_curly()?.syntax().clone().into());
let use_tree_list = use_tree_list.insert_children(pos, to_insert); let use_tree_list = use_tree_list.insert_children(pos, to_insert);
Some(lhs.with_use_tree_list(use_tree_list)) Some(lhs.with_use_tree_list(use_tree_list))
} }

View file

@ -60,10 +60,10 @@ pub fn extract_trivial_expression(block: &ast::BlockExpr) -> Option<ast::Expr> {
} else { } else {
// Unwrap `{ continue; }` // Unwrap `{ continue; }`
let (stmt,) = block.statements().next_tuple()?; let (stmt,) = block.statements().next_tuple()?;
if has_anything_else(stmt.syntax()) { if let ast::Stmt::ExprStmt(expr_stmt) = stmt {
if has_anything_else(expr_stmt.syntax()) {
return None; return None;
} }
if let ast::Stmt::ExprStmt(expr_stmt) = stmt {
let expr = expr_stmt.expr()?; let expr = expr_stmt.expr()?;
match expr.syntax().kind() { match expr.syntax().kind() {
CONTINUE_EXPR | BREAK_EXPR | RETURN_EXPR => return Some(expr), CONTINUE_EXPR | BREAK_EXPR | RETURN_EXPR => return Some(expr),

View file

@ -497,14 +497,16 @@ impl ExprCollector<'_> {
self.collect_block_items(&block); self.collect_block_items(&block);
let statements = block let statements = block
.statements() .statements()
.map(|s| match s { .filter_map(|s| match s {
ast::Stmt::LetStmt(stmt) => { ast::Stmt::LetStmt(stmt) => {
let pat = self.collect_pat_opt(stmt.pat()); let pat = self.collect_pat_opt(stmt.pat());
let type_ref = stmt.ascribed_type().map(TypeRef::from_ast); let type_ref = stmt.ascribed_type().map(TypeRef::from_ast);
let initializer = stmt.initializer().map(|e| self.collect_expr(e)); 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) => {
Some(Statement::Expr(self.collect_expr_opt(stmt.expr())))
} }
ast::Stmt::ExprStmt(stmt) => Statement::Expr(self.collect_expr_opt(stmt.expr())),
}) })
.collect(); .collect();
let tail = block.expr().map(|e| self.collect_expr(e)); let tail = block.expr().map(|e| self.collect_expr(e));
@ -556,6 +558,7 @@ impl ExprCollector<'_> {
let ast_id = self.expander.ast_id(&def); let ast_id = self.expander.ast_id(&def);
(TraitLoc { container, ast_id }.intern(self.db).into(), def.name()) (TraitLoc { container, ast_id }.intern(self.db).into(), def.name())
} }
ast::ModuleItem::ExternBlock(_) => continue, // FIXME: collect from extern blocks
ast::ModuleItem::ImplDef(_) ast::ModuleItem::ImplDef(_)
| ast::ModuleItem::UseItem(_) | ast::ModuleItem::UseItem(_)
| ast::ModuleItem::ExternCrateItem(_) | ast::ModuleItem::ExternCrateItem(_)

View file

@ -266,6 +266,10 @@ impl RawItemsCollector {
self.add_macro(current_module, it); self.add_macro(current_module, it);
return; return;
} }
ast::ModuleItem::ExternBlock(_) => {
// FIXME: add extern block
return;
}
}; };
if let Some(name) = name { if let Some(name) = name {
let name = name.as_name(); let name = name.as_name();

View file

@ -28,7 +28,7 @@ pub(super) fn lower_path(mut path: ast::Path, hygiene: &Hygiene) -> Option<Path>
loop { loop {
let segment = path.segment()?; let segment = path.segment()?;
if segment.has_colon_colon() { if segment.coloncolon().is_some() {
kind = PathKind::Abs; kind = PathKind::Abs;
} }

View file

@ -34,7 +34,7 @@ pub(crate) fn lower_use_tree(
let alias = tree.alias().map(|a| { let alias = tree.alias().map(|a| {
a.name().map(|it| it.as_name()).map_or(ImportAlias::Underscore, ImportAlias::Alias) 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() { if let Some(ast_path) = tree.path() {
// Handle self in a path. // Handle self in a path.
// E.g. `use something::{self, <...>}` // E.g. `use something::{self, <...>}`

View file

@ -84,6 +84,10 @@ impl RawVisibility {
let path = ModPath { kind: PathKind::Super(1), segments: Vec::new() }; let path = ModPath { kind: PathKind::Super(1), segments: Vec::new() };
RawVisibility::Module(path) RawVisibility::Module(path)
} }
ast::VisibilityKind::PubSelf => {
let path = ModPath { kind: PathKind::Plain, segments: Vec::new() };
RawVisibility::Module(path)
}
ast::VisibilityKind::Pub => RawVisibility::Public, ast::VisibilityKind::Pub => RawVisibility::Public,
} }
} }

View file

@ -23,7 +23,7 @@ use insta::assert_snapshot;
use ra_db::{fixture::WithFixture, salsa::Database, FilePosition, SourceDatabase}; use ra_db::{fixture::WithFixture, salsa::Database, FilePosition, SourceDatabase};
use ra_syntax::{ use ra_syntax::{
algo, algo,
ast::{self, AstNode}, ast::{self, AstNode, AstToken},
}; };
use stdx::format_to; 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 node = src_ptr.value.to_node(&src_ptr.file_syntax(&db));
let (range, text) = if let Some(self_param) = ast::SelfParam::cast(node.clone()) { 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 { } else {
(src_ptr.value.range(), node.text().to_string().replace("\n", " ")) (src_ptr.value.range(), node.text().to_string().replace("\n", " "))
}; };

View file

@ -245,7 +245,7 @@ fn opt_fn_ret_type(p: &mut Parser) -> bool {
if p.at(T![->]) { if p.at(T![->]) {
let m = p.start(); let m = p.start();
p.bump(T![->]); p.bump(T![->]);
types::type_(p); types::type_no_bounds(p);
m.complete(p, RET_TYPE); m.complete(p, RET_TYPE);
true true
} else { } else {

View file

@ -105,6 +105,7 @@ pub enum SyntaxKind {
DEFAULT_KW, DEFAULT_KW,
EXISTENTIAL_KW, EXISTENTIAL_KW,
UNION_KW, UNION_KW,
RAW_KW,
INT_NUMBER, INT_NUMBER,
FLOAT_NUMBER, FLOAT_NUMBER,
CHAR, CHAR,
@ -258,7 +259,7 @@ impl SyntaxKind {
| IMPL_KW | IN_KW | LET_KW | LOOP_KW | MACRO_KW | MATCH_KW | MOD_KW | MOVE_KW | 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 | 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 | 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, _ => false,
} }
} }
@ -651,4 +652,7 @@ macro_rules! T {
( union ) => { ( union ) => {
$crate::SyntaxKind::UNION_KW $crate::SyntaxKind::UNION_KW
}; };
( raw ) => {
$crate::SyntaxKind::RAW_KW
};
} }

View file

@ -7,7 +7,7 @@ use std::{
use itertools::Itertools; use itertools::Itertools;
use ra_text_edit::TextEditBuilder; use ra_text_edit::TextEditBuilder;
use rustc_hash::{FxHashMap, FxHashSet}; use rustc_hash::FxHashMap;
use crate::{ use crate::{
AstNode, Direction, NodeOrToken, SyntaxElement, SyntaxNode, SyntaxNodePtr, SyntaxToken, AstNode, Direction, NodeOrToken, SyntaxElement, SyntaxNode, SyntaxNodePtr, SyntaxToken,
@ -72,8 +72,18 @@ pub fn find_covering_element(root: &SyntaxNode, range: TextRange) -> SyntaxEleme
} }
pub fn least_common_ancestor(u: &SyntaxNode, v: &SyntaxNode) -> Option<SyntaxNode> { pub fn least_common_ancestor(u: &SyntaxNode, v: &SyntaxNode) -> Option<SyntaxNode> {
let u_ancestors = u.ancestors().collect::<FxHashSet<SyntaxNode>>(); if u == v {
v.ancestors().find(|it| u_ancestors.contains(it)) return Some(u.clone());
}
let u_depth = u.ancestors().count();
let v_depth = v.ancestors().count();
let keep = u_depth.min(v_depth);
let u_candidates = u.ancestors().skip(u_depth - keep);
let v_canidates = v.ancestors().skip(v_depth - keep);
let (res, _) = u_candidates.zip(v_canidates).find(|(x, y)| x == y)?;
Some(res)
} }
pub fn neighbor<T: AstNode>(me: &T, direction: Direction) -> Option<T> { pub fn neighbor<T: AstNode>(me: &T, direction: Direction) -> Option<T> {

View file

@ -21,7 +21,7 @@ pub use self::{
AttrKind, FieldKind, PathSegmentKind, SelfParamKind, SlicePatComponents, StructKind, AttrKind, FieldKind, PathSegmentKind, SelfParamKind, SlicePatComponents, StructKind,
TypeBoundKind, VisibilityKind, TypeBoundKind, VisibilityKind,
}, },
generated::*, generated::{nodes::*, tokens::*},
tokens::*, tokens::*,
traits::*, traits::*,
}; };
@ -64,6 +64,22 @@ pub trait AstToken {
} }
} }
mod support {
use super::{AstChildren, AstNode, AstToken, SyntaxNode};
pub(super) fn child<N: AstNode>(parent: &SyntaxNode) -> Option<N> {
parent.children().find_map(N::cast)
}
pub(super) fn children<N: AstNode>(parent: &SyntaxNode) -> AstChildren<N> {
AstChildren::new(parent)
}
pub(super) fn token<T: AstToken>(parent: &SyntaxNode) -> Option<T> {
parent.children_with_tokens().filter_map(|it| it.into_token()).find_map(T::cast)
}
}
/// An iterator over `SyntaxNode` children of a particular AST type. /// An iterator over `SyntaxNode` children of a particular AST type.
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct AstChildren<N> { pub struct AstChildren<N> {
@ -271,7 +287,7 @@ where
let pred = predicates.next().unwrap(); let pred = predicates.next().unwrap();
let mut bounds = pred.type_bound_list().unwrap().bounds(); 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("'b", bounds.next());
assert_bound("'c", bounds.next()); assert_bound("'c", bounds.next());

View file

@ -99,7 +99,7 @@ impl ast::ItemList {
None => match self.l_curly() { None => match self.l_curly() {
Some(it) => ( Some(it) => (
" ".to_string() + &leading_indent(self.syntax()).unwrap_or_default(), " ".to_string() + &leading_indent(self.syntax()).unwrap_or_default(),
InsertPosition::After(it), InsertPosition::After(it.syntax().clone().into()),
), ),
None => return self.clone(), None => return self.clone(),
}, },
@ -109,10 +109,6 @@ impl ast::ItemList {
[ws.ws().into(), item.syntax().clone().into()].into(); [ws.ws().into(), item.syntax().clone().into()].into();
self.insert_children(position, to_insert) self.insert_children(position, to_insert)
} }
fn l_curly(&self) -> Option<SyntaxElement> {
self.syntax().children_with_tokens().find(|it| it.kind() == T!['{'])
}
} }
impl ast::RecordFieldList { impl ast::RecordFieldList {
@ -147,7 +143,7 @@ impl ast::RecordFieldList {
macro_rules! after_l_curly { macro_rules! after_l_curly {
() => {{ () => {{
let anchor = match self.l_curly() { let anchor = match self.l_curly() {
Some(it) => it, Some(it) => it.syntax().clone().into(),
None => return self.clone(), None => return self.clone(),
}; };
InsertPosition::After(anchor) InsertPosition::After(anchor)
@ -189,24 +185,20 @@ impl ast::RecordFieldList {
self.insert_children(position, to_insert) self.insert_children(position, to_insert)
} }
fn l_curly(&self) -> Option<SyntaxElement> {
self.syntax().children_with_tokens().find(|it| it.kind() == T!['{'])
}
} }
impl ast::TypeParam { impl ast::TypeParam {
#[must_use] #[must_use]
pub fn remove_bounds(&self) -> ast::TypeParam { pub fn remove_bounds(&self) -> ast::TypeParam {
let colon = match self.colon_token() { let colon = match self.colon() {
Some(it) => it, Some(it) => it,
None => return self.clone(), None => return self.clone(),
}; };
let end = match self.type_bound_list() { let end = match self.type_bound_list() {
Some(it) => it.syntax().clone().into(), 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 @@ impl ast::UseTree {
Some(it) => it, Some(it) => it,
None => return self.clone(), None => return self.clone(),
}; };
let use_tree = let use_tree = make::use_tree(
make::use_tree(suffix.clone(), self.use_tree_list(), self.alias(), self.has_star()); suffix.clone(),
self.use_tree_list(),
self.alias(),
self.star().is_some(),
);
let nested = make::use_tree_list(iter::once(use_tree)); let nested = make::use_tree_list(iter::once(use_tree));
return make::use_tree(prefix.clone(), Some(nested), None, false); return make::use_tree(prefix.clone(), Some(nested), None, false);

View file

@ -52,6 +52,10 @@ impl ast::RefExpr {
pub fn is_mut(&self) -> bool { pub fn is_mut(&self) -> bool {
self.syntax().children_with_tokens().any(|n| n.kind() == T![mut]) self.syntax().children_with_tokens().any(|n| n.kind() == T![mut])
} }
pub fn raw_token(&self) -> Option<SyntaxToken> {
None // FIXME: implement &raw
}
} }
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]

View file

@ -4,7 +4,9 @@
use itertools::Itertools; use itertools::Itertools;
use crate::{ use crate::{
ast::{self, child_opt, children, AstNode, AttrInput, NameOwner, SyntaxNode}, ast::{
self, child_opt, children, support, AstNode, AstToken, AttrInput, NameOwner, SyntaxNode,
},
SmolStr, SyntaxElement, SmolStr, SyntaxElement,
SyntaxKind::*, SyntaxKind::*,
SyntaxToken, T, SyntaxToken, T,
@ -130,13 +132,6 @@ impl ast::PathSegment {
}; };
Some(res) 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 { impl ast::Path {
@ -154,12 +149,6 @@ impl ast::Module {
} }
} }
impl ast::UseTree {
pub fn has_star(&self) -> bool {
self.syntax().children_with_tokens().any(|it| it.kind() == T![*])
}
}
impl ast::UseTreeList { impl ast::UseTreeList {
pub fn parent_use_tree(&self) -> ast::UseTree { pub fn parent_use_tree(&self) -> ast::UseTree {
self.syntax() self.syntax()
@ -167,20 +156,6 @@ impl ast::UseTreeList {
.and_then(ast::UseTree::cast) .and_then(ast::UseTree::cast)
.expect("UseTreeLists are always nested in UseTrees") .expect("UseTreeLists are always nested in UseTrees")
} }
pub fn l_curly(&self) -> Option<SyntaxToken> {
self.token(T!['{'])
}
pub fn r_curly(&self) -> Option<SyntaxToken> {
self.token(T!['}'])
}
fn token(&self, kind: SyntaxKind) -> Option<SyntaxToken> {
self.syntax()
.children_with_tokens()
.filter_map(|it| it.into_token())
.find(|it| it.kind() == kind)
}
} }
impl ast::ImplDef { impl ast::ImplDef {
@ -387,24 +362,9 @@ pub enum SelfParamKind {
} }
impl ast::SelfParam { 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 { pub fn kind(&self) -> SelfParamKind {
let borrowed = self.syntax().children_with_tokens().any(|n| n.kind() == T![&]); if self.amp().is_some() {
if borrowed { if self.amp_mut_kw().is_some() {
// 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])
{
SelfParamKind::MutRef SelfParamKind::MutRef
} else { } else {
SelfParamKind::Ref SelfParamKind::Ref
@ -413,32 +373,23 @@ impl ast::SelfParam {
SelfParamKind::Owned SelfParamKind::Owned
} }
} }
}
impl ast::LifetimeParam { /// the "mut" in "mut self", not the one in "&mut self"
pub fn lifetime_token(&self) -> Option<SyntaxToken> { pub fn mut_kw(&self) -> Option<ast::MutKw> {
self.syntax() self.syntax()
.children_with_tokens() .children_with_tokens()
.filter_map(|it| it.into_token()) .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 { /// the "mut" in "&mut self", not the one in "mut self"
pub fn colon_token(&self) -> Option<SyntaxToken> { pub fn amp_mut_kw(&self) -> Option<ast::MutKw> {
self.syntax() self.syntax()
.children_with_tokens() .children_with_tokens()
.filter_map(|it| it.into_token()) .filter_map(|it| it.into_token())
.find(|it| it.kind() == T![:]) .skip_while(|it| it.kind() != T![&])
} .find_map(ast::MutKw::cast)
}
impl ast::WherePred {
pub fn lifetime_token(&self) -> Option<SyntaxToken> {
self.syntax()
.children_with_tokens()
.filter_map(|it| it.into_token())
.find(|it| it.kind() == LIFETIME)
} }
} }
@ -449,7 +400,7 @@ pub enum TypeBoundKind {
/// for<'a> ... /// for<'a> ...
ForType(ast::ForType), ForType(ast::ForType),
/// 'a /// 'a
Lifetime(ast::SyntaxToken), Lifetime(ast::Lifetime),
} }
impl ast::TypeBound { impl ast::TypeBound {
@ -465,21 +416,28 @@ impl ast::TypeBound {
} }
} }
fn lifetime(&self) -> Option<SyntaxToken> { pub fn has_question_mark(&self) -> bool {
self.syntax() self.question().is_some()
.children_with_tokens()
.filter_map(|it| it.into_token())
.find(|it| it.kind() == LIFETIME)
} }
pub fn question_mark_token(&self) -> Option<SyntaxToken> { pub fn const_question(&self) -> Option<ast::Question> {
self.syntax() self.syntax()
.children_with_tokens() .children_with_tokens()
.filter_map(|it| it.into_token()) .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 question(&self) -> Option<ast::Question> {
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 {
support::token(&self.syntax)
} }
pub fn has_question_mark(&self) -> bool {
self.question_mark_token().is_some()
} }
} }
@ -493,6 +451,7 @@ pub enum VisibilityKind {
In(ast::Path), In(ast::Path),
PubCrate, PubCrate,
PubSuper, PubSuper,
PubSelf,
Pub, Pub,
} }
@ -504,6 +463,8 @@ impl ast::Visibility {
VisibilityKind::PubCrate VisibilityKind::PubCrate
} else if self.is_pub_super() { } else if self.is_pub_super() {
VisibilityKind::PubSuper VisibilityKind::PubSuper
} else if self.is_pub_self() {
VisibilityKind::PubSuper
} else { } else {
VisibilityKind::Pub VisibilityKind::Pub
} }
@ -516,6 +477,10 @@ impl ast::Visibility {
fn is_pub_super(&self) -> bool { fn is_pub_super(&self) -> bool {
self.syntax().children_with_tokens().any(|it| it.kind() == T![super]) 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 { impl ast::MacroCall {
@ -528,3 +493,41 @@ impl ast::MacroCall {
} }
} }
} }
impl ast::LifetimeParam {
pub fn lifetime_bounds(&self) -> impl Iterator<Item = ast::Lifetime> {
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<ast::Pat> {
self.syntax()
.children_with_tokens()
.take_while(|it| !ast::RangeSeparator::can_cast(it.kind()))
.filter_map(|it| it.into_node())
.find_map(ast::Pat::cast)
}
pub fn end(&self) -> Option<ast::Pat> {
self.syntax()
.children_with_tokens()
.skip_while(|it| !ast::RangeSeparator::can_cast(it.kind()))
.filter_map(|it| it.into_node())
.find_map(ast::Pat::cast)
}
}
impl ast::TokenTree {
pub fn left_delimiter(&self) -> Option<ast::LeftDelimiter> {
self.syntax().first_child_or_token()?.into_token().and_then(ast::LeftDelimiter::cast)
}
pub fn right_delimiter(&self) -> Option<ast::RightDelimiter> {
self.syntax().last_child_or_token()?.into_token().and_then(ast::RightDelimiter::cast)
}
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -5,7 +5,7 @@
use itertools::Itertools; use itertools::Itertools;
use crate::{ use crate::{
ast::{self, child_opt, children, AstChildren, AstNode, AstToken}, ast::{self, child_opt, children, support, AstChildren, AstNode, AstToken},
syntax_node::SyntaxElementChildren, syntax_node::SyntaxElementChildren,
}; };
@ -31,6 +31,10 @@ pub trait LoopBodyOwner: AstNode {
fn loop_body(&self) -> Option<ast::BlockExpr> { fn loop_body(&self) -> Option<ast::BlockExpr> {
child_opt(self) child_opt(self)
} }
fn label(&self) -> Option<ast::Label> {
child_opt(self)
}
} }
pub trait ArgListOwner: AstNode { pub trait ArgListOwner: AstNode {
@ -65,6 +69,10 @@ pub trait TypeBoundsOwner: AstNode {
fn type_bound_list(&self) -> Option<ast::TypeBoundList> { fn type_bound_list(&self) -> Option<ast::TypeBoundList> {
child_opt(self) child_opt(self)
} }
fn colon(&self) -> Option<ast::Colon> {
support::token(self.syntax())
}
} }
pub trait AttrsOwner: AstNode { pub trait AttrsOwner: AstNode {

View file

@ -0,0 +1,61 @@
SOURCE_FILE@[0; 40)
FN_DEF@[0; 39)
FN_KW@[0; 2) "fn"
WHITESPACE@[2; 3) " "
NAME@[3; 4)
IDENT@[3; 4) "f"
TYPE_PARAM_LIST@[4; 7)
L_ANGLE@[4; 5) "<"
TYPE_PARAM@[5; 6)
NAME@[5; 6)
IDENT@[5; 6) "T"
R_ANGLE@[6; 7) ">"
PARAM_LIST@[7; 9)
L_PAREN@[7; 8) "("
R_PAREN@[8; 9) ")"
WHITESPACE@[9; 10) " "
WHERE_CLAUSE@[10; 36)
WHERE_KW@[10; 15) "where"
WHITESPACE@[15; 16) " "
WHERE_PRED@[16; 36)
PATH_TYPE@[16; 17)
PATH@[16; 17)
PATH_SEGMENT@[16; 17)
NAME_REF@[16; 17)
IDENT@[16; 17) "T"
COLON@[17; 18) ":"
WHITESPACE@[18; 19) " "
TYPE_BOUND_LIST@[19; 36)
TYPE_BOUND@[19; 29)
PATH_TYPE@[19; 29)
PATH@[19; 29)
PATH_SEGMENT@[19; 29)
NAME_REF@[19; 21)
IDENT@[19; 21) "Fn"
PARAM_LIST@[21; 23)
L_PAREN@[21; 22) "("
R_PAREN@[22; 23) ")"
WHITESPACE@[23; 24) " "
RET_TYPE@[24; 29)
THIN_ARROW@[24; 26) "->"
WHITESPACE@[26; 27) " "
PATH_TYPE@[27; 29)
PATH@[27; 29)
PATH_SEGMENT@[27; 29)
NAME_REF@[27; 29)
IDENT@[27; 29) "u8"
WHITESPACE@[29; 30) " "
PLUS@[30; 31) "+"
WHITESPACE@[31; 32) " "
TYPE_BOUND@[32; 36)
PATH_TYPE@[32; 36)
PATH@[32; 36)
PATH_SEGMENT@[32; 36)
NAME_REF@[32; 36)
IDENT@[32; 36) "Send"
WHITESPACE@[36; 37) " "
BLOCK_EXPR@[37; 39)
BLOCK@[37; 39)
L_CURLY@[37; 38) "{"
R_CURLY@[38; 39) "}"
WHITESPACE@[39; 40) "\n"

View file

@ -0,0 +1 @@
fn f<T>() where T: Fn() -> u8 + Send {}

View file

@ -70,7 +70,7 @@ pub(crate) const KINDS_SRC: KindsSrc = KindsSrc {
"match", "mod", "move", "mut", "pub", "ref", "return", "self", "static", "struct", "super", "match", "mod", "move", "mut", "pub", "ref", "return", "self", "static", "struct", "super",
"trait", "true", "try", "type", "unsafe", "use", "where", "while", "trait", "true", "try", "type", "unsafe", "use", "where", "while",
], ],
contextual_keywords: &["auto", "default", "existential", "union"], contextual_keywords: &["auto", "default", "existential", "union", "raw"],
literals: &[ literals: &[
"INT_NUMBER", "INT_NUMBER",
"FLOAT_NUMBER", "FLOAT_NUMBER",
@ -227,6 +227,7 @@ pub(crate) const KINDS_SRC: KindsSrc = KindsSrc {
pub(crate) struct AstSrc<'a> { pub(crate) struct AstSrc<'a> {
pub(crate) nodes: &'a [AstNodeSrc<'a>], pub(crate) nodes: &'a [AstNodeSrc<'a>],
pub(crate) enums: &'a [AstEnumSrc<'a>], pub(crate) enums: &'a [AstEnumSrc<'a>],
pub(crate) token_enums: &'a [AstEnumSrc<'a>],
} }
pub(crate) struct AstNodeSrc<'a> { pub(crate) struct AstNodeSrc<'a> {
@ -297,235 +298,310 @@ macro_rules! ast_enums {
pub(crate) const AST_SRC: AstSrc = AstSrc { pub(crate) const AST_SRC: AstSrc = AstSrc {
nodes: &ast_nodes! { nodes: &ast_nodes! {
struct SourceFile: ModuleItemOwner, FnDefOwner { struct SourceFile: ModuleItemOwner, FnDefOwner, AttrsOwner {
modules: [Module], modules: [Module],
} }
struct FnDef: VisibilityOwner, NameOwner, TypeParamsOwner, DocCommentsOwner, AttrsOwner { struct FnDef: VisibilityOwner, NameOwner, TypeParamsOwner, DocCommentsOwner, AttrsOwner {
Abi,
ConstKw,
DefaultKw,
AsyncKw,
UnsafeKw,
FnKw,
ParamList, ParamList,
RetType, RetType,
body: BlockExpr, body: BlockExpr,
Semi
} }
struct RetType { TypeRef } struct RetType { ThinArrow, TypeRef }
struct StructDef: VisibilityOwner, NameOwner, TypeParamsOwner, AttrsOwner, DocCommentsOwner { struct StructDef: VisibilityOwner, NameOwner, TypeParamsOwner, AttrsOwner, DocCommentsOwner {
StructKw,
FieldDefList,
Semi
} }
struct UnionDef: VisibilityOwner, NameOwner, TypeParamsOwner, AttrsOwner, DocCommentsOwner { struct UnionDef: VisibilityOwner, NameOwner, TypeParamsOwner, AttrsOwner, DocCommentsOwner {
UnionKw,
RecordFieldDefList, RecordFieldDefList,
} }
struct RecordFieldDefList { fields: [RecordFieldDef] } struct RecordFieldDefList { LCurly, fields: [RecordFieldDef], RCurly }
struct RecordFieldDef: VisibilityOwner, NameOwner, AttrsOwner, DocCommentsOwner, TypeAscriptionOwner { } struct RecordFieldDef: VisibilityOwner, NameOwner, AttrsOwner, DocCommentsOwner, TypeAscriptionOwner { }
struct TupleFieldDefList { fields: [TupleFieldDef] } struct TupleFieldDefList { LParen, fields: [TupleFieldDef], RParen }
struct TupleFieldDef: VisibilityOwner, AttrsOwner { struct TupleFieldDef: VisibilityOwner, AttrsOwner {
TypeRef, TypeRef,
} }
struct EnumDef: VisibilityOwner, NameOwner, TypeParamsOwner, AttrsOwner, DocCommentsOwner { struct EnumDef: VisibilityOwner, NameOwner, TypeParamsOwner, AttrsOwner, DocCommentsOwner {
EnumKw,
variant_list: EnumVariantList, variant_list: EnumVariantList,
} }
struct EnumVariantList { struct EnumVariantList {
LCurly,
variants: [EnumVariant], variants: [EnumVariant],
RCurly
} }
struct EnumVariant: NameOwner, DocCommentsOwner, AttrsOwner { struct EnumVariant: VisibilityOwner, NameOwner, DocCommentsOwner, AttrsOwner {
FieldDefList,
Eq,
Expr Expr
} }
struct TraitDef: VisibilityOwner, NameOwner, AttrsOwner, DocCommentsOwner, TypeParamsOwner, TypeBoundsOwner { struct TraitDef: VisibilityOwner, NameOwner, AttrsOwner, DocCommentsOwner, TypeParamsOwner, TypeBoundsOwner {
UnsafeKw,
AutoKw,
TraitKw,
ItemList, ItemList,
} }
struct Module: VisibilityOwner, NameOwner, AttrsOwner, DocCommentsOwner { struct Module: VisibilityOwner, NameOwner, AttrsOwner, DocCommentsOwner {
ModKw,
ItemList, ItemList,
Semi
} }
struct ItemList: FnDefOwner, ModuleItemOwner { struct ItemList: FnDefOwner, ModuleItemOwner {
LCurly,
impl_items: [ImplItem], impl_items: [ImplItem],
RCurly
} }
struct ConstDef: VisibilityOwner, NameOwner, TypeParamsOwner, AttrsOwner, DocCommentsOwner, TypeAscriptionOwner { struct ConstDef: VisibilityOwner, NameOwner, TypeParamsOwner, AttrsOwner, DocCommentsOwner, TypeAscriptionOwner {
DefaultKw,
ConstKw,
Eq,
body: Expr, body: Expr,
Semi
} }
struct StaticDef: VisibilityOwner, NameOwner, TypeParamsOwner, AttrsOwner, DocCommentsOwner, TypeAscriptionOwner { struct StaticDef: VisibilityOwner, NameOwner, TypeParamsOwner, AttrsOwner, DocCommentsOwner, TypeAscriptionOwner {
StaticKw,
MutKw,
Eq,
body: Expr, body: Expr,
Semi
} }
struct TypeAliasDef: VisibilityOwner, NameOwner, TypeParamsOwner, AttrsOwner, DocCommentsOwner, TypeBoundsOwner { struct TypeAliasDef: VisibilityOwner, NameOwner, TypeParamsOwner, AttrsOwner, DocCommentsOwner, TypeBoundsOwner {
DefaultKw,
TypeKw,
Eq,
TypeRef, TypeRef,
Semi
} }
struct ImplDef: TypeParamsOwner, AttrsOwner { struct ImplDef: TypeParamsOwner, AttrsOwner {
DefaultKw,
ConstKw,
UnsafeKw,
ImplKw,
Excl,
ForKw,
ItemList, ItemList,
} }
struct ParenType { TypeRef } struct ParenType { LParen, TypeRef, RParen }
struct TupleType { fields: [TypeRef] } struct TupleType { LParen, fields: [TypeRef], RParen }
struct NeverType { } struct NeverType { Excl }
struct PathType { Path } struct PathType { Path }
struct PointerType { TypeRef } struct PointerType { Star, ConstKw, TypeRef }
struct ArrayType { TypeRef, Expr } struct ArrayType { LBrack, TypeRef, Semi, Expr, RBrack }
struct SliceType { TypeRef } struct SliceType { LBrack, TypeRef, RBrack }
struct ReferenceType { TypeRef } struct ReferenceType { Amp, Lifetime, MutKw, TypeRef }
struct PlaceholderType { } struct PlaceholderType { Underscore }
struct FnPointerType { ParamList, RetType } struct FnPointerType { Abi, UnsafeKw, FnKw, ParamList, RetType }
struct ForType { TypeRef } struct ForType { ForKw, TypeParamList, TypeRef }
struct ImplTraitType: TypeBoundsOwner {} struct ImplTraitType: TypeBoundsOwner { ImplKw }
struct DynTraitType: TypeBoundsOwner {} struct DynTraitType: TypeBoundsOwner { DynKw }
struct TupleExpr { exprs: [Expr] } struct TupleExpr: AttrsOwner { LParen, exprs: [Expr], RParen }
struct ArrayExpr { exprs: [Expr] } struct ArrayExpr: AttrsOwner { LBrack, exprs: [Expr], Semi, RBrack }
struct ParenExpr { Expr } struct ParenExpr: AttrsOwner { LParen, Expr, RParen }
struct PathExpr { Path } struct PathExpr { Path }
struct LambdaExpr { struct LambdaExpr: AttrsOwner {
StaticKw,
AsyncKw,
MoveKw,
ParamList, ParamList,
RetType, RetType,
body: Expr, body: Expr,
} }
struct IfExpr { Condition } struct IfExpr: AttrsOwner { IfKw, Condition }
struct LoopExpr: LoopBodyOwner { } struct LoopExpr: AttrsOwner, LoopBodyOwner { LoopKw }
struct TryBlockExpr { body: BlockExpr } struct TryBlockExpr: AttrsOwner { TryKw, body: BlockExpr }
struct ForExpr: LoopBodyOwner { struct ForExpr: AttrsOwner, LoopBodyOwner {
ForKw,
Pat, Pat,
InKw,
iterable: Expr, iterable: Expr,
} }
struct WhileExpr: LoopBodyOwner { Condition } struct WhileExpr: AttrsOwner, LoopBodyOwner { WhileKw, Condition }
struct ContinueExpr {} struct ContinueExpr: AttrsOwner { ContinueKw, Lifetime }
struct BreakExpr { Expr } struct BreakExpr: AttrsOwner { BreakKw, Lifetime, Expr }
struct Label {} struct Label { Lifetime }
struct BlockExpr { Block } struct BlockExpr: AttrsOwner { Label, UnsafeKw, Block }
struct ReturnExpr { Expr } struct ReturnExpr: AttrsOwner { Expr }
struct CallExpr: ArgListOwner { Expr } struct CallExpr: ArgListOwner { Expr }
struct MethodCallExpr: ArgListOwner { struct MethodCallExpr: AttrsOwner, ArgListOwner {
Expr, NameRef, TypeArgList, Expr, Dot, NameRef, TypeArgList,
} }
struct IndexExpr {} struct IndexExpr: AttrsOwner { LBrack, RBrack }
struct FieldExpr { Expr, NameRef } struct FieldExpr: AttrsOwner { Expr, Dot, NameRef }
struct AwaitExpr { Expr } struct AwaitExpr: AttrsOwner { Expr, Dot, AwaitKw }
struct TryExpr { Expr } struct TryExpr: AttrsOwner { TryKw, Expr }
struct CastExpr { Expr, TypeRef } struct CastExpr: AttrsOwner { Expr, AsKw, TypeRef }
struct RefExpr { Expr } struct RefExpr: AttrsOwner { Amp, RawKw, MutKw, Expr }
struct PrefixExpr { Expr } struct PrefixExpr: AttrsOwner { PrefixOp, Expr }
struct BoxExpr { Expr } struct BoxExpr: AttrsOwner { BoxKw, Expr }
struct RangeExpr {} struct RangeExpr: AttrsOwner { RangeOp }
struct BinExpr {} struct BinExpr: AttrsOwner { BinOp }
struct Literal {} struct Literal { LiteralToken }
struct MatchExpr { Expr, MatchArmList } struct MatchExpr: AttrsOwner { MatchKw, Expr, MatchArmList }
struct MatchArmList: AttrsOwner { arms: [MatchArm] } struct MatchArmList: AttrsOwner { LCurly, arms: [MatchArm], RCurly }
struct MatchArm: AttrsOwner { struct MatchArm: AttrsOwner {
pat: Pat, pat: Pat,
guard: MatchGuard, guard: MatchGuard,
FatArrow,
Expr, Expr,
} }
struct MatchGuard { Expr } struct MatchGuard { IfKw, Expr }
struct RecordLit { Path, RecordFieldList} struct RecordLit { Path, RecordFieldList}
struct RecordFieldList { struct RecordFieldList {
LCurly,
fields: [RecordField], fields: [RecordField],
Dotdot,
spread: Expr, spread: Expr,
RCurly
} }
struct RecordField { NameRef, Expr } struct RecordField: AttrsOwner { NameRef, Colon, Expr }
struct OrPat { pats: [Pat] } struct OrPat { pats: [Pat] }
struct ParenPat { Pat } struct ParenPat { LParen, Pat, RParen }
struct RefPat { Pat } struct RefPat { Amp, MutKw, Pat }
struct BoxPat { Pat } struct BoxPat { BoxKw, Pat }
struct BindPat: NameOwner { Pat } struct BindPat: AttrsOwner, NameOwner { RefKw, MutKw, Pat }
struct PlaceholderPat { } struct PlaceholderPat { Underscore }
struct DotDotPat { } struct DotDotPat { Dotdot }
struct PathPat { Path } struct PathPat { Path }
struct SlicePat { args: [Pat] } struct SlicePat { LBrack, args: [Pat], RBrack }
struct RangePat {} struct RangePat { RangeSeparator }
struct LiteralPat { Literal } struct LiteralPat { Literal }
struct MacroPat { MacroCall } struct MacroPat { MacroCall }
struct RecordPat { RecordFieldPatList, Path } struct RecordPat { RecordFieldPatList, Path }
struct RecordFieldPatList { struct RecordFieldPatList {
LCurly,
pats: [RecordInnerPat],
record_field_pats: [RecordFieldPat], record_field_pats: [RecordFieldPat],
bind_pats: [BindPat], bind_pats: [BindPat],
Dotdot,
RCurly
} }
struct RecordFieldPat: NameOwner { Pat } struct RecordFieldPat: AttrsOwner, NameOwner { Colon, Pat }
struct TupleStructPat { Path, args: [Pat] } struct TupleStructPat { Path, LParen, args: [Pat], RParen }
struct TuplePat { args: [Pat] } struct TuplePat { LParen, args: [Pat], RParen }
struct Visibility {} struct Visibility { PubKw, SuperKw, SelfKw, CrateKw }
struct Name {} struct Name { Ident }
struct NameRef {} struct NameRef { NameRefToken }
struct MacroCall: NameOwner, AttrsOwner,DocCommentsOwner { 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 TokenTree {}
struct TypeParamList { struct TypeParamList {
LAngle,
generic_params: [GenericParam],
type_params: [TypeParam], type_params: [TypeParam],
lifetime_params: [LifetimeParam], lifetime_params: [LifetimeParam],
const_params: [ConstParam],
RAngle
} }
struct TypeParam: NameOwner, AttrsOwner, TypeBoundsOwner { struct TypeParam: NameOwner, AttrsOwner, TypeBoundsOwner {
Eq,
default_type: TypeRef, default_type: TypeRef,
} }
struct ConstParam: NameOwner, AttrsOwner, TypeAscriptionOwner { struct ConstParam: NameOwner, AttrsOwner, TypeAscriptionOwner {
Eq,
default_val: Expr, default_val: Expr,
} }
struct LifetimeParam: AttrsOwner { } struct LifetimeParam: AttrsOwner { Lifetime}
struct TypeBound { TypeRef} struct TypeBound { Lifetime, /* Question, */ ConstKw, /* Question, */ TypeRef}
struct TypeBoundList { bounds: [TypeBound] } struct TypeBoundList { bounds: [TypeBound] }
struct WherePred: TypeBoundsOwner { TypeRef } struct WherePred: TypeBoundsOwner { Lifetime, TypeRef }
struct WhereClause { predicates: [WherePred] } struct WhereClause { WhereKw, predicates: [WherePred] }
struct ExprStmt { Expr } struct Abi { String }
struct LetStmt: TypeAscriptionOwner { struct ExprStmt: AttrsOwner { Expr, Semi }
struct LetStmt: AttrsOwner, TypeAscriptionOwner {
LetKw,
Pat, Pat,
Eq,
initializer: Expr, initializer: Expr,
} }
struct Condition { Pat, Expr } struct Condition { LetKw, Pat, Eq, Expr }
struct Block: AttrsOwner, ModuleItemOwner { struct Block: AttrsOwner, ModuleItemOwner {
LCurly,
statements: [Stmt], statements: [Stmt],
Expr, Expr,
RCurly,
} }
struct ParamList { struct ParamList {
LParen,
SelfParam, SelfParam,
params: [Param], params: [Param],
RParen
} }
struct SelfParam: TypeAscriptionOwner, AttrsOwner { } struct SelfParam: TypeAscriptionOwner, AttrsOwner { Amp, Lifetime, SelfKw }
struct Param: TypeAscriptionOwner, AttrsOwner { struct Param: TypeAscriptionOwner, AttrsOwner {
Pat, Pat,
Dotdotdot
} }
struct UseItem: AttrsOwner, VisibilityOwner { struct UseItem: AttrsOwner, VisibilityOwner {
UseKw,
UseTree, UseTree,
} }
struct UseTree { struct UseTree {
Path, UseTreeList, Alias Path, Star, UseTreeList, Alias
} }
struct Alias: NameOwner { } struct Alias: NameOwner { AsKw }
struct UseTreeList { use_trees: [UseTree] } struct UseTreeList { LCurly, use_trees: [UseTree], RCurly }
struct ExternCrateItem: AttrsOwner, VisibilityOwner { struct ExternCrateItem: AttrsOwner, VisibilityOwner {
NameRef, Alias, ExternKw, CrateKw, NameRef, Alias,
} }
struct ArgList { struct ArgList {
LParen,
args: [Expr], args: [Expr],
RParen
} }
struct Path { struct Path {
segment: PathSegment, segment: PathSegment,
qualifier: Path, qualifier: Path,
} }
struct PathSegment { struct PathSegment {
NameRef, TypeArgList, ParamList, RetType, PathType, Coloncolon, LAngle, NameRef, TypeArgList, ParamList, RetType, PathType, RAngle
} }
struct TypeArgList { struct TypeArgList {
Coloncolon,
LAngle,
generic_args: [GenericArg],
type_args: [TypeArg], type_args: [TypeArg],
lifetime_args: [LifetimeArg], lifetime_args: [LifetimeArg],
assoc_type_args: [AssocTypeArg], assoc_type_args: [AssocTypeArg],
const_arg: [ConstArg], const_args: [ConstArg],
RAngle
} }
struct TypeArg { TypeRef } struct TypeArg { TypeRef }
struct AssocTypeArg { NameRef, TypeRef } struct AssocTypeArg : TypeBoundsOwner { NameRef, Eq, TypeRef }
struct LifetimeArg {} struct LifetimeArg { Lifetime }
struct ConstArg { Literal, BlockExpr } struct ConstArg { Literal, Eq, BlockExpr }
struct MacroItems: ModuleItemOwner, FnDefOwner { } struct MacroItems: ModuleItemOwner, FnDefOwner { }
@ -533,12 +609,44 @@ pub(crate) const AST_SRC: AstSrc = AstSrc {
statements: [Stmt], statements: [Stmt],
Expr, 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! { enums: &ast_enums! {
enum NominalDef: NameOwner, TypeParamsOwner, AttrsOwner { enum NominalDef: NameOwner, TypeParamsOwner, AttrsOwner {
StructDef, EnumDef, UnionDef, StructDef, EnumDef, UnionDef,
} }
enum GenericParam {
LifetimeParam,
TypeParam,
ConstParam
}
enum GenericArg {
LifetimeArg,
TypeArg,
ConstArg,
AssocTypeArg
}
enum TypeRef { enum TypeRef {
ParenType, ParenType,
TupleType, TupleType,
@ -555,7 +663,7 @@ pub(crate) const AST_SRC: AstSrc = AstSrc {
DynTraitType, DynTraitType,
} }
enum ModuleItem: AttrsOwner, VisibilityOwner { enum ModuleItem: NameOwner, AttrsOwner, VisibilityOwner {
StructDef, StructDef,
UnionDef, UnionDef,
EnumDef, EnumDef,
@ -569,13 +677,20 @@ pub(crate) const AST_SRC: AstSrc = AstSrc {
StaticDef, StaticDef,
Module, Module,
MacroCall, MacroCall,
ExternBlock
} }
enum ImplItem: AttrsOwner { /* impl blocks can also contain MacroCall */
FnDef, TypeAliasDef, ConstDef, 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, TupleExpr,
ArrayExpr, ArrayExpr,
ParenExpr, ParenExpr,
@ -627,7 +742,88 @@ pub(crate) const AST_SRC: AstSrc = AstSrc {
MacroPat, MacroPat,
} }
enum RecordInnerPat {
RecordFieldPat,
BindPat
}
enum AttrInput { Literal, TokenTree } enum AttrInput { Literal, TokenTree }
enum Stmt { ExprStmt, LetStmt } enum Stmt {
LetStmt,
ExprStmt,
// macro calls are parsed as expression statements */
}
enum FieldDefList {
RecordFieldDefList,
TupleFieldDefList,
}
},
token_enums: &ast_enums! {
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
}
}, },
}; };

View file

@ -22,8 +22,9 @@ const GRAMMAR_DIR: &str = "crates/ra_parser/src/grammar";
const OK_INLINE_TESTS_DIR: &str = "crates/ra_syntax/test_data/parser/inline/ok"; const OK_INLINE_TESTS_DIR: &str = "crates/ra_syntax/test_data/parser/inline/ok";
const ERR_INLINE_TESTS_DIR: &str = "crates/ra_syntax/test_data/parser/inline/err"; const ERR_INLINE_TESTS_DIR: &str = "crates/ra_syntax/test_data/parser/inline/err";
pub const SYNTAX_KINDS: &str = "crates/ra_parser/src/syntax_kind/generated.rs"; const SYNTAX_KINDS: &str = "crates/ra_parser/src/syntax_kind/generated.rs";
pub const AST: &str = "crates/ra_syntax/src/ast/generated.rs"; const AST_NODES: &str = "crates/ra_syntax/src/ast/generated/nodes.rs";
const AST_TOKENS: &str = "crates/ra_syntax/src/ast/generated/tokens.rs";
const ASSISTS_DIR: &str = "crates/ra_assists/src/handlers"; const ASSISTS_DIR: &str = "crates/ra_assists/src/handlers";
const ASSISTS_TESTS: &str = "crates/ra_assists/src/doc_tests/generated.rs"; const ASSISTS_TESTS: &str = "crates/ra_assists/src/doc_tests/generated.rs";

View file

@ -3,10 +3,13 @@
//! Specifically, it generates the `SyntaxKind` enum and a number of newtype //! Specifically, it generates the `SyntaxKind` enum and a number of newtype
//! wrappers around `SyntaxNode` which implement `ra_syntax::AstNode`. //! wrappers around `SyntaxNode` which implement `ra_syntax::AstNode`.
use std::{
borrow::Cow,
collections::{BTreeSet, HashSet},
};
use proc_macro2::{Punct, Spacing}; use proc_macro2::{Punct, Spacing};
use quote::{format_ident, quote}; use quote::{format_ident, quote};
use std::borrow::Cow;
use std::collections::{BTreeSet, HashMap, HashSet};
use crate::{ use crate::{
ast_src::{AstSrc, FieldSrc, KindsSrc, AST_SRC, KINDS_SRC}, ast_src::{AstSrc, FieldSrc, KindsSrc, AST_SRC, KINDS_SRC},
@ -19,9 +22,13 @@ pub fn generate_syntax(mode: Mode) -> Result<()> {
let syntax_kinds = generate_syntax_kinds(KINDS_SRC)?; let syntax_kinds = generate_syntax_kinds(KINDS_SRC)?;
update(syntax_kinds_file.as_path(), &syntax_kinds, mode)?; update(syntax_kinds_file.as_path(), &syntax_kinds, mode)?;
let ast_file = project_root().join(codegen::AST); let ast_nodes_file = project_root().join(codegen::AST_NODES);
let ast = generate_ast(KINDS_SRC, AST_SRC)?; let contents = generate_nodes(KINDS_SRC, AST_SRC)?;
update(ast_file.as_path(), &ast, mode)?; update(ast_nodes_file.as_path(), &contents, mode)?;
let ast_tokens_file = project_root().join(codegen::AST_TOKENS);
let contents = generate_tokens(KINDS_SRC, AST_SRC)?;
update(ast_tokens_file.as_path(), &contents, mode)?;
Ok(()) Ok(())
} }
@ -33,7 +40,7 @@ struct ElementKinds {
has_tokens: bool, has_tokens: bool,
} }
fn generate_ast(kinds: KindsSrc<'_>, grammar: AstSrc<'_>) -> Result<String> { fn generate_tokens(kinds: KindsSrc<'_>, grammar: AstSrc<'_>) -> Result<String> {
let all_token_kinds: Vec<_> = kinds let all_token_kinds: Vec<_> = kinds
.punct .punct
.into_iter() .into_iter()
@ -51,46 +58,6 @@ fn generate_ast(kinds: KindsSrc<'_>, grammar: AstSrc<'_>) -> Result<String> {
.chain(kinds.tokens.into_iter().copied().map(|x| x.into())) .chain(kinds.tokens.into_iter().copied().map(|x| x.into()))
.collect(); .collect();
let mut element_kinds_map = HashMap::new();
for kind in &all_token_kinds {
let kind = &**kind;
let name = to_pascal_case(kind);
element_kinds_map.insert(
name,
ElementKinds {
kinds: Some(format_ident!("{}", kind)).into_iter().collect(),
has_nodes: false,
has_tokens: true,
},
);
}
for kind in kinds.nodes {
let name = to_pascal_case(kind);
element_kinds_map.insert(
name,
ElementKinds {
kinds: Some(format_ident!("{}", *kind)).into_iter().collect(),
has_nodes: true,
has_tokens: false,
},
);
}
for en in grammar.enums {
let mut element_kinds: ElementKinds = Default::default();
for variant in en.variants {
if let Some(variant_element_kinds) = element_kinds_map.get(*variant) {
element_kinds.kinds.extend(variant_element_kinds.kinds.iter().cloned());
element_kinds.has_tokens |= variant_element_kinds.has_tokens;
element_kinds.has_nodes |= variant_element_kinds.has_nodes;
} else {
panic!("Enum variant has type that does not exist or was not declared before the enum: {}", *variant);
}
}
element_kinds_map.insert(en.name.to_string(), element_kinds);
}
let tokens = all_token_kinds.iter().map(|kind_str| { let tokens = all_token_kinds.iter().map(|kind_str| {
let kind_str = &**kind_str; let kind_str = &**kind_str;
let kind = format_ident!("{}", kind_str); let kind = format_ident!("{}", kind_str);
@ -108,12 +75,7 @@ fn generate_ast(kinds: KindsSrc<'_>, grammar: AstSrc<'_>) -> Result<String> {
} }
impl AstToken for #name { impl AstToken for #name {
fn can_cast(kind: SyntaxKind) -> bool { fn can_cast(kind: SyntaxKind) -> bool { kind == #kind }
match kind {
#kind => true,
_ => false,
}
}
fn cast(syntax: SyntaxToken) -> Option<Self> { fn cast(syntax: SyntaxToken) -> Option<Self> {
if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None } if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
} }
@ -122,6 +84,99 @@ fn generate_ast(kinds: KindsSrc<'_>, grammar: AstSrc<'_>) -> Result<String> {
} }
}); });
let enums = grammar.token_enums.iter().map(|en| {
let variants = en.variants.iter().map(|var| format_ident!("{}", var)).collect::<Vec<_>>();
let name = format_ident!("{}", en.name);
let kinds = variants
.iter()
.map(|name| format_ident!("{}", to_upper_snake_case(&name.to_string())))
.collect::<Vec<_>>();
assert!(en.traits.is_empty());
quote! {
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum #name {
#(#variants(#variants),)*
}
#(
impl From<#variants> for #name {
fn from(node: #variants) -> #name {
#name::#variants(node)
}
}
)*
impl std::fmt::Display for #name {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
std::fmt::Display::fmt(self.syntax(), f)
}
}
impl AstToken for #name {
fn can_cast(kind: SyntaxKind) -> bool {
match kind {
#(#kinds)|* => true,
_ => false,
}
}
fn cast(syntax: SyntaxToken) -> Option<Self> {
let res = match syntax.kind() {
#(
#kinds => #name::#variants(#variants { syntax }),
)*
_ => return None,
};
Some(res)
}
fn syntax(&self) -> &SyntaxToken {
match self {
#(
#name::#variants(it) => &it.syntax,
)*
}
}
}
}
});
crate::reformat(quote! {
use crate::{SyntaxToken, SyntaxKind::{self, *}, ast::AstToken};
#(#tokens)*
#(#enums)*
})
}
fn generate_nodes(kinds: KindsSrc<'_>, grammar: AstSrc<'_>) -> Result<String> {
let all_token_kinds: Vec<_> = kinds
.punct
.into_iter()
.map(|(_, kind)| kind)
.copied()
.map(|x| x.into())
.chain(
kinds
.keywords
.into_iter()
.chain(kinds.contextual_keywords.into_iter())
.map(|name| Cow::Owned(format!("{}_KW", to_upper_snake_case(&name)))),
)
.chain(kinds.literals.into_iter().copied().map(|x| x.into()))
.chain(kinds.tokens.into_iter().copied().map(|x| x.into()))
.collect();
let mut token_kinds = HashSet::new();
for kind in &all_token_kinds {
let kind = &**kind;
let name = to_pascal_case(kind);
token_kinds.insert(name);
}
for en in grammar.token_enums {
token_kinds.insert(en.name.to_string());
}
let nodes = grammar.nodes.iter().map(|node| { let nodes = grammar.nodes.iter().map(|node| {
let name = format_ident!("{}", node.name); let name = format_ident!("{}", node.name);
let kind = format_ident!("{}", to_upper_snake_case(&name.to_string())); let kind = format_ident!("{}", to_upper_snake_case(&name.to_string()));
@ -146,14 +201,23 @@ fn generate_ast(kinds: KindsSrc<'_>, grammar: AstSrc<'_>) -> Result<String> {
FieldSrc::Many(_) => { FieldSrc::Many(_) => {
quote! { quote! {
pub fn #method_name(&self) -> AstChildren<#ty> { pub fn #method_name(&self) -> AstChildren<#ty> {
AstChildren::new(&self.syntax) support::children(&self.syntax)
} }
} }
} }
FieldSrc::Optional(_) | FieldSrc::Shorthand => { FieldSrc::Optional(_) | FieldSrc::Shorthand => {
let is_token = token_kinds.contains(&ty.to_string());
if is_token {
quote! { quote! {
pub fn #method_name(&self) -> Option<#ty> { pub fn #method_name(&self) -> Option<#ty> {
AstChildren::new(&self.syntax).next() support::token(&self.syntax)
}
}
} else {
quote! {
pub fn #method_name(&self) -> Option<#ty> {
support::child(&self.syntax)
}
} }
} }
} }
@ -166,18 +230,9 @@ fn generate_ast(kinds: KindsSrc<'_>, grammar: AstSrc<'_>) -> Result<String> {
pub(crate) syntax: SyntaxNode, pub(crate) syntax: SyntaxNode,
} }
impl std::fmt::Display for #name {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
std::fmt::Display::fmt(self.syntax(), f)
}
}
impl AstNode for #name { impl AstNode for #name {
fn can_cast(kind: SyntaxKind) -> bool { fn can_cast(kind: SyntaxKind) -> bool {
match kind { kind == #kind
#kind => true,
_ => false,
}
} }
fn cast(syntax: SyntaxNode) -> Option<Self> { fn cast(syntax: SyntaxNode) -> Option<Self> {
if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None } if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
@ -219,12 +274,6 @@ fn generate_ast(kinds: KindsSrc<'_>, grammar: AstSrc<'_>) -> Result<String> {
} }
)* )*
impl std::fmt::Display for #name {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
std::fmt::Display::fmt(self.syntax(), f)
}
}
impl AstNode for #name { impl AstNode for #name {
fn can_cast(kind: SyntaxKind) -> bool { fn can_cast(kind: SyntaxKind) -> bool {
match kind { match kind {
@ -249,10 +298,26 @@ fn generate_ast(kinds: KindsSrc<'_>, grammar: AstSrc<'_>) -> Result<String> {
} }
} }
} }
#(#traits)* #(#traits)*
} }
}); });
let displays = grammar
.enums
.iter()
.map(|it| format_ident!("{}", it.name))
.chain(grammar.nodes.iter().map(|it| format_ident!("{}", it.name)))
.map(|name| {
quote! {
impl std::fmt::Display for #name {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
std::fmt::Display::fmt(self.syntax(), f)
}
}
}
});
let defined_nodes: HashSet<_> = grammar.nodes.iter().map(|node| node.name).collect(); let defined_nodes: HashSet<_> = grammar.nodes.iter().map(|node| node.name).collect();
for node in kinds for node in kinds
@ -265,15 +330,16 @@ fn generate_ast(kinds: KindsSrc<'_>, grammar: AstSrc<'_>) -> Result<String> {
} }
let ast = quote! { let ast = quote! {
#[allow(unused_imports)]
use crate::{ use crate::{
SyntaxNode, SyntaxToken, SyntaxElement, NodeOrToken, SyntaxKind::{self, *}, SyntaxNode, SyntaxKind::{self, *},
ast::{self, AstNode, AstToken, AstChildren}, ast::{self, AstNode, AstChildren, support},
}; };
#(#tokens)* use super::tokens::*;
#(#nodes)* #(#nodes)*
#(#enums)* #(#enums)*
#(#displays)*
}; };
let pretty = crate::reformat(ast)?; let pretty = crate::reformat(ast)?;

View file

@ -67,6 +67,7 @@ fn reformat(text: impl std::fmt::Display) -> Result<String> {
let mut rustfmt = Command::new("rustup") let mut rustfmt = Command::new("rustup")
.args(&["run", TOOLCHAIN, "--", "rustfmt", "--config-path"]) .args(&["run", TOOLCHAIN, "--", "rustfmt", "--config-path"])
.arg(project_root().join("rustfmt.toml")) .arg(project_root().join("rustfmt.toml"))
.args(&["--config", "fn_single_line=true"])
.stdin(Stdio::piped()) .stdin(Stdio::piped())
.stdout(Stdio::piped()) .stdout(Stdio::piped())
.spawn()?; .spawn()?;