@@ -165,6 +165,11 @@ format_error({illegal,Type}) ->
165
165
lists :flatten (io_lib :fwrite (" illegal ~w " , [Type ]));
166
166
format_error ({base ,Base }) ->
167
167
lists :flatten (io_lib :fwrite (" illegal base '~w '" , [Base ]));
168
+ format_error ({float_base ,Base }) ->
169
+ lists :flatten (io_lib :fwrite (" illegal base '~w ' - only 10, 16 or 2 are allowed for floating point literals" , [Base ]));
170
+ format_error ({exponent ,Base }) ->
171
+ C = if Base =:= 10 -> $e ; true -> $p end ,
172
+ lists :flatten (io_lib :fwrite (" only '~c ' allowed as exponent character in base ~w " , [C , Base ]));
168
173
format_error (indentation ) ->
169
174
" bad indentation in triple-quoted string" ;
170
175
format_error (white_space ) ->
@@ -1820,7 +1825,7 @@ scan_number([$#|Cs]=Cs0, St, Line, Col, Toks, Ncs0, Us) ->
1820
1825
try list_to_integer (remove_digit_separators (Ncs , Us )) of
1821
1826
B when is_integer (B ), 2 =< B , B =< 1 + $Z - $A + 10 ->
1822
1827
Bcs = Ncs ++ [$# ],
1823
- scan_based_int (Cs , St , Line , Col , Toks , B , [], Bcs , no_underscore );
1828
+ scan_based_num (Cs , St , Line , Col , Toks , B , [], Bcs , no_underscore );
1824
1829
B when is_integer (B ) ->
1825
1830
Len = length (Ncs ),
1826
1831
scan_error ({base ,B }, Line , Col , Line , incr_column (Col , Len ), Cs0 )
@@ -1857,29 +1862,40 @@ remove_digit_separators(Number, with_underscore) ->
1857
1862
orelse (C >= $A andalso B > 10 andalso C < $A + B - 10 )
1858
1863
orelse (C >= $a andalso B > 10 andalso C < $a + B - 10 )))).
1859
1864
1860
- scan_based_int (Cs , # erl_scan {}= St , Line , Col , Toks , {B ,NCs ,BCs ,Us })
1865
+ scan_based_num (Cs , # erl_scan {}= St , Line , Col , Toks , {B ,NCs ,BCs ,Us })
1861
1866
when is_integer (B ), 2 =< B , B =< 1 + $Z - $A + 10 ->
1862
- scan_based_int (Cs , St , Line , Col , Toks , B , NCs , BCs , Us ).
1867
+ scan_based_num (Cs , St , Line , Col , Toks , B , NCs , BCs , Us ).
1863
1868
1864
- scan_based_int ([C |Cs ], St , Line , Col , Toks , B , Ncs , Bcs , Us ) when
1869
+ scan_based_num ([C |Cs ], St , Line , Col , Toks , B , Ncs , Bcs , Us ) when
1865
1870
? BASED_DIGIT (C , B ) ->
1866
- scan_based_int (Cs , St , Line , Col , Toks , B , [C |Ncs ], Bcs , Us );
1867
- scan_based_int ([$_ ,Next |Cs ], St , Line , Col , Toks , B , [Prev |_ ]= Ncs , Bcs , _Us )
1871
+ scan_based_num (Cs , St , Line , Col , Toks , B , [C |Ncs ], Bcs , Us );
1872
+ scan_based_num ([$_ ,Next |Cs ], St , Line , Col , Toks , B , [Prev |_ ]= Ncs , Bcs , _Us )
1868
1873
when ? BASED_DIGIT (Next , B ) andalso ? BASED_DIGIT (Prev , B ) ->
1869
- scan_based_int (Cs , St , Line , Col , Toks , B , [Next ,$_ |Ncs ], Bcs ,
1874
+ scan_based_num (Cs , St , Line , Col , Toks , B , [Next ,$_ |Ncs ], Bcs ,
1870
1875
with_underscore );
1871
- scan_based_int ([$_ ]= Cs , St , Line , Col , Toks , B , NCs , BCs , Us ) ->
1872
- {more ,{Cs ,St ,Col ,Toks ,Line ,{B ,NCs ,BCs ,Us },fun scan_based_int /6 }};
1873
- scan_based_int ([C |_ ]= Cs0 , _St , Line , Col , _Toks , _B , Ncs , Bcs , _Us ) when ? NAMECHAR (C ) ->
1876
+ scan_based_num ([$_ ]= Cs , St , Line , Col , Toks , B , NCs , BCs , Us ) ->
1877
+ {more ,{Cs ,St ,Col ,Toks ,Line ,{B ,NCs ,BCs ,Us },fun scan_based_num /6 }};
1878
+ scan_based_num ([$. ,C |Cs ], St , Line , Col , Toks , B , Ncs , BCs , Us ) when ? BASED_DIGIT (C , B ) ->
1879
+ if B =:= 10 ; B =:= 2 ; B =:= 16 ->
1880
+ scan_based_fraction (Cs , St , Line , Col , Toks , B , [C ,$. |Ncs ], BCs , Us );
1881
+ true ->
1882
+ Ncol = incr_column (Col , length (Ncs ) + length (BCs )),
1883
+ scan_error ({float_base , B }, Line , Col , Line , Ncol , Cs )
1884
+ end ;
1885
+ scan_based_num ([$. ,C |_ ]= Cs0 , _St , Line , Col , _Toks , _B , Ncs , Bcs , _Us ) when ? NAMECHAR (C ) ->
1886
+ scan_error ({illegal ,float }, Line , Col , Line , incr_column (Col , length (Ncs ) + length (Bcs )), Cs0 );
1887
+ scan_based_num ([$. ]= Cs , St , Line , Col , Toks , B , Ncs , BCs , Us ) ->
1888
+ {more ,{Cs ,St ,Col ,Toks ,Line ,{B ,Ncs ,BCs ,Us },fun scan_based_num /6 }};
1889
+ scan_based_num ([C |_ ]= Cs0 , _St , Line , Col , _Toks , _B , Ncs , Bcs , _Us ) when ? NAMECHAR (C ) ->
1874
1890
scan_error ({illegal ,integer }, Line , Col , Line , incr_column (Col , length (Ncs ) + length (Bcs )), Cs0 );
1875
- scan_based_int ([]= Cs , St , Line , Col , Toks , B , NCs , BCs , Us ) ->
1876
- {more ,{Cs ,St ,Col ,Toks ,Line ,{B ,NCs ,BCs ,Us },fun scan_based_int /6 }};
1877
- scan_based_int (Cs , _St , Line , Col , _Toks , _B , [], Bcs , _Us ) ->
1891
+ scan_based_num ([]= Cs , St , Line , Col , Toks , B , NCs , BCs , Us ) ->
1892
+ {more ,{Cs ,St ,Col ,Toks ,Line ,{B ,NCs ,BCs ,Us },fun scan_based_num /6 }};
1893
+ scan_based_num (Cs , _St , Line , Col , _Toks , _B , [], Bcs , _Us ) ->
1878
1894
% % No actual digits following the base.
1879
1895
Len = length (Bcs ),
1880
1896
Ncol = incr_column (Col , Len ),
1881
1897
scan_error ({illegal ,integer }, Line , Col , Line , Ncol , Cs );
1882
- scan_based_int (Cs , St , Line , Col , Toks , B , Ncs0 , [_ |_ ]= Bcs , Us ) ->
1898
+ scan_based_num (Cs , St , Line , Col , Toks , B , Ncs0 , [_ |_ ]= Bcs , Us ) ->
1883
1899
Ncs = lists :reverse (Ncs0 ),
1884
1900
try list_to_integer (remove_digit_separators (Ncs , Us ), B ) of
1885
1901
N ->
@@ -1892,6 +1908,93 @@ scan_based_int(Cs, St, Line, Col, Toks, B, Ncs0, [_|_]=Bcs, Us) ->
1892
1908
scan_error ({illegal ,integer }, Line , Col , Line , Ncol , Cs )
1893
1909
end .
1894
1910
1911
+ scan_based_fraction (Cs , # erl_scan {}= St , Line , Col , Toks , {B ,Ncs ,BCs ,Us }) ->
1912
+ scan_based_fraction (Cs , St , Line , Col , Toks , B , Ncs , BCs , Us ).
1913
+
1914
+ scan_based_fraction ([C |Cs ], St , Line , Col , Toks , B , Ncs , BCs , Us ) when ? BASED_DIGIT (C , B ) ->
1915
+ scan_based_fraction (Cs , St , Line , Col , Toks , B , [C |Ncs ], BCs , Us );
1916
+ scan_based_fraction ([$_ ,Next |Cs ], St , Line , Col , Toks , B , [Prev |_ ]= Ncs , BCs , _Us ) when
1917
+ ? BASED_DIGIT (Next , B ) andalso ? BASED_DIGIT (Prev , B ) ->
1918
+ scan_based_fraction (Cs , St , Line , Col , Toks , B , [Next ,$_ |Ncs ], BCs , with_underscore );
1919
+ scan_based_fraction ([$_ ]= Cs , St , Line , Col , Toks , B , Ncs , BCs , Us ) ->
1920
+ {more ,{Cs ,St ,Col ,Toks ,Line ,{B ,Ncs ,BCs ,Us },fun scan_based_fraction /6 }};
1921
+ scan_based_fraction ([E |Cs ], St , Line , Col , Toks , B , Ncs , BCs , Us ) when E =:= $e ; E =:= $E ->
1922
+ if B =:= 10 ->
1923
+ scan_based_exponent_sign (Cs , St , Line , Col , Toks , B , Ncs , BCs , [E ], Us );
1924
+ true ->
1925
+ Ncol = incr_column (Col , length (Ncs )+ length (BCs )),
1926
+ scan_error ({exponent ,B }, Line , Col , Line , Ncol , Cs )
1927
+ end ;
1928
+ scan_based_fraction ([E |Cs ], St , Line , Col , Toks , B , Ncs , BCs , Us ) when E =:= $p ; E =:= $P ->
1929
+ if B =/= 10 ->
1930
+ scan_based_exponent_sign (Cs , St , Line , Col , Toks , B , Ncs , BCs , [E ], Us );
1931
+ true ->
1932
+ Ncol = incr_column (Col , length (Ncs )+ length (BCs )),
1933
+ scan_error ({exponent ,B }, Line , Col , Line , Ncol , Cs )
1934
+ end ;
1935
+ scan_based_fraction ([C |_ ]= Cs0 , _St , Line , Col , _Toks , _B , Ncs , BCs , _Us ) when ? NAMECHAR (C ) ->
1936
+ scan_error ({illegal ,float }, Line , Col , Line , incr_column (Col , length (Ncs ) + length (BCs )), Cs0 );
1937
+ scan_based_fraction ([]= Cs , St , Line , Col , Toks , B , Ncs , BCs , Us ) ->
1938
+ {more ,{Cs ,St ,Col ,Toks ,Line ,{B ,Ncs ,BCs ,Us },fun scan_based_fraction /6 }};
1939
+ scan_based_fraction (Cs , St , Line , Col , Toks , B , Ncs , BCs , Us ) ->
1940
+ based_float_end (Cs , St , Line , Col , Toks , B , Ncs , BCs , [], Us ).
1941
+
1942
+ scan_based_exponent_sign (Cs , # erl_scan {}= St , Line , Col , Toks , {B ,Ncs ,BCs ,ECs ,Us }) ->
1943
+ scan_based_exponent_sign (Cs , St , Line , Col , Toks , B , Ncs , BCs , ECs , Us ).
1944
+
1945
+ scan_based_exponent_sign ([C |Cs ], St , Line , Col , Toks , B , Ncs , BCs , ECs , Us ) when
1946
+ C =:= $+ ; C =:= $- ->
1947
+ scan_based_exponent (Cs , St , Line , Col , Toks , B , Ncs , BCs , [C |ECs ], Us );
1948
+ scan_based_exponent_sign ([]= Cs , St , Line , Col , Toks , B , Ncs , BCs , ECs , Us ) ->
1949
+ {more ,{Cs ,St ,Col ,Toks ,Line ,{B ,Ncs ,BCs , ECs ,Us },fun scan_based_exponent_sign /6 }};
1950
+ scan_based_exponent_sign (Cs , St , Line , Col , Toks , B , Ncs , BCs , ECs , Us ) ->
1951
+ scan_based_exponent (Cs , St , Line , Col , Toks , B , Ncs , BCs , ECs , Us ).
1952
+
1953
+ scan_based_exponent (Cs , # erl_scan {}= St , Line , Col , Toks , {B ,Ncs ,BCs ,ECs ,Us }) ->
1954
+ scan_based_exponent (Cs , St , Line , Col , Toks , B , Ncs , BCs , ECs , Us ).
1955
+
1956
+ scan_based_exponent ([C |Cs ], St , Line , Col , Toks , B , Ncs , BCs , ECs , Us ) when ? DIGIT (C ) ->
1957
+ scan_based_exponent (Cs , St , Line , Col , Toks , B , Ncs , BCs , [C |ECs ], Us );
1958
+ scan_based_exponent ([$_ ,Next |Cs ], St , Line , Col , Toks , B , Ncs , BCs , [Prev |_ ]= ECs , _ ) when
1959
+ ? DIGIT (Next ) andalso ? DIGIT (Prev ) ->
1960
+ scan_based_exponent (Cs , St , Line , Col , Toks , B , Ncs , BCs , [Next ,$_ |ECs ], with_underscore );
1961
+ scan_based_exponent ([$_ ]= Cs , St , Line , Col , Toks , B , Ncs , BCs , ECs , Us ) ->
1962
+ {more ,{Cs ,St ,Col ,Toks ,Line ,{B ,Ncs ,BCs ,ECs ,Us },fun scan_based_exponent /6 }};
1963
+ scan_based_exponent ([]= Cs , St , Line , Col , Toks , B , Ncs , BCs , ECs , Us ) ->
1964
+ {more ,{Cs ,St ,Col ,Toks ,Line ,{B ,Ncs ,BCs ,ECs , Us },fun scan_based_exponent /6 }};
1965
+ scan_based_exponent (Cs , St , Line , Col , Toks , B , Ncs , BCs , ECs , Us ) ->
1966
+ based_float_end (Cs , St , Line , Col , Toks , B , Ncs , BCs , ECs , Us ).
1967
+
1968
+ % Note: the base and exponent parts are always in decimal
1969
+ based_float_end (Cs , St , Line , Col , Toks , 10 , Ncs0 , BCs , ECs , Us ) ->
1970
+ Ncs = lists :reverse (Ncs0 ),
1971
+ Fcs = Ncs ++ lists :reverse (ECs ),
1972
+ try list_to_float (remove_digit_separators (Fcs , Us )) of
1973
+ F ->
1974
+ Tcs = BCs ++ Fcs ,
1975
+ tok3 (Cs , St , Line , Col , Toks , float , Tcs , F )
1976
+ catch
1977
+ _ :_ ->
1978
+ Ncol = incr_column (Col , length (Ncs ) + length (BCs )),
1979
+ scan_error ({illegal ,float }, Line , Col , Line , Ncol , Cs )
1980
+ end ;
1981
+ based_float_end (Cs , St , Line , Col , Toks , B , Ncs0 , BCs , ECs0 , Us ) when B =/= 10 ->
1982
+ ECs = lists :reverse (ECs0 ),
1983
+ Exp = case ECs of
1984
+ [] -> 0 ;
1985
+ _ -> list_to_integer (remove_digit_separators (tl (ECs ), Us ))
1986
+ end ,
1987
+ Tcs = BCs ++ lists :reverse (Ncs0 ) ++ ECs ,
1988
+ Ncs = trim_float_zeros (lists :reverse (trim_float_zeros (remove_digit_separators (Ncs0 , Us )))),
1989
+ FBits = (length (Ncs ) - string :chr (Ncs , $. )) * case B of 2 -> 1 ; 16 -> 4 end ,
1990
+ % % note that there will always be at least one digit in the fraction, even if 0
1991
+ F = list_to_integer (lists :delete ($. ,Ncs ), B ) * math :pow (2 , Exp - FBits ),
1992
+ tok3 (Cs , St , Line , Col , Toks , float , Tcs , F ).
1993
+
1994
+ trim_float_zeros ([$0 , $. | _ ]= Cs ) -> Cs ;
1995
+ trim_float_zeros ([$0 | Cs ]) -> trim_float_zeros (Cs );
1996
+ trim_float_zeros (Cs ) -> Cs .
1997
+
1895
1998
scan_fraction (Cs , # erl_scan {}= St , Line , Col , Toks , {Ncs ,Us }) ->
1896
1999
scan_fraction (Cs , St , Line , Col , Toks , Ncs , Us ).
1897
2000
0 commit comments