Auto merge of #117050 - c410-f3r:here-we-go-again, r=petrochenkov
[`RFC 3086`] Attempt to try to resolve blocking concerns Implements what is described at https://github.com/rust-lang/rust/issues/83527#issuecomment-1744822345 to hopefully make some progress. It is unknown if such approach is or isn't desired due to the lack of further feedback, as such, it is probably best to nominate this PR to the official entities. `@rustbot` labels +I-compiler-nominated
This commit is contained in:
commit
f651b436ce
16 changed files with 715 additions and 281 deletions
|
@ -41,6 +41,7 @@ use std::path::PathBuf;
|
|||
use std::rc::Rc;
|
||||
use std::{iter, mem};
|
||||
|
||||
#[cfg(bootstrap)]
|
||||
macro_rules! ast_fragments {
|
||||
(
|
||||
$($Kind:ident($AstTy:ty) {
|
||||
|
@ -165,6 +166,131 @@ macro_rules! ast_fragments {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(not(bootstrap))]
|
||||
macro_rules! ast_fragments {
|
||||
(
|
||||
$($Kind:ident($AstTy:ty) {
|
||||
$kind_name:expr;
|
||||
$(one fn $mut_visit_ast:ident; fn $visit_ast:ident;)?
|
||||
$(many fn $flat_map_ast_elt:ident; fn $visit_ast_elt:ident($($args:tt)*);)?
|
||||
fn $make_ast:ident;
|
||||
})*
|
||||
) => {
|
||||
/// A fragment of AST that can be produced by a single macro expansion.
|
||||
/// Can also serve as an input and intermediate result for macro expansion operations.
|
||||
pub enum AstFragment {
|
||||
OptExpr(Option<P<ast::Expr>>),
|
||||
MethodReceiverExpr(P<ast::Expr>),
|
||||
$($Kind($AstTy),)*
|
||||
}
|
||||
|
||||
/// "Discriminant" of an AST fragment.
|
||||
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||
pub enum AstFragmentKind {
|
||||
OptExpr,
|
||||
MethodReceiverExpr,
|
||||
$($Kind,)*
|
||||
}
|
||||
|
||||
impl AstFragmentKind {
|
||||
pub fn name(self) -> &'static str {
|
||||
match self {
|
||||
AstFragmentKind::OptExpr => "expression",
|
||||
AstFragmentKind::MethodReceiverExpr => "expression",
|
||||
$(AstFragmentKind::$Kind => $kind_name,)*
|
||||
}
|
||||
}
|
||||
|
||||
fn make_from<'a>(self, result: Box<dyn MacResult + 'a>) -> Option<AstFragment> {
|
||||
match self {
|
||||
AstFragmentKind::OptExpr =>
|
||||
result.make_expr().map(Some).map(AstFragment::OptExpr),
|
||||
AstFragmentKind::MethodReceiverExpr =>
|
||||
result.make_expr().map(AstFragment::MethodReceiverExpr),
|
||||
$(AstFragmentKind::$Kind => result.$make_ast().map(AstFragment::$Kind),)*
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AstFragment {
|
||||
pub fn add_placeholders(&mut self, placeholders: &[NodeId]) {
|
||||
if placeholders.is_empty() {
|
||||
return;
|
||||
}
|
||||
match self {
|
||||
$($(AstFragment::$Kind(ast) => ast.extend(placeholders.iter().flat_map(|id| {
|
||||
${ignore($flat_map_ast_elt)}
|
||||
placeholder(AstFragmentKind::$Kind, *id, None).$make_ast()
|
||||
})),)?)*
|
||||
_ => panic!("unexpected AST fragment kind")
|
||||
}
|
||||
}
|
||||
|
||||
pub fn make_opt_expr(self) -> Option<P<ast::Expr>> {
|
||||
match self {
|
||||
AstFragment::OptExpr(expr) => expr,
|
||||
_ => panic!("AstFragment::make_* called on the wrong kind of fragment"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn make_method_receiver_expr(self) -> P<ast::Expr> {
|
||||
match self {
|
||||
AstFragment::MethodReceiverExpr(expr) => expr,
|
||||
_ => panic!("AstFragment::make_* called on the wrong kind of fragment"),
|
||||
}
|
||||
}
|
||||
|
||||
$(pub fn $make_ast(self) -> $AstTy {
|
||||
match self {
|
||||
AstFragment::$Kind(ast) => ast,
|
||||
_ => panic!("AstFragment::make_* called on the wrong kind of fragment"),
|
||||
}
|
||||
})*
|
||||
|
||||
fn make_ast<T: InvocationCollectorNode>(self) -> T::OutputTy {
|
||||
T::fragment_to_output(self)
|
||||
}
|
||||
|
||||
pub fn mut_visit_with<F: MutVisitor>(&mut self, vis: &mut F) {
|
||||
match self {
|
||||
AstFragment::OptExpr(opt_expr) => {
|
||||
visit_clobber(opt_expr, |opt_expr| {
|
||||
if let Some(expr) = opt_expr {
|
||||
vis.filter_map_expr(expr)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
});
|
||||
}
|
||||
AstFragment::MethodReceiverExpr(expr) => vis.visit_method_receiver_expr(expr),
|
||||
$($(AstFragment::$Kind(ast) => vis.$mut_visit_ast(ast),)?)*
|
||||
$($(AstFragment::$Kind(ast) =>
|
||||
ast.flat_map_in_place(|ast| vis.$flat_map_ast_elt(ast)),)?)*
|
||||
}
|
||||
}
|
||||
|
||||
pub fn visit_with<'a, V: Visitor<'a>>(&'a self, visitor: &mut V) {
|
||||
match self {
|
||||
AstFragment::OptExpr(Some(expr)) => visitor.visit_expr(expr),
|
||||
AstFragment::OptExpr(None) => {}
|
||||
AstFragment::MethodReceiverExpr(expr) => visitor.visit_method_receiver_expr(expr),
|
||||
$($(AstFragment::$Kind(ast) => visitor.$visit_ast(ast),)?)*
|
||||
$($(AstFragment::$Kind(ast) => for ast_elt in &ast[..] {
|
||||
visitor.$visit_ast_elt(ast_elt, $($args)*);
|
||||
})?)*
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> MacResult for crate::mbe::macro_rules::ParserAnyMacro<'a> {
|
||||
$(fn $make_ast(self: Box<crate::mbe::macro_rules::ParserAnyMacro<'a>>)
|
||||
-> Option<$AstTy> {
|
||||
Some(self.make(AstFragmentKind::$Kind).$make_ast())
|
||||
})*
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ast_fragments! {
|
||||
Expr(P<ast::Expr>) { "expression"; one fn visit_expr; fn visit_expr; fn make_expr; }
|
||||
Pat(P<ast::Pat>) { "pattern"; one fn visit_pat; fn visit_pat; fn make_pat; }
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue