Skip to content

Commit aa298a4

Browse files
authored
Merge pull request #3157 from BuckleScript/hex_float
part2: add hexstring_of_float support
2 parents ccc71d5 + 5dea80d commit aa298a4

File tree

6 files changed

+117
-39
lines changed

6 files changed

+117
-39
lines changed

jscomp/core/lam_dispatch_primitive.ml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -694,7 +694,9 @@ let translate loc (prim_name : string)
694694

695695
end
696696
| "caml_format_float"
697-
697+
#if OCAML_VERSION =~ ">4.03.0" then
698+
| "caml_hexstring_of_float"
699+
#end
698700
| "caml_nativeint_format"
699701
| "caml_int32_format"
700702
| "caml_float_of_string"

jscomp/runtime/caml_format.ml

Lines changed: 50 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -570,6 +570,52 @@ let caml_format_float fmt x =
570570
end;
571571
finish_formatting f !s
572572

573+
let caml_hexstring_of_float : float -> int -> char -> string =
574+
fun%raw x prec style -> {|
575+
if (!isFinite(x)) {
576+
if (isNaN(x)) return "nan";
577+
return x > 0 ? "infinity":"-infinity";
578+
}
579+
var sign = (x==0 && 1/x == -Infinity)?1:(x>=0)?0:1;
580+
if(sign) x = -x;
581+
var exp = 0;
582+
if (x == 0) { }
583+
else if (x < 1) {
584+
while (x < 1 && exp > -1022) { x *= 2; exp-- }
585+
} else {
586+
while (x >= 2) { x /= 2; exp++ }
587+
}
588+
var exp_sign = exp < 0 ? '' : '+';
589+
var sign_str = '';
590+
if (sign) sign_str = '-'
591+
else {
592+
switch(style){
593+
case 43 /* '+' */: sign_str = '+'; break;
594+
case 32 /* ' ' */: sign_str = ' '; break;
595+
default: break;
596+
}
597+
}
598+
if (prec >= 0 && prec < 13) {
599+
/* If a precision is given, and is small, round mantissa accordingly */
600+
var cst = Math.pow(2,prec * 4);
601+
x = Math.round(x * cst) / cst;
602+
}
603+
var x_str = x.toString(16);
604+
if(prec >= 0){
605+
var idx = x_str.indexOf('.');
606+
if(idx<0) {
607+
x_str += '.' + '0'.repeat(prec);
608+
}
609+
else {
610+
var size = idx+1+prec;
611+
if(x_str.length < size)
612+
x_str += '0'.repeat(size - x_str.length);
613+
else
614+
x_str = x_str.substr(0,size);
615+
}
616+
}
617+
return (sign_str + '0x' + x_str + 'p' + exp_sign + exp.toString(10));
618+
|}
573619
(**
574620
external float_of_string : string -> float = "caml_float_of_string"
575621
pervasives.ml
@@ -586,7 +632,7 @@ let caml_format_float fmt x =
586632
let float_of_string : string -> exn -> float =
587633
#if OCAML_VERSION =~ ">4.3.0" then
588634
fun%raw s exn -> {|
589-
{
635+
590636
var res = +s;
591637
if ((s.length > 0) && (res === res))
592638
return res;
@@ -609,11 +655,11 @@ let float_of_string : string -> exn -> float =
609655
if (/^-inf(inity)?$/i.test(s))
610656
return -Infinity;
611657
throw exn;
612-
}
658+
613659
|}
614660
#else
615661
fun%raw s exn -> {|
616-
{
662+
617663
var res = +s;
618664
if ((s.length > 0) && (res === res))
619665
return res;
@@ -627,7 +673,7 @@ let float_of_string : string -> exn -> float =
627673
if (/^-inf(inity)?$/i.test(s))
628674
return -Infinity;
629675
throw exn;
630-
}
676+
631677
|}
632678
#end
633679

jscomp/runtime/caml_format.mli

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,9 @@
3131
(** *)
3232

3333
val caml_format_float : string -> float -> string
34-
34+
#if OCAML_VERSION =~ ">4.03.0" then
35+
val caml_hexstring_of_float : float -> int -> char -> string
36+
#end
3537
val caml_format_int : string -> nativeint -> string
3638
val caml_nativeint_format : string -> nativeint -> string
3739
val caml_int32_format : string -> nativeint -> string

jscomp/test/format_test.ml

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -84,17 +84,51 @@ let () =
8484
#end
8585
;;
8686

87+
88+
#if OCAML_VERSION =~ ">4.03.0" then
89+
let sl f =
90+
Printf.sprintf "%h" f
91+
92+
let aux_list loc ls =
93+
List.iter (fun (a,b) ->
94+
eq loc (sl a ) b
95+
) ls
96+
let literals =
97+
[
98+
0x3.fp+1, "0x1.f8p+2" (* (1. +. 0xf8p0 /. 0x1_00p0) *. 4.*);
99+
0.3, "0x1.3333333333333p-2";
100+
infinity, "infinity";
101+
0.4, "0x1.999999999999ap-2";
102+
0.5, "0x1p-1";
103+
0.6, "0x1.3333333333333p-1";
104+
0.7, "0x1.6666666666666p-1";
105+
0.8, "0x1.999999999999ap-1";
106+
0.9, "0x1.ccccccccccccdp-1";
107+
]
108+
109+
let () =
110+
aux_list __LOC__ literals
111+
112+
let () =
113+
eq __LOC__ (Printf.sprintf "%H" 0x3.fp+1) "0X1.F8P+2"
114+
let scan_float loc s expect =
115+
Scanf.sscanf s "%h" (fun result -> eq loc result expect)
116+
117+
let () =
118+
scan_float __LOC__ "0x3f.p1" 0x3f.p1;
119+
scan_float __LOC__ "0x1.3333333333333p-2" 0.3;
120+
List.iter (fun (a,b) ->
121+
scan_float __LOC__ b a
122+
) literals
123+
#end
124+
125+
87126
#if
88127
(* OCAML_VERSION =~ ">4.03.0" *) 0
89128
then
90129

91130

92131

93132

94-
let () = eq __LOC__ (Printf.sprintf "%h" 0x3.fp+1) "0x1.f8p+2"
95-
let () = eq __LOC__ (Printf.sprintf "%H" 0x3.fp+1) "0x1.F8P+2"
96-
97-
let () = eq __LOC__ (Printf.sprintf "%h" 0.3) "0x1.3333333333333p-2"
98-
99133
#end
100134
let () = Mt.from_pair_suites __FILE__ !suites

lib/js/caml_format.js

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -771,29 +771,20 @@ function caml_format_float(fmt, x) {
771771
}
772772

773773
var float_of_string = function (s,exn){
774-
{
774+
775775
var res = +s;
776776
if ((s.length > 0) && (res === res))
777777
return res;
778778
s = s.replace(/_/g, "");
779779
res = +s;
780780
if (((s.length > 0) && (res === res)) || /^[+-]?nan$/i.test(s)) {
781781
return res;
782-
}
783-
;
784-
if (/^ *0x[0-9a-f_]+p[+-]?[0-9_]+/i.test(s)) {
785-
var pidx = s.indexOf('p');
786-
pidx = (pidx == -1) ? s.indexOf('P') : pidx;
787-
var exp = +s.substring(pidx + 1);
788-
res = +s.substring(0, pidx);
789-
return res * Math.pow(2, exp);
790-
}
782+
};
791783
if (/^\+?inf(inity)?$/i.test(s))
792784
return Infinity;
793785
if (/^-inf(inity)?$/i.test(s))
794786
return -Infinity;
795787
throw exn;
796-
}
797788

798789
};
799790

lib/whole_compiler.ml

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -82976,7 +82976,7 @@ module Js_number : sig
8297682976
type t = float
8297782977

8297882978

82979-
val to_string : t -> string
82979+
(* val to_string : t -> string *)
8298082980

8298182981

8298282982
val caml_float_literal_to_js_string : string -> string
@@ -83057,18 +83057,20 @@ let to_string v =
8305783057
else Printf.sprintf "%.18g" v
8305883058

8305983059

83060+
let rec is_hex_format_aux (v : string) cur =
83061+
if v.[cur] = '-' || v.[cur]= '+' then
83062+
is_hex_format_ox v (cur + 1)
83063+
else is_hex_format_ox v cur
83064+
and is_hex_format_ox v cur =
83065+
v.[cur] = '0' &&
83066+
(v.[cur + 1] = 'x' || v.[cur + 1] = 'X')
83067+
83068+
let is_hex_format (v : string) =
83069+
try is_hex_format_aux v 0 with _ -> false
8306083070

83061-
let caml_float_literal_to_js_string v =
83071+
83072+
let caml_float_literal_to_js_string (v : string) : string =
8306283073
let len = String.length v in
83063-
if len >= 2 &&
83064-
v.[0] = '0' &&
83065-
(v.[1] = 'x' || v.[1] = 'X') then
83066-
assert false
83067-
(* TODO: catchup when upgraded to 4.3
83068-
it does not make sense too much since js dos not
83069-
support it natively
83070-
*)
83071-
else
8307283074

8307383075
let rec aux buf i =
8307483076
if i >= len then buf
@@ -83762,11 +83764,11 @@ and expression_desc cxt (level:int) f x : cxt =
8376283764
| Number v ->
8376383765
let s =
8376483766
match v with
83765-
| Float {f = v} ->
83766-
Js_number.caml_float_literal_to_js_string v
83767+
| Float {f} ->
83768+
Js_number.caml_float_literal_to_js_string f
8376783769
(* attach string here for float constant folding?*)
83768-
| Int { i = v; _}
83769-
-> Int32.to_string v (* check , js convention with ocaml lexical convention *)
83770+
| Int { i; _}
83771+
-> Int32.to_string i (* check , js convention with ocaml lexical convention *)
8377083772
| Uint i
8377183773
-> Format.asprintf "%lu" i
8377283774
| Nint i -> Nativeint.to_string i in
@@ -83776,7 +83778,8 @@ and expression_desc cxt (level:int) f x : cxt =
8377683778
else level = 15 (* Parenthesize as well when followed by a dot. *)
8377783779
&& s.[0] <> 'I' (* Infinity *)
8377883780
&& s.[0] <> 'N' (* NaN *) in
83779-
let action = fun _ -> P.string f s in
83781+
let action =
83782+
fun _ -> P.string f s in
8378083783
(
8378183784
if need_paren
8378283785
then P.paren f action
@@ -95390,7 +95393,7 @@ let translate loc (prim_name : string)
9539095393

9539195394
end
9539295395
| "caml_format_float"
95393-
95396+
9539495397
| "caml_nativeint_format"
9539595398
| "caml_int32_format"
9539695399
| "caml_float_of_string"

0 commit comments

Comments
 (0)