diff options
| author | Chayim Refael Friedman <chayimfr@gmail.com> | 2024-12-30 05:46:06 +0200 |
|---|---|---|
| committer | Chayim Refael Friedman <chayimfr@gmail.com> | 2024-12-30 05:46:06 +0200 |
| commit | 33f1f1d787f9f3a41a1983219d27d24f741c9fb1 (patch) | |
| tree | 41035b23c18216ac399d405fdc45cfaa2c91bfc1 | |
| parent | a0c052fa57083031234f35462fbee5026413fd8d (diff) | |
| download | rust-33f1f1d787f9f3a41a1983219d27d24f741c9fb1.tar.gz rust-33f1f1d787f9f3a41a1983219d27d24f741c9fb1.zip | |
Move some more AST makers to the quote macro
And implement addons as necessary. There are many more makers to be moved, and I'm not completely satisfied with this (due to the ease of making a mistake in the AST structure, and slightly less but also because of the need to remember whitespaces), but this is already enough to see how this will look like.
4 files changed, 58 insertions, 53 deletions
diff --git a/src/tools/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/Cargo.toml index 7f3abcccc47..e303b3c1109 100644 --- a/src/tools/rust-analyzer/Cargo.toml +++ b/src/tools/rust-analyzer/Cargo.toml @@ -203,6 +203,8 @@ new_ret_no_self = "allow" useless_asref = "allow" # Has false positives assigning_clones = "allow" +# Does not work with macros +vec_init_then_push = "allow" ## Following lints should be tackled at some point too_many_arguments = "allow" diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_fn_type_alias.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_fn_type_alias.rs index f4b4c22d98d..9d01ec00f83 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_fn_type_alias.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_fn_type_alias.rs @@ -85,7 +85,6 @@ pub(crate) fn generate_fn_type_alias(acc: &mut Assists, ctx: &AssistContext<'_>) let is_unsafe = func_node.unsafe_token().is_some(); let ty = make::ty_fn_ptr( - None, is_unsafe, func_node.abi(), fn_params_vec.into_iter(), diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs index 059028bea82..76b39c3b73f 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs @@ -8,7 +8,8 @@ //! Keep in mind that `from_text` functions should be kept private. The public //! API should require to assemble every node piecewise. The trick of //! `parse(format!())` we use internally is an implementation detail -- long -//! term, it will be replaced with direct tree manipulation. +//! term, it will be replaced with `quote!`. Do not add more usages to `from_text` - +//! use `quote!` instead. mod quote; @@ -120,7 +121,11 @@ pub fn name(name: &str) -> ast::Name { } pub fn name_ref(name_ref: &str) -> ast::NameRef { let raw_escape = raw_ident_esc(name_ref); - ast_from_text(&format!("fn f() {{ {raw_escape}{name_ref}; }}")) + quote! { + NameRef { + [IDENT format!("{raw_escape}{name_ref}")] + } + } } fn raw_ident_esc(ident: &str) -> &'static str { if is_raw_identifier(ident, Edition::CURRENT) { @@ -137,7 +142,11 @@ pub fn lifetime(text: &str) -> ast::Lifetime { tmp = format!("'{text}"); text = &tmp; } - ast_from_text(&format!("fn f<{text}>() {{ }}")) + quote! { + Lifetime { + [LIFETIME_IDENT text] + } + } } // FIXME: replace stringly-typed constructor with a family of typed ctors, a-la @@ -177,63 +186,37 @@ pub fn ty_alias( where_clause: Option<ast::WhereClause>, assignment: Option<(ast::Type, Option<ast::WhereClause>)>, ) -> ast::TypeAlias { - let mut s = String::new(); - s.push_str(&format!("type {ident}")); - - if let Some(list) = generic_param_list { - s.push_str(&list.to_string()); - } - - if let Some(list) = type_param_bounds { - s.push_str(&format!(" : {list}")); - } - - if let Some(cl) = where_clause { - s.push_str(&format!(" {cl}")); - } - - if let Some(exp) = assignment { - if let Some(cl) = exp.1 { - s.push_str(&format!(" = {} {cl}", exp.0)); - } else { - s.push_str(&format!(" = {}", exp.0)); + let (assignment_ty, assignment_where) = assignment.unzip(); + let assignment_where = assignment_where.flatten(); + quote! { + TypeAlias { + [type] " " + Name { [IDENT ident] } + #generic_param_list + #(" " [:] " " #type_param_bounds)* + #(" " #where_clause)* + #(" " [=] " " #assignment_ty)* + #(" " #assignment_where)* + [;] } } - - s.push(';'); - ast_from_text(&s) } pub fn ty_fn_ptr<I: Iterator<Item = Param>>( - for_lifetime_list: Option<ast::GenericParamList>, is_unsafe: bool, abi: Option<ast::Abi>, - params: I, + mut params: I, ret_type: Option<ast::RetType>, ) -> ast::FnPtrType { - let mut s = String::from("type __ = "); - - if let Some(list) = for_lifetime_list { - format_to!(s, "for{} ", list); - } - - if is_unsafe { - s.push_str("unsafe "); - } - - if let Some(abi) = abi { - format_to!(s, "{} ", abi) - } - - s.push_str("fn"); - - format_to!(s, "({})", params.map(|p| p.to_string()).join(", ")); - - if let Some(ret_type) = ret_type { - format_to!(s, " {}", ret_type); + let is_unsafe = is_unsafe.then_some(()); + let first_param = params.next(); + quote! { + FnPtrType { + #(#is_unsafe [unsafe] " ")* #(#abi " ")* [fn] + ['('] #first_param #([,] " " #params)* [')'] + #(" " #ret_type)* + } } - - ast_from_text(&s) } pub fn assoc_item_list() -> ast::AssocItemList { diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/make/quote.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/make/quote.rs index 1c66a413f87..300ef25c137 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/make/quote.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/make/quote.rs @@ -28,6 +28,19 @@ macro_rules! quote_impl_ { }; ( @append $children:ident + [ $token_kind:ident $token_text:expr ] + $($rest:tt)* + ) => { + $children.push($crate::ast::make::quote::NodeOrToken::Token( + $crate::ast::make::quote::GreenToken::new( + $crate::ast::make::quote::RSyntaxKind($crate::SyntaxKind::$token_kind as u16), + &$token_text, + ), + )); + $crate::ast::make::quote::quote_impl!( @append $children $($rest)* ); + }; + + ( @append $children:ident [$($token:tt)+] $($rest:tt)* ) => { @@ -115,7 +128,9 @@ pub(crate) use quote_impl_ as quote_impl; /// A `quote!`-like API for crafting AST nodes. /// /// Syntax: AST nodes are created with `Node { children }`, where `Node` is the node name in `ast` (`ast::Node`). -/// Tokens are creates with their syntax enclosed by brackets, e.g. `[::]` or `['{']`. Whitespaces can be added +/// Tokens are creates with their syntax enclosed by brackets, e.g. `[::]` or `['{']`. Alternatively, tokens can +/// be created with the syntax `[token_kind token_text]`, where `token_kind` is a variant of `SyntaxKind` (e.g. +/// `IDENT`) and `token_text` is an expression producing `String` or `&str`. Whitespaces can be added /// as string literals (i.e. `"\n "` is a whitespace token). Interpolation is allowed with `#` (`#variable`), /// from `AstNode`s and `Option`s of them. Repetition is also supported, with only one repeating variable /// and no separator (`#("\n" #variable [>])*`), for any `IntoIterator`. Note that `Option`s are also `IntoIterator`, @@ -126,6 +141,7 @@ pub(crate) use quote_impl_ as quote_impl; /// Be careful to closely match the Ungrammar AST, there is no validation for this! macro_rules! quote_ { ( $root:ident { $($tree:tt)* } ) => {{ + #[allow(unused_mut)] let mut root = ::std::vec::Vec::<$crate::ast::make::quote::NodeOrToken< $crate::ast::make::quote::GreenNode, $crate::ast::make::quote::GreenToken, @@ -146,7 +162,7 @@ pub(crate) trait ToNodeChild { impl<N: AstNode> ToNodeChild for N { fn append_node_child(self, children: &mut Vec<NodeOrToken<GreenNode, GreenToken>>) { - children.push(self.syntax().clone_subtree().green().to_owned().into()); + children.push((*self.syntax().clone_subtree().green()).to_owned().into()); } } @@ -158,6 +174,11 @@ impl<C: ToNodeChild> ToNodeChild for Option<C> { } } +// This is useful when you want conditionally, based on some `bool`, to emit some code. +impl ToNodeChild for () { + fn append_node_child(self, _children: &mut Vec<NodeOrToken<GreenNode, GreenToken>>) {} +} + pub(crate) const fn verify_only_whitespaces(text: &str) { let text = text.as_bytes(); let mut i = 0; |
