@@ -650,12 +650,13 @@ impl<'a> StringReader<'a> {
650650 /// token, and updates the interner
651651 fn next_token_inner ( & mut self ) -> token:: Token {
652652 let c = self . curr ;
653- if ident_start ( c) && match ( c. unwrap ( ) , self . nextch ( ) ) {
653+ if ident_start ( c) && match ( c. unwrap ( ) , self . nextch ( ) , self . nextnextch ( ) ) {
654654 // Note: r as in r" or r#" is part of a raw string literal,
655655 // b as in b' is part of a byte literal.
656656 // They are not identifiers, and are handled further down.
657- ( 'r' , Some ( '"' ) ) | ( 'r' , Some ( '#' ) ) |
658- ( 'b' , Some ( '"' ) ) | ( 'b' , Some ( '\'' ) ) => false ,
657+ ( 'r' , Some ( '"' ) , _) | ( 'r' , Some ( '#' ) , _) |
658+ ( 'b' , Some ( '"' ) , _) | ( 'b' , Some ( '\'' ) , _) |
659+ ( 'b' , Some ( 'r' ) , Some ( '"' ) ) | ( 'b' , Some ( 'r' ) , Some ( '#' ) ) => false ,
659660 _ => true
660661 } {
661662 let start = self . last_pos ;
@@ -863,6 +864,7 @@ impl<'a> StringReader<'a> {
863864 return match self . curr {
864865 Some ( '\'' ) => parse_byte ( self ) ,
865866 Some ( '"' ) => parse_byte_string ( self ) ,
867+ Some ( 'r' ) => parse_raw_byte_string ( self ) ,
866868 _ => unreachable ! ( ) // Should have been a token::IDENT above.
867869 } ;
868870
@@ -978,6 +980,54 @@ impl<'a> StringReader<'a> {
978980 self_. bump ( ) ;
979981 return token:: LIT_BINARY ( Rc :: new ( value) ) ;
980982 }
983+
984+ fn parse_raw_byte_string ( self_ : & mut StringReader ) -> token:: Token {
985+ let start_bpos = self_. last_pos ;
986+ self_. bump ( ) ;
987+ let mut hash_count = 0 u;
988+ while self_. curr_is ( '#' ) {
989+ self_. bump ( ) ;
990+ hash_count += 1 ;
991+ }
992+
993+ if self_. is_eof ( ) {
994+ self_. fatal_span ( start_bpos, self_. last_pos , "unterminated raw string" ) ;
995+ } else if !self_. curr_is ( '"' ) {
996+ self_. fatal_span_char ( start_bpos, self_. last_pos ,
997+ "only `#` is allowed in raw string delimitation; \
998+ found illegal character",
999+ self_. curr . unwrap ( ) ) ;
1000+ }
1001+ self_. bump ( ) ;
1002+ let content_start_bpos = self_. last_pos ;
1003+ let mut content_end_bpos;
1004+ ' outer: loop {
1005+ match self_. curr {
1006+ None => self_. fatal_span ( start_bpos, self_. last_pos ,
1007+ "unterminated raw string" ) ,
1008+ Some ( '"' ) => {
1009+ content_end_bpos = self_. last_pos ;
1010+ for _ in range ( 0 , hash_count) {
1011+ self_. bump ( ) ;
1012+ if !self_. curr_is ( '#' ) {
1013+ continue ' outer;
1014+ }
1015+ }
1016+ break ;
1017+ } ,
1018+ Some ( c) => if c > '\x7F' {
1019+ self_. err_span_char ( self_. last_pos , self_. last_pos ,
1020+ "raw byte string must be ASCII" , c) ;
1021+ }
1022+ }
1023+ self_. bump ( ) ;
1024+ }
1025+ self_. bump ( ) ;
1026+ let bytes = self_. with_str_from_to ( content_start_bpos,
1027+ content_end_bpos,
1028+ |s| s. as_bytes ( ) . to_owned ( ) ) ;
1029+ return token:: LIT_BINARY_RAW ( Rc :: new ( bytes) , hash_count) ;
1030+ }
9811031 }
9821032 '"' => {
9831033 let mut accum_str = String :: new ( ) ;
0 commit comments