7
7
use std:: ops:: Range ;
8
8
use std:: cell:: Cell ;
9
9
use std:: char;
10
- use std:: num;
10
+ use std:: num:: { self , Float } ;
11
11
use std:: ascii:: AsciiExt ;
12
12
use std:: borrow:: { Cow , ToOwned } ;
13
13
use std:: borrow:: Cow :: { Owned , Borrowed } ;
14
+ use std:: i32;
14
15
15
16
use self :: Token :: * ;
16
17
@@ -638,32 +639,51 @@ fn consume_name<'a>(tokenizer: &mut Tokenizer<'a>) -> Cow<'a, str> {
638
639
}
639
640
640
641
641
- fn consume_digits ( tokenizer : & mut Tokenizer ) {
642
- while !tokenizer. is_eof ( ) {
643
- match tokenizer. next_char ( ) {
644
- '0' ...'9' => tokenizer. advance ( 1 ) ,
645
- _ => break
646
- }
647
- }
648
- }
649
-
650
-
651
642
fn consume_numeric < ' a > ( tokenizer : & mut Tokenizer < ' a > ) -> Token < ' a > {
652
643
// Parse [+-]?\d*(\.\d+)?([eE][+-]?\d+)?
653
644
// But this is always called so that there is at least one digit in \d*(\.\d+)?
654
- let start_pos = tokenizer. position ( ) ;
655
- let mut is_integer = true ;
656
- let has_sign = matches ! ( tokenizer. next_char( ) , '-' | '+' ) ;
645
+
646
+ // Do all the math in f64 so that large numbers overflow to +/-inf
647
+ // and i32::{MIN, MAX} are within range.
648
+
649
+ let ( has_sign, sign) = match tokenizer. next_char ( ) {
650
+ '-' => ( true , -1. ) ,
651
+ '+' => ( true , 1. ) ,
652
+ _ => ( false , 1. ) ,
653
+ } ;
657
654
if has_sign {
658
655
tokenizer. advance ( 1 ) ;
659
656
}
660
- consume_digits ( tokenizer) ;
657
+
658
+ let mut integral_part: f64 = 0. ;
659
+ while let Some ( digit) = tokenizer. next_char ( ) . to_digit ( 10 ) {
660
+ integral_part = integral_part * 10. + digit as f64 ;
661
+ tokenizer. advance ( 1 ) ;
662
+ if tokenizer. is_eof ( ) {
663
+ break
664
+ }
665
+ }
666
+
667
+ let mut is_integer = true ;
668
+
669
+ let mut fractional_part: f64 = 0. ;
661
670
if tokenizer. has_at_least ( 1 ) && tokenizer. next_char ( ) == '.'
662
671
&& matches ! ( tokenizer. char_at( 1 ) , '0' ...'9' ) {
663
672
is_integer = false ;
664
- tokenizer. advance ( 2 ) ; // '.' and first digit
665
- consume_digits ( tokenizer) ;
673
+ tokenizer. advance ( 1 ) ; // '.' and first digit
674
+ let mut divisor = 10. ;
675
+ while let Some ( digit) = tokenizer. next_char ( ) . to_digit ( 10 ) {
676
+ fractional_part += digit as f64 / divisor;
677
+ divisor *= 10. ;
678
+ tokenizer. advance ( 1 ) ;
679
+ if tokenizer. is_eof ( ) {
680
+ break
681
+ }
682
+ }
666
683
}
684
+
685
+ let mut value = sign * ( integral_part + fractional_part) ;
686
+
667
687
if (
668
688
tokenizer. has_at_least ( 1 )
669
689
&& matches ! ( tokenizer. next_char( ) , 'e' | 'E' )
@@ -675,37 +695,57 @@ fn consume_numeric<'a>(tokenizer: &mut Tokenizer<'a>) -> Token<'a> {
675
695
&& matches ! ( tokenizer. char_at( 2 ) , '0' ...'9' )
676
696
) {
677
697
is_integer = false ;
678
- tokenizer. advance ( 2 ) ; // 'e' or 'E', and sign or first digit
679
- consume_digits ( tokenizer) ;
680
- }
681
- let ( value, int_value) = {
682
- let mut repr = tokenizer. slice_from ( start_pos) ;
683
- // Remove any + sign as int::parse() does not parse them.
684
- if repr. starts_with ( "+" ) {
685
- repr = & repr[ 1 ..]
698
+ tokenizer. advance ( 1 ) ;
699
+ let ( has_sign, sign) = match tokenizer. next_char ( ) {
700
+ '-' => ( true , -1. ) ,
701
+ '+' => ( true , 1. ) ,
702
+ _ => ( false , 1. ) ,
703
+ } ;
704
+ if has_sign {
705
+ tokenizer. advance ( 1 ) ;
706
+ }
707
+ let mut exponent: f64 = 0. ;
708
+ while let Some ( digit) = tokenizer. next_char ( ) . to_digit ( 10 ) {
709
+ exponent = exponent * 10. + digit as f64 ;
710
+ tokenizer. advance ( 1 ) ;
711
+ if tokenizer. is_eof ( ) {
712
+ break
713
+ }
686
714
}
687
- // TODO: handle overflow
688
- ( repr. parse :: < f32 > ( ) . unwrap ( ) , if is_integer {
689
- Some ( repr. parse :: < i32 > ( ) . unwrap ( ) )
715
+ value *= Float :: powf ( 10. , sign * exponent) ;
716
+ }
717
+
718
+ let int_value = if is_integer {
719
+ Some ( if value >= i32:: MAX as f64 {
720
+ i32:: MAX
721
+ } else if value <= i32:: MIN as f64 {
722
+ i32:: MIN
690
723
} else {
691
- None
724
+ value as i32
692
725
} )
726
+ } else {
727
+ None
693
728
} ;
729
+
694
730
if !tokenizer. is_eof ( ) && tokenizer. next_char ( ) == '%' {
695
731
tokenizer. advance ( 1 ) ;
696
732
return Percentage ( PercentageValue {
697
- unit_value : value / 100. ,
733
+ unit_value : value as f32 / 100. ,
698
734
int_value : int_value,
699
735
has_sign : has_sign,
700
736
} )
701
737
}
702
738
let value = NumericValue {
703
- value : value,
739
+ value : value as f32 ,
704
740
int_value : int_value,
705
741
has_sign : has_sign,
706
742
} ;
707
- if is_ident_start ( tokenizer) { Dimension ( value, consume_name ( tokenizer) ) }
708
- else { Number ( value) }
743
+ if is_ident_start ( tokenizer) {
744
+ Dimension ( value, consume_name ( tokenizer) )
745
+ }
746
+ else {
747
+ Number ( value)
748
+ }
709
749
}
710
750
711
751
0 commit comments