Skip to content

Commit 9608afb

Browse files
committed
[Belt] Stricter parse for Int and Float
The actual implementation of Belt.Int.fromString relies on the Javascript parseInt function [0]. That function parses Strings in a permissive manner. For instance, if the function encounters an alphabetical character, it returns the value up to that character: parseInt("123a456") // output: 123 The same applies for Belt.Float.fromString that relies on parseFloat [1] and have a similar interpretation. This commit proposes a stricter implementation of Int and Float parsing using the Javascript Number constructor [2]. The Belt.Int.fromString uses the more specific Math.trunc function [3], that parses string similarly to Number and then returns the Int part of that number. Relying only on the Number constructor keeps the implementation simple. However, there exists one last quirk while using it with an empty string. It returns the 0 value: Number("") // ouptput: 0 Consequently, Belt.Int.fromString("") will return 0. Tests for Belt.(Int/Float).fromString have been updated in order to reflect that. Fix rescript-lang#3732 [0] https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/parseInt [1] https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/parseFloat [2] https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/Number [3] https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/trunc
1 parent bf887f1 commit 9608afb

File tree

4 files changed

+22
-4
lines changed

4 files changed

+22
-4
lines changed

jscomp/others/belt_Float.ml

+1-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ external toInt: float -> int = "%intoffloat"
3232

3333
external fromInt: int -> float = "%identity"
3434

35-
external fromString: string -> float = "parseFloat" [@@bs.val]
35+
external fromString: string -> float = "Number" [@@bs.val]
3636

3737
let fromString i =
3838
match (fromString i) with

jscomp/others/belt_Int.ml

+1-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ external toFloat: int -> float = "%identity"
3232

3333
external fromFloat: float -> int = "%intoffloat"
3434

35-
external fromString: string -> (_ [@bs.as 10]) -> int = "parseInt" [@@bs.val]
35+
external fromString: string -> (_ [@bs.as 10]) -> int = "Math.trunc" [@@bs.val]
3636

3737
let fromString i =
3838
match fromString i with

jscomp/test/bs_float_test.ml

+10-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,16 @@ let () =
2929
eq __LOC__ (F.fromString "-1.0") (Some (-1.0));
3030
eq __LOC__ (F.fromString "-1.5") (Some (-1.5));
3131
eq __LOC__ (F.fromString "-1.7") (Some (-1.7));
32-
eq __LOC__ (F.fromString "not a float") None
32+
eq __LOC__ (F.fromString "17e-1") (Some (1.7));
33+
eq __LOC__ (F.fromString "-17e-1") (Some (-1.7));
34+
eq __LOC__ (F.fromString " -17e-1 ") (Some (-1.7));
35+
eq __LOC__ (F.fromString "0x11") (Some (17.));
36+
eq __LOC__ (F.fromString "0b11") (Some (3.));
37+
eq __LOC__ (F.fromString "0o11") (Some (9.));
38+
eq __LOC__ (F.fromString "") (Some (0.));
39+
eq __LOC__ (F.fromString "not a float") None;
40+
eq __LOC__ (F.fromString "100.0abcdef") None;
41+
eq __LOC__ (F.fromString "123_456.7") None
3342

3443
let () =
3544
eq __LOC__ (F.toString 1.0) "1";

jscomp/test/bs_int_test.ml

+10-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,16 @@ let () =
2929
eq __LOC__ (I.fromString "-1.0") (Some (-1));
3030
eq __LOC__ (I.fromString "-1.5") (Some (-1));
3131
eq __LOC__ (I.fromString "-1.7") (Some (-1));
32-
eq __LOC__ (I.fromString "not an int") None
32+
eq __LOC__ (I.fromString "17e-1") (Some (1));
33+
eq __LOC__ (I.fromString "-17e-1") (Some (-1));
34+
eq __LOC__ (I.fromString " -17e-1 ") (Some (-1));
35+
eq __LOC__ (I.fromString "0x11") (Some (17));
36+
eq __LOC__ (I.fromString "0b11") (Some (3));
37+
eq __LOC__ (I.fromString "0o11") (Some (9));
38+
eq __LOC__ (I.fromString "") (Some (0));
39+
eq __LOC__ (I.fromString "not an int") None;
40+
eq __LOC__ (I.fromString "100abcdef") None;
41+
eq __LOC__ (I.fromString "123_456") None
3342

3443
let () =
3544
eq __LOC__ (I.toString 1) "1";

0 commit comments

Comments
 (0)