1+ use std:: borrow:: Cow ;
12use std:: mem;
23
34use rustc_ast:: token:: {
45 self , Delimiter , IdentIsRaw , InvisibleOrigin , Lit , LitKind , MetaVarKind , Token , TokenKind ,
56} ;
67use rustc_ast:: tokenstream:: { DelimSpacing , DelimSpan , Spacing , TokenStream , TokenTree } ;
7- use rustc_ast:: { ExprKind , StmtKind , TyKind , UnOp } ;
8+ use rustc_ast:: { self as ast , ExprKind , ItemKind , StmtKind , TyKind , UnOp } ;
89use rustc_data_structures:: fx:: FxHashMap ;
910use rustc_errors:: { Diag , DiagCtxtHandle , PResult , pluralize} ;
1011use rustc_parse:: lexer:: nfc_normalize;
@@ -18,12 +19,12 @@ use smallvec::{SmallVec, smallvec};
1819
1920use crate :: errors:: {
2021 CountRepetitionMisplaced , MacroVarStillRepeating , MetaVarsDifSeqMatchers , MustRepeatOnce ,
21- MveUnrecognizedVar , NoSyntaxVarsExprRepeat ,
22+ MveExprHasNoField , MveUnrecognizedVar , NoSyntaxVarsExprRepeat ,
2223} ;
2324use crate :: mbe:: macro_parser:: NamedMatch ;
2425use crate :: mbe:: macro_parser:: NamedMatch :: * ;
2526use crate :: mbe:: metavar_expr:: { MetaVarExprConcatElem , RAW_IDENT_ERR } ;
26- use crate :: mbe:: { self , KleeneOp , MetaVarExpr } ;
27+ use crate :: mbe:: { self , KleeneOp , MetaVarExpr , MetaVarRecursiveExpr } ;
2728
2829/// Context needed to perform transcription of metavariable expressions.
2930struct TranscrCtx < ' psess , ' itp > {
@@ -540,11 +541,105 @@ fn transcribe_metavar_expr<'tx>(
540541 return Err ( out_of_bounds_err ( dcx, tscx. repeats . len ( ) , dspan. entire ( ) , "len" ) ) ;
541542 }
542543 } ,
544+ MetaVarExpr :: Recursive ( ref expr) => {
545+ let pnr = eval_metavar_recursive_expr ( tscx, expr) ?;
546+ return transcribe_pnr ( tscx, dspan. entire ( ) , & pnr) ;
547+ }
543548 } ;
544549 tscx. result . push ( tt) ;
545550 Ok ( ( ) )
546551}
547552
553+ /// Evaluate recursive metavariable expressions into a `ParseNtResult`.
554+ ///
555+ /// This does not do any transcription; that's handled in the caller.
556+ ///
557+ /// It's okay to recurse here for now, because we expect a limited degree of nested fields. More
558+ /// complex expressions may require translating this into a proper interpreter.
559+ fn eval_metavar_recursive_expr < ' psess , ' interp > (
560+ tscx : & TranscrCtx < ' psess , ' interp > ,
561+ expr : & MetaVarRecursiveExpr ,
562+ ) -> PResult < ' psess , Cow < ' interp , ParseNtResult > > {
563+ let dcx = tscx. psess . dcx ( ) ;
564+ match expr {
565+ MetaVarRecursiveExpr :: Ident ( ident) => {
566+ let span = ident. span ;
567+ let ident = MacroRulesNormalizedIdent :: new ( * ident) ;
568+ match matched_from_mrn_ident ( dcx, span, ident, tscx. interp ) ? {
569+ NamedMatch :: MatchedSingle ( pnr) => Ok ( Cow :: Borrowed ( pnr) ) ,
570+ NamedMatch :: MatchedSeq ( named_matches) => {
571+ let Some ( ( curr_idx, _) ) = tscx. repeats . last ( ) else {
572+ return Err ( dcx. struct_span_err ( span, "invalid syntax" ) ) ;
573+ } ;
574+ match & named_matches[ * curr_idx] {
575+ MatchedSeq ( _) => {
576+ Err ( dcx. create_err ( MacroVarStillRepeating { span, ident } ) )
577+ }
578+ MatchedSingle ( pnr) => Ok ( Cow :: Borrowed ( pnr) ) ,
579+ }
580+ }
581+ }
582+ }
583+ MetaVarRecursiveExpr :: Field { expr : base_expr, field } => {
584+ let base_pnr = eval_metavar_recursive_expr ( tscx, base_expr) ?;
585+ let err_unknown_field = || {
586+ Err ( dcx. create_err ( MveExprHasNoField {
587+ span : field. span ,
588+ pnr_type : pnr_type ( & base_pnr) ,
589+ field : * field,
590+ } ) )
591+ } ;
592+ match ( base_pnr. as_ref ( ) , field. name ) {
593+ ( ParseNtResult :: Adt ( adt_item) , sym:: name) => {
594+ let ident = match adt_item. kind {
595+ ItemKind :: Struct ( ident, ..)
596+ | ItemKind :: Enum ( ident, ..)
597+ | ItemKind :: Union ( ident, ..) => ident,
598+ _ => dcx. span_bug ( field. span , "`adt` item was not an adt" ) ,
599+ } ;
600+ Ok ( ident_pnr ( ident) )
601+ }
602+ ( ParseNtResult :: Fn ( fn_item) , sym:: name) => {
603+ let f = require_fn_item ( fn_item) ;
604+ Ok ( ident_pnr ( f. ident ) )
605+ }
606+ ( _, _) => err_unknown_field ( ) ,
607+ }
608+ }
609+ }
610+ }
611+
612+ fn ident_pnr ( ident : Ident ) -> Cow < ' static , ParseNtResult > {
613+ Cow :: Owned ( ParseNtResult :: Ident ( ident, ident. is_raw_guess ( ) . into ( ) ) )
614+ }
615+
616+ fn pnr_type ( pnr : & ParseNtResult ) -> & ' static str {
617+ match pnr {
618+ ParseNtResult :: Tt ( ..) => "tt" ,
619+ ParseNtResult :: Ident ( ..) => "ident" ,
620+ ParseNtResult :: Lifetime ( ..) => "lifetime" ,
621+ ParseNtResult :: Item ( ..) => "item" ,
622+ ParseNtResult :: Fn ( ..) => "fn" ,
623+ ParseNtResult :: Adt ( ..) => "adt" ,
624+ ParseNtResult :: Block ( ..) => "block" ,
625+ ParseNtResult :: Stmt ( ..) => "stmt" ,
626+ ParseNtResult :: Pat ( ..) => "pat" ,
627+ ParseNtResult :: Expr ( ..) => "expr" ,
628+ ParseNtResult :: Literal ( ..) => "literal" ,
629+ ParseNtResult :: Ty ( ..) => "ty" ,
630+ ParseNtResult :: Meta ( ..) => "meta" ,
631+ ParseNtResult :: Path ( ..) => "path" ,
632+ ParseNtResult :: Vis ( ..) => "vis" ,
633+ }
634+ }
635+
636+ fn require_fn_item ( item : & ast:: Item ) -> & ast:: Fn {
637+ match item. kind {
638+ ItemKind :: Fn ( ref f) => & f,
639+ _ => panic ! ( "`fn` item was not a fn" ) ,
640+ }
641+ }
642+
548643/// Handle the `${concat(...)}` metavariable expression.
549644fn metavar_expr_concat < ' tx > (
550645 tscx : & mut TranscrCtx < ' tx , ' _ > ,
@@ -891,8 +986,19 @@ fn matched_from_ident<'ctx, 'interp, 'rslt>(
891986where
892987 ' interp : ' rslt ,
893988{
894- let span = ident. span ;
895- let key = MacroRulesNormalizedIdent :: new ( ident) ;
989+ matched_from_mrn_ident ( dcx, ident. span , MacroRulesNormalizedIdent :: new ( ident) , interp)
990+ }
991+
992+ /// Returns a `NamedMatch` item declared on the LHS given an arbitrary [MacroRulesNormalizedIdent]
993+ fn matched_from_mrn_ident < ' ctx , ' interp , ' rslt > (
994+ dcx : DiagCtxtHandle < ' ctx > ,
995+ span : Span ,
996+ key : MacroRulesNormalizedIdent ,
997+ interp : & ' interp FxHashMap < MacroRulesNormalizedIdent , NamedMatch > ,
998+ ) -> PResult < ' ctx , & ' rslt NamedMatch >
999+ where
1000+ ' interp : ' rslt ,
1001+ {
8961002 interp. get ( & key) . ok_or_else ( || dcx. create_err ( MveUnrecognizedVar { span, key } ) )
8971003}
8981004
0 commit comments