@@ -1409,18 +1409,46 @@ fn parse_abstract_literal(
14091409 let ( integer, mut int_text) = base_result?;
14101410 base_text. append ( & mut int_text) ;
14111411 base_text. push ( b'#' ) ;
1412- if ( 2 ..=16 ) . contains ( & base) {
1413- Ok ( (
1414- AbstractLiteral ,
1415- Value :: AbstractLiteral ( base_text, ast:: AbstractLiteral :: Integer ( integer) ) ,
1416- ) )
1417- } else {
1418- Err ( TokenError :: range (
1412+ if !( 2 ..=16 ) . contains ( & base) {
1413+ return Err ( TokenError :: range (
14191414 state. pos ( ) ,
14201415 pos_after_initial,
14211416 format ! ( "Base must be at least 2 and at most 16, got {base}" ) ,
1422- ) )
1417+ ) ) ;
14231418 }
1419+ // Optional exponent: value is base ** exp, per LRM 15.5.3
1420+ let value = if matches ! ( reader. peek( ) ?, Some ( b'e' | b'E' ) ) {
1421+ base_text. push ( reader. peek ( ) ?. unwrap ( ) ) ;
1422+ reader. skip ( ) ;
1423+ let ( exp, mut exp_text) = parse_exponent ( reader) ?;
1424+ base_text. append ( & mut exp_text) ;
1425+ if exp < 0 {
1426+ return Err ( TokenError :: range (
1427+ state. pos ( ) ,
1428+ reader. pos ( ) ,
1429+ "Integer literals may not have negative exponent" ,
1430+ ) ) ;
1431+ }
1432+ match base
1433+ . checked_pow ( exp as u32 )
1434+ . and_then ( |x| x. checked_mul ( integer) )
1435+ {
1436+ Some ( v) => v,
1437+ None => {
1438+ return Err ( TokenError :: range (
1439+ state. pos ( ) ,
1440+ reader. pos ( ) ,
1441+ "Integer too large for 64-bit unsigned" ,
1442+ ) ) ;
1443+ }
1444+ }
1445+ } else {
1446+ integer
1447+ } ;
1448+ Ok ( (
1449+ AbstractLiteral ,
1450+ Value :: AbstractLiteral ( base_text, ast:: AbstractLiteral :: Integer ( value) ) ,
1451+ ) )
14241452 } else {
14251453 Err ( TokenError :: range (
14261454 state. pos ( ) ,
@@ -2695,6 +2723,64 @@ my_other_ident",
26952723 ) ;
26962724 }
26972725
2726+ #[ test]
2727+ fn tokenize_based_integer_with_exponent ( ) {
2728+ // LRM 15.5.3: exponent is power of base
2729+ assert_eq ! (
2730+ kind_value_tokenize( "16#E#E1" ) ,
2731+ vec![ (
2732+ AbstractLiteral ,
2733+ Value :: AbstractLiteral (
2734+ Latin1String :: new( b"16#E#E1" ) ,
2735+ ast:: AbstractLiteral :: Integer ( 224 )
2736+ )
2737+ ) , ]
2738+ ) ;
2739+ assert_eq ! (
2740+ kind_value_tokenize( "2#1#e4" ) ,
2741+ vec![ (
2742+ AbstractLiteral ,
2743+ Value :: AbstractLiteral (
2744+ Latin1String :: new( b"2#1#e4" ) ,
2745+ ast:: AbstractLiteral :: Integer ( 16 )
2746+ )
2747+ ) , ]
2748+ ) ;
2749+ assert_eq ! (
2750+ kind_value_tokenize( "10#5#E+2" ) ,
2751+ vec![ (
2752+ AbstractLiteral ,
2753+ Value :: AbstractLiteral (
2754+ Latin1String :: new( b"10#5#E+2" ) ,
2755+ ast:: AbstractLiteral :: Integer ( 500 )
2756+ )
2757+ ) , ]
2758+ ) ;
2759+ assert_eq ! (
2760+ kind_value_tokenize( "16#FF#E0" ) ,
2761+ vec![ (
2762+ AbstractLiteral ,
2763+ Value :: AbstractLiteral (
2764+ Latin1String :: new( b"16#FF#E0" ) ,
2765+ ast:: AbstractLiteral :: Integer ( 255 )
2766+ )
2767+ ) , ]
2768+ ) ;
2769+ }
2770+
2771+ #[ test]
2772+ fn tokenize_based_integer_negative_exponent ( ) {
2773+ let code = Code :: new ( "2#1#e-1" ) ;
2774+ let ( tokens, _) = code. tokenize_result ( ) ;
2775+ assert_eq ! (
2776+ tokens,
2777+ vec![ Err ( Diagnostic :: syntax_error(
2778+ code. pos( ) ,
2779+ "Integer literals may not have negative exponent" ,
2780+ ) ) ]
2781+ ) ;
2782+ }
2783+
26982784 #[ test]
26992785 fn tokenize_illegal_integer ( ) {
27002786 let code = Code :: new ( "100k" ) ;
0 commit comments