mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-10-25 17:28:17 +00:00
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.
This commit is contained in:
parent
abd7263179
commit
791a63255b
4 changed files with 58 additions and 53 deletions
|
|
@ -203,6 +203,8 @@ new_ret_no_self = "allow"
|
||||||
useless_asref = "allow"
|
useless_asref = "allow"
|
||||||
# Has false positives
|
# Has false positives
|
||||||
assigning_clones = "allow"
|
assigning_clones = "allow"
|
||||||
|
# Does not work with macros
|
||||||
|
vec_init_then_push = "allow"
|
||||||
|
|
||||||
## Following lints should be tackled at some point
|
## Following lints should be tackled at some point
|
||||||
too_many_arguments = "allow"
|
too_many_arguments = "allow"
|
||||||
|
|
|
||||||
|
|
@ -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 is_unsafe = func_node.unsafe_token().is_some();
|
||||||
let ty = make::ty_fn_ptr(
|
let ty = make::ty_fn_ptr(
|
||||||
None,
|
|
||||||
is_unsafe,
|
is_unsafe,
|
||||||
func_node.abi(),
|
func_node.abi(),
|
||||||
fn_params_vec.into_iter(),
|
fn_params_vec.into_iter(),
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,8 @@
|
||||||
//! Keep in mind that `from_text` functions should be kept private. The public
|
//! Keep in mind that `from_text` functions should be kept private. The public
|
||||||
//! API should require to assemble every node piecewise. The trick of
|
//! API should require to assemble every node piecewise. The trick of
|
||||||
//! `parse(format!())` we use internally is an implementation detail -- long
|
//! `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;
|
mod quote;
|
||||||
|
|
||||||
|
|
@ -120,7 +121,11 @@ pub fn name(name: &str) -> ast::Name {
|
||||||
}
|
}
|
||||||
pub fn name_ref(name_ref: &str) -> ast::NameRef {
|
pub fn name_ref(name_ref: &str) -> ast::NameRef {
|
||||||
let raw_escape = raw_ident_esc(name_ref);
|
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 {
|
fn raw_ident_esc(ident: &str) -> &'static str {
|
||||||
if is_raw_identifier(ident, Edition::CURRENT) {
|
if is_raw_identifier(ident, Edition::CURRENT) {
|
||||||
|
|
@ -137,7 +142,11 @@ pub fn lifetime(text: &str) -> ast::Lifetime {
|
||||||
tmp = format!("'{text}");
|
tmp = format!("'{text}");
|
||||||
text = &tmp;
|
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
|
// 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>,
|
where_clause: Option<ast::WhereClause>,
|
||||||
assignment: Option<(ast::Type, Option<ast::WhereClause>)>,
|
assignment: Option<(ast::Type, Option<ast::WhereClause>)>,
|
||||||
) -> ast::TypeAlias {
|
) -> ast::TypeAlias {
|
||||||
let mut s = String::new();
|
let (assignment_ty, assignment_where) = assignment.unzip();
|
||||||
s.push_str(&format!("type {ident}"));
|
let assignment_where = assignment_where.flatten();
|
||||||
|
quote! {
|
||||||
if let Some(list) = generic_param_list {
|
TypeAlias {
|
||||||
s.push_str(&list.to_string());
|
[type] " "
|
||||||
}
|
Name { [IDENT ident] }
|
||||||
|
#generic_param_list
|
||||||
if let Some(list) = type_param_bounds {
|
#(" " [:] " " #type_param_bounds)*
|
||||||
s.push_str(&format!(" : {list}"));
|
#(" " #where_clause)*
|
||||||
}
|
#(" " [=] " " #assignment_ty)*
|
||||||
|
#(" " #assignment_where)*
|
||||||
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));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
s.push(';');
|
|
||||||
ast_from_text(&s)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ty_fn_ptr<I: Iterator<Item = Param>>(
|
pub fn ty_fn_ptr<I: Iterator<Item = Param>>(
|
||||||
for_lifetime_list: Option<ast::GenericParamList>,
|
|
||||||
is_unsafe: bool,
|
is_unsafe: bool,
|
||||||
abi: Option<ast::Abi>,
|
abi: Option<ast::Abi>,
|
||||||
params: I,
|
mut params: I,
|
||||||
ret_type: Option<ast::RetType>,
|
ret_type: Option<ast::RetType>,
|
||||||
) -> ast::FnPtrType {
|
) -> ast::FnPtrType {
|
||||||
let mut s = String::from("type __ = ");
|
let is_unsafe = is_unsafe.then_some(());
|
||||||
|
let first_param = params.next();
|
||||||
if let Some(list) = for_lifetime_list {
|
quote! {
|
||||||
format_to!(s, "for{} ", list);
|
FnPtrType {
|
||||||
|
#(#is_unsafe [unsafe] " ")* #(#abi " ")* [fn]
|
||||||
|
['('] #first_param #([,] " " #params)* [')']
|
||||||
|
#(" " #ret_type)*
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
ast_from_text(&s)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn assoc_item_list() -> ast::AssocItemList {
|
pub fn assoc_item_list() -> ast::AssocItemList {
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,19 @@ macro_rules! quote_impl_ {
|
||||||
$crate::ast::make::quote::quote_impl!( @append $children $($rest)* );
|
$crate::ast::make::quote::quote_impl!( @append $children $($rest)* );
|
||||||
};
|
};
|
||||||
|
|
||||||
|
( @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
|
( @append $children:ident
|
||||||
[$($token:tt)+]
|
[$($token:tt)+]
|
||||||
$($rest:tt)*
|
$($rest:tt)*
|
||||||
|
|
@ -115,7 +128,9 @@ pub(crate) use quote_impl_ as quote_impl;
|
||||||
/// A `quote!`-like API for crafting AST nodes.
|
/// 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`).
|
/// 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`),
|
/// 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
|
/// 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`,
|
/// 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!
|
/// Be careful to closely match the Ungrammar AST, there is no validation for this!
|
||||||
macro_rules! quote_ {
|
macro_rules! quote_ {
|
||||||
( $root:ident { $($tree:tt)* } ) => {{
|
( $root:ident { $($tree:tt)* } ) => {{
|
||||||
|
#[allow(unused_mut)]
|
||||||
let mut root = ::std::vec::Vec::<$crate::ast::make::quote::NodeOrToken<
|
let mut root = ::std::vec::Vec::<$crate::ast::make::quote::NodeOrToken<
|
||||||
$crate::ast::make::quote::GreenNode,
|
$crate::ast::make::quote::GreenNode,
|
||||||
$crate::ast::make::quote::GreenToken,
|
$crate::ast::make::quote::GreenToken,
|
||||||
|
|
@ -146,7 +162,7 @@ pub(crate) trait ToNodeChild {
|
||||||
|
|
||||||
impl<N: AstNode> ToNodeChild for N {
|
impl<N: AstNode> ToNodeChild for N {
|
||||||
fn append_node_child(self, children: &mut Vec<NodeOrToken<GreenNode, GreenToken>>) {
|
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) {
|
pub(crate) const fn verify_only_whitespaces(text: &str) {
|
||||||
let text = text.as_bytes();
|
let text = text.as_bytes();
|
||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue