1
+ use std:: borrow:: Cow ;
1
2
use std:: mem;
2
3
3
4
use rustc_ast:: token:: {
4
5
self , Delimiter , IdentIsRaw , InvisibleOrigin , Lit , LitKind , MetaVarKind , Token , TokenKind ,
5
6
} ;
6
7
use 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 } ;
8
9
use rustc_data_structures:: fx:: FxHashMap ;
9
10
use rustc_errors:: { Diag , DiagCtxtHandle , PResult , pluralize} ;
10
11
use rustc_parse:: lexer:: nfc_normalize;
@@ -18,12 +19,12 @@ use smallvec::{SmallVec, smallvec};
18
19
19
20
use crate :: errors:: {
20
21
CountRepetitionMisplaced , MacroVarStillRepeating , MetaVarsDifSeqMatchers , MustRepeatOnce ,
21
- MveUnrecognizedVar , NoSyntaxVarsExprRepeat ,
22
+ MveExprHasNoField , MveUnrecognizedVar , NoSyntaxVarsExprRepeat ,
22
23
} ;
23
24
use crate :: mbe:: macro_parser:: NamedMatch ;
24
25
use crate :: mbe:: macro_parser:: NamedMatch :: * ;
25
26
use crate :: mbe:: metavar_expr:: { MetaVarExprConcatElem , RAW_IDENT_ERR } ;
26
- use crate :: mbe:: { self , KleeneOp , MetaVarExpr } ;
27
+ use crate :: mbe:: { self , KleeneOp , MetaVarExpr , MetaVarRecursiveExpr } ;
27
28
28
29
/// Context needed to perform transcription of metavariable expressions.
29
30
struct TranscrCtx < ' psess , ' itp > {
@@ -540,11 +541,105 @@ fn transcribe_metavar_expr<'tx>(
540
541
return Err ( out_of_bounds_err ( dcx, tscx. repeats . len ( ) , dspan. entire ( ) , "len" ) ) ;
541
542
}
542
543
} ,
544
+ MetaVarExpr :: Recursive ( ref expr) => {
545
+ let pnr = eval_metavar_recursive_expr ( tscx, expr) ?;
546
+ return transcribe_pnr ( tscx, dspan. entire ( ) , & pnr) ;
547
+ }
543
548
} ;
544
549
tscx. result . push ( tt) ;
545
550
Ok ( ( ) )
546
551
}
547
552
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
+
548
643
/// Handle the `${concat(...)}` metavariable expression.
549
644
fn metavar_expr_concat < ' tx > (
550
645
tscx : & mut TranscrCtx < ' tx , ' _ > ,
@@ -891,8 +986,19 @@ fn matched_from_ident<'ctx, 'interp, 'rslt>(
891
986
where
892
987
' interp : ' rslt ,
893
988
{
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
+ {
896
1002
interp. get ( & key) . ok_or_else ( || dcx. create_err ( MveUnrecognizedVar { span, key } ) )
897
1003
}
898
1004
0 commit comments