@@ -770,10 +770,10 @@ impl<'a> Parser<'a> {
770
770
match self . token . uninterpolate ( ) . kind {
771
771
token:: Ident ( ..) => self . parse_dot_suffix ( base, lo) ,
772
772
token:: Literal ( token:: Lit { kind : token:: Integer , symbol, suffix } ) => {
773
- Ok ( self . parse_tuple_field_access_expr ( lo, base, symbol, suffix) )
773
+ Ok ( self . parse_tuple_field_access_expr ( lo, base, symbol, suffix, None ) )
774
774
}
775
- token:: Literal ( token:: Lit { kind : token:: Float , symbol, .. } ) => {
776
- self . recover_field_access_by_float_lit ( lo, base, symbol)
775
+ token:: Literal ( token:: Lit { kind : token:: Float , symbol, suffix } ) => {
776
+ Ok ( self . parse_tuple_field_access_expr_float ( lo, base, symbol, suffix ) )
777
777
}
778
778
_ => {
779
779
self . error_unexpected_after_dot ( ) ;
@@ -788,45 +788,84 @@ impl<'a> Parser<'a> {
788
788
self . struct_span_err ( self . token . span , & format ! ( "unexpected token: `{}`" , actual) ) . emit ( ) ;
789
789
}
790
790
791
- fn recover_field_access_by_float_lit (
791
+ // We need and identifier or integer, but the next token is a float.
792
+ // Break the float into components to extract the identifier or integer.
793
+ // FIXME: With current `TokenCursor` it's hard to break tokens into more than 2
794
+ // parts unless those parts are processed immediately. `TokenCursor` should either
795
+ // support pushing "future tokens" (would be also helpful to `break_and_eat`), or
796
+ // we should break everything including floats into more basic proc-macro style
797
+ // tokens in the lexer (probably preferable).
798
+ fn parse_tuple_field_access_expr_float (
792
799
& mut self ,
793
800
lo : Span ,
794
801
base : P < Expr > ,
795
- sym : Symbol ,
796
- ) -> PResult < ' a , P < Expr > > {
797
- self . bump ( ) ;
798
-
799
- let fstr = sym. as_str ( ) ;
800
- let msg = format ! ( "unexpected token: `{}`" , sym) ;
801
-
802
- let mut err = self . struct_span_err ( self . prev_token . span , & msg) ;
803
- err. span_label ( self . prev_token . span , "unexpected token" ) ;
804
-
805
- if fstr. chars ( ) . all ( |x| "0123456789." . contains ( x) ) {
806
- let float = match fstr. parse :: < f64 > ( ) {
807
- Ok ( f) => f,
808
- Err ( _) => {
809
- err. emit ( ) ;
810
- return Ok ( base) ;
802
+ float : Symbol ,
803
+ suffix : Option < Symbol > ,
804
+ ) -> P < Expr > {
805
+ #[ derive( Debug ) ]
806
+ enum FloatComponent {
807
+ IdentLike ( String ) ,
808
+ Punct ( char ) ,
809
+ }
810
+ use FloatComponent :: * ;
811
+
812
+ let mut components = Vec :: new ( ) ;
813
+ let mut ident_like = String :: new ( ) ;
814
+ for c in float. as_str ( ) . chars ( ) {
815
+ if c == '_' || c. is_ascii_alphanumeric ( ) {
816
+ ident_like. push ( c) ;
817
+ } else if matches ! ( c, '.' | '+' | '-' ) {
818
+ if !ident_like. is_empty ( ) {
819
+ components. push ( IdentLike ( mem:: take ( & mut ident_like) ) ) ;
811
820
}
812
- } ;
813
- let sugg = pprust:: to_string ( |s| {
814
- s. popen ( ) ;
815
- s. print_expr ( & base) ;
816
- s. s . word ( "." ) ;
817
- s. print_usize ( float. trunc ( ) as usize ) ;
818
- s. pclose ( ) ;
819
- s. s . word ( "." ) ;
820
- s. s . word ( fstr. splitn ( 2 , '.' ) . last ( ) . unwrap ( ) . to_string ( ) )
821
- } ) ;
822
- err. span_suggestion (
823
- lo. to ( self . prev_token . span ) ,
824
- "try parenthesizing the first index" ,
825
- sugg,
826
- Applicability :: MachineApplicable ,
827
- ) ;
821
+ components. push ( Punct ( c) ) ;
822
+ } else {
823
+ panic ! ( "unexpected character in a float token: {:?}" , c)
824
+ }
825
+ }
826
+ if !ident_like. is_empty ( ) {
827
+ components. push ( IdentLike ( ident_like) ) ;
828
+ }
829
+
830
+ // FIXME: Make the span more precise.
831
+ let span = self . token . span ;
832
+ match & * components {
833
+ // 1e2
834
+ [ IdentLike ( i) ] => {
835
+ self . parse_tuple_field_access_expr ( lo, base, Symbol :: intern ( & i) , suffix, None )
836
+ }
837
+ // 1.
838
+ [ IdentLike ( i) , Punct ( '.' ) ] => {
839
+ assert ! ( suffix. is_none( ) ) ;
840
+ let symbol = Symbol :: intern ( & i) ;
841
+ self . token = Token :: new ( token:: Ident ( symbol, false ) , span) ;
842
+ let next_token = Token :: new ( token:: Dot , span) ;
843
+ self . parse_tuple_field_access_expr ( lo, base, symbol, None , Some ( next_token) )
844
+ }
845
+ // 1.2 | 1.2e3
846
+ [ IdentLike ( i1) , Punct ( '.' ) , IdentLike ( i2) ] => {
847
+ let symbol1 = Symbol :: intern ( & i1) ;
848
+ self . token = Token :: new ( token:: Ident ( symbol1, false ) , span) ;
849
+ let next_token1 = Token :: new ( token:: Dot , span) ;
850
+ let base1 =
851
+ self . parse_tuple_field_access_expr ( lo, base, symbol1, None , Some ( next_token1) ) ;
852
+ let symbol2 = Symbol :: intern ( & i2) ;
853
+ let next_token2 = Token :: new ( token:: Ident ( symbol2, false ) , span) ;
854
+ self . bump_with ( next_token2) ; // `.`
855
+ self . parse_tuple_field_access_expr ( lo, base1, symbol2, suffix, None )
856
+ }
857
+ // 1e+ | 1e- (recovered)
858
+ [ IdentLike ( _) , Punct ( '+' | '-' ) ] |
859
+ // 1e+2 | 1e-2
860
+ [ IdentLike ( _) , Punct ( '+' | '-' ) , IdentLike ( _) ] |
861
+ // 1.2e+3 | 1.2e-3
862
+ [ IdentLike ( _) , Punct ( '.' ) , IdentLike ( _) , Punct ( '+' | '-' ) , IdentLike ( _) ] => {
863
+ // See the FIXME about `TokenCursor` above.
864
+ self . error_unexpected_after_dot ( ) ;
865
+ base
866
+ }
867
+ _ => panic ! ( "unexpected components in a float token: {:?}" , components) ,
828
868
}
829
- Err ( err)
830
869
}
831
870
832
871
fn parse_tuple_field_access_expr (
@@ -835,8 +874,12 @@ impl<'a> Parser<'a> {
835
874
base : P < Expr > ,
836
875
field : Symbol ,
837
876
suffix : Option < Symbol > ,
877
+ next_token : Option < Token > ,
838
878
) -> P < Expr > {
839
- self . bump ( ) ;
879
+ match next_token {
880
+ Some ( next_token) => self . bump_with ( next_token) ,
881
+ None => self . bump ( ) ,
882
+ }
840
883
let span = self . prev_token . span ;
841
884
let field = ExprKind :: Field ( base, Ident :: new ( field, span) ) ;
842
885
self . expect_no_suffix ( span, "a tuple index" , suffix) ;
0 commit comments