@@ -209,17 +209,19 @@ impl ast::String {
209
209
let text = & text[ self . text_range_between_quotes ( ) ? - self . syntax ( ) . text_range ( ) . start ( ) ] ;
210
210
211
211
let mut buf = String :: new ( ) ;
212
- let mut text_iter = text . chars ( ) ;
212
+ let mut prev_end = 0 ;
213
213
let mut has_error = false ;
214
214
unescape_literal ( text, Mode :: Str , & mut |char_range, unescaped_char| match (
215
215
unescaped_char,
216
216
buf. capacity ( ) == 0 ,
217
217
) {
218
218
( Ok ( c) , false ) => buf. push ( c) ,
219
- ( Ok ( c) , true ) if char_range. len ( ) == 1 && Some ( c) == text_iter. next ( ) => ( ) ,
219
+ ( Ok ( _) , true ) if char_range. len ( ) == 1 && char_range. start == prev_end => {
220
+ prev_end = char_range. end
221
+ }
220
222
( Ok ( c) , true ) => {
221
223
buf. reserve_exact ( text. len ( ) ) ;
222
- buf. push_str ( & text[ ..char_range . start ] ) ;
224
+ buf. push_str ( & text[ ..prev_end ] ) ;
223
225
buf. push ( c) ;
224
226
}
225
227
( Err ( _) , _) => has_error = true ,
@@ -252,17 +254,19 @@ impl ast::ByteString {
252
254
let text = & text[ self . text_range_between_quotes ( ) ? - self . syntax ( ) . text_range ( ) . start ( ) ] ;
253
255
254
256
let mut buf: Vec < u8 > = Vec :: new ( ) ;
255
- let mut text_iter = text . chars ( ) ;
257
+ let mut prev_end = 0 ;
256
258
let mut has_error = false ;
257
259
unescape_literal ( text, Mode :: ByteStr , & mut |char_range, unescaped_char| match (
258
260
unescaped_char,
259
261
buf. capacity ( ) == 0 ,
260
262
) {
261
263
( Ok ( c) , false ) => buf. push ( c as u8 ) ,
262
- ( Ok ( c) , true ) if char_range. len ( ) == 1 && Some ( c) == text_iter. next ( ) => ( ) ,
264
+ ( Ok ( _) , true ) if char_range. len ( ) == 1 && char_range. start == prev_end => {
265
+ prev_end = char_range. end
266
+ }
263
267
( Ok ( c) , true ) => {
264
268
buf. reserve_exact ( text. len ( ) ) ;
265
- buf. extend_from_slice ( text[ ..char_range . start ] . as_bytes ( ) ) ;
269
+ buf. extend_from_slice ( text[ ..prev_end ] . as_bytes ( ) ) ;
266
270
buf. push ( c as u8 ) ;
267
271
}
268
272
( Err ( _) , _) => has_error = true ,
@@ -445,6 +449,36 @@ mod tests {
445
449
check_string_value ( r"\foobar" , None ) ;
446
450
check_string_value ( r"\nfoobar" , "\n foobar" ) ;
447
451
check_string_value ( r"C:\\Windows\\System32\\" , "C:\\ Windows\\ System32\\ " ) ;
452
+ check_string_value ( r"\x61bcde" , "abcde" ) ;
453
+ check_string_value (
454
+ r"a\
455
+ bcde" , "abcde" ,
456
+ ) ;
457
+ }
458
+
459
+ fn check_byte_string_value < ' a , const N : usize > (
460
+ lit : & str ,
461
+ expected : impl Into < Option < & ' a [ u8 ; N ] > > ,
462
+ ) {
463
+ assert_eq ! (
464
+ ast:: ByteString { syntax: make:: tokens:: literal( & format!( "b\" {}\" " , lit) ) }
465
+ . value( )
466
+ . as_deref( ) ,
467
+ expected. into( ) . map( |value| & value[ ..] )
468
+ ) ;
469
+ }
470
+
471
+ #[ test]
472
+ fn test_byte_string_escape ( ) {
473
+ check_byte_string_value ( r"foobar" , b"foobar" ) ;
474
+ check_byte_string_value ( r"\foobar" , None :: < & [ u8 ; 0 ] > ) ;
475
+ check_byte_string_value ( r"\nfoobar" , b"\n foobar" ) ;
476
+ check_byte_string_value ( r"C:\\Windows\\System32\\" , b"C:\\ Windows\\ System32\\ " ) ;
477
+ check_byte_string_value ( r"\x61bcde" , b"abcde" ) ;
478
+ check_byte_string_value (
479
+ r"a\
480
+ bcde" , b"abcde" ,
481
+ ) ;
448
482
}
449
483
450
484
#[ test]
0 commit comments