@@ -8,8 +8,12 @@ use rustc_span::symbol::Ident;
88use rustc_span:: Span ;
99
1010/// A meta-variable expression, for expansions based on properties of meta-variables.
11- #[ derive( Debug , Clone , PartialEq , Encodable , Decodable ) ]
11+ #[ derive( Debug , Decodable , Encodable , PartialEq ) ]
1212pub ( crate ) enum MetaVarExpr {
13+ /// Unification of two identifiers. The `bool` of each element indicates if there is a
14+ /// preceding dollar sign.
15+ Concat ( Box < [ MetaVarExprConcatElem ] > ) ,
16+
1317 /// The number of repetitions of an identifier.
1418 Count ( Ident , usize ) ,
1519
@@ -41,6 +45,34 @@ impl MetaVarExpr {
4145 check_trailing_token ( & mut tts, sess) ?;
4246 let mut iter = args. trees ( ) ;
4347 let rslt = match ident. as_str ( ) {
48+ "concat" => {
49+ fn element < ' sess > (
50+ iter : & mut RefTokenTreeCursor < ' _ > ,
51+ sess : & ' sess ParseSess ,
52+ span : Span ,
53+ ) -> PResult < ' sess , MetaVarExprConcatElem > {
54+ let is_var = try_eat_dollar ( iter) ;
55+ let ident = parse_ident ( iter, sess, span) ?;
56+ Ok ( MetaVarExprConcatElem { ident, is_var } )
57+ }
58+
59+ let mut rslt = Vec :: new ( ) ;
60+ rslt. push ( element ( & mut iter, sess, ident. span ) ?) ;
61+ if !try_eat_comma ( & mut iter) {
62+ return Err ( sess. dcx . struct_span_err ( ident. span , "expected comma" ) ) ;
63+ }
64+ rslt. push ( element ( & mut iter, sess, ident. span ) ?) ;
65+ loop {
66+ if iter. look_ahead ( 0 ) . is_none ( ) {
67+ break ;
68+ }
69+ if !try_eat_comma ( & mut iter) {
70+ return Err ( sess. dcx . struct_span_err ( ident. span , "expected comma" ) ) ;
71+ }
72+ rslt. push ( element ( & mut iter, sess, ident. span ) ?) ;
73+ }
74+ MetaVarExpr :: Concat ( rslt. into ( ) )
75+ }
4476 "count" => parse_count ( & mut iter, sess, ident. span ) ?,
4577 "ignore" => {
4678 eat_dollar ( & mut iter, sess, ident. span ) ?;
@@ -67,11 +99,17 @@ impl MetaVarExpr {
6799 pub ( crate ) fn ident ( & self ) -> Option < Ident > {
68100 match * self {
69101 MetaVarExpr :: Count ( ident, _) | MetaVarExpr :: Ignore ( ident) => Some ( ident) ,
70- MetaVarExpr :: Index ( ..) | MetaVarExpr :: Length ( ..) => None ,
102+ MetaVarExpr :: Concat { .. } | MetaVarExpr :: Index ( ..) | MetaVarExpr :: Length ( ..) => None ,
71103 }
72104 }
73105}
74106
107+ #[ derive( Debug , Decodable , Encodable , PartialEq ) ]
108+ pub ( crate ) struct MetaVarExprConcatElem {
109+ pub ( crate ) ident : Ident ,
110+ pub ( crate ) is_var : bool ,
111+ }
112+
75113// Checks if there are any remaining tokens. For example, `${ignore(ident ... a b c ...)}`
76114fn check_trailing_token < ' sess > (
77115 iter : & mut RefTokenTreeCursor < ' _ > ,
@@ -169,6 +207,17 @@ fn try_eat_comma(iter: &mut RefTokenTreeCursor<'_>) -> bool {
169207 false
170208}
171209
210+ /// Tries to move the iterator forward returning `true` if there is a dollar sign. If not, then the
211+ /// iterator is not modified and the result is `false`.
212+ fn try_eat_dollar ( iter : & mut RefTokenTreeCursor < ' _ > ) -> bool {
213+ if let Some ( TokenTree :: Token ( token:: Token { kind : token:: Dollar , .. } , _) ) = iter. look_ahead ( 0 )
214+ {
215+ let _ = iter. next ( ) ;
216+ return true ;
217+ }
218+ false
219+ }
220+
172221/// Expects that the next item is a dollar sign.
173222fn eat_dollar < ' sess > (
174223 iter : & mut RefTokenTreeCursor < ' _ > ,
0 commit comments