Skip to content

Commit 6debf4e

Browse files
committed
part1: add hex float notation support and basic tests around pervasives.ml constant
1 parent 7dc4938 commit 6debf4e

File tree

6 files changed

+103
-43
lines changed

6 files changed

+103
-43
lines changed

jscomp/core/js_dump.ml

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -631,11 +631,11 @@ and expression_desc cxt (level:int) f x : cxt =
631631
| Number v ->
632632
let s =
633633
match v with
634-
| Float {f = v} ->
635-
Js_number.caml_float_literal_to_js_string v
634+
| Float {f} ->
635+
Js_number.caml_float_literal_to_js_string f
636636
(* attach string here for float constant folding?*)
637-
| Int { i = v; _}
638-
-> Int32.to_string v (* check , js convention with ocaml lexical convention *)
637+
| Int { i; _}
638+
-> Int32.to_string i (* check , js convention with ocaml lexical convention *)
639639
| Uint i
640640
-> Format.asprintf "%lu" i
641641
| Nint i -> Nativeint.to_string i in
@@ -645,7 +645,8 @@ and expression_desc cxt (level:int) f x : cxt =
645645
else level = 15 (* Parenthesize as well when followed by a dot. *)
646646
&& s.[0] <> 'I' (* Infinity *)
647647
&& s.[0] <> 'N' (* NaN *) in
648-
let action = fun _ -> P.string f s in
648+
let action =
649+
fun _ -> P.string f s in
649650
(
650651
if need_paren
651652
then P.paren f action

jscomp/core/js_number.ml

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -72,17 +72,22 @@ let to_string v =
7272
else Printf.sprintf "%.18g" v
7373

7474

75+
let rec is_hex_format_aux (v : string) cur =
76+
if v.[cur] = '-' || v.[cur]= '+' then
77+
is_hex_format_ox v (cur + 1)
78+
else is_hex_format_ox v cur
79+
and is_hex_format_ox v cur =
80+
v.[cur] = '0' &&
81+
(v.[cur + 1] = 'x' || v.[cur + 1] = 'X')
7582

76-
let caml_float_literal_to_js_string v =
83+
let is_hex_format (v : string) =
84+
try is_hex_format_aux v 0 with _ -> false
85+
86+
87+
let caml_float_literal_to_js_string (v : string) : string =
7788
let len = String.length v in
78-
if len >= 2 &&
79-
v.[0] = '0' &&
80-
(v.[1] = 'x' || v.[1] = 'X') then
81-
assert false
82-
(* TODO: catchup when upgraded to 4.3
83-
it does not make sense too much since js dos not
84-
support it natively
85-
*)
89+
if len >= 2 && is_hex_format v then
90+
to_string (float_of_string v)
8691
else
8792

8893
let rec aux buf i =

jscomp/core/js_number.mli

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
type t = float
3232

3333

34-
val to_string : t -> string
34+
(* val to_string : t -> string *)
3535

3636

3737
val caml_float_literal_to_js_string : string -> string

jscomp/stdlib-406/pervasives.ml

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -201,19 +201,13 @@ external float_of_bits : int64 -> float
201201
[@@unboxed] [@@noalloc]
202202
#end
203203
#if BS then
204-
external infinity : float = "POSITIVE_INFINITY"
205-
[@@bs.val] [@@bs.scope "Number"]
206-
external neg_infinity : float = "NEGATIVE_INFINITY"
207-
[@@bs.val] [@@bs.scope "Number"]
204+
let infinity = 0x1p2047
205+
let neg_infinity = -0x1p2047
208206
external nan : float = "NaN"
209207
[@@bs.val] [@@bs.scope "Number"]
210-
external max_float : float = "MAX_VALUE"
211-
[@@bs.val] [@@bs.scope "Number"]
212-
external min_float : float = "MIN_VALUE"
213-
[@@bs.val] [@@bs.scope "Number"]
214-
(* external epsilon_float : float = "EPSILON" (* ES 2015 *)
215-
[@@bs.val] [@@bs.scope "Number"] *)
216-
let epsilon_float = 2.220446049250313e-16
208+
let max_float = 0x1.ffff_ffff_ffff_fp+1023
209+
let min_float = 0x1p-1022
210+
let epsilon_float = 0x1p-52
217211
#else
218212
let infinity =
219213
float_of_bits 0x7F_F0_00_00_00_00_00_00L

jscomp/stdlib-406/pervasives.mli

Lines changed: 6 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -614,29 +614,18 @@ external int_of_float : float -> int = "%intoffloat"
614614
The result is unspecified if the argument is [nan] or falls outside the
615615
range of representable integers. *)
616616

617-
#if BS then
618-
external infinity : float = "POSITIVE_INFINITY"
619-
[@@bs.val] [@@bs.scope "Number"]
620-
external neg_infinity : float = "NEGATIVE_INFINITY"
621-
[@@bs.val] [@@bs.scope "Number"]
622-
external nan : float = "NaN"
623-
[@@bs.val] [@@bs.scope "Number"]
624-
external max_float : float = "MAX_VALUE"
625-
[@@bs.val] [@@bs.scope "Number"]
626-
external min_float : float = "MIN_VALUE"
627-
[@@bs.val] [@@bs.scope "Number"]
628-
(* external epsilon_float : float = "EPSILON" (* ES 2015 *)
629-
[@@bs.val] [@@bs.scope "Number"] *)
630-
val epsilon_float : float
631-
#else
632-
633617
val infinity : float
634618
(** Positive infinity. *)
635619

636620
val neg_infinity : float
637621
(** Negative infinity. *)
638622

623+
#if BS then
624+
external nan : float = "NaN" [@@bs.val] [@@bs.scope "Number"]
625+
(* we could also use [0. /. 0.] *)
626+
#else
639627
val nan : float
628+
#end
640629
(** A special floating-point value denoting the result of an
641630
undefined operation such as [0.0 /. 0.0]. Stands for
642631
'not a number'. Any floating-point operation with [nan] as
@@ -653,7 +642,7 @@ val min_float : float
653642
val epsilon_float : float
654643
(** The difference between [1.0] and the smallest exactly representable
655644
floating-point number greater than [1.0]. *)
656-
#end
645+
657646

658647
type fpclass =
659648
FP_normal (** Normal number, none of the below *)

jscomp/test/format_test.ml

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,81 @@ let eq loc x y =
55
suites :=
66
(loc ^" id " ^ (string_of_int !test_id), (fun _ -> Mt.Eq(x,y))) :: !suites
77

8+
let eq3 loc a b c =
9+
eq loc a b ;
10+
eq loc b c ;
11+
eq loc a c
812

913
let u () = "xx %s" ^^ "yy"
1014

15+
module M = struct
16+
external infinity : float = "POSITIVE_INFINITY"
17+
[@@bs.val] [@@bs.scope "Number"]
18+
external neg_infinity : float = "NEGATIVE_INFINITY"
19+
[@@bs.val] [@@bs.scope "Number"]
20+
external nan : float = "NaN"
21+
[@@bs.val] [@@bs.scope "Number"]
22+
external max_float : float = "MAX_VALUE"
23+
[@@bs.val] [@@bs.scope "Number"]
24+
end
1125
let () =
1226
eq __LOC__ (Format.asprintf (u ()) "x") ("xx x" ^ "yy")
27+
1328

29+
#if OCAML_VERSION =~ ">4.03.0" then
30+
let () =
31+
eq __LOC__ (0x3.fp+1) (7.875);
32+
33+
34+
eq __LOC__ (-0x3.fp+1) (-7.875);
35+
(* in standard, it is still infinity, but
36+
ideally should give an warning
37+
*)
38+
eq3 __LOC__ 0x1p2047 M.infinity infinity;
39+
eq3 __LOC__ (-0x1p2047) M.neg_infinity neg_infinity;
40+
eq3 __LOC__ max_float 0x1.ffff_ffff_ffff_fp+1023 M.max_float;
41+
eq __LOC__ (classify_float 0x1.2p2047) FP_infinite;
42+
eq __LOC__ (classify_float 0x1.1p2047) FP_infinite;
43+
44+
45+
eq __LOC__ min_float 0x1p-1022;
46+
eq __LOC__ epsilon_float 0x1p-52;
47+
eq __LOC__ 0x0.0000_0000_0000_1p-1022 5e-324;
48+
eq __LOC__
49+
(0x1.0000_0000_0000_1 -. 1.) epsilon_float;
50+
eq __LOC__
51+
(0x1p-1023 /. 0x1p-1022) 0x1p-1;
52+
eq __LOC__ (classify_float 0x1p-1023) FP_subnormal;
53+
eq __LOC__
54+
0x1p-1023 0x0.8p-1022;
55+
eq __LOC__
56+
0x0.ffff_ffff_ffff_ffff_ffp-1022
57+
0x1p-1022;
58+
59+
eq __LOC__
60+
((1. +. 0xffp0 /. 0x100p0 ) *. 8.)
61+
(0x1.ffp3);
62+
eq __LOC__
63+
((1. +. 0xfffp0 /. 0x1000p0) *. 8.)
64+
0x1.fffp3;
65+
eq __LOC__
66+
((1. +. 0xffffp0 /. 0x10000p0) *. 8.)
67+
0x1.ffffp3
68+
;;
69+
#end
70+
(*TODO: add scanf example *)
71+
#if
72+
(* OCAML_VERSION =~ ">4.03.0" *) 0
73+
then
74+
75+
76+
let () =
77+
eq __LOC__ (float_of_string "0x3.fp+1") 0x3.fp+1;;
78+
79+
let () = eq __LOC__ (Printf.sprintf "%h" 0x3.fp+1) "0x1.f8p+2"
80+
let () = eq __LOC__ (Printf.sprintf "%H" 0x3.fp+1) "0x1.F8P+2"
81+
82+
let () = eq __LOC__ (Printf.sprintf "%h" 0.3) "0x1.3333333333333p-2"
83+
84+
#end
1485
let () = Mt.from_pair_suites __FILE__ !suites

0 commit comments

Comments
 (0)