@@ -149,6 +149,46 @@ impl reader for TtReader {
149
149
fn dup ( @mut self ) -> @mut reader { dup_tt_reader ( self ) as @mut reader }
150
150
}
151
151
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
+
162
+ // report a lexical error spanning [`from_pos`, `to_pos`), appending an
163
+ // escaped character to the error message
164
+ fn fatal_span_char ( rdr : @mut StringReader ,
165
+ from_pos : BytePos ,
166
+ to_pos : BytePos ,
167
+ m : ~str ,
168
+ c : char )
169
+ -> ! {
170
+ let mut m = m;
171
+ m. push_str ( ": " ) ;
172
+ char:: escape_default ( c, |c| m. push_char ( c) ) ;
173
+ fatal_span ( rdr, from_pos, to_pos, m) ;
174
+ }
175
+
176
+ // report a lexical error spanning [`from_pos`, `to_pos`), appending the
177
+ // offending string to the error message
178
+ fn fatal_span_verbose ( rdr : @mut StringReader ,
179
+ from_pos : BytePos ,
180
+ to_pos : BytePos ,
181
+ m : ~str )
182
+ -> ! {
183
+ let mut m = m;
184
+ m. push_str ( ": " ) ;
185
+ let s = rdr. src . slice (
186
+ byte_offset ( rdr, from_pos) . to_uint ( ) ,
187
+ byte_offset ( rdr, to_pos) . to_uint ( ) ) ;
188
+ m. push_str ( s) ;
189
+ fatal_span ( rdr, from_pos, to_pos, m) ;
190
+ }
191
+
152
192
// EFFECT: advance peek_tok and peek_span to refer to the next token.
153
193
// EFFECT: update the interner, maybe.
154
194
fn string_advance_token ( r : @mut StringReader ) {
@@ -327,7 +367,8 @@ fn consume_block_comment(rdr: @mut StringReader)
327
367
bump ( rdr) ;
328
368
}
329
369
if is_eof ( rdr) {
330
- rdr. fatal ( ~"unterminated block doc-comment") ;
370
+ fatal_span ( rdr, start_bpos, rdr. last_pos ,
371
+ ~"unterminated block doc-comment") ;
331
372
} else {
332
373
bump ( rdr) ;
333
374
bump ( rdr) ;
@@ -344,8 +385,12 @@ fn consume_block_comment(rdr: @mut StringReader)
344
385
}
345
386
}
346
387
} else {
388
+ let start_bpos = rdr. last_pos - BytePos ( 2 u) ;
347
389
loop {
348
- if is_eof ( rdr) { rdr. fatal ( ~"unterminated block comment") ; }
390
+ if is_eof ( rdr) {
391
+ fatal_span ( rdr, start_bpos, rdr. last_pos ,
392
+ ~"unterminated block comment") ;
393
+ }
349
394
if rdr. curr == '*' && nextch ( rdr) == '/' {
350
395
bump ( rdr) ;
351
396
bump ( rdr) ;
@@ -361,7 +406,7 @@ fn consume_block_comment(rdr: @mut StringReader)
361
406
if res. is_some ( ) { res } else { consume_whitespace_and_comments ( rdr) }
362
407
}
363
408
364
- fn scan_exponent ( rdr : @mut StringReader ) -> Option < ~str > {
409
+ fn scan_exponent ( rdr : @mut StringReader , start_bpos : BytePos ) -> Option < ~str > {
365
410
let mut c = rdr. curr ;
366
411
let mut rslt = ~"";
367
412
if c == 'e' || c == 'E' {
@@ -375,7 +420,10 @@ fn scan_exponent(rdr: @mut StringReader) -> Option<~str> {
375
420
let exponent = scan_digits ( rdr, 10 u) ;
376
421
if exponent. len ( ) > 0 u {
377
422
return Some ( rslt + exponent) ;
378
- } else { rdr. fatal ( ~"scan_exponent: bad fp literal") ; }
423
+ } else {
424
+ fatal_span ( rdr, start_bpos, rdr. last_pos ,
425
+ ~"scan_exponent: bad fp literal") ;
426
+ }
379
427
} else { return None :: < ~str > ; }
380
428
}
381
429
@@ -399,6 +447,7 @@ fn scan_number(c: char, rdr: @mut StringReader) -> token::Token {
399
447
let mut base = 10 u;
400
448
let mut c = c;
401
449
let mut n = nextch ( rdr) ;
450
+ let start_bpos = rdr. last_pos ;
402
451
if c == '0' && n == 'x' {
403
452
bump ( rdr) ;
404
453
bump ( rdr) ;
@@ -442,11 +491,13 @@ fn scan_number(c: char, rdr: @mut StringReader) -> token::Token {
442
491
else { either:: Right ( ast:: ty_u64) } ;
443
492
}
444
493
if num_str. len ( ) == 0 u {
445
- rdr. fatal ( ~"no valid digits found for number") ;
494
+ fatal_span ( rdr, start_bpos, rdr. last_pos ,
495
+ ~"no valid digits found for number") ;
446
496
}
447
497
let parsed = match from_str_radix :: < u64 > ( num_str, base as uint ) {
448
498
Some ( p) => p,
449
- None => rdr. fatal ( ~"int literal is too large")
499
+ None => fatal_span ( rdr, start_bpos, rdr. last_pos ,
500
+ ~"int literal is too large")
450
501
} ;
451
502
452
503
match tp {
@@ -464,12 +515,14 @@ fn scan_number(c: char, rdr: @mut StringReader) -> token::Token {
464
515
}
465
516
if is_float {
466
517
match base {
467
- 16 u => rdr. fatal ( ~"hexadecimal float literal is not supported") ,
468
- 2 u => rdr. fatal ( ~"binary float literal is not supported") ,
518
+ 16 u => fatal_span ( rdr, start_bpos, rdr. last_pos ,
519
+ ~"hexadecimal float literal is not supported") ,
520
+ 2 u => fatal_span ( rdr, start_bpos, rdr. last_pos ,
521
+ ~"binary float literal is not supported") ,
469
522
_ => ( )
470
523
}
471
524
}
472
- match scan_exponent ( rdr) {
525
+ match scan_exponent ( rdr, start_bpos ) {
473
526
Some ( ref s) => {
474
527
is_float = true ;
475
528
num_str. push_str ( * s) ;
@@ -507,11 +560,13 @@ fn scan_number(c: char, rdr: @mut StringReader) -> token::Token {
507
560
return token:: LIT_FLOAT_UNSUFFIXED ( str_to_ident ( num_str) ) ;
508
561
} else {
509
562
if num_str. len ( ) == 0 u {
510
- rdr. fatal ( ~"no valid digits found for number") ;
563
+ fatal_span ( rdr, start_bpos, rdr. last_pos ,
564
+ ~"no valid digits found for number") ;
511
565
}
512
566
let parsed = match from_str_radix :: < u64 > ( num_str, base as uint ) {
513
567
Some ( p) => p,
514
- None => rdr. fatal ( ~"int literal is too large")
568
+ None => fatal_span ( rdr, start_bpos, rdr. last_pos ,
569
+ ~"int literal is too large")
515
570
} ;
516
571
517
572
debug ! ( "lexing %s as an unsuffixed integer literal" ,
@@ -523,19 +578,23 @@ fn scan_number(c: char, rdr: @mut StringReader) -> token::Token {
523
578
fn scan_numeric_escape ( rdr : @mut StringReader , n_hex_digits : uint ) -> char {
524
579
let mut accum_int = 0 ;
525
580
let mut i = n_hex_digits;
581
+ let start_bpos = rdr. last_pos ;
526
582
while i != 0 u {
527
583
let n = rdr. curr ;
528
- bump ( rdr) ;
529
584
if !is_hex_digit ( n) {
530
- rdr. fatal ( fmt ! ( "illegal numeric character escape: %d" , n as int) ) ;
585
+ fatal_span_char ( rdr, rdr. last_pos , rdr. pos ,
586
+ ~"illegal character in numeric character escape",
587
+ n) ;
531
588
}
589
+ bump ( rdr) ;
532
590
accum_int *= 16 ;
533
591
accum_int += hex_digit_val ( n) ;
534
592
i -= 1 u;
535
593
}
536
594
match char:: from_u32 ( accum_int as u32 ) {
537
595
Some ( x) => x,
538
- None => rdr. fatal ( fmt ! ( "illegal numeric character escape" ) )
596
+ None => fatal_span ( rdr, start_bpos, rdr. last_pos ,
597
+ ~"illegal numeric character escape")
539
598
}
540
599
}
541
600
@@ -691,6 +750,7 @@ fn next_token_inner(rdr: @mut StringReader) -> token::Token {
691
750
if c2 == '\\' {
692
751
// '\X' for some X must be a character constant:
693
752
let escaped = rdr. curr ;
753
+ let escaped_pos = rdr. last_pos ;
694
754
bump ( rdr) ;
695
755
match escaped {
696
756
'n' => { c2 = '\n' ; }
@@ -704,32 +764,39 @@ fn next_token_inner(rdr: @mut StringReader) -> token::Token {
704
764
'u' => { c2 = scan_numeric_escape ( rdr, 4 u) ; }
705
765
'U' => { c2 = scan_numeric_escape ( rdr, 8 u) ; }
706
766
c2 => {
707
- rdr. fatal ( fmt ! ( "unknown character escape: %d" , c2 as int) ) ;
767
+ fatal_span_char ( rdr, escaped_pos, rdr. last_pos ,
768
+ ~"unknown character escape", c2) ;
708
769
}
709
770
}
710
771
}
711
772
if rdr. curr != '\'' {
712
- rdr. fatal ( ~"unterminated character constant") ;
773
+ fatal_span_verbose ( rdr,
774
+ // Byte offsetting here is okay because the
775
+ // character before position `start` is an
776
+ // ascii single quote.
777
+ start - BytePos ( 1 u) ,
778
+ rdr. last_pos ,
779
+ ~"unterminated character constant") ;
713
780
}
714
781
bump ( rdr) ; // advance curr past token
715
782
return token:: LIT_CHAR ( c2 as u32 ) ;
716
783
}
717
784
'"' => {
718
785
let mut accum_str = ~"";
719
- let n = rdr. last_pos ;
786
+ let start_bpos = rdr. last_pos ;
720
787
bump ( rdr) ;
721
788
while rdr. curr != '"' {
722
789
if is_eof ( rdr) {
723
- do with_str_from ( rdr, n) |s| {
724
- rdr. fatal ( fmt ! ( "unterminated double quote string: %s" , s) ) ;
725
- }
790
+ fatal_span ( rdr, start_bpos, rdr. last_pos ,
791
+ ~"unterminated double quote string") ;
726
792
}
727
793
728
794
let ch = rdr. curr ;
729
795
bump ( rdr) ;
730
796
match ch {
731
797
'\\' => {
732
798
let escaped = rdr. curr ;
799
+ let escaped_pos = rdr. last_pos ;
733
800
bump ( rdr) ;
734
801
match escaped {
735
802
'n' => accum_str. push_char ( '\n' ) ,
@@ -750,7 +817,8 @@ fn next_token_inner(rdr: @mut StringReader) -> token::Token {
750
817
accum_str. push_char ( scan_numeric_escape ( rdr, 8 u) ) ;
751
818
}
752
819
c2 => {
753
- rdr. fatal ( fmt ! ( "unknown string escape: %d" , c2 as int) ) ;
820
+ fatal_span_char ( rdr, escaped_pos, rdr. last_pos ,
821
+ ~"unknown string escape", c2) ;
754
822
}
755
823
}
756
824
}
@@ -786,11 +854,8 @@ fn next_token_inner(rdr: @mut StringReader) -> token::Token {
786
854
'^' => { return binop ( rdr, token:: CARET ) ; }
787
855
'%' => { return binop ( rdr, token:: PERCENT ) ; }
788
856
c => {
789
- // So the error span points to the unrecognized character
790
- rdr. peek_span = codemap:: mk_sp ( rdr. last_pos , rdr. pos ) ;
791
- let mut cs = ~"";
792
- char:: escape_default ( c, |c| cs. push_char ( c) ) ;
793
- rdr. fatal ( fmt ! ( "unknown start of token: %s" , cs) ) ;
857
+ fatal_span_char ( rdr, rdr. last_pos , rdr. pos ,
858
+ ~"unknown start of token", c) ;
794
859
}
795
860
}
796
861
}
0 commit comments