@@ -369,6 +369,25 @@ impl<'a> StringReader<'a> {
369
369
self . nextnextch ( ) == Some ( c)
370
370
}
371
371
372
+ /// Eats <XID_start><XID_continue>*, if possible.
373
+ fn scan_optional_raw_name ( & mut self ) -> Option < ast:: Name > {
374
+ if !ident_start ( self . curr ) {
375
+ return None
376
+ }
377
+ let start = self . last_pos ;
378
+ while ident_continue ( self . curr ) {
379
+ self . bump ( ) ;
380
+ }
381
+
382
+ self . with_str_from ( start, |string| {
383
+ if string == "_" {
384
+ None
385
+ } else {
386
+ Some ( token:: intern ( string) )
387
+ }
388
+ } )
389
+ }
390
+
372
391
/// PRECONDITION: self.curr is not whitespace
373
392
/// Eats any kind of comment.
374
393
fn scan_comment ( & mut self ) -> Option < TokenAndSpan > {
@@ -638,7 +657,7 @@ impl<'a> StringReader<'a> {
638
657
}
639
658
640
659
/// Lex a LIT_INTEGER or a LIT_FLOAT
641
- fn scan_number ( & mut self , c : char ) -> token:: Token {
660
+ fn scan_number ( & mut self , c : char ) -> token:: Lit {
642
661
let mut num_digits;
643
662
let mut base = 10 ;
644
663
let start_bpos = self . last_pos ;
@@ -655,17 +674,17 @@ impl<'a> StringReader<'a> {
655
674
}
656
675
'u' | 'i' => {
657
676
self . scan_int_suffix ( ) ;
658
- return token:: Literal ( token :: Integer ( self . name_from ( start_bpos) ) ) ;
677
+ return token:: Integer ( self . name_from ( start_bpos) ) ;
659
678
} ,
660
679
'f' => {
661
680
let last_pos = self . last_pos ;
662
681
self . scan_float_suffix ( ) ;
663
682
self . check_float_base ( start_bpos, last_pos, base) ;
664
- return token:: Literal ( token :: Float ( self . name_from ( start_bpos) ) ) ;
683
+ return token:: Float ( self . name_from ( start_bpos) ) ;
665
684
}
666
685
_ => {
667
686
// just a 0
668
- return token:: Literal ( token :: Integer ( self . name_from ( start_bpos) ) ) ;
687
+ return token:: Integer ( self . name_from ( start_bpos) ) ;
669
688
}
670
689
}
671
690
} else if c. is_digit_radix ( 10 ) {
@@ -678,7 +697,7 @@ impl<'a> StringReader<'a> {
678
697
self . err_span_ ( start_bpos, self . last_pos , "no valid digits found for number" ) ;
679
698
// eat any suffix
680
699
self . scan_int_suffix ( ) ;
681
- return token:: Literal ( token :: Integer ( token:: intern ( "0" ) ) ) ;
700
+ return token:: Integer ( token:: intern ( "0" ) ) ;
682
701
}
683
702
684
703
// might be a float, but don't be greedy if this is actually an
@@ -696,25 +715,25 @@ impl<'a> StringReader<'a> {
696
715
}
697
716
let last_pos = self . last_pos ;
698
717
self . check_float_base ( start_bpos, last_pos, base) ;
699
- return token:: Literal ( token :: Float ( self . name_from ( start_bpos) ) ) ;
718
+ return token:: Float ( self . name_from ( start_bpos) ) ;
700
719
} else if self . curr_is ( 'f' ) {
701
720
// or it might be an integer literal suffixed as a float
702
721
self . scan_float_suffix ( ) ;
703
722
let last_pos = self . last_pos ;
704
723
self . check_float_base ( start_bpos, last_pos, base) ;
705
- return token:: Literal ( token :: Float ( self . name_from ( start_bpos) ) ) ;
724
+ return token:: Float ( self . name_from ( start_bpos) ) ;
706
725
} else {
707
726
// it might be a float if it has an exponent
708
727
if self . curr_is ( 'e' ) || self . curr_is ( 'E' ) {
709
728
self . scan_float_exponent ( ) ;
710
729
self . scan_float_suffix ( ) ;
711
730
let last_pos = self . last_pos ;
712
731
self . check_float_base ( start_bpos, last_pos, base) ;
713
- return token:: Literal ( token :: Float ( self . name_from ( start_bpos) ) ) ;
732
+ return token:: Float ( self . name_from ( start_bpos) ) ;
714
733
}
715
734
// but we certainly have an integer!
716
735
self . scan_int_suffix ( ) ;
717
- return token:: Literal ( token :: Integer ( self . name_from ( start_bpos) ) ) ;
736
+ return token:: Integer ( self . name_from ( start_bpos) ) ;
718
737
}
719
738
}
720
739
@@ -967,7 +986,9 @@ impl<'a> StringReader<'a> {
967
986
}
968
987
969
988
if is_dec_digit ( c) {
970
- return self . scan_number ( c. unwrap ( ) ) ;
989
+ let num = self . scan_number ( c. unwrap ( ) ) ;
990
+ let suffix = self . scan_optional_raw_name ( ) ;
991
+ return token:: Literal ( num, suffix)
971
992
}
972
993
973
994
if self . read_embedded_ident {
@@ -1126,17 +1147,19 @@ impl<'a> StringReader<'a> {
1126
1147
}
1127
1148
let id = if valid { self . name_from ( start) } else { token:: intern ( "0" ) } ;
1128
1149
self . bump ( ) ; // advance curr past token
1129
- return token:: Literal ( token:: Char ( id) ) ;
1150
+ let suffix = self . scan_optional_raw_name ( ) ;
1151
+ return token:: Literal ( token:: Char ( id) , suffix) ;
1130
1152
}
1131
1153
'b' => {
1132
1154
self . bump ( ) ;
1133
- return match self . curr {
1155
+ let lit = match self . curr {
1134
1156
Some ( '\'' ) => self . scan_byte ( ) ,
1135
1157
Some ( '"' ) => self . scan_byte_string ( ) ,
1136
1158
Some ( 'r' ) => self . scan_raw_byte_string ( ) ,
1137
1159
_ => unreachable ! ( ) // Should have been a token::Ident above.
1138
1160
} ;
1139
-
1161
+ let suffix = self . scan_optional_raw_name ( ) ;
1162
+ return token:: Literal ( lit, suffix) ;
1140
1163
}
1141
1164
'"' => {
1142
1165
let start_bpos = self . last_pos ;
@@ -1157,7 +1180,8 @@ impl<'a> StringReader<'a> {
1157
1180
let id = if valid { self . name_from ( start_bpos + BytePos ( 1 ) ) }
1158
1181
else { token:: intern ( "??" ) } ;
1159
1182
self . bump ( ) ;
1160
- return token:: Literal ( token:: Str_ ( id) ) ;
1183
+ let suffix = self . scan_optional_raw_name ( ) ;
1184
+ return token:: Literal ( token:: Str_ ( id) , suffix) ;
1161
1185
}
1162
1186
'r' => {
1163
1187
let start_bpos = self . last_pos ;
@@ -1224,7 +1248,8 @@ impl<'a> StringReader<'a> {
1224
1248
} else {
1225
1249
token:: intern ( "??" )
1226
1250
} ;
1227
- return token:: Literal ( token:: StrRaw ( id, hash_count) ) ;
1251
+ let suffix = self . scan_optional_raw_name ( ) ;
1252
+ return token:: Literal ( token:: StrRaw ( id, hash_count) , suffix) ;
1228
1253
}
1229
1254
'-' => {
1230
1255
if self . nextch_is ( '>' ) {
@@ -1293,7 +1318,7 @@ impl<'a> StringReader<'a> {
1293
1318
|| ( self . curr_is ( '#' ) && self . nextch_is ( '!' ) && !self . nextnextch_is ( '[' ) )
1294
1319
}
1295
1320
1296
- fn scan_byte ( & mut self ) -> token:: Token {
1321
+ fn scan_byte ( & mut self ) -> token:: Lit {
1297
1322
self . bump ( ) ;
1298
1323
let start = self . last_pos ;
1299
1324
@@ -1314,10 +1339,10 @@ impl<'a> StringReader<'a> {
1314
1339
1315
1340
let id = if valid { self . name_from ( start) } else { token:: intern ( "??" ) } ;
1316
1341
self . bump ( ) ; // advance curr past token
1317
- return token:: Literal ( token :: Byte ( id) ) ;
1342
+ return token:: Byte ( id) ;
1318
1343
}
1319
1344
1320
- fn scan_byte_string ( & mut self ) -> token:: Token {
1345
+ fn scan_byte_string ( & mut self ) -> token:: Lit {
1321
1346
self . bump ( ) ;
1322
1347
let start = self . last_pos ;
1323
1348
let mut valid = true ;
@@ -1336,10 +1361,10 @@ impl<'a> StringReader<'a> {
1336
1361
}
1337
1362
let id = if valid { self . name_from ( start) } else { token:: intern ( "??" ) } ;
1338
1363
self . bump ( ) ;
1339
- return token:: Literal ( token :: Binary ( id) ) ;
1364
+ return token:: Binary ( id) ;
1340
1365
}
1341
1366
1342
- fn scan_raw_byte_string ( & mut self ) -> token:: Token {
1367
+ fn scan_raw_byte_string ( & mut self ) -> token:: Lit {
1343
1368
let start_bpos = self . last_pos ;
1344
1369
self . bump ( ) ;
1345
1370
let mut hash_count = 0 u;
@@ -1387,9 +1412,9 @@ impl<'a> StringReader<'a> {
1387
1412
self . bump ( ) ;
1388
1413
}
1389
1414
self . bump ( ) ;
1390
- return token:: Literal ( token :: BinaryRaw ( self . name_from_to ( content_start_bpos,
1391
- content_end_bpos) ,
1392
- hash_count) ) ;
1415
+ return token:: BinaryRaw ( self . name_from_to ( content_start_bpos,
1416
+ content_end_bpos) ,
1417
+ hash_count) ;
1393
1418
}
1394
1419
}
1395
1420
@@ -1536,17 +1561,17 @@ mod test {
1536
1561
1537
1562
#[ test] fn character_a ( ) {
1538
1563
assert_eq ! ( setup( & mk_sh( ) , "'a'" . to_string( ) ) . next_token( ) . tok,
1539
- token:: Literal ( token:: Char ( token:: intern( "a" ) ) ) ) ;
1564
+ token:: Literal ( token:: Char ( token:: intern( "a" ) ) , None ) ) ;
1540
1565
}
1541
1566
1542
1567
#[ test] fn character_space ( ) {
1543
1568
assert_eq ! ( setup( & mk_sh( ) , "' '" . to_string( ) ) . next_token( ) . tok,
1544
- token:: Literal ( token:: Char ( token:: intern( " " ) ) ) ) ;
1569
+ token:: Literal ( token:: Char ( token:: intern( " " ) ) , None ) ) ;
1545
1570
}
1546
1571
1547
1572
#[ test] fn character_escaped ( ) {
1548
1573
assert_eq ! ( setup( & mk_sh( ) , "'\\ n'" . to_string( ) ) . next_token( ) . tok,
1549
- token:: Literal ( token:: Char ( token:: intern( "\\ n" ) ) ) ) ;
1574
+ token:: Literal ( token:: Char ( token:: intern( "\\ n" ) ) , None ) ) ;
1550
1575
}
1551
1576
1552
1577
#[ test] fn lifetime_name ( ) {
@@ -1558,7 +1583,38 @@ mod test {
1558
1583
assert_eq ! ( setup( & mk_sh( ) ,
1559
1584
"r###\" \" #a\\ b\x00 c\" \" ###" . to_string( ) ) . next_token( )
1560
1585
. tok,
1561
- token:: Literal ( token:: StrRaw ( token:: intern( "\" #a\\ b\x00 c\" " ) , 3 ) ) ) ;
1586
+ token:: Literal ( token:: StrRaw ( token:: intern( "\" #a\\ b\x00 c\" " ) , 3 ) , None ) ) ;
1587
+ }
1588
+
1589
+ #[ test] fn literal_suffixes ( ) {
1590
+ macro_rules! test {
1591
+ ( $input: expr, $tok_type: ident, $tok_contents: expr) => { {
1592
+ assert_eq!( setup( & mk_sh( ) , format!( "{}suffix" , $input) ) . next_token( ) . tok,
1593
+ token:: Literal ( token:: $tok_type( token:: intern( $tok_contents) ) ,
1594
+ Some ( token:: intern( "suffix" ) ) ) ) ;
1595
+ // with a whitespace separator:
1596
+ assert_eq!( setup( & mk_sh( ) , format!( "{} suffix" , $input) ) . next_token( ) . tok,
1597
+ token:: Literal ( token:: $tok_type( token:: intern( $tok_contents) ) ,
1598
+ None ) ) ;
1599
+ } }
1600
+ }
1601
+
1602
+ test ! ( "'a'" , Char , "a" ) ;
1603
+ test ! ( "b'a'" , Byte , "a" ) ;
1604
+ test ! ( "\" a\" " , Str_ , "a" ) ;
1605
+ test ! ( "b\" a\" " , Binary , "a" ) ;
1606
+ test ! ( "1234" , Integer , "1234" ) ;
1607
+ test ! ( "0b101" , Integer , "0b101" ) ;
1608
+ test ! ( "0xABC" , Integer , "0xABC" ) ;
1609
+ test ! ( "1.0" , Float , "1.0" ) ;
1610
+ test ! ( "1.0e10" , Float , "1.0e10" ) ;
1611
+
1612
+ assert_eq ! ( setup( & mk_sh( ) , "r###\" raw\" ###suffix" . to_string( ) ) . next_token( ) . tok,
1613
+ token:: Literal ( token:: StrRaw ( token:: intern( "raw" ) , 3 ) ,
1614
+ Some ( token:: intern( "suffix" ) ) ) ) ;
1615
+ assert_eq ! ( setup( & mk_sh( ) , "br###\" raw\" ###suffix" . to_string( ) ) . next_token( ) . tok,
1616
+ token:: Literal ( token:: BinaryRaw ( token:: intern( "raw" ) , 3 ) ,
1617
+ Some ( token:: intern( "suffix" ) ) ) ) ;
1562
1618
}
1563
1619
1564
1620
#[ test] fn line_doc_comments ( ) {
@@ -1574,7 +1630,7 @@ mod test {
1574
1630
token:: Comment => { } ,
1575
1631
_ => panic ! ( "expected a comment!" )
1576
1632
}
1577
- assert_eq ! ( lexer. next_token( ) . tok, token:: Literal ( token:: Char ( token:: intern( "a" ) ) ) ) ;
1633
+ assert_eq ! ( lexer. next_token( ) . tok, token:: Literal ( token:: Char ( token:: intern( "a" ) ) , None ) ) ;
1578
1634
}
1579
1635
1580
1636
}
0 commit comments