@@ -121,6 +121,7 @@ register_builtin! {
121
121
( compile_error, CompileError ) => compile_error_expand,
122
122
( concat, Concat ) => concat_expand,
123
123
( concat_idents, ConcatIdents ) => concat_idents_expand,
124
+ ( concat_bytes, ConcatBytes ) => concat_bytes_expand,
124
125
( include, Include ) => include_expand,
125
126
( include_bytes, IncludeBytes ) => include_bytes_expand,
126
127
( include_str, IncludeStr ) => include_str_expand,
@@ -359,6 +360,12 @@ fn unquote_str(lit: &tt::Literal) -> Option<String> {
359
360
token. value ( ) . map ( |it| it. into_owned ( ) )
360
361
}
361
362
363
+ fn unquote_byte_string ( lit : & tt:: Literal ) -> Option < Vec < u8 > > {
364
+ let lit = ast:: make:: tokens:: literal ( & lit. to_string ( ) ) ;
365
+ let token = ast:: ByteString :: cast ( lit) ?;
366
+ token. value ( ) . map ( |it| it. into_owned ( ) )
367
+ }
368
+
362
369
fn compile_error_expand (
363
370
_db : & dyn AstDatabase ,
364
371
_id : MacroCallId ,
@@ -422,6 +429,74 @@ fn concat_expand(
422
429
ExpandResult { value : ExpandedEager :: new ( quote ! ( #text) ) , err }
423
430
}
424
431
432
+ fn concat_bytes_expand (
433
+ _db : & dyn AstDatabase ,
434
+ _arg_id : MacroCallId ,
435
+ tt : & tt:: Subtree ,
436
+ ) -> ExpandResult < ExpandedEager > {
437
+ let mut bytes = Vec :: new ( ) ;
438
+ let mut err = None ;
439
+ for ( i, t) in tt. token_trees . iter ( ) . enumerate ( ) {
440
+ match t {
441
+ tt:: TokenTree :: Leaf ( tt:: Leaf :: Literal ( lit) ) => {
442
+ let token = ast:: make:: tokens:: literal ( & lit. to_string ( ) ) ;
443
+ match token. kind ( ) {
444
+ syntax:: SyntaxKind :: BYTE => bytes. push ( token. text ( ) . to_string ( ) ) ,
445
+ syntax:: SyntaxKind :: BYTE_STRING => {
446
+ let components = unquote_byte_string ( lit) . unwrap_or_else ( || Vec :: new ( ) ) ;
447
+ components. into_iter ( ) . for_each ( |x| bytes. push ( x. to_string ( ) ) ) ;
448
+ }
449
+ _ => {
450
+ err. get_or_insert ( mbe:: ExpandError :: UnexpectedToken . into ( ) ) ;
451
+ break ;
452
+ }
453
+ }
454
+ }
455
+ tt:: TokenTree :: Leaf ( tt:: Leaf :: Punct ( punct) ) if i % 2 == 1 && punct. char == ',' => ( ) ,
456
+ tt:: TokenTree :: Subtree ( tree)
457
+ if tree. delimiter_kind ( ) == Some ( tt:: DelimiterKind :: Bracket ) =>
458
+ {
459
+ if let Err ( e) = concat_bytes_expand_subtree ( tree, & mut bytes) {
460
+ err. get_or_insert ( e) ;
461
+ break ;
462
+ }
463
+ }
464
+ _ => {
465
+ err. get_or_insert ( mbe:: ExpandError :: UnexpectedToken . into ( ) ) ;
466
+ break ;
467
+ }
468
+ }
469
+ }
470
+ let ident = tt:: Ident { text : bytes. join ( ", " ) . into ( ) , id : tt:: TokenId :: unspecified ( ) } ;
471
+ ExpandResult { value : ExpandedEager :: new ( quote ! ( [ #ident] ) ) , err }
472
+ }
473
+
474
+ fn concat_bytes_expand_subtree (
475
+ tree : & tt:: Subtree ,
476
+ bytes : & mut Vec < String > ,
477
+ ) -> Result < ( ) , ExpandError > {
478
+ for ( ti, tt) in tree. token_trees . iter ( ) . enumerate ( ) {
479
+ match tt {
480
+ tt:: TokenTree :: Leaf ( tt:: Leaf :: Literal ( lit) ) => {
481
+ let lit = ast:: make:: tokens:: literal ( & lit. to_string ( ) ) ;
482
+ match lit. kind ( ) {
483
+ syntax:: SyntaxKind :: BYTE | syntax:: SyntaxKind :: INT_NUMBER => {
484
+ bytes. push ( lit. text ( ) . to_string ( ) )
485
+ }
486
+ _ => {
487
+ return Err ( mbe:: ExpandError :: UnexpectedToken . into ( ) ) ;
488
+ }
489
+ }
490
+ }
491
+ tt:: TokenTree :: Leaf ( tt:: Leaf :: Punct ( punct) ) if ti % 2 == 1 && punct. char == ',' => ( ) ,
492
+ _ => {
493
+ return Err ( mbe:: ExpandError :: UnexpectedToken . into ( ) ) ;
494
+ }
495
+ }
496
+ }
497
+ Ok ( ( ) )
498
+ }
499
+
425
500
fn concat_idents_expand (
426
501
_db : & dyn AstDatabase ,
427
502
_arg_id : MacroCallId ,
0 commit comments