@@ -770,10 +770,10 @@ impl<'a> Parser<'a> {
770770 match self . token . uninterpolate ( ) . kind {
771771 token:: Ident ( ..) => self . parse_dot_suffix ( base, lo) ,
772772 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 ) )
774774 }
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 ) )
777777 }
778778 _ => {
779779 self . error_unexpected_after_dot ( ) ;
@@ -788,45 +788,84 @@ impl<'a> Parser<'a> {
788788 self . struct_span_err ( self . token . span , & format ! ( "unexpected token: `{}`" , actual) ) . emit ( ) ;
789789 }
790790
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 (
792799 & mut self ,
793800 lo : Span ,
794801 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) ) ) ;
811820 }
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) ,
828868 }
829- Err ( err)
830869 }
831870
832871 fn parse_tuple_field_access_expr (
@@ -835,8 +874,12 @@ impl<'a> Parser<'a> {
835874 base : P < Expr > ,
836875 field : Symbol ,
837876 suffix : Option < Symbol > ,
877+ next_token : Option < Token > ,
838878 ) -> P < Expr > {
839- self . bump ( ) ;
879+ match next_token {
880+ Some ( next_token) => self . bump_with ( next_token) ,
881+ None => self . bump ( ) ,
882+ }
840883 let span = self . prev_token . span ;
841884 let field = ExprKind :: Field ( base, Ident :: new ( field, span) ) ;
842885 self . expect_no_suffix ( span, "a tuple index" , suffix) ;
0 commit comments