@@ -149,6 +149,16 @@ impl reader for TtReader {
149149 fn dup ( @mut self ) -> @mut reader { dup_tt_reader ( self ) as @mut reader }
150150}
151151
152+ // report a lexical error spanning [`from_pos`, `to_pos`)
153+ fn fatal_span ( rdr : @mut StringReader ,
154+ from_pos : BytePos ,
155+ to_pos : BytePos ,
156+ m : ~str )
157+ -> ! {
158+ rdr. peek_span = codemap:: mk_sp ( from_pos, to_pos) ;
159+ rdr. fatal ( m) ;
160+ }
161+
152162// EFFECT: advance peek_tok and peek_span to refer to the next token.
153163// EFFECT: update the interner, maybe.
154164fn string_advance_token ( r : @mut StringReader ) {
@@ -327,7 +337,8 @@ fn consume_block_comment(rdr: @mut StringReader)
327337 bump ( rdr) ;
328338 }
329339 if is_eof ( rdr) {
330- rdr. fatal ( ~"unterminated block doc-comment") ;
340+ fatal_span ( rdr, start_bpos, rdr. last_pos ,
341+ ~"unterminated block doc-comment") ;
331342 } else {
332343 bump ( rdr) ;
333344 bump ( rdr) ;
@@ -344,8 +355,12 @@ fn consume_block_comment(rdr: @mut StringReader)
344355 }
345356 }
346357 } else {
358+ let start_bpos = rdr. last_pos - BytePos ( 2 u) ;
347359 loop {
348- if is_eof ( rdr) { rdr. fatal ( ~"unterminated block comment") ; }
360+ if is_eof ( rdr) {
361+ fatal_span ( rdr, start_bpos, rdr. last_pos ,
362+ ~"unterminated block comment") ;
363+ }
349364 if rdr. curr == '*' && nextch ( rdr) == '/' {
350365 bump ( rdr) ;
351366 bump ( rdr) ;
@@ -362,6 +377,7 @@ fn consume_block_comment(rdr: @mut StringReader)
362377}
363378
364379fn scan_exponent ( rdr : @mut StringReader ) -> Option < ~str > {
380+ let start_bpos = rdr. last_pos ;
365381 let mut c = rdr. curr ;
366382 let mut rslt = ~"";
367383 if c == 'e' || c == 'E' {
@@ -375,7 +391,10 @@ fn scan_exponent(rdr: @mut StringReader) -> Option<~str> {
375391 let exponent = scan_digits ( rdr, 10 u) ;
376392 if exponent. len ( ) > 0 u {
377393 return Some ( rslt + exponent) ;
378- } else { rdr. fatal ( ~"scan_exponent: bad fp literal") ; }
394+ } else {
395+ fatal_span ( rdr, start_bpos, rdr. last_pos ,
396+ ~"scan_exponent: bad fp literal") ;
397+ }
379398 } else { return None :: < ~str > ; }
380399}
381400
@@ -399,6 +418,7 @@ fn scan_number(c: char, rdr: @mut StringReader) -> token::Token {
399418 let mut base = 10 u;
400419 let mut c = c;
401420 let mut n = nextch ( rdr) ;
421+ let start_bpos = rdr. last_pos ;
402422 if c == '0' && n == 'x' {
403423 bump ( rdr) ;
404424 bump ( rdr) ;
@@ -442,11 +462,13 @@ fn scan_number(c: char, rdr: @mut StringReader) -> token::Token {
442462 else { either:: Right ( ast:: ty_u64) } ;
443463 }
444464 if num_str. len ( ) == 0 u {
445- rdr. fatal ( ~"no valid digits found for number") ;
465+ fatal_span ( rdr, start_bpos, rdr. last_pos ,
466+ ~"no valid digits found for number") ;
446467 }
447468 let parsed = match from_str_radix :: < u64 > ( num_str, base as uint ) {
448469 Some ( p) => p,
449- None => rdr. fatal ( ~"int literal is too large")
470+ None => fatal_span ( rdr, start_bpos, rdr. last_pos ,
471+ ~"int literal is too large")
450472 } ;
451473
452474 match tp {
@@ -464,8 +486,10 @@ fn scan_number(c: char, rdr: @mut StringReader) -> token::Token {
464486 }
465487 if is_float {
466488 match base {
467- 16 u => rdr. fatal ( ~"hexadecimal float literal is not supported") ,
468- 2 u => rdr. fatal ( ~"binary float literal is not supported") ,
489+ 16 u => fatal_span ( rdr, start_bpos, rdr. last_pos ,
490+ ~"hexadecimal float literal is not supported") ,
491+ 2 u => fatal_span ( rdr, start_bpos, rdr. last_pos ,
492+ ~"binary float literal is not supported") ,
469493 _ => ( )
470494 }
471495 }
@@ -507,11 +531,13 @@ fn scan_number(c: char, rdr: @mut StringReader) -> token::Token {
507531 return token:: LIT_FLOAT_UNSUFFIXED ( str_to_ident ( num_str) ) ;
508532 } else {
509533 if num_str. len ( ) == 0 u {
510- rdr. fatal ( ~"no valid digits found for number") ;
534+ fatal_span ( rdr, start_bpos, rdr. last_pos ,
535+ ~"no valid digits found for number") ;
511536 }
512537 let parsed = match from_str_radix :: < u64 > ( num_str, base as uint ) {
513538 Some ( p) => p,
514- None => rdr. fatal ( ~"int literal is too large")
539+ None => fatal_span ( rdr, start_bpos, rdr. last_pos ,
540+ ~"int literal is too large")
515541 } ;
516542
517543 debug ! ( "lexing %s as an unsuffixed integer literal" ,
@@ -523,19 +549,23 @@ fn scan_number(c: char, rdr: @mut StringReader) -> token::Token {
523549fn scan_numeric_escape ( rdr : @mut StringReader , n_hex_digits : uint ) -> char {
524550 let mut accum_int = 0 ;
525551 let mut i = n_hex_digits;
552+ let start_bpos = rdr. last_pos ;
526553 while i != 0 u {
527554 let n = rdr. curr ;
528- bump ( rdr) ;
529555 if !is_hex_digit ( n) {
530- rdr. fatal ( fmt ! ( "illegal numeric character escape: %d" , n as int) ) ;
556+ fatal_span ( rdr, rdr. last_pos , rdr. pos ,
557+ fmt ! ( "illegal numeric character escape: %d" ,
558+ n as int) ) ;
531559 }
560+ bump ( rdr) ;
532561 accum_int *= 16 ;
533562 accum_int += hex_digit_val ( n) ;
534563 i -= 1 u;
535564 }
536565 match char:: from_u32 ( accum_int as u32 ) {
537566 Some ( x) => x,
538- None => rdr. fatal ( fmt ! ( "illegal numeric character escape" ) )
567+ None => fatal_span ( rdr, start_bpos, rdr. last_pos ,
568+ fmt ! ( "illegal numeric character escape" ) )
539569 }
540570}
541571
@@ -691,6 +721,7 @@ fn next_token_inner(rdr: @mut StringReader) -> token::Token {
691721 if c2 == '\\' {
692722 // '\X' for some X must be a character constant:
693723 let escaped = rdr. curr ;
724+ let escaped_pos = rdr. last_pos ;
694725 bump ( rdr) ;
695726 match escaped {
696727 'n' => { c2 = '\n' ; }
@@ -704,12 +735,18 @@ fn next_token_inner(rdr: @mut StringReader) -> token::Token {
704735 'u' => { c2 = scan_numeric_escape ( rdr, 4 u) ; }
705736 'U' => { c2 = scan_numeric_escape ( rdr, 8 u) ; }
706737 c2 => {
707- rdr. fatal ( fmt ! ( "unknown character escape: %d" , c2 as int) ) ;
738+ fatal_span ( rdr, escaped_pos, rdr. last_pos ,
739+ fmt ! ( "unknown character escape: %d" , c2 as int) ) ;
708740 }
709741 }
710742 }
711743 if rdr. curr != '\'' {
712- rdr. fatal ( ~"unterminated character constant") ;
744+ fatal_span ( rdr,
745+ // Byte offsetting here is okay because the character
746+ // before position `start` is an ascii single quote.
747+ start - BytePos ( 1 u) ,
748+ rdr. last_pos ,
749+ ~"unterminated character constant") ;
713750 }
714751 bump ( rdr) ; // advance curr past token
715752 return token:: LIT_CHAR ( c2 as u32 ) ;
@@ -721,7 +758,9 @@ fn next_token_inner(rdr: @mut StringReader) -> token::Token {
721758 while rdr. curr != '"' {
722759 if is_eof ( rdr) {
723760 do with_str_from ( rdr, n) |s| {
724- rdr. fatal ( fmt ! ( "unterminated double quote string: %s" , s) ) ;
761+ fatal_span ( rdr, n, rdr. last_pos ,
762+ fmt ! ( "unterminated double quote string: %s" ,
763+ s) ) ;
725764 }
726765 }
727766
@@ -730,6 +769,7 @@ fn next_token_inner(rdr: @mut StringReader) -> token::Token {
730769 match ch {
731770 '\\' => {
732771 let escaped = rdr. curr ;
772+ let escaped_pos = rdr. last_pos ;
733773 bump ( rdr) ;
734774 match escaped {
735775 'n' => accum_str. push_char ( '\n' ) ,
@@ -750,7 +790,8 @@ fn next_token_inner(rdr: @mut StringReader) -> token::Token {
750790 accum_str. push_char ( scan_numeric_escape ( rdr, 8 u) ) ;
751791 }
752792 c2 => {
753- rdr. fatal ( fmt ! ( "unknown string escape: %d" , c2 as int) ) ;
793+ fatal_span ( rdr, escaped_pos, rdr. last_pos ,
794+ fmt ! ( "unknown string escape: %d" , c2 as int) ) ;
754795 }
755796 }
756797 }
@@ -786,11 +827,10 @@ fn next_token_inner(rdr: @mut StringReader) -> token::Token {
786827 '^' => { return binop ( rdr, token:: CARET ) ; }
787828 '%' => { return binop ( rdr, token:: PERCENT ) ; }
788829 c => {
789- // So the error span points to the unrecognized character
790- rdr. peek_span = codemap:: mk_sp ( rdr. last_pos , rdr. pos ) ;
791830 let mut cs = ~"";
792831 char:: escape_default ( c, |c| cs. push_char ( c) ) ;
793- rdr. fatal ( fmt ! ( "unknown start of token: %s" , cs) ) ;
832+ fatal_span ( rdr, rdr. last_pos , rdr. pos ,
833+ fmt ! ( "unknown start of token: %s" , cs) ) ;
794834 }
795835 }
796836}
0 commit comments