@@ -8,8 +8,12 @@ use rustc_span::symbol::Ident;
8
8
use rustc_span:: Span ;
9
9
10
10
/// 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 ) ]
12
12
pub ( 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
+
13
17
/// The number of repetitions of an identifier.
14
18
Count ( Ident , usize ) ,
15
19
@@ -41,6 +45,34 @@ impl MetaVarExpr {
41
45
check_trailing_token ( & mut tts, sess) ?;
42
46
let mut iter = args. trees ( ) ;
43
47
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
+ }
44
76
"count" => parse_count ( & mut iter, sess, ident. span ) ?,
45
77
"ignore" => {
46
78
eat_dollar ( & mut iter, sess, ident. span ) ?;
@@ -67,11 +99,17 @@ impl MetaVarExpr {
67
99
pub ( crate ) fn ident ( & self ) -> Option < Ident > {
68
100
match * self {
69
101
MetaVarExpr :: Count ( ident, _) | MetaVarExpr :: Ignore ( ident) => Some ( ident) ,
70
- MetaVarExpr :: Index ( ..) | MetaVarExpr :: Length ( ..) => None ,
102
+ MetaVarExpr :: Concat { .. } | MetaVarExpr :: Index ( ..) | MetaVarExpr :: Length ( ..) => None ,
71
103
}
72
104
}
73
105
}
74
106
107
+ #[ derive( Debug , Decodable , Encodable , PartialEq ) ]
108
+ pub ( crate ) struct MetaVarExprConcatElem {
109
+ pub ( crate ) ident : Ident ,
110
+ pub ( crate ) is_var : bool ,
111
+ }
112
+
75
113
// Checks if there are any remaining tokens. For example, `${ignore(ident ... a b c ...)}`
76
114
fn check_trailing_token < ' sess > (
77
115
iter : & mut RefTokenTreeCursor < ' _ > ,
@@ -169,6 +207,17 @@ fn try_eat_comma(iter: &mut RefTokenTreeCursor<'_>) -> bool {
169
207
false
170
208
}
171
209
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
+
172
221
/// Expects that the next item is a dollar sign.
173
222
fn eat_dollar < ' sess > (
174
223
iter : & mut RefTokenTreeCursor < ' _ > ,
0 commit comments