diff --git a/CHANGELOG.md b/CHANGELOG.md index a7767e387e..d6ba9d2e0b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -43,6 +43,7 @@ - Fix `-nostdlib` internal compiler option. https://github.com/rescript-lang/rescript-compiler/pull/6824 - Remove a number of ast nodes never populated by the .res parser, and resulting dead code. https://github.com/rescript-lang/rescript-compiler/pull/6830 - Remove coercion with 2 types from internal representation. Coercion `e : t1 :> t2` was only supported in `.ml` syntax and never by the `.res` parser. https://github.com/rescript-lang/rescript-compiler/pull/6829 +- Convert `caml_format` and `js_math` to `.res`. https://github.com/rescript-lang/rescript-compiler/pull/6834 #### :nail_care: Polish diff --git a/jscomp/others/belt_Array.res b/jscomp/others/belt_Array.res index fdb72f48ad..13ea4f2bd8 100644 --- a/jscomp/others/belt_Array.res +++ b/jscomp/others/belt_Array.res @@ -64,10 +64,16 @@ let swapUnsafe = (xs, i, j) => { setUnsafe(xs, j, tmp) } + +@val @scope("Math") external random : unit => float = "random" +@val @scope("Math") external floor : float => int = "floor" +external toFloat: int => float = "%floatofint" + let shuffleInPlace = xs => { let len = length(xs) + let random_int = (min, max) => floor(random() *. toFloat(max - min)) + min for i in 0 to len - 1 { - swapUnsafe(xs, i, Js_math.random_int(i, len)) /* [i,len) */ + swapUnsafe(xs, i, random_int(i, len)) /* [i,len) */ } } diff --git a/jscomp/others/js_math.ml b/jscomp/others/js_math.res similarity index 76% rename from jscomp/others/js_math.ml rename to jscomp/others/js_math.res index 977af91f9e..23c2e3b387 100644 --- a/jscomp/others/js_math.ml +++ b/jscomp/others/js_math.res @@ -1,4 +1,4 @@ -(* Copyright (C) 2015-2016 Bloomberg Finance L.P. +@@ocaml.text(/* Copyright (C) 2015-2016 Bloomberg Finance L.P. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by @@ -20,151 +20,167 @@ * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *) + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -(** +" Provide utilities for JS Math. Note: The constants `_E`, `_LN10`, `_LN2`, `_LOG10E`, `_LOG2E`, `_PI`, `_SQRT1_2`, and `_SQRT2` begin with an underscore because ReScript variable names cannot begin with a capital letter. (Module names begin with upper case.) -*) +") -external _E : float = "E" -[@@val] [@@scope "Math"] -(** +@val +@scope("Math") +@ocaml.doc(" Euler's number; ≈ 2.718281828459045. See [`Math.E`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/E) on MDN. -*) +") +external _E: float = "E" -external _LN2 : float = "LN2" -[@@val] [@@scope "Math"] -(** +@val +@scope("Math") +@ocaml.doc(" Natural logarithm of 2; ≈ 0.6931471805599453. See [`Math.LN2`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/LN2) on MDN. -*) +") +external _LN2: float = "LN2" -external _LN10 : float = "LN10" -[@@val] [@@scope "Math"] -(** +@val +@scope("Math") +@ocaml.doc(" Natural logarithm of 10; ≈ 2.302585092994046. See [`Math.LN10`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/LN10) on MDN. -*) +") +external _LN10: float = "LN10" -external _LOG2E : float = "LOG2E" -[@@val] [@@scope "Math"] -(** +@val +@scope("Math") +@ocaml.doc(" Base 2 logarithm of E; ≈ 1.4426950408889634. See [`Math.LOG2E`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/LOG2E) on MDN. -*) +") +external _LOG2E: float = "LOG2E" -external _LOG10E : float = "LOG10E" -[@@val] [@@scope "Math"] -(** +@val +@scope("Math") +@ocaml.doc(" Base 10 logarithm of E; ≈ 0.4342944819032518. See [`Math.LOG10E`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/LOG10E) on MDN. -*) +") +external _LOG10E: float = "LOG10E" -external _PI : float = "PI" -[@@val] [@@scope "Math"] -(** +@val +@scope("Math") +@ocaml.doc(" Pi - ratio of the circumference to the diameter of a circle; ≈ 3.141592653589793. See [`Math.PI`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/PI) on MDN. -*) +") +external _PI: float = "PI" -external _SQRT1_2 : float = "SQRT1_2" -[@@val] [@@scope "Math"] -(** +@val +@scope("Math") +@ocaml.doc(" Square root of 1/2; ≈ 0.7071067811865476. See [`Math.SQRT1_2`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/SQRT1_2) on MDN. -*) +") +external _SQRT1_2: float = "SQRT1_2" -external _SQRT2 : float = "SQRT2" -[@@val] [@@scope "Math"] -(** +@val +@scope("Math") +@ocaml.doc(" Square root of 2; ≈ 1.4142135623730951. See [`Math.SQRT2`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/SQRT2) on MDN. -*) +") +external _SQRT2: float = "SQRT2" -external abs_int : int -> int = "abs" -[@@val] [@@scope "Math"] -(** +@val +@scope("Math") +@ocaml.doc(" Absolute value for integer argument. See [`Math.abs`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/abs) on MDN. -*) +") +external abs_int: int => int = "abs" -external abs_float : float -> float = "abs" -[@@val] [@@scope "Math"] -(** +@val +@scope("Math") +@ocaml.doc(" Absolute value for float argument. See [`Math.abs`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/abs) on MDN. -*) +") +external abs_float: float => float = "abs" -external acos : float -> float = "acos" -[@@val] [@@scope "Math"] -(** +@val +@scope("Math") +@ocaml.doc(" Arccosine (in radians) of argument; returns `NaN` if the argument is outside the range [-1.0, 1.0]. See [`Math.acos`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/acos) on MDN. -*) +") +external acos: float => float = "acos" -external acosh : float -> float = "acosh" -[@@val] [@@scope "Math"] -(** +@val +@scope("Math") +@ocaml.doc(" Hyperbolic arccosine (in radians) of argument; returns `NaN` if the argument is less than 1.0. See [`Math.acosh`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/acosh) on MDN. -*) +") +external acosh: float => float = "acosh" -external asin : float -> float = "asin" -[@@val] [@@scope "Math"] -(** +@val +@scope("Math") +@ocaml.doc(" Arcsine (in radians) of argument; returns `NaN` if the argument is outside the range [-1.0, 1.0]. See [`Math.asin`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/asin) on MDN. -*) +") +external asin: float => float = "asin" -external asinh : float -> float = "asinh" -[@@val] [@@scope "Math"] -(** +@val +@scope("Math") +@ocaml.doc(" Hyperbolic arcsine (in radians) of argument. See [`Math.asinh`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/asinh) on MDN. -*) +") +external asinh: float => float = "asinh" -external atan : float -> float = "atan" -[@@val] [@@scope "Math"] -(** +@val +@scope("Math") +@ocaml.doc(" Arctangent (in radians) of argument. See [`Math.atan`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/atan) on MDN. -*) +") +external atan: float => float = "atan" -external atanh : float -> float = "atanh" -[@@val] [@@scope "Math"] -(** +@val +@scope("Math") +@ocaml.doc(" Hyperbolic arctangent (in radians) of argument; returns `NaN` if the argument is is outside the range [-1.0, 1.0]. Returns `-Infinity` and `Infinity` for arguments -1.0 and 1.0. See [`Math.atanh`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/atanh) on MDN. -*) +") +external atanh: float => float = "atanh" -external atan2 : y:float -> x:float -> unit -> float = "atan2" -[@@val] [@@scope "Math"] -(** +@val +@scope("Math") +@ocaml.doc(" Returns the angle (in radians) of the quotient `y /. x`. It is also the angle between the *x*-axis and point (*x*, *y*). See [`Math.atan2`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/atan2) @@ -179,19 +195,21 @@ Js.Math.atan2(~x=-5.0, ~y=5.0, ()) Js.Math.atan2(~x=-5.0, ~y=5.0, ()) == 3.0 *. Js.Math._PI /. 4.0 Js.Math.atan2(~x=-0.0, ~y=-5.0, ()) == -.Js.Math._PI /. 2.0 ``` -*) +") +external atan2: (~y: float, ~x: float, unit) => float = "atan2" -external cbrt : float -> float = "cbrt" -[@@val] [@@scope "Math"] -(** +@val +@scope("Math") +@ocaml.doc(" Cube root. See [`Math.cbrt`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/cbrt) on MDN -*) +") +external cbrt: float => float = "cbrt" -external unsafe_ceil_int : float -> int = "ceil" -[@@val] [@@scope "Math"] -(** +@val +@scope("Math") +@ocaml.doc(" Returns the smallest integer greater than or equal to the argument. This function may return values not representable by `int`, whose range is -2147483648 to 2147483647. This is because, in JavaScript, there are only @@ -208,12 +226,12 @@ Js.Math.unsafe_ceil_int(3.0) == 3 Js.Math.unsafe_ceil_int(-3.1) == -3 Js.Math.unsafe_ceil_int(1.0e15) // result is outside range of int datatype ``` -*) +") +external unsafe_ceil_int: float => int = "ceil" -let unsafe_ceil = unsafe_ceil_int -[@@deprecated "Please use `unsafe_ceil_int` instead"] +@deprecated("Please use `unsafe_ceil_int` instead") let unsafe_ceil = unsafe_ceil_int -(** +@ocaml.doc(" Returns the smallest `int` greater than or equal to the argument; the result is pinned to the range of the `int` data type: -2147483648 to 2147483647. See [`Math.ceil`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/ceil) @@ -228,17 +246,21 @@ Js.Math.ceil_int(-3.1) == -3 Js.Math.ceil_int(-1.0e15) == -2147483648 Js.Math.ceil_int(1.0e15) == 2147483647 ``` -*) -let ceil_int (f : float) : int = - if f > Js_int.toFloat Js_int.max then Js_int.max - else if f < Js_int.toFloat Js_int.min then Js_int.min - else unsafe_ceil_int f - -let ceil = ceil_int [@@deprecated "Please use `ceil_int` instead"] - -external ceil_float : float -> float = "ceil" -[@@val] [@@scope "Math"] -(** +") +let ceil_int = (f: float): int => + if f > Js_int.toFloat(Js_int.max) { + Js_int.max + } else if f < Js_int.toFloat(Js_int.min) { + Js_int.min + } else { + unsafe_ceil_int(f) + } + +@deprecated("Please use `ceil_int` instead") let ceil = ceil_int + +@val +@scope("Math") +@ocaml.doc(" Returns the smallest integral value greater than or equal to the argument. The result is a `float` and is not restricted to the `int` data type range. See @@ -253,11 +275,12 @@ Js.Math.ceil_float(3.0) == 3.0 Js.Math.ceil_float(-3.1) == -3.0 Js.Math.ceil_float(2_150_000_000.3) == 2_150_000_001.0 ``` -*) +") +external ceil_float: float => float = "ceil" -external clz32 : int -> int = "clz32" -[@@val] [@@scope "Math"] -(** +@val +@scope("Math") +@ocaml.doc(" Number of leading zero bits of the argument's 32 bit int representation. See [`Math.clz32`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/clz32) on MDN. @@ -269,45 +292,50 @@ Js.Math.clz32(0) == 32 Js.Math.clz32(-1) == 0 Js.Math.clz32(255) == 24 ``` -*) +") +external clz32: int => int = "clz32" -external cos : float -> float = "cos" -[@@val] [@@scope "Math"] -(** +@val +@scope("Math") +@ocaml.doc(" Cosine of argument, which must be specified in radians. See [`Math.cos`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/cos) on MDN. -*) +") +external cos: float => float = "cos" -external cosh : float -> float = "cosh" -[@@val] [@@scope "Math"] -(** +@val +@scope("Math") +@ocaml.doc(" Hyperbolic cosine of argument, which must be specified in radians. See [`Math.cosh`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/cosh) on MDN. -*) +") +external cosh: float => float = "cosh" -external exp : float -> float = "exp" -[@@val] [@@scope "Math"] -(** +@val +@scope("Math") +@ocaml.doc(" Natural exponentional; returns *e* (the base of natural logarithms) to the power of the given argument. See [`Math.exp`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/exp) on MDN. -*) +") +external exp: float => float = "exp" -external expm1 : float -> float = "expm1" -[@@val] [@@scope "Math"] -(** +@val +@scope("Math") +@ocaml.doc(" Returns *e* (the base of natural logarithms) to the power of the given argument minus 1. See [`Math.expm1`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/expm1) on MDN. -*) +") +external expm1: float => float = "expm1" -external unsafe_floor_int : float -> int = "floor" -[@@val] [@@scope "Math"] -(** +@val +@scope("Math") +@ocaml.doc(" Returns the largest integer less than or equal to the argument. This function may return values not representable by `int`, whose range is -2147483648 to 2147483647. This is because, in JavaScript, there are only 64-bit floating @@ -324,12 +352,12 @@ Js.Math.unsafe_floor_int(3.0) == 3 Js.Math.unsafe_floor_int(-3.7) == -4 Js.Math.unsafe_floor_int(1.0e15) // result is outside range of int datatype ``` -*) +") +external unsafe_floor_int: float => int = "floor" -let unsafe_floor = unsafe_floor_int -[@@deprecated "Please use `unsafe_floor_int` instead"] +@deprecated("Please use `unsafe_floor_int` instead") let unsafe_floor = unsafe_floor_int -(** +@ocaml.doc(" Returns the largest `int` less than or equal to the argument; the result is pinned to the range of the `int` data type: -2147483648 to 2147483647. See [`Math.floor`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/floor) @@ -344,17 +372,21 @@ Js.Math.floor_int(-3.1) == -4 Js.Math.floor_int(-1.0e15) == -2147483648 Js.Math.floor_int(1.0e15) == 2147483647 ``` -*) -let floor_int f = - if f > Js_int.toFloat Js_int.max then Js_int.max - else if f < Js_int.toFloat Js_int.min then Js_int.min - else unsafe_floor f - -let floor = floor_int [@@deprecated "Please use `floor_int` instead"] - -external floor_float : float -> float = "floor" -[@@val] [@@scope "Math"] -(** +") +let floor_int = f => + if f > Js_int.toFloat(Js_int.max) { + Js_int.max + } else if f < Js_int.toFloat(Js_int.min) { + Js_int.min + } else { + unsafe_floor(f) + } + +@deprecated("Please use `floor_int` instead") let floor = floor_int + +@val +@scope("Math") +@ocaml.doc(" Returns the largest integral value less than or equal to the argument. The result is a `float` and is not restricted to the `int` data type range. See [`Math.floor`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/floor) @@ -368,11 +400,12 @@ Js.Math.floor_float(3.0) == 3.0 Js.Math.floor_float(-3.1) == -4.0 Js.Math.floor_float(2_150_000_000.3) == 2_150_000_000.0 ``` -*) +") +external floor_float: float => float = "floor" -external fround : float -> float = "fround" -[@@val] [@@scope "Math"] -(** +@val +@scope("Math") +@ocaml.doc(" Round to nearest single precision float. See [`Math.fround`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/fround) on MDN. @@ -383,20 +416,23 @@ on MDN. Js.Math.fround(5.5) == 5.5 Js.Math.fround(5.05) == 5.050000190734863 ``` -*) +") +external fround: float => float = "fround" -external hypot : float -> float -> float = "hypot" -[@@val] [@@scope "Math"] -(** +@val +@scope("Math") +@ocaml.doc(" Returns the square root of the sum of squares of its two arguments (the Pythagorean formula). See [`Math.hypot`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/hypot) on MDN. -*) +") +external hypot: (float, float) => float = "hypot" -external hypotMany : float array -> float = "hypot" -[@@val] [@@variadic] [@@scope "Math"] -(** +@val +@variadic +@scope("Math") +@ocaml.doc(" Returns the square root of the sum of squares of the numbers in the array argument (generalized Pythagorean equation). Using an array allows you to have more than two items. See @@ -408,20 +444,22 @@ on MDN. ```rescript Js.Math.hypotMany([3.0, 4.0, 12.0]) == 13.0 ``` -*) +") +external hypotMany: array => float = "hypot" -external imul : int -> int -> int = "imul" -[@@val] [@@scope "Math"] -(** +@val +@scope("Math") +@ocaml.doc(" 32-bit integer multiplication. Use this only when you need to optimize performance of multiplication of numbers stored as 32-bit integers. See [`Math.imul`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/imul) on MDN. -*) +") +external imul: (int, int) => int = "imul" -external log : float -> float = "log" -[@@val] [@@scope "Math"] -(** +@val +@scope("Math") +@ocaml.doc(" Returns the natural logarithm of its argument; this is the number *x* such that *e**x* equals the argument. Returns `NaN` for negative arguments. See @@ -434,11 +472,12 @@ on MDN. Js.Math.log(Js.Math._E) == 1.0 Js.Math.log(100.0) == 4.605170185988092 ``` -*) +") +external log: float => float = "log" -external log1p : float -> float = "log1p" -[@@val] [@@scope "Math"] -(** +@val +@scope("Math") +@ocaml.doc(" Returns the natural logarithm of one plus the argument. Returns `NaN` for arguments less than -1. See [`Math.log1p`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/log1p) @@ -450,11 +489,12 @@ on MDN. Js.Math.log1p(Js.Math._E -. 1.0) == 1.0 Js.Math.log1p(99.0) == 4.605170185988092 ``` -*) +") +external log1p: float => float = "log1p" -external log10 : float -> float = "log10" -[@@val] [@@scope "Math"] -(** +@val +@scope("Math") +@ocaml.doc(" Returns the base 10 logarithm of its argument. Returns `NaN` for negative arguments. See [`Math.log10`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/log10) @@ -467,11 +507,12 @@ Js.Math.log10(1000.0) == 3.0 Js.Math.log10(0.01) == -2.0 Js.Math.log10(Js.Math.sqrt(10.0)) == 0.5 ``` -*) +") +external log10: float => float = "log10" -external log2 : float -> float = "log2" -[@@val] [@@scope "Math"] -(** +@val +@scope("Math") +@ocaml.doc(" Returns the base 2 logarithm of its argument. Returns `NaN` for negative arguments. See [`Math.log2`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/log2) @@ -484,77 +525,89 @@ Js.Math.log2(512.0) == 9.0 Js.Math.log2(0.125) == -3.0 Js.Math.log2(Js.Math._SQRT2) == 0.5000000000000001 // due to precision ``` -*) +") +external log2: float => float = "log2" -external max_int : int -> int -> int = "max" -[@@val] [@@scope "Math"] -(** +@val +@scope("Math") +@ocaml.doc(" Returns the maximum of its two integer arguments. See [`Math.max`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/max) on MDN. -*) +") +external max_int: (int, int) => int = "max" -external maxMany_int : int array -> int = "max" -[@@val] [@@variadic] [@@scope "Math"] -(** +@val +@variadic +@scope("Math") +@ocaml.doc(" Returns the maximum of the integers in the given array. See [`Math.max`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/max) on MDN. -*) +") +external maxMany_int: array => int = "max" -external max_float : float -> float -> float = "max" -[@@val] [@@scope "Math"] -(** +@val +@scope("Math") +@ocaml.doc(" Returns the maximum of its two floating point arguments. See [`Math.max`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/max) on MDN. -*) +") +external max_float: (float, float) => float = "max" -external maxMany_float : float array -> float = "max" -[@@val] [@@variadic] [@@scope "Math"] -(** +@val +@variadic +@scope("Math") +@ocaml.doc(" Returns the maximum of the floating point values in the given array. See [`Math.max`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/max) on MDN. -*) +") +external maxMany_float: array => float = "max" -external min_int : int -> int -> int = "min" -[@@val] [@@scope "Math"] -(** +@val +@scope("Math") +@ocaml.doc(" Returns the minimum of its two integer arguments. See [`Math.min`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/min) on MDN. -*) +") +external min_int: (int, int) => int = "min" -external minMany_int : int array -> int = "min" -[@@val] [@@variadic] [@@scope "Math"] -(** +@val +@variadic +@scope("Math") +@ocaml.doc(" Returns the minimum of the integers in the given array. See [`Math.min`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/min) on MDN. -*) +") +external minMany_int: array => int = "min" -external min_float : float -> float -> float = "min" -[@@val] [@@scope "Math"] -(** +@val +@scope("Math") +@ocaml.doc(" Returns the minimum of its two floating point arguments. See [`Math.min`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/min) on MDN. -*) +") +external min_float: (float, float) => float = "min" -external minMany_float : float array -> float = "min" -[@@val] [@@variadic] [@@scope "Math"] -(** +@val +@variadic +@scope("Math") +@ocaml.doc(" Returns the minimum of the floating point values in the given array. See [`Math.min`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/min) on MDN. -*) +") +external minMany_float: array => float = "min" -external pow_int : base:int -> exp:int -> int = "pow" -[@@val] -[@@scope "Math"] -[@@deprecated "use `pow_float` instead, the return type may be not int"] -(** +@val +@scope("Math") +@deprecated("use `pow_float` instead, the return type may be not int") +@ocaml.doc(" Raises the given base to the given exponent. (Arguments and result are integers.) See [`Math.pow`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/pow) @@ -565,11 +618,12 @@ on MDN. ```rescript Js.Math.pow_int(~base=3, ~exp=4) == 81 ``` -*) +") +external pow_int: (~base: int, ~exp: int) => int = "pow" -external pow_float : base:float -> exp:float -> float = "pow" -[@@val] [@@scope "Math"] -(** +@val +@scope("Math") +@ocaml.doc(" Raises the given base to the given exponent. (Arguments and result are floats.) Returns `NaN` if the result would be imaginary. See [`Math.pow`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/pow) @@ -584,27 +638,29 @@ Js.Math.pow_float(~base=625.0, ~exp=0.5) == 25.0 Js.Math.pow_float(~base=625.0, ~exp=-0.5) == 0.04 Js.Float.isNaN(Js.Math.pow_float(~base=-2.0, ~exp=0.5)) == true ``` -*) +") +external pow_float: (~base: float, ~exp: float) => float = "pow" -external random : unit -> float = "random" -[@@val] [@@scope "Math"] -(** +@val +@scope("Math") +@ocaml.doc(" Returns a random number in the half-closed interval [0,1). See [`Math.random`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/random) on MDN. -*) +") +external random: unit => float = "random" -(** +@ocaml.doc(" A call to `random_int(minVal, maxVal)` returns a random number in the half-closed interval [minVal, maxVal). See [`Math.random`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/random) on MDN. -*) -let random_int min max = floor (random () *. Js_int.toFloat (max - min)) + min +") +let random_int = (min, max) => floor(random() *. Js_int.toFloat(max - min)) + min -external unsafe_round : float -> int = "round" -[@@val] [@@scope "Math"] -(** +@val +@scope("Math") +@ocaml.doc(" Rounds its argument to nearest integer. For numbers with a fractional portion of exactly 0.5, the argument is rounded to the next integer in the direction of positive infinity. This function may return values not representable by @@ -621,78 +677,87 @@ Js.Math.unsafe_round(3.7) == 4 Js.Math.unsafe_round(-3.5) == -3 Js.Math.unsafe_round(2_150_000_000_000.3) // out of range for int ``` -*) +") +external unsafe_round: float => int = "round" -external round : float -> float = "round" -[@@val] [@@scope "Math"] -(** +@val +@scope("Math") +@ocaml.doc(" Rounds to nearest integral value (expressed as a float). See [`Math.round`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/round) on MDN. -*) +") +external round: float => float = "round" -external sign_int : int -> int = "sign" -[@@val] [@@scope "Math"] -(** +@val +@scope("Math") +@ocaml.doc(" Returns the sign of its integer argument: -1 if negative, 0 if zero, 1 if positive. See [`Math.sign`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/sign) on MDN. -*) +") +external sign_int: int => int = "sign" -external sign_float : float -> float = "sign" -[@@val] [@@scope "Math"] -(** +@val +@scope("Math") +@ocaml.doc(" Returns the sign of its float argument: -1.0 if negative, 0.0 if zero, 1.0 if positive. See [`Math.sign`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/sign) on MDN. -*) +") +external sign_float: float => float = "sign" -external sin : float -> float = "sin" -[@@val] [@@scope "Math"] -(** +@val +@scope("Math") +@ocaml.doc(" Sine of argument, which must be specified in radians. See [`Math.sin`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/sin) on MDN. -*) +") +external sin: float => float = "sin" -external sinh : float -> float = "sinh" -[@@val] [@@scope "Math"] -(** +@val +@scope("Math") +@ocaml.doc(" Hyperbolic sine of argument, which must be specified in radians. See [`Math.sinh`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/sinh) on MDN. -*) +") +external sinh: float => float = "sinh" -external sqrt : float -> float = "sqrt" -[@@val] [@@scope "Math"] -(** +@val +@scope("Math") +@ocaml.doc(" Square root. If the argument is negative, this function returns `NaN`. See [`Math.sqrt`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/sqrt) on MDN. -*) +") +external sqrt: float => float = "sqrt" -external tan : float -> float = "tan" -[@@val] [@@scope "Math"] -(** +@val +@scope("Math") +@ocaml.doc(" Tangent of argument, which must be specified in radians. Returns `NaN` if the argument is positive infinity or negative infinity. See [`Math.cos`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/cos) on MDN. -*) +") +external tan: float => float = "tan" -external tanh : float -> float = "tanh" -[@@val] [@@scope "Math"] -(** +@val +@scope("Math") +@ocaml.doc(" Hyperbolic tangent of argument, which must be specified in radians. See [`Math.tanh`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/tanh) on MDN. -*) +") +external tanh: float => float = "tanh" -external unsafe_trunc : float -> int = "trunc" -[@@val] [@@scope "Math"] -(** +@val +@scope("Math") +@ocaml.doc(" Truncates its argument; i.e., removes fractional digits. This function may return values not representable by `int`, whose range is -2147483648 to 2147483647. This is because, in JavaScript, there are only 64-bit floating @@ -700,12 +765,14 @@ point numbers, which can represent integers in the range ±(253-1) exactly. See [`Math.trunc`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/trunc) on MDN. -*) +") +external unsafe_trunc: float => int = "trunc" -external trunc : float -> float = "trunc" -[@@val] [@@scope "Math"] -(** +@val +@scope("Math") +@ocaml.doc(" Truncates its argument; i.e., removes fractional digits. See [`Math.trunc`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/trunc) on MDN. -*) +") +external trunc: float => float = "trunc" diff --git a/jscomp/others/release.ninja b/jscomp/others/release.ninja index 86a92b89f8..e2424da2d3 100644 --- a/jscomp/others/release.ninja +++ b/jscomp/others/release.ninja @@ -39,7 +39,7 @@ o others/js_list.cmi : cc others/js_list.resi | others/belt_internals.cmi others o others/js_map.cmi others/js_map.cmj : cc others/js_map.res | others/belt_internals.cmi others/js.cmi $bsc o others/js_mapperRt.cmj : cc_cmi others/js_mapperRt.res | others/belt_internals.cmi others/js.cmi others/js.cmj others/js_mapperRt.cmi $bsc o others/js_mapperRt.cmi : cc others/js_mapperRt.resi | others/belt_internals.cmi others/js.cmi $bsc -o others/js_math.cmi others/js_math.cmj : cc others/js_math.ml | others/belt_internals.cmi others/js.cmi others/js_int.cmj $bsc +o others/js_math.cmi others/js_math.cmj : cc others/js_math.res | others/belt_internals.cmi others/js.cmi others/js_int.cmj $bsc o others/js_null.cmj : cc_cmi others/js_null.res | others/belt_internals.cmi others/js.cmi others/js.cmj others/js_exn.cmj others/js_null.cmi $bsc o others/js_null.cmi : cc others/js_null.resi | others/belt_internals.cmi others/js.cmi others/js.cmj $bsc o others/js_null_undefined.cmj : cc_cmi others/js_null_undefined.res | others/belt_internals.cmi others/js.cmi others/js.cmj others/js_null_undefined.cmi $bsc @@ -75,7 +75,7 @@ o others/jsxPPXReactSupportC.cmi others/jsxPPXReactSupportC.cmj : cc others/jsxP o others/jsxPPXReactSupportU.cmi others/jsxPPXReactSupportU.cmj : cc others/jsxPPXReactSupportU.res | others/belt_internals.cmi others/js.cmi others/jsxU.cmj $bsc o others/jsxU.cmi others/jsxU.cmj : cc others/jsxU.res | others/belt_internals.cmi others/js.cmi $bsc o js_pkg : phony others/js_OO.cmi others/js_OO.cmj others/js_array.cmi others/js_array.cmj others/js_array2.cmi others/js_array2.cmj others/js_bigint.cmi others/js_bigint.cmj others/js_blob.cmi others/js_blob.cmj others/js_cast.cmi others/js_cast.cmj others/js_console.cmi others/js_console.cmj others/js_date.cmi others/js_date.cmj others/js_dict.cmi others/js_dict.cmj others/js_exn.cmi others/js_exn.cmj others/js_file.cmi others/js_file.cmj others/js_float.cmi others/js_float.cmj others/js_global.cmi others/js_global.cmj others/js_int.cmi others/js_int.cmj others/js_json.cmi others/js_json.cmj others/js_list.cmi others/js_list.cmj others/js_map.cmi others/js_map.cmj others/js_mapperRt.cmi others/js_mapperRt.cmj others/js_math.cmi others/js_math.cmj others/js_null.cmi others/js_null.cmj others/js_null_undefined.cmi others/js_null_undefined.cmj others/js_obj.cmi others/js_obj.cmj others/js_option.cmi others/js_option.cmj others/js_promise.cmi others/js_promise.cmj others/js_promise2.cmi others/js_promise2.cmj others/js_re.cmi others/js_re.cmj others/js_result.cmi others/js_result.cmj others/js_set.cmi others/js_set.cmj others/js_string.cmi others/js_string.cmj others/js_string2.cmi others/js_string2.cmj others/js_typed_array.cmi others/js_typed_array.cmj others/js_typed_array2.cmi others/js_typed_array2.cmj others/js_types.cmi others/js_types.cmj others/js_undefined.cmi others/js_undefined.cmj others/js_vector.cmi others/js_vector.cmj others/js_weakmap.cmi others/js_weakmap.cmj others/js_weakset.cmi others/js_weakset.cmj others/jsxC.cmi others/jsxC.cmj others/jsxDOMC.cmi others/jsxDOMC.cmj others/jsxDOMStyle.cmi others/jsxDOMStyle.cmj others/jsxDOMU.cmi others/jsxDOMU.cmj others/jsxEventC.cmi others/jsxEventC.cmj others/jsxEventU.cmi others/jsxEventU.cmj others/jsxPPXReactSupportC.cmi others/jsxPPXReactSupportC.cmj others/jsxPPXReactSupportU.cmi others/jsxPPXReactSupportU.cmj others/jsxU.cmi others/jsxU.cmj -o others/belt_Array.cmj : cc_cmi others/belt_Array.res | others/belt.cmi others/belt_Array.cmi others/belt_internals.cmi others/js.cmi others/js.cmj others/js_math.cmj $bsc js_pkg +o others/belt_Array.cmj : cc_cmi others/belt_Array.res | others/belt.cmi others/belt_Array.cmi others/belt_internals.cmi others/js.cmi others/js.cmj $bsc js_pkg o others/belt_Array.cmi : cc others/belt_Array.resi | others/belt.cmi others/belt_internals.cmi others/js.cmi others/js.cmj $bsc js_pkg o others/belt_Float.cmj : cc_cmi others/belt_Float.res | others/belt.cmi others/belt_Float.cmi others/belt_internals.cmi others/js.cmi $bsc js_pkg o others/belt_Float.cmi : cc others/belt_Float.resi | others/belt_internals.cmi others/js.cmi $bsc diff --git a/jscomp/runtime/caml_format.ml b/jscomp/runtime/caml_format.ml deleted file mode 100644 index 482ddff684..0000000000 --- a/jscomp/runtime/caml_format.ml +++ /dev/null @@ -1,683 +0,0 @@ - - -(* - * Js_of_ocaml runtime support - * http://www.ocsigen.org/js_of_ocaml/ - * Copyright (C) 2010 Jérôme Vouillon - * Laboratoire PPS - CNRS Université Paris Diderot - * Copyright (C) 2015-2016 Bloomberg Finance L.P. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published * by - * the Free Software Foundation, with linking exception; - * either version 2.1 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - *) - - - -external (.![]) : string -> int -> int = "%string_unsafe_get" -external (.!()) : string -> int -> char = "%string_unsafe_get" - -let code_0 = "0".![0] -let code_a = "a".![0] -let code_A = "A".![0] - -module Caml_char = struct - external code : char -> int = "%identity" - external unsafe_chr : int -> char = "%identity" -end - -let failwith s = raise (Failure s) -(* let invalid_argument s= raise (Invalid_argument s ) *) - -let (>>>) = Caml_nativeint_extern.shift_right_logical - - - -let (+~) = Caml_nativeint_extern.add -let ( *~ ) = Caml_nativeint_extern.mul - -let parse_digit c = - match c with - | '0' .. '9' - -> Caml_char.code c - code_0 - | 'A' .. 'Z' - -> Caml_char.code c - (code_A - 10) - | 'a' .. 'z' - -> Caml_char.code c - (code_a - 10 ) - | _ -> -1 - -type of_string_base = - | Oct - | Hex - | Dec - | Bin - -let int_of_string_base = function - | Oct -> 8 - | Hex -> 16 - | Dec -> 10 - | Bin -> 2 - -let parse_sign_and_base (s : string) = - let sign = ref 1 in - let base = ref Dec in - let i = ref 0 in - (match s.!(i.contents) with - | '-' -> - sign .contents<- -1; - i.contents <- i.contents + 1 - | '+' -> - i.contents <- i.contents + 1 - | _ -> ()); - if s.!(i.contents) = '0' then - (match s.!(i.contents + 1) with - | ('x' | 'X') - -> base .contents<- Hex; i.contents<- i.contents + 2 - | ( 'o' | 'O') - -> base .contents<- Oct; i .contents<- i.contents + 2 - | ('b' | 'B' ) - -> base .contents<- Bin; i .contents<- i.contents + 2 - | ('u' | 'U') - -> i .contents<- i.contents + 2 - | _ -> ()); - (i.contents, sign.contents, base.contents) - - -let int_of_string (s : string) : int = - let i, sign, hbase = parse_sign_and_base s in - let base = int_of_string_base hbase in - let threshold = (-1 >>> 0) in - let len =Caml_string_extern.length s in - let c = if i < len then s.!(i) else '\000' in - let d = parse_digit c in - let () = - if d < 0 || d >= base then - failwith "int_of_string" in - (* let () = [%debugger] in *) - let rec aux acc k = - if k = len then acc - else - let a = s.!(k) in - if a = '_' then aux acc ( k + 1) - else - let v = parse_digit a in - if v < 0 || v >= base then - failwith "int_of_string" - else - let acc = base *~ acc +~ v in - if acc > threshold then - failwith "int_of_string" - else aux acc ( k + 1) - in - let res = sign *~ aux d (i + 1) in - let or_res = res lor 0 in - (if base = 10 && res <> or_res then - failwith "int_of_string"); - or_res - -let hex_threshold, - dec_threshold, - oct_threshold, - bin_threshold = - 1152921504606846975L, - 1844674407370955161L, - 2305843009213693951L, - 9223372036854775807L - -let int64_of_string s = - let i, sign, hbase = parse_sign_and_base s in - let base = Caml_int64_extern.of_int (int_of_string_base hbase) in - let sign = Caml_int64_extern.of_int sign in - let threshold = - match hbase with - | Hex -> (* 2 ^ 64 - 1 / 16*) - hex_threshold - | Dec -> - dec_threshold - | Oct -> - oct_threshold - | Bin -> - bin_threshold - in - let len =Caml_string_extern.length s in - let c = if i < len then s.!(i) else '\000' in - let d = Caml_int64_extern.of_int (parse_digit c) in - let () = - if d < 0L || d >= base then - failwith "int64_of_string" in - let (+~) = Caml_int64_extern.add in - let ( *~ ) = Caml_int64_extern.mul in - - let rec aux acc k = - if k = len then acc - else - let a = s.!(k) in - if a = '_' then aux acc ( k + 1) - else - let v = Caml_int64_extern.of_int (parse_digit a) in - if v < 0L || v >= base || acc > threshold then - failwith "int64_of_string" - else - let acc = base *~ acc +~ v in - aux acc ( k + 1) - in - let res = sign *~ aux d (i + 1) in - let or_res = Caml_int64_extern.logor res 0L in - (if base = 10L && res <> or_res then - failwith "int64_of_string"); - or_res - -type base = - | Oct | Hex | Dec -let int_of_base = function - | Oct -> 8 - | Hex -> 16 - | Dec -> 10 - -type fmt = { - mutable justify : string; - mutable signstyle : string; - mutable filter : string ; - mutable alternate : bool; - mutable base : base; - mutable signedconv : bool; - mutable width :int; - mutable uppercase : bool; - mutable sign : int; - mutable prec : int; - mutable conv : string -} - -let lowercase (c : char) : char = - if (c >= 'A' && c <= 'Z') - || (c >= '\192' && c <= '\214') - || (c >= '\216' && c <= '\222') - then Caml_char.unsafe_chr(Caml_char.code c + 32) - else c - -let parse_format fmt = - let module String = Caml_string_extern in - let len =Caml_string_extern.length fmt in - if len > 31 then - raise (Invalid_argument "format_int: format too long") ; - let rec aux (f : fmt) i : fmt = - if i >= len then f - else - let c = fmt.[i] in - match c with - | '-' -> - f.justify <- "-"; - aux f (i + 1) - | '+'|' ' - -> - f.signstyle <- Caml_string_extern.of_char c ; - aux f (i + 1) - | '#' -> - f.alternate <- true; - aux f (i + 1) - | '0' -> - f.filter <- "0"; - aux f (i + 1) - | '1' .. '9' - -> - begin - f.width <- 0; - let j = ref i in - - while (let w = fmt.![j.contents] - code_0 in w >=0 && w <= 9 ) do - f.width <- f.width * 10 + fmt.![j.contents] - code_0; - j.contents <- j.contents + 1 - done; - aux f j.contents - end - | '.' - -> - f.prec <- 0; - let j = ref (i + 1 ) in - while (let w = fmt.![j.contents] - code_0 in w >=0 && w <= 9 ) do - f.prec <- f.prec * 10 + fmt.![j.contents] - code_0; - j.contents <- j.contents + 1; - done; - aux f j.contents - | 'd' - | 'i' -> - f.signedconv <- true; - f.base <- Dec; - aux f (i + 1) - | 'u' -> - f.base <- Dec; - aux f (i + 1) - | 'x' -> - f.base <- Hex; - aux f (i + 1) - | 'X' -> - f.base <- Hex; - f.uppercase <- true; - aux f (i + 1) - | 'o' -> - f.base <- Oct; - aux f (i + 1) - (* | 'O' -> base .contents<- 8; uppercase .contents<- true no uppercase for oct *) - | 'e' | 'f' | 'g' - -> - f.signedconv <- true; - f.conv <- Caml_string_extern.of_char c ; - aux f (i + 1) - | 'E' | 'F' | 'G' - -> - f.signedconv <- true; - f.uppercase <- true; - f.conv <- Caml_string_extern.of_char (lowercase c); - aux f (i + 1) - | _ -> - aux f (i + 1) - in - aux { justify = "+" ; - signstyle = "-"; - filter = " " ; - alternate = false ; - base= Dec ; - signedconv= false ; - width = 0 ; - uppercase= false ; - sign = 1 ; - prec = (-1); - conv = "f"} 0 - - - -let finish_formatting (config : fmt) rawbuffer = - let { - justify; - signstyle; - filter ; - alternate; - base; - signedconv; - width; - uppercase; - sign; - prec = _ ; - conv = _ ; - } = config in - let len = ref (Caml_string_extern.length rawbuffer) in - if signedconv && (sign < 0 || signstyle <> "-") then - len.contents <- len.contents + 1; - if alternate then - begin - if base = Oct then - len.contents <- len.contents + 1 - else - if base = Hex then - len.contents<- len.contents + 2 - else () - end ; - let buffer = ref "" in - (* let (+=) buffer s = buffer .contents<- buffer.contents ^ s in - FIXME: should get inlined - *) - (* let (+:) s = buffer .contents<- buffer.contents ^ s in *) - if justify = "+" && filter = " " then - for _ = len.contents to width - 1 do - buffer.contents<- buffer.contents ^ filter - done; - if signedconv then - if sign < 0 then - buffer .contents<- buffer.contents ^ "-" - else if signstyle <> "-" then - buffer .contents<- buffer.contents ^ signstyle - else () ; - if alternate && base = Oct then - buffer .contents<- buffer.contents ^ "0"; - if alternate && base == Hex then - buffer .contents<- buffer.contents ^ "0x"; - - if justify = "+" && filter = "0" then - for _ = len.contents to width - 1 do - buffer .contents<- buffer.contents ^ filter; - done; - begin - if uppercase then - buffer .contents<- buffer.contents ^ Caml_string_extern.toUpperCase rawbuffer - else - buffer .contents<- buffer.contents ^ rawbuffer - end; - if justify = "-" then - for _ = len.contents to width - 1 do - buffer .contents<- buffer.contents ^ " "; - done; - buffer.contents - - - -let aux f (i : int) : string = - let i = - if i < 0 then - if f.signedconv then - begin - f.sign <- -1; - (-i)>>>0 - (* when i is min_int, [-i] could overflow *) - end - else - i >>> 0 - else i in - let s = ref (Caml_string_extern.of_int i ~base:(int_of_base f.base)) in - if f.prec >= 0 then - begin - f.filter <- " "; - let n = f.prec -Caml_string_extern.length s.contents in - if n > 0 then - s .contents<- Caml_string_extern.repeat "0" n ^ s.contents - end ; - finish_formatting f s.contents - -let format_int fmt i = - if fmt = "%d" then Caml_nativeint_extern.to_string i - else - let f = parse_format fmt in - aux f i - -(* This can handle unsigned integer (-1L) and print it as "%Lu" which - will overflow signed integer in general -*) -let dec_of_pos_int64 x = - - - (if x < 0L then - - let wbase = 10L in - let cvtbl = "0123456789" in - let y = Caml_int64.discard_sign x in - (* 2 ^ 63 + y `div_mod` 10 *) - - let quotient_l = 922337203685477580L (* 2 ^ 63 / 10 *) - (* {lo = -858993460n; hi = 214748364n} *) - (* TODO: int64 constant folding so that we can do idiomatic code - 2 ^ 63 / 10 *)in - let modulus_l = 8L in - (* let c, d = Caml_int64.div_mod (Caml_int64.add y modulus_l) wbase in - we can not do the code above, it can overflow when y is really large - *) - let c, d = Caml_int64.div_mod y wbase in - let e ,f = Caml_int64.div_mod (Caml_int64_extern.add modulus_l d) wbase in - let quotient = - (Caml_int64_extern.add (Caml_int64_extern.add quotient_l c ) - e) in - Caml_int64.to_string quotient ^ - (Caml_string_extern.get_string_unsafe - cvtbl (Caml_int64_extern.to_int f)) - else - Caml_int64.to_string x) - -let oct_of_int64 x = - let s = ref "" in - let wbase = 8L in - let cvtbl = "01234567" in - (if x < 0L then - begin - let y = Caml_int64.discard_sign x in - (* 2 ^ 63 + y `div_mod` 8 *) - let quotient_l = 1152921504606846976L - (* {lo = 0n; hi = 268435456n } *) (* 2 ^ 31 / 8 *) - in - - (* let c, d = Caml_int64.div_mod (Caml_int64.add y modulus_l) wbase in - we can not do the code above, it can overflow when y is really large - *) - let c, d = Caml_int64.div_mod y wbase in - - let quotient = - ref (Caml_int64_extern.add quotient_l c ) in - let modulus = ref d in - s .contents<- - Caml_string_extern.get_string_unsafe - cvtbl (Caml_int64_extern.to_int modulus.contents) ^ s.contents ; - - while quotient.contents <> 0L do - let a, b = Caml_int64.div_mod quotient.contents wbase in - quotient .contents<- a; - modulus .contents<- b; - s .contents<- Caml_string_extern.get_string_unsafe cvtbl (Caml_int64_extern.to_int modulus.contents) ^ s.contents ; - done; - end - else - let a, b = Caml_int64.div_mod x wbase in - let quotient = ref a in - let modulus = ref b in - s .contents<- - Caml_string_extern.get_string_unsafe - cvtbl (Caml_int64_extern.to_int modulus.contents) ^ s.contents ; - - while quotient.contents <> 0L do - let a, b = Caml_int64.div_mod (quotient.contents) wbase in - quotient .contents<- a; - modulus .contents<- b; - s .contents<- Caml_string_extern.get_string_unsafe cvtbl (Caml_int64_extern.to_int modulus.contents) ^ s.contents ; - done); s.contents - - -(* FIXME: improve codegen for such cases - let div_mod (x : int64) (y : int64) : int64 * int64 = - let a, b = Caml_int64.(div_mod (unsafe_of_int64 x) (unsafe_of_int64 y)) in - Caml_int64.unsafe_to_int64 a , Caml_int64.unsafe_to_int64 b -*) -let int64_format fmt x = - if fmt = "%d" then Caml_int64.to_string x - else - let f = parse_format fmt in - let x = - if f.signedconv && x < 0L then - begin - f.sign <- -1; - Caml_int64_extern.neg x - end - else x in - let s = - - begin match f.base with - | Hex -> - Caml_int64.to_hex x - | Oct -> - oct_of_int64 x - | Dec -> - dec_of_pos_int64 x - end in - let fill_s = - if f.prec >= 0 then - begin - f.filter <- " "; - let n = f.prec -Caml_string_extern.length s in - if n > 0 then - ("0" |. Caml_string_extern.repeat n) ^ s else s - end else s in - - finish_formatting f fill_s - -let format_float fmt x = - let module String = Caml_string_extern in - let f = parse_format fmt in - let prec = if f.prec < 0 then 6 else f.prec in - let x = if x < 0. then (f.sign <- (-1); -. x) else x in - let s = ref "" in - if Caml_float_extern.isNaN x then - begin - s .contents<- "nan"; - f.filter <- " " - end - else if not (Caml_float_extern.isFinite x) then - begin - s .contents<- "inf"; - f.filter <- " " - end - else - begin - match f.conv with - | "e" - -> - s .contents<- Caml_float_extern.toExponentialWithPrecision x ~digits:prec; - (* exponent should be at least two digits - {[ - (3.3).toExponential() - "3.3e+0" - 3.3e+00 - ]} - *) - let i =Caml_string_extern.length s.contents in - if s.contents.[i-3] = 'e' then - begin - s .contents<- Caml_string_extern.slice s.contents 0 (i - 1) ^ "0" ^ Caml_string_extern.slice_rest s.contents (i - 1) - end - | "f" - -> - (* this will not work large numbers *) - (* ("%3.10f", 3e+56, "300000000000000005792779041490073052596128503513888063488.0000000000") *) - s .contents<- Caml_float_extern.toFixedWithPrecision x ~digits:prec - | "g" -> - let prec = if prec <> 0 then prec else 1 in - s .contents<- Caml_float_extern.toExponentialWithPrecision x ~digits:(prec - 1); - let j = Caml_string_extern.index_of s.contents "e" in - let exp = Caml_float.int_of_float (Caml_float_extern.fromString (Caml_string_extern.slice_rest s.contents (j + 1))) in - if exp < -4 || x >= 1e21 ||Caml_string_extern.length (Caml_float_extern.toFixed x) > prec then - let i = ref (j - 1) in - while s.contents.[i.contents] = '0' do - i.contents <- i.contents - 1 - done; - if s.contents.[i.contents] = '.' then - i.contents <- i.contents - 1 ; - s .contents<- Caml_string_extern.slice s.contents 0 (i.contents+1) ^ Caml_string_extern.slice_rest s.contents j ; - let i =Caml_string_extern.length s.contents in - if s.contents.[i - 3] = 'e' then - s .contents<- Caml_string_extern.slice s.contents 0 (i - 1) ^ "0" ^ Caml_string_extern.slice_rest s.contents (i - 1) - else () - else - let p = ref prec in - if exp < 0 then - begin - p.contents<- p.contents - (exp + 1); - s.contents<- Caml_float_extern.toFixedWithPrecision x ~digits:p.contents - end - else - while (s .contents<- Caml_float_extern.toFixedWithPrecision x ~digits:p.contents;Caml_string_extern.length s.contents > prec + 1) do - p.contents <- p.contents - 1 - done ; - if p.contents <> 0 then - let k = ref (Caml_string_extern.length s.contents - 1) in - while s.contents.[k.contents] = '0' do - k.contents <- k.contents - 1 - done ; - if s.contents.[k.contents] = '.' then - k.contents <- k.contents - 1 ; - s .contents<- Caml_string_extern.slice s.contents 0 (k.contents + 1) - - | _ -> () - end; - finish_formatting f s.contents - - - - -let hexstring_of_float : float -> int -> char -> string = - [%raw{|function(x,prec,style){ - if (!isFinite(x)) { - if (isNaN(x)) return "nan"; - return x > 0 ? "infinity":"-infinity"; - } - var sign = (x==0 && 1/x == -Infinity)?1:(x>=0)?0:1; - if(sign) x = -x; - var exp = 0; - if (x == 0) { } - else if (x < 1) { - while (x < 1 && exp > -1022) { x *= 2; exp-- } - } else { - while (x >= 2) { x /= 2; exp++ } - } - var exp_sign = exp < 0 ? '' : '+'; - var sign_str = ''; - if (sign) sign_str = '-' - else { - switch(style){ - case 43 /* '+' */: sign_str = '+'; break; - case 32 /* ' ' */: sign_str = ' '; break; - default: break; - } - } - if (prec >= 0 && prec < 13) { - /* If a precision is given, and is small, round mantissa accordingly */ - var cst = Math.pow(2,prec * 4); - x = Math.round(x * cst) / cst; - } - var x_str = x.toString(16); - if(prec >= 0){ - var idx = x_str.indexOf('.'); - if(idx<0) { - x_str += '.' + '0'.repeat(prec); - } - else { - var size = idx+1+prec; - if(x_str.length < size) - x_str += '0'.repeat(size - x_str.length); - else - x_str = x_str.substr(0,size); - } - } - return (sign_str + '0x' + x_str + 'p' + exp_sign + exp.toString(10)); -}|}] - - -let float_of_string : string -> exn -> float = - [%raw{|function(s,exn){ - - var res = +s; - if ((s.length > 0) && (res === res)) - return res; - s = s.replace(/_/g, ""); - res = +s; - if (((s.length > 0) && (res === res)) || /^[+-]?nan$/i.test(s)) { - return res; - }; - var m = /^ *([+-]?)0x([0-9a-f]+)\.?([0-9a-f]*)p([+-]?[0-9]+)/i.exec(s); - // 1 2 3 4 - if(m){ - var m3 = m[3].replace(/0+$/,''); - var mantissa = parseInt(m[1] + m[2] + m3, 16); - var exponent = (m[4]|0) - 4*m3.length; - res = mantissa * Math.pow(2, exponent); - return res; - } - if (/^\+?inf(inity)?$/i.test(s)) - return Infinity; - if (/^-inf(inity)?$/i.test(s)) - return -Infinity; - throw new Error(exn.RE_EXN_ID, { cause: exn });; -} -|}] - - - -(** - Pervasives.float_of_string : string -> float = "?float_of_string" - Semantics is slightly different from javascript : - console.assert(float_of_string('infinity')===Infinity) - console.assert(float_of_string('Infinity')===Infinity - parseFloat('Infinity') === Infinity - parseFloat('infinity') === Nan -*) -let float_of_string (s : string) : float = - float_of_string s (Failure "float_of_string") - - - - - - diff --git a/jscomp/runtime/caml_format.mli b/jscomp/runtime/caml_format.mli deleted file mode 100644 index 5dbe9d902e..0000000000 --- a/jscomp/runtime/caml_format.mli +++ /dev/null @@ -1,46 +0,0 @@ -(* Copyright (C) 2015-2016 Bloomberg Finance L.P. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * In addition to the permissions granted to you by the LGPL, you may combine - * or link a "work that uses the Library" with a publicly distributed version - * of this file to produce a combined library or application, then distribute - * that combined work under the terms of your choosing, with no requirement - * to comply with the obligations normally placed on you by section 4 of the - * LGPL version 3 (or the corresponding section of a later version of the LGPL - * should you choose to use a later version). - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *) - - - - - - - -(** *) - -val format_float : string -> float -> string - -val hexstring_of_float : float -> int -> char -> string - -val format_int : string -> int -> string - - - -val float_of_string : string -> float -val int64_format : string -> int64 -> string -val int_of_string : string -> int - -val int64_of_string : string -> int64 - diff --git a/jscomp/runtime/caml_format.res b/jscomp/runtime/caml_format.res new file mode 100644 index 0000000000..3dc37757f7 --- /dev/null +++ b/jscomp/runtime/caml_format.res @@ -0,0 +1,724 @@ +/* + * Js_of_ocaml runtime support + * http://www.ocsigen.org/js_of_ocaml/ + * Copyright (C) 2010 Jérôme Vouillon + * Laboratoire PPS - CNRS Université Paris Diderot + * Copyright (C) 2015-2016 Bloomberg Finance L.P. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published * by + * the Free Software Foundation, with linking exception; + * either version 2.1 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +external \".![]": (string, int) => int = "%string_unsafe_get" +external \".!()": (string, int) => char = "%string_unsafe_get" + +let code_0 = 48 // '0' +let code_a = 97 // 'a' +let code_A = 65 // 'A' + +module Caml_char = { + external code: char => int = "%identity" + external unsafe_chr: int => char = "%identity" +} + +let failwith = s => raise(Failure(s)) +/* let invalid_argument s= raise (Invalid_argument s ) */ + +let \">>>" = Caml_nativeint_extern.shift_right_logical + +let \"+~" = Caml_nativeint_extern.add +let \"*~" = Caml_nativeint_extern.mul + +let parse_digit = c => + switch c { + | '0' .. '9' => Caml_char.code(c) - code_0 + | 'A' .. 'Z' => Caml_char.code(c) - (code_A - 10) + | 'a' .. 'z' => Caml_char.code(c) - (code_a - 10) + | _ => -1 + } + +type of_string_base = + | Oct + | Hex + | Dec + | Bin + +let int_of_string_base = x => + switch x { + | Oct => 8 + | Hex => 16 + | Dec => 10 + | Bin => 2 + } + +let parse_sign_and_base = (s: string) => { + let sign = ref(1) + let base = ref(Dec) + let i = ref(0) + switch \".!()"(s, i.contents) { + | '-' => + sign.contents = -1 + i.contents = i.contents + 1 + | '+' => i.contents = i.contents + 1 + | _ => () + } + if \".!()"(s, i.contents) == '0' { + switch \".!()"(s, i.contents + 1) { + | 'x' | 'X' => + base.contents = Hex + i.contents = i.contents + 2 + | 'o' | 'O' => + base.contents = Oct + i.contents = i.contents + 2 + | 'b' | 'B' => + base.contents = Bin + i.contents = i.contents + 2 + | 'u' | 'U' => i.contents = i.contents + 2 + | _ => () + } + } + (i.contents, sign.contents, base.contents) +} + +let int_of_string = (s: string): int => { + let (i, sign, hbase) = parse_sign_and_base(s) + let base = int_of_string_base(hbase) + let threshold = \">>>"(-1, 0) + let len = Caml_string_extern.length(s) + let c = if i < len { + \".!()"(s, i) + } else { + '\000' + } + let d = parse_digit(c) + let () = if d < 0 || d >= base { + failwith("int_of_string") + } + /* let () = [%debugger] in */ + let rec aux = (acc, k) => + if k == len { + acc + } else { + let a = \".!()"(s, k) + if a == '_' { + aux(acc, k + 1) + } else { + let v = parse_digit(a) + if v < 0 || v >= base { + failwith("int_of_string") + } else { + let acc = \"+~"(\"*~"(base, acc), v) + if acc > threshold { + failwith("int_of_string") + } else { + aux(acc, k + 1) + } + } + } + } + + let res = \"*~"(sign, aux(d, i + 1)) + let or_res = lor(res, 0) + if base == 10 && res != or_res { + failwith("int_of_string") + } + or_res +} + +let (hex_threshold, dec_threshold, oct_threshold, bin_threshold) = ( + 1152921504606846975L, + 1844674407370955161L, + 2305843009213693951L, + 9223372036854775807L, +) + +let int64_of_string = s => { + let (i, sign, hbase) = parse_sign_and_base(s) + let base = Caml_int64_extern.of_int(int_of_string_base(hbase)) + let sign = Caml_int64_extern.of_int(sign) + let threshold = switch hbase { + | Hex => /* 2 ^ 64 - 1 / 16 */ + hex_threshold + | Dec => dec_threshold + | Oct => oct_threshold + | Bin => bin_threshold + } + + let len = Caml_string_extern.length(s) + let c = if i < len { + \".!()"(s, i) + } else { + '\000' + } + let d = Caml_int64_extern.of_int(parse_digit(c)) + let () = if d < 0L || d >= base { + failwith("int64_of_string") + } + let \"+~" = Caml_int64_extern.add + let \"*~" = Caml_int64_extern.mul + + let rec aux = (acc, k) => + if k == len { + acc + } else { + let a = \".!()"(s, k) + if a == '_' { + aux(acc, k + 1) + } else { + let v = Caml_int64_extern.of_int(parse_digit(a)) + if v < 0L || (v >= base || acc > threshold) { + failwith("int64_of_string") + } else { + let acc = \"+~"(\"*~"(base, acc), v) + aux(acc, k + 1) + } + } + } + + let res = \"*~"(sign, aux(d, i + 1)) + let or_res = Caml_int64_extern.logor(res, 0L) + if base == 10L && res != or_res { + failwith("int64_of_string") + } + or_res +} + +type base = Oct | Hex | Dec +let int_of_base = x => + switch x { + | Oct => 8 + | Hex => 16 + | Dec => 10 + } + +type fmt = { + mutable justify: string, + mutable signstyle: string, + mutable filter: string, + mutable alternate: bool, + mutable base: base, + mutable signedconv: bool, + mutable width: int, + mutable uppercase: bool, + mutable sign: int, + mutable prec: int, + mutable conv: string, +} + +let lowercase = (c: char): char => + if (c >= 'A' && c <= 'Z') || ((c >= '\192' && c <= '\214') || c >= '\216' && c <= '\222') { + Caml_char.unsafe_chr(Caml_char.code(c) + 32) + } else { + c + } + +let parse_format = fmt => { + module String = Caml_string_extern + let len = Caml_string_extern.length(fmt) + if len > 31 { + raise(Invalid_argument("format_int: format too long")) + } + let rec aux = (f: fmt, i): fmt => + if i >= len { + f + } else { + let c = String.get(fmt, i) + switch c { + | '-' => + f.justify = "-" + aux(f, i + 1) + | '+' | ' ' => + f.signstyle = Caml_string_extern.of_char(c) + aux(f, i + 1) + | '#' => + f.alternate = true + aux(f, i + 1) + | '0' => + f.filter = "0" + aux(f, i + 1) + | '1' .. '9' => + f.width = 0 + let j = ref(i) + + while { + let w = \".![]"(fmt, j.contents) - code_0 + w >= 0 && w <= 9 + } { + f.width = f.width * 10 + \".![]"(fmt, j.contents) - code_0 + j.contents = j.contents + 1 + } + aux(f, j.contents) + | '.' => + f.prec = 0 + let j = ref(i + 1) + while { + let w = \".![]"(fmt, j.contents) - code_0 + w >= 0 && w <= 9 + } { + f.prec = f.prec * 10 + \".![]"(fmt, j.contents) - code_0 + j.contents = j.contents + 1 + } + aux(f, j.contents) + | 'd' + | 'i' => + f.signedconv = true + f.base = Dec + aux(f, i + 1) + | 'u' => + f.base = Dec + aux(f, i + 1) + | 'x' => + f.base = Hex + aux(f, i + 1) + | 'X' => + f.base = Hex + f.uppercase = true + aux(f, i + 1) + | 'o' => + f.base = Oct + aux(f, i + 1) + /* | 'O' -> base .contents<- 8; uppercase .contents<- true no uppercase for oct */ + | 'e' | 'f' | 'g' => + f.signedconv = true + f.conv = Caml_string_extern.of_char(c) + aux(f, i + 1) + | 'E' | 'F' | 'G' => + f.signedconv = true + f.uppercase = true + f.conv = Caml_string_extern.of_char(lowercase(c)) + aux(f, i + 1) + | _ => aux(f, i + 1) + } + } + + aux( + { + justify: "+", + signstyle: "-", + filter: " ", + alternate: false, + base: Dec, + signedconv: false, + width: 0, + uppercase: false, + sign: 1, + prec: -1, + conv: "f", + }, + 0, + ) +} + +let finish_formatting = (config: fmt, rawbuffer) => { + let { + justify, + signstyle, + filter, + alternate, + base, + signedconv, + width, + uppercase, + sign, + prec: _, + conv: _, + } = config + let len = ref(Caml_string_extern.length(rawbuffer)) + if signedconv && (sign < 0 || signstyle != "-") { + len.contents = len.contents + 1 + } + if alternate { + if base == Oct { + len.contents = len.contents + 1 + } else if base == Hex { + len.contents = len.contents + 2 + } else { + () + } + } + let buffer = ref("") + + /* let (+=) buffer s = buffer .contents<- buffer.contents ^ s in + FIXME: should get inlined + */ + /* let (+:) s = buffer .contents<- buffer.contents ^ s in */ + if justify == "+" && filter == " " { + for _ in len.contents to width - 1 { + buffer.contents = buffer.contents ++ filter + } + } + if signedconv { + if sign < 0 { + buffer.contents = buffer.contents ++ "-" + } else if signstyle != "-" { + buffer.contents = buffer.contents ++ signstyle + } else { + () + } + } + if alternate && base == Oct { + buffer.contents = buffer.contents ++ "0" + } + if alternate && base === Hex { + buffer.contents = buffer.contents ++ "0x" + } + + if justify == "+" && filter == "0" { + for _ in len.contents to width - 1 { + buffer.contents = buffer.contents ++ filter + } + } + if uppercase { + buffer.contents = buffer.contents ++ Caml_string_extern.toUpperCase(rawbuffer) + } else { + buffer.contents = buffer.contents ++ rawbuffer + } + if justify == "-" { + for _ in len.contents to width - 1 { + buffer.contents = buffer.contents ++ " " + } + } + buffer.contents +} + +let aux = (f, i: int): string => { + let i = if i < 0 { + if f.signedconv { + f.sign = -1 + \">>>"(-i, 0) + /* when i is min_int, [-i] could overflow */ + } else { + \">>>"(i, 0) + } + } else { + i + } + let s = ref(Caml_string_extern.of_int(i, ~base=int_of_base(f.base))) + if f.prec >= 0 { + f.filter = " " + let n = f.prec - Caml_string_extern.length(s.contents) + if n > 0 { + s.contents = Caml_string_extern.repeat("0", n) ++ s.contents + } + } + finish_formatting(f, s.contents) +} + +let format_int = (fmt, i) => + if fmt == "%d" { + Caml_nativeint_extern.to_string(i) + } else { + let f = parse_format(fmt) + aux(f, i) + } + +/* This can handle unsigned integer (-1L) and print it as "%Lu" which + will overflow signed integer in general +*/ +let dec_of_pos_int64 = x => + if x < 0L { + let wbase = 10L + let cvtbl = "0123456789" + let y = Caml_int64.discard_sign(x) + /* 2 ^ 63 + y `div_mod` 10 */ + + let quotient_l = 922337203685477580L /* 2 ^ 63 / 10 */ + /* {lo = -858993460n; hi = 214748364n} */ + /* TODO: int64 constant folding so that we can do idiomatic code + 2 ^ 63 / 10 */ + let modulus_l = 8L + /* let c, d = Caml_int64.div_mod (Caml_int64.add y modulus_l) wbase in + we can not do the code above, it can overflow when y is really large + */ + let (c, d) = Caml_int64.div_mod(y, wbase) + let (e, f) = Caml_int64.div_mod(Caml_int64_extern.add(modulus_l, d), wbase) + let quotient = Caml_int64_extern.add(Caml_int64_extern.add(quotient_l, c), e) + Caml_int64.to_string(quotient) ++ + Caml_string_extern.get_string_unsafe(cvtbl, Caml_int64_extern.to_int(f)) + } else { + Caml_int64.to_string(x) + } + +let oct_of_int64 = x => { + let s = ref("") + let wbase = 8L + let cvtbl = "01234567" + if x < 0L { + let y = Caml_int64.discard_sign(x) + /* 2 ^ 63 + y `div_mod` 8 */ + let quotient_l = 1152921504606846976L + /* {lo = 0n; hi = 268435456n } */ /* 2 ^ 31 / 8 */ + + /* let c, d = Caml_int64.div_mod (Caml_int64.add y modulus_l) wbase in + we can not do the code above, it can overflow when y is really large + */ + let (c, d) = Caml_int64.div_mod(y, wbase) + + let quotient = ref(Caml_int64_extern.add(quotient_l, c)) + let modulus = ref(d) + s.contents = + Caml_string_extern.get_string_unsafe(cvtbl, Caml_int64_extern.to_int(modulus.contents)) ++ + s.contents + + while quotient.contents != 0L { + let (a, b) = Caml_int64.div_mod(quotient.contents, wbase) + quotient.contents = a + modulus.contents = b + s.contents = + Caml_string_extern.get_string_unsafe(cvtbl, Caml_int64_extern.to_int(modulus.contents)) ++ + s.contents + } + } else { + let (a, b) = Caml_int64.div_mod(x, wbase) + let quotient = ref(a) + let modulus = ref(b) + s.contents = + Caml_string_extern.get_string_unsafe(cvtbl, Caml_int64_extern.to_int(modulus.contents)) ++ + s.contents + + while quotient.contents != 0L { + let (a, b) = Caml_int64.div_mod(quotient.contents, wbase) + quotient.contents = a + modulus.contents = b + s.contents = + Caml_string_extern.get_string_unsafe(cvtbl, Caml_int64_extern.to_int(modulus.contents)) ++ + s.contents + } + } + s.contents +} + +/* FIXME: improve codegen for such cases + let div_mod (x : int64) (y : int64) : int64 * int64 = + let a, b = Caml_int64.(div_mod (unsafe_of_int64 x) (unsafe_of_int64 y)) in + Caml_int64.unsafe_to_int64 a , Caml_int64.unsafe_to_int64 b +*/ +let int64_format = (fmt, x) => + if fmt == "%d" { + Caml_int64.to_string(x) + } else { + let f = parse_format(fmt) + let x = if f.signedconv && x < 0L { + f.sign = -1 + Caml_int64_extern.neg(x) + } else { + x + } + let s = switch f.base { + | Hex => Caml_int64.to_hex(x) + | Oct => oct_of_int64(x) + | Dec => dec_of_pos_int64(x) + } + let fill_s = if f.prec >= 0 { + f.filter = " " + let n = f.prec - Caml_string_extern.length(s) + if n > 0 { + "0"->Caml_string_extern.repeat(n) ++ s + } else { + s + } + } else { + s + } + + finish_formatting(f, fill_s) + } + +let format_float = (fmt, x) => { + module String = Caml_string_extern + let f = parse_format(fmt) + let prec = if f.prec < 0 { + 6 + } else { + f.prec + } + let x = if x < 0. { + f.sign = -1 + -.x + } else { + x + } + let s = ref("") + if Caml_float_extern.isNaN(x) { + s.contents = "nan" + f.filter = " " + } else if !Caml_float_extern.isFinite(x) { + s.contents = "inf" + f.filter = " " + } else { + switch f.conv { + | "e" => + s.contents = Caml_float_extern.toExponentialWithPrecision(x, ~digits=prec) + /* exponent should be at least two digits + {[ + (3.3).toExponential() + "3.3e+0" + 3.3e+00 + ]} + */ + let i = Caml_string_extern.length(s.contents) + if String.get(s.contents, i - 3) == 'e' { + s.contents = + Caml_string_extern.slice(s.contents, 0, i - 1) ++ + ("0" ++ + Caml_string_extern.slice_rest(s.contents, i - 1)) + } + | "f" => + /* this will not work large numbers */ + /* ("%3.10f", 3e+56, "300000000000000005792779041490073052596128503513888063488.0000000000") */ + s.contents = Caml_float_extern.toFixedWithPrecision(x, ~digits=prec) + | "g" => + let prec = if prec != 0 { + prec + } else { + 1 + } + s.contents = Caml_float_extern.toExponentialWithPrecision(x, ~digits=prec - 1) + let j = Caml_string_extern.index_of(s.contents, "e") + let exp = Caml_float.int_of_float( + Caml_float_extern.fromString(Caml_string_extern.slice_rest(s.contents, j + 1)), + ) + if exp < -4 || (x >= 1e21 || Caml_string_extern.length(Caml_float_extern.toFixed(x)) > prec) { + let i = ref(j - 1) + while String.get(s.contents, i.contents) == '0' { + i.contents = i.contents - 1 + } + if String.get(s.contents, i.contents) == '.' { + i.contents = i.contents - 1 + } + s.contents = + Caml_string_extern.slice(s.contents, 0, i.contents + 1) ++ + Caml_string_extern.slice_rest(s.contents, j) + let i = Caml_string_extern.length(s.contents) + if String.get(s.contents, i - 3) == 'e' { + s.contents = + Caml_string_extern.slice(s.contents, 0, i - 1) ++ + ("0" ++ + Caml_string_extern.slice_rest(s.contents, i - 1)) + } else { + () + } + } else { + let p = ref(prec) + if exp < 0 { + p.contents = p.contents - (exp + 1) + s.contents = Caml_float_extern.toFixedWithPrecision(x, ~digits=p.contents) + } else { + while { + s.contents = Caml_float_extern.toFixedWithPrecision(x, ~digits=p.contents) + Caml_string_extern.length(s.contents) > prec + 1 + } { + p.contents = p.contents - 1 + } + } + if p.contents != 0 { + let k = ref(Caml_string_extern.length(s.contents) - 1) + while String.get(s.contents, k.contents) == '0' { + k.contents = k.contents - 1 + } + if String.get(s.contents, k.contents) == '.' { + k.contents = k.contents - 1 + } + s.contents = Caml_string_extern.slice(s.contents, 0, k.contents + 1) + } + } + + | _ => () + } + } + finish_formatting(f, s.contents) +} + +let hexstring_of_float: (float, int, char) => string = %raw(`function(x,prec,style){ + if (!isFinite(x)) { + if (isNaN(x)) return "nan"; + return x > 0 ? "infinity":"-infinity"; + } + var sign = (x==0 && 1/x == -Infinity)?1:(x>=0)?0:1; + if(sign) x = -x; + var exp = 0; + if (x == 0) { } + else if (x < 1) { + while (x < 1 && exp > -1022) { x *= 2; exp-- } + } else { + while (x >= 2) { x /= 2; exp++ } + } + var exp_sign = exp < 0 ? '' : '+'; + var sign_str = ''; + if (sign) sign_str = '-' + else { + switch(style){ + case 43 /* '+' */: sign_str = '+'; break; + case 32 /* ' ' */: sign_str = ' '; break; + default: break; + } + } + if (prec >= 0 && prec < 13) { + /* If a precision is given, and is small, round mantissa accordingly */ + var cst = Math.pow(2,prec * 4); + x = Math.round(x * cst) / cst; + } + var x_str = x.toString(16); + if(prec >= 0){ + var idx = x_str.indexOf('.'); + if(idx<0) { + x_str += '.' + '0'.repeat(prec); + } + else { + var size = idx+1+prec; + if(x_str.length < size) + x_str += '0'.repeat(size - x_str.length); + else + x_str = x_str.substr(0,size); + } + } + return (sign_str + '0x' + x_str + 'p' + exp_sign + exp.toString(10)); +}`) + +let float_of_string: (string, exn) => float = %raw(`function(s,exn){ + + var res = +s; + if ((s.length > 0) && (res === res)) + return res; + s = s.replace(/_/g, ""); + res = +s; + if (((s.length > 0) && (res === res)) || /^[+-]?nan$/i.test(s)) { + return res; + }; + var m = /^ *([+-]?)0x([0-9a-f]+)\.?([0-9a-f]*)p([+-]?[0-9]+)/i.exec(s); + // 1 2 3 4 + if(m){ + var m3 = m[3].replace(/0+$/,''); + var mantissa = parseInt(m[1] + m[2] + m3, 16); + var exponent = (m[4]|0) - 4*m3.length; + res = mantissa * Math.pow(2, exponent); + return res; + } + if (/^\+?inf(inity)?$/i.test(s)) + return Infinity; + if (/^-inf(inity)?$/i.test(s)) + return -Infinity; + throw new Error(exn.RE_EXN_ID, { cause: exn });; +} +`) + +@ocaml.doc(" + Pervasives.float_of_string : string -> float = \"?float_of_string\" + Semantics is slightly different from javascript : + console.assert(float_of_string('infinity')===Infinity) + console.assert(float_of_string('Infinity')===Infinity + parseFloat('Infinity') === Infinity + parseFloat('infinity') === Nan +") +let float_of_string = (s: string): float => float_of_string(s, Failure("float_of_string")) diff --git a/jscomp/runtime/caml_format.resi b/jscomp/runtime/caml_format.resi new file mode 100644 index 0000000000..7f9362cf3a --- /dev/null +++ b/jscomp/runtime/caml_format.resi @@ -0,0 +1,39 @@ +@@ocaml.text( + /* Copyright (C) 2015-2016 Bloomberg Finance L.P. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * In addition to the permissions granted to you by the LGPL, you may combine + * or link a "work that uses the Library" with a publicly distributed version + * of this file to produce a combined library or application, then distribute + * that combined work under the terms of your choosing, with no requirement + * to comply with the obligations normally placed on you by section 4 of the + * LGPL version 3 (or the corresponding section of a later version of the LGPL + * should you choose to use a later version). + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + + " " +) + +let format_float: (string, float) => string + +let hexstring_of_float: (float, int, char) => string + +let format_int: (string, int) => string + +let float_of_string: string => float +let int64_format: (string, int64) => string +let int_of_string: string => int + +let int64_of_string: string => int64 diff --git a/jscomp/runtime/caml_string_extern.res b/jscomp/runtime/caml_string_extern.res index 57942ca957..6bfafc88f7 100644 --- a/jscomp/runtime/caml_string_extern.res +++ b/jscomp/runtime/caml_string_extern.res @@ -50,5 +50,6 @@ external of_small_int_array: (@as(json`null`) _, array) => string = "String external length: string => int = "%string_length" external unsafe_get: (string, int) => char = "%string_unsafe_get" external unsafe_set: (bytes, int, char) => unit = "%bytes_unsafe_set" +external get: (string, int) => char = "%string_unsafe_get" @send external repeat: (string, int) => string = "repeat" diff --git a/jscomp/runtime/release.ninja b/jscomp/runtime/release.ninja index 7cb3e6aeed..5fb3ac1435 100644 --- a/jscomp/runtime/release.ninja +++ b/jscomp/runtime/release.ninja @@ -25,8 +25,8 @@ o runtime/caml_exceptions.cmj : cc_cmi runtime/caml_exceptions.res | runtime/cam o runtime/caml_exceptions.cmi : cc runtime/caml_exceptions.resi | runtime/bs_stdlib_mini.cmi runtime/js.cmi runtime/js.cmj o runtime/caml_float.cmj : cc_cmi runtime/caml_float.res | runtime/caml_float.cmi runtime/caml_float_extern.cmj o runtime/caml_float.cmi : cc runtime/caml_float.resi | runtime/bs_stdlib_mini.cmi runtime/js.cmi runtime/js.cmj -o runtime/caml_format.cmj : cc_cmi runtime/caml_format.ml | runtime/caml.cmj runtime/caml_float.cmj runtime/caml_float_extern.cmj runtime/caml_format.cmi runtime/caml_int64.cmj runtime/caml_int64_extern.cmj runtime/caml_nativeint_extern.cmj runtime/caml_string_extern.cmj -o runtime/caml_format.cmi : cc runtime/caml_format.mli | runtime/bs_stdlib_mini.cmi runtime/js.cmi runtime/js.cmj +o runtime/caml_format.cmj : cc_cmi runtime/caml_format.res | runtime/caml.cmj runtime/caml_float.cmj runtime/caml_float_extern.cmj runtime/caml_format.cmi runtime/caml_int64.cmj runtime/caml_int64_extern.cmj runtime/caml_nativeint_extern.cmj runtime/caml_string_extern.cmj +o runtime/caml_format.cmi : cc runtime/caml_format.resi | runtime/bs_stdlib_mini.cmi runtime/js.cmi runtime/js.cmj o runtime/caml_hash.cmj : cc_cmi runtime/caml_hash.res | runtime/caml_hash.cmi runtime/caml_hash_primitive.cmj runtime/caml_nativeint_extern.cmj runtime/js.cmj o runtime/caml_hash.cmi : cc runtime/caml_hash.resi | runtime/bs_stdlib_mini.cmi runtime/js.cmi runtime/js.cmj o runtime/caml_hash_primitive.cmj : cc_cmi runtime/caml_hash_primitive.res | runtime/caml_hash_primitive.cmi runtime/caml_string_extern.cmj diff --git a/lib/es6/belt_Array.js b/lib/es6/belt_Array.js index d309b07a1b..7f5f88b640 100644 --- a/lib/es6/belt_Array.js +++ b/lib/es6/belt_Array.js @@ -2,7 +2,6 @@ import * as Caml from "./caml.js"; import * as Curry from "./curry.js"; -import * as Js_math from "./js_math.js"; import * as Caml_option from "./caml_option.js"; function get(arr, i) { @@ -61,8 +60,11 @@ function swapUnsafe(xs, i, j) { function shuffleInPlace(xs) { let len = xs.length; + let random_int = function (min, max) { + return Math.floor(Math.random() * (max - min | 0)) + min | 0; + }; for(let i = 0; i < len; ++i){ - swapUnsafe(xs, i, Js_math.random_int(i, len)); + swapUnsafe(xs, i, random_int(i, len)); } } diff --git a/lib/es6/caml_format.js b/lib/es6/caml_format.js index e645606202..5cdc04e050 100644 --- a/lib/es6/caml_format.js +++ b/lib/es6/caml_format.js @@ -19,12 +19,12 @@ function parse_digit(c) { } else if (c > 57 || c < 48) { return -1; } else { - return c - /* '0' */48 | 0; + return c - 48 | 0; } } -function int_of_string_base(param) { - switch (param) { +function int_of_string_base(x) { + switch (x) { case "Oct" : return 8; case "Hex" : @@ -274,8 +274,8 @@ function int64_of_string(s) { return or_res; } -function int_of_base(param) { - switch (param) { +function int_of_base(x) { + switch (x) { case "Oct" : return 8; case "Hex" : @@ -413,10 +413,10 @@ function parse_format(fmt) { f.prec = 0; let j = i + 1 | 0; while((function () { - let w = fmt.codePointAt(j) - /* '0' */48 | 0; + let w = fmt.codePointAt(j) - 48 | 0; return w >= 0 && w <= 9; })()) { - f.prec = (Math.imul(f.prec, 10) + fmt.codePointAt(j) | 0) - /* '0' */48 | 0; + f.prec = (Math.imul(f.prec, 10) + fmt.codePointAt(j) | 0) - 48 | 0; j = j + 1 | 0; }; _i = j; @@ -452,10 +452,10 @@ function parse_format(fmt) { f.width = 0; let j$1 = i; while((function () { - let w = fmt.codePointAt(j$1) - /* '0' */48 | 0; + let w = fmt.codePointAt(j$1) - 48 | 0; return w >= 0 && w <= 9; })()) { - f.width = (Math.imul(f.width, 10) + fmt.codePointAt(j$1) | 0) - /* '0' */48 | 0; + f.width = (Math.imul(f.width, 10) + fmt.codePointAt(j$1) | 0) - 48 | 0; j$1 = j$1 + 1 | 0; }; _i = j$1; diff --git a/lib/js/belt_Array.js b/lib/js/belt_Array.js index 2484641da4..2f1ab345bf 100644 --- a/lib/js/belt_Array.js +++ b/lib/js/belt_Array.js @@ -2,7 +2,6 @@ let Caml = require("./caml.js"); let Curry = require("./curry.js"); -let Js_math = require("./js_math.js"); let Caml_option = require("./caml_option.js"); function get(arr, i) { @@ -61,8 +60,11 @@ function swapUnsafe(xs, i, j) { function shuffleInPlace(xs) { let len = xs.length; + let random_int = function (min, max) { + return Math.floor(Math.random() * (max - min | 0)) + min | 0; + }; for(let i = 0; i < len; ++i){ - swapUnsafe(xs, i, Js_math.random_int(i, len)); + swapUnsafe(xs, i, random_int(i, len)); } } diff --git a/lib/js/caml_format.js b/lib/js/caml_format.js index 860ae7ca0f..b34ad42999 100644 --- a/lib/js/caml_format.js +++ b/lib/js/caml_format.js @@ -19,12 +19,12 @@ function parse_digit(c) { } else if (c > 57 || c < 48) { return -1; } else { - return c - /* '0' */48 | 0; + return c - 48 | 0; } } -function int_of_string_base(param) { - switch (param) { +function int_of_string_base(x) { + switch (x) { case "Oct" : return 8; case "Hex" : @@ -274,8 +274,8 @@ function int64_of_string(s) { return or_res; } -function int_of_base(param) { - switch (param) { +function int_of_base(x) { + switch (x) { case "Oct" : return 8; case "Hex" : @@ -413,10 +413,10 @@ function parse_format(fmt) { f.prec = 0; let j = i + 1 | 0; while((function () { - let w = fmt.codePointAt(j) - /* '0' */48 | 0; + let w = fmt.codePointAt(j) - 48 | 0; return w >= 0 && w <= 9; })()) { - f.prec = (Math.imul(f.prec, 10) + fmt.codePointAt(j) | 0) - /* '0' */48 | 0; + f.prec = (Math.imul(f.prec, 10) + fmt.codePointAt(j) | 0) - 48 | 0; j = j + 1 | 0; }; _i = j; @@ -452,10 +452,10 @@ function parse_format(fmt) { f.width = 0; let j$1 = i; while((function () { - let w = fmt.codePointAt(j$1) - /* '0' */48 | 0; + let w = fmt.codePointAt(j$1) - 48 | 0; return w >= 0 && w <= 9; })()) { - f.width = (Math.imul(f.width, 10) + fmt.codePointAt(j$1) | 0) - /* '0' */48 | 0; + f.width = (Math.imul(f.width, 10) + fmt.codePointAt(j$1) | 0) - 48 | 0; j$1 = j$1 + 1 | 0; }; _i = j$1; diff --git a/packages/artifacts.txt b/packages/artifacts.txt index 2bfabdebdd..adda960af5 100644 --- a/packages/artifacts.txt +++ b/packages/artifacts.txt @@ -805,7 +805,7 @@ lib/ocaml/js_mapperRt.resi lib/ocaml/js_math.cmi lib/ocaml/js_math.cmj lib/ocaml/js_math.cmt -lib/ocaml/js_math.ml +lib/ocaml/js_math.res lib/ocaml/js_null.cmi lib/ocaml/js_null.cmj lib/ocaml/js_null.cmt