@@ -213,10 +213,22 @@ fn byte_offset(rdr: &StringReader, pos: BytePos) -> BytePos {
213
213
( pos - rdr. filemap . start_pos )
214
214
}
215
215
216
+ /// Calls `f` with a string slice of the source text spanning from `start`
217
+ /// up to but excluding `rdr.last_pos`, meaning the slice does not include
218
+ /// the character `rdr.curr`.
216
219
pub fn with_str_from < T > ( rdr : @mut StringReader , start : BytePos , f : & fn ( s : & str ) -> T ) -> T {
220
+ with_str_from_to ( rdr, start, rdr. last_pos , f)
221
+ }
222
+
223
+ /// Calls `f` with astring slice of the source text spanning from `start`
224
+ /// up to but excluding `end`.
225
+ fn with_str_from_to < T > ( rdr : @mut StringReader ,
226
+ start : BytePos ,
227
+ end : BytePos ,
228
+ f : & fn ( s : & str ) -> T ) -> T {
217
229
f ( rdr. src . slice (
218
230
byte_offset ( rdr, start) . to_uint ( ) ,
219
- byte_offset ( rdr, rdr . last_pos ) . to_uint ( ) ) )
231
+ byte_offset ( rdr, end ) . to_uint ( ) ) )
220
232
}
221
233
222
234
// EFFECT: advance the StringReader by one character. If a newline is
@@ -612,7 +624,10 @@ fn ident_continue(c: char) -> bool {
612
624
// EFFECT: updates the interner
613
625
fn next_token_inner ( rdr : @mut StringReader ) -> token:: Token {
614
626
let c = rdr. curr ;
615
- if ident_start ( c) {
627
+ if ident_start ( c) && nextch ( rdr) != '"' && nextch ( rdr) != '#' {
628
+ // Note: r as in r" or r#" is part of a raw string literal,
629
+ // not an identifier, and is handled further down.
630
+
616
631
let start = rdr. last_pos ;
617
632
while ident_continue ( rdr. curr ) {
618
633
bump ( rdr) ;
@@ -829,6 +844,47 @@ fn next_token_inner(rdr: @mut StringReader) -> token::Token {
829
844
bump ( rdr) ;
830
845
return token:: LIT_STR ( str_to_ident ( accum_str) ) ;
831
846
}
847
+ 'r' => {
848
+ let start_bpos = rdr. last_pos ;
849
+ bump ( rdr) ;
850
+ let mut hash_count = 0 u;
851
+ while rdr. curr == '#' {
852
+ bump ( rdr) ;
853
+ hash_count += 1 ;
854
+ }
855
+ if rdr. curr != '"' {
856
+ fatal_span_char ( rdr, start_bpos, rdr. last_pos ,
857
+ ~"only `#` is allowed in raw string delimitation; \
858
+ found illegal character",
859
+ rdr. curr ) ;
860
+ }
861
+ bump ( rdr) ;
862
+ let content_start_bpos = rdr. last_pos ;
863
+ let mut content_end_bpos;
864
+ ' outer: loop {
865
+ if is_eof ( rdr) {
866
+ fatal_span ( rdr, start_bpos, rdr. last_pos ,
867
+ ~"unterminated raw string") ;
868
+ }
869
+ if rdr. curr == '"' {
870
+ content_end_bpos = rdr. last_pos ;
871
+ for _ in range ( 0 , hash_count) {
872
+ bump ( rdr) ;
873
+ if rdr. curr != '#' {
874
+ continue ' outer;
875
+ }
876
+ }
877
+ break ;
878
+ }
879
+ bump ( rdr) ;
880
+ }
881
+ bump ( rdr) ;
882
+ let str_content = with_str_from_to ( rdr,
883
+ content_start_bpos,
884
+ content_end_bpos,
885
+ str_to_ident) ;
886
+ return token:: LIT_STR ( str_content) ;
887
+ }
832
888
'-' => {
833
889
if nextch ( rdr) == '>' {
834
890
bump ( rdr) ;
@@ -987,6 +1043,14 @@ mod test {
987
1043
assert_eq ! ( tok, token:: LIFETIME ( id) ) ;
988
1044
}
989
1045
1046
+ #[ test] fn raw_string( ) {
1047
+ let env = setup( @"r###\" \" #a\\ b\x00 c\" \" ###") ;
1048
+ let TokenAndSpan { tok, sp: _} =
1049
+ env. string_reader. next_token( ) ;
1050
+ let id = token:: str_to_ident( "\" #a\\ b\x00 c\" ") ;
1051
+ assert_eq!( tok, token:: LIT_STR ( id) ) ;
1052
+ }
1053
+
990
1054
#[ test] fn line_doc_comments( ) {
991
1055
assert!( !is_line_non_doc_comment( "///") ) ;
992
1056
assert!( !is_line_non_doc_comment( "/// blah") ) ;
0 commit comments