diff --git a/CHANGELOG.md b/CHANGELOG.md index c26e09255e..d1b7f2d0b3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,7 +23,8 @@ - Use FORCE_COLOR environmental variable to force colorized output https://github.com/rescript-lang/rescript-compiler/pull/7033 - Allow spreads of variants in patterns (`| ...someVariant as v => `) when the variant spread is a subtype of the variant matched on. https://github.com/rescript-lang/rescript-compiler/pull/6721 - Fix the issue where dynamic imports are not working for function-defined externals. https://github.com/rescript-lang/rescript-compiler/pull/7060 -- Allow pattern matching on dicts. `switch someDict { | dict{"one": 1} => Js.log("one is one") }` https://github.com/rescript-lang/rescript-compiler/pull/7059 +- Allow pattern matching on dicts. `switch someDict { | dict{"one": 1} => Js.log("one is one") }`. https://github.com/rescript-lang/rescript-compiler/pull/7059 +- "ReScript Core" standard library is now included in the `rescript` npm package. https://github.com/rescript-lang/rescript-compiler/pull/7108 #### :bug: Bug fix diff --git a/lib/es6/Array.js b/lib/es6/Array.js index 794ad95431..5d83e76143 100644 --- a/lib/es6/Array.js +++ b/lib/es6/Array.js @@ -1,497 +1,192 @@ -import * as List from "./List.js"; -import * as Primitive_array from "./Primitive_array.js"; -import * as Primitive_exceptions from "./Primitive_exceptions.js"; +import * as Primitive_option from "./Primitive_option.js"; -let init = ((length, f) => Array.from({ length }, f)); - -function make(len, x) { - return init(len, param => x); -} - -function unsafe_sub(array, offset, length) { - return array.slice(offset, offset + length | 0); -} - -function concat(list) { - return List.fold_left((arr1, arr2) => arr1.concat(arr2), [], list); -} - -function create_float(len) { - return init(len, param => 0.0); -} - -function make_matrix(sx, sy, init$1) { - let x = []; - let res = init(sx, param => x); - for (let x$1 = 0; x$1 < sx; ++x$1) { - res[x$1] = init(sy, param => init$1); +function make(length, x) { + if (length <= 0) { + return []; } - return res; + let arr = new Array(length); + arr.fill(x); + return arr; } -function append(a1, a2) { - let l1 = a1.length; - if (l1 === 0) { - return a2.slice(); - } else if (a2.length === 0) { - return unsafe_sub(a1, 0, l1); - } else { - return a1.concat(a2); +function fromInitializer(length, f) { + if (length <= 0) { + return []; } + let arr = new Array(length); + for (let i = 0; i < length; ++i) { + arr[i] = f(i); + } + return arr; } -function sub(a, ofs, len) { - if (ofs < 0 || len < 0 || ofs > (a.length - len | 0)) { - throw { - RE_EXN_ID: "Invalid_argument", - _1: "Array.sub", - Error: new Error() +function equal(a, b, eq) { + let len = a.length; + if (len === b.length) { + let _i = 0; + while (true) { + let i = _i; + if (i === len) { + return true; + } + if (!eq(a[i], b[i])) { + return false; + } + _i = i + 1 | 0; + continue; }; + } else { + return false; } - return unsafe_sub(a, ofs, len); } -function fill(a, ofs, len, v) { - if (ofs < 0 || len < 0 || ofs > (a.length - len | 0)) { - throw { - RE_EXN_ID: "Invalid_argument", - _1: "Array.fill", - Error: new Error() +function compare(a, b, cmp) { + let lenA = a.length; + let lenB = b.length; + if (lenA < lenB) { + return -1; + } else if (lenA > lenB) { + return 1; + } else { + let _i = 0; + while (true) { + let i = _i; + if (i === lenA) { + return 0; + } + let c = cmp(a[i], b[i]); + if (c !== 0) { + return c; + } + _i = i + 1 | 0; + continue; }; } - for (let i = ofs, i_finish = ofs + len | 0; i < i_finish; ++i) { - a[i] = v; - } } -function blit(a1, ofs1, a2, ofs2, len) { - if (len < 0 || ofs1 < 0 || ofs1 > (a1.length - len | 0) || ofs2 < 0 || ofs2 > (a2.length - len | 0)) { - throw { - RE_EXN_ID: "Invalid_argument", - _1: "Array.blit", - Error: new Error() - }; - } - for (let i = 0; i < len; ++i) { - a2[ofs2 + i | 0] = a1[ofs1 + i | 0]; +function indexOfOpt(arr, item) { + let index = arr.indexOf(item); + if (index !== -1) { + return index; } + } -function iter(f, a) { - for (let i = 0, i_finish = a.length; i < i_finish; ++i) { - f(a[i]); +function lastIndexOfOpt(arr, item) { + let index = arr.lastIndexOf(item); + if (index !== -1) { + return index; } + } -function iter2(f, a, b) { - if (a.length !== b.length) { - throw { - RE_EXN_ID: "Invalid_argument", - _1: "Array.iter2: arrays must have the same length", - Error: new Error() - }; - } - for (let i = 0, i_finish = a.length; i < i_finish; ++i) { - f(a[i], b[i]); - } +function reduce(arr, init, f) { + return arr.reduce(f, init); } -function map(f, a) { - let l = a.length; - if (l === 0) { - return []; - } - let x = f(a[0]); - let r = init(l, param => x); - for (let i = 1; i < l; ++i) { - r[i] = f(a[i]); - } - return r; +function reduceWithIndex(arr, init, f) { + return arr.reduce(f, init); } -function map2(f, a, b) { - let la = a.length; - let lb = b.length; - if (la !== lb) { - throw { - RE_EXN_ID: "Invalid_argument", - _1: "Array.map2: arrays must have the same length", - Error: new Error() - }; - } - if (la === 0) { - return []; - } - let x = f(a[0], b[0]); - let r = init(la, param => x); - for (let i = 1; i < la; ++i) { - r[i] = f(a[i], b[i]); - } - return r; +function reduceRight(arr, init, f) { + return arr.reduceRight(f, init); } -function iteri(f, a) { - for (let i = 0, i_finish = a.length; i < i_finish; ++i) { - f(i, a[i]); - } +function reduceRightWithIndex(arr, init, f) { + return arr.reduceRight(f, init); } -function mapi(f, a) { - let l = a.length; - if (l === 0) { - return []; - } - let x = f(0, a[0]); - let r = init(l, param => x); - for (let i = 1; i < l; ++i) { - r[i] = f(i, a[i]); +function findIndexOpt(array, finder) { + let index = array.findIndex(finder); + if (index !== -1) { + return index; } - return r; + } -function to_list(a) { - let _i = a.length - 1 | 0; - let _res = /* [] */0; - while (true) { - let res = _res; - let i = _i; - if (i < 0) { - return res; - } - _res = { - hd: a[i], - tl: res - }; - _i = i - 1 | 0; - continue; - }; +function swapUnsafe(xs, i, j) { + let tmp = xs[i]; + xs[i] = xs[j]; + xs[j] = tmp; } -function list_length(_accu, _param) { - while (true) { - let param = _param; - let accu = _accu; - if (!param) { - return accu; - } - _param = param.tl; - _accu = accu + 1 | 0; - continue; - }; +function random_int(min, max) { + return (Math.floor(Math.random() * (max - min | 0)) | 0) + min | 0; } -function of_list(param) { - if (!param) { - return []; +function shuffle(xs) { + let len = xs.length; + for (let i = 0; i < len; ++i) { + swapUnsafe(xs, i, random_int(i, len)); } - let hd = param.hd; - let len = list_length(0, param); - let a = init(len, param => hd); - let _i = 1; - let _param = param.tl; - while (true) { - let param$1 = _param; - let i = _i; - if (!param$1) { - return a; - } - a[i] = param$1.hd; - _param = param$1.tl; - _i = i + 1 | 0; - continue; - }; } -function fold_left(f, x, a) { - let r = x; - for (let i = 0, i_finish = a.length; i < i_finish; ++i) { - r = f(r, a[i]); - } - return r; +function toShuffled(xs) { + let result = xs.slice(); + shuffle(result); + return result; } -function fold_right(f, a, x) { - let r = x; - for (let i = a.length - 1 | 0; i >= 0; --i) { - r = f(a[i], r); - } +function filterMap(a, f) { + let l = a.length; + let r = new Array(l); + let j = 0; + for (let i = 0; i < l; ++i) { + let v = a[i]; + let v$1 = f(v); + if (v$1 !== undefined) { + r[j] = Primitive_option.valFromOption(v$1); + j = j + 1 | 0; + } + + } + r.length = j; return r; } -function exists(p, a) { - let n = a.length; - let _i = 0; - while (true) { - let i = _i; - if (i === n) { - return false; - } - if (p(a[i])) { - return true; - } - _i = i + 1 | 0; - continue; - }; +function keepSome(__x) { + return filterMap(__x, x => x); } -function for_all(p, a) { - let n = a.length; +function findMap(arr, f) { let _i = 0; while (true) { let i = _i; - if (i === n) { - return true; + if (i === arr.length) { + return; } - if (!p(a[i])) { - return false; + let r = f(arr[i]); + if (r !== undefined) { + return r; } _i = i + 1 | 0; continue; }; } -function mem(x, a) { - let n = a.length; - let _i = 0; - while (true) { - let i = _i; - if (i === n) { - return false; - } - if (a[i] === x) { - return true; - } - _i = i + 1 | 0; - continue; - }; +function last(a) { + return a[a.length - 1 | 0]; } -function memq(x, a) { - let n = a.length; - let _i = 0; - while (true) { - let i = _i; - if (i === n) { - return false; - } - if (x === a[i]) { - return true; - } - _i = i + 1 | 0; - continue; - }; -} - -let Bottom = /* @__PURE__ */Primitive_exceptions.create("Array.Bottom"); - -function sort(cmp, a) { - let maxson = (l, i) => { - let i31 = ((i + i | 0) + i | 0) + 1 | 0; - let x = i31; - if ((i31 + 2 | 0) < l) { - if (cmp(Primitive_array.get(a, i31), Primitive_array.get(a, i31 + 1 | 0)) < 0) { - x = i31 + 1 | 0; - } - if (cmp(Primitive_array.get(a, x), Primitive_array.get(a, i31 + 2 | 0)) < 0) { - x = i31 + 2 | 0; - } - return x; - } - if ((i31 + 1 | 0) < l && cmp(Primitive_array.get(a, i31), Primitive_array.get(a, i31 + 1 | 0)) < 0) { - return i31 + 1 | 0; - } - if (i31 < l) { - return i31; - } - throw { - RE_EXN_ID: Bottom, - _1: i, - Error: new Error() - }; - }; - let trickle = (l, i, e) => { - try { - let _i = i; - while (true) { - let i$1 = _i; - let j = maxson(l, i$1); - if (cmp(Primitive_array.get(a, j), e) <= 0) { - return Primitive_array.set(a, i$1, e); - } - Primitive_array.set(a, i$1, Primitive_array.get(a, j)); - _i = j; - continue; - }; - } catch (raw_i) { - let i$2 = Primitive_exceptions.internalToException(raw_i); - if (i$2.RE_EXN_ID === Bottom) { - return Primitive_array.set(a, i$2._1, e); - } - throw i$2; - } - }; - let bubble = (l, i) => { - try { - let _i = i; - while (true) { - let i$1 = _i; - let j = maxson(l, i$1); - Primitive_array.set(a, i$1, Primitive_array.get(a, j)); - _i = j; - continue; - }; - } catch (raw_i) { - let i$2 = Primitive_exceptions.internalToException(raw_i); - if (i$2.RE_EXN_ID === Bottom) { - return i$2._1; - } - throw i$2; - } - }; - let trickleup = (_i, e) => { - while (true) { - let i = _i; - let father = (i - 1 | 0) / 3 | 0; - if (i === father) { - throw { - RE_EXN_ID: "Assert_failure", - _1: [ - "Array.res", - 294, - 4 - ], - Error: new Error() - }; - } - if (cmp(Primitive_array.get(a, father), e) >= 0) { - return Primitive_array.set(a, i, e); - } - Primitive_array.set(a, i, Primitive_array.get(a, father)); - if (father <= 0) { - return Primitive_array.set(a, 0, e); - } - _i = father; - continue; - }; - }; - let l = a.length; - for (let i = ((l + 1 | 0) / 3 | 0) - 1 | 0; i >= 0; --i) { - trickle(l, i, Primitive_array.get(a, i)); - } - for (let i$1 = l - 1 | 0; i$1 >= 2; --i$1) { - let e = Primitive_array.get(a, i$1); - Primitive_array.set(a, i$1, Primitive_array.get(a, 0)); - trickleup(bubble(i$1, 0), e); - } - if (l <= 1) { - return; - } - let e$1 = Primitive_array.get(a, 1); - Primitive_array.set(a, 1, Primitive_array.get(a, 0)); - Primitive_array.set(a, 0, e$1); -} - -function stable_sort(cmp, a) { - let merge = (src1ofs, src1len, src2, src2ofs, src2len, dst, dstofs) => { - let src1r = src1ofs + src1len | 0; - let src2r = src2ofs + src2len | 0; - let _i1 = src1ofs; - let _s1 = Primitive_array.get(a, src1ofs); - let _i2 = src2ofs; - let _s2 = Primitive_array.get(src2, src2ofs); - let _d = dstofs; - while (true) { - let d = _d; - let s2 = _s2; - let i2 = _i2; - let s1 = _s1; - let i1 = _i1; - if (cmp(s1, s2) <= 0) { - Primitive_array.set(dst, d, s1); - let i1$1 = i1 + 1 | 0; - if (i1$1 >= src1r) { - return blit(src2, i2, dst, d + 1 | 0, src2r - i2 | 0); - } - _d = d + 1 | 0; - _s1 = Primitive_array.get(a, i1$1); - _i1 = i1$1; - continue; - } - Primitive_array.set(dst, d, s2); - let i2$1 = i2 + 1 | 0; - if (i2$1 >= src2r) { - return blit(a, i1, dst, d + 1 | 0, src1r - i1 | 0); - } - _d = d + 1 | 0; - _s2 = Primitive_array.get(src2, i2$1); - _i2 = i2$1; - continue; - }; - }; - let isortto = (srcofs, dst, dstofs, len) => { - for (let i = 0; i < len; ++i) { - let e = Primitive_array.get(a, srcofs + i | 0); - let j = (dstofs + i | 0) - 1 | 0; - while (j >= dstofs && cmp(Primitive_array.get(dst, j), e) > 0) { - Primitive_array.set(dst, j + 1 | 0, Primitive_array.get(dst, j)); - j = j - 1 | 0; - }; - Primitive_array.set(dst, j + 1 | 0, e); - } - }; - let sortto = (srcofs, dst, dstofs, len) => { - if (len <= 5) { - return isortto(srcofs, dst, dstofs, len); - } - let l1 = len / 2 | 0; - let l2 = len - l1 | 0; - sortto(srcofs + l1 | 0, dst, dstofs + l1 | 0, l2); - sortto(srcofs, a, srcofs + l2 | 0, l1); - merge(srcofs + l2 | 0, l1, dst, dstofs + l1 | 0, l2, dst, dstofs); - }; - let l = a.length; - if (l <= 5) { - return isortto(0, a, 0, l); - } - let l1 = l / 2 | 0; - let l2 = l - l1 | 0; - let x = Primitive_array.get(a, 0); - let t = init(l2, param => x); - sortto(l1, t, 0, l2); - sortto(0, a, l2, l1); - merge(l2, l1, t, 0, l2, a, 0); -} - -let fast_sort = stable_sort; - export { make, - create_float, - init, - make_matrix, - append, - concat, - sub, - fill, - blit, - to_list, - of_list, - iter, - iteri, - map, - mapi, - fold_left, - fold_right, - iter2, - map2, - for_all, - exists, - mem, - memq, - sort, - stable_sort, - fast_sort, + fromInitializer, + equal, + compare, + indexOfOpt, + lastIndexOfOpt, + reduce, + reduceWithIndex, + reduceRight, + reduceRightWithIndex, + findIndexOpt, + filterMap, + keepSome, + toShuffled, + shuffle, + findMap, + last, } /* No side effect */ diff --git a/lib/es6/ArrayBuffer.js b/lib/es6/ArrayBuffer.js new file mode 100644 index 0000000000..ae1b9f17e6 --- /dev/null +++ b/lib/es6/ArrayBuffer.js @@ -0,0 +1 @@ +/* This output is empty. Its source's type definitions, externals and/or unused code got optimized away. */ diff --git a/lib/es6/AsyncIterator.js b/lib/es6/AsyncIterator.js new file mode 100644 index 0000000000..2fb3590e1a --- /dev/null +++ b/lib/es6/AsyncIterator.js @@ -0,0 +1,43 @@ + + +import * as Primitive_option from "./Primitive_option.js"; + +function value(v) { + return { + done: false, + value: Primitive_option.some(v) + }; +} + +function done(finalValue) { + return { + done: true, + value: finalValue + }; +} + +async function forEach(iterator, f) { + let iteratorDone = false; + while (!iteratorDone) { + let match = await iterator.next(); + f(match.value); + iteratorDone = match.done; + }; +} + +let make = (function makeAsyncIterator(next) { + return { + next, + [Symbol.asyncIterator]() { + return this; + } + } +}); + +export { + make, + value, + done, + forEach, +} +/* No side effect */ diff --git a/lib/es6/BigInt.js b/lib/es6/BigInt.js new file mode 100644 index 0000000000..483f59a0eb --- /dev/null +++ b/lib/es6/BigInt.js @@ -0,0 +1,16 @@ + + + +function toInt(t) { + return Number(t) | 0; +} + +function lnot(x) { + return x ^ -1n; +} + +export { + toInt, + lnot, +} +/* No side effect */ diff --git a/lib/es6/BigInt64Array.js b/lib/es6/BigInt64Array.js new file mode 100644 index 0000000000..cd168743c9 --- /dev/null +++ b/lib/es6/BigInt64Array.js @@ -0,0 +1,9 @@ + + + +let Constants = {}; + +export { + Constants, +} +/* No side effect */ diff --git a/lib/es6/BigUint64Array.js b/lib/es6/BigUint64Array.js new file mode 100644 index 0000000000..cd168743c9 --- /dev/null +++ b/lib/es6/BigUint64Array.js @@ -0,0 +1,9 @@ + + + +let Constants = {}; + +export { + Constants, +} +/* No side effect */ diff --git a/lib/es6/Console.js b/lib/es6/Console.js new file mode 100644 index 0000000000..ae1b9f17e6 --- /dev/null +++ b/lib/es6/Console.js @@ -0,0 +1 @@ +/* This output is empty. Its source's type definitions, externals and/or unused code got optimized away. */ diff --git a/lib/es6/DataView.js b/lib/es6/DataView.js new file mode 100644 index 0000000000..ae1b9f17e6 --- /dev/null +++ b/lib/es6/DataView.js @@ -0,0 +1 @@ +/* This output is empty. Its source's type definitions, externals and/or unused code got optimized away. */ diff --git a/lib/es6/Date.js b/lib/es6/Date.js new file mode 100644 index 0000000000..8c66aa05db --- /dev/null +++ b/lib/es6/Date.js @@ -0,0 +1,20 @@ + + +import * as Primitive_float from "./Primitive_float.js"; + +let UTC = {}; + +function equal(a, b) { + return a.getTime() === b.getTime(); +} + +function compare(a, b) { + return Primitive_float.compare(a.getTime(), b.getTime()); +} + +export { + UTC, + equal, + compare, +} +/* No side effect */ diff --git a/lib/es6/Dict.js b/lib/es6/Dict.js new file mode 100644 index 0000000000..4d12162214 --- /dev/null +++ b/lib/es6/Dict.js @@ -0,0 +1,30 @@ + + + +function $$delete$1(dict, string) { + delete(dict[string]); +} + +function forEach(dict, f) { + Object.values(dict).forEach(value => f(value)); +} + +function forEachWithKey(dict, f) { + Object.entries(dict).forEach(param => f(param[1], param[0])); +} + +function mapValues(dict, f) { + let target = {}; + forEachWithKey(dict, (value, key) => { + target[key] = f(value); + }); + return target; +} + +export { + $$delete$1 as $$delete, + forEach, + forEachWithKey, + mapValues, +} +/* No side effect */ diff --git a/lib/es6/Error.js b/lib/es6/Error.js new file mode 100644 index 0000000000..a7b7eb76c0 --- /dev/null +++ b/lib/es6/Error.js @@ -0,0 +1,29 @@ + + + +let $$EvalError = {}; + +let $$RangeError = {}; + +let $$ReferenceError = {}; + +let $$SyntaxError = {}; + +let $$TypeError = {}; + +let $$URIError = {}; + +function panic(msg) { + throw new Error("Panic! " + msg); +} + +export { + $$EvalError, + $$RangeError, + $$ReferenceError, + $$SyntaxError, + $$TypeError, + $$URIError, + panic, +} +/* No side effect */ diff --git a/lib/es6/Js_exn.js b/lib/es6/Exn.js similarity index 100% rename from lib/es6/Js_exn.js rename to lib/es6/Exn.js diff --git a/lib/es6/Float.js b/lib/es6/Float.js new file mode 100644 index 0000000000..d0955e3ce0 --- /dev/null +++ b/lib/es6/Float.js @@ -0,0 +1,29 @@ + + + +let Constants = {}; + +function fromString(i) { + let i$1 = parseFloat(i); + if (isNaN(i$1)) { + return; + } else { + return i$1; + } +} + +function clamp(min, max, value) { + let value$1 = max !== undefined && max < value ? max : value; + if (min !== undefined && min > value$1) { + return min; + } else { + return value$1; + } +} + +export { + Constants, + fromString, + clamp, +} +/* No side effect */ diff --git a/lib/es6/Float32Array.js b/lib/es6/Float32Array.js new file mode 100644 index 0000000000..cd168743c9 --- /dev/null +++ b/lib/es6/Float32Array.js @@ -0,0 +1,9 @@ + + + +let Constants = {}; + +export { + Constants, +} +/* No side effect */ diff --git a/lib/es6/Float64Array.js b/lib/es6/Float64Array.js new file mode 100644 index 0000000000..cd168743c9 --- /dev/null +++ b/lib/es6/Float64Array.js @@ -0,0 +1,9 @@ + + + +let Constants = {}; + +export { + Constants, +} +/* No side effect */ diff --git a/lib/es6/Hashtbl.js b/lib/es6/Hashtbl.js deleted file mode 100644 index c95915f5b8..0000000000 --- a/lib/es6/Hashtbl.js +++ /dev/null @@ -1,12 +0,0 @@ - - -import * as Primitive_hash from "./Primitive_hash.js"; - -function hash(x) { - return Primitive_hash.hash(10, 100, 0, x); -} - -export { - hash, -} -/* No side effect */ diff --git a/lib/es6/Int.js b/lib/es6/Int.js new file mode 100644 index 0000000000..d817901429 --- /dev/null +++ b/lib/es6/Int.js @@ -0,0 +1,86 @@ + + +import * as $$Array from "./Array.js"; + +function fromString(x, radix) { + let maybeInt = radix !== undefined ? parseInt(x, radix) : parseInt(x); + if (isNaN(maybeInt) || maybeInt > 2147483647 || maybeInt < -2147483648) { + return; + } else { + return maybeInt | 0; + } +} + +function abs(x) { + if (x >= 0) { + return x; + } else { + return -x | 0; + } +} + +function range(start, end, optionsOpt) { + let options = optionsOpt !== undefined ? optionsOpt : ({}); + let isInverted = start > end; + let n = options.step; + let step; + if (n !== undefined) { + if (n !== 0) { + step = n; + } else { + if (start !== end) { + throw new RangeError("Incorrect range arguments"); + } + step = n; + } + } else { + step = isInverted ? -1 : 1; + } + let length; + if (isInverted === step >= 0) { + length = 0; + } else if (step === 0) { + length = options.inclusive === true ? 1 : 0; + } else { + let range$1 = isInverted ? start - end | 0 : end - start | 0; + let range$2 = options.inclusive === true ? range$1 + 1 | 0 : range$1; + length = Math.ceil(range$2 / abs(step)) | 0; + } + return $$Array.fromInitializer(length, i => start + Math.imul(i, step) | 0); +} + +function rangeWithOptions(start, end, options) { + return range(start, end, options); +} + +function clamp(min, max, value) { + let value$1 = max !== undefined && max < value ? max : value; + if (min !== undefined && min > value$1) { + return min; + } else { + return value$1; + } +} + +function lnot(x) { + return x ^ -1; +} + +let Bitwise = { + lnot: lnot +}; + +let Constants = { + minValue: -2147483648, + maxValue: 2147483647 +}; + +export { + Constants, + fromString, + range, + rangeWithOptions, + clamp, + Bitwise, +} +/* No side effect */ diff --git a/lib/es6/Int16Array.js b/lib/es6/Int16Array.js new file mode 100644 index 0000000000..cd168743c9 --- /dev/null +++ b/lib/es6/Int16Array.js @@ -0,0 +1,9 @@ + + + +let Constants = {}; + +export { + Constants, +} +/* No side effect */ diff --git a/lib/es6/Int32Array.js b/lib/es6/Int32Array.js new file mode 100644 index 0000000000..cd168743c9 --- /dev/null +++ b/lib/es6/Int32Array.js @@ -0,0 +1,9 @@ + + + +let Constants = {}; + +export { + Constants, +} +/* No side effect */ diff --git a/lib/es6/Int8Array.js b/lib/es6/Int8Array.js new file mode 100644 index 0000000000..cd168743c9 --- /dev/null +++ b/lib/es6/Int8Array.js @@ -0,0 +1,9 @@ + + + +let Constants = {}; + +export { + Constants, +} +/* No side effect */ diff --git a/lib/es6/Intl.js b/lib/es6/Intl.js new file mode 100644 index 0000000000..17f2e18e06 --- /dev/null +++ b/lib/es6/Intl.js @@ -0,0 +1,36 @@ + + + +let Common; + +let Collator; + +let DateTimeFormat; + +let ListFormat; + +let Locale; + +let NumberFormat; + +let PluralRules; + +let RelativeTimeFormat; + +let Segmenter; + +let Segments; + +export { + Common, + Collator, + DateTimeFormat, + ListFormat, + Locale, + NumberFormat, + PluralRules, + RelativeTimeFormat, + Segmenter, + Segments, +} +/* No side effect */ diff --git a/lib/es6/Intl_Collator.js b/lib/es6/Intl_Collator.js new file mode 100644 index 0000000000..ae1b9f17e6 --- /dev/null +++ b/lib/es6/Intl_Collator.js @@ -0,0 +1 @@ +/* This output is empty. Its source's type definitions, externals and/or unused code got optimized away. */ diff --git a/lib/es6/Intl_Common.js b/lib/es6/Intl_Common.js new file mode 100644 index 0000000000..ae1b9f17e6 --- /dev/null +++ b/lib/es6/Intl_Common.js @@ -0,0 +1 @@ +/* This output is empty. Its source's type definitions, externals and/or unused code got optimized away. */ diff --git a/lib/es6/Intl_DateTimeFormat.js b/lib/es6/Intl_DateTimeFormat.js new file mode 100644 index 0000000000..ae1b9f17e6 --- /dev/null +++ b/lib/es6/Intl_DateTimeFormat.js @@ -0,0 +1 @@ +/* This output is empty. Its source's type definitions, externals and/or unused code got optimized away. */ diff --git a/lib/es6/Intl_ListFormat.js b/lib/es6/Intl_ListFormat.js new file mode 100644 index 0000000000..ae1b9f17e6 --- /dev/null +++ b/lib/es6/Intl_ListFormat.js @@ -0,0 +1 @@ +/* This output is empty. Its source's type definitions, externals and/or unused code got optimized away. */ diff --git a/lib/es6/Intl_Locale.js b/lib/es6/Intl_Locale.js new file mode 100644 index 0000000000..ae1b9f17e6 --- /dev/null +++ b/lib/es6/Intl_Locale.js @@ -0,0 +1 @@ +/* This output is empty. Its source's type definitions, externals and/or unused code got optimized away. */ diff --git a/lib/es6/Intl_NumberFormat.js b/lib/es6/Intl_NumberFormat.js new file mode 100644 index 0000000000..4b29a9b669 --- /dev/null +++ b/lib/es6/Intl_NumberFormat.js @@ -0,0 +1,9 @@ + + + +let Grouping; + +export { + Grouping, +} +/* No side effect */ diff --git a/lib/es6/Intl_NumberFormat_Grouping.js b/lib/es6/Intl_NumberFormat_Grouping.js new file mode 100644 index 0000000000..4633bbc588 --- /dev/null +++ b/lib/es6/Intl_NumberFormat_Grouping.js @@ -0,0 +1,35 @@ + + +import * as Type from "./Type.js"; + +function parseJsValue(value) { + let value$1 = Type.Classify.classify(value); + if (typeof value$1 !== "object") { + return; + } + switch (value$1.TAG) { + case "Bool" : + return { + NAME: "bool", + VAL: value$1._0 + }; + case "String" : + switch (value$1._0) { + case "always" : + return "always"; + case "auto" : + return "auto"; + case "min2" : + return "min2"; + default: + return; + } + default: + return; + } +} + +export { + parseJsValue, +} +/* No side effect */ diff --git a/lib/es6/Intl_PluralRules.js b/lib/es6/Intl_PluralRules.js new file mode 100644 index 0000000000..ae1b9f17e6 --- /dev/null +++ b/lib/es6/Intl_PluralRules.js @@ -0,0 +1 @@ +/* This output is empty. Its source's type definitions, externals and/or unused code got optimized away. */ diff --git a/lib/es6/Intl_RelativeTimeFormat.js b/lib/es6/Intl_RelativeTimeFormat.js new file mode 100644 index 0000000000..ae1b9f17e6 --- /dev/null +++ b/lib/es6/Intl_RelativeTimeFormat.js @@ -0,0 +1 @@ +/* This output is empty. Its source's type definitions, externals and/or unused code got optimized away. */ diff --git a/lib/es6/Intl_Segmenter.js b/lib/es6/Intl_Segmenter.js new file mode 100644 index 0000000000..ae1b9f17e6 --- /dev/null +++ b/lib/es6/Intl_Segmenter.js @@ -0,0 +1 @@ +/* This output is empty. Its source's type definitions, externals and/or unused code got optimized away. */ diff --git a/lib/es6/Intl_Segments.js b/lib/es6/Intl_Segments.js new file mode 100644 index 0000000000..ae1b9f17e6 --- /dev/null +++ b/lib/es6/Intl_Segments.js @@ -0,0 +1 @@ +/* This output is empty. Its source's type definitions, externals and/or unused code got optimized away. */ diff --git a/lib/es6/Iterator.js b/lib/es6/Iterator.js new file mode 100644 index 0000000000..e793b51c42 --- /dev/null +++ b/lib/es6/Iterator.js @@ -0,0 +1,16 @@ + + + +function forEach(iterator, f) { + let iteratorDone = false; + while (!iteratorDone) { + let match = iterator.next(); + f(match.value); + iteratorDone = match.done; + }; +} + +export { + forEach, +} +/* No side effect */ diff --git a/lib/es6/JSON.js b/lib/es6/JSON.js new file mode 100644 index 0000000000..e547968d71 --- /dev/null +++ b/lib/es6/JSON.js @@ -0,0 +1,100 @@ + + +import * as Primitive_option from "./Primitive_option.js"; + +function classify(value) { + let match = Object.prototype.toString.call(value); + switch (match) { + case "[object Array]" : + return { + TAG: "Array", + _0: value + }; + case "[object Boolean]" : + return { + TAG: "Bool", + _0: value + }; + case "[object Null]" : + return "Null"; + case "[object Number]" : + return { + TAG: "Number", + _0: value + }; + case "[object String]" : + return { + TAG: "String", + _0: value + }; + default: + return { + TAG: "Object", + _0: value + }; + } +} + +let Classify = { + classify: classify +}; + +let Encode = {}; + +function bool(json) { + if (typeof json === "boolean") { + return json; + } + +} + +function $$null(json) { + if (json === undefined) { + return Primitive_option.some(undefined); + } + +} + +function string(json) { + if (typeof json === "string") { + return json; + } + +} + +function float(json) { + if (typeof json === "number") { + return json; + } + +} + +function object(json) { + if (typeof json === "object" && !Array.isArray(json) && json !== undefined) { + return json; + } + +} + +function array(json) { + if (Array.isArray(json)) { + return json; + } + +} + +let Decode = { + bool: bool, + $$null: $$null, + string: string, + float: float, + object: object, + array: array +}; + +export { + Classify, + Encode, + Decode, +} +/* No side effect */ diff --git a/lib/es6/List.js b/lib/es6/List.js index dbde576692..89b2209010 100644 --- a/lib/es6/List.js +++ b/lib/es6/List.js @@ -1,1606 +1,957 @@ -import * as Pervasives from "./Pervasives.js"; +import * as $$Array from "./Array.js"; +import * as Primitive_int from "./Primitive_int.js"; import * as Primitive_option from "./Primitive_option.js"; -function length(l) { - let _len = 0; - let _param = l; - while (true) { - let param = _param; - let len = _len; - if (!param) { - return len; - } - _param = param.tl; - _len = len + 1 | 0; - continue; - }; -} - -function cons(a, l) { - return { - hd: a, - tl: l - }; +function head(x) { + if (x) { + return Primitive_option.some(x.hd); + } + } -function hd(param) { - if (param) { - return param.hd; +function headExn(x) { + if (x) { + return x.hd; } throw { - RE_EXN_ID: "Failure", - _1: "hd", + RE_EXN_ID: "Not_found", Error: new Error() }; } -function tl(param) { - if (param) { - return param.tl; +function tail(x) { + if (x) { + return x.tl; + } + +} + +function tailExn(x) { + if (x) { + return x.tl; } throw { - RE_EXN_ID: "Failure", - _1: "tl", + RE_EXN_ID: "Not_found", Error: new Error() }; } -function nth(l, n) { +function add(xs, x) { + return { + hd: x, + tl: xs + }; +} + +function get(x, n) { + if (n < 0) { + return; + } else { + let _x = x; + let _n = n; + while (true) { + let n$1 = _n; + let x$1 = _x; + if (!x$1) { + return; + } + if (n$1 === 0) { + return Primitive_option.some(x$1.hd); + } + _n = n$1 - 1 | 0; + _x = x$1.tl; + continue; + }; + } +} + +function getExn(x, n) { if (n < 0) { throw { - RE_EXN_ID: "Invalid_argument", - _1: "List.nth", + RE_EXN_ID: "Not_found", Error: new Error() }; } - let _l = l; + let _x = x; let _n = n; while (true) { let n$1 = _n; - let l$1 = _l; - if (l$1) { + let x$1 = _x; + if (x$1) { if (n$1 === 0) { - return l$1.hd; + return x$1.hd; } _n = n$1 - 1 | 0; - _l = l$1.tl; + _x = x$1.tl; continue; } throw { - RE_EXN_ID: "Failure", - _1: "nth", + RE_EXN_ID: "Not_found", Error: new Error() }; }; } -function nth_opt(l, n) { - if (n < 0) { - throw { - RE_EXN_ID: "Invalid_argument", - _1: "List.nth", - Error: new Error() - }; - } - let _l = l; - let _n = n; +function partitionAux(p, _cell, _precX, _precY) { while (true) { - let n$1 = _n; - let l$1 = _l; - if (!l$1) { + let precY = _precY; + let precX = _precX; + let cell = _cell; + if (!cell) { return; } - if (n$1 === 0) { - return Primitive_option.some(l$1.hd); + let t = cell.tl; + let h = cell.hd; + let next = { + hd: h, + tl: /* [] */0 + }; + if (p(h)) { + precX.tl = next; + _precX = next; + _cell = t; + continue; } - _n = n$1 - 1 | 0; - _l = l$1.tl; + precY.tl = next; + _precY = next; + _cell = t; continue; }; } -function rev_append(_l1, _l2) { +function splitAux(_cell, _precX, _precY) { while (true) { - let l2 = _l2; - let l1 = _l1; - if (!l1) { - return l2; + let precY = _precY; + let precX = _precX; + let cell = _cell; + if (!cell) { + return; } - _l2 = { - hd: l1.hd, - tl: l2 + let match = cell.hd; + let nextA = { + hd: match[0], + tl: /* [] */0 }; - _l1 = l1.tl; - continue; - }; -} - -function rev(l) { - return rev_append(l, /* [] */0); -} - -function init_tailrec_aux(_acc, _i, n, f) { - while (true) { - let i = _i; - let acc = _acc; - if (i >= n) { - return acc; - } - _i = i + 1 | 0; - _acc = { - hd: f(i), - tl: acc + let nextB = { + hd: match[1], + tl: /* [] */0 }; + precX.tl = nextA; + precY.tl = nextB; + _precY = nextB; + _precX = nextA; + _cell = cell.tl; continue; }; } -function init_aux(i, n, f) { - if (i >= n) { - return /* [] */0; - } - let r = f(i); - return { - hd: r, - tl: init_aux(i + 1 | 0, n, f) - }; -} - -function init(len, f) { - if (len < 0) { - throw { - RE_EXN_ID: "Invalid_argument", - _1: "List.init", - Error: new Error() - }; - } - if (len > 10000) { - return rev_append(init_tailrec_aux(/* [] */0, 0, len, f), /* [] */0); - } else { - return init_aux(0, len, f); - } -} - -function flatten(param) { - if (param) { - return Pervasives.$at(param.hd, flatten(param.tl)); - } else { - return /* [] */0; - } -} - -function map(f, param) { - if (!param) { - return /* [] */0; - } - let r = f(param.hd); - return { - hd: r, - tl: map(f, param.tl) - }; -} - -function mapi(i, f, param) { - if (!param) { - return /* [] */0; - } - let r = f(i, param.hd); - return { - hd: r, - tl: mapi(i + 1 | 0, f, param.tl) - }; -} - -function mapi$1(f, l) { - return mapi(0, f, l); -} - -function rev_map(f, l) { - let _accu = /* [] */0; - let _param = l; +function copyAuxCont(_cellX, _prec) { while (true) { - let param = _param; - let accu = _accu; - if (!param) { - return accu; + let prec = _prec; + let cellX = _cellX; + if (!cellX) { + return prec; } - _param = param.tl; - _accu = { - hd: f(param.hd), - tl: accu + let next = { + hd: cellX.hd, + tl: /* [] */0 }; + prec.tl = next; + _prec = next; + _cellX = cellX.tl; continue; }; } -function iter(f, _param) { +function copyAuxWitFilter(f, _cellX, _prec) { while (true) { - let param = _param; - if (!param) { + let prec = _prec; + let cellX = _cellX; + if (!cellX) { return; } - f(param.hd); - _param = param.tl; + let t = cellX.tl; + let h = cellX.hd; + if (f(h)) { + let next = { + hd: h, + tl: /* [] */0 + }; + prec.tl = next; + _prec = next; + _cellX = t; + continue; + } + _cellX = t; continue; }; } -function iteri(f, l) { - let _i = 0; - let _param = l; +function copyAuxWithFilterIndex(f, _cellX, _prec, _i) { while (true) { - let param = _param; let i = _i; - if (!param) { + let prec = _prec; + let cellX = _cellX; + if (!cellX) { return; } - f(i, param.hd); - _param = param.tl; + let t = cellX.tl; + let h = cellX.hd; + if (f(h, i)) { + let next = { + hd: h, + tl: /* [] */0 + }; + prec.tl = next; + _i = i + 1 | 0; + _prec = next; + _cellX = t; + continue; + } _i = i + 1 | 0; + _cellX = t; continue; }; } -function fold_left(f, _accu, _l) { +function copyAuxWitFilterMap(f, _cellX, _prec) { while (true) { - let l = _l; - let accu = _accu; - if (!l) { - return accu; + let prec = _prec; + let cellX = _cellX; + if (!cellX) { + return; } - _l = l.tl; - _accu = f(accu, l.hd); + let t = cellX.tl; + let h = f(cellX.hd); + if (h !== undefined) { + let next = { + hd: Primitive_option.valFromOption(h), + tl: /* [] */0 + }; + prec.tl = next; + _prec = next; + _cellX = t; + continue; + } + _cellX = t; continue; }; } -function fold_right(f, l, accu) { - if (l) { - return f(l.hd, fold_right(f, l.tl, accu)); - } else { - return accu; - } -} - -function map2(f, l1, l2) { - if (l1) { - if (l2) { - let r = f(l1.hd, l2.hd); - return { - hd: r, - tl: map2(f, l1.tl, l2.tl) - }; +function removeAssocAuxWithMap(_cellX, x, _prec, f) { + while (true) { + let prec = _prec; + let cellX = _cellX; + if (!cellX) { + return false; } - throw { - RE_EXN_ID: "Invalid_argument", - _1: "List.map2", - Error: new Error() + let t = cellX.tl; + let h = cellX.hd; + if (f(h[0], x)) { + prec.tl = t; + return true; + } + let next = { + hd: h, + tl: /* [] */0 }; - } - if (!l2) { - return /* [] */0; - } - throw { - RE_EXN_ID: "Invalid_argument", - _1: "List.map2", - Error: new Error() + prec.tl = next; + _prec = next; + _cellX = t; + continue; }; } -function rev_map2(f, l1, l2) { - let _accu = /* [] */0; - let _l1 = l1; - let _l2 = l2; +function setAssocAuxWithMap(_cellX, x, k, _prec, eq) { while (true) { - let l2$1 = _l2; - let l1$1 = _l1; - let accu = _accu; - if (l1$1) { - if (l2$1) { - _l2 = l2$1.tl; - _l1 = l1$1.tl; - _accu = { - hd: f(l1$1.hd, l2$1.hd), - tl: accu - }; - continue; - } - throw { - RE_EXN_ID: "Invalid_argument", - _1: "List.rev_map2", - Error: new Error() - }; + let prec = _prec; + let cellX = _cellX; + if (!cellX) { + return false; } - if (l2$1) { - throw { - RE_EXN_ID: "Invalid_argument", - _1: "List.rev_map2", - Error: new Error() + let t = cellX.tl; + let h = cellX.hd; + if (eq(h[0], x)) { + prec.tl = { + hd: [ + x, + k + ], + tl: t }; + return true; } - return accu; + let next = { + hd: h, + tl: /* [] */0 + }; + prec.tl = next; + _prec = next; + _cellX = t; + continue; }; } -function iter2(f, _l1, _l2) { +function copyAuxWithMap(_cellX, _prec, f) { while (true) { - let l2 = _l2; - let l1 = _l1; - if (l1) { - if (l2) { - f(l1.hd, l2.hd); - _l2 = l2.tl; - _l1 = l1.tl; - continue; - } - throw { - RE_EXN_ID: "Invalid_argument", - _1: "List.iter2", - Error: new Error() - }; - } - if (!l2) { + let prec = _prec; + let cellX = _cellX; + if (!cellX) { return; } - throw { - RE_EXN_ID: "Invalid_argument", - _1: "List.iter2", - Error: new Error() + let next = { + hd: f(cellX.hd), + tl: /* [] */0 }; + prec.tl = next; + _prec = next; + _cellX = cellX.tl; + continue; }; } -function fold_left2(f, _accu, _l1, _l2) { +function zipAux(_cellX, _cellY, _prec) { while (true) { - let l2 = _l2; - let l1 = _l1; - let accu = _accu; - if (l1) { - if (l2) { - _l2 = l2.tl; - _l1 = l1.tl; - _accu = f(accu, l1.hd, l2.hd); - continue; - } - throw { - RE_EXN_ID: "Invalid_argument", - _1: "List.fold_left2", - Error: new Error() - }; - } - if (l2) { - throw { - RE_EXN_ID: "Invalid_argument", - _1: "List.fold_left2", - Error: new Error() - }; + let prec = _prec; + let cellY = _cellY; + let cellX = _cellX; + if (!cellX) { + return; } - return accu; - }; -} - -function fold_right2(f, l1, l2, accu) { - if (l1) { - if (l2) { - return f(l1.hd, l2.hd, fold_right2(f, l1.tl, l2.tl, accu)); + if (!cellY) { + return; } - throw { - RE_EXN_ID: "Invalid_argument", - _1: "List.fold_right2", - Error: new Error() - }; - } - if (l2) { - throw { - RE_EXN_ID: "Invalid_argument", - _1: "List.fold_right2", - Error: new Error() + let next = { + hd: [ + cellX.hd, + cellY.hd + ], + tl: /* [] */0 }; - } - return accu; -} - -function for_all(p, _param) { - while (true) { - let param = _param; - if (!param) { - return true; - } - if (!p(param.hd)) { - return false; - } - _param = param.tl; + prec.tl = next; + _prec = next; + _cellY = cellY.tl; + _cellX = cellX.tl; continue; }; } -function exists(p, _param) { +function copyAuxWithMap2(f, _cellX, _cellY, _prec) { while (true) { - let param = _param; - if (!param) { - return false; + let prec = _prec; + let cellY = _cellY; + let cellX = _cellX; + if (!cellX) { + return; } - if (p(param.hd)) { - return true; + if (!cellY) { + return; } - _param = param.tl; + let next = { + hd: f(cellX.hd, cellY.hd), + tl: /* [] */0 + }; + prec.tl = next; + _prec = next; + _cellY = cellY.tl; + _cellX = cellX.tl; continue; }; } -function for_all2(p, _l1, _l2) { +function copyAuxWithMapI(f, _i, _cellX, _prec) { while (true) { - let l2 = _l2; - let l1 = _l1; - if (l1) { - if (l2) { - if (!p(l1.hd, l2.hd)) { - return false; - } - _l2 = l2.tl; - _l1 = l1.tl; - continue; - } - throw { - RE_EXN_ID: "Invalid_argument", - _1: "List.for_all2", - Error: new Error() - }; - } - if (!l2) { - return true; + let prec = _prec; + let cellX = _cellX; + let i = _i; + if (!cellX) { + return; } - throw { - RE_EXN_ID: "Invalid_argument", - _1: "List.for_all2", - Error: new Error() + let next = { + hd: f(cellX.hd, i), + tl: /* [] */0 }; + prec.tl = next; + _prec = next; + _cellX = cellX.tl; + _i = i + 1 | 0; + continue; }; } -function exists2(p, _l1, _l2) { +function takeAux(_n, _cell, _prec) { while (true) { - let l2 = _l2; - let l1 = _l1; - if (l1) { - if (l2) { - if (p(l1.hd, l2.hd)) { - return true; - } - _l2 = l2.tl; - _l1 = l1.tl; - continue; - } - throw { - RE_EXN_ID: "Invalid_argument", - _1: "List.exists2", - Error: new Error() - }; + let prec = _prec; + let cell = _cell; + let n = _n; + if (n === 0) { + return true; } - if (!l2) { + if (!cell) { return false; } - throw { - RE_EXN_ID: "Invalid_argument", - _1: "List.exists2", - Error: new Error() + let cell$1 = { + hd: cell.hd, + tl: /* [] */0 }; + prec.tl = cell$1; + _prec = cell$1; + _cell = cell.tl; + _n = n - 1 | 0; + continue; }; } -function mem(x, _param) { +function splitAtAux(_n, _cell, _prec) { while (true) { - let param = _param; - if (!param) { - return false; + let prec = _prec; + let cell = _cell; + let n = _n; + if (n === 0) { + return cell; } - if (param.hd === x) { - return true; + if (!cell) { + return; } - _param = param.tl; + let cell$1 = { + hd: cell.hd, + tl: /* [] */0 + }; + prec.tl = cell$1; + _prec = cell$1; + _cell = cell.tl; + _n = n - 1 | 0; continue; }; } -function memq(x, _param) { - while (true) { - let param = _param; - if (!param) { - return false; - } - if (param.hd === x) { - return true; - } - _param = param.tl; - continue; +function take(lst, n) { + if (n < 0) { + return; + } + if (n === 0) { + return /* [] */0; + } + if (!lst) { + return; + } + let cell = { + hd: lst.hd, + tl: /* [] */0 }; + let has = takeAux(n - 1 | 0, lst.tl, cell); + if (has) { + return cell; + } + } -function assoc(x, _param) { - while (true) { - let param = _param; - if (param) { - let match = param.hd; - if (match[0] === x) { - return match[1]; +function drop(lst, n) { + if (n < 0) { + return; + } else { + let _l = lst; + let _n = n; + while (true) { + let n$1 = _n; + let l = _l; + if (n$1 === 0) { + return l; } - _param = param.tl; + if (!l) { + return; + } + _n = n$1 - 1 | 0; + _l = l.tl; continue; - } - throw { - RE_EXN_ID: "Not_found", - Error: new Error() }; + } +} + +function splitAt(lst, n) { + if (n < 0) { + return; + } + if (n === 0) { + return [ + /* [] */0, + lst + ]; + } + if (!lst) { + return; + } + let cell = { + hd: lst.hd, + tl: /* [] */0 }; + let rest = splitAtAux(n - 1 | 0, lst.tl, cell); + if (rest !== undefined) { + return [ + cell, + rest + ]; + } + } -function assoc_opt(x, _param) { +function concat(xs, ys) { + if (!xs) { + return ys; + } + let cell = { + hd: xs.hd, + tl: /* [] */0 + }; + copyAuxCont(xs.tl, cell).tl = ys; + return cell; +} + +function map(xs, f) { + if (!xs) { + return /* [] */0; + } + let cell = { + hd: f(xs.hd), + tl: /* [] */0 + }; + copyAuxWithMap(xs.tl, cell, f); + return cell; +} + +function zipBy(l1, l2, f) { + if (!l1) { + return /* [] */0; + } + if (!l2) { + return /* [] */0; + } + let cell = { + hd: f(l1.hd, l2.hd), + tl: /* [] */0 + }; + copyAuxWithMap2(f, l1.tl, l2.tl, cell); + return cell; +} + +function mapWithIndex(xs, f) { + if (!xs) { + return /* [] */0; + } + let cell = { + hd: f(xs.hd, 0), + tl: /* [] */0 + }; + copyAuxWithMapI(f, 1, xs.tl, cell); + return cell; +} + +function fromInitializer(n, f) { + if (n <= 0) { + return /* [] */0; + } + let headX = { + hd: f(0), + tl: /* [] */0 + }; + let cur = headX; + let i = 1; + while (i < n) { + let v = { + hd: f(i), + tl: /* [] */0 + }; + cur.tl = v; + cur = v; + i = i + 1 | 0; + }; + return headX; +} + +function make(n, v) { + if (n <= 0) { + return /* [] */0; + } + let headX = { + hd: v, + tl: /* [] */0 + }; + let cur = headX; + let i = 1; + while (i < n) { + let v$1 = { + hd: v, + tl: /* [] */0 + }; + cur.tl = v$1; + cur = v$1; + i = i + 1 | 0; + }; + return headX; +} + +function length(xs) { + let _x = xs; + let _acc = 0; while (true) { - let param = _param; - if (!param) { - return; + let acc = _acc; + let x = _x; + if (!x) { + return acc; } - let match = param.hd; - if (match[0] === x) { - return Primitive_option.some(match[1]); + _acc = acc + 1 | 0; + _x = x.tl; + continue; + }; +} + +function fillAux(arr, _i, _x) { + while (true) { + let x = _x; + let i = _i; + if (!x) { + return; } - _param = param.tl; + arr[i] = x.hd; + _x = x.tl; + _i = i + 1 | 0; continue; }; } -function assq(x, _param) { +function fromArray(a) { + let _i = a.length - 1 | 0; + let _res = /* [] */0; while (true) { - let param = _param; - if (param) { - let match = param.hd; - if (match[0] === x) { - return match[1]; - } - _param = param.tl; - continue; + let res = _res; + let i = _i; + if (i < 0) { + return res; } - throw { - RE_EXN_ID: "Not_found", - Error: new Error() + _res = { + hd: a[i], + tl: res }; + _i = i - 1 | 0; + continue; }; } -function assq_opt(x, _param) { +function toArray(x) { + let len = length(x); + let arr = new Array(len); + fillAux(arr, 0, x); + return arr; +} + +function toShuffled(xs) { + let v = toArray(xs); + $$Array.shuffle(v); + return fromArray(v); +} + +function reverseConcat(_l1, _l2) { while (true) { - let param = _param; - if (!param) { - return; - } - let match = param.hd; - if (match[0] === x) { - return Primitive_option.some(match[1]); + let l2 = _l2; + let l1 = _l1; + if (!l1) { + return l2; } - _param = param.tl; + _l2 = { + hd: l1.hd, + tl: l2 + }; + _l1 = l1.tl; continue; }; } -function mem_assoc(x, _param) { +function reverse(l) { + return reverseConcat(l, /* [] */0); +} + +function flatAux(_prec, _xs) { while (true) { - let param = _param; - if (!param) { - return false; - } - if (param.hd[0] === x) { - return true; + let xs = _xs; + let prec = _prec; + if (xs) { + _xs = xs.tl; + _prec = copyAuxCont(xs.hd, prec); + continue; } - _param = param.tl; - continue; + prec.tl = /* [] */0; + return; }; } -function mem_assq(x, _param) { +function flat(_xs) { while (true) { - let param = _param; - if (!param) { - return false; + let xs = _xs; + if (!xs) { + return /* [] */0; } - if (param.hd[0] === x) { - return true; + let match = xs.hd; + if (match) { + let cell = { + hd: match.hd, + tl: /* [] */0 + }; + flatAux(copyAuxCont(match.tl, cell), xs.tl); + return cell; } - _param = param.tl; + _xs = xs.tl; continue; }; } -function remove_assoc(x, param) { - if (!param) { - return /* [] */0; +function concatMany(xs) { + let len = xs.length; + if (len === 1) { + return xs[0]; } - let l = param.tl; - let pair = param.hd; - if (pair[0] === x) { - return l; - } else { - return { - hd: pair, - tl: remove_assoc(x, l) - }; - } -} - -function remove_assq(x, param) { - if (!param) { + if (len === 0) { return /* [] */0; } - let l = param.tl; - let pair = param.hd; - if (pair[0] === x) { - return l; - } else { - return { - hd: pair, - tl: remove_assq(x, l) - }; + let len$1 = xs.length; + let v = xs[len$1 - 1 | 0]; + for (let i = len$1 - 2 | 0; i >= 0; --i) { + v = concat(xs[i], v); } + return v; } -function find(p, _param) { +function mapReverse(l, f) { + let _accu = /* [] */0; + let _xs = l; while (true) { - let param = _param; - if (param) { - let x = param.hd; - if (p(x)) { - return x; - } - _param = param.tl; - continue; + let xs = _xs; + let accu = _accu; + if (!xs) { + return accu; } - throw { - RE_EXN_ID: "Not_found", - Error: new Error() + _xs = xs.tl; + _accu = { + hd: f(xs.hd), + tl: accu }; + continue; }; } -function find_opt(p, _param) { +function forEach(_xs, f) { while (true) { - let param = _param; - if (!param) { + let xs = _xs; + if (!xs) { return; } - let x = param.hd; - if (p(x)) { - return Primitive_option.some(x); + f(xs.hd); + _xs = xs.tl; + continue; + }; +} + +function forEachWithIndex(l, f) { + let _xs = l; + let _i = 0; + while (true) { + let i = _i; + let xs = _xs; + if (!xs) { + return; } - _param = param.tl; + f(xs.hd, i); + _i = i + 1 | 0; + _xs = xs.tl; continue; }; } -function find_all(p, l) { - let _accu = /* [] */0; - let _param = l; +function reduce(_l, _accu, f) { while (true) { - let param = _param; let accu = _accu; - if (!param) { - return rev_append(accu, /* [] */0); + let l = _l; + if (!l) { + return accu; } - let l$1 = param.tl; - let x = param.hd; - if (p(x)) { - _param = l$1; - _accu = { - hd: x, - tl: accu - }; - continue; + _accu = f(accu, l.hd); + _l = l.tl; + continue; + }; +} + +function reduceReverseUnsafe(l, accu, f) { + if (l) { + return f(reduceReverseUnsafe(l.tl, accu, f), l.hd); + } else { + return accu; + } +} + +function reduceReverse(l, acc, f) { + let len = length(l); + if (len < 1000) { + return reduceReverseUnsafe(l, acc, f); + } else { + let a = toArray(l); + let r = acc; + for (let i = a.length - 1 | 0; i >= 0; --i) { + r = f(r, a[i]); } - _param = l$1; + return r; + } +} + +function reduceWithIndex(l, acc, f) { + let _l = l; + let _acc = acc; + let _i = 0; + while (true) { + let i = _i; + let acc$1 = _acc; + let l$1 = _l; + if (!l$1) { + return acc$1; + } + _i = i + 1 | 0; + _acc = f(acc$1, l$1.hd, i); + _l = l$1.tl; continue; }; } -function partition(p, l) { - let _yes = /* [] */0; - let _no = /* [] */0; - let _param = l; +function mapReverse2(l1, l2, f) { + let _l1 = l1; + let _l2 = l2; + let _accu = /* [] */0; while (true) { - let param = _param; - let no = _no; - let yes = _yes; - if (!param) { - return [ - rev_append(yes, /* [] */0), - rev_append(no, /* [] */0) - ]; - } - let l$1 = param.tl; - let x = param.hd; - if (p(x)) { - _param = l$1; - _yes = { - hd: x, - tl: yes - }; - continue; + let accu = _accu; + let l2$1 = _l2; + let l1$1 = _l1; + if (!l1$1) { + return accu; } - _param = l$1; - _no = { - hd: x, - tl: no + if (!l2$1) { + return accu; + } + _accu = { + hd: f(l1$1.hd, l2$1.hd), + tl: accu }; + _l2 = l2$1.tl; + _l1 = l1$1.tl; continue; }; } -function split(param) { - if (!param) { - return [ - /* [] */0, - /* [] */0 - ]; - } - let match = param.hd; - let match$1 = split(param.tl); - return [ - { - hd: match[0], - tl: match$1[0] - }, - { - hd: match[1], - tl: match$1[1] +function forEach2(_l1, _l2, f) { + while (true) { + let l2 = _l2; + let l1 = _l1; + if (!l1) { + return; } - ]; + if (!l2) { + return; + } + f(l1.hd, l2.hd); + _l2 = l2.tl; + _l1 = l1.tl; + continue; + }; } -function combine(l1, l2) { - if (l1) { - if (l2) { - return { - hd: [ - l1.hd, - l2.hd - ], - tl: combine(l1.tl, l2.tl) - }; +function reduce2(_l1, _l2, _accu, f) { + while (true) { + let accu = _accu; + let l2 = _l2; + let l1 = _l1; + if (!l1) { + return accu; } - throw { - RE_EXN_ID: "Invalid_argument", - _1: "List.combine", - Error: new Error() - }; - } - if (!l2) { - return /* [] */0; - } - throw { - RE_EXN_ID: "Invalid_argument", - _1: "List.combine", - Error: new Error() + if (!l2) { + return accu; + } + _accu = f(accu, l1.hd, l2.hd); + _l2 = l2.tl; + _l1 = l1.tl; + continue; }; } -function merge(cmp, l1, l2) { - if (!l1) { - return l2; - } - if (!l2) { - return l1; +function reduceReverse2Unsafe(l1, l2, accu, f) { + if (l1 && l2) { + return f(reduceReverse2Unsafe(l1.tl, l2.tl, accu, f), l1.hd, l2.hd); + } else { + return accu; } - let h2 = l2.hd; - let h1 = l1.hd; - if (cmp(h1, h2) <= 0) { - return { - hd: h1, - tl: merge(cmp, l1.tl, l2) - }; +} + +function reduceReverse2(l1, l2, acc, f) { + let len = length(l1); + if (len < 1000) { + return reduceReverse2Unsafe(l1, l2, acc, f); } else { - return { - hd: h2, - tl: merge(cmp, l1, l2.tl) - }; + let a = toArray(l1); + let b = toArray(l2); + let r = acc; + let len$1 = Primitive_int.max(a.length, b.length); + for (let i = len$1 - 1 | 0; i >= 0; --i) { + r = f(r, a[i], b[i]); + } + return r; } } -function chop(_k, _l) { +function every(_xs, p) { while (true) { - let l = _l; - let k = _k; - if (k === 0) { - return l; + let xs = _xs; + if (!xs) { + return true; } - if (l) { - _l = l.tl; - _k = k - 1 | 0; - continue; + if (!p(xs.hd)) { + return false; } - throw { - RE_EXN_ID: "Assert_failure", - _1: [ - "List.res", - 411, - 11 - ], - Error: new Error() - }; + _xs = xs.tl; + continue; }; } -function stable_sort(cmp, l) { - let sort = (n, l) => { - if (n !== 2) { - if (n === 3 && l) { - let match = l.tl; - if (match) { - let match$1 = match.tl; - if (match$1) { - let x3 = match$1.hd; - let x2 = match.hd; - let x1 = l.hd; - if (cmp(x1, x2) <= 0) { - if (cmp(x2, x3) <= 0) { - return { - hd: x1, - tl: { - hd: x2, - tl: { - hd: x3, - tl: /* [] */0 - } - } - }; - } else if (cmp(x1, x3) <= 0) { - return { - hd: x1, - tl: { - hd: x3, - tl: { - hd: x2, - tl: /* [] */0 - } - } - }; - } else { - return { - hd: x3, - tl: { - hd: x1, - tl: { - hd: x2, - tl: /* [] */0 - } - } - }; - } - } else if (cmp(x1, x3) <= 0) { - return { - hd: x2, - tl: { - hd: x1, - tl: { - hd: x3, - tl: /* [] */0 - } - } - }; - } else if (cmp(x2, x3) <= 0) { - return { - hd: x2, - tl: { - hd: x3, - tl: { - hd: x1, - tl: /* [] */0 - } - } - }; - } else { - return { - hd: x3, - tl: { - hd: x2, - tl: { - hd: x1, - tl: /* [] */0 - } - } - }; - } - } - - } - - } - - } else if (l) { - let match$2 = l.tl; - if (match$2) { - let x2$1 = match$2.hd; - let x1$1 = l.hd; - if (cmp(x1$1, x2$1) <= 0) { - return { - hd: x1$1, - tl: { - hd: x2$1, - tl: /* [] */0 - } - }; - } else { - return { - hd: x2$1, - tl: { - hd: x1$1, - tl: /* [] */0 - } - }; - } - } - - } - let n1 = (n >> 1); - let n2 = n - n1 | 0; - let l2 = chop(n1, l); - let s1 = rev_sort(n1, l); - let s2 = rev_sort(n2, l2); - let _l1 = s1; - let _l2 = s2; - let _accu = /* [] */0; - while (true) { - let accu = _accu; - let l2$1 = _l2; - let l1 = _l1; - if (!l1) { - return rev_append(l2$1, accu); - } - if (!l2$1) { - return rev_append(l1, accu); - } - let h2 = l2$1.hd; - let h1 = l1.hd; - if (cmp(h1, h2) > 0) { - _accu = { - hd: h1, - tl: accu - }; - _l1 = l1.tl; - continue; - } - _accu = { - hd: h2, - tl: accu - }; - _l2 = l2$1.tl; - continue; - }; - }; - let rev_sort = (n, l) => { - if (n !== 2) { - if (n === 3 && l) { - let match = l.tl; - if (match) { - let match$1 = match.tl; - if (match$1) { - let x3 = match$1.hd; - let x2 = match.hd; - let x1 = l.hd; - if (cmp(x1, x2) > 0) { - if (cmp(x2, x3) > 0) { - return { - hd: x1, - tl: { - hd: x2, - tl: { - hd: x3, - tl: /* [] */0 - } - } - }; - } else if (cmp(x1, x3) > 0) { - return { - hd: x1, - tl: { - hd: x3, - tl: { - hd: x2, - tl: /* [] */0 - } - } - }; - } else { - return { - hd: x3, - tl: { - hd: x1, - tl: { - hd: x2, - tl: /* [] */0 - } - } - }; - } - } else if (cmp(x1, x3) > 0) { - return { - hd: x2, - tl: { - hd: x1, - tl: { - hd: x3, - tl: /* [] */0 - } - } - }; - } else if (cmp(x2, x3) > 0) { - return { - hd: x2, - tl: { - hd: x3, - tl: { - hd: x1, - tl: /* [] */0 - } - } - }; - } else { - return { - hd: x3, - tl: { - hd: x2, - tl: { - hd: x1, - tl: /* [] */0 - } - } - }; - } - } - - } - - } - - } else if (l) { - let match$2 = l.tl; - if (match$2) { - let x2$1 = match$2.hd; - let x1$1 = l.hd; - if (cmp(x1$1, x2$1) > 0) { - return { - hd: x1$1, - tl: { - hd: x2$1, - tl: /* [] */0 - } - }; - } else { - return { - hd: x2$1, - tl: { - hd: x1$1, - tl: /* [] */0 - } - }; - } - } - - } - let n1 = (n >> 1); - let n2 = n - n1 | 0; - let l2 = chop(n1, l); - let s1 = sort(n1, l); - let s2 = sort(n2, l2); - let _l1 = s1; - let _l2 = s2; - let _accu = /* [] */0; - while (true) { - let accu = _accu; - let l2$1 = _l2; - let l1 = _l1; - if (!l1) { - return rev_append(l2$1, accu); - } - if (!l2$1) { - return rev_append(l1, accu); - } - let h2 = l2$1.hd; - let h1 = l1.hd; - if (cmp(h1, h2) <= 0) { - _accu = { - hd: h1, - tl: accu - }; - _l1 = l1.tl; - continue; - } - _accu = { - hd: h2, - tl: accu - }; - _l2 = l2$1.tl; - continue; - }; +function some(_xs, p) { + while (true) { + let xs = _xs; + if (!xs) { + return false; + } + if (p(xs.hd)) { + return true; + } + _xs = xs.tl; + continue; }; - let len = length(l); - if (len < 2) { - return l; - } else { - return sort(len, l); - } } -function sort_uniq(cmp, l) { - let sort = (n, l) => { - if (n !== 2) { - if (n === 3 && l) { - let match = l.tl; - if (match) { - let match$1 = match.tl; - if (match$1) { - let x3 = match$1.hd; - let x2 = match.hd; - let x1 = l.hd; - let c = cmp(x1, x2); - if (c === 0) { - let c$1 = cmp(x2, x3); - if (c$1 === 0) { - return { - hd: x2, - tl: /* [] */0 - }; - } else if (c$1 < 0) { - return { - hd: x2, - tl: { - hd: x3, - tl: /* [] */0 - } - }; - } else { - return { - hd: x3, - tl: { - hd: x2, - tl: /* [] */0 - } - }; - } - } - if (c < 0) { - let c$2 = cmp(x2, x3); - if (c$2 === 0) { - return { - hd: x1, - tl: { - hd: x2, - tl: /* [] */0 - } - }; - } - if (c$2 < 0) { - return { - hd: x1, - tl: { - hd: x2, - tl: { - hd: x3, - tl: /* [] */0 - } - } - }; - } - let c$3 = cmp(x1, x3); - if (c$3 === 0) { - return { - hd: x1, - tl: { - hd: x2, - tl: /* [] */0 - } - }; - } else if (c$3 < 0) { - return { - hd: x1, - tl: { - hd: x3, - tl: { - hd: x2, - tl: /* [] */0 - } - } - }; - } else { - return { - hd: x3, - tl: { - hd: x1, - tl: { - hd: x2, - tl: /* [] */0 - } - } - }; - } - } - let c$4 = cmp(x1, x3); - if (c$4 === 0) { - return { - hd: x2, - tl: { - hd: x1, - tl: /* [] */0 - } - }; - } - if (c$4 < 0) { - return { - hd: x2, - tl: { - hd: x1, - tl: { - hd: x3, - tl: /* [] */0 - } - } - }; - } - let c$5 = cmp(x2, x3); - if (c$5 === 0) { - return { - hd: x2, - tl: { - hd: x1, - tl: /* [] */0 - } - }; - } else if (c$5 < 0) { - return { - hd: x2, - tl: { - hd: x3, - tl: { - hd: x1, - tl: /* [] */0 - } - } - }; - } else { - return { - hd: x3, - tl: { - hd: x2, - tl: { - hd: x1, - tl: /* [] */0 - } - } - }; - } - } - - } - - } - - } else if (l) { - let match$2 = l.tl; - if (match$2) { - let x2$1 = match$2.hd; - let x1$1 = l.hd; - let c$6 = cmp(x1$1, x2$1); - if (c$6 === 0) { - return { - hd: x1$1, - tl: /* [] */0 - }; - } else if (c$6 < 0) { - return { - hd: x1$1, - tl: { - hd: x2$1, - tl: /* [] */0 - } - }; - } else { - return { - hd: x2$1, - tl: { - hd: x1$1, - tl: /* [] */0 - } - }; - } - } - - } - let n1 = (n >> 1); - let n2 = n - n1 | 0; - let l2 = chop(n1, l); - let s1 = rev_sort(n1, l); - let s2 = rev_sort(n2, l2); - let _l1 = s1; - let _l2 = s2; - let _accu = /* [] */0; - while (true) { - let accu = _accu; - let l2$1 = _l2; - let l1 = _l1; - if (!l1) { - return rev_append(l2$1, accu); - } - if (!l2$1) { - return rev_append(l1, accu); - } - let t2 = l2$1.tl; - let h2 = l2$1.hd; - let t1 = l1.tl; - let h1 = l1.hd; - let c$7 = cmp(h1, h2); - if (c$7 === 0) { - _accu = { - hd: h1, - tl: accu - }; - _l2 = t2; - _l1 = t1; - continue; - } - if (c$7 > 0) { - _accu = { - hd: h1, - tl: accu - }; - _l1 = t1; - continue; - } - _accu = { - hd: h2, - tl: accu - }; - _l2 = t2; - continue; - }; - }; - let rev_sort = (n, l) => { - if (n !== 2) { - if (n === 3 && l) { - let match = l.tl; - if (match) { - let match$1 = match.tl; - if (match$1) { - let x3 = match$1.hd; - let x2 = match.hd; - let x1 = l.hd; - let c = cmp(x1, x2); - if (c === 0) { - let c$1 = cmp(x2, x3); - if (c$1 === 0) { - return { - hd: x2, - tl: /* [] */0 - }; - } else if (c$1 > 0) { - return { - hd: x2, - tl: { - hd: x3, - tl: /* [] */0 - } - }; - } else { - return { - hd: x3, - tl: { - hd: x2, - tl: /* [] */0 - } - }; - } - } - if (c > 0) { - let c$2 = cmp(x2, x3); - if (c$2 === 0) { - return { - hd: x1, - tl: { - hd: x2, - tl: /* [] */0 - } - }; - } - if (c$2 > 0) { - return { - hd: x1, - tl: { - hd: x2, - tl: { - hd: x3, - tl: /* [] */0 - } - } - }; - } - let c$3 = cmp(x1, x3); - if (c$3 === 0) { - return { - hd: x1, - tl: { - hd: x2, - tl: /* [] */0 - } - }; - } else if (c$3 > 0) { - return { - hd: x1, - tl: { - hd: x3, - tl: { - hd: x2, - tl: /* [] */0 - } - } - }; - } else { - return { - hd: x3, - tl: { - hd: x1, - tl: { - hd: x2, - tl: /* [] */0 - } - } - }; - } - } - let c$4 = cmp(x1, x3); - if (c$4 === 0) { - return { - hd: x2, - tl: { - hd: x1, - tl: /* [] */0 - } - }; - } - if (c$4 > 0) { - return { - hd: x2, - tl: { - hd: x1, - tl: { - hd: x3, - tl: /* [] */0 - } - } - }; - } - let c$5 = cmp(x2, x3); - if (c$5 === 0) { - return { - hd: x2, - tl: { - hd: x1, - tl: /* [] */0 - } - }; - } else if (c$5 > 0) { - return { - hd: x2, - tl: { - hd: x3, - tl: { - hd: x1, - tl: /* [] */0 - } - } - }; - } else { - return { - hd: x3, - tl: { - hd: x2, - tl: { - hd: x1, - tl: /* [] */0 - } - } - }; - } - } - - } - - } - - } else if (l) { - let match$2 = l.tl; - if (match$2) { - let x2$1 = match$2.hd; - let x1$1 = l.hd; - let c$6 = cmp(x1$1, x2$1); - if (c$6 === 0) { - return { - hd: x1$1, - tl: /* [] */0 - }; - } else if (c$6 > 0) { - return { - hd: x1$1, - tl: { - hd: x2$1, - tl: /* [] */0 - } - }; - } else { - return { - hd: x2$1, - tl: { - hd: x1$1, - tl: /* [] */0 - } - }; - } - } - - } - let n1 = (n >> 1); - let n2 = n - n1 | 0; - let l2 = chop(n1, l); - let s1 = sort(n1, l); - let s2 = sort(n2, l2); - let _l1 = s1; - let _l2 = s2; - let _accu = /* [] */0; - while (true) { - let accu = _accu; - let l2$1 = _l2; - let l1 = _l1; - if (!l1) { - return rev_append(l2$1, accu); - } - if (!l2$1) { - return rev_append(l1, accu); - } - let t2 = l2$1.tl; - let h2 = l2$1.hd; - let t1 = l1.tl; - let h1 = l1.hd; - let c$7 = cmp(h1, h2); - if (c$7 === 0) { - _accu = { - hd: h1, - tl: accu - }; - _l2 = t2; - _l1 = t1; - continue; - } - if (c$7 < 0) { - _accu = { - hd: h1, - tl: accu - }; - _l1 = t1; - continue; - } - _accu = { - hd: h2, - tl: accu - }; - _l2 = t2; - continue; - }; +function every2(_l1, _l2, p) { + while (true) { + let l2 = _l2; + let l1 = _l1; + if (!l1) { + return true; + } + if (!l2) { + return true; + } + if (!p(l1.hd, l2.hd)) { + return false; + } + _l2 = l2.tl; + _l1 = l1.tl; + continue; }; - let len = length(l); - if (len < 2) { - return l; - } else { - return sort(len, l); - } } -function compare_lengths(_l1, _l2) { +function compareLength(_l1, _l2) { while (true) { let l2 = _l2; let l1 = _l1; @@ -1620,90 +971,392 @@ function compare_lengths(_l1, _l2) { }; } -function compare_length_with(_l, _n) { +function compare(_l1, _l2, p) { while (true) { - let n = _n; - let l = _l; - if (!l) { - if (n === 0) { - return 0; - } else if (n > 0) { + let l2 = _l2; + let l1 = _l1; + if (!l1) { + if (l2) { return -1; } else { - return 1; + return 0; } } - if (n <= 0) { + if (!l2) { return 1; } - _n = n - 1 | 0; - _l = l.tl; + let c = p(l1.hd, l2.hd); + if (c !== 0) { + return c; + } + _l2 = l2.tl; + _l1 = l1.tl; + continue; + }; +} + +function equal(_l1, _l2, p) { + while (true) { + let l2 = _l2; + let l1 = _l1; + if (!l1) { + if (l2) { + return false; + } else { + return true; + } + } + if (!l2) { + return false; + } + if (!p(l1.hd, l2.hd)) { + return false; + } + _l2 = l2.tl; + _l1 = l1.tl; + continue; + }; +} + +function some2(_l1, _l2, p) { + while (true) { + let l2 = _l2; + let l1 = _l1; + if (!l1) { + return false; + } + if (!l2) { + return false; + } + if (p(l1.hd, l2.hd)) { + return true; + } + _l2 = l2.tl; + _l1 = l1.tl; continue; }; } -let append = Pervasives.$at; +function has(_xs, x, eq) { + while (true) { + let xs = _xs; + if (!xs) { + return false; + } + if (eq(xs.hd, x)) { + return true; + } + _xs = xs.tl; + continue; + }; +} + +function getAssoc(_xs, x, eq) { + while (true) { + let xs = _xs; + if (!xs) { + return; + } + let match = xs.hd; + if (eq(match[0], x)) { + return Primitive_option.some(match[1]); + } + _xs = xs.tl; + continue; + }; +} + +function hasAssoc(_xs, x, eq) { + while (true) { + let xs = _xs; + if (!xs) { + return false; + } + if (eq(xs.hd[0], x)) { + return true; + } + _xs = xs.tl; + continue; + }; +} + +function removeAssoc(xs, x, eq) { + if (!xs) { + return /* [] */0; + } + let l = xs.tl; + let pair = xs.hd; + if (eq(pair[0], x)) { + return l; + } + let cell = { + hd: pair, + tl: /* [] */0 + }; + let removed = removeAssocAuxWithMap(l, x, cell, eq); + if (removed) { + return cell; + } else { + return xs; + } +} + +function setAssoc(xs, x, k, eq) { + if (!xs) { + return { + hd: [ + x, + k + ], + tl: /* [] */0 + }; + } + let l = xs.tl; + let pair = xs.hd; + if (eq(pair[0], x)) { + return { + hd: [ + x, + k + ], + tl: l + }; + } + let cell = { + hd: pair, + tl: /* [] */0 + }; + let replaced = setAssocAuxWithMap(l, x, k, cell, eq); + if (replaced) { + return cell; + } else { + return { + hd: [ + x, + k + ], + tl: xs + }; + } +} + +function sort(xs, cmp) { + let arr = toArray(xs); + arr.sort(cmp); + return fromArray(arr); +} + +function find(_xs, p) { + while (true) { + let xs = _xs; + if (!xs) { + return; + } + let x = xs.hd; + if (p(x)) { + return Primitive_option.some(x); + } + _xs = xs.tl; + continue; + }; +} -let concat = flatten; +function filter(_xs, p) { + while (true) { + let xs = _xs; + if (!xs) { + return /* [] */0; + } + let t = xs.tl; + let h = xs.hd; + if (p(h)) { + let cell = { + hd: h, + tl: /* [] */0 + }; + copyAuxWitFilter(p, t, cell); + return cell; + } + _xs = t; + continue; + }; +} -let filter = find_all; +function filterWithIndex(xs, p) { + let _xs = xs; + let _i = 0; + while (true) { + let i = _i; + let xs$1 = _xs; + if (!xs$1) { + return /* [] */0; + } + let t = xs$1.tl; + let h = xs$1.hd; + if (p(h, i)) { + let cell = { + hd: h, + tl: /* [] */0 + }; + copyAuxWithFilterIndex(p, t, cell, i + 1 | 0); + return cell; + } + _i = i + 1 | 0; + _xs = t; + continue; + }; +} -let sort = stable_sort; +function filterMap(_xs, p) { + while (true) { + let xs = _xs; + if (!xs) { + return /* [] */0; + } + let t = xs.tl; + let h = p(xs.hd); + if (h !== undefined) { + let cell = { + hd: Primitive_option.valFromOption(h), + tl: /* [] */0 + }; + copyAuxWitFilterMap(p, t, cell); + return cell; + } + _xs = t; + continue; + }; +} + +function partition(l, p) { + if (!l) { + return [ + /* [] */0, + /* [] */0 + ]; + } + let h = l.hd; + let nextX = { + hd: h, + tl: /* [] */0 + }; + let nextY = { + hd: h, + tl: /* [] */0 + }; + let b = p(h); + partitionAux(p, l.tl, nextX, nextY); + if (b) { + return [ + nextX, + nextY.tl + ]; + } else { + return [ + nextX.tl, + nextY + ]; + } +} + +function unzip(xs) { + if (!xs) { + return [ + /* [] */0, + /* [] */0 + ]; + } + let match = xs.hd; + let cellX = { + hd: match[0], + tl: /* [] */0 + }; + let cellY = { + hd: match[1], + tl: /* [] */0 + }; + splitAux(xs.tl, cellX, cellY); + return [ + cellX, + cellY + ]; +} + +function zip(l1, l2) { + if (!l1) { + return /* [] */0; + } + if (!l2) { + return /* [] */0; + } + let cell = { + hd: [ + l1.hd, + l2.hd + ], + tl: /* [] */0 + }; + zipAux(l1.tl, l2.tl, cell); + return cell; +} -let fast_sort = stable_sort; +let size = length; export { length, - compare_lengths, - compare_length_with, - cons, - hd, - tl, - nth, - nth_opt, - rev, - init, - append, - rev_append, + size, + head, + headExn, + tail, + tailExn, + add, + get, + getExn, + make, + fromInitializer, + toShuffled, + drop, + take, + splitAt, concat, - flatten, - iter, - iteri, + concatMany, + reverseConcat, + flat, map, - mapi$1 as mapi, - rev_map, - fold_left, - fold_right, - iter2, - map2, - rev_map2, - fold_left2, - fold_right2, - for_all, - exists, - for_all2, - exists2, - mem, - memq, + zip, + zipBy, + mapWithIndex, + fromArray, + toArray, + reverse, + mapReverse, + forEach, + forEachWithIndex, + reduce, + reduceWithIndex, + reduceReverse, + mapReverse2, + forEach2, + reduce2, + reduceReverse2, + every, + some, + every2, + some2, + compareLength, + compare, + equal, + has, find, - find_opt, filter, - find_all, + filterWithIndex, + filterMap, partition, - assoc, - assoc_opt, - assq, - assq_opt, - mem_assoc, - mem_assq, - remove_assoc, - remove_assq, - split, - combine, + unzip, + getAssoc, + hasAssoc, + removeAssoc, + setAssoc, sort, - stable_sort, - fast_sort, - sort_uniq, - merge, } /* No side effect */ diff --git a/lib/es6/Math.js b/lib/es6/Math.js new file mode 100644 index 0000000000..964eb210be --- /dev/null +++ b/lib/es6/Math.js @@ -0,0 +1,29 @@ + + + +let Constants = {}; + +function floor(f) { + return Math.floor(f) | 0; +} + +function ceil(f) { + return Math.ceil(f) | 0; +} + +function random(min, max) { + let f = Math.random() * (max - min | 0); + return (Math.floor(f) | 0) + min | 0; +} + +let Int = { + floor: floor, + ceil: ceil, + random: random +}; + +export { + Constants, + Int, +} +/* No side effect */ diff --git a/lib/es6/Null.js b/lib/es6/Null.js new file mode 100644 index 0000000000..42519ac00b --- /dev/null +++ b/lib/es6/Null.js @@ -0,0 +1,86 @@ + + +import * as Option from "./Option.js"; +import * as Primitive_option from "./Primitive_option.js"; + +function fromOption(option) { + if (option !== undefined) { + return Primitive_option.valFromOption(option); + } + +} + +function equal(a, b, eq) { + return Option.equal((a == null) ? undefined : Primitive_option.some(a), (b == null) ? undefined : Primitive_option.some(b), eq); +} + +function compare(a, b, cmp) { + return Option.compare((a == null) ? undefined : Primitive_option.some(a), (b == null) ? undefined : Primitive_option.some(b), cmp); +} + +function getOr(value, $$default) { + if (value == null) { + return $$default; + } else { + return value; + } +} + +function getExn(value) { + if (!(value == null)) { + return value; + } + throw { + RE_EXN_ID: "Invalid_argument", + _1: "Null.getExn: value is null", + Error: new Error() + }; +} + +function forEach(value, f) { + if (!(value == null)) { + return f(value); + } + +} + +function map(value, f) { + if (!(value == null)) { + return f(value); + } + +} + +function mapOr(value, $$default, f) { + if (value == null) { + return $$default; + } else { + return f(value); + } +} + +function flatMap(value, f) { + if (!(value == null)) { + return f(value); + } + +} + +let getWithDefault = getOr; + +let mapWithDefault = mapOr; + +export { + equal, + compare, + fromOption, + getOr, + getWithDefault, + getExn, + forEach, + map, + mapOr, + mapWithDefault, + flatMap, +} +/* No side effect */ diff --git a/lib/es6/Nullable.js b/lib/es6/Nullable.js new file mode 100644 index 0000000000..714f9d68a8 --- /dev/null +++ b/lib/es6/Nullable.js @@ -0,0 +1,88 @@ + + +import * as Option from "./Option.js"; +import * as Primitive_option from "./Primitive_option.js"; + +function fromOption(option) { + if (option !== undefined) { + return Primitive_option.valFromOption(option); + } + +} + +function equal(a, b, eq) { + return Option.equal(a === null ? undefined : Primitive_option.some(a), b === null ? undefined : Primitive_option.some(b), eq); +} + +function compare(a, b, cmp) { + return Option.compare(a === null ? undefined : Primitive_option.some(a), b === null ? undefined : Primitive_option.some(b), cmp); +} + +function getOr(value, $$default) { + if (value !== null) { + return value; + } else { + return $$default; + } +} + +function getExn(value) { + if (value !== null) { + return value; + } + throw { + RE_EXN_ID: "Invalid_argument", + _1: "Nullable.getExn: value is null or undefined", + Error: new Error() + }; +} + +function forEach(value, f) { + if (value !== null) { + return f(value); + } + +} + +function map(value, f) { + if (value !== null) { + return f(value); + } else { + return value; + } +} + +function mapOr(value, $$default, f) { + if (value !== null) { + return f(value); + } else { + return $$default; + } +} + +function flatMap(value, f) { + if (value !== null) { + return f(value); + } else { + return value; + } +} + +let getWithDefault = getOr; + +let mapWithDefault = mapOr; + +export { + equal, + compare, + fromOption, + getOr, + getWithDefault, + getExn, + forEach, + map, + mapOr, + mapWithDefault, + flatMap, +} +/* No side effect */ diff --git a/lib/es6/Object.js b/lib/es6/Object.js new file mode 100644 index 0000000000..ae1b9f17e6 --- /dev/null +++ b/lib/es6/Object.js @@ -0,0 +1 @@ +/* This output is empty. Its source's type definitions, externals and/or unused code got optimized away. */ diff --git a/lib/es6/Option.js b/lib/es6/Option.js new file mode 100644 index 0000000000..d869bbcd7b --- /dev/null +++ b/lib/es6/Option.js @@ -0,0 +1,120 @@ + + +import * as $$Error from "./Error.js"; +import * as Primitive_option from "./Primitive_option.js"; + +function filter(opt, p) { + if (opt !== undefined && p(Primitive_option.valFromOption(opt))) { + return opt; + } + +} + +function forEach(opt, f) { + if (opt !== undefined) { + return f(Primitive_option.valFromOption(opt)); + } + +} + +function getExn(x, message) { + if (x !== undefined) { + return Primitive_option.valFromOption(x); + } else { + return $$Error.panic(message !== undefined ? message : "Option.getExn called for None value"); + } +} + +function mapOr(opt, $$default, f) { + if (opt !== undefined) { + return f(Primitive_option.valFromOption(opt)); + } else { + return $$default; + } +} + +function map(opt, f) { + if (opt !== undefined) { + return Primitive_option.some(f(Primitive_option.valFromOption(opt))); + } + +} + +function flatMap(opt, f) { + if (opt !== undefined) { + return f(Primitive_option.valFromOption(opt)); + } + +} + +function getOr(opt, $$default) { + if (opt !== undefined) { + return Primitive_option.valFromOption(opt); + } else { + return $$default; + } +} + +function orElse(opt, other) { + if (opt !== undefined) { + return opt; + } else { + return other; + } +} + +function isSome(x) { + return x !== undefined; +} + +function isNone(x) { + return x === undefined; +} + +function equal(a, b, eq) { + if (a !== undefined) { + if (b !== undefined) { + return eq(Primitive_option.valFromOption(a), Primitive_option.valFromOption(b)); + } else { + return false; + } + } else { + return b === undefined; + } +} + +function compare(a, b, cmp) { + if (a !== undefined) { + if (b !== undefined) { + return cmp(Primitive_option.valFromOption(a), Primitive_option.valFromOption(b)); + } else { + return 1; + } + } else if (b !== undefined) { + return -1; + } else { + return 0; + } +} + +let mapWithDefault = mapOr; + +let getWithDefault = getOr; + +export { + filter, + forEach, + getExn, + mapOr, + mapWithDefault, + map, + flatMap, + getOr, + getWithDefault, + orElse, + isSome, + isNone, + equal, + compare, +} +/* No side effect */ diff --git a/lib/es6/Ordering.js b/lib/es6/Ordering.js new file mode 100644 index 0000000000..c249cde65b --- /dev/null +++ b/lib/es6/Ordering.js @@ -0,0 +1,37 @@ + + + +function isLess(ord) { + return ord < 0; +} + +function isEqual(ord) { + return ord === 0; +} + +function isGreater(ord) { + return ord > 0; +} + +function invert(ord) { + return - ord; +} + +function fromInt(n) { + if (n < 0) { + return -1; + } else if (n > 0) { + return 1; + } else { + return 0; + } +} + +export { + isLess, + isEqual, + isGreater, + invert, + fromInt, +} +/* No side effect */ diff --git a/lib/es6/Pervasives.js b/lib/es6/Pervasives.js index 754d72f936..ee989cf955 100644 --- a/lib/es6/Pervasives.js +++ b/lib/es6/Pervasives.js @@ -1,5 +1,6 @@ +import * as $$Error from "./Error.js"; import * as Primitive_exceptions from "./Primitive_exceptions.js"; function failwith(s) { @@ -18,7 +19,7 @@ function invalid_arg(s) { }; } -let Exit = /* @__PURE__ */Primitive_exceptions.create("Pervasives.Pervasives.Exit"); +let Exit = /* @__PURE__ */Primitive_exceptions.create("Pervasives.Exit"); function abs(x) { if (x >= 0) { @@ -115,28 +116,6 @@ function $at(l1, l2) { } } -let Pervasives = { - failwith: failwith, - invalid_arg: invalid_arg, - Exit: Exit, - abs: abs, - lnot: lnot, - max_int: 2147483647, - min_int: min_int, - infinity: Infinity, - neg_infinity: -Infinity, - max_float: 1.79769313486231571e+308, - min_float: 2.22507385850720138e-308, - epsilon_float: 2.22044604925031308e-16, - classify_float: classify_float, - char_of_int: char_of_int, - string_of_bool: string_of_bool, - bool_of_string: bool_of_string, - bool_of_string_opt: bool_of_string_opt, - int_of_string_opt: int_of_string_opt, - $at: $at -}; - let max_int = 2147483647; let infinity = Infinity; @@ -149,8 +128,9 @@ let min_float = 2.22507385850720138e-308; let epsilon_float = 2.22044604925031308e-16; +let panic = $$Error.panic; + export { - Pervasives, failwith, invalid_arg, Exit, @@ -170,5 +150,6 @@ export { bool_of_string_opt, int_of_string_opt, $at, + panic, } /* No side effect */ diff --git a/lib/es6/Promise.js b/lib/es6/Promise.js new file mode 100644 index 0000000000..475b96b4d9 --- /dev/null +++ b/lib/es6/Promise.js @@ -0,0 +1,12 @@ + + +import * as Primitive_exceptions from "./Primitive_exceptions.js"; + +function $$catch(promise, callback) { + return promise.catch(err => callback(Primitive_exceptions.internalToException(err))); +} + +export { + $$catch, +} +/* No side effect */ diff --git a/lib/es6/RegExp.js b/lib/es6/RegExp.js new file mode 100644 index 0000000000..e3ed57758e --- /dev/null +++ b/lib/es6/RegExp.js @@ -0,0 +1,9 @@ + + + +let Result = {}; + +export { + Result, +} +/* No side effect */ diff --git a/lib/es6/Result.js b/lib/es6/Result.js new file mode 100644 index 0000000000..bda5bad6c7 --- /dev/null +++ b/lib/es6/Result.js @@ -0,0 +1,130 @@ + + + +function getExn(x) { + if (x.TAG === "Ok") { + return x._0; + } + throw { + RE_EXN_ID: "Not_found", + Error: new Error() + }; +} + +function mapOr(opt, $$default, f) { + if (opt.TAG === "Ok") { + return f(opt._0); + } else { + return $$default; + } +} + +function map(opt, f) { + if (opt.TAG === "Ok") { + return { + TAG: "Ok", + _0: f(opt._0) + }; + } else { + return opt; + } +} + +function flatMap(opt, f) { + if (opt.TAG === "Ok") { + return f(opt._0); + } else { + return opt; + } +} + +function getOr(opt, $$default) { + if (opt.TAG === "Ok") { + return opt._0; + } else { + return $$default; + } +} + +function isOk(x) { + if (x.TAG === "Ok") { + return true; + } else { + return false; + } +} + +function isError(x) { + if (x.TAG === "Ok") { + return false; + } else { + return true; + } +} + +function equal(a, b, f) { + if (a.TAG === "Ok") { + if (b.TAG === "Ok") { + return f(a._0, b._0); + } else { + return false; + } + } else if (b.TAG === "Ok") { + return false; + } else { + return true; + } +} + +function compare(a, b, f) { + if (a.TAG === "Ok") { + if (b.TAG === "Ok") { + return f(a._0, b._0); + } else { + return 1; + } + } else if (b.TAG === "Ok") { + return -1; + } else { + return 0; + } +} + +function forEach(r, f) { + if (r.TAG === "Ok") { + return f(r._0); + } + +} + +function mapError(r, f) { + if (r.TAG === "Ok") { + return r; + } else { + return { + TAG: "Error", + _0: f(r._0) + }; + } +} + +let mapWithDefault = mapOr; + +let getWithDefault = getOr; + +export { + getExn, + mapOr, + mapWithDefault, + map, + flatMap, + getOr, + getWithDefault, + isOk, + isError, + equal, + compare, + forEach, + mapError, +} +/* No side effect */ diff --git a/lib/es6/String.js b/lib/es6/String.js index f4f200eb1c..d68111d2a3 100644 --- a/lib/es6/String.js +++ b/lib/es6/String.js @@ -1,323 +1,33 @@ -import * as Char from "./Char.js"; -import * as $$Array from "./Array.js"; -import * as Primitive_exceptions from "./Primitive_exceptions.js"; -function apply1(f, bytes) { - if (bytes.length === 0) { - return bytes; +function indexOfOpt(s, search) { + let index = s.indexOf(search); + if (index !== -1) { + return index; } - let r = bytes.slice(); - r[0] = f(bytes[0]); - return r; + } -function concat(sep, xs) { - return $$Array.of_list(xs).join(sep); -} - -function bos(str) { - return $$Array.map(str => str.codePointAt(0), Array.from(str)); -} - -function make(len, ch) { - return String.fromCodePoint(ch).repeat(len); -} - -function init(len, f) { - return $$Array.init(len, i => String.fromCodePoint(f(i))).join(""); -} - -function sub(s, ofs, len) { - return String.fromCodePoint(...$$Array.sub(bos(s), ofs, len)); -} - -function iter(f, s) { - for (let i = 0, i_finish = s.length; i < i_finish; ++i) { - f(s.codePointAt(i)); - } -} - -function iteri(f, s) { - for (let i = 0, i_finish = s.length; i < i_finish; ++i) { - f(i, s.codePointAt(i)); - } -} - -function map(f, s) { - return String.fromCodePoint(...$$Array.map(f, bos(s))); -} - -function mapi(f, s) { - return String.fromCodePoint(...$$Array.mapi(f, bos(s))); -} - -function escaped(s) { - let needs_escape = _i => { - while (true) { - let i = _i; - if (i >= s.length) { - return false; - } - let match = s.codePointAt(i); - if (match < 32) { - return true; - } - if (match > 92 || match < 34) { - if (match >= 127) { - return true; - } - _i = i + 1 | 0; - continue; - } - if (match > 91 || match < 35) { - return true; - } - _i = i + 1 | 0; - continue; - }; - }; - if (!needs_escape(0)) { - return s; - } - let bytes = bos(s); - return $$Array.map(Char.escaped, bytes).join(""); -} - -function index_rec(s, lim, _i, c) { - while (true) { - let i = _i; - if (i >= lim) { - throw { - RE_EXN_ID: "Not_found", - Error: new Error() - }; - } - if (s.codePointAt(i) === c) { - return i; - } - _i = i + 1 | 0; - continue; - }; -} - -function index(s, c) { - return index_rec(s, s.length, 0, c); -} - -function index_rec_opt(s, lim, _i, c) { - while (true) { - let i = _i; - if (i >= lim) { - return; - } - if (s.codePointAt(i) === c) { - return i; - } - _i = i + 1 | 0; - continue; - }; -} - -function index_opt(s, c) { - return index_rec_opt(s, s.length, 0, c); -} - -function index_from(s, i, c) { - let l = s.length; - if (i < 0 || i > l) { - throw { - RE_EXN_ID: "Invalid_argument", - _1: "String.index_from / Bytes.index_from", - Error: new Error() - }; - } - return index_rec(s, l, i, c); -} - -function index_from_opt(s, i, c) { - let l = s.length; - if (i < 0 || i > l) { - throw { - RE_EXN_ID: "Invalid_argument", - _1: "String.index_from_opt / Bytes.index_from_opt", - Error: new Error() - }; +function lastIndexOfOpt(s, search) { + let index = s.lastIndexOf(search); + if (index !== -1) { + return index; } - return index_rec_opt(s, l, i, c); -} - -function rindex_rec(s, _i, c) { - while (true) { - let i = _i; - if (i < 0) { - throw { - RE_EXN_ID: "Not_found", - Error: new Error() - }; - } - if (s.codePointAt(i) === c) { - return i; - } - _i = i - 1 | 0; - continue; - }; -} - -function rindex(s, c) { - return rindex_rec(s, s.length - 1 | 0, c); -} - -function rindex_from(s, i, c) { - if (i < -1 || i >= s.length) { - throw { - RE_EXN_ID: "Invalid_argument", - _1: "String.rindex_from / Bytes.rindex_from", - Error: new Error() - }; - } - return rindex_rec(s, i, c); -} - -function rindex_rec_opt(s, _i, c) { - while (true) { - let i = _i; - if (i < 0) { - return; - } - if (s.codePointAt(i) === c) { - return i; - } - _i = i - 1 | 0; - continue; - }; -} - -function rindex_opt(s, c) { - return rindex_rec_opt(s, s.length - 1 | 0, c); -} - -function rindex_from_opt(s, i, c) { - if (i < -1 || i >= s.length) { - throw { - RE_EXN_ID: "Invalid_argument", - _1: "String.rindex_from_opt / Bytes.rindex_from_opt", - Error: new Error() - }; - } - return rindex_rec_opt(s, i, c); -} - -function contains_from(s, i, c) { - let l = s.length; - if (i < 0 || i > l) { - throw { - RE_EXN_ID: "Invalid_argument", - _1: "String.contains_from / Bytes.contains_from", - Error: new Error() - }; - } - try { - index_rec(s, l, i, c); - return true; - } catch (raw_exn) { - let exn = Primitive_exceptions.internalToException(raw_exn); - if (exn.RE_EXN_ID === "Not_found") { - return false; - } - throw exn; - } -} - -function contains(s, c) { - return contains_from(s, 0, c); -} - -function rcontains_from(s, i, c) { - if (i < 0 || i >= s.length) { - throw { - RE_EXN_ID: "Invalid_argument", - _1: "String.rcontains_from / Bytes.rcontains_from", - Error: new Error() - }; - } - try { - rindex_rec(s, i, c); - return true; - } catch (raw_exn) { - let exn = Primitive_exceptions.internalToException(raw_exn); - if (exn.RE_EXN_ID === "Not_found") { - return false; - } - throw exn; - } -} - -function uppercase_ascii(s) { - let bytes = bos(s); - return String.fromCodePoint(...$$Array.map(Char.uppercase_ascii, bytes)); -} - -function lowercase_ascii(s) { - let bytes = bos(s); - return String.fromCodePoint(...$$Array.map(Char.lowercase_ascii, bytes)); -} - -function capitalize_ascii(s) { - let bytes = bos(s); - return String.fromCodePoint(...apply1(Char.uppercase_ascii, bytes)); -} - -function uncapitalize_ascii(s) { - let bytes = bos(s); - return String.fromCodePoint(...apply1(Char.lowercase_ascii, bytes)); + } -function split_on_char(sep, s) { - let r = /* [] */0; - let j = s.length; - for (let i = s.length - 1 | 0; i >= 0; --i) { - if (s.codePointAt(i) === sep) { - r = { - hd: sub(s, i + 1 | 0, (j - i | 0) - 1 | 0), - tl: r - }; - j = i; - } - +function searchOpt(s, re) { + let index = s.search(re); + if (index !== -1) { + return index; } - return { - hd: sub(s, 0, j), - tl: r - }; + } export { - make, - init, - sub, - concat, - iter, - iteri, - map, - mapi, - escaped, - index, - index_opt, - rindex, - rindex_opt, - index_from, - index_from_opt, - rindex_from, - rindex_from_opt, - contains, - contains_from, - rcontains_from, - uppercase_ascii, - lowercase_ascii, - capitalize_ascii, - uncapitalize_ascii, - split_on_char, + indexOfOpt, + lastIndexOfOpt, + searchOpt, } /* No side effect */ diff --git a/lib/es6/Symbol.js b/lib/es6/Symbol.js new file mode 100644 index 0000000000..ae1b9f17e6 --- /dev/null +++ b/lib/es6/Symbol.js @@ -0,0 +1 @@ +/* This output is empty. Its source's type definitions, externals and/or unused code got optimized away. */ diff --git a/lib/es6/Type.js b/lib/es6/Type.js new file mode 100644 index 0000000000..9ee5d6e69d --- /dev/null +++ b/lib/es6/Type.js @@ -0,0 +1,58 @@ + + + +function classify(value) { + let match = Object.prototype.toString.call(value); + switch (match) { + case "[object BigInt]" : + return { + TAG: "BigInt", + _0: value + }; + case "[object Boolean]" : + return { + TAG: "Bool", + _0: value + }; + case "[object AsyncFunction]" : + case "[object Function]" : + case "[object GeneratorFunction]" : + return { + TAG: "Function", + _0: value + }; + case "[object Null]" : + return "Null"; + case "[object Number]" : + return { + TAG: "Number", + _0: value + }; + case "[object String]" : + return { + TAG: "String", + _0: value + }; + case "[object Symbol]" : + return { + TAG: "Symbol", + _0: value + }; + case "[object Undefined]" : + return "Undefined"; + default: + return { + TAG: "Object", + _0: value + }; + } +} + +let Classify = { + classify: classify +}; + +export { + Classify, +} +/* No side effect */ diff --git a/lib/es6/TypedArray.js b/lib/es6/TypedArray.js new file mode 100644 index 0000000000..ae1b9f17e6 --- /dev/null +++ b/lib/es6/TypedArray.js @@ -0,0 +1 @@ +/* This output is empty. Its source's type definitions, externals and/or unused code got optimized away. */ diff --git a/lib/es6/Uint16Array.js b/lib/es6/Uint16Array.js new file mode 100644 index 0000000000..cd168743c9 --- /dev/null +++ b/lib/es6/Uint16Array.js @@ -0,0 +1,9 @@ + + + +let Constants = {}; + +export { + Constants, +} +/* No side effect */ diff --git a/lib/es6/Uint32Array.js b/lib/es6/Uint32Array.js new file mode 100644 index 0000000000..cd168743c9 --- /dev/null +++ b/lib/es6/Uint32Array.js @@ -0,0 +1,9 @@ + + + +let Constants = {}; + +export { + Constants, +} +/* No side effect */ diff --git a/lib/es6/Uint8Array.js b/lib/es6/Uint8Array.js new file mode 100644 index 0000000000..cd168743c9 --- /dev/null +++ b/lib/es6/Uint8Array.js @@ -0,0 +1,9 @@ + + + +let Constants = {}; + +export { + Constants, +} +/* No side effect */ diff --git a/lib/es6/Uint8ClampedArray.js b/lib/es6/Uint8ClampedArray.js new file mode 100644 index 0000000000..cd168743c9 --- /dev/null +++ b/lib/es6/Uint8ClampedArray.js @@ -0,0 +1,9 @@ + + + +let Constants = {}; + +export { + Constants, +} +/* No side effect */ diff --git a/lib/es6/WeakMap.js b/lib/es6/WeakMap.js new file mode 100644 index 0000000000..ae1b9f17e6 --- /dev/null +++ b/lib/es6/WeakMap.js @@ -0,0 +1 @@ +/* This output is empty. Its source's type definitions, externals and/or unused code got optimized away. */ diff --git a/lib/es6/WeakSet.js b/lib/es6/WeakSet.js new file mode 100644 index 0000000000..ae1b9f17e6 --- /dev/null +++ b/lib/es6/WeakSet.js @@ -0,0 +1 @@ +/* This output is empty. Its source's type definitions, externals and/or unused code got optimized away. */ diff --git a/lib/js/Array.js b/lib/js/Array.js index 2e6213b61d..2af73849d4 100644 --- a/lib/js/Array.js +++ b/lib/js/Array.js @@ -1,495 +1,190 @@ 'use strict'; -let List = require("./List.js"); -let Primitive_array = require("./Primitive_array.js"); -let Primitive_exceptions = require("./Primitive_exceptions.js"); +let Primitive_option = require("./Primitive_option.js"); -let init = ((length, f) => Array.from({ length }, f)); - -function make(len, x) { - return init(len, param => x); -} - -function unsafe_sub(array, offset, length) { - return array.slice(offset, offset + length | 0); -} - -function concat(list) { - return List.fold_left((arr1, arr2) => arr1.concat(arr2), [], list); -} - -function create_float(len) { - return init(len, param => 0.0); -} - -function make_matrix(sx, sy, init$1) { - let x = []; - let res = init(sx, param => x); - for (let x$1 = 0; x$1 < sx; ++x$1) { - res[x$1] = init(sy, param => init$1); +function make(length, x) { + if (length <= 0) { + return []; } - return res; + let arr = new Array(length); + arr.fill(x); + return arr; } -function append(a1, a2) { - let l1 = a1.length; - if (l1 === 0) { - return a2.slice(); - } else if (a2.length === 0) { - return unsafe_sub(a1, 0, l1); - } else { - return a1.concat(a2); +function fromInitializer(length, f) { + if (length <= 0) { + return []; } + let arr = new Array(length); + for (let i = 0; i < length; ++i) { + arr[i] = f(i); + } + return arr; } -function sub(a, ofs, len) { - if (ofs < 0 || len < 0 || ofs > (a.length - len | 0)) { - throw { - RE_EXN_ID: "Invalid_argument", - _1: "Array.sub", - Error: new Error() +function equal(a, b, eq) { + let len = a.length; + if (len === b.length) { + let _i = 0; + while (true) { + let i = _i; + if (i === len) { + return true; + } + if (!eq(a[i], b[i])) { + return false; + } + _i = i + 1 | 0; + continue; }; + } else { + return false; } - return unsafe_sub(a, ofs, len); } -function fill(a, ofs, len, v) { - if (ofs < 0 || len < 0 || ofs > (a.length - len | 0)) { - throw { - RE_EXN_ID: "Invalid_argument", - _1: "Array.fill", - Error: new Error() +function compare(a, b, cmp) { + let lenA = a.length; + let lenB = b.length; + if (lenA < lenB) { + return -1; + } else if (lenA > lenB) { + return 1; + } else { + let _i = 0; + while (true) { + let i = _i; + if (i === lenA) { + return 0; + } + let c = cmp(a[i], b[i]); + if (c !== 0) { + return c; + } + _i = i + 1 | 0; + continue; }; } - for (let i = ofs, i_finish = ofs + len | 0; i < i_finish; ++i) { - a[i] = v; - } } -function blit(a1, ofs1, a2, ofs2, len) { - if (len < 0 || ofs1 < 0 || ofs1 > (a1.length - len | 0) || ofs2 < 0 || ofs2 > (a2.length - len | 0)) { - throw { - RE_EXN_ID: "Invalid_argument", - _1: "Array.blit", - Error: new Error() - }; - } - for (let i = 0; i < len; ++i) { - a2[ofs2 + i | 0] = a1[ofs1 + i | 0]; +function indexOfOpt(arr, item) { + let index = arr.indexOf(item); + if (index !== -1) { + return index; } + } -function iter(f, a) { - for (let i = 0, i_finish = a.length; i < i_finish; ++i) { - f(a[i]); +function lastIndexOfOpt(arr, item) { + let index = arr.lastIndexOf(item); + if (index !== -1) { + return index; } + } -function iter2(f, a, b) { - if (a.length !== b.length) { - throw { - RE_EXN_ID: "Invalid_argument", - _1: "Array.iter2: arrays must have the same length", - Error: new Error() - }; - } - for (let i = 0, i_finish = a.length; i < i_finish; ++i) { - f(a[i], b[i]); - } +function reduce(arr, init, f) { + return arr.reduce(f, init); } -function map(f, a) { - let l = a.length; - if (l === 0) { - return []; - } - let x = f(a[0]); - let r = init(l, param => x); - for (let i = 1; i < l; ++i) { - r[i] = f(a[i]); - } - return r; +function reduceWithIndex(arr, init, f) { + return arr.reduce(f, init); } -function map2(f, a, b) { - let la = a.length; - let lb = b.length; - if (la !== lb) { - throw { - RE_EXN_ID: "Invalid_argument", - _1: "Array.map2: arrays must have the same length", - Error: new Error() - }; - } - if (la === 0) { - return []; - } - let x = f(a[0], b[0]); - let r = init(la, param => x); - for (let i = 1; i < la; ++i) { - r[i] = f(a[i], b[i]); - } - return r; +function reduceRight(arr, init, f) { + return arr.reduceRight(f, init); } -function iteri(f, a) { - for (let i = 0, i_finish = a.length; i < i_finish; ++i) { - f(i, a[i]); - } +function reduceRightWithIndex(arr, init, f) { + return arr.reduceRight(f, init); } -function mapi(f, a) { - let l = a.length; - if (l === 0) { - return []; - } - let x = f(0, a[0]); - let r = init(l, param => x); - for (let i = 1; i < l; ++i) { - r[i] = f(i, a[i]); +function findIndexOpt(array, finder) { + let index = array.findIndex(finder); + if (index !== -1) { + return index; } - return r; + } -function to_list(a) { - let _i = a.length - 1 | 0; - let _res = /* [] */0; - while (true) { - let res = _res; - let i = _i; - if (i < 0) { - return res; - } - _res = { - hd: a[i], - tl: res - }; - _i = i - 1 | 0; - continue; - }; +function swapUnsafe(xs, i, j) { + let tmp = xs[i]; + xs[i] = xs[j]; + xs[j] = tmp; } -function list_length(_accu, _param) { - while (true) { - let param = _param; - let accu = _accu; - if (!param) { - return accu; - } - _param = param.tl; - _accu = accu + 1 | 0; - continue; - }; +function random_int(min, max) { + return (Math.floor(Math.random() * (max - min | 0)) | 0) + min | 0; } -function of_list(param) { - if (!param) { - return []; +function shuffle(xs) { + let len = xs.length; + for (let i = 0; i < len; ++i) { + swapUnsafe(xs, i, random_int(i, len)); } - let hd = param.hd; - let len = list_length(0, param); - let a = init(len, param => hd); - let _i = 1; - let _param = param.tl; - while (true) { - let param$1 = _param; - let i = _i; - if (!param$1) { - return a; - } - a[i] = param$1.hd; - _param = param$1.tl; - _i = i + 1 | 0; - continue; - }; } -function fold_left(f, x, a) { - let r = x; - for (let i = 0, i_finish = a.length; i < i_finish; ++i) { - r = f(r, a[i]); - } - return r; +function toShuffled(xs) { + let result = xs.slice(); + shuffle(result); + return result; } -function fold_right(f, a, x) { - let r = x; - for (let i = a.length - 1 | 0; i >= 0; --i) { - r = f(a[i], r); - } +function filterMap(a, f) { + let l = a.length; + let r = new Array(l); + let j = 0; + for (let i = 0; i < l; ++i) { + let v = a[i]; + let v$1 = f(v); + if (v$1 !== undefined) { + r[j] = Primitive_option.valFromOption(v$1); + j = j + 1 | 0; + } + + } + r.length = j; return r; } -function exists(p, a) { - let n = a.length; - let _i = 0; - while (true) { - let i = _i; - if (i === n) { - return false; - } - if (p(a[i])) { - return true; - } - _i = i + 1 | 0; - continue; - }; +function keepSome(__x) { + return filterMap(__x, x => x); } -function for_all(p, a) { - let n = a.length; +function findMap(arr, f) { let _i = 0; while (true) { let i = _i; - if (i === n) { - return true; + if (i === arr.length) { + return; } - if (!p(a[i])) { - return false; + let r = f(arr[i]); + if (r !== undefined) { + return r; } _i = i + 1 | 0; continue; }; } -function mem(x, a) { - let n = a.length; - let _i = 0; - while (true) { - let i = _i; - if (i === n) { - return false; - } - if (a[i] === x) { - return true; - } - _i = i + 1 | 0; - continue; - }; +function last(a) { + return a[a.length - 1 | 0]; } -function memq(x, a) { - let n = a.length; - let _i = 0; - while (true) { - let i = _i; - if (i === n) { - return false; - } - if (x === a[i]) { - return true; - } - _i = i + 1 | 0; - continue; - }; -} - -let Bottom = /* @__PURE__ */Primitive_exceptions.create("Array.Bottom"); - -function sort(cmp, a) { - let maxson = (l, i) => { - let i31 = ((i + i | 0) + i | 0) + 1 | 0; - let x = i31; - if ((i31 + 2 | 0) < l) { - if (cmp(Primitive_array.get(a, i31), Primitive_array.get(a, i31 + 1 | 0)) < 0) { - x = i31 + 1 | 0; - } - if (cmp(Primitive_array.get(a, x), Primitive_array.get(a, i31 + 2 | 0)) < 0) { - x = i31 + 2 | 0; - } - return x; - } - if ((i31 + 1 | 0) < l && cmp(Primitive_array.get(a, i31), Primitive_array.get(a, i31 + 1 | 0)) < 0) { - return i31 + 1 | 0; - } - if (i31 < l) { - return i31; - } - throw { - RE_EXN_ID: Bottom, - _1: i, - Error: new Error() - }; - }; - let trickle = (l, i, e) => { - try { - let _i = i; - while (true) { - let i$1 = _i; - let j = maxson(l, i$1); - if (cmp(Primitive_array.get(a, j), e) <= 0) { - return Primitive_array.set(a, i$1, e); - } - Primitive_array.set(a, i$1, Primitive_array.get(a, j)); - _i = j; - continue; - }; - } catch (raw_i) { - let i$2 = Primitive_exceptions.internalToException(raw_i); - if (i$2.RE_EXN_ID === Bottom) { - return Primitive_array.set(a, i$2._1, e); - } - throw i$2; - } - }; - let bubble = (l, i) => { - try { - let _i = i; - while (true) { - let i$1 = _i; - let j = maxson(l, i$1); - Primitive_array.set(a, i$1, Primitive_array.get(a, j)); - _i = j; - continue; - }; - } catch (raw_i) { - let i$2 = Primitive_exceptions.internalToException(raw_i); - if (i$2.RE_EXN_ID === Bottom) { - return i$2._1; - } - throw i$2; - } - }; - let trickleup = (_i, e) => { - while (true) { - let i = _i; - let father = (i - 1 | 0) / 3 | 0; - if (i === father) { - throw { - RE_EXN_ID: "Assert_failure", - _1: [ - "Array.res", - 294, - 4 - ], - Error: new Error() - }; - } - if (cmp(Primitive_array.get(a, father), e) >= 0) { - return Primitive_array.set(a, i, e); - } - Primitive_array.set(a, i, Primitive_array.get(a, father)); - if (father <= 0) { - return Primitive_array.set(a, 0, e); - } - _i = father; - continue; - }; - }; - let l = a.length; - for (let i = ((l + 1 | 0) / 3 | 0) - 1 | 0; i >= 0; --i) { - trickle(l, i, Primitive_array.get(a, i)); - } - for (let i$1 = l - 1 | 0; i$1 >= 2; --i$1) { - let e = Primitive_array.get(a, i$1); - Primitive_array.set(a, i$1, Primitive_array.get(a, 0)); - trickleup(bubble(i$1, 0), e); - } - if (l <= 1) { - return; - } - let e$1 = Primitive_array.get(a, 1); - Primitive_array.set(a, 1, Primitive_array.get(a, 0)); - Primitive_array.set(a, 0, e$1); -} - -function stable_sort(cmp, a) { - let merge = (src1ofs, src1len, src2, src2ofs, src2len, dst, dstofs) => { - let src1r = src1ofs + src1len | 0; - let src2r = src2ofs + src2len | 0; - let _i1 = src1ofs; - let _s1 = Primitive_array.get(a, src1ofs); - let _i2 = src2ofs; - let _s2 = Primitive_array.get(src2, src2ofs); - let _d = dstofs; - while (true) { - let d = _d; - let s2 = _s2; - let i2 = _i2; - let s1 = _s1; - let i1 = _i1; - if (cmp(s1, s2) <= 0) { - Primitive_array.set(dst, d, s1); - let i1$1 = i1 + 1 | 0; - if (i1$1 >= src1r) { - return blit(src2, i2, dst, d + 1 | 0, src2r - i2 | 0); - } - _d = d + 1 | 0; - _s1 = Primitive_array.get(a, i1$1); - _i1 = i1$1; - continue; - } - Primitive_array.set(dst, d, s2); - let i2$1 = i2 + 1 | 0; - if (i2$1 >= src2r) { - return blit(a, i1, dst, d + 1 | 0, src1r - i1 | 0); - } - _d = d + 1 | 0; - _s2 = Primitive_array.get(src2, i2$1); - _i2 = i2$1; - continue; - }; - }; - let isortto = (srcofs, dst, dstofs, len) => { - for (let i = 0; i < len; ++i) { - let e = Primitive_array.get(a, srcofs + i | 0); - let j = (dstofs + i | 0) - 1 | 0; - while (j >= dstofs && cmp(Primitive_array.get(dst, j), e) > 0) { - Primitive_array.set(dst, j + 1 | 0, Primitive_array.get(dst, j)); - j = j - 1 | 0; - }; - Primitive_array.set(dst, j + 1 | 0, e); - } - }; - let sortto = (srcofs, dst, dstofs, len) => { - if (len <= 5) { - return isortto(srcofs, dst, dstofs, len); - } - let l1 = len / 2 | 0; - let l2 = len - l1 | 0; - sortto(srcofs + l1 | 0, dst, dstofs + l1 | 0, l2); - sortto(srcofs, a, srcofs + l2 | 0, l1); - merge(srcofs + l2 | 0, l1, dst, dstofs + l1 | 0, l2, dst, dstofs); - }; - let l = a.length; - if (l <= 5) { - return isortto(0, a, 0, l); - } - let l1 = l / 2 | 0; - let l2 = l - l1 | 0; - let x = Primitive_array.get(a, 0); - let t = init(l2, param => x); - sortto(l1, t, 0, l2); - sortto(0, a, l2, l1); - merge(l2, l1, t, 0, l2, a, 0); -} - -let fast_sort = stable_sort; - exports.make = make; -exports.create_float = create_float; -exports.init = init; -exports.make_matrix = make_matrix; -exports.append = append; -exports.concat = concat; -exports.sub = sub; -exports.fill = fill; -exports.blit = blit; -exports.to_list = to_list; -exports.of_list = of_list; -exports.iter = iter; -exports.iteri = iteri; -exports.map = map; -exports.mapi = mapi; -exports.fold_left = fold_left; -exports.fold_right = fold_right; -exports.iter2 = iter2; -exports.map2 = map2; -exports.for_all = for_all; -exports.exists = exists; -exports.mem = mem; -exports.memq = memq; -exports.sort = sort; -exports.stable_sort = stable_sort; -exports.fast_sort = fast_sort; +exports.fromInitializer = fromInitializer; +exports.equal = equal; +exports.compare = compare; +exports.indexOfOpt = indexOfOpt; +exports.lastIndexOfOpt = lastIndexOfOpt; +exports.reduce = reduce; +exports.reduceWithIndex = reduceWithIndex; +exports.reduceRight = reduceRight; +exports.reduceRightWithIndex = reduceRightWithIndex; +exports.findIndexOpt = findIndexOpt; +exports.filterMap = filterMap; +exports.keepSome = keepSome; +exports.toShuffled = toShuffled; +exports.shuffle = shuffle; +exports.findMap = findMap; +exports.last = last; /* No side effect */ diff --git a/lib/js/ArrayBuffer.js b/lib/js/ArrayBuffer.js new file mode 100644 index 0000000000..ae1b9f17e6 --- /dev/null +++ b/lib/js/ArrayBuffer.js @@ -0,0 +1 @@ +/* This output is empty. Its source's type definitions, externals and/or unused code got optimized away. */ diff --git a/lib/js/AsyncIterator.js b/lib/js/AsyncIterator.js new file mode 100644 index 0000000000..c45654bafe --- /dev/null +++ b/lib/js/AsyncIterator.js @@ -0,0 +1,41 @@ +'use strict'; + +let Primitive_option = require("./Primitive_option.js"); + +function value(v) { + return { + done: false, + value: Primitive_option.some(v) + }; +} + +function done(finalValue) { + return { + done: true, + value: finalValue + }; +} + +async function forEach(iterator, f) { + let iteratorDone = false; + while (!iteratorDone) { + let match = await iterator.next(); + f(match.value); + iteratorDone = match.done; + }; +} + +let make = (function makeAsyncIterator(next) { + return { + next, + [Symbol.asyncIterator]() { + return this; + } + } +}); + +exports.make = make; +exports.value = value; +exports.done = done; +exports.forEach = forEach; +/* No side effect */ diff --git a/lib/js/BigInt.js b/lib/js/BigInt.js new file mode 100644 index 0000000000..dbcaa74f96 --- /dev/null +++ b/lib/js/BigInt.js @@ -0,0 +1,14 @@ +'use strict'; + + +function toInt(t) { + return Number(t) | 0; +} + +function lnot(x) { + return x ^ -1n; +} + +exports.toInt = toInt; +exports.lnot = lnot; +/* No side effect */ diff --git a/lib/js/BigInt64Array.js b/lib/js/BigInt64Array.js new file mode 100644 index 0000000000..8ff6f5bdb3 --- /dev/null +++ b/lib/js/BigInt64Array.js @@ -0,0 +1,7 @@ +'use strict'; + + +let Constants = {}; + +exports.Constants = Constants; +/* No side effect */ diff --git a/lib/js/BigUint64Array.js b/lib/js/BigUint64Array.js new file mode 100644 index 0000000000..8ff6f5bdb3 --- /dev/null +++ b/lib/js/BigUint64Array.js @@ -0,0 +1,7 @@ +'use strict'; + + +let Constants = {}; + +exports.Constants = Constants; +/* No side effect */ diff --git a/lib/js/Console.js b/lib/js/Console.js new file mode 100644 index 0000000000..ae1b9f17e6 --- /dev/null +++ b/lib/js/Console.js @@ -0,0 +1 @@ +/* This output is empty. Its source's type definitions, externals and/or unused code got optimized away. */ diff --git a/lib/js/DataView.js b/lib/js/DataView.js new file mode 100644 index 0000000000..ae1b9f17e6 --- /dev/null +++ b/lib/js/DataView.js @@ -0,0 +1 @@ +/* This output is empty. Its source's type definitions, externals and/or unused code got optimized away. */ diff --git a/lib/js/Date.js b/lib/js/Date.js new file mode 100644 index 0000000000..ef4be50a41 --- /dev/null +++ b/lib/js/Date.js @@ -0,0 +1,18 @@ +'use strict'; + +let Primitive_float = require("./Primitive_float.js"); + +let UTC = {}; + +function equal(a, b) { + return a.getTime() === b.getTime(); +} + +function compare(a, b) { + return Primitive_float.compare(a.getTime(), b.getTime()); +} + +exports.UTC = UTC; +exports.equal = equal; +exports.compare = compare; +/* No side effect */ diff --git a/lib/js/Dict.js b/lib/js/Dict.js new file mode 100644 index 0000000000..4e8aab1fe0 --- /dev/null +++ b/lib/js/Dict.js @@ -0,0 +1,28 @@ +'use strict'; + + +function $$delete$1(dict, string) { + delete(dict[string]); +} + +function forEach(dict, f) { + Object.values(dict).forEach(value => f(value)); +} + +function forEachWithKey(dict, f) { + Object.entries(dict).forEach(param => f(param[1], param[0])); +} + +function mapValues(dict, f) { + let target = {}; + forEachWithKey(dict, (value, key) => { + target[key] = f(value); + }); + return target; +} + +exports.$$delete = $$delete$1; +exports.forEach = forEach; +exports.forEachWithKey = forEachWithKey; +exports.mapValues = mapValues; +/* No side effect */ diff --git a/lib/js/Error.js b/lib/js/Error.js new file mode 100644 index 0000000000..bb0913400c --- /dev/null +++ b/lib/js/Error.js @@ -0,0 +1,27 @@ +'use strict'; + + +let $$EvalError = {}; + +let $$RangeError = {}; + +let $$ReferenceError = {}; + +let $$SyntaxError = {}; + +let $$TypeError = {}; + +let $$URIError = {}; + +function panic(msg) { + throw new Error("Panic! " + msg); +} + +exports.$$EvalError = $$EvalError; +exports.$$RangeError = $$RangeError; +exports.$$ReferenceError = $$ReferenceError; +exports.$$SyntaxError = $$SyntaxError; +exports.$$TypeError = $$TypeError; +exports.$$URIError = $$URIError; +exports.panic = panic; +/* No side effect */ diff --git a/lib/js/Js_exn.js b/lib/js/Exn.js similarity index 100% rename from lib/js/Js_exn.js rename to lib/js/Exn.js diff --git a/lib/js/Float.js b/lib/js/Float.js new file mode 100644 index 0000000000..ecb91a0c04 --- /dev/null +++ b/lib/js/Float.js @@ -0,0 +1,27 @@ +'use strict'; + + +let Constants = {}; + +function fromString(i) { + let i$1 = parseFloat(i); + if (isNaN(i$1)) { + return; + } else { + return i$1; + } +} + +function clamp(min, max, value) { + let value$1 = max !== undefined && max < value ? max : value; + if (min !== undefined && min > value$1) { + return min; + } else { + return value$1; + } +} + +exports.Constants = Constants; +exports.fromString = fromString; +exports.clamp = clamp; +/* No side effect */ diff --git a/lib/js/Float32Array.js b/lib/js/Float32Array.js new file mode 100644 index 0000000000..8ff6f5bdb3 --- /dev/null +++ b/lib/js/Float32Array.js @@ -0,0 +1,7 @@ +'use strict'; + + +let Constants = {}; + +exports.Constants = Constants; +/* No side effect */ diff --git a/lib/js/Float64Array.js b/lib/js/Float64Array.js new file mode 100644 index 0000000000..8ff6f5bdb3 --- /dev/null +++ b/lib/js/Float64Array.js @@ -0,0 +1,7 @@ +'use strict'; + + +let Constants = {}; + +exports.Constants = Constants; +/* No side effect */ diff --git a/lib/js/Int.js b/lib/js/Int.js new file mode 100644 index 0000000000..147f1cef99 --- /dev/null +++ b/lib/js/Int.js @@ -0,0 +1,84 @@ +'use strict'; + +let $$Array = require("./Array.js"); + +function fromString(x, radix) { + let maybeInt = radix !== undefined ? parseInt(x, radix) : parseInt(x); + if (isNaN(maybeInt) || maybeInt > 2147483647 || maybeInt < -2147483648) { + return; + } else { + return maybeInt | 0; + } +} + +function abs(x) { + if (x >= 0) { + return x; + } else { + return -x | 0; + } +} + +function range(start, end, optionsOpt) { + let options = optionsOpt !== undefined ? optionsOpt : ({}); + let isInverted = start > end; + let n = options.step; + let step; + if (n !== undefined) { + if (n !== 0) { + step = n; + } else { + if (start !== end) { + throw new RangeError("Incorrect range arguments"); + } + step = n; + } + } else { + step = isInverted ? -1 : 1; + } + let length; + if (isInverted === step >= 0) { + length = 0; + } else if (step === 0) { + length = options.inclusive === true ? 1 : 0; + } else { + let range$1 = isInverted ? start - end | 0 : end - start | 0; + let range$2 = options.inclusive === true ? range$1 + 1 | 0 : range$1; + length = Math.ceil(range$2 / abs(step)) | 0; + } + return $$Array.fromInitializer(length, i => start + Math.imul(i, step) | 0); +} + +function rangeWithOptions(start, end, options) { + return range(start, end, options); +} + +function clamp(min, max, value) { + let value$1 = max !== undefined && max < value ? max : value; + if (min !== undefined && min > value$1) { + return min; + } else { + return value$1; + } +} + +function lnot(x) { + return x ^ -1; +} + +let Bitwise = { + lnot: lnot +}; + +let Constants = { + minValue: -2147483648, + maxValue: 2147483647 +}; + +exports.Constants = Constants; +exports.fromString = fromString; +exports.range = range; +exports.rangeWithOptions = rangeWithOptions; +exports.clamp = clamp; +exports.Bitwise = Bitwise; +/* No side effect */ diff --git a/lib/js/Int16Array.js b/lib/js/Int16Array.js new file mode 100644 index 0000000000..8ff6f5bdb3 --- /dev/null +++ b/lib/js/Int16Array.js @@ -0,0 +1,7 @@ +'use strict'; + + +let Constants = {}; + +exports.Constants = Constants; +/* No side effect */ diff --git a/lib/js/Int32Array.js b/lib/js/Int32Array.js new file mode 100644 index 0000000000..8ff6f5bdb3 --- /dev/null +++ b/lib/js/Int32Array.js @@ -0,0 +1,7 @@ +'use strict'; + + +let Constants = {}; + +exports.Constants = Constants; +/* No side effect */ diff --git a/lib/js/Int8Array.js b/lib/js/Int8Array.js new file mode 100644 index 0000000000..8ff6f5bdb3 --- /dev/null +++ b/lib/js/Int8Array.js @@ -0,0 +1,7 @@ +'use strict'; + + +let Constants = {}; + +exports.Constants = Constants; +/* No side effect */ diff --git a/lib/js/Intl.js b/lib/js/Intl.js new file mode 100644 index 0000000000..58e3e0d4ca --- /dev/null +++ b/lib/js/Intl.js @@ -0,0 +1,34 @@ +'use strict'; + + +let Common; + +let Collator; + +let DateTimeFormat; + +let ListFormat; + +let Locale; + +let NumberFormat; + +let PluralRules; + +let RelativeTimeFormat; + +let Segmenter; + +let Segments; + +exports.Common = Common; +exports.Collator = Collator; +exports.DateTimeFormat = DateTimeFormat; +exports.ListFormat = ListFormat; +exports.Locale = Locale; +exports.NumberFormat = NumberFormat; +exports.PluralRules = PluralRules; +exports.RelativeTimeFormat = RelativeTimeFormat; +exports.Segmenter = Segmenter; +exports.Segments = Segments; +/* No side effect */ diff --git a/lib/js/Intl_Collator.js b/lib/js/Intl_Collator.js new file mode 100644 index 0000000000..ae1b9f17e6 --- /dev/null +++ b/lib/js/Intl_Collator.js @@ -0,0 +1 @@ +/* This output is empty. Its source's type definitions, externals and/or unused code got optimized away. */ diff --git a/lib/js/Intl_Common.js b/lib/js/Intl_Common.js new file mode 100644 index 0000000000..ae1b9f17e6 --- /dev/null +++ b/lib/js/Intl_Common.js @@ -0,0 +1 @@ +/* This output is empty. Its source's type definitions, externals and/or unused code got optimized away. */ diff --git a/lib/js/Intl_DateTimeFormat.js b/lib/js/Intl_DateTimeFormat.js new file mode 100644 index 0000000000..ae1b9f17e6 --- /dev/null +++ b/lib/js/Intl_DateTimeFormat.js @@ -0,0 +1 @@ +/* This output is empty. Its source's type definitions, externals and/or unused code got optimized away. */ diff --git a/lib/js/Intl_ListFormat.js b/lib/js/Intl_ListFormat.js new file mode 100644 index 0000000000..ae1b9f17e6 --- /dev/null +++ b/lib/js/Intl_ListFormat.js @@ -0,0 +1 @@ +/* This output is empty. Its source's type definitions, externals and/or unused code got optimized away. */ diff --git a/lib/js/Intl_Locale.js b/lib/js/Intl_Locale.js new file mode 100644 index 0000000000..ae1b9f17e6 --- /dev/null +++ b/lib/js/Intl_Locale.js @@ -0,0 +1 @@ +/* This output is empty. Its source's type definitions, externals and/or unused code got optimized away. */ diff --git a/lib/js/Intl_NumberFormat.js b/lib/js/Intl_NumberFormat.js new file mode 100644 index 0000000000..0d1f1ed91f --- /dev/null +++ b/lib/js/Intl_NumberFormat.js @@ -0,0 +1,7 @@ +'use strict'; + + +let Grouping; + +exports.Grouping = Grouping; +/* No side effect */ diff --git a/lib/js/Intl_NumberFormat_Grouping.js b/lib/js/Intl_NumberFormat_Grouping.js new file mode 100644 index 0000000000..56dd9f43eb --- /dev/null +++ b/lib/js/Intl_NumberFormat_Grouping.js @@ -0,0 +1,33 @@ +'use strict'; + +let Type = require("./Type.js"); + +function parseJsValue(value) { + let value$1 = Type.Classify.classify(value); + if (typeof value$1 !== "object") { + return; + } + switch (value$1.TAG) { + case "Bool" : + return { + NAME: "bool", + VAL: value$1._0 + }; + case "String" : + switch (value$1._0) { + case "always" : + return "always"; + case "auto" : + return "auto"; + case "min2" : + return "min2"; + default: + return; + } + default: + return; + } +} + +exports.parseJsValue = parseJsValue; +/* No side effect */ diff --git a/lib/js/Intl_PluralRules.js b/lib/js/Intl_PluralRules.js new file mode 100644 index 0000000000..ae1b9f17e6 --- /dev/null +++ b/lib/js/Intl_PluralRules.js @@ -0,0 +1 @@ +/* This output is empty. Its source's type definitions, externals and/or unused code got optimized away. */ diff --git a/lib/js/Intl_RelativeTimeFormat.js b/lib/js/Intl_RelativeTimeFormat.js new file mode 100644 index 0000000000..ae1b9f17e6 --- /dev/null +++ b/lib/js/Intl_RelativeTimeFormat.js @@ -0,0 +1 @@ +/* This output is empty. Its source's type definitions, externals and/or unused code got optimized away. */ diff --git a/lib/js/Intl_Segmenter.js b/lib/js/Intl_Segmenter.js new file mode 100644 index 0000000000..ae1b9f17e6 --- /dev/null +++ b/lib/js/Intl_Segmenter.js @@ -0,0 +1 @@ +/* This output is empty. Its source's type definitions, externals and/or unused code got optimized away. */ diff --git a/lib/js/Intl_Segments.js b/lib/js/Intl_Segments.js new file mode 100644 index 0000000000..ae1b9f17e6 --- /dev/null +++ b/lib/js/Intl_Segments.js @@ -0,0 +1 @@ +/* This output is empty. Its source's type definitions, externals and/or unused code got optimized away. */ diff --git a/lib/js/Iterator.js b/lib/js/Iterator.js new file mode 100644 index 0000000000..e696f08b1a --- /dev/null +++ b/lib/js/Iterator.js @@ -0,0 +1,14 @@ +'use strict'; + + +function forEach(iterator, f) { + let iteratorDone = false; + while (!iteratorDone) { + let match = iterator.next(); + f(match.value); + iteratorDone = match.done; + }; +} + +exports.forEach = forEach; +/* No side effect */ diff --git a/lib/js/JSON.js b/lib/js/JSON.js new file mode 100644 index 0000000000..b3fe6b0f6e --- /dev/null +++ b/lib/js/JSON.js @@ -0,0 +1,98 @@ +'use strict'; + +let Primitive_option = require("./Primitive_option.js"); + +function classify(value) { + let match = Object.prototype.toString.call(value); + switch (match) { + case "[object Array]" : + return { + TAG: "Array", + _0: value + }; + case "[object Boolean]" : + return { + TAG: "Bool", + _0: value + }; + case "[object Null]" : + return "Null"; + case "[object Number]" : + return { + TAG: "Number", + _0: value + }; + case "[object String]" : + return { + TAG: "String", + _0: value + }; + default: + return { + TAG: "Object", + _0: value + }; + } +} + +let Classify = { + classify: classify +}; + +let Encode = {}; + +function bool(json) { + if (typeof json === "boolean") { + return json; + } + +} + +function $$null(json) { + if (json === undefined) { + return Primitive_option.some(undefined); + } + +} + +function string(json) { + if (typeof json === "string") { + return json; + } + +} + +function float(json) { + if (typeof json === "number") { + return json; + } + +} + +function object(json) { + if (typeof json === "object" && !Array.isArray(json) && json !== undefined) { + return json; + } + +} + +function array(json) { + if (Array.isArray(json)) { + return json; + } + +} + +let Decode = { + bool: bool, + $$null: $$null, + string: string, + float: float, + object: object, + array: array +}; + +exports.Classify = Classify; +exports.Encode = Encode; +exports.Decode = Decode; +/* No side effect */ diff --git a/lib/js/List.js b/lib/js/List.js index 32a4309148..129fb6f5cf 100644 --- a/lib/js/List.js +++ b/lib/js/List.js @@ -1,1606 +1,957 @@ 'use strict'; -let Pervasives = require("./Pervasives.js"); +let $$Array = require("./Array.js"); +let Primitive_int = require("./Primitive_int.js"); let Primitive_option = require("./Primitive_option.js"); -function length(l) { - let _len = 0; - let _param = l; - while (true) { - let param = _param; - let len = _len; - if (!param) { - return len; - } - _param = param.tl; - _len = len + 1 | 0; - continue; - }; -} - -function cons(a, l) { - return { - hd: a, - tl: l - }; +function head(x) { + if (x) { + return Primitive_option.some(x.hd); + } + } -function hd(param) { - if (param) { - return param.hd; +function headExn(x) { + if (x) { + return x.hd; } throw { - RE_EXN_ID: "Failure", - _1: "hd", + RE_EXN_ID: "Not_found", Error: new Error() }; } -function tl(param) { - if (param) { - return param.tl; +function tail(x) { + if (x) { + return x.tl; + } + +} + +function tailExn(x) { + if (x) { + return x.tl; } throw { - RE_EXN_ID: "Failure", - _1: "tl", + RE_EXN_ID: "Not_found", Error: new Error() }; } -function nth(l, n) { +function add(xs, x) { + return { + hd: x, + tl: xs + }; +} + +function get(x, n) { + if (n < 0) { + return; + } else { + let _x = x; + let _n = n; + while (true) { + let n$1 = _n; + let x$1 = _x; + if (!x$1) { + return; + } + if (n$1 === 0) { + return Primitive_option.some(x$1.hd); + } + _n = n$1 - 1 | 0; + _x = x$1.tl; + continue; + }; + } +} + +function getExn(x, n) { if (n < 0) { throw { - RE_EXN_ID: "Invalid_argument", - _1: "List.nth", + RE_EXN_ID: "Not_found", Error: new Error() }; } - let _l = l; + let _x = x; let _n = n; while (true) { let n$1 = _n; - let l$1 = _l; - if (l$1) { + let x$1 = _x; + if (x$1) { if (n$1 === 0) { - return l$1.hd; + return x$1.hd; } _n = n$1 - 1 | 0; - _l = l$1.tl; + _x = x$1.tl; continue; } throw { - RE_EXN_ID: "Failure", - _1: "nth", + RE_EXN_ID: "Not_found", Error: new Error() }; }; } -function nth_opt(l, n) { - if (n < 0) { - throw { - RE_EXN_ID: "Invalid_argument", - _1: "List.nth", - Error: new Error() - }; - } - let _l = l; - let _n = n; +function partitionAux(p, _cell, _precX, _precY) { while (true) { - let n$1 = _n; - let l$1 = _l; - if (!l$1) { + let precY = _precY; + let precX = _precX; + let cell = _cell; + if (!cell) { return; } - if (n$1 === 0) { - return Primitive_option.some(l$1.hd); + let t = cell.tl; + let h = cell.hd; + let next = { + hd: h, + tl: /* [] */0 + }; + if (p(h)) { + precX.tl = next; + _precX = next; + _cell = t; + continue; } - _n = n$1 - 1 | 0; - _l = l$1.tl; + precY.tl = next; + _precY = next; + _cell = t; continue; }; } -function rev_append(_l1, _l2) { +function splitAux(_cell, _precX, _precY) { while (true) { - let l2 = _l2; - let l1 = _l1; - if (!l1) { - return l2; + let precY = _precY; + let precX = _precX; + let cell = _cell; + if (!cell) { + return; } - _l2 = { - hd: l1.hd, - tl: l2 + let match = cell.hd; + let nextA = { + hd: match[0], + tl: /* [] */0 }; - _l1 = l1.tl; - continue; - }; -} - -function rev(l) { - return rev_append(l, /* [] */0); -} - -function init_tailrec_aux(_acc, _i, n, f) { - while (true) { - let i = _i; - let acc = _acc; - if (i >= n) { - return acc; - } - _i = i + 1 | 0; - _acc = { - hd: f(i), - tl: acc + let nextB = { + hd: match[1], + tl: /* [] */0 }; + precX.tl = nextA; + precY.tl = nextB; + _precY = nextB; + _precX = nextA; + _cell = cell.tl; continue; }; } -function init_aux(i, n, f) { - if (i >= n) { - return /* [] */0; - } - let r = f(i); - return { - hd: r, - tl: init_aux(i + 1 | 0, n, f) - }; -} - -function init(len, f) { - if (len < 0) { - throw { - RE_EXN_ID: "Invalid_argument", - _1: "List.init", - Error: new Error() - }; - } - if (len > 10000) { - return rev_append(init_tailrec_aux(/* [] */0, 0, len, f), /* [] */0); - } else { - return init_aux(0, len, f); - } -} - -function flatten(param) { - if (param) { - return Pervasives.$at(param.hd, flatten(param.tl)); - } else { - return /* [] */0; - } -} - -function map(f, param) { - if (!param) { - return /* [] */0; - } - let r = f(param.hd); - return { - hd: r, - tl: map(f, param.tl) - }; -} - -function mapi(i, f, param) { - if (!param) { - return /* [] */0; - } - let r = f(i, param.hd); - return { - hd: r, - tl: mapi(i + 1 | 0, f, param.tl) - }; -} - -function mapi$1(f, l) { - return mapi(0, f, l); -} - -function rev_map(f, l) { - let _accu = /* [] */0; - let _param = l; +function copyAuxCont(_cellX, _prec) { while (true) { - let param = _param; - let accu = _accu; - if (!param) { - return accu; + let prec = _prec; + let cellX = _cellX; + if (!cellX) { + return prec; } - _param = param.tl; - _accu = { - hd: f(param.hd), - tl: accu + let next = { + hd: cellX.hd, + tl: /* [] */0 }; + prec.tl = next; + _prec = next; + _cellX = cellX.tl; continue; }; } -function iter(f, _param) { +function copyAuxWitFilter(f, _cellX, _prec) { while (true) { - let param = _param; - if (!param) { + let prec = _prec; + let cellX = _cellX; + if (!cellX) { return; } - f(param.hd); - _param = param.tl; + let t = cellX.tl; + let h = cellX.hd; + if (f(h)) { + let next = { + hd: h, + tl: /* [] */0 + }; + prec.tl = next; + _prec = next; + _cellX = t; + continue; + } + _cellX = t; continue; }; } -function iteri(f, l) { - let _i = 0; - let _param = l; +function copyAuxWithFilterIndex(f, _cellX, _prec, _i) { while (true) { - let param = _param; let i = _i; - if (!param) { + let prec = _prec; + let cellX = _cellX; + if (!cellX) { return; } - f(i, param.hd); - _param = param.tl; + let t = cellX.tl; + let h = cellX.hd; + if (f(h, i)) { + let next = { + hd: h, + tl: /* [] */0 + }; + prec.tl = next; + _i = i + 1 | 0; + _prec = next; + _cellX = t; + continue; + } _i = i + 1 | 0; + _cellX = t; continue; }; } -function fold_left(f, _accu, _l) { +function copyAuxWitFilterMap(f, _cellX, _prec) { while (true) { - let l = _l; - let accu = _accu; - if (!l) { - return accu; + let prec = _prec; + let cellX = _cellX; + if (!cellX) { + return; } - _l = l.tl; - _accu = f(accu, l.hd); + let t = cellX.tl; + let h = f(cellX.hd); + if (h !== undefined) { + let next = { + hd: Primitive_option.valFromOption(h), + tl: /* [] */0 + }; + prec.tl = next; + _prec = next; + _cellX = t; + continue; + } + _cellX = t; continue; }; } -function fold_right(f, l, accu) { - if (l) { - return f(l.hd, fold_right(f, l.tl, accu)); - } else { - return accu; - } -} - -function map2(f, l1, l2) { - if (l1) { - if (l2) { - let r = f(l1.hd, l2.hd); - return { - hd: r, - tl: map2(f, l1.tl, l2.tl) - }; +function removeAssocAuxWithMap(_cellX, x, _prec, f) { + while (true) { + let prec = _prec; + let cellX = _cellX; + if (!cellX) { + return false; } - throw { - RE_EXN_ID: "Invalid_argument", - _1: "List.map2", - Error: new Error() + let t = cellX.tl; + let h = cellX.hd; + if (f(h[0], x)) { + prec.tl = t; + return true; + } + let next = { + hd: h, + tl: /* [] */0 }; - } - if (!l2) { - return /* [] */0; - } - throw { - RE_EXN_ID: "Invalid_argument", - _1: "List.map2", - Error: new Error() + prec.tl = next; + _prec = next; + _cellX = t; + continue; }; } -function rev_map2(f, l1, l2) { - let _accu = /* [] */0; - let _l1 = l1; - let _l2 = l2; +function setAssocAuxWithMap(_cellX, x, k, _prec, eq) { while (true) { - let l2$1 = _l2; - let l1$1 = _l1; - let accu = _accu; - if (l1$1) { - if (l2$1) { - _l2 = l2$1.tl; - _l1 = l1$1.tl; - _accu = { - hd: f(l1$1.hd, l2$1.hd), - tl: accu - }; - continue; - } - throw { - RE_EXN_ID: "Invalid_argument", - _1: "List.rev_map2", - Error: new Error() - }; + let prec = _prec; + let cellX = _cellX; + if (!cellX) { + return false; } - if (l2$1) { - throw { - RE_EXN_ID: "Invalid_argument", - _1: "List.rev_map2", - Error: new Error() + let t = cellX.tl; + let h = cellX.hd; + if (eq(h[0], x)) { + prec.tl = { + hd: [ + x, + k + ], + tl: t }; + return true; } - return accu; + let next = { + hd: h, + tl: /* [] */0 + }; + prec.tl = next; + _prec = next; + _cellX = t; + continue; }; } -function iter2(f, _l1, _l2) { +function copyAuxWithMap(_cellX, _prec, f) { while (true) { - let l2 = _l2; - let l1 = _l1; - if (l1) { - if (l2) { - f(l1.hd, l2.hd); - _l2 = l2.tl; - _l1 = l1.tl; - continue; - } - throw { - RE_EXN_ID: "Invalid_argument", - _1: "List.iter2", - Error: new Error() - }; - } - if (!l2) { + let prec = _prec; + let cellX = _cellX; + if (!cellX) { return; } - throw { - RE_EXN_ID: "Invalid_argument", - _1: "List.iter2", - Error: new Error() + let next = { + hd: f(cellX.hd), + tl: /* [] */0 }; + prec.tl = next; + _prec = next; + _cellX = cellX.tl; + continue; }; } -function fold_left2(f, _accu, _l1, _l2) { +function zipAux(_cellX, _cellY, _prec) { while (true) { - let l2 = _l2; - let l1 = _l1; - let accu = _accu; - if (l1) { - if (l2) { - _l2 = l2.tl; - _l1 = l1.tl; - _accu = f(accu, l1.hd, l2.hd); - continue; - } - throw { - RE_EXN_ID: "Invalid_argument", - _1: "List.fold_left2", - Error: new Error() - }; - } - if (l2) { - throw { - RE_EXN_ID: "Invalid_argument", - _1: "List.fold_left2", - Error: new Error() - }; + let prec = _prec; + let cellY = _cellY; + let cellX = _cellX; + if (!cellX) { + return; } - return accu; - }; -} - -function fold_right2(f, l1, l2, accu) { - if (l1) { - if (l2) { - return f(l1.hd, l2.hd, fold_right2(f, l1.tl, l2.tl, accu)); + if (!cellY) { + return; } - throw { - RE_EXN_ID: "Invalid_argument", - _1: "List.fold_right2", - Error: new Error() - }; - } - if (l2) { - throw { - RE_EXN_ID: "Invalid_argument", - _1: "List.fold_right2", - Error: new Error() + let next = { + hd: [ + cellX.hd, + cellY.hd + ], + tl: /* [] */0 }; - } - return accu; -} - -function for_all(p, _param) { - while (true) { - let param = _param; - if (!param) { - return true; - } - if (!p(param.hd)) { - return false; - } - _param = param.tl; + prec.tl = next; + _prec = next; + _cellY = cellY.tl; + _cellX = cellX.tl; continue; }; } -function exists(p, _param) { +function copyAuxWithMap2(f, _cellX, _cellY, _prec) { while (true) { - let param = _param; - if (!param) { - return false; + let prec = _prec; + let cellY = _cellY; + let cellX = _cellX; + if (!cellX) { + return; } - if (p(param.hd)) { - return true; + if (!cellY) { + return; } - _param = param.tl; + let next = { + hd: f(cellX.hd, cellY.hd), + tl: /* [] */0 + }; + prec.tl = next; + _prec = next; + _cellY = cellY.tl; + _cellX = cellX.tl; continue; }; } -function for_all2(p, _l1, _l2) { +function copyAuxWithMapI(f, _i, _cellX, _prec) { while (true) { - let l2 = _l2; - let l1 = _l1; - if (l1) { - if (l2) { - if (!p(l1.hd, l2.hd)) { - return false; - } - _l2 = l2.tl; - _l1 = l1.tl; - continue; - } - throw { - RE_EXN_ID: "Invalid_argument", - _1: "List.for_all2", - Error: new Error() - }; - } - if (!l2) { - return true; + let prec = _prec; + let cellX = _cellX; + let i = _i; + if (!cellX) { + return; } - throw { - RE_EXN_ID: "Invalid_argument", - _1: "List.for_all2", - Error: new Error() + let next = { + hd: f(cellX.hd, i), + tl: /* [] */0 }; + prec.tl = next; + _prec = next; + _cellX = cellX.tl; + _i = i + 1 | 0; + continue; }; } -function exists2(p, _l1, _l2) { +function takeAux(_n, _cell, _prec) { while (true) { - let l2 = _l2; - let l1 = _l1; - if (l1) { - if (l2) { - if (p(l1.hd, l2.hd)) { - return true; - } - _l2 = l2.tl; - _l1 = l1.tl; - continue; - } - throw { - RE_EXN_ID: "Invalid_argument", - _1: "List.exists2", - Error: new Error() - }; + let prec = _prec; + let cell = _cell; + let n = _n; + if (n === 0) { + return true; } - if (!l2) { + if (!cell) { return false; } - throw { - RE_EXN_ID: "Invalid_argument", - _1: "List.exists2", - Error: new Error() + let cell$1 = { + hd: cell.hd, + tl: /* [] */0 }; + prec.tl = cell$1; + _prec = cell$1; + _cell = cell.tl; + _n = n - 1 | 0; + continue; }; } -function mem(x, _param) { +function splitAtAux(_n, _cell, _prec) { while (true) { - let param = _param; - if (!param) { - return false; + let prec = _prec; + let cell = _cell; + let n = _n; + if (n === 0) { + return cell; } - if (param.hd === x) { - return true; + if (!cell) { + return; } - _param = param.tl; + let cell$1 = { + hd: cell.hd, + tl: /* [] */0 + }; + prec.tl = cell$1; + _prec = cell$1; + _cell = cell.tl; + _n = n - 1 | 0; continue; }; } -function memq(x, _param) { - while (true) { - let param = _param; - if (!param) { - return false; - } - if (param.hd === x) { - return true; - } - _param = param.tl; - continue; +function take(lst, n) { + if (n < 0) { + return; + } + if (n === 0) { + return /* [] */0; + } + if (!lst) { + return; + } + let cell = { + hd: lst.hd, + tl: /* [] */0 }; + let has = takeAux(n - 1 | 0, lst.tl, cell); + if (has) { + return cell; + } + } -function assoc(x, _param) { - while (true) { - let param = _param; - if (param) { - let match = param.hd; - if (match[0] === x) { - return match[1]; +function drop(lst, n) { + if (n < 0) { + return; + } else { + let _l = lst; + let _n = n; + while (true) { + let n$1 = _n; + let l = _l; + if (n$1 === 0) { + return l; } - _param = param.tl; + if (!l) { + return; + } + _n = n$1 - 1 | 0; + _l = l.tl; continue; - } - throw { - RE_EXN_ID: "Not_found", - Error: new Error() }; + } +} + +function splitAt(lst, n) { + if (n < 0) { + return; + } + if (n === 0) { + return [ + /* [] */0, + lst + ]; + } + if (!lst) { + return; + } + let cell = { + hd: lst.hd, + tl: /* [] */0 }; + let rest = splitAtAux(n - 1 | 0, lst.tl, cell); + if (rest !== undefined) { + return [ + cell, + rest + ]; + } + } -function assoc_opt(x, _param) { +function concat(xs, ys) { + if (!xs) { + return ys; + } + let cell = { + hd: xs.hd, + tl: /* [] */0 + }; + copyAuxCont(xs.tl, cell).tl = ys; + return cell; +} + +function map(xs, f) { + if (!xs) { + return /* [] */0; + } + let cell = { + hd: f(xs.hd), + tl: /* [] */0 + }; + copyAuxWithMap(xs.tl, cell, f); + return cell; +} + +function zipBy(l1, l2, f) { + if (!l1) { + return /* [] */0; + } + if (!l2) { + return /* [] */0; + } + let cell = { + hd: f(l1.hd, l2.hd), + tl: /* [] */0 + }; + copyAuxWithMap2(f, l1.tl, l2.tl, cell); + return cell; +} + +function mapWithIndex(xs, f) { + if (!xs) { + return /* [] */0; + } + let cell = { + hd: f(xs.hd, 0), + tl: /* [] */0 + }; + copyAuxWithMapI(f, 1, xs.tl, cell); + return cell; +} + +function fromInitializer(n, f) { + if (n <= 0) { + return /* [] */0; + } + let headX = { + hd: f(0), + tl: /* [] */0 + }; + let cur = headX; + let i = 1; + while (i < n) { + let v = { + hd: f(i), + tl: /* [] */0 + }; + cur.tl = v; + cur = v; + i = i + 1 | 0; + }; + return headX; +} + +function make(n, v) { + if (n <= 0) { + return /* [] */0; + } + let headX = { + hd: v, + tl: /* [] */0 + }; + let cur = headX; + let i = 1; + while (i < n) { + let v$1 = { + hd: v, + tl: /* [] */0 + }; + cur.tl = v$1; + cur = v$1; + i = i + 1 | 0; + }; + return headX; +} + +function length(xs) { + let _x = xs; + let _acc = 0; while (true) { - let param = _param; - if (!param) { - return; + let acc = _acc; + let x = _x; + if (!x) { + return acc; } - let match = param.hd; - if (match[0] === x) { - return Primitive_option.some(match[1]); + _acc = acc + 1 | 0; + _x = x.tl; + continue; + }; +} + +function fillAux(arr, _i, _x) { + while (true) { + let x = _x; + let i = _i; + if (!x) { + return; } - _param = param.tl; + arr[i] = x.hd; + _x = x.tl; + _i = i + 1 | 0; continue; }; } -function assq(x, _param) { +function fromArray(a) { + let _i = a.length - 1 | 0; + let _res = /* [] */0; while (true) { - let param = _param; - if (param) { - let match = param.hd; - if (match[0] === x) { - return match[1]; - } - _param = param.tl; - continue; + let res = _res; + let i = _i; + if (i < 0) { + return res; } - throw { - RE_EXN_ID: "Not_found", - Error: new Error() + _res = { + hd: a[i], + tl: res }; + _i = i - 1 | 0; + continue; }; } -function assq_opt(x, _param) { +function toArray(x) { + let len = length(x); + let arr = new Array(len); + fillAux(arr, 0, x); + return arr; +} + +function toShuffled(xs) { + let v = toArray(xs); + $$Array.shuffle(v); + return fromArray(v); +} + +function reverseConcat(_l1, _l2) { while (true) { - let param = _param; - if (!param) { - return; - } - let match = param.hd; - if (match[0] === x) { - return Primitive_option.some(match[1]); + let l2 = _l2; + let l1 = _l1; + if (!l1) { + return l2; } - _param = param.tl; + _l2 = { + hd: l1.hd, + tl: l2 + }; + _l1 = l1.tl; continue; }; } -function mem_assoc(x, _param) { +function reverse(l) { + return reverseConcat(l, /* [] */0); +} + +function flatAux(_prec, _xs) { while (true) { - let param = _param; - if (!param) { - return false; - } - if (param.hd[0] === x) { - return true; + let xs = _xs; + let prec = _prec; + if (xs) { + _xs = xs.tl; + _prec = copyAuxCont(xs.hd, prec); + continue; } - _param = param.tl; - continue; + prec.tl = /* [] */0; + return; }; } -function mem_assq(x, _param) { +function flat(_xs) { while (true) { - let param = _param; - if (!param) { - return false; + let xs = _xs; + if (!xs) { + return /* [] */0; } - if (param.hd[0] === x) { - return true; + let match = xs.hd; + if (match) { + let cell = { + hd: match.hd, + tl: /* [] */0 + }; + flatAux(copyAuxCont(match.tl, cell), xs.tl); + return cell; } - _param = param.tl; + _xs = xs.tl; continue; }; } -function remove_assoc(x, param) { - if (!param) { - return /* [] */0; +function concatMany(xs) { + let len = xs.length; + if (len === 1) { + return xs[0]; } - let l = param.tl; - let pair = param.hd; - if (pair[0] === x) { - return l; - } else { - return { - hd: pair, - tl: remove_assoc(x, l) - }; - } -} - -function remove_assq(x, param) { - if (!param) { + if (len === 0) { return /* [] */0; } - let l = param.tl; - let pair = param.hd; - if (pair[0] === x) { - return l; - } else { - return { - hd: pair, - tl: remove_assq(x, l) - }; + let len$1 = xs.length; + let v = xs[len$1 - 1 | 0]; + for (let i = len$1 - 2 | 0; i >= 0; --i) { + v = concat(xs[i], v); } + return v; } -function find(p, _param) { +function mapReverse(l, f) { + let _accu = /* [] */0; + let _xs = l; while (true) { - let param = _param; - if (param) { - let x = param.hd; - if (p(x)) { - return x; - } - _param = param.tl; - continue; + let xs = _xs; + let accu = _accu; + if (!xs) { + return accu; } - throw { - RE_EXN_ID: "Not_found", - Error: new Error() + _xs = xs.tl; + _accu = { + hd: f(xs.hd), + tl: accu }; + continue; }; } -function find_opt(p, _param) { +function forEach(_xs, f) { while (true) { - let param = _param; - if (!param) { + let xs = _xs; + if (!xs) { return; } - let x = param.hd; - if (p(x)) { - return Primitive_option.some(x); + f(xs.hd); + _xs = xs.tl; + continue; + }; +} + +function forEachWithIndex(l, f) { + let _xs = l; + let _i = 0; + while (true) { + let i = _i; + let xs = _xs; + if (!xs) { + return; } - _param = param.tl; + f(xs.hd, i); + _i = i + 1 | 0; + _xs = xs.tl; continue; }; } -function find_all(p, l) { - let _accu = /* [] */0; - let _param = l; +function reduce(_l, _accu, f) { while (true) { - let param = _param; let accu = _accu; - if (!param) { - return rev_append(accu, /* [] */0); + let l = _l; + if (!l) { + return accu; } - let l$1 = param.tl; - let x = param.hd; - if (p(x)) { - _param = l$1; - _accu = { - hd: x, - tl: accu - }; - continue; + _accu = f(accu, l.hd); + _l = l.tl; + continue; + }; +} + +function reduceReverseUnsafe(l, accu, f) { + if (l) { + return f(reduceReverseUnsafe(l.tl, accu, f), l.hd); + } else { + return accu; + } +} + +function reduceReverse(l, acc, f) { + let len = length(l); + if (len < 1000) { + return reduceReverseUnsafe(l, acc, f); + } else { + let a = toArray(l); + let r = acc; + for (let i = a.length - 1 | 0; i >= 0; --i) { + r = f(r, a[i]); } - _param = l$1; + return r; + } +} + +function reduceWithIndex(l, acc, f) { + let _l = l; + let _acc = acc; + let _i = 0; + while (true) { + let i = _i; + let acc$1 = _acc; + let l$1 = _l; + if (!l$1) { + return acc$1; + } + _i = i + 1 | 0; + _acc = f(acc$1, l$1.hd, i); + _l = l$1.tl; continue; }; } -function partition(p, l) { - let _yes = /* [] */0; - let _no = /* [] */0; - let _param = l; +function mapReverse2(l1, l2, f) { + let _l1 = l1; + let _l2 = l2; + let _accu = /* [] */0; while (true) { - let param = _param; - let no = _no; - let yes = _yes; - if (!param) { - return [ - rev_append(yes, /* [] */0), - rev_append(no, /* [] */0) - ]; - } - let l$1 = param.tl; - let x = param.hd; - if (p(x)) { - _param = l$1; - _yes = { - hd: x, - tl: yes - }; - continue; + let accu = _accu; + let l2$1 = _l2; + let l1$1 = _l1; + if (!l1$1) { + return accu; } - _param = l$1; - _no = { - hd: x, - tl: no + if (!l2$1) { + return accu; + } + _accu = { + hd: f(l1$1.hd, l2$1.hd), + tl: accu }; + _l2 = l2$1.tl; + _l1 = l1$1.tl; continue; }; } -function split(param) { - if (!param) { - return [ - /* [] */0, - /* [] */0 - ]; - } - let match = param.hd; - let match$1 = split(param.tl); - return [ - { - hd: match[0], - tl: match$1[0] - }, - { - hd: match[1], - tl: match$1[1] +function forEach2(_l1, _l2, f) { + while (true) { + let l2 = _l2; + let l1 = _l1; + if (!l1) { + return; } - ]; + if (!l2) { + return; + } + f(l1.hd, l2.hd); + _l2 = l2.tl; + _l1 = l1.tl; + continue; + }; } -function combine(l1, l2) { - if (l1) { - if (l2) { - return { - hd: [ - l1.hd, - l2.hd - ], - tl: combine(l1.tl, l2.tl) - }; +function reduce2(_l1, _l2, _accu, f) { + while (true) { + let accu = _accu; + let l2 = _l2; + let l1 = _l1; + if (!l1) { + return accu; } - throw { - RE_EXN_ID: "Invalid_argument", - _1: "List.combine", - Error: new Error() - }; - } - if (!l2) { - return /* [] */0; - } - throw { - RE_EXN_ID: "Invalid_argument", - _1: "List.combine", - Error: new Error() + if (!l2) { + return accu; + } + _accu = f(accu, l1.hd, l2.hd); + _l2 = l2.tl; + _l1 = l1.tl; + continue; }; } -function merge(cmp, l1, l2) { - if (!l1) { - return l2; - } - if (!l2) { - return l1; +function reduceReverse2Unsafe(l1, l2, accu, f) { + if (l1 && l2) { + return f(reduceReverse2Unsafe(l1.tl, l2.tl, accu, f), l1.hd, l2.hd); + } else { + return accu; } - let h2 = l2.hd; - let h1 = l1.hd; - if (cmp(h1, h2) <= 0) { - return { - hd: h1, - tl: merge(cmp, l1.tl, l2) - }; +} + +function reduceReverse2(l1, l2, acc, f) { + let len = length(l1); + if (len < 1000) { + return reduceReverse2Unsafe(l1, l2, acc, f); } else { - return { - hd: h2, - tl: merge(cmp, l1, l2.tl) - }; + let a = toArray(l1); + let b = toArray(l2); + let r = acc; + let len$1 = Primitive_int.max(a.length, b.length); + for (let i = len$1 - 1 | 0; i >= 0; --i) { + r = f(r, a[i], b[i]); + } + return r; } } -function chop(_k, _l) { +function every(_xs, p) { while (true) { - let l = _l; - let k = _k; - if (k === 0) { - return l; + let xs = _xs; + if (!xs) { + return true; } - if (l) { - _l = l.tl; - _k = k - 1 | 0; - continue; + if (!p(xs.hd)) { + return false; } - throw { - RE_EXN_ID: "Assert_failure", - _1: [ - "List.res", - 411, - 11 - ], - Error: new Error() - }; + _xs = xs.tl; + continue; }; } -function stable_sort(cmp, l) { - let sort = (n, l) => { - if (n !== 2) { - if (n === 3 && l) { - let match = l.tl; - if (match) { - let match$1 = match.tl; - if (match$1) { - let x3 = match$1.hd; - let x2 = match.hd; - let x1 = l.hd; - if (cmp(x1, x2) <= 0) { - if (cmp(x2, x3) <= 0) { - return { - hd: x1, - tl: { - hd: x2, - tl: { - hd: x3, - tl: /* [] */0 - } - } - }; - } else if (cmp(x1, x3) <= 0) { - return { - hd: x1, - tl: { - hd: x3, - tl: { - hd: x2, - tl: /* [] */0 - } - } - }; - } else { - return { - hd: x3, - tl: { - hd: x1, - tl: { - hd: x2, - tl: /* [] */0 - } - } - }; - } - } else if (cmp(x1, x3) <= 0) { - return { - hd: x2, - tl: { - hd: x1, - tl: { - hd: x3, - tl: /* [] */0 - } - } - }; - } else if (cmp(x2, x3) <= 0) { - return { - hd: x2, - tl: { - hd: x3, - tl: { - hd: x1, - tl: /* [] */0 - } - } - }; - } else { - return { - hd: x3, - tl: { - hd: x2, - tl: { - hd: x1, - tl: /* [] */0 - } - } - }; - } - } - - } - - } - - } else if (l) { - let match$2 = l.tl; - if (match$2) { - let x2$1 = match$2.hd; - let x1$1 = l.hd; - if (cmp(x1$1, x2$1) <= 0) { - return { - hd: x1$1, - tl: { - hd: x2$1, - tl: /* [] */0 - } - }; - } else { - return { - hd: x2$1, - tl: { - hd: x1$1, - tl: /* [] */0 - } - }; - } - } - - } - let n1 = (n >> 1); - let n2 = n - n1 | 0; - let l2 = chop(n1, l); - let s1 = rev_sort(n1, l); - let s2 = rev_sort(n2, l2); - let _l1 = s1; - let _l2 = s2; - let _accu = /* [] */0; - while (true) { - let accu = _accu; - let l2$1 = _l2; - let l1 = _l1; - if (!l1) { - return rev_append(l2$1, accu); - } - if (!l2$1) { - return rev_append(l1, accu); - } - let h2 = l2$1.hd; - let h1 = l1.hd; - if (cmp(h1, h2) > 0) { - _accu = { - hd: h1, - tl: accu - }; - _l1 = l1.tl; - continue; - } - _accu = { - hd: h2, - tl: accu - }; - _l2 = l2$1.tl; - continue; - }; - }; - let rev_sort = (n, l) => { - if (n !== 2) { - if (n === 3 && l) { - let match = l.tl; - if (match) { - let match$1 = match.tl; - if (match$1) { - let x3 = match$1.hd; - let x2 = match.hd; - let x1 = l.hd; - if (cmp(x1, x2) > 0) { - if (cmp(x2, x3) > 0) { - return { - hd: x1, - tl: { - hd: x2, - tl: { - hd: x3, - tl: /* [] */0 - } - } - }; - } else if (cmp(x1, x3) > 0) { - return { - hd: x1, - tl: { - hd: x3, - tl: { - hd: x2, - tl: /* [] */0 - } - } - }; - } else { - return { - hd: x3, - tl: { - hd: x1, - tl: { - hd: x2, - tl: /* [] */0 - } - } - }; - } - } else if (cmp(x1, x3) > 0) { - return { - hd: x2, - tl: { - hd: x1, - tl: { - hd: x3, - tl: /* [] */0 - } - } - }; - } else if (cmp(x2, x3) > 0) { - return { - hd: x2, - tl: { - hd: x3, - tl: { - hd: x1, - tl: /* [] */0 - } - } - }; - } else { - return { - hd: x3, - tl: { - hd: x2, - tl: { - hd: x1, - tl: /* [] */0 - } - } - }; - } - } - - } - - } - - } else if (l) { - let match$2 = l.tl; - if (match$2) { - let x2$1 = match$2.hd; - let x1$1 = l.hd; - if (cmp(x1$1, x2$1) > 0) { - return { - hd: x1$1, - tl: { - hd: x2$1, - tl: /* [] */0 - } - }; - } else { - return { - hd: x2$1, - tl: { - hd: x1$1, - tl: /* [] */0 - } - }; - } - } - - } - let n1 = (n >> 1); - let n2 = n - n1 | 0; - let l2 = chop(n1, l); - let s1 = sort(n1, l); - let s2 = sort(n2, l2); - let _l1 = s1; - let _l2 = s2; - let _accu = /* [] */0; - while (true) { - let accu = _accu; - let l2$1 = _l2; - let l1 = _l1; - if (!l1) { - return rev_append(l2$1, accu); - } - if (!l2$1) { - return rev_append(l1, accu); - } - let h2 = l2$1.hd; - let h1 = l1.hd; - if (cmp(h1, h2) <= 0) { - _accu = { - hd: h1, - tl: accu - }; - _l1 = l1.tl; - continue; - } - _accu = { - hd: h2, - tl: accu - }; - _l2 = l2$1.tl; - continue; - }; +function some(_xs, p) { + while (true) { + let xs = _xs; + if (!xs) { + return false; + } + if (p(xs.hd)) { + return true; + } + _xs = xs.tl; + continue; }; - let len = length(l); - if (len < 2) { - return l; - } else { - return sort(len, l); - } } -function sort_uniq(cmp, l) { - let sort = (n, l) => { - if (n !== 2) { - if (n === 3 && l) { - let match = l.tl; - if (match) { - let match$1 = match.tl; - if (match$1) { - let x3 = match$1.hd; - let x2 = match.hd; - let x1 = l.hd; - let c = cmp(x1, x2); - if (c === 0) { - let c$1 = cmp(x2, x3); - if (c$1 === 0) { - return { - hd: x2, - tl: /* [] */0 - }; - } else if (c$1 < 0) { - return { - hd: x2, - tl: { - hd: x3, - tl: /* [] */0 - } - }; - } else { - return { - hd: x3, - tl: { - hd: x2, - tl: /* [] */0 - } - }; - } - } - if (c < 0) { - let c$2 = cmp(x2, x3); - if (c$2 === 0) { - return { - hd: x1, - tl: { - hd: x2, - tl: /* [] */0 - } - }; - } - if (c$2 < 0) { - return { - hd: x1, - tl: { - hd: x2, - tl: { - hd: x3, - tl: /* [] */0 - } - } - }; - } - let c$3 = cmp(x1, x3); - if (c$3 === 0) { - return { - hd: x1, - tl: { - hd: x2, - tl: /* [] */0 - } - }; - } else if (c$3 < 0) { - return { - hd: x1, - tl: { - hd: x3, - tl: { - hd: x2, - tl: /* [] */0 - } - } - }; - } else { - return { - hd: x3, - tl: { - hd: x1, - tl: { - hd: x2, - tl: /* [] */0 - } - } - }; - } - } - let c$4 = cmp(x1, x3); - if (c$4 === 0) { - return { - hd: x2, - tl: { - hd: x1, - tl: /* [] */0 - } - }; - } - if (c$4 < 0) { - return { - hd: x2, - tl: { - hd: x1, - tl: { - hd: x3, - tl: /* [] */0 - } - } - }; - } - let c$5 = cmp(x2, x3); - if (c$5 === 0) { - return { - hd: x2, - tl: { - hd: x1, - tl: /* [] */0 - } - }; - } else if (c$5 < 0) { - return { - hd: x2, - tl: { - hd: x3, - tl: { - hd: x1, - tl: /* [] */0 - } - } - }; - } else { - return { - hd: x3, - tl: { - hd: x2, - tl: { - hd: x1, - tl: /* [] */0 - } - } - }; - } - } - - } - - } - - } else if (l) { - let match$2 = l.tl; - if (match$2) { - let x2$1 = match$2.hd; - let x1$1 = l.hd; - let c$6 = cmp(x1$1, x2$1); - if (c$6 === 0) { - return { - hd: x1$1, - tl: /* [] */0 - }; - } else if (c$6 < 0) { - return { - hd: x1$1, - tl: { - hd: x2$1, - tl: /* [] */0 - } - }; - } else { - return { - hd: x2$1, - tl: { - hd: x1$1, - tl: /* [] */0 - } - }; - } - } - - } - let n1 = (n >> 1); - let n2 = n - n1 | 0; - let l2 = chop(n1, l); - let s1 = rev_sort(n1, l); - let s2 = rev_sort(n2, l2); - let _l1 = s1; - let _l2 = s2; - let _accu = /* [] */0; - while (true) { - let accu = _accu; - let l2$1 = _l2; - let l1 = _l1; - if (!l1) { - return rev_append(l2$1, accu); - } - if (!l2$1) { - return rev_append(l1, accu); - } - let t2 = l2$1.tl; - let h2 = l2$1.hd; - let t1 = l1.tl; - let h1 = l1.hd; - let c$7 = cmp(h1, h2); - if (c$7 === 0) { - _accu = { - hd: h1, - tl: accu - }; - _l2 = t2; - _l1 = t1; - continue; - } - if (c$7 > 0) { - _accu = { - hd: h1, - tl: accu - }; - _l1 = t1; - continue; - } - _accu = { - hd: h2, - tl: accu - }; - _l2 = t2; - continue; - }; - }; - let rev_sort = (n, l) => { - if (n !== 2) { - if (n === 3 && l) { - let match = l.tl; - if (match) { - let match$1 = match.tl; - if (match$1) { - let x3 = match$1.hd; - let x2 = match.hd; - let x1 = l.hd; - let c = cmp(x1, x2); - if (c === 0) { - let c$1 = cmp(x2, x3); - if (c$1 === 0) { - return { - hd: x2, - tl: /* [] */0 - }; - } else if (c$1 > 0) { - return { - hd: x2, - tl: { - hd: x3, - tl: /* [] */0 - } - }; - } else { - return { - hd: x3, - tl: { - hd: x2, - tl: /* [] */0 - } - }; - } - } - if (c > 0) { - let c$2 = cmp(x2, x3); - if (c$2 === 0) { - return { - hd: x1, - tl: { - hd: x2, - tl: /* [] */0 - } - }; - } - if (c$2 > 0) { - return { - hd: x1, - tl: { - hd: x2, - tl: { - hd: x3, - tl: /* [] */0 - } - } - }; - } - let c$3 = cmp(x1, x3); - if (c$3 === 0) { - return { - hd: x1, - tl: { - hd: x2, - tl: /* [] */0 - } - }; - } else if (c$3 > 0) { - return { - hd: x1, - tl: { - hd: x3, - tl: { - hd: x2, - tl: /* [] */0 - } - } - }; - } else { - return { - hd: x3, - tl: { - hd: x1, - tl: { - hd: x2, - tl: /* [] */0 - } - } - }; - } - } - let c$4 = cmp(x1, x3); - if (c$4 === 0) { - return { - hd: x2, - tl: { - hd: x1, - tl: /* [] */0 - } - }; - } - if (c$4 > 0) { - return { - hd: x2, - tl: { - hd: x1, - tl: { - hd: x3, - tl: /* [] */0 - } - } - }; - } - let c$5 = cmp(x2, x3); - if (c$5 === 0) { - return { - hd: x2, - tl: { - hd: x1, - tl: /* [] */0 - } - }; - } else if (c$5 > 0) { - return { - hd: x2, - tl: { - hd: x3, - tl: { - hd: x1, - tl: /* [] */0 - } - } - }; - } else { - return { - hd: x3, - tl: { - hd: x2, - tl: { - hd: x1, - tl: /* [] */0 - } - } - }; - } - } - - } - - } - - } else if (l) { - let match$2 = l.tl; - if (match$2) { - let x2$1 = match$2.hd; - let x1$1 = l.hd; - let c$6 = cmp(x1$1, x2$1); - if (c$6 === 0) { - return { - hd: x1$1, - tl: /* [] */0 - }; - } else if (c$6 > 0) { - return { - hd: x1$1, - tl: { - hd: x2$1, - tl: /* [] */0 - } - }; - } else { - return { - hd: x2$1, - tl: { - hd: x1$1, - tl: /* [] */0 - } - }; - } - } - - } - let n1 = (n >> 1); - let n2 = n - n1 | 0; - let l2 = chop(n1, l); - let s1 = sort(n1, l); - let s2 = sort(n2, l2); - let _l1 = s1; - let _l2 = s2; - let _accu = /* [] */0; - while (true) { - let accu = _accu; - let l2$1 = _l2; - let l1 = _l1; - if (!l1) { - return rev_append(l2$1, accu); - } - if (!l2$1) { - return rev_append(l1, accu); - } - let t2 = l2$1.tl; - let h2 = l2$1.hd; - let t1 = l1.tl; - let h1 = l1.hd; - let c$7 = cmp(h1, h2); - if (c$7 === 0) { - _accu = { - hd: h1, - tl: accu - }; - _l2 = t2; - _l1 = t1; - continue; - } - if (c$7 < 0) { - _accu = { - hd: h1, - tl: accu - }; - _l1 = t1; - continue; - } - _accu = { - hd: h2, - tl: accu - }; - _l2 = t2; - continue; - }; +function every2(_l1, _l2, p) { + while (true) { + let l2 = _l2; + let l1 = _l1; + if (!l1) { + return true; + } + if (!l2) { + return true; + } + if (!p(l1.hd, l2.hd)) { + return false; + } + _l2 = l2.tl; + _l1 = l1.tl; + continue; }; - let len = length(l); - if (len < 2) { - return l; - } else { - return sort(len, l); - } } -function compare_lengths(_l1, _l2) { +function compareLength(_l1, _l2) { while (true) { let l2 = _l2; let l1 = _l1; @@ -1620,88 +971,390 @@ function compare_lengths(_l1, _l2) { }; } -function compare_length_with(_l, _n) { +function compare(_l1, _l2, p) { while (true) { - let n = _n; - let l = _l; - if (!l) { - if (n === 0) { - return 0; - } else if (n > 0) { + let l2 = _l2; + let l1 = _l1; + if (!l1) { + if (l2) { return -1; } else { - return 1; + return 0; } } - if (n <= 0) { + if (!l2) { return 1; } - _n = n - 1 | 0; - _l = l.tl; + let c = p(l1.hd, l2.hd); + if (c !== 0) { + return c; + } + _l2 = l2.tl; + _l1 = l1.tl; + continue; + }; +} + +function equal(_l1, _l2, p) { + while (true) { + let l2 = _l2; + let l1 = _l1; + if (!l1) { + if (l2) { + return false; + } else { + return true; + } + } + if (!l2) { + return false; + } + if (!p(l1.hd, l2.hd)) { + return false; + } + _l2 = l2.tl; + _l1 = l1.tl; + continue; + }; +} + +function some2(_l1, _l2, p) { + while (true) { + let l2 = _l2; + let l1 = _l1; + if (!l1) { + return false; + } + if (!l2) { + return false; + } + if (p(l1.hd, l2.hd)) { + return true; + } + _l2 = l2.tl; + _l1 = l1.tl; continue; }; } -let append = Pervasives.$at; +function has(_xs, x, eq) { + while (true) { + let xs = _xs; + if (!xs) { + return false; + } + if (eq(xs.hd, x)) { + return true; + } + _xs = xs.tl; + continue; + }; +} + +function getAssoc(_xs, x, eq) { + while (true) { + let xs = _xs; + if (!xs) { + return; + } + let match = xs.hd; + if (eq(match[0], x)) { + return Primitive_option.some(match[1]); + } + _xs = xs.tl; + continue; + }; +} + +function hasAssoc(_xs, x, eq) { + while (true) { + let xs = _xs; + if (!xs) { + return false; + } + if (eq(xs.hd[0], x)) { + return true; + } + _xs = xs.tl; + continue; + }; +} + +function removeAssoc(xs, x, eq) { + if (!xs) { + return /* [] */0; + } + let l = xs.tl; + let pair = xs.hd; + if (eq(pair[0], x)) { + return l; + } + let cell = { + hd: pair, + tl: /* [] */0 + }; + let removed = removeAssocAuxWithMap(l, x, cell, eq); + if (removed) { + return cell; + } else { + return xs; + } +} + +function setAssoc(xs, x, k, eq) { + if (!xs) { + return { + hd: [ + x, + k + ], + tl: /* [] */0 + }; + } + let l = xs.tl; + let pair = xs.hd; + if (eq(pair[0], x)) { + return { + hd: [ + x, + k + ], + tl: l + }; + } + let cell = { + hd: pair, + tl: /* [] */0 + }; + let replaced = setAssocAuxWithMap(l, x, k, cell, eq); + if (replaced) { + return cell; + } else { + return { + hd: [ + x, + k + ], + tl: xs + }; + } +} + +function sort(xs, cmp) { + let arr = toArray(xs); + arr.sort(cmp); + return fromArray(arr); +} + +function find(_xs, p) { + while (true) { + let xs = _xs; + if (!xs) { + return; + } + let x = xs.hd; + if (p(x)) { + return Primitive_option.some(x); + } + _xs = xs.tl; + continue; + }; +} -let concat = flatten; +function filter(_xs, p) { + while (true) { + let xs = _xs; + if (!xs) { + return /* [] */0; + } + let t = xs.tl; + let h = xs.hd; + if (p(h)) { + let cell = { + hd: h, + tl: /* [] */0 + }; + copyAuxWitFilter(p, t, cell); + return cell; + } + _xs = t; + continue; + }; +} -let filter = find_all; +function filterWithIndex(xs, p) { + let _xs = xs; + let _i = 0; + while (true) { + let i = _i; + let xs$1 = _xs; + if (!xs$1) { + return /* [] */0; + } + let t = xs$1.tl; + let h = xs$1.hd; + if (p(h, i)) { + let cell = { + hd: h, + tl: /* [] */0 + }; + copyAuxWithFilterIndex(p, t, cell, i + 1 | 0); + return cell; + } + _i = i + 1 | 0; + _xs = t; + continue; + }; +} -let sort = stable_sort; +function filterMap(_xs, p) { + while (true) { + let xs = _xs; + if (!xs) { + return /* [] */0; + } + let t = xs.tl; + let h = p(xs.hd); + if (h !== undefined) { + let cell = { + hd: Primitive_option.valFromOption(h), + tl: /* [] */0 + }; + copyAuxWitFilterMap(p, t, cell); + return cell; + } + _xs = t; + continue; + }; +} + +function partition(l, p) { + if (!l) { + return [ + /* [] */0, + /* [] */0 + ]; + } + let h = l.hd; + let nextX = { + hd: h, + tl: /* [] */0 + }; + let nextY = { + hd: h, + tl: /* [] */0 + }; + let b = p(h); + partitionAux(p, l.tl, nextX, nextY); + if (b) { + return [ + nextX, + nextY.tl + ]; + } else { + return [ + nextX.tl, + nextY + ]; + } +} + +function unzip(xs) { + if (!xs) { + return [ + /* [] */0, + /* [] */0 + ]; + } + let match = xs.hd; + let cellX = { + hd: match[0], + tl: /* [] */0 + }; + let cellY = { + hd: match[1], + tl: /* [] */0 + }; + splitAux(xs.tl, cellX, cellY); + return [ + cellX, + cellY + ]; +} + +function zip(l1, l2) { + if (!l1) { + return /* [] */0; + } + if (!l2) { + return /* [] */0; + } + let cell = { + hd: [ + l1.hd, + l2.hd + ], + tl: /* [] */0 + }; + zipAux(l1.tl, l2.tl, cell); + return cell; +} -let fast_sort = stable_sort; +let size = length; exports.length = length; -exports.compare_lengths = compare_lengths; -exports.compare_length_with = compare_length_with; -exports.cons = cons; -exports.hd = hd; -exports.tl = tl; -exports.nth = nth; -exports.nth_opt = nth_opt; -exports.rev = rev; -exports.init = init; -exports.append = append; -exports.rev_append = rev_append; +exports.size = size; +exports.head = head; +exports.headExn = headExn; +exports.tail = tail; +exports.tailExn = tailExn; +exports.add = add; +exports.get = get; +exports.getExn = getExn; +exports.make = make; +exports.fromInitializer = fromInitializer; +exports.toShuffled = toShuffled; +exports.drop = drop; +exports.take = take; +exports.splitAt = splitAt; exports.concat = concat; -exports.flatten = flatten; -exports.iter = iter; -exports.iteri = iteri; +exports.concatMany = concatMany; +exports.reverseConcat = reverseConcat; +exports.flat = flat; exports.map = map; -exports.mapi = mapi$1; -exports.rev_map = rev_map; -exports.fold_left = fold_left; -exports.fold_right = fold_right; -exports.iter2 = iter2; -exports.map2 = map2; -exports.rev_map2 = rev_map2; -exports.fold_left2 = fold_left2; -exports.fold_right2 = fold_right2; -exports.for_all = for_all; -exports.exists = exists; -exports.for_all2 = for_all2; -exports.exists2 = exists2; -exports.mem = mem; -exports.memq = memq; +exports.zip = zip; +exports.zipBy = zipBy; +exports.mapWithIndex = mapWithIndex; +exports.fromArray = fromArray; +exports.toArray = toArray; +exports.reverse = reverse; +exports.mapReverse = mapReverse; +exports.forEach = forEach; +exports.forEachWithIndex = forEachWithIndex; +exports.reduce = reduce; +exports.reduceWithIndex = reduceWithIndex; +exports.reduceReverse = reduceReverse; +exports.mapReverse2 = mapReverse2; +exports.forEach2 = forEach2; +exports.reduce2 = reduce2; +exports.reduceReverse2 = reduceReverse2; +exports.every = every; +exports.some = some; +exports.every2 = every2; +exports.some2 = some2; +exports.compareLength = compareLength; +exports.compare = compare; +exports.equal = equal; +exports.has = has; exports.find = find; -exports.find_opt = find_opt; exports.filter = filter; -exports.find_all = find_all; +exports.filterWithIndex = filterWithIndex; +exports.filterMap = filterMap; exports.partition = partition; -exports.assoc = assoc; -exports.assoc_opt = assoc_opt; -exports.assq = assq; -exports.assq_opt = assq_opt; -exports.mem_assoc = mem_assoc; -exports.mem_assq = mem_assq; -exports.remove_assoc = remove_assoc; -exports.remove_assq = remove_assq; -exports.split = split; -exports.combine = combine; +exports.unzip = unzip; +exports.getAssoc = getAssoc; +exports.hasAssoc = hasAssoc; +exports.removeAssoc = removeAssoc; +exports.setAssoc = setAssoc; exports.sort = sort; -exports.stable_sort = stable_sort; -exports.fast_sort = fast_sort; -exports.sort_uniq = sort_uniq; -exports.merge = merge; /* No side effect */ diff --git a/lib/js/Math.js b/lib/js/Math.js new file mode 100644 index 0000000000..5d9e3eef7c --- /dev/null +++ b/lib/js/Math.js @@ -0,0 +1,27 @@ +'use strict'; + + +let Constants = {}; + +function floor(f) { + return Math.floor(f) | 0; +} + +function ceil(f) { + return Math.ceil(f) | 0; +} + +function random(min, max) { + let f = Math.random() * (max - min | 0); + return (Math.floor(f) | 0) + min | 0; +} + +let Int = { + floor: floor, + ceil: ceil, + random: random +}; + +exports.Constants = Constants; +exports.Int = Int; +/* No side effect */ diff --git a/lib/js/Null.js b/lib/js/Null.js new file mode 100644 index 0000000000..d324e36b01 --- /dev/null +++ b/lib/js/Null.js @@ -0,0 +1,84 @@ +'use strict'; + +let Option = require("./Option.js"); +let Primitive_option = require("./Primitive_option.js"); + +function fromOption(option) { + if (option !== undefined) { + return Primitive_option.valFromOption(option); + } + +} + +function equal(a, b, eq) { + return Option.equal((a == null) ? undefined : Primitive_option.some(a), (b == null) ? undefined : Primitive_option.some(b), eq); +} + +function compare(a, b, cmp) { + return Option.compare((a == null) ? undefined : Primitive_option.some(a), (b == null) ? undefined : Primitive_option.some(b), cmp); +} + +function getOr(value, $$default) { + if (value == null) { + return $$default; + } else { + return value; + } +} + +function getExn(value) { + if (!(value == null)) { + return value; + } + throw { + RE_EXN_ID: "Invalid_argument", + _1: "Null.getExn: value is null", + Error: new Error() + }; +} + +function forEach(value, f) { + if (!(value == null)) { + return f(value); + } + +} + +function map(value, f) { + if (!(value == null)) { + return f(value); + } + +} + +function mapOr(value, $$default, f) { + if (value == null) { + return $$default; + } else { + return f(value); + } +} + +function flatMap(value, f) { + if (!(value == null)) { + return f(value); + } + +} + +let getWithDefault = getOr; + +let mapWithDefault = mapOr; + +exports.equal = equal; +exports.compare = compare; +exports.fromOption = fromOption; +exports.getOr = getOr; +exports.getWithDefault = getWithDefault; +exports.getExn = getExn; +exports.forEach = forEach; +exports.map = map; +exports.mapOr = mapOr; +exports.mapWithDefault = mapWithDefault; +exports.flatMap = flatMap; +/* No side effect */ diff --git a/lib/js/Nullable.js b/lib/js/Nullable.js new file mode 100644 index 0000000000..eeb1eee1fb --- /dev/null +++ b/lib/js/Nullable.js @@ -0,0 +1,86 @@ +'use strict'; + +let Option = require("./Option.js"); +let Primitive_option = require("./Primitive_option.js"); + +function fromOption(option) { + if (option !== undefined) { + return Primitive_option.valFromOption(option); + } + +} + +function equal(a, b, eq) { + return Option.equal(a === null ? undefined : Primitive_option.some(a), b === null ? undefined : Primitive_option.some(b), eq); +} + +function compare(a, b, cmp) { + return Option.compare(a === null ? undefined : Primitive_option.some(a), b === null ? undefined : Primitive_option.some(b), cmp); +} + +function getOr(value, $$default) { + if (value !== null) { + return value; + } else { + return $$default; + } +} + +function getExn(value) { + if (value !== null) { + return value; + } + throw { + RE_EXN_ID: "Invalid_argument", + _1: "Nullable.getExn: value is null or undefined", + Error: new Error() + }; +} + +function forEach(value, f) { + if (value !== null) { + return f(value); + } + +} + +function map(value, f) { + if (value !== null) { + return f(value); + } else { + return value; + } +} + +function mapOr(value, $$default, f) { + if (value !== null) { + return f(value); + } else { + return $$default; + } +} + +function flatMap(value, f) { + if (value !== null) { + return f(value); + } else { + return value; + } +} + +let getWithDefault = getOr; + +let mapWithDefault = mapOr; + +exports.equal = equal; +exports.compare = compare; +exports.fromOption = fromOption; +exports.getOr = getOr; +exports.getWithDefault = getWithDefault; +exports.getExn = getExn; +exports.forEach = forEach; +exports.map = map; +exports.mapOr = mapOr; +exports.mapWithDefault = mapWithDefault; +exports.flatMap = flatMap; +/* No side effect */ diff --git a/lib/js/Object.js b/lib/js/Object.js new file mode 100644 index 0000000000..ae1b9f17e6 --- /dev/null +++ b/lib/js/Object.js @@ -0,0 +1 @@ +/* This output is empty. Its source's type definitions, externals and/or unused code got optimized away. */ diff --git a/lib/js/Option.js b/lib/js/Option.js new file mode 100644 index 0000000000..221ab3fbba --- /dev/null +++ b/lib/js/Option.js @@ -0,0 +1,118 @@ +'use strict'; + +let $$Error = require("./Error.js"); +let Primitive_option = require("./Primitive_option.js"); + +function filter(opt, p) { + if (opt !== undefined && p(Primitive_option.valFromOption(opt))) { + return opt; + } + +} + +function forEach(opt, f) { + if (opt !== undefined) { + return f(Primitive_option.valFromOption(opt)); + } + +} + +function getExn(x, message) { + if (x !== undefined) { + return Primitive_option.valFromOption(x); + } else { + return $$Error.panic(message !== undefined ? message : "Option.getExn called for None value"); + } +} + +function mapOr(opt, $$default, f) { + if (opt !== undefined) { + return f(Primitive_option.valFromOption(opt)); + } else { + return $$default; + } +} + +function map(opt, f) { + if (opt !== undefined) { + return Primitive_option.some(f(Primitive_option.valFromOption(opt))); + } + +} + +function flatMap(opt, f) { + if (opt !== undefined) { + return f(Primitive_option.valFromOption(opt)); + } + +} + +function getOr(opt, $$default) { + if (opt !== undefined) { + return Primitive_option.valFromOption(opt); + } else { + return $$default; + } +} + +function orElse(opt, other) { + if (opt !== undefined) { + return opt; + } else { + return other; + } +} + +function isSome(x) { + return x !== undefined; +} + +function isNone(x) { + return x === undefined; +} + +function equal(a, b, eq) { + if (a !== undefined) { + if (b !== undefined) { + return eq(Primitive_option.valFromOption(a), Primitive_option.valFromOption(b)); + } else { + return false; + } + } else { + return b === undefined; + } +} + +function compare(a, b, cmp) { + if (a !== undefined) { + if (b !== undefined) { + return cmp(Primitive_option.valFromOption(a), Primitive_option.valFromOption(b)); + } else { + return 1; + } + } else if (b !== undefined) { + return -1; + } else { + return 0; + } +} + +let mapWithDefault = mapOr; + +let getWithDefault = getOr; + +exports.filter = filter; +exports.forEach = forEach; +exports.getExn = getExn; +exports.mapOr = mapOr; +exports.mapWithDefault = mapWithDefault; +exports.map = map; +exports.flatMap = flatMap; +exports.getOr = getOr; +exports.getWithDefault = getWithDefault; +exports.orElse = orElse; +exports.isSome = isSome; +exports.isNone = isNone; +exports.equal = equal; +exports.compare = compare; +/* No side effect */ diff --git a/lib/js/Ordering.js b/lib/js/Ordering.js new file mode 100644 index 0000000000..ee7f5ca1ea --- /dev/null +++ b/lib/js/Ordering.js @@ -0,0 +1,35 @@ +'use strict'; + + +function isLess(ord) { + return ord < 0; +} + +function isEqual(ord) { + return ord === 0; +} + +function isGreater(ord) { + return ord > 0; +} + +function invert(ord) { + return - ord; +} + +function fromInt(n) { + if (n < 0) { + return -1; + } else if (n > 0) { + return 1; + } else { + return 0; + } +} + +exports.isLess = isLess; +exports.isEqual = isEqual; +exports.isGreater = isGreater; +exports.invert = invert; +exports.fromInt = fromInt; +/* No side effect */ diff --git a/lib/js/Pervasives.js b/lib/js/Pervasives.js index a162ffc7be..fa6d5f7e68 100644 --- a/lib/js/Pervasives.js +++ b/lib/js/Pervasives.js @@ -1,5 +1,6 @@ 'use strict'; +let $$Error = require("./Error.js"); let Primitive_exceptions = require("./Primitive_exceptions.js"); function failwith(s) { @@ -18,7 +19,7 @@ function invalid_arg(s) { }; } -let Exit = /* @__PURE__ */Primitive_exceptions.create("Pervasives.Pervasives.Exit"); +let Exit = /* @__PURE__ */Primitive_exceptions.create("Pervasives.Exit"); function abs(x) { if (x >= 0) { @@ -115,28 +116,6 @@ function $at(l1, l2) { } } -let Pervasives = { - failwith: failwith, - invalid_arg: invalid_arg, - Exit: Exit, - abs: abs, - lnot: lnot, - max_int: 2147483647, - min_int: min_int, - infinity: Infinity, - neg_infinity: -Infinity, - max_float: 1.79769313486231571e+308, - min_float: 2.22507385850720138e-308, - epsilon_float: 2.22044604925031308e-16, - classify_float: classify_float, - char_of_int: char_of_int, - string_of_bool: string_of_bool, - bool_of_string: bool_of_string, - bool_of_string_opt: bool_of_string_opt, - int_of_string_opt: int_of_string_opt, - $at: $at -}; - let max_int = 2147483647; let infinity = Infinity; @@ -149,7 +128,8 @@ let min_float = 2.22507385850720138e-308; let epsilon_float = 2.22044604925031308e-16; -exports.Pervasives = Pervasives; +let panic = $$Error.panic; + exports.failwith = failwith; exports.invalid_arg = invalid_arg; exports.Exit = Exit; @@ -169,4 +149,5 @@ exports.bool_of_string = bool_of_string; exports.bool_of_string_opt = bool_of_string_opt; exports.int_of_string_opt = int_of_string_opt; exports.$at = $at; +exports.panic = panic; /* No side effect */ diff --git a/lib/js/Promise.js b/lib/js/Promise.js new file mode 100644 index 0000000000..eb6fd42776 --- /dev/null +++ b/lib/js/Promise.js @@ -0,0 +1,10 @@ +'use strict'; + +let Primitive_exceptions = require("./Primitive_exceptions.js"); + +function $$catch(promise, callback) { + return promise.catch(err => callback(Primitive_exceptions.internalToException(err))); +} + +exports.$$catch = $$catch; +/* No side effect */ diff --git a/lib/js/RegExp.js b/lib/js/RegExp.js new file mode 100644 index 0000000000..5ce0fbaab3 --- /dev/null +++ b/lib/js/RegExp.js @@ -0,0 +1,7 @@ +'use strict'; + + +let Result = {}; + +exports.Result = Result; +/* No side effect */ diff --git a/lib/js/Result.js b/lib/js/Result.js new file mode 100644 index 0000000000..d29b38e588 --- /dev/null +++ b/lib/js/Result.js @@ -0,0 +1,128 @@ +'use strict'; + + +function getExn(x) { + if (x.TAG === "Ok") { + return x._0; + } + throw { + RE_EXN_ID: "Not_found", + Error: new Error() + }; +} + +function mapOr(opt, $$default, f) { + if (opt.TAG === "Ok") { + return f(opt._0); + } else { + return $$default; + } +} + +function map(opt, f) { + if (opt.TAG === "Ok") { + return { + TAG: "Ok", + _0: f(opt._0) + }; + } else { + return opt; + } +} + +function flatMap(opt, f) { + if (opt.TAG === "Ok") { + return f(opt._0); + } else { + return opt; + } +} + +function getOr(opt, $$default) { + if (opt.TAG === "Ok") { + return opt._0; + } else { + return $$default; + } +} + +function isOk(x) { + if (x.TAG === "Ok") { + return true; + } else { + return false; + } +} + +function isError(x) { + if (x.TAG === "Ok") { + return false; + } else { + return true; + } +} + +function equal(a, b, f) { + if (a.TAG === "Ok") { + if (b.TAG === "Ok") { + return f(a._0, b._0); + } else { + return false; + } + } else if (b.TAG === "Ok") { + return false; + } else { + return true; + } +} + +function compare(a, b, f) { + if (a.TAG === "Ok") { + if (b.TAG === "Ok") { + return f(a._0, b._0); + } else { + return 1; + } + } else if (b.TAG === "Ok") { + return -1; + } else { + return 0; + } +} + +function forEach(r, f) { + if (r.TAG === "Ok") { + return f(r._0); + } + +} + +function mapError(r, f) { + if (r.TAG === "Ok") { + return r; + } else { + return { + TAG: "Error", + _0: f(r._0) + }; + } +} + +let mapWithDefault = mapOr; + +let getWithDefault = getOr; + +exports.getExn = getExn; +exports.mapOr = mapOr; +exports.mapWithDefault = mapWithDefault; +exports.map = map; +exports.flatMap = flatMap; +exports.getOr = getOr; +exports.getWithDefault = getWithDefault; +exports.isOk = isOk; +exports.isError = isError; +exports.equal = equal; +exports.compare = compare; +exports.forEach = forEach; +exports.mapError = mapError; +/* No side effect */ diff --git a/lib/js/String.js b/lib/js/String.js index 0ff74c6bc5..b653c67e12 100644 --- a/lib/js/String.js +++ b/lib/js/String.js @@ -1,321 +1,31 @@ 'use strict'; -let Char = require("./Char.js"); -let $$Array = require("./Array.js"); -let Primitive_exceptions = require("./Primitive_exceptions.js"); -function apply1(f, bytes) { - if (bytes.length === 0) { - return bytes; +function indexOfOpt(s, search) { + let index = s.indexOf(search); + if (index !== -1) { + return index; } - let r = bytes.slice(); - r[0] = f(bytes[0]); - return r; + } -function concat(sep, xs) { - return $$Array.of_list(xs).join(sep); -} - -function bos(str) { - return $$Array.map(str => str.codePointAt(0), Array.from(str)); -} - -function make(len, ch) { - return String.fromCodePoint(ch).repeat(len); -} - -function init(len, f) { - return $$Array.init(len, i => String.fromCodePoint(f(i))).join(""); -} - -function sub(s, ofs, len) { - return String.fromCodePoint(...$$Array.sub(bos(s), ofs, len)); -} - -function iter(f, s) { - for (let i = 0, i_finish = s.length; i < i_finish; ++i) { - f(s.codePointAt(i)); - } -} - -function iteri(f, s) { - for (let i = 0, i_finish = s.length; i < i_finish; ++i) { - f(i, s.codePointAt(i)); - } -} - -function map(f, s) { - return String.fromCodePoint(...$$Array.map(f, bos(s))); -} - -function mapi(f, s) { - return String.fromCodePoint(...$$Array.mapi(f, bos(s))); -} - -function escaped(s) { - let needs_escape = _i => { - while (true) { - let i = _i; - if (i >= s.length) { - return false; - } - let match = s.codePointAt(i); - if (match < 32) { - return true; - } - if (match > 92 || match < 34) { - if (match >= 127) { - return true; - } - _i = i + 1 | 0; - continue; - } - if (match > 91 || match < 35) { - return true; - } - _i = i + 1 | 0; - continue; - }; - }; - if (!needs_escape(0)) { - return s; - } - let bytes = bos(s); - return $$Array.map(Char.escaped, bytes).join(""); -} - -function index_rec(s, lim, _i, c) { - while (true) { - let i = _i; - if (i >= lim) { - throw { - RE_EXN_ID: "Not_found", - Error: new Error() - }; - } - if (s.codePointAt(i) === c) { - return i; - } - _i = i + 1 | 0; - continue; - }; -} - -function index(s, c) { - return index_rec(s, s.length, 0, c); -} - -function index_rec_opt(s, lim, _i, c) { - while (true) { - let i = _i; - if (i >= lim) { - return; - } - if (s.codePointAt(i) === c) { - return i; - } - _i = i + 1 | 0; - continue; - }; -} - -function index_opt(s, c) { - return index_rec_opt(s, s.length, 0, c); -} - -function index_from(s, i, c) { - let l = s.length; - if (i < 0 || i > l) { - throw { - RE_EXN_ID: "Invalid_argument", - _1: "String.index_from / Bytes.index_from", - Error: new Error() - }; - } - return index_rec(s, l, i, c); -} - -function index_from_opt(s, i, c) { - let l = s.length; - if (i < 0 || i > l) { - throw { - RE_EXN_ID: "Invalid_argument", - _1: "String.index_from_opt / Bytes.index_from_opt", - Error: new Error() - }; +function lastIndexOfOpt(s, search) { + let index = s.lastIndexOf(search); + if (index !== -1) { + return index; } - return index_rec_opt(s, l, i, c); -} - -function rindex_rec(s, _i, c) { - while (true) { - let i = _i; - if (i < 0) { - throw { - RE_EXN_ID: "Not_found", - Error: new Error() - }; - } - if (s.codePointAt(i) === c) { - return i; - } - _i = i - 1 | 0; - continue; - }; -} - -function rindex(s, c) { - return rindex_rec(s, s.length - 1 | 0, c); -} - -function rindex_from(s, i, c) { - if (i < -1 || i >= s.length) { - throw { - RE_EXN_ID: "Invalid_argument", - _1: "String.rindex_from / Bytes.rindex_from", - Error: new Error() - }; - } - return rindex_rec(s, i, c); -} - -function rindex_rec_opt(s, _i, c) { - while (true) { - let i = _i; - if (i < 0) { - return; - } - if (s.codePointAt(i) === c) { - return i; - } - _i = i - 1 | 0; - continue; - }; -} - -function rindex_opt(s, c) { - return rindex_rec_opt(s, s.length - 1 | 0, c); -} - -function rindex_from_opt(s, i, c) { - if (i < -1 || i >= s.length) { - throw { - RE_EXN_ID: "Invalid_argument", - _1: "String.rindex_from_opt / Bytes.rindex_from_opt", - Error: new Error() - }; - } - return rindex_rec_opt(s, i, c); -} - -function contains_from(s, i, c) { - let l = s.length; - if (i < 0 || i > l) { - throw { - RE_EXN_ID: "Invalid_argument", - _1: "String.contains_from / Bytes.contains_from", - Error: new Error() - }; - } - try { - index_rec(s, l, i, c); - return true; - } catch (raw_exn) { - let exn = Primitive_exceptions.internalToException(raw_exn); - if (exn.RE_EXN_ID === "Not_found") { - return false; - } - throw exn; - } -} - -function contains(s, c) { - return contains_from(s, 0, c); -} - -function rcontains_from(s, i, c) { - if (i < 0 || i >= s.length) { - throw { - RE_EXN_ID: "Invalid_argument", - _1: "String.rcontains_from / Bytes.rcontains_from", - Error: new Error() - }; - } - try { - rindex_rec(s, i, c); - return true; - } catch (raw_exn) { - let exn = Primitive_exceptions.internalToException(raw_exn); - if (exn.RE_EXN_ID === "Not_found") { - return false; - } - throw exn; - } -} - -function uppercase_ascii(s) { - let bytes = bos(s); - return String.fromCodePoint(...$$Array.map(Char.uppercase_ascii, bytes)); -} - -function lowercase_ascii(s) { - let bytes = bos(s); - return String.fromCodePoint(...$$Array.map(Char.lowercase_ascii, bytes)); -} - -function capitalize_ascii(s) { - let bytes = bos(s); - return String.fromCodePoint(...apply1(Char.uppercase_ascii, bytes)); -} - -function uncapitalize_ascii(s) { - let bytes = bos(s); - return String.fromCodePoint(...apply1(Char.lowercase_ascii, bytes)); + } -function split_on_char(sep, s) { - let r = /* [] */0; - let j = s.length; - for (let i = s.length - 1 | 0; i >= 0; --i) { - if (s.codePointAt(i) === sep) { - r = { - hd: sub(s, i + 1 | 0, (j - i | 0) - 1 | 0), - tl: r - }; - j = i; - } - +function searchOpt(s, re) { + let index = s.search(re); + if (index !== -1) { + return index; } - return { - hd: sub(s, 0, j), - tl: r - }; + } -exports.make = make; -exports.init = init; -exports.sub = sub; -exports.concat = concat; -exports.iter = iter; -exports.iteri = iteri; -exports.map = map; -exports.mapi = mapi; -exports.escaped = escaped; -exports.index = index; -exports.index_opt = index_opt; -exports.rindex = rindex; -exports.rindex_opt = rindex_opt; -exports.index_from = index_from; -exports.index_from_opt = index_from_opt; -exports.rindex_from = rindex_from; -exports.rindex_from_opt = rindex_from_opt; -exports.contains = contains; -exports.contains_from = contains_from; -exports.rcontains_from = rcontains_from; -exports.uppercase_ascii = uppercase_ascii; -exports.lowercase_ascii = lowercase_ascii; -exports.capitalize_ascii = capitalize_ascii; -exports.uncapitalize_ascii = uncapitalize_ascii; -exports.split_on_char = split_on_char; +exports.indexOfOpt = indexOfOpt; +exports.lastIndexOfOpt = lastIndexOfOpt; +exports.searchOpt = searchOpt; /* No side effect */ diff --git a/lib/js/Symbol.js b/lib/js/Symbol.js new file mode 100644 index 0000000000..ae1b9f17e6 --- /dev/null +++ b/lib/js/Symbol.js @@ -0,0 +1 @@ +/* This output is empty. Its source's type definitions, externals and/or unused code got optimized away. */ diff --git a/lib/js/Type.js b/lib/js/Type.js new file mode 100644 index 0000000000..97e70a072d --- /dev/null +++ b/lib/js/Type.js @@ -0,0 +1,56 @@ +'use strict'; + + +function classify(value) { + let match = Object.prototype.toString.call(value); + switch (match) { + case "[object BigInt]" : + return { + TAG: "BigInt", + _0: value + }; + case "[object Boolean]" : + return { + TAG: "Bool", + _0: value + }; + case "[object AsyncFunction]" : + case "[object Function]" : + case "[object GeneratorFunction]" : + return { + TAG: "Function", + _0: value + }; + case "[object Null]" : + return "Null"; + case "[object Number]" : + return { + TAG: "Number", + _0: value + }; + case "[object String]" : + return { + TAG: "String", + _0: value + }; + case "[object Symbol]" : + return { + TAG: "Symbol", + _0: value + }; + case "[object Undefined]" : + return "Undefined"; + default: + return { + TAG: "Object", + _0: value + }; + } +} + +let Classify = { + classify: classify +}; + +exports.Classify = Classify; +/* No side effect */ diff --git a/lib/js/TypedArray.js b/lib/js/TypedArray.js new file mode 100644 index 0000000000..ae1b9f17e6 --- /dev/null +++ b/lib/js/TypedArray.js @@ -0,0 +1 @@ +/* This output is empty. Its source's type definitions, externals and/or unused code got optimized away. */ diff --git a/lib/js/Uint16Array.js b/lib/js/Uint16Array.js new file mode 100644 index 0000000000..8ff6f5bdb3 --- /dev/null +++ b/lib/js/Uint16Array.js @@ -0,0 +1,7 @@ +'use strict'; + + +let Constants = {}; + +exports.Constants = Constants; +/* No side effect */ diff --git a/lib/js/Uint32Array.js b/lib/js/Uint32Array.js new file mode 100644 index 0000000000..8ff6f5bdb3 --- /dev/null +++ b/lib/js/Uint32Array.js @@ -0,0 +1,7 @@ +'use strict'; + + +let Constants = {}; + +exports.Constants = Constants; +/* No side effect */ diff --git a/lib/js/Uint8Array.js b/lib/js/Uint8Array.js new file mode 100644 index 0000000000..8ff6f5bdb3 --- /dev/null +++ b/lib/js/Uint8Array.js @@ -0,0 +1,7 @@ +'use strict'; + + +let Constants = {}; + +exports.Constants = Constants; +/* No side effect */ diff --git a/lib/js/Uint8ClampedArray.js b/lib/js/Uint8ClampedArray.js new file mode 100644 index 0000000000..8ff6f5bdb3 --- /dev/null +++ b/lib/js/Uint8ClampedArray.js @@ -0,0 +1,7 @@ +'use strict'; + + +let Constants = {}; + +exports.Constants = Constants; +/* No side effect */ diff --git a/lib/js/WeakMap.js b/lib/js/WeakMap.js new file mode 100644 index 0000000000..ae1b9f17e6 --- /dev/null +++ b/lib/js/WeakMap.js @@ -0,0 +1 @@ +/* This output is empty. Its source's type definitions, externals and/or unused code got optimized away. */ diff --git a/lib/js/WeakSet.js b/lib/js/WeakSet.js new file mode 100644 index 0000000000..ae1b9f17e6 --- /dev/null +++ b/lib/js/WeakSet.js @@ -0,0 +1 @@ +/* This output is empty. Its source's type definitions, externals and/or unused code got optimized away. */ diff --git a/packages/artifacts.txt b/packages/artifacts.txt index a916707e1c..ac398baaae 100644 --- a/packages/artifacts.txt +++ b/packages/artifacts.txt @@ -26,6 +26,8 @@ darwinarm64/rewatch.exe docs/docson/build-schema.json lib/bstracing lib/es6/Array.js +lib/es6/ArrayBuffer.js +lib/es6/AsyncIterator.js lib/es6/Belt.js lib/es6/Belt_Array.js lib/es6/Belt_Float.js @@ -69,11 +71,40 @@ lib/es6/Belt_internalMapString.js lib/es6/Belt_internalSetBuckets.js lib/es6/Belt_internalSetInt.js lib/es6/Belt_internalSetString.js +lib/es6/BigInt.js +lib/es6/BigInt64Array.js +lib/es6/BigUint64Array.js lib/es6/Char.js +lib/es6/Console.js +lib/es6/DataView.js +lib/es6/Date.js +lib/es6/Dict.js lib/es6/Dom.js lib/es6/Dom_storage.js lib/es6/Dom_storage2.js -lib/es6/Hashtbl.js +lib/es6/Error.js +lib/es6/Exn.js +lib/es6/Float.js +lib/es6/Float32Array.js +lib/es6/Float64Array.js +lib/es6/Int.js +lib/es6/Int16Array.js +lib/es6/Int32Array.js +lib/es6/Int8Array.js +lib/es6/Intl.js +lib/es6/Intl_Collator.js +lib/es6/Intl_Common.js +lib/es6/Intl_DateTimeFormat.js +lib/es6/Intl_ListFormat.js +lib/es6/Intl_Locale.js +lib/es6/Intl_NumberFormat.js +lib/es6/Intl_NumberFormat_Grouping.js +lib/es6/Intl_PluralRules.js +lib/es6/Intl_RelativeTimeFormat.js +lib/es6/Intl_Segmenter.js +lib/es6/Intl_Segments.js +lib/es6/Iterator.js +lib/es6/JSON.js lib/es6/Js.js lib/es6/Js_OO.js lib/es6/Js_array.js @@ -83,7 +114,6 @@ lib/es6/Js_blob.js lib/es6/Js_console.js lib/es6/Js_date.js lib/es6/Js_dict.js -lib/es6/Js_exn.js lib/es6/Js_extern.js lib/es6/Js_file.js lib/es6/Js_float.js @@ -117,7 +147,13 @@ lib/es6/JsxPPXReactSupport.js lib/es6/Lazy.js lib/es6/List.js lib/es6/Map.js +lib/es6/Math.js +lib/es6/Null.js +lib/es6/Nullable.js lib/es6/Obj.js +lib/es6/Object.js +lib/es6/Option.js +lib/es6/Ordering.js lib/es6/Pervasives.js lib/es6/Primitive_array.js lib/es6/Primitive_array_extern.js @@ -142,10 +178,24 @@ lib/es6/Primitive_promise.js lib/es6/Primitive_string.js lib/es6/Primitive_string_extern.js lib/es6/Primitive_util.js +lib/es6/Promise.js +lib/es6/RegExp.js +lib/es6/Result.js lib/es6/Set.js lib/es6/String.js +lib/es6/Symbol.js +lib/es6/Type.js +lib/es6/TypedArray.js +lib/es6/Uint16Array.js +lib/es6/Uint32Array.js +lib/es6/Uint8Array.js +lib/es6/Uint8ClampedArray.js +lib/es6/WeakMap.js +lib/es6/WeakSet.js lib/es6/package.json lib/js/Array.js +lib/js/ArrayBuffer.js +lib/js/AsyncIterator.js lib/js/Belt.js lib/js/Belt_Array.js lib/js/Belt_Float.js @@ -189,11 +239,40 @@ lib/js/Belt_internalMapString.js lib/js/Belt_internalSetBuckets.js lib/js/Belt_internalSetInt.js lib/js/Belt_internalSetString.js +lib/js/BigInt.js +lib/js/BigInt64Array.js +lib/js/BigUint64Array.js lib/js/Char.js +lib/js/Console.js +lib/js/DataView.js +lib/js/Date.js +lib/js/Dict.js lib/js/Dom.js lib/js/Dom_storage.js lib/js/Dom_storage2.js -lib/js/Hashtbl.js +lib/js/Error.js +lib/js/Exn.js +lib/js/Float.js +lib/js/Float32Array.js +lib/js/Float64Array.js +lib/js/Int.js +lib/js/Int16Array.js +lib/js/Int32Array.js +lib/js/Int8Array.js +lib/js/Intl.js +lib/js/Intl_Collator.js +lib/js/Intl_Common.js +lib/js/Intl_DateTimeFormat.js +lib/js/Intl_ListFormat.js +lib/js/Intl_Locale.js +lib/js/Intl_NumberFormat.js +lib/js/Intl_NumberFormat_Grouping.js +lib/js/Intl_PluralRules.js +lib/js/Intl_RelativeTimeFormat.js +lib/js/Intl_Segmenter.js +lib/js/Intl_Segments.js +lib/js/Iterator.js +lib/js/JSON.js lib/js/Js.js lib/js/Js_OO.js lib/js/Js_array.js @@ -203,7 +282,6 @@ lib/js/Js_blob.js lib/js/Js_console.js lib/js/Js_date.js lib/js/Js_dict.js -lib/js/Js_exn.js lib/js/Js_extern.js lib/js/Js_file.js lib/js/Js_float.js @@ -237,7 +315,13 @@ lib/js/JsxPPXReactSupport.js lib/js/Lazy.js lib/js/List.js lib/js/Map.js +lib/js/Math.js +lib/js/Null.js +lib/js/Nullable.js lib/js/Obj.js +lib/js/Object.js +lib/js/Option.js +lib/js/Ordering.js lib/js/Pervasives.js lib/js/Primitive_array.js lib/js/Primitive_array_extern.js @@ -262,8 +346,20 @@ lib/js/Primitive_promise.js lib/js/Primitive_string.js lib/js/Primitive_string_extern.js lib/js/Primitive_util.js +lib/js/Promise.js +lib/js/RegExp.js +lib/js/Result.js lib/js/Set.js lib/js/String.js +lib/js/Symbol.js +lib/js/Type.js +lib/js/TypedArray.js +lib/js/Uint16Array.js +lib/js/Uint32Array.js +lib/js/Uint8Array.js +lib/js/Uint8ClampedArray.js +lib/js/WeakMap.js +lib/js/WeakSet.js lib/minisocket.js lib/ocaml/Array.cmi lib/ocaml/Array.cmj @@ -271,6 +367,16 @@ lib/ocaml/Array.cmt lib/ocaml/Array.cmti lib/ocaml/Array.res lib/ocaml/Array.resi +lib/ocaml/ArrayBuffer.cmi +lib/ocaml/ArrayBuffer.cmj +lib/ocaml/ArrayBuffer.cmt +lib/ocaml/ArrayBuffer.res +lib/ocaml/AsyncIterator.cmi +lib/ocaml/AsyncIterator.cmj +lib/ocaml/AsyncIterator.cmt +lib/ocaml/AsyncIterator.cmti +lib/ocaml/AsyncIterator.res +lib/ocaml/AsyncIterator.resi lib/ocaml/Belt.cmi lib/ocaml/Belt.cmj lib/ocaml/Belt.cmt @@ -519,12 +625,46 @@ lib/ocaml/Belt_internalSetString.cmi lib/ocaml/Belt_internalSetString.cmj lib/ocaml/Belt_internalSetString.cmt lib/ocaml/Belt_internalSetString.res +lib/ocaml/BigInt.cmi +lib/ocaml/BigInt.cmj +lib/ocaml/BigInt.cmt +lib/ocaml/BigInt.res +lib/ocaml/BigInt64Array.cmi +lib/ocaml/BigInt64Array.cmj +lib/ocaml/BigInt64Array.cmt +lib/ocaml/BigInt64Array.res +lib/ocaml/BigUint64Array.cmi +lib/ocaml/BigUint64Array.cmj +lib/ocaml/BigUint64Array.cmt +lib/ocaml/BigUint64Array.res lib/ocaml/Char.cmi lib/ocaml/Char.cmj lib/ocaml/Char.cmt lib/ocaml/Char.cmti lib/ocaml/Char.res lib/ocaml/Char.resi +lib/ocaml/Console.cmi +lib/ocaml/Console.cmj +lib/ocaml/Console.cmt +lib/ocaml/Console.cmti +lib/ocaml/Console.res +lib/ocaml/Console.resi +lib/ocaml/DataView.cmi +lib/ocaml/DataView.cmj +lib/ocaml/DataView.cmt +lib/ocaml/DataView.res +lib/ocaml/Date.cmi +lib/ocaml/Date.cmj +lib/ocaml/Date.cmt +lib/ocaml/Date.cmti +lib/ocaml/Date.res +lib/ocaml/Date.resi +lib/ocaml/Dict.cmi +lib/ocaml/Dict.cmj +lib/ocaml/Dict.cmt +lib/ocaml/Dict.cmti +lib/ocaml/Dict.res +lib/ocaml/Dict.resi lib/ocaml/Dom.cmi lib/ocaml/Dom.cmj lib/ocaml/Dom.cmt @@ -537,12 +677,110 @@ lib/ocaml/Dom_storage2.cmi lib/ocaml/Dom_storage2.cmj lib/ocaml/Dom_storage2.cmt lib/ocaml/Dom_storage2.res -lib/ocaml/Hashtbl.cmi -lib/ocaml/Hashtbl.cmj -lib/ocaml/Hashtbl.cmt -lib/ocaml/Hashtbl.cmti -lib/ocaml/Hashtbl.res -lib/ocaml/Hashtbl.resi +lib/ocaml/Error.cmi +lib/ocaml/Error.cmj +lib/ocaml/Error.cmt +lib/ocaml/Error.cmti +lib/ocaml/Error.res +lib/ocaml/Error.resi +lib/ocaml/Exn.cmi +lib/ocaml/Exn.cmj +lib/ocaml/Exn.cmt +lib/ocaml/Exn.cmti +lib/ocaml/Exn.res +lib/ocaml/Exn.resi +lib/ocaml/Float.cmi +lib/ocaml/Float.cmj +lib/ocaml/Float.cmt +lib/ocaml/Float.cmti +lib/ocaml/Float.res +lib/ocaml/Float.resi +lib/ocaml/Float32Array.cmi +lib/ocaml/Float32Array.cmj +lib/ocaml/Float32Array.cmt +lib/ocaml/Float32Array.res +lib/ocaml/Float64Array.cmi +lib/ocaml/Float64Array.cmj +lib/ocaml/Float64Array.cmt +lib/ocaml/Float64Array.res +lib/ocaml/Int.cmi +lib/ocaml/Int.cmj +lib/ocaml/Int.cmt +lib/ocaml/Int.cmti +lib/ocaml/Int.res +lib/ocaml/Int.resi +lib/ocaml/Int16Array.cmi +lib/ocaml/Int16Array.cmj +lib/ocaml/Int16Array.cmt +lib/ocaml/Int16Array.res +lib/ocaml/Int32Array.cmi +lib/ocaml/Int32Array.cmj +lib/ocaml/Int32Array.cmt +lib/ocaml/Int32Array.res +lib/ocaml/Int8Array.cmi +lib/ocaml/Int8Array.cmj +lib/ocaml/Int8Array.cmt +lib/ocaml/Int8Array.res +lib/ocaml/Intl.cmi +lib/ocaml/Intl.cmj +lib/ocaml/Intl.cmt +lib/ocaml/Intl.res +lib/ocaml/Intl_Collator.cmi +lib/ocaml/Intl_Collator.cmj +lib/ocaml/Intl_Collator.cmt +lib/ocaml/Intl_Collator.res +lib/ocaml/Intl_Common.cmi +lib/ocaml/Intl_Common.cmj +lib/ocaml/Intl_Common.cmt +lib/ocaml/Intl_Common.res +lib/ocaml/Intl_DateTimeFormat.cmi +lib/ocaml/Intl_DateTimeFormat.cmj +lib/ocaml/Intl_DateTimeFormat.cmt +lib/ocaml/Intl_DateTimeFormat.res +lib/ocaml/Intl_ListFormat.cmi +lib/ocaml/Intl_ListFormat.cmj +lib/ocaml/Intl_ListFormat.cmt +lib/ocaml/Intl_ListFormat.res +lib/ocaml/Intl_Locale.cmi +lib/ocaml/Intl_Locale.cmj +lib/ocaml/Intl_Locale.cmt +lib/ocaml/Intl_Locale.res +lib/ocaml/Intl_NumberFormat.cmi +lib/ocaml/Intl_NumberFormat.cmj +lib/ocaml/Intl_NumberFormat.cmt +lib/ocaml/Intl_NumberFormat.res +lib/ocaml/Intl_NumberFormat_Grouping.cmi +lib/ocaml/Intl_NumberFormat_Grouping.cmj +lib/ocaml/Intl_NumberFormat_Grouping.cmt +lib/ocaml/Intl_NumberFormat_Grouping.res +lib/ocaml/Intl_PluralRules.cmi +lib/ocaml/Intl_PluralRules.cmj +lib/ocaml/Intl_PluralRules.cmt +lib/ocaml/Intl_PluralRules.res +lib/ocaml/Intl_RelativeTimeFormat.cmi +lib/ocaml/Intl_RelativeTimeFormat.cmj +lib/ocaml/Intl_RelativeTimeFormat.cmt +lib/ocaml/Intl_RelativeTimeFormat.res +lib/ocaml/Intl_Segmenter.cmi +lib/ocaml/Intl_Segmenter.cmj +lib/ocaml/Intl_Segmenter.cmt +lib/ocaml/Intl_Segmenter.res +lib/ocaml/Intl_Segments.cmi +lib/ocaml/Intl_Segments.cmj +lib/ocaml/Intl_Segments.cmt +lib/ocaml/Intl_Segments.res +lib/ocaml/Iterator.cmi +lib/ocaml/Iterator.cmj +lib/ocaml/Iterator.cmt +lib/ocaml/Iterator.cmti +lib/ocaml/Iterator.res +lib/ocaml/Iterator.resi +lib/ocaml/JSON.cmi +lib/ocaml/JSON.cmj +lib/ocaml/JSON.cmt +lib/ocaml/JSON.cmti +lib/ocaml/JSON.res +lib/ocaml/JSON.resi lib/ocaml/Js.cmi lib/ocaml/Js.cmj lib/ocaml/Js.cmt @@ -581,12 +819,6 @@ lib/ocaml/Js_dict.cmt lib/ocaml/Js_dict.cmti lib/ocaml/Js_dict.res lib/ocaml/Js_dict.resi -lib/ocaml/Js_exn.cmi -lib/ocaml/Js_exn.cmj -lib/ocaml/Js_exn.cmt -lib/ocaml/Js_exn.cmti -lib/ocaml/Js_exn.res -lib/ocaml/Js_exn.resi lib/ocaml/Js_extern.cmi lib/ocaml/Js_extern.cmj lib/ocaml/Js_extern.cmt @@ -736,11 +968,45 @@ lib/ocaml/List.resi lib/ocaml/Map.cmi lib/ocaml/Map.cmj lib/ocaml/Map.cmt +lib/ocaml/Map.cmti lib/ocaml/Map.res +lib/ocaml/Map.resi +lib/ocaml/Math.cmi +lib/ocaml/Math.cmj +lib/ocaml/Math.cmt +lib/ocaml/Math.cmti +lib/ocaml/Math.res +lib/ocaml/Math.resi +lib/ocaml/Null.cmi +lib/ocaml/Null.cmj +lib/ocaml/Null.cmt +lib/ocaml/Null.cmti +lib/ocaml/Null.res +lib/ocaml/Null.resi +lib/ocaml/Nullable.cmi +lib/ocaml/Nullable.cmj +lib/ocaml/Nullable.cmt +lib/ocaml/Nullable.cmti +lib/ocaml/Nullable.res +lib/ocaml/Nullable.resi lib/ocaml/Obj.cmi lib/ocaml/Obj.cmj lib/ocaml/Obj.cmt lib/ocaml/Obj.res +lib/ocaml/Object.cmi +lib/ocaml/Object.cmj +lib/ocaml/Object.cmt +lib/ocaml/Object.res +lib/ocaml/Option.cmi +lib/ocaml/Option.cmj +lib/ocaml/Option.cmt +lib/ocaml/Option.cmti +lib/ocaml/Option.res +lib/ocaml/Option.resi +lib/ocaml/Ordering.cmi +lib/ocaml/Ordering.cmj +lib/ocaml/Ordering.cmt +lib/ocaml/Ordering.res lib/ocaml/Pervasives.cmi lib/ocaml/Pervasives.cmj lib/ocaml/Pervasives.cmt @@ -851,16 +1117,74 @@ lib/ocaml/Primitive_util.cmi lib/ocaml/Primitive_util.cmj lib/ocaml/Primitive_util.cmt lib/ocaml/Primitive_util.res +lib/ocaml/Promise.cmi +lib/ocaml/Promise.cmj +lib/ocaml/Promise.cmt +lib/ocaml/Promise.cmti +lib/ocaml/Promise.res +lib/ocaml/Promise.resi +lib/ocaml/RegExp.cmi +lib/ocaml/RegExp.cmj +lib/ocaml/RegExp.cmt +lib/ocaml/RegExp.cmti +lib/ocaml/RegExp.res +lib/ocaml/RegExp.resi +lib/ocaml/Result.cmi +lib/ocaml/Result.cmj +lib/ocaml/Result.cmt +lib/ocaml/Result.cmti +lib/ocaml/Result.res +lib/ocaml/Result.resi lib/ocaml/Set.cmi lib/ocaml/Set.cmj lib/ocaml/Set.cmt +lib/ocaml/Set.cmti lib/ocaml/Set.res +lib/ocaml/Set.resi lib/ocaml/String.cmi lib/ocaml/String.cmj lib/ocaml/String.cmt lib/ocaml/String.cmti lib/ocaml/String.res lib/ocaml/String.resi +lib/ocaml/Symbol.cmi +lib/ocaml/Symbol.cmj +lib/ocaml/Symbol.cmt +lib/ocaml/Symbol.res +lib/ocaml/Type.cmi +lib/ocaml/Type.cmj +lib/ocaml/Type.cmt +lib/ocaml/Type.cmti +lib/ocaml/Type.res +lib/ocaml/Type.resi +lib/ocaml/TypedArray.cmi +lib/ocaml/TypedArray.cmj +lib/ocaml/TypedArray.cmt +lib/ocaml/TypedArray.res +lib/ocaml/Uint16Array.cmi +lib/ocaml/Uint16Array.cmj +lib/ocaml/Uint16Array.cmt +lib/ocaml/Uint16Array.res +lib/ocaml/Uint32Array.cmi +lib/ocaml/Uint32Array.cmj +lib/ocaml/Uint32Array.cmt +lib/ocaml/Uint32Array.res +lib/ocaml/Uint8Array.cmi +lib/ocaml/Uint8Array.cmj +lib/ocaml/Uint8Array.cmt +lib/ocaml/Uint8Array.res +lib/ocaml/Uint8ClampedArray.cmi +lib/ocaml/Uint8ClampedArray.cmj +lib/ocaml/Uint8ClampedArray.cmt +lib/ocaml/Uint8ClampedArray.res +lib/ocaml/WeakMap.cmi +lib/ocaml/WeakMap.cmj +lib/ocaml/WeakMap.cmt +lib/ocaml/WeakMap.res +lib/ocaml/WeakSet.cmi +lib/ocaml/WeakSet.cmj +lib/ocaml/WeakSet.cmt +lib/ocaml/WeakSet.res linux/bsb_helper.exe linux/bsc.exe linux/ninja.exe diff --git a/packages/playground-bundling/package-lock.json b/packages/playground-bundling/package-lock.json index 6d7f57dac6..85a1ed5159 100644 --- a/packages/playground-bundling/package-lock.json +++ b/packages/playground-bundling/package-lock.json @@ -9,18 +9,9 @@ "version": "1.0.0", "license": "ISC", "dependencies": { - "@rescript/core": "^1.5.2", "@rescript/react": "^0.13.0" } }, - "node_modules/@rescript/core": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/@rescript/core/-/core-1.5.2.tgz", - "integrity": "sha512-VWRFHrQu8hWnd9Y9LYZ8kig2urybhZlDVGy5u50bqf2WCRAeysBIfxK8eN4VlpQT38igMo0/uLX1KSpwCVMYGw==", - "peerDependencies": { - "rescript": "^11.1.0-rc.7" - } - }, "node_modules/@rescript/react": { "version": "0.13.0", "resolved": "https://registry.npmjs.org/@rescript/react/-/react-0.13.0.tgz", @@ -73,21 +64,6 @@ "react": "^18.2.0" } }, - "node_modules/rescript": { - "version": "11.1.1", - "resolved": "https://registry.npmjs.org/rescript/-/rescript-11.1.1.tgz", - "integrity": "sha512-FMELeoiR1n3LzBdBt+k7U4l0vsz5Xh0HBSHf+0NhyhzZkMRLkEKEDNrcqZc6RIux9bxmxoO+zEa9qFM01VOXAw==", - "hasInstallScript": true, - "peer": true, - "bin": { - "bsc": "bsc", - "bstracing": "lib/bstracing", - "rescript": "rescript" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/scheduler": { "version": "0.23.0", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", @@ -99,12 +75,6 @@ } }, "dependencies": { - "@rescript/core": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/@rescript/core/-/core-1.5.2.tgz", - "integrity": "sha512-VWRFHrQu8hWnd9Y9LYZ8kig2urybhZlDVGy5u50bqf2WCRAeysBIfxK8eN4VlpQT38igMo0/uLX1KSpwCVMYGw==", - "requires": {} - }, "@rescript/react": { "version": "0.13.0", "resolved": "https://registry.npmjs.org/@rescript/react/-/react-0.13.0.tgz", @@ -145,12 +115,6 @@ "scheduler": "^0.23.0" } }, - "rescript": { - "version": "11.1.1", - "resolved": "https://registry.npmjs.org/rescript/-/rescript-11.1.1.tgz", - "integrity": "sha512-FMELeoiR1n3LzBdBt+k7U4l0vsz5Xh0HBSHf+0NhyhzZkMRLkEKEDNrcqZc6RIux9bxmxoO+zEa9qFM01VOXAw==", - "peer": true - }, "scheduler": { "version": "0.23.0", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", diff --git a/packages/playground-bundling/package.json b/packages/playground-bundling/package.json index bdc31fb0df..59780359ca 100644 --- a/packages/playground-bundling/package.json +++ b/packages/playground-bundling/package.json @@ -11,7 +11,6 @@ "author": "", "license": "ISC", "dependencies": { - "@rescript/core": "^1.5.2", "@rescript/react": "^0.13.0" } } diff --git a/packages/playground-bundling/rescript.json b/packages/playground-bundling/rescript.json index bb00f330c9..5f53495101 100644 --- a/packages/playground-bundling/rescript.json +++ b/packages/playground-bundling/rescript.json @@ -1,7 +1,7 @@ { "name": "playground", "version": "0.1.0", - "bs-dependencies": ["@rescript/react", "@rescript/core"], + "bs-dependencies": ["@rescript/react"], "package-specs": { "module": "esmodule", "in-source": false diff --git a/playground/playground_test.js b/playground/playground_test.js index 62fefcc180..98807109cf 100644 --- a/playground/playground_test.js +++ b/playground/playground_test.js @@ -1,12 +1,9 @@ require("./compiler.js") require("./packages/compiler-builtins/cmij.js") require("./packages/@rescript/react/cmij.js") -require("./packages/@rescript/core/cmij.js") let compiler = rescript_compiler.make() -compiler.setOpenModules(["RescriptCore"]) - let result = compiler.rescript.compile(` @@jsxConfig({ version: 4, mode: "automatic" }) diff --git a/playground/upload_bundle.sh b/playground/upload_bundle.sh index 99a9c64593..135b0ba29f 100755 --- a/playground/upload_bundle.sh +++ b/playground/upload_bundle.sh @@ -29,7 +29,7 @@ if [ ! -f "${NETRC_FILE}" ]; then echo "machine ${KEYCDN_SRV} login $KEYCDN_USER password $KEYCDN_PASSWORD" > "${NETRC_FILE}" fi -PACKAGES=("compiler-builtins" "@rescript/react" "@rescript/core") +PACKAGES=("compiler-builtins" "@rescript/react") echo "Uploading compiler.js file..." curl --ftp-create-dirs -T "${SCRIPT_DIR}/compiler.js" --ssl --netrc-file $NETRC_FILE ftp://${KEYCDN_SRV}/v${VERSION}/compiler.js diff --git a/runtime/Array.res b/runtime/Array.res index 6339770b3a..23ff2dc7b1 100644 --- a/runtime/Array.res +++ b/runtime/Array.res @@ -1,383 +1,269 @@ -// FIXME: -// This exists for compatibility reason. -// Move this into Pervasives or Core - -// Caution: `Array.get` is implicitly used by `array[idx]` syntax -external get: (array<'a>, int) => 'a = "%array_safe_get" - -// Caution: `Array.set` is implicitly used by `array[idx]` syntax -external set: (array<'a>, int, 'a) => unit = "%array_safe_set" - -// Below is all deprecated and should be removed in v13 - -external length: array<'a> => int = "%array_length" +@new external makeUninitializedUnsafe: int => array<'a> = "Array" +@set external truncateToLengthUnsafe: (array<'a>, int) => unit = "length" +external getUnsafe: (array<'a>, int) => 'a = "%array_unsafe_get" +external setUnsafe: (array<'a>, int, 'a) => unit = "%array_unsafe_set" external unsafe_get: (array<'a>, int) => 'a = "%array_unsafe_get" -external unsafe_set: (array<'a>, int, 'a) => unit = "%array_unsafe_set" - -let init: (int, int => 'a) => array<'a> = %raw(`(length, f) => Array.from({ length }, f)`) - -let make = (len, x) => init(len, _ => x) - -@send external slice: (array<'a>, int, int) => array<'a> = "slice" -let unsafe_sub = (array, offset, length) => array->slice(offset, offset + length) - -@send external concat: (array<'a>, array<'a>) => array<'a> = "concat" -@send external append_prim: (array<'a>, array<'a>) => array<'a> = "concat" - -let concat = list => { - List.fold_left((arr1, arr2) => arr1->concat(arr2), [], list) -} - -let unsafe_blit = (srcArray, srcOffset, destArray, destOffset, len) => { - for i in 0 to len - 1 { - destArray->unsafe_set(destOffset + i, srcArray->unsafe_get(srcOffset + i)) - } -} - -let create_float = len => make(len, 0.0) +@val external fromIterator: Iterator.t<'a> => array<'a> = "Array.from" +@val external fromArrayLike: Js.Array2.array_like<'a> => array<'a> = "Array.from" +@val +external fromArrayLikeWithMap: (Js.Array2.array_like<'a>, 'a => 'b) => array<'b> = "Array.from" -let make_matrix = (sx, sy, init) => { - let res = make(sx, []) - for x in 0 to pred(sx) { - unsafe_set(res, x, make(sy, init)) - } - res -} +@send external fillAll: (array<'a>, 'a) => unit = "fill" -@send external copy: array<'a> => array<'a> = "slice" +@send external fillToEnd: (array<'a>, 'a, ~start: int) => unit = "fill" -let append = (a1, a2) => { - let l1 = length(a1) - if l1 == 0 { - copy(a2) - } else if length(a2) == 0 { - unsafe_sub(a1, 0, l1) - } else { - append_prim(a1, a2) - } -} +@send external fill: (array<'a>, 'a, ~start: int, ~end: int) => unit = "fill" -let sub = (a, ofs, len) => - if ofs < 0 || (len < 0 || ofs > length(a) - len) { - invalid_arg("Array.sub") +let make = (~length, x) => + if length <= 0 { + [] } else { - unsafe_sub(a, ofs, len) + let arr = makeUninitializedUnsafe(length) + arr->fillAll(x) + arr } -let fill = (a, ofs, len, v) => - if ofs < 0 || (len < 0 || ofs > length(a) - len) { - invalid_arg("Array.fill") +let fromInitializer = (~length, f) => + if length <= 0 { + [] } else { - for i in ofs to ofs + len - 1 { - unsafe_set(a, i, v) + let arr = makeUninitializedUnsafe(length) + for i in 0 to length - 1 { + arr->setUnsafe(i, f(i)) } + arr } -let blit = (a1, ofs1, a2, ofs2, len) => - if len < 0 || (ofs1 < 0 || (ofs1 > length(a1) - len || (ofs2 < 0 || ofs2 > length(a2) - len))) { - invalid_arg("Array.blit") - } else { - unsafe_blit(a1, ofs1, a2, ofs2, len) - } +@val external isArray: 'a => bool = "Array.isArray" -let iter = (f, a) => - for i in 0 to length(a) - 1 { - f(unsafe_get(a, i)) - } +@get external length: array<'a> => int = "length" -let iter2 = (f, a, b) => - if length(a) != length(b) { - invalid_arg("Array.iter2: arrays must have the same length") +let rec equalFromIndex = (a, b, i, eq, len) => + if i === len { + true + } else if eq(a->getUnsafe(i), b->getUnsafe(i)) { + equalFromIndex(a, b, i + 1, eq, len) } else { - for i in 0 to length(a) - 1 { - f(unsafe_get(a, i), unsafe_get(b, i)) - } + false } -let map = (f, a) => { - let l = length(a) - if l == 0 { - [] +let equal = (a, b, eq) => { + let len = a->length + if len === b->length { + equalFromIndex(a, b, 0, eq, len) } else { - let r = make(l, f(unsafe_get(a, 0))) - for i in 1 to l - 1 { - unsafe_set(r, i, f(unsafe_get(a, i))) - } - r + false } } -let map2 = (f, a, b) => { - let la = length(a) - let lb = length(b) - if la != lb { - invalid_arg("Array.map2: arrays must have the same length") - } else if la == 0 { - [] +let rec compareFromIndex = (a, b, i, cmp, len) => + if i === len { + Ordering.equal } else { - let r = make(la, f(unsafe_get(a, 0), unsafe_get(b, 0))) - for i in 1 to la - 1 { - unsafe_set(r, i, f(unsafe_get(a, i), unsafe_get(b, i))) + let c = cmp(a->getUnsafe(i), b->getUnsafe(i)) + if c == Ordering.equal { + compareFromIndex(a, b, i + 1, cmp, len) + } else { + c } - r } + +let compare = (a, b, cmp) => { + let lenA = a->length + let lenB = b->length + lenA < lenB + ? Ordering.less + : lenA > lenB + ? Ordering.greater + : compareFromIndex(a, b, 0, cmp, lenA) } -let iteri = (f, a) => - for i in 0 to length(a) - 1 { - f(i, unsafe_get(a, i)) - } +@send external copyAllWithin: (array<'a>, ~target: int) => array<'a> = "copyWithin" -let mapi = (f, a) => { - let l = length(a) - if l == 0 { - [] - } else { - let r = make(l, f(0, unsafe_get(a, 0))) - for i in 1 to l - 1 { - unsafe_set(r, i, f(i, unsafe_get(a, i))) - } - r - } -} +@send +external copyWithinToEnd: (array<'a>, ~target: int, ~start: int) => array<'a> = "copyWithin" -let to_list = a => { - let rec tolist = (i, res) => - if i < 0 { - res - } else { - tolist(i - 1, list{unsafe_get(a, i), ...res}) - } - tolist(length(a) - 1, list{}) -} +@send +external copyWithin: (array<'a>, ~target: int, ~start: int, ~end: int) => array<'a> = "copyWithin" -/* Cannot use List.length here because the List module depends on Array. */ -let rec list_length = (accu, param) => - switch param { - | list{} => accu - | list{_, ...t} => list_length(succ(accu), t) - } +@send external pop: array<'a> => option<'a> = "pop" -let of_list = param => - switch param { - | list{} => [] - | list{hd, ...tl} as l => - let a = make(list_length(0, l), hd) - let rec fill = (i, param) => - switch param { - | list{} => a - | list{hd, ...tl} => - unsafe_set(a, i, hd) - fill(i + 1, tl) - } - fill(1, tl) - } +@send external push: (array<'a>, 'a) => unit = "push" -let fold_left = (f, x, a) => { - let r = ref(x) - for i in 0 to length(a) - 1 { - r := f(r.contents, unsafe_get(a, i)) - } - r.contents -} +@variadic @send external pushMany: (array<'a>, array<'a>) => unit = "push" -let fold_right = (f, a, x) => { - let r = ref(x) - for i in length(a) - 1 downto 0 { - r := f(unsafe_get(a, i), r.contents) - } - r.contents -} +@send external reverse: array<'a> => unit = "reverse" +@send external toReversed: array<'a> => array<'a> = "toReversed" -let exists = (p, a) => { - let n = length(a) - let rec loop = i => - if i == n { - false - } else if p(unsafe_get(a, i)) { - true - } else { - loop(succ(i)) - } - loop(0) -} +@send external shift: array<'a> => option<'a> = "shift" -let for_all = (p, a) => { - let n = length(a) - let rec loop = i => - if i == n { - true - } else if p(unsafe_get(a, i)) { - loop(succ(i)) - } else { - false - } - loop(0) -} +@variadic @send +external splice: (array<'a>, ~start: int, ~remove: int, ~insert: array<'a>) => unit = "splice" +@variadic @send +external toSpliced: (array<'a>, ~start: int, ~remove: int, ~insert: array<'a>) => array<'a> = + "toSpliced" -let mem = (x, a) => { - let n = length(a) - let rec loop = i => - if i == n { - false - } else if compare(unsafe_get(a, i), x) == 0 { - true - } else { - loop(succ(i)) - } - loop(0) -} +@send external with: (array<'a>, int, 'a) => array<'a> = "with" -let memq = (x, a) => { - let n = length(a) - let rec loop = i => - if i == n { - false - } else if x === unsafe_get(a, i) { - true - } else { - loop(succ(i)) - } - loop(0) -} +@send external unshift: (array<'a>, 'a) => unit = "unshift" -exception Bottom(int) -let sort = (cmp, a) => { - let maxson = (l, i) => { - let i31 = i + i + i + 1 - let x = ref(i31) - if i31 + 2 < l { - if cmp(get(a, i31), get(a, i31 + 1)) < 0 { - x := i31 + 1 - } - if cmp(get(a, x.contents), get(a, i31 + 2)) < 0 { - x := i31 + 2 - } - x.contents - } else if i31 + 1 < l && cmp(get(a, i31), get(a, i31 + 1)) < 0 { - i31 + 1 - } else if i31 < l { - i31 - } else { - raise(Bottom(i)) - } +@variadic @send external unshiftMany: (array<'a>, array<'a>) => unit = "unshift" + +@send external concat: (array<'a>, array<'a>) => array<'a> = "concat" +@variadic @send external concatMany: (array<'a>, array>) => array<'a> = "concat" + +@send external flat: array> => array<'a> = "flat" + +@send external includes: (array<'a>, 'a) => bool = "includes" + +@send external indexOf: (array<'a>, 'a) => int = "indexOf" +let indexOfOpt = (arr, item) => + switch arr->indexOf(item) { + | -1 => None + | index => Some(index) } +@send external indexOfFrom: (array<'a>, 'a, int) => int = "indexOf" - let rec trickledown = (l, i, e) => { - let j = maxson(l, i) - if cmp(get(a, j), e) > 0 { - set(a, i, get(a, j)) - trickledown(l, j, e) - } else { - set(a, i, e) - } +@send external join: (array, string) => string = "join" + +@deprecated("Use `join` instead") @send +external joinWith: (array, string) => string = "join" + +@send external joinUnsafe: (array<'a>, string) => string = "join" + +@deprecated("Use `joinUnsafe` instead") @send +external joinWithUnsafe: (array<'a>, string) => string = "join" + +@send external lastIndexOf: (array<'a>, 'a) => int = "lastIndexOf" +let lastIndexOfOpt = (arr, item) => + switch arr->lastIndexOf(item) { + | -1 => None + | index => Some(index) } +@send external lastIndexOfFrom: (array<'a>, 'a, int) => int = "lastIndexOf" - let trickle = (l, i, e) => - try trickledown(l, i, e) catch { - | Bottom(i) => set(a, i, e) - } - let rec bubbledown = (l, i) => { - let j = maxson(l, i) - set(a, i, get(a, j)) - bubbledown(l, j) +@send external slice: (array<'a>, ~start: int, ~end: int) => array<'a> = "slice" +@send external sliceToEnd: (array<'a>, ~start: int) => array<'a> = "slice" +@send external copy: array<'a> => array<'a> = "slice" + +@send external sort: (array<'a>, ('a, 'a) => Ordering.t) => unit = "sort" +@send external toSorted: (array<'a>, ('a, 'a) => Ordering.t) => array<'a> = "toSorted" + +@send external toString: array<'a> => string = "toString" +@send external toLocaleString: array<'a> => string = "toLocaleString" + +@send external every: (array<'a>, 'a => bool) => bool = "every" +@send external everyWithIndex: (array<'a>, ('a, int) => bool) => bool = "every" + +@send external filter: (array<'a>, 'a => bool) => array<'a> = "filter" +@send external filterWithIndex: (array<'a>, ('a, int) => bool) => array<'a> = "filter" + +@send external find: (array<'a>, 'a => bool) => option<'a> = "find" +@send external findWithIndex: (array<'a>, ('a, int) => bool) => option<'a> = "find" + +@send external findIndex: (array<'a>, 'a => bool) => int = "findIndex" +@send external findIndexWithIndex: (array<'a>, ('a, int) => bool) => int = "findIndex" + +@send external forEach: (array<'a>, 'a => unit) => unit = "forEach" +@send external forEachWithIndex: (array<'a>, ('a, int) => unit) => unit = "forEach" + +@send external map: (array<'a>, 'a => 'b) => array<'b> = "map" +@send external mapWithIndex: (array<'a>, ('a, int) => 'b) => array<'b> = "map" + +@send external reduce: (array<'b>, ('a, 'b) => 'a, 'a) => 'a = "reduce" +let reduce = (arr, init, f) => reduce(arr, f, init) +@send external reduceWithIndex: (array<'b>, ('a, 'b, int) => 'a, 'a) => 'a = "reduce" +let reduceWithIndex = (arr, init, f) => reduceWithIndex(arr, f, init) +@send +external reduceRight: (array<'b>, ('a, 'b) => 'a, 'a) => 'a = "reduceRight" +let reduceRight = (arr, init, f) => reduceRight(arr, f, init) +@send +external reduceRightWithIndex: (array<'b>, ('a, 'b, int) => 'a, 'a) => 'a = "reduceRight" +let reduceRightWithIndex = (arr, init, f) => reduceRightWithIndex(arr, f, init) + +@send external some: (array<'a>, 'a => bool) => bool = "some" +@send external someWithIndex: (array<'a>, ('a, int) => bool) => bool = "some" + +@get_index external get: (array<'a>, int) => option<'a> = "" +@set_index external set: (array<'a>, int, 'a) => unit = "" + +@get_index external getSymbol: (array<'a>, Symbol.t) => option<'b> = "" +@get_index external getSymbolUnsafe: (array<'a>, Symbol.t) => 'b = "" +@set_index external setSymbol: (array<'a>, Symbol.t, 'b) => unit = "" + +let findIndexOpt = (array: array<'a>, finder: 'a => bool): option => + switch findIndex(array, finder) { + | -1 => None + | index => Some(index) } - let bubble = (l, i) => - try bubbledown(l, i) catch { - | Bottom(i) => i - } - let rec trickleup = (i, e) => { - let father = (i - 1) / 3 - assert(i != father) - if cmp(get(a, father), e) < 0 { - set(a, i, get(a, father)) - if father > 0 { - trickleup(father, e) - } else { - set(a, 0, e) - } - } else { - set(a, i, e) - } +let swapUnsafe = (xs, i, j) => { + let tmp = getUnsafe(xs, i) + setUnsafe(xs, i, getUnsafe(xs, j)) + setUnsafe(xs, j, tmp) +} + +module M = { + @val external floor: float => float = "Math.floor" + @val external random: unit => float = "Math.random" + external fromFloat: float => int = "%intoffloat" + external toFloat: int => float = "%identity" + + let random_int: (int, int) => int = (min, max) => + floor(random() *. toFloat(max - min))->fromFloat + min +} + +let shuffle = xs => { + let len = length(xs) + for i in 0 to len - 1 { + swapUnsafe(xs, i, M.random_int(i, len)) /* [i,len) */ } +} +let toShuffled = xs => { + let result = copy(xs) + shuffle(result) + result +} + +let filterMap = (a, f) => { let l = length(a) - for i in (l + 1) / 3 - 1 downto 0 { - trickle(l, i, get(a, i)) - } - for i in l - 1 downto 2 { - let e = get(a, i) - set(a, i, get(a, 0)) - trickleup(bubble(i, 0), e) - } - if l > 1 { - let e = get(a, 1) - set(a, 1, get(a, 0)) - set(a, 0, e) + let r = makeUninitializedUnsafe(l) + let j = ref(0) + for i in 0 to l - 1 { + let v = getUnsafe(a, i) + switch f(v) { + | None => () + | Some(v) => + setUnsafe(r, j.contents, v) + j.contents = j.contents + 1 + } } + truncateToLengthUnsafe(r, j.contents) + r } -let cutoff = 5 -let stable_sort = (cmp, a) => { - let merge = (src1ofs, src1len, src2, src2ofs, src2len, dst, dstofs) => { - let src1r = src1ofs + src1len and src2r = src2ofs + src2len - let rec loop = (i1, s1, i2, s2, d) => - if cmp(s1, s2) <= 0 { - set(dst, d, s1) - let i1 = i1 + 1 - if i1 < src1r { - loop(i1, get(a, i1), i2, s2, d + 1) - } else { - blit(src2, i2, dst, d + 1, src2r - i2) - } - } else { - set(dst, d, s2) - let i2 = i2 + 1 - if i2 < src2r { - loop(i1, s1, i2, get(src2, i2), d + 1) - } else { - blit(a, i1, dst, d + 1, src1r - i1) - } - } - loop(src1ofs, get(a, src1ofs), src2ofs, get(src2, src2ofs), dstofs) - } +let keepSome = filterMap(_, x => x) - let isortto = (srcofs, dst, dstofs, len) => - for i in 0 to len - 1 { - let e = get(a, srcofs + i) - let j = ref(dstofs + i - 1) - while j.contents >= dstofs && cmp(get(dst, j.contents), e) > 0 { - set(dst, j.contents + 1, get(dst, j.contents)) - decr(j) - } - set(dst, j.contents + 1, e) - } +@send external flatMap: (array<'a>, 'a => array<'b>) => array<'b> = "flatMap" +@send external flatMapWithIndex: (array<'a>, ('a, int) => array<'b>) => array<'b> = "flatMap" - let rec sortto = (srcofs, dst, dstofs, len) => - if len <= cutoff { - isortto(srcofs, dst, dstofs, len) +let findMap = (arr, f) => { + let rec loop = i => + if i == arr->length { + None } else { - let l1 = len / 2 - let l2 = len - l1 - sortto(srcofs + l1, dst, dstofs + l1, l2) - sortto(srcofs, a, srcofs + l2, l1) - merge(srcofs + l2, l1, dst, dstofs + l1, l2, dst, dstofs) + switch f(getUnsafe(arr, i)) { + | None => loop(i + 1) + | Some(_) as r => r + } } - let l = length(a) - if l <= cutoff { - isortto(0, a, 0, l) - } else { - let l1 = l / 2 - let l2 = l - l1 - let t = make(l2, get(a, 0)) - sortto(l1, t, 0, l2) - sortto(0, a, l2, l1) - merge(l2, l1, t, 0, l2, a, 0) - } + loop(0) } -let fast_sort = stable_sort +@send external at: (array<'a>, int) => option<'a> = "at" + +let last = a => a->get(a->length - 1) diff --git a/runtime/Array.resi b/runtime/Array.resi index 74a7c24724..8b57906b27 100644 --- a/runtime/Array.resi +++ b/runtime/Array.resi @@ -1,249 +1,1089 @@ -// FIXME: -// This exists for compatibility reason. -// Move this into Pervasives or Core - -// Caution: `Array.get` is implicitly used by `array[idx]` syntax -external get: (array<'a>, int) => 'a = "%array_safe_get" - -// Caution: `Array.set` is implicitly used by `array[idx]` syntax -external set: (array<'a>, int, 'a) => unit = "%array_safe_set" - -// Below is all deprecated and should be removed in v13 - -/** Return the length (number of elements) of the given array. */ -@deprecated("Use Core instead. This will be removed in v13") -external length: array<'a> => int = "%array_length" - -/** [Array.make n x] returns a fresh array of length [n], - initialized with [x]. - All the elements of this new array are initially - physically equal to [x] (in the sense of the [==] predicate). - Consequently, if [x] is mutable, it is shared among all elements - of the array, and modifying [x] through one of the array entries - will modify all other entries at the same time. - - Raise [Invalid_argument] if [n < 0] or [n > Sys.max_array_length]. - If the value of [x] is a floating-point number, then the maximum - size is only [Sys.max_array_length / 2].*/ -@deprecated("Use Core instead. This will be removed in v13") -let make: (int, 'a) => array<'a> - -/** [Array.create_float n] returns a fresh float array of length [n], - with uninitialized data. - @since 4.03 */ -@deprecated("Use Core instead. This will be removed in v13") -let create_float: int => array - -/** [Array.init n f] returns a fresh array of length [n], - with element number [i] initialized to the result of [f i]. - In other terms, [Array.init n f] tabulates the results of [f] - applied to the integers [0] to [n-1]. - - Raise [Invalid_argument] if [n < 0] or [n > Sys.max_array_length]. - If the return type of [f] is [float], then the maximum - size is only [Sys.max_array_length / 2].*/ -@deprecated("Use Core instead. This will be removed in v13") -let init: (int, int => 'a) => array<'a> - -/** [Array.make_matrix dimx dimy e] returns a two-dimensional array - (an array of arrays) with first dimension [dimx] and - second dimension [dimy]. All the elements of this new matrix - are initially physically equal to [e]. - The element ([x,y]) of a matrix [m] is accessed - with the notation [m.(x).(y)]. - - Raise [Invalid_argument] if [dimx] or [dimy] is negative or - greater than {!Sys.max_array_length}. - If the value of [e] is a floating-point number, then the maximum - size is only [Sys.max_array_length / 2]. */ -@deprecated("Use Core instead. This will be removed in v13") -let make_matrix: (int, int, 'a) => array> - -/** [Array.append v1 v2] returns a fresh array containing the - concatenation of the arrays [v1] and [v2]. */ -@deprecated("Use Core instead. This will be removed in v13") -let append: (array<'a>, array<'a>) => array<'a> - -/** Same as {!Array.append}, but concatenates a list of arrays. */ -@deprecated("Use Core instead. This will be removed in v13") -let concat: list> => array<'a> - -/** [Array.sub a start len] returns a fresh array of length [len], - containing the elements number [start] to [start + len - 1] - of array [a]. - - Raise [Invalid_argument "Array.sub"] if [start] and [len] do not - designate a valid subarray of [a]; that is, if - [start < 0], or [len < 0], or [start + len > Array.length a]. */ -@deprecated("Use Core instead. This will be removed in v13") -let sub: (array<'a>, int, int) => array<'a> - -/** [Array.copy a] returns a copy of [a], that is, a fresh array - containing the same elements as [a]. */ -@deprecated("Use Core instead. This will be removed in v13") +/** + `fromIterator(iterator)` + + Creates an array from the provided `iterator` + + ```res example + let map = Map.fromArray([("foo", 1), ("bar", 2)]) + + Array.fromIterator(map->Map.values) // [1, 2] + ``` + */ +@val +external fromIterator: Iterator.t<'a> => array<'a> = "Array.from" + +// TODO: Docs +@val external fromArrayLike: Js.Array2.array_like<'a> => array<'a> = "Array.from" + +// TODO: Docs +@val +external fromArrayLikeWithMap: (Js.Array2.array_like<'a>, 'a => 'b) => array<'b> = "Array.from" + +/** + `make(~length, init)` + + Creates an array of length `length` initialized with the value of `init`. + + ```res example + Array.make(~length=3, #apple) == [#apple, #apple, #apple] + ``` +*/ +let make: (~length: int, 'a) => array<'a> + +/** + `fromInitializer(~length, f)` + + Creates an array of length `length` initialized with the value returned from `f ` for each index. + + ```res example + Array.fromInitializer(~length=3, i => i + 3) == [3, 4, 5] + ``` +*/ +let fromInitializer: (~length: int, int => 'a) => array<'a> + +let equal: (array<'a>, array<'a>, ('a, 'a) => bool) => bool + +let compare: (array<'a>, array<'a>, ('a, 'a) => Ordering.t) => Ordering.t + +@val external isArray: 'a => bool = "Array.isArray" + +/** +`length(array)` returns the length of (i.e. number of items in) the array. + +See [`Array.length`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/length) on MDN. + +## Examples +```rescript +let someArray = ["hi", "hello"] + +Console.log(someArray->Array.length) // 2 +``` +*/ +@get +external length: array<'a> => int = "length" + +// TODO: Docs +@send external copyAllWithin: (array<'a>, ~target: int) => array<'a> = "copyWithin" + +// TODO: Docs +@send +external copyWithinToEnd: (array<'a>, ~target: int, ~start: int) => array<'a> = "copyWithin" + +// TODO: Docs +@send +external copyWithin: (array<'a>, ~target: int, ~start: int, ~end: int) => array<'a> = "copyWithin" + +/** +`fillAll(array, value)` fills the entire `array` with `value`. + +Beware this will *mutate* the array. + +See [`Array.fill`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/fill) on MDN. + +## Examples +```rescript +let myArray = [1, 2, 3, 4] +myArray->Array.fillAll(9) + +Console.log(myArray) // [9, 9, 9, 9] +``` +*/ +@send +external fillAll: (array<'a>, 'a) => unit = "fill" + +/** +`fillToEnd(array, value, ~start)` fills `array` with `value` from the `start` index. + +Beware this will *mutate* the array. + +See [`Array.fill`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/fill) on MDN. + +## Examples +```rescript +let myArray = [1, 2, 3, 4] +myArray->Array.fillToEnd(9, ~start=1) + +Console.log(myArray) // [1, 9, 9, 9] +``` +*/ +@send +external fillToEnd: (array<'a>, 'a, ~start: int) => unit = "fill" + +/** +`fill(array, value, ~start, ~end)` fills `array` with `value` from `start` to `end`. + +Beware this will *mutate* the array. + +See [`Array.fill`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/fill) on MDN. + +## Examples +```rescript +let myArray = [1, 2, 3, 4] +myArray->Array.fill(9, ~start=1, ~end=2) + +Console.log(myArray) // [1, 9, 9, 4] +``` +*/ +@send +external fill: (array<'a>, 'a, ~start: int, ~end: int) => unit = "fill" + +/** +`pop(array)` removes the last item from `array` and returns it. + +Beware this will *mutate* the array. + +See [`Array.pop`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/pop) on MDN. + +## Examples +```rescript +let someArray = ["hi", "hello"] +let lastItem = someArray->Array.pop // "hello" + +Console.log(someArray) // ["hi"]. Notice last item is gone. +``` +*/ +@send +external pop: array<'a> => option<'a> = "pop" + +/** +`push(array, item)` appends `item` to the end of `array`. + +Beware this will *mutate* the array. + +See [`Array.push`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/push) on MDN. + +## Examples +```rescript +let someArray = ["hi", "hello"] +someArray->Array.push("yay") + +Console.log(someArray) // ["hi", "hello", "yay"] +``` +*/ +@send +external push: (array<'a>, 'a) => unit = "push" + +/** +`pushMany(array, itemsArray)` appends many new items to the end of the array. + +Beware this will *mutate* the array. + +See [`Array.push`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/push) on MDN. + +## Examples +```rescript +let someArray = ["hi", "hello"] +someArray->Array.pushMany(["yay", "wehoo"]) + +Console.log(someArray) // ["hi", "hello", "yay", "wehoo"] +``` +*/ +@variadic +@send +external pushMany: (array<'a>, array<'a>) => unit = "push" + +/** +`reverse(array)` reverses the order of the items in `array`. + +Beware this will *mutate* the array. + +See [`Array.reverse`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reverse) on MDN. + +## Examples +```rescript +let someArray = ["hi", "hello"] +someArray->Array.reverse + +Console.log(someArray) // ["hello", "h1"] +``` +*/ +@send +external reverse: array<'a> => unit = "reverse" + +/** +`shift(array)` removes the first item in the array, and returns it. + +Beware this will *mutate* the array. + +See [`Array.shift`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/shift) on MDN. + +## Examples +```rescript +let someArray = ["hi", "hello"] +let lastItem = someArray->Array.shift // "hi" + +Console.log(someArray) // ["hello"]. Notice first item is gone. +``` +*/ +@send +external shift: array<'a> => option<'a> = "shift" + +/** +`toSorted(array, comparator)` returns a new, sorted array from `array`, using the `comparator` function. + +See [`Array.toSorted`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/toSorted) on MDN. + +## Examples +```rescript +let someArray = [3, 2, 1] +let sorted = someArray->Array.toSorted(Int.compare) + +Console.log(sorted) // [1, 2, 3] +Console.log(someArray) // [3, 2, 1]. Original unchanged +``` +*/ +@send +external toSorted: (array<'a>, ('a, 'a) => Ordering.t) => array<'a> = "toSorted" + +/** +`sort(array, comparator)` sorts `array` in-place using the `comparator` function. + +Beware this will *mutate* the array. + +See [`Array.sort`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort) on MDN. + +## Examples +```rescript +let someArray = [3, 2, 1] +someArray->Array.sort((a, b) => float(a - b)) + +Console.log(someArray) // [1, 2, 3] +``` +*/ +@send +external sort: (array<'a>, ('a, 'a) => Ordering.t) => unit = "sort" + +@variadic @send +external splice: (array<'a>, ~start: int, ~remove: int, ~insert: array<'a>) => unit = "splice" + +@variadic @send +external toSpliced: (array<'a>, ~start: int, ~remove: int, ~insert: array<'a>) => array<'a> = + "toSpliced" + +@send external with: (array<'a>, int, 'a) => array<'a> = "with" + +/** +`unshift(array, item)` inserts a new item at the start of the array. + +Beware this will *mutate* the array. + +See [`Array.unshift`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/unshift) on MDN. + +## Examples +```rescript +let someArray = ["hi", "hello"] +someArray->Array.unshift("yay") + +Console.log(someArray) // ["yay", "hi", "hello"] +``` +*/ +@send +external unshift: (array<'a>, 'a) => unit = "unshift" + +/** +`unshiftMany(array, itemsArray)` inserts many new items to the start of the array. + +Beware this will *mutate* the array. + +See [`Array.push`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/unshift) on MDN. + +## Examples +```rescript +let someArray = ["hi", "hello"] +someArray->Array.unshiftMany(["yay", "wehoo"]) + +Console.log(someArray) // ["yay", "wehoo", "hi", "hello"] +``` +*/ +@variadic +@send +external unshiftMany: (array<'a>, array<'a>) => unit = "unshift" + +/** +`concat(array1, array2)` concatenates the two arrays, creating a new array. + +See [`Array.concat`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/concat) on MDN. + +## Examples +```rescript +let array1 = ["hi", "hello"] +let array2 = ["yay", "wehoo"] + +let someArray = array1->Array.concat(array2) + +Console.log(someArray) // ["hi", "hello", "yay", "wehoo"] +``` +*/ +@send +external concat: (array<'a>, array<'a>) => array<'a> = "concat" + +/** +`concatMany(array1, arrays)` concatenates array1 with several other arrays, creating a new array. + +See [`Array.concat`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/concat) on MDN. + +## Examples +```rescript +let array1 = ["hi", "hello"] +let array2 = ["yay"] +let array3 = ["wehoo"] + +let someArray = array1->Array.concatMany([array2, array3]) + +Console.log(someArray) // ["hi", "hello", "yay", "wehoo"] +``` +*/ +@variadic +@send +external concatMany: (array<'a>, array>) => array<'a> = "concat" + +/** +`flat(arrays)` concatenates an array of arrays into a single array. + +See [`Array.flat`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/flat) on MDN. + +## Examples +```rescript +Console.log([[1], [2], [3, 4]]->Array.flat) // [1, 2, 3, 4] +``` +*/ +@send +external flat: array> => array<'a> = "flat" + +/** +`includes(array, item)` checks whether `array` includes `item`, by doing a [strict check for equality](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Strict_equality). + +See [`Array.includes`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/includes) on MDN. + +## Examples +```rescript +Console.log([1, 2]->Array.includes(1)) // true +Console.log([1, 2]->Array.includes(3)) // false +Console.log([{"language": "ReScript"}]->Array.includes({"language": "ReScript"})) // false, because of strict equality +``` +*/ +@send +external includes: (array<'a>, 'a) => bool = "includes" + +/** +`indexOf(array, item)` returns the index of the provided `item` in `array`. Uses [strict check for equality](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Strict_equality) when comparing items. + +Returns `-1` if the item doesn not exist. Check out `Array.indexOfOpt` for a version that returns `None` instead of `-1` if the item does not exist. + +See [`Array.indexOf`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf) on MDN. + +## Examples +```rescript +Console.log([1, 2]->Array.indexOf(2)) // 1 +Console.log([1, 2]->Array.indexOf(3)) // -1 +Console.log([{"language": "ReScript"}]->Array.indexOf({"language": "ReScript"})) // -1, because of strict equality +``` +*/ +@send +external indexOf: (array<'a>, 'a) => int = "indexOf" + +/** +`indexOfOpt(array, item)` returns an option of the index of the provided `item` in `array`. Uses [strict check for equality](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Strict_equality) when comparing items. + +See [`Array.indexOf`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf) on MDN. + +## Examples +```rescript +Console.log([1, 2]->Array.indexOfOpt(2)) // Some(1) +Console.log([1, 2]->Array.indexOfOpt(3)) // None +Console.log([{"language": "ReScript"}]->Array.indexOfOpt({"language": "ReScript"})) // None, because of strict equality +``` +*/ +let indexOfOpt: (array<'a>, 'a) => option +@send external indexOfFrom: (array<'a>, 'a, int) => int = "indexOf" + +/** +`join(array, separator)` produces a string where all items of `array` are printed, separated by `separator`. Array items must be strings, to join number or other arrays, use `joinUnsafe`. Under the hood this will run JavaScript's `toString` on all the array items. + +See [Array.join](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/join) + +## Examples +```rescript +let array = ["One", "Two", "Three"] + +Console.log(array->Array.join(" -- ")) // One -- Two -- Three +``` +*/ +@send +external join: (array, string) => string = "join" + +/** +`joinWith(array, separator)` produces a string where all items of `array` are printed, separated by `separator`. Array items must be strings, to join number or other arrays, use `joinWithUnsafe`. Under the hood this will run JavaScript's `toString` on all the array items. + +## Examples +```rescript +let array = ["One", "Two", "Three"] + +Console.log(array->Array.joinWith(" -- ")) // One -- Two -- Three +``` +*/ +@deprecated("Use `join` instead") +@send +external joinWith: (array, string) => string = "join" + +/** +`joinUnsafe(array, separator)` produces a string where all items of `array` are printed, separated by `separator`. Under the hood this will run JavaScript's `toString` on all the array items. + +See [Array.join](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/join) + +## Examples +```rescript +let array = [1, 2, 3] + +Console.log(array->Array.joinUnsafe(" -- ")) // 1 -- 2 -- 3 +``` +*/ +@send +external joinUnsafe: (array<'a>, string) => string = "join" + +/** +`joinWithUnsafe(array, separator)` produces a string where all items of `array` are printed, separated by `separator`. Under the hood this will run JavaScript's `toString` on all the array items. + +## Examples +```rescript +let array = [1, 2, 3] + +Console.log(array->Array.joinWithUnsafe(" -- ")) // 1 -- 2 -- 3 +``` +*/ +@deprecated("Use `joinUnsafe` instead") +@send +external joinWithUnsafe: (array<'a>, string) => string = "join" +@send external lastIndexOf: (array<'a>, 'a) => int = "lastIndexOf" +let lastIndexOfOpt: (array<'a>, 'a) => option +@send external lastIndexOfFrom: (array<'a>, 'a, int) => int = "lastIndexOf" + +/** +`slice(array, ~start, ~end)` creates a new array of items copied from `array` from `start` until (but not including) `end`. + +See [`Array.slice`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/slice) on MDN. + +## Examples +```rescript +let myArray = [1, 2, 3, 4] + +Console.log(myArray->Array.slice(~start=1, ~end=3)) // [2, 3] +``` +*/ +@send +external slice: (array<'a>, ~start: int, ~end: int) => array<'a> = "slice" + +/** +`sliceToEnd(array, start)` creates a new array from `array`, with all items from `array` starting from `start`. + +See [`Array.slice`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/slice) on MDN. + +## Examples +```rescript +let myArray = [1, 2, 3, 4] + +Console.log(myArray->Array.sliceToEnd(~start=1)) // [2, 3, 4] +``` +*/ +@send +external sliceToEnd: (array<'a>, ~start: int) => array<'a> = "slice" +/** +`copy(array)` makes a copy of the array with the items in it, but does not make copies of the items themselves. + +## Examples +```rescript +let myArray = [1, 2, 3] +let copyOfMyArray = myArray->Array.copy + +Console.log(copyOfMyArray) // [1, 2, 3] +Console.log(myArray === copyOfMyArray) // false +``` +*/ @send external copy: array<'a> => array<'a> = "slice" -/** [Array.fill a ofs len x] modifies the array [a] in place, - storing [x] in elements number [ofs] to [ofs + len - 1]. - - Raise [Invalid_argument "Array.fill"] if [ofs] and [len] do not - designate a valid subarray of [a]. */ -@deprecated("Use Core instead. This will be removed in v13") -let fill: (array<'a>, int, int, 'a) => unit - -/** [Array.blit v1 o1 v2 o2 len] copies [len] elements - from array [v1], starting at element number [o1], to array [v2], - starting at element number [o2]. It works correctly even if - [v1] and [v2] are the same array, and the source and - destination chunks overlap. - - Raise [Invalid_argument "Array.blit"] if [o1] and [len] do not - designate a valid subarray of [v1], or if [o2] and [len] do not - designate a valid subarray of [v2]. */ -@deprecated("Use Core instead. This will be removed in v13") -let blit: (array<'a>, int, array<'a>, int, int) => unit - -/** [Array.to_list a] returns the list of all the elements of [a]. */ -@deprecated("Use Core instead. This will be removed in v13") -let to_list: array<'a> => list<'a> - -/** [Array.of_list l] returns a fresh array containing the elements - of [l]. */ -@deprecated("Use Core instead. This will be removed in v13") -let of_list: list<'a> => array<'a> - -/* {1 Iterators} */ - -/** [Array.iter f a] applies function [f] in turn to all - the elements of [a]. It is equivalent to - [f a.(0); f a.(1); ...; f a.(Array.length a - 1); ()]. */ -@deprecated("Use Core instead. This will be removed in v13") -let iter: ('a => unit, array<'a>) => unit - -/** Same as {!Array.iter}, but the - function is applied with the index of the element as first argument, - and the element itself as second argument. */ -@deprecated("Use Core instead. This will be removed in v13") -let iteri: ((int, 'a) => unit, array<'a>) => unit - -/** [Array.map f a] applies function [f] to all the elements of [a], - and builds an array with the results returned by [f]: - [[| f a.(0); f a.(1); ...; f a.(Array.length a - 1) |]]. */ -@deprecated("Use Core instead. This will be removed in v13") -let map: ('a => 'b, array<'a>) => array<'b> - -/** Same as {!Array.map}, but the - function is applied to the index of the element as first argument, - and the element itself as second argument. */ -@deprecated("Use Core instead. This will be removed in v13") -let mapi: ((int, 'a) => 'b, array<'a>) => array<'b> - -/** [Array.fold_left f x a] computes - [f (... (f (f x a.(0)) a.(1)) ...) a.(n-1)], - where [n] is the length of the array [a]. */ -@deprecated("Use Core instead. This will be removed in v13") -let fold_left: (('a, 'b) => 'a, 'a, array<'b>) => 'a - -/** [Array.fold_right f a x] computes - [f a.(0) (f a.(1) ( ... (f a.(n-1) x) ...))], - where [n] is the length of the array [a]. */ -@deprecated("Use Core instead. This will be removed in v13") -let fold_right: (('b, 'a) => 'a, array<'b>, 'a) => 'a - -/* {1 Iterators on two arrays} */ - -/** [Array.iter2 f a b] applies function [f] to all the elements of [a] - and [b]. - Raise [Invalid_argument] if the arrays are not the same size. - @since 4.03.0 */ -@deprecated("Use Core instead. This will be removed in v13") -let iter2: (('a, 'b) => unit, array<'a>, array<'b>) => unit - -/** [Array.map2 f a b] applies function [f] to all the elements of [a] - and [b], and builds an array with the results returned by [f]: - [[| f a.(0) b.(0); ...; f a.(Array.length a - 1) b.(Array.length b - 1)|]]. - Raise [Invalid_argument] if the arrays are not the same size. - @since 4.03.0 */ -@deprecated("Use Core instead. This will be removed in v13") -let map2: (('a, 'b) => 'c, array<'a>, array<'b>) => array<'c> - -/* {1 Array scanning} */ - -/** [Array.for_all p [|a1; ...; an|]] checks if all elements of the array - satisfy the predicate [p]. That is, it returns - [(p a1) && (p a2) && ... && (p an)]. - @since 4.03.0 */ -@deprecated("Use Core instead. This will be removed in v13") -let for_all: ('a => bool, array<'a>) => bool - -/** [Array.exists p [|a1; ...; an|]] checks if at least one element of - the array satisfies the predicate [p]. That is, it returns - [(p a1) || (p a2) || ... || (p an)]. - @since 4.03.0 */ -@deprecated("Use Core instead. This will be removed in v13") -let exists: ('a => bool, array<'a>) => bool - -/** [mem a l] is true if and only if [a] is equal - to an element of [l]. - @since 4.03.0 */ -@deprecated("Use Core instead. This will be removed in v13") -let mem: ('a, array<'a>) => bool - -/** Same as {!Array.mem}, but uses physical equality instead of structural - equality to compare array elements. - @since 4.03.0 */ -@deprecated("Use Core instead. This will be removed in v13") -let memq: ('a, array<'a>) => bool - -/* {1 Sorting} */ - -/** Sort an array in increasing order according to a comparison - function. The comparison function must return 0 if its arguments - compare as equal, a positive integer if the first is greater, - and a negative integer if the first is smaller (see below for a - complete specification). For example, {!Pervasives.compare} is - a suitable comparison function, provided there are no floating-point - NaN values in the data. After calling [Array.sort], the - array is sorted in place in increasing order. - [Array.sort] is guaranteed to run in constant heap space - and (at most) logarithmic stack space. - - The current implementation uses Heap Sort. It runs in constant - stack space. - - Specification of the comparison function: - Let [a] be the array and [cmp] the comparison function. The following - must be true for all x, y, z in a : -- [cmp x y] > 0 if and only if [cmp y x] < 0 -- if [cmp x y] >= 0 and [cmp y z] >= 0 then [cmp x z] >= 0 - - When [Array.sort] returns, [a] contains the same elements as before, - reordered in such a way that for all i and j valid indices of [a] : -- [cmp a.(i) a.(j)] >= 0 if and only if i >= j -*/ -@deprecated("Use Core instead. This will be removed in v13") -let sort: (('a, 'a) => int, array<'a>) => unit - -/** Same as {!Array.sort}, but the sorting algorithm is stable (i.e. - elements that compare equal are kept in their original order) and - not guaranteed to run in constant heap space. - - The current implementation uses Merge Sort. It uses [n/2] - words of heap space, where [n] is the length of the array. - It is usually faster than the current implementation of {!Array.sort}. -*/ -@deprecated("Use Core instead. This will be removed in v13") -let stable_sort: (('a, 'a) => int, array<'a>) => unit - -/** Same as {!Array.sort} or {!Array.stable_sort}, whichever is faster - on typical input. -*/ -@deprecated("Use Core instead. This will be removed in v13") -let fast_sort: (('a, 'a) => int, array<'a>) => unit - -@deprecated("Use Core instead. This will be removed in v13") +/** +`toString(array)` stringifies `array` by running `toString` on all of the array elements and joining them with ",". + +See [`Array.toString`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/toString) on MDN. + +## Examples +```rescript +let array = [1, 2, 3, 4] + +Console.log(array->Array.toString) // "1,2,3,4" +``` +*/ +@send +external toString: array<'a> => string = "toString" + +@send external toLocaleString: array<'a> => string = "toLocaleString" + +/** +`every(array, predicate)` returns true if `predicate` returns true for all items in `array`. + +See [`Array.every`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/every) on MDN. + +## Examples +```rescript +let array = [1, 2, 3, 4] + +Console.log(array->Array.every(num => num <= 4)) // true +Console.log(array->Array.every(num => num === 1)) // false +``` +*/ +@send +external every: (array<'a>, 'a => bool) => bool = "every" + +/** +`everyWithIndex(array, checker)` returns true if all items in `array` returns true when running the provided `checker` function. + +See [`Array.every`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/every) on MDN. + +## Examples +```rescript +let array = [1, 2, 3, 4] + +Console.log(array->Array.everyWithIndex((num, index) => index < 2 && num <= 2)) // true +Console.log(array->Array.everyWithIndex((num, index) => index < 2 && num >= 2)) // false +``` +*/ +@send +external everyWithIndex: (array<'a>, ('a, int) => bool) => bool = "every" + +/** +`filter(array, checker)` returns a new array containing all elements from `array` for which the provided `checker` function returns true. + +See [`Array.filter`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter) on MDN. + +## Examples +```rescript +let array = [1, 2, 3, 4] + +Console.log(array->Array.filter(num => num > 2)) // [3, 4] +``` +*/ +@send +external filter: (array<'a>, 'a => bool) => array<'a> = "filter" + +/** +`filterWithIndex(array, checker)` returns a new array containing all elements from `array` for which the provided `checker` function returns true. + +See [`Array.filter`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter) on MDN. + +## Examples +```rescript +let array = [1, 2, 3, 4] + +Console.log(array->Array.filterWithIndex((num, index) => index === 0 || num === 2)) // [1, 2] +``` +*/ +@send +external filterWithIndex: (array<'a>, ('a, int) => bool) => array<'a> = "filter" + +/** +`find(array, checker)` returns the first element of `array` where the provided `checker` function returns true. + +See [`Array.find`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find) on MDN. + +## Examples +```rescript +type languages = ReScript | TypeScript | JavaScript + +let array = [ReScript, TypeScript, JavaScript] + +switch array->Array.find(item => item == ReScript) { +| None => Console.log("No item...") +| Some(_) => Console.log("Yay, ReScript!") +} +``` +*/ +@send +external find: (array<'a>, 'a => bool) => option<'a> = "find" + +/** +`findWithIndex(array, checker)` returns the first element of `array` where the provided `checker` function returns true. + +See [`Array.find`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find) on MDN. + +## Examples +```rescript +type languages = ReScript | TypeScript | JavaScript + +let array = [TypeScript, JavaScript, ReScript] + +switch array->Array.findWithIndex((item, index) => index > 1 && item == ReScript) { +| None => Console.log("No item...") +| Some(_) => Console.log("Yay, ReScript exists in a later position!") +} +``` +*/ +@send +external findWithIndex: (array<'a>, ('a, int) => bool) => option<'a> = "find" + +/** +`findIndex(array, checker)` returns the index of the first element of `array` where the provided `checker` function returns true. + +Returns `-1` if the item does not exist. Consider using `Array.findIndexOpt` if you want an option instead (where `-1` would be `None`). + +See [`Array.findIndex`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findIndex) on MDN. + +## Examples +```rescript +type languages = ReScript | TypeScript | JavaScript + +let array = [ReScript, JavaScript] + +Console.log(array->Array.findIndex(item => item == ReScript)) // 0 +Console.log(array->Array.findIndex(item => item == TypeScript)) // -1 +``` +*/ +@send +external findIndex: (array<'a>, 'a => bool) => int = "findIndex" + +/** +`findIndexWithIndex(array, checker)` returns the index of the first element of `array` where the provided `checker` function returns true. + +Returns `-1` if the item does not exist. Consider using `Array.findIndexOpt` if you want an option instead (where `-1` would be `None`). + +See [`Array.findIndex`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findIndex) on MDN. + +## Examples +```rescript +type languages = ReScript | TypeScript | JavaScript + +let array = [ReScript, JavaScript] + +let isReScriptFirst = array->Array.findIndexWithIndex((item, index) => index === 0 && item == ReScript) +let isTypeScriptFirst = array->Array.findIndexWithIndex((item, index) => index === 0 && item == TypeScript) + +Console.log(isReScriptFirst) // 0 +Console.log(isTypeScriptFirst) // -1 +``` +*/ +@send +external findIndexWithIndex: (array<'a>, ('a, int) => bool) => int = "findIndex" + +/** +`forEach(array, fn)` runs the provided `fn` on every element of `array`. + +See [`Array.forEach`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach) on MDN. + +## Examples +```rescript +let array = ["Hello", "Hi", "Good bye"] + +array->Array.forEach(item => { + Console.log(item) +}) +``` +*/ +@send +external forEach: (array<'a>, 'a => unit) => unit = "forEach" + +/** +`forEachWithIndex(array, fn)` runs the provided `fn` on every element of `array`. + +See [`Array.forEach`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach) on MDN. + +## Examples +```rescript +let array = ["Hello", "Hi", "Good bye"] + +array->Array.forEachWithIndex((item, index) => { + Console.log("At item " ++ Int.toString(index) ++ ": " ++ item) +}) +``` +*/ +@send +external forEachWithIndex: (array<'a>, ('a, int) => unit) => unit = "forEach" + +/** +`map(array, fn)` returns a new array with all elements from `array`, each element transformed using the provided `fn`. + +See [`Array.map`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map) on MDN. + +## Examples +```rescript +let array = ["Hello", "Hi", "Good bye"] +let mappedArray = array->Array.map(greeting => greeting ++ " to you") + +Console.log(mappedArray) // ["Hello to you", "Hi to you", "Good bye to you"] +``` +*/ +@send +external map: (array<'a>, 'a => 'b) => array<'b> = "map" + +/** +`mapWithIndex(array, fn)` returns a new array with all elements from `array`, each element transformed using the provided `fn`. + +See [`Array.map`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map) on MDN. + +## Examples +```rescript +let array = ["Hello", "Hi", "Good bye"] +let mappedArray = + array->Array.mapWithIndex((greeting, index) => + greeting ++ " at position " ++ Int.toString(index) + ) + +Console.log(mappedArray) // ["Hello at position 0", "Hi at position 1", "Good bye at position 2"] +``` +*/ +@send +external mapWithIndex: (array<'a>, ('a, int) => 'b) => array<'b> = "map" + +/** + `reduce(xs, init, fn)` + + Applies `fn` to each element of `xs` from beginning to end. Function `fn` has two parameters: the item from the list and an “accumulator”; which starts with a value of `init`. `reduce` returns the final value of the accumulator. + + ```res example + Array.reduce([2, 3, 4], 1, (a, b) => a + b) == 10 + + Array.reduce(["a", "b", "c", "d"], "", (a, b) => a ++ b) == "abcd" + ``` +*/ +let reduce: (array<'a>, 'b, ('b, 'a) => 'b) => 'b + +/** + `reduceWithIndex(x, init, fn)` + + Applies `fn` to each element of `xs` from beginning to end. Function `fn` has three parameters: the item from the array and an “accumulator”, which starts with a value of `init` and the index of each element. `reduceWithIndex` returns the final value of the accumulator. + + ```res example + Array.reduceWithIndex([1, 2, 3, 4], 0, (acc, x, i) => acc + x + i) == 16 + ``` +*/ +let reduceWithIndex: (array<'a>, 'b, ('b, 'a, int) => 'b) => 'b + +/** + `reduceRight(xs, init, fn)` + + Works like `Array.reduce`; except that function `fn` is applied to each item of `xs` from the last back to the first. + + ```res example + Array.reduceRight(["a", "b", "c", "d"], "", (a, b) => a ++ b) == "dcba" + ``` +*/ +let reduceRight: (array<'a>, 'b, ('b, 'a) => 'b) => 'b + +/** + `reduceRightWithIndex(xs, init, fn)` + + Like `reduceRight`, but with an additional index argument on the callback function. + + ```res example + Array.reduceRightWithIndex([1, 2, 3, 4], 0, (acc, x, i) => acc + x + i) == 16 + ``` +*/ +let reduceRightWithIndex: (array<'a>, 'b, ('b, 'a, int) => 'b) => 'b + +/** +`some(array, predicate)` returns true if `predicate` returns true for any element in `array`. + +See [`Array.some`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/some) on MDN. + +## Examples +```rescript +let array = ["Hello", "Hi", "Good bye"] + +Console.log(array->Array.some(greeting => greeting === "Hello")) // true +``` +*/ +@send +external some: (array<'a>, 'a => bool) => bool = "some" + +/** +`someWithIndex(array, checker)` returns true if running the provided `checker` function on any element in `array` returns true. + +See [`Array.some`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/some) on MDN. + +## Examples +```rescript +let array = ["Hello", "Hi", "Good bye"] + +Console.log(array->Array.someWithIndex((greeting, index) => greeting === "Hello" && index === 0)) // true +``` +*/ +@send +external someWithIndex: (array<'a>, ('a, int) => bool) => bool = "some" + +/** +`get(array, index)` returns the element at `index` of `array`. + +Returns `None` if the index does not exist in the array. Equivalent to doing `array[index]` in JavaScript. + +## Examples +```rescript +let array = ["Hello", "Hi", "Good bye"] + +array->Array.get(0) == Some("Hello") // true +array->Array.get(3) == None // true +``` +*/ +@get_index +external get: (array<'a>, int) => option<'a> = "" + +/** +`set(array, index, item)` sets the provided `item` at `index` of `array`. + +Beware this will *mutate* the array. + +## Examples +```rescript +let array = ["Hello", "Hi", "Good bye"] +array->Array.set(1, "Hello") + +Console.log(array[1]) // "Hello" +``` +*/ +@set_index +external set: (array<'a>, int, 'a) => unit = "" +@get_index external getSymbol: (array<'a>, Symbol.t) => option<'b> = "" +@get_index external getSymbolUnsafe: (array<'a>, Symbol.t) => 'b = "" +@set_index external setSymbol: (array<'a>, Symbol.t, 'b) => unit = "" + +/** +`getUnsafe(array, index)` returns the element at `index` of `array`. + +This is _unsafe_, meaning it will return `undefined` value if `index` does not exist in `array`. + +Use `Array.getUnsafe` only when you are sure the `index` exists (i.e. when using for-loop). + +## Examples +```rescript +let array = [1, 2, 3] +for index in 0 to array->Array.length - 1 { + let value = array->Array.getUnsafe(index) + Console.log(value) +} +``` +*/ +external getUnsafe: (array<'a>, int) => 'a = "%array_unsafe_get" + +/** +`unsafe_get(array, index)` returns the element at `index` of `array`. + +This is _unsafe_, meaning it will return `undefined` value if `index` does not exist in `array`. + +Use `Array.unsafe_get` only when you are sure the `index` exists (i.e. when using for-loop). + +## Examples +```rescript +let array = [1, 2, 3] +for index in 0 to array->Array.length - 1 { + let value = array->Array.unsafe_get(index) + Console.log(value) +} +``` +*/ +@deprecated("Use getUnsafe instead. This will be removed in v13") external unsafe_get: (array<'a>, int) => 'a = "%array_unsafe_get" -@deprecated("Use Core instead. This will be removed in v13") -external unsafe_set: (array<'a>, int, 'a) => unit = "%array_unsafe_set" +/** +`setUnsafe(array, index, item)` sets the provided `item` at `index` of `array`. + +Beware this will *mutate* the array, and is *unsafe*. + +## Examples +```rescript +let array = ["Hello", "Hi", "Good bye"] +array->Array.setUnsafe(1, "Hello") + +Console.log(array[1]) // "Hello" +``` +*/ +external setUnsafe: (array<'a>, int, 'a) => unit = "%array_unsafe_set" + +/** +`findIndexOpt(array, checker)` returns the index of the first element of `array` where the provided `checker` function returns true. + +Returns `None` if no item matches. + +See [`Array.findIndex`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findIndex) on MDN. + +## Examples +```rescript +type languages = ReScript | TypeScript | JavaScript + +let array = [ReScript, TypeScript, JavaScript] + +switch array->Array.findIndexOpt(item => item == ReScript) { +| None => Console.log("Ahh, no ReScript...") +| Some(index) => Console.log("Yay, ReScript at index " ++ Int.toString(index)) +} +``` +*/ +let findIndexOpt: (array<'a>, 'a => bool) => option + +/** +`toReversed(array)` creates a new array with all items from `array` in reversed order. + +See [`Array.toReversed`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/toReversed) on MDN. + +## Examples +```rescript +let someArray = ["hi", "hello"] +let reversed = someArray->Array.toReversed + +Console.log(reversed) // ["hello", "h1"] +Console.log(someArray) // ["h1", "hello"]. Original unchanged +``` +*/ +@send +external toReversed: array<'a> => array<'a> = "toReversed" + +/** +`filterMap(array, fn)` + +Calls `fn` for each element and returns a new array containing results of the `fn` calls which are not `None`. + +## Examples +```rescript +let array = ["Hello", "Hi", "Good bye"] + +Console.log( + array->Array.filterMap(item => + switch item { + | "Hello" => Some(item->String.length) + | _ => None + } + ), +) // [5] +``` +*/ +let filterMap: (array<'a>, 'a => option<'b>) => array<'b> + +/** + `keepSome(arr)` + + Returns a new array containing `value` for all elements that are `Some(value)` + and ignoring every value that is `None` + + ```res example + Array.keepSome([Some(1), None, Some(3)]) == [1, 3] + ``` +*/ +let keepSome: array> => array<'a> + +/** +`toShuffled(array)` returns a new array with all items in `array` in a random order. + +## Examples +```rescript +let array = ["Hello", "Hi", "Good bye"] +let shuffledArray = array->Array.toShuffled + +Console.log(shuffledArray) +``` +*/ +let toShuffled: array<'a> => array<'a> + +/** +`shuffle(array)` randomizes the position of all items in `array`. + +Beware this will *mutate* the array. + +## Examples +```rescript +let array = ["Hello", "Hi", "Good bye"] +array->Array.shuffle + +Console.log(array) +``` +*/ +let shuffle: array<'a> => unit + +/** +`flatMap(array, mapper)` returns a new array concatenating the arrays returned from running `mapper` on all items in `array`. + +## Examples +```rescript +type language = ReScript | TypeScript | JavaScript + +let array = [ReScript, TypeScript, JavaScript] + +Console.log( + array->Array.flatMap(item => + switch item { + | ReScript => [1, 2, 3] + | TypeScript => [4, 5, 6] + | JavaScript => [7, 8, 9] + } + ), +) +// [1, 2, 3, 4, 5, 6, 7, 8, 9] +``` +*/ +@send +external flatMap: (array<'a>, 'a => array<'b>) => array<'b> = "flatMap" + +/** +`flatMapWithIndex(array, mapper)` returns a new array concatenating the arrays returned from running `mapper` on all items in `array`. + +## Examples +```rescript +type language = ReScript | TypeScript | JavaScript + +let array = [ReScript, TypeScript, JavaScript] + +Console.log( + array->Array.flatMapWithIndex((item, index) => + switch item { + | ReScript => [index] + | TypeScript => [index, index + 1] + | JavaScript => [index, index + 1, index + 2] + } + ), +) +// [0, 1, 2, 2, 3, 4] +``` +*/ +@send +external flatMapWithIndex: (array<'a>, ('a, int) => array<'b>) => array<'b> = "flatMap" + +/** + `findMap(arr, fn)` + + Calls `fn` for each element and returns the first value from `fn` that is `Some(_)`. + Otherwise returns `None` + + ```res example + Array.findMap([1, 2, 3], n => mod(n, 2) == 0 ? Some(n - 2) : None) == Some(0) // true + ``` +*/ +let findMap: (array<'a>, 'a => option<'b>) => option<'b> + +/** + `at(array, index)` + + Get an element by its index. Negative indices count backwards from the last item. + + ## Examples + ```rescript + ["a", "b", "c"]->Array.at(0) // Some("a") + ["a", "b", "c"]->Array.at(2) // Some("c") + ["a", "b", "c"]->Array.at(3) // None + ["a", "b", "c"]->Array.at(-1) // Some("c") + ["a", "b", "c"]->Array.at(-3) // Some("a") + ["a", "b", "c"]->Array.at(-4) // None + ``` +*/ +@send +external at: (array<'a>, int) => option<'a> = "at" + +/** +`last(array)` returns the last element of `array`. + +Returns `None` if the array is empty. + +## Examples +```rescript +let array = ["Hello", "Hi", "Good bye"] + +array->Array.last == Some("Good bye") // true +[]->Array.last == None // true +``` +*/ +let last: array<'a> => option<'a> diff --git a/runtime/ArrayBuffer.res b/runtime/ArrayBuffer.res new file mode 100644 index 0000000000..0beb684b40 --- /dev/null +++ b/runtime/ArrayBuffer.res @@ -0,0 +1,7 @@ +type t = Js.TypedArray2.ArrayBuffer.t + +@new external make: int => t = "ArrayBuffer" +@get external byteLength: t => int = "byteLength" + +@send external slice: (t, ~start: int, ~end: int) => t = "slice" +@send external sliceToEnd: (t, ~start: int) => t = "slice" diff --git a/runtime/AsyncIterator.res b/runtime/AsyncIterator.res new file mode 100644 index 0000000000..56abad2837 --- /dev/null +++ b/runtime/AsyncIterator.res @@ -0,0 +1,37 @@ +type t<'a> + +type value<'a> = { + done: bool, + value: option<'a>, +} + +let value = v => { + done: false, + value: Some(v), +} + +let done = (~finalValue=?) => { + done: true, + value: finalValue, +} + +@send external next: t<'a> => promise> = "next" + +let forEach = async (iterator, f) => { + let iteratorDone = ref(false) + + while !iteratorDone.contents { + let {done, value} = await iterator->next + f(value) + iteratorDone := done + } +} + +let make: (unit => promise>) => t<'value> = %raw(`function makeAsyncIterator(next) { + return { + next, + [Symbol.asyncIterator]() { + return this; + } + } +}`) diff --git a/runtime/AsyncIterator.resi b/runtime/AsyncIterator.resi new file mode 100644 index 0000000000..bbe8de3b09 --- /dev/null +++ b/runtime/AsyncIterator.resi @@ -0,0 +1,160 @@ +/*** +Bindings to async iterators, a way to do async iteration in JavaScript. + +See [async iterator protocols](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols#the_async_iterator_and_async_iterable_protocols) on MDN.*/ + +/** +The type representing an async iterator. +*/ +type t<'a> + +type value<'a> = { + /** + Whether there are more values to iterate on before the iterator is done. + */ + done: bool, + /** + The value of this iteration, if any. + */ + value: option<'a>, +} + +/** + `make(nextFn)` + + Creates an async iterator from a function that returns the next value of the iterator. + + ## Examples + - A simple example, creating an async iterator that returns 1, 2, 3: + ```rescript + let context = ref(0) + + let asyncIterator = AsyncIterator.make(async () => { + let currentValue = context.contents + // Increment current value + context := currentValue + 1 + + { + AsyncIterator.value: Some(currentValue), + done: currentValue >= 3 + } + }) + + // This will log 1, 2, 3 + await asyncIterator->AsyncIterator.forEach(value => + switch value { + | Some(value) => Console.log(value) + | None => () + } + ) + ``` + */ +let make: (unit => promise>) => t<'value> + +/** + `value(value)` + + Shorthand for creating a value object with the provided value, and the `done` property set to false. + + ## Examples + ```rescript + let context = ref(0) + + let asyncIterator = AsyncIterator.make(async () => { + let currentValue = context.contents + // Increment current value + context := currentValue + 1 + + if currentValue >= 3 { + AsyncIterator.done() + } else { + AsyncIterator.value(currentValue) + } + }) + ``` + */ +let value: 'value => value<'value> + +/** + `done(~finalValue=?)` + + Shorthand for creating a value object with the `done` property set to true, and the provided value as the final value, if any. + + ## Examples + ```rescript + let context = ref(0) + + let asyncIterator = AsyncIterator.make(async () => { + let currentValue = context.contents + // Increment current value + context := currentValue + 1 + + if currentValue >= 3 { + AsyncIterator.done() + } else { + AsyncIterator.value(currentValue) + } + }) + ``` + */ +let done: (~finalValue: 'value=?) => value<'value> + +/** +`next(asyncIterator)` + +Returns the next value of the iterator, if any. + +See [async iterator protocols](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols#the_async_iterator_and_async_iterable_protocols) on MDN. + +## Examples +- A simple example, getting the next value: +```rescript +@val external asyncIterator: AsyncIterator.t = "someAsyncIterator" +let value = await asyncIterator->AsyncIterator.next +``` + +- Complete example, including looping over all values: +```rescript +// Let's pretend we get an async iterator returning ints from somewhere. +@val external asyncIterator: AsyncIterator.t = "someAsyncIterator" + + +let processMyAsyncIterator = async () => { + // ReScript doesn't have `for ... of` loops, but it's easy to mimic using a while loop. + let break = ref(false) + + while !break.contents { + // Await the next iterator value + let {value, done} = await asyncIterator->AsyncIterator.next + + // Exit the while loop if the iterator says it's done + break := done + + // This will log the (int) value of the current async iteration, if a value was returned. + Console.log(value) + } +} +``` +*/ +@send +external next: t<'a> => promise> = "next" + +/** +`forEach(iterator, fn)` consumes all values in the async iterator and runs the callback `fn` for each value. + +See [iterator protocols](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols) on MDN. + +## Examples +```rescript +// Let's pretend we get an async iterator returning ints from somewhere. +@val external asyncIterator: AsyncIterator.t = "someAsyncIterator" + +await asyncIterator->AsyncIterator.forEach(value => + switch value { + | Some(value) if value > 10 => Console.log("More than 10!") + | _ => () + } +) +``` +*/ +let forEach: (t<'a>, option<'a> => unit) => promise diff --git a/runtime/BigInt.res b/runtime/BigInt.res new file mode 100644 index 0000000000..a9fca8a7df --- /dev/null +++ b/runtime/BigInt.res @@ -0,0 +1,97 @@ +@val external asIntN: (~width: int, bigint) => bigint = "BigInt.asIntN" +@val external asUintN: (~width: int, bigint) => bigint = "BigInt.asUintN" + +@val external fromString: string => bigint = "BigInt" + +@val +/** +Parses the given `string` into a `bigint` using JavaScript semantics. Return the +number as a `bigint` if successfully parsed. Uncaught syntax exception otherwise. + +## Examples + +```rescript +/* returns 123n */ +BigInt.fromStringExn("123") + +/* returns 0n */ +BigInt.fromStringExn("") + +/* returns 17n */ +BigInt.fromStringExn("0x11") + +/* returns 3n */ +BigInt.fromStringExn("0b11") + +/* returns 9n */ +BigInt.fromStringExn("0o11") + +/* catch exception */ +try { + BigInt.fromStringExn("a") +} catch { +| Exn.Error(_error) => 0n +} +``` +*/ +external fromStringExn: string => bigint = "BigInt" +@val external fromInt: int => bigint = "BigInt" +@val external fromFloat: float => bigint = "BigInt" + +@send +/** +Formats a `bigint` as a string. Return a `string` representing the given value. +See [`toString`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toString) on MDN. + +## Examples + +```rescript +/* prints "123" */ +Js.BigInt.toString(123n)->Js.log +``` +*/ +external toString: (bigint, ~radix: int=?) => string = "toString" + +@deprecated("Use `toString` with `~radix` instead") @send +external toStringWithRadix: (bigint, ~radix: int) => string = "toString" + +@send +/** +Returns a string with a language-sensitive representation of this BigInt value. + +## Examples + +```rescript +/* prints "123" */ +Js.BigInt.toString(123n)->Js.log +``` +*/ +external toLocaleString: bigint => string = "toLocaleString" + +@val external toFloat: bigint => float = "Number" + +let toInt = t => t->toFloat->Int.fromFloat + +external \"+": (bigint, bigint) => bigint = "%addbigint" +external \"-": (bigint, bigint) => bigint = "%subbigint" +external \"*": (bigint, bigint) => bigint = "%mulbigint" +external \"/": (bigint, bigint) => bigint = "%divbigint" +external \"~-": bigint => bigint = "%negbigint" +external \"~+": bigint => bigint = "%identity" +external \"**": (bigint, bigint) => bigint = "%powbigint" + +external add: (bigint, bigint) => bigint = "%addfloat" +external sub: (bigint, bigint) => bigint = "%subfloat" +external mul: (bigint, bigint) => bigint = "%mulfloat" +external div: (bigint, bigint) => bigint = "%divfloat" + +external mod: (bigint, bigint) => bigint = "%modbigint" + +external land: (bigint, bigint) => bigint = "%andbigint" +external lor: (bigint, bigint) => bigint = "%orbigint" +external lxor: (bigint, bigint) => bigint = "%xorbigint" + +external lsl: (bigint, bigint) => bigint = "%lslbigint" +external asr: (bigint, bigint) => bigint = "%asrbigint" + +let lnot = x => lxor(x, -1n) diff --git a/runtime/BigInt64Array.res b/runtime/BigInt64Array.res new file mode 100644 index 0000000000..4435a72108 --- /dev/null +++ b/runtime/BigInt64Array.res @@ -0,0 +1,53 @@ +/** The `BigInt64Array` typed array represents an array of 64-bit signed integers in platform byte order. See [BigInt64Array on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt64Array) +*/ +type t = TypedArray.t + +module Constants = { + /**`bytesPerElement` returns the element size. See [BYTES_PER_ELEMENT on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray/BYTES_PER_ELEMENT) + */ + @val + external bytesPerElement: int = "BigInt64Array.BYTES_PER_ELEMENT" +} + +/** `fromArray` creates a `BigInt64Array` from an array of values. See [TypedArray constructor on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt64Array/BigInt64Array) +*/ +@new +external fromArray: array => t = "BigInt64Array" + +/** `fromBuffer` creates a `BigInt64Array` from an `ArrayBuffer.t`. See [TypedArray constructor on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt64Array/BigInt64Array) + +**Note:** This is a potentially unsafe operation. Ensure the buffer is large enough and only accessed within its bounds. +*/ +@new +external fromBuffer: ArrayBuffer.t => t = "BigInt64Array" + +/** `fromBufferToEnd` creates a `BigInt64Array` from an `ArrayBuffer.t`, starting at a particular offset and continuing through to the end. See [TypedArray constructor on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt64Array/BigInt64Array) + +**Note:** This is a potentially unsafe operation. Ensure the buffer is large enough and only accessed within its bounds. +*/ +@new +external fromBufferToEnd: (ArrayBuffer.t, ~byteOffset: int) => t = "BigInt64Array" + +/** `fromBufferWithRange` creates a `BigInt64Array` from an `ArrayBuffer.t`, starting at a particular offset and consuming `length` **bytes**. See [TypedArray constructor on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt64Array/BigInt64Array) + +**Note:** This is a potentially unsafe operation. Ensure the buffer is large enough and only accessed within its bounds. +*/ +@new +external fromBufferWithRange: (ArrayBuffer.t, ~byteOffset: int, ~length: int) => t = "BigInt64Array" + +/** `fromLength` creates a zero-initialized `BigInt64Array` to hold the specified count of numbers; this is **not** a byte length. See [TypedArray constructor on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt64Array/BigInt64Array) + +**Note:** This is a potentially unsafe operation. Ensure the buffer is large enough and only accessed within its bounds. +*/ +@new +external fromLength: int => t = "BigInt64Array" + +/** `fromArrayLikeOrIterable` creates a `BigInt64Array` from an array-like or iterable object. See [TypedArray.from on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray/from) +*/ +@val +external fromArrayLikeOrIterable: 'a => t = "BigInt64Array.from" + +/** `fromArrayLikeOrIterableWithMap` creates a `BigInt64Array` from an array-like or iterable object and applies the mapping function to each item. The mapping function expects (value, index). See [TypedArray.from on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray/from) +*/ +@val +external fromArrayLikeOrIterableWithMap: ('a, ('b, int) => bigint) => t = "BigInt64Array.from" diff --git a/runtime/BigUint64Array.res b/runtime/BigUint64Array.res new file mode 100644 index 0000000000..d9f527d59a --- /dev/null +++ b/runtime/BigUint64Array.res @@ -0,0 +1,54 @@ +/** The `BigUint64Array` typed array represents an array of 64-bit unsigned integers in platform byte order. See [BigUint64Array on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigUint64Array) +*/ +type t = TypedArray.t + +module Constants = { + /**`bytesPerElement` returns the element size. See [BYTES_PER_ELEMENT on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray/BYTES_PER_ELEMENT) + */ + @val + external bytesPerElement: int = "BigUint64Array.BYTES_PER_ELEMENT" +} + +/** `fromArray` creates a `BigUint64Array` from an array of values. See [TypedArray constructor on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigUint64Array/BigUint64Array) +*/ +@new +external fromArray: array => t = "BigUint64Array" + +/** `fromBuffer` creates a `BigUint64Array` from an `ArrayBuffer.t`. See [TypedArray constructor on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigUint64Array/BigUint64Array) + +**Note:** This is a potentially unsafe operation. Ensure the buffer is large enough and only accessed within its bounds. +*/ +@new +external fromBuffer: ArrayBuffer.t => t = "BigUint64Array" + +/** `fromBufferToEnd` creates a `BigUint64Array` from an `ArrayBuffer.t`, starting at a particular offset and continuing through to the end. See [TypedArray constructor on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigUint64Array/BigUint64Array) + +**Note:** This is a potentially unsafe operation. Ensure the buffer is large enough and only accessed within its bounds. +*/ +@new +external fromBufferToEnd: (ArrayBuffer.t, ~byteOffset: int) => t = "BigUint64Array" + +/** `fromBufferWithRange` creates a `BigUint64Array` from an `ArrayBuffer.t`, starting at a particular offset and consuming `length` **bytes**. See [TypedArray constructor on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigUint64Array/BigUint64Array) + +**Note:** This is a potentially unsafe operation. Ensure the buffer is large enough and only accessed within its bounds. +*/ +@new +external fromBufferWithRange: (ArrayBuffer.t, ~byteOffset: int, ~length: int) => t = + "BigUint64Array" + +/** `fromLength` creates a zero-initialized `BigUint64Array` to hold the specified count of numbers; this is **not** a byte length. See [TypedArray constructor on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigUint64Array/BigUint64Array) + +**Note:** This is a potentially unsafe operation. Ensure the buffer is large enough and only accessed within its bounds. +*/ +@new +external fromLength: int => t = "BigUint64Array" + +/** `fromArrayLikeOrIterable` creates a `BigUint64Array` from an array-like or iterable object. See [TypedArray.from on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray/from) +*/ +@val +external fromArrayLikeOrIterable: 'a => t = "BigUint64Array.from" + +/** `fromArrayLikeOrIterableWithMap` creates a `BigUint64Array` from an array-like or iterable object and applies the mapping function to each item. The mapping function expects (value, index). See [TypedArray.from on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray/from) +*/ +@val +external fromArrayLikeOrIterableWithMap: ('a, ('b, int) => bigint) => t = "BigUint64Array.from" diff --git a/runtime/Console.res b/runtime/Console.res new file mode 100644 index 0000000000..2c85d0242b --- /dev/null +++ b/runtime/Console.res @@ -0,0 +1,67 @@ +@val external assert_: (bool, 'a) => unit = "console.assert" +@val external assert2: (bool, 'a, 'b) => unit = "console.assert" +@val external assert3: (bool, 'a, 'b, 'c) => unit = "console.assert" +@val external assert4: (bool, 'a, 'b, 'c, 'd) => unit = "console.assert" +@val external assert5: (bool, 'a, 'b, 'c, 'd, 'e) => unit = "console.assert" +@val external assert6: (bool, 'a, 'b, 'c, 'd, 'e, 'f) => unit = "console.assert" +@val @variadic external assertMany: (bool, array<_>) => unit = "console.assert" + +@val external clear: unit => unit = "console.clear" + +@val external count: string => unit = "console.count" +@val external countReset: string => unit = "console.countReset" + +@val external debug: 'a => unit = "console.debug" +@val external debug2: ('a, 'b) => unit = "console.debug" +@val external debug3: ('a, 'b, 'c) => unit = "console.debug" +@val external debug4: ('a, 'b, 'c, 'd) => unit = "console.debug" +@val external debug5: ('a, 'b, 'c, 'd, 'e) => unit = "console.debug" +@val external debug6: ('a, 'b, 'c, 'd, 'e, 'f) => unit = "console.debug" +@val @variadic external debugMany: array<_> => unit = "console.debug" + +@val external dir: 'a => unit = "console.dir" +@val external dirxml: 'a => unit = "console.dirxml" + +@val external error: 'a => unit = "console.error" +@val external error2: ('a, 'b) => unit = "console.error" +@val external error3: ('a, 'b, 'c) => unit = "console.error" +@val external error4: ('a, 'b, 'c, 'd) => unit = "console.error" +@val external error5: ('a, 'b, 'c, 'd, 'e) => unit = "console.error" +@val external error6: ('a, 'b, 'c, 'd, 'e, 'f) => unit = "console.error" +@val @variadic external errorMany: array<_> => unit = "console.error" + +@val external group: string => unit = "console.group" +@val external groupCollapsed: string => unit = "console.groupCollapsed" +@val external groupEnd: unit => unit = "console.groupEnd" + +@val external info: 'a => unit = "console.info" +@val external info2: ('a, 'b) => unit = "console.info" +@val external info3: ('a, 'b, 'c) => unit = "console.info" +@val external info4: ('a, 'b, 'c, 'd) => unit = "console.info" +@val external info5: ('a, 'b, 'c, 'd, 'e) => unit = "console.info" +@val external info6: ('a, 'b, 'c, 'd, 'e, 'f) => unit = "console.info" +@val @variadic external infoMany: array<_> => unit = "console.info" + +@val external log: 'a => unit = "console.log" +@val external log2: ('a, 'b) => unit = "console.log" +@val external log3: ('a, 'b, 'c) => unit = "console.log" +@val external log4: ('a, 'b, 'c, 'd) => unit = "console.log" +@val external log5: ('a, 'b, 'c, 'd, 'e) => unit = "console.log" +@val external log6: ('a, 'b, 'c, 'd, 'e, 'f) => unit = "console.log" +@val @variadic external logMany: array<_> => unit = "console.log" + +@val external table: 'a => unit = "console.table" + +@val external time: string => unit = "console.time" +@val external timeEnd: string => unit = "console.timeEnd" +@val external timeLog: string => unit = "console.timeLog" + +@val external trace: unit => unit = "console.trace" + +@val external warn: 'a => unit = "console.warn" +@val external warn2: ('a, 'b) => unit = "console.warn" +@val external warn3: ('a, 'b, 'c) => unit = "console.warn" +@val external warn4: ('a, 'b, 'c, 'd) => unit = "console.warn" +@val external warn5: ('a, 'b, 'c, 'd, 'e) => unit = "console.warn" +@val external warn6: ('a, 'b, 'c, 'd, 'e, 'f) => unit = "console.warn" +@val @variadic external warnMany: array<_> => unit = "console.warn" diff --git a/runtime/Console.resi b/runtime/Console.resi new file mode 100644 index 0000000000..ec1d757ab3 --- /dev/null +++ b/runtime/Console.resi @@ -0,0 +1,786 @@ +/*** +Functions for interacting with JavaScript console. + +See: [`console`](https://developer.mozilla.org/en-US/docs/Web/API/Console). +*/ + +/** +`assert_(assertion, value)` print a message to console if `assertion` evaluates `false`. Does nothing if it's `true`. + +See [`console.assert`](https://developer.mozilla.org/en-US/docs/Web/API/console/assert) +on MDN. + +## Examples + +```rescript +Console.assert_(false, "Hello World!") +Console.assert_(42 == 42, "The answer") +``` +*/ +@val +external assert_: (bool, 'a) => unit = "console.assert" + +/** +`assert2(v1, v2)`. Like `assert_`, but with two arguments. + +## Examples + +```rescript +Console.assert2(false, "Hello", "World") +Console.assert2(42 == 42, [1, 2, 3], '4') +``` +*/ +@val +external assert2: (bool, 'a, 'b) => unit = "console.assert" + +/** +`assert3(v1, v2, v3)`. Like `assert_`, but with three arguments. + +## Examples + +```rescript +Console.assert3(false, "Hello", "World", "ReScript") +Console.assert3(42 == 42, "One", 2, #3) +``` +*/ +@val +external assert3: (bool, 'a, 'b, 'c) => unit = "console.assert" + +/** +`assert4(v1, v2, v3, v4)`. Like `assert_`, but with four arguments. + +## Examples + +```rescript +let value = 42 +Console.assert4(false, "Hello", "World", "ReScript", "!!!") +Console.assert4(value == 42, [1, 2], (3, 4), [#5, #6], #"polyvar") +``` +*/ +@val +external assert4: (bool, 'a, 'b, 'c, 'd) => unit = "console.assert" + +/** +`assert5(v1, v2, v3, v4, v5)`. Like `assert_`, but with five arguments. + +## Examples + +```rescript +let value = 42 +Console.assert5(false, "Hello", "World", "JS", '!', '!') +Console.assert5(value == 42, [1, 2], (3, 4), [#5, #6], #"polyvar", {"name": "ReScript"}) +``` +*/ +@val +external assert5: (bool, 'a, 'b, 'c, 'd, 'e) => unit = "console.assert" + +/** +`assert6(v1, v2)`. Like `assert_`, but with six arguments. + +## Examples + +```rescript +let value = 42 +Console.assert6(false, "Hello", "World", "JS", '!', '!', '?') +Console.assert6(value == 42, [1, 2], (3, 4), [#5, #6], #"polyvar", {"name": "ReScript"}, 42) +``` +*/ +@val +external assert6: (bool, 'a, 'b, 'c, 'd, 'e, 'f) => unit = "console.assert" + +/** +`assertMany(assertion, arr)`. Like `assert_`, but variadic. + +## Examples + +```rescript +let value = 42 +Console.assertMany(false, ["Hello", "World"]) +Console.assertMany(value == 42, [1, 2, 3]) +``` +*/ +@val +@variadic +external assertMany: (bool, array<_>) => unit = "console.assert" + +/** +`clear()` clears the console, if allowed. + +See [`console.clear`](https://developer.mozilla.org/en-US/docs/Web/API/console/clear) +on MDN. + +## Examples + +```rescript +Console.clear() +``` +*/ +@val +external clear: unit => unit = "console.clear" + +/** +`count(label)` prints to the console the number of times it's been called with the given label. + +See [`console.count`](https://developer.mozilla.org/en-US/docs/Web/API/console/count) +on MDN. + +## Examples + +```rescript +Console.count("rescript") +``` +*/ +@val +external count: string => unit = "console.count" + +/** +`countReset(label)` resets the count for the given label to 0. + +See [`console.countReset`](https://developer.mozilla.org/en-US/docs/Web/API/console/countReset) +on MDN. + +## Examples + +```rescript +Console.countReset("rescript") +``` +*/ +@val +external countReset: string => unit = "console.countReset" + +/** +`debug(value)` print a debug message to console. + +See [`console.debug`](https://developer.mozilla.org/en-US/docs/Web/API/console/debug) +on MDN. + +## Examples + +```rescript +Console.debug("Hello") +let obj = {"name": "ReScript", "version": 10} +Console.debug(obj) +``` +*/ +@val +external debug: 'a => unit = "console.debug" + +/** +`debug2(v1, v2)`. Like `debug`, but with two arguments. + +## Examples + +```rescript +Console.debug2("Hello", "World") +Console.debug2([1, 2, 3], '4') +``` +*/ +@val +external debug2: ('a, 'b) => unit = "console.debug" + +/** +`debug3(v1, v2, v3)`. Like `debug`, but with three arguments. + +## Examples + +```rescript +Console.debug3("Hello", "World", "ReScript") +Console.debug3("One", 2, #3) +``` +*/ +@val +external debug3: ('a, 'b, 'c) => unit = "console.debug" + +/** +`debug4(v1, v2, v3, v4)`. Like `debug`, but with four arguments. + +## Examples + +```rescript +Console.debug4("Hello", "World", "ReScript", "!!!") +Console.debug4([1, 2], (3, 4), [#5, #6], #"polyvar") +``` +*/ +@val +external debug4: ('a, 'b, 'c, 'd) => unit = "console.debug" + +/** +`debug5(v1, v2, v3, v4, v5)`. Like `debug`, but with five arguments. + +## Examples + +```rescript +Console.debug5("Hello", "World", "JS", '!', '!') +Console.debug5([1, 2], (3, 4), [#5, #6], #"polyvar", {"name": "ReScript"}) +``` +*/ +@val +external debug5: ('a, 'b, 'c, 'd, 'e) => unit = "console.debug" + +/** +`debug6(v1, v2, v3, v4, v5, v6)`. Like `debug`, but with six arguments. + +## Examples + +```rescript +Console.debug6("Hello", "World", "JS", '!', '!', '?') +Console.debug6([1, 2], (3, 4), [#5, #6], #"polyvar", {"name": "ReScript"}, 42) +``` +*/ +@val +external debug6: ('a, 'b, 'c, 'd, 'e, 'f) => unit = "console.debug" + +/** +`debugMany(arr)`. Like `debug`, but variadic. + +## Examples + +```rescript +Console.debugMany(["Hello", "World"]) +Console.debugMany([1, 2, 3]) +``` +*/ +@val +@variadic +external debugMany: array<_> => unit = "console.debug" + +/** +`dir(object)` displays an interactive view of the object in the console. + +See [`console.dir`](https://developer.mozilla.org/en-US/docs/Web/API/console/dir) +on MDN. + +## Examples + +```rescript +Console.dir({"language": "rescript", "version": "10.1.2"}) +``` +*/ +@val +external dir: 'a => unit = "console.dir" + +/** +`dirxml(object)` displays an interactive tree view of an XML/HTML element in the console. + +See [`console.dirxml`](https://developer.mozilla.org/en-US/docs/Web/API/console/dirxml) +on MDN. +*/ +@val +external dirxml: 'a => unit = "console.dirxml" + +/** +`error(value)` prints an error message to console. + +See [`console.error`](https://developer.mozilla.org/en-US/docs/Web/API/console/error) +on MDN. + +## Examples + +```rescript +Console.error("error message") +Console.error(("error", "invalid value")) +``` +*/ +@val +external error: 'a => unit = "console.error" + +/** +`error(v1, v2)`. Like `error`, but two arguments. + +## Examples + +```rescript +Console.error2("Error", "here") +Console.error2(("log", "error"), "message") +``` +*/ +@val +external error2: ('a, 'b) => unit = "console.error" + +/** +`error3(v1, v2, v3)`. Like `error`, but three arguments. + +## Examples + +```rescript +Console.error3("Hello", "World", "!!!") +Console.error3(#first, #second, #third) +``` +*/ +@val +external error3: ('a, 'b, 'c) => unit = "console.error" + +/** +`error4(v1, v2, v3, v4)`. Like `error`, but with four arguments. + +## Examples + +```rescript +Console.error4("Hello", "World", "ReScript", '!') +Console.error4(#first, #second, #third, ("fourth")) +``` +*/ +@val +external error4: ('a, 'b, 'c, 'd) => unit = "console.error" + +/** +`error5(v1, v2, v3, v4, v5)`. Like `error`, but with five arguments. + +## Examples + +```rescript +Console.error5('e', 'r', 'r', 'o', 'r') +Console.error5(1, #second, #third, ("fourth"), 'c') +``` +*/ +@val +external error5: ('a, 'b, 'c, 'd, 'e) => unit = "console.error" + +/** +`error6(v1, v2, v3, v4, v5, v6)`. Like `error`, but with six arguments. + +## Examples + +```rescript +Console.error6("Hello", "World", "from", "JS", "!!!", '!') +Console.error6([1, 2], (3, 4), [#5, #6], #"polyvar", {"name": "ReScript"}, 42) +``` +*/ +@val +external error6: ('a, 'b, 'c, 'd, 'e, 'f) => unit = "console.error" + +/** +`group(label)` creates a new "group" level with the given label. + +See [`console.group`](https://developer.mozilla.org/en-US/docs/Web/API/console/group) +on MDN. + +## Example + +```rescript +Console.group("first group") +Console.group("second group") +Console.log("a message on the second level") +Console.groupEnd() +Console.log("a message message on the first level") +Console.groupEnd() +``` +*/ +@val +external group: string => unit = "console.group" + +/** +`groupCollapsed(label)`. Like `group` but collapses the group initially. + +See [`console.groupCollapsed`](https://developer.mozilla.org/en-US/docs/Web/API/console/groupCollapsed) +on MDN. +*/ +@val +external groupCollapsed: string => unit = "console.groupCollapsed" + +/** +`groupEnd()` ends the current group. + +See [`console.groupEnd`](https://developer.mozilla.org/en-US/docs/Web/API/console/groupEnd) +on MDN. +*/ +@val +external groupEnd: unit => unit = "console.groupEnd" + +/** +`errorMany(arr)`. Like `error`, but variadic. + +## Examples + +```rescript +Console.errorMany(["Hello", "World"]) +Console.errorMany([1, 2, 3]) +``` +*/ +@val +@variadic +external errorMany: array<_> => unit = "console.error" + +/** +`info(value)` print an informational message to console. + +See [`console.info`](https://developer.mozilla.org/en-US/docs/Web/API/console/info) +on MDN. + +## Examples + +```rescript +Console.info("Information") +Console.info(("Hello", "JS")) +``` +*/ +@val +external info: 'a => unit = "console.info" + +/** +`info2(v1, v2)`. Like `info`, but with two arguments. + +## Examples + +```rescript +Console.info2("Info", "failed to download") +Console.info2(#info, {"name": "ReScript"}) +``` +*/ +@val +external info2: ('a, 'b) => unit = "console.info" + +/** +`info3(v1, v2, v3)`. Like `info`, but with three arguments. + +## Examples + +```rescript +Console.info3("Hello", "World", "ReScript") +Console.info3([1, 2, 3], #4, #5) +``` +*/ +@val +external info3: ('a, 'b, 'c) => unit = "console.info" + +/** +`info4(v1, v2, v3, v4)`. Like `info`, but with four arguments. + +## Examples + +```rescript +Console.info4("Hello", "World", "ReScript", '!') +Console.info4([1, 2, 3], #4, #5, #lastinfo) +``` +*/ +@val +external info4: ('a, 'b, 'c, 'd) => unit = "console.info" + +/** +`info5(v1, v2, v3, v4, v5)`. Like `info`, but with five arguments. + +## Examples + +```rescript +Console.info5("Hello", "World", "from", "JS", "!!!") +Console.info5([1, 2], (3, 4), [#5, #6], #"polyvar", {"name": "ReScript"}) +``` +*/ +@val +external info5: ('a, 'b, 'c, 'd, 'e) => unit = "console.info" + +/** +`info6(v1, v2, v3, v4, v5, v6)`. Like `info`, but with six arguments. + +## Examples + +```rescript +Console.info6("Hello", "World", "from", "JS", "!!!", '!') +Console.info6([1, 2], (3, 4), [#5, #6], #"polyvar", {"name": "ReScript"}, 42) +``` +*/ +@val +external info6: ('a, 'b, 'c, 'd, 'e, 'f) => unit = "console.info" + +/** +`infoMany(arr)`. Like `info`, but variadic. + +## Examples + +```rescript +Console.infoMany(["Hello", "World"]) +Console.infoMany([1, 2, 3]) +``` +*/ +@val +@variadic +external infoMany: array<_> => unit = "console.info" + +/** +`log(value)` print a message to console. + +See [`console.log`](https://developer.mozilla.org/en-US/docs/Web/API/console/log) +on MDN. + +## Examples + +```rescript +Console.log("Hello") +let obj = {"name": "ReScript", "version": 10} +Console.log(obj) +``` +*/ +@val +external log: 'a => unit = "console.log" + +/** +`log2(v1, v2)`. Like `log`, but with two arguments. + +## Examples + +```rescript +Console.log2("Hello", "World") +Console.log2([1, 2, 3], '4') +``` +*/ +@val +external log2: ('a, 'b) => unit = "console.log" + +/** +`log3(v1, v2, v3)`. Like `log`, but with three arguments. + +## Examples + +```rescript +Console.log3("Hello", "World", "ReScript") +Console.log3("One", 2, #3) +``` +*/ +@val +external log3: ('a, 'b, 'c) => unit = "console.log" + +/** +`log4(v1, v2, v3, v4)`. Like `log`, but with four arguments. + +## Examples + +```rescript +Console.log4("Hello", "World", "ReScript", "!!!") +Console.log4([1, 2], (3, 4), [#5, #6], #"polyvar") +``` +*/ +@val +external log4: ('a, 'b, 'c, 'd) => unit = "console.log" + +/** +`log5(v1, v2, v3, v4, v5)`. Like `log`, but with five arguments. + +## Examples + +```rescript +Console.log5("Hello", "World", "JS", '!', '!') +Console.log5([1, 2], (3, 4), [#5, #6], #"polyvar", {"name": "ReScript"}) +``` +*/ +@val +external log5: ('a, 'b, 'c, 'd, 'e) => unit = "console.log" + +/** +`log6(v1, v2, v3, v4, v5, v6)`. Like `log`, but with six arguments. + +## Examples + +```rescript +Console.log6("Hello", "World", "JS", '!', '!', '?') +Console.log6([1, 2], (3, 4), [#5, #6], #"polyvar", {"name": "ReScript"}, 42) +``` +*/ +@val +external log6: ('a, 'b, 'c, 'd, 'e, 'f) => unit = "console.log" + +/** +`logMany(arr)`. Like `log`, but variadic. + +## Examples + +```rescript +Console.logMany(["Hello", "World"]) +Console.logMany([1, 2, 3]) +``` +*/ +@val +@variadic +external logMany: array<_> => unit = "console.log" + +/** +`table(object)` displays an tabular view of the object in the console. + +See [`console.table`](https://developer.mozilla.org/en-US/docs/Web/API/console/table) +on MDN. + +## Examples + +```rescript +Console.table({"language": "rescript", "version": "10.1.2"}) +``` +*/ +@val +external table: 'a => unit = "console.table" + +/** +`time(label)` creates a timer to measure how long an operation takes. `label` +must be a unique name. Call `console.timeEnd` with the same `label` to print +output time. + +See [`console.time`](https://developer.mozilla.org/en-US/docs/Web/API/console/time) +on MDN. + +## Examples + +```rescript +Console.time("for_time") +for x in 3 downto 1 { + Console.log(x) + Console.timeLog("for_time") +} +Console.timeEnd("for_time") +``` +*/ +@val +external time: string => unit = "console.time" + +/** +`timeEnd(label)` stops a timer created by `time`. + +See [`console.timeEnd`](https://developer.mozilla.org/en-US/docs/Web/API/console/timeEnd) +on MDN. + +## Examples + +```rescript +Console.time("for_time") +for x in 3 downto 1 { + Console.log(x) + Console.timeLog("for_time") +} +Console.timeEnd("for_time") +``` +*/ +@val +external timeEnd: string => unit = "console.timeEnd" + +/** +`timeLog(label)` prints the current elapsed time of the given timer to the console. + +See [`console.timeLog`](https://developer.mozilla.org/en-US/docs/Web/API/console/timeLog) +on MDN. + +## Examples + +```rescript +Console.time("for_time") +for x in 3 downto 1 { + Console.log(x) + Console.timeLog("for_time") +} +Console.timeEnd("for_time") +``` +*/ +@val +external timeLog: string => unit = "console.timeLog" + +/** +`trace()` print a stack trace to console. + +See [`console.trace`](https://developer.mozilla.org/en-US/docs/Web/API/console/trace) +on MDN. + +## Examples + +```rescript +let main = () => { + Console.trace() +} +main() +// In the console, the following trace will be displayed: +// main +// +``` +*/ +@val +external trace: unit => unit = "console.trace" + +/** +`warn(value)` print a warning message to console. + +See [`console.warn`](https://developer.mozilla.org/en-US/docs/Web/API/console/warn) +on MDN. + +## Examples + +```rescript +Console.warn("Warning") +Console.warn(("Warning", "invalid number")) +``` +*/ +@val +external warn: 'a => unit = "console.warn" + +/** +`warn2(v1, v2)`. Like `warn`, but two arguments. + +## Examples + +```rescript +Console.warn2("Hello", "World") +Console.warn2([1, 2, 3], 4) +``` +*/ +@val +external warn2: ('a, 'b) => unit = "console.warn" + +/** +`warn3(v1, v2, v3)`. Like `warn`, but three arguments. + +## Examples + +```rescript +Console.warn3("Hello", "World", "ReScript") +Console.warn3([1, 2, 3], #4, #5) +``` +*/ +@val +external warn3: ('a, 'b, 'c) => unit = "console.warn" + +/** +`warn4(v1, v2, v3, v4)`. Like `warn`, but with four arguments. + +## Examples + +```rescript +Console.warn4("Hello", "World", "ReScript", "!!!") +Console.warn4(#first, #second, #third, ("fourth")) +``` +*/ +@val +external warn4: ('a, 'b, 'c, 'd) => unit = "console.warn" + +/** +`warn5(v1, v2, v3, v4, v5)`. Like `warn`, but with five arguments. + +## Examples + +```rescript +Console.warn5("Hello", "World", "from", "JS", "!!!") +Console.warn5([1, 2], (3, 4), [#5, #6], #"polyvar", {"name": "ReScript"}) +``` +*/ +@val +external warn5: ('a, 'b, 'c, 'd, 'e) => unit = "console.warn" + +/** +`warn6(v1, v2, v3, v4, v5, v6)`. Like `warn`, but with six arguments. + +## Examples + +```rescript +Console.warn6("Hello", "World", "from", "JS", "!!!", '!') +Console.warn6([1, 2], (3, 4), [#5, #6], #"polyvar", {"name": "ReScript"}, 42) +``` +*/ +@val +external warn6: ('a, 'b, 'c, 'd, 'e, 'f) => unit = "console.warn" + +/** +`warnMany(arr)`. Like `warn`, but variadic. + +## Examples + +```rescript +Console.warnMany(["Hello", "World"]) +Console.warnMany([1, 2, 3]) +``` +*/ +@val +@variadic +external warnMany: array<_> => unit = "console.warn" diff --git a/runtime/DataView.res b/runtime/DataView.res new file mode 100644 index 0000000000..8c75a4dff1 --- /dev/null +++ b/runtime/DataView.res @@ -0,0 +1,36 @@ +type t + +@new external fromBuffer: ArrayBuffer.t => t = "DataView" +@new external fromBufferToEnd: (ArrayBuffer.t, ~byteOffset: int) => t = "DataView" +@new +external fromBufferWithRange: (ArrayBuffer.t, ~byteOffset: int, ~length: int) => t = "DataView" + +@get external buffer: t => ArrayBuffer.t = "buffer" +@get external byteLength: t => int = "byteLength" +@get external byteOffset: t => int = "byteOffset" + +@send external getInt8: (t, int) => int = "getInt8" +@send external getUint8: (t, int) => int = "getUint8" +@send external getInt16: (t, int) => int = "getInt16" +@send external getUint16: (t, int) => int = "getUint16" +@send external getInt32: (t, int) => int = "getInt32" +@send external getUint32: (t, int) => int = "getUint32" + +@send external getFloat32: (t, int) => float = "getFloat32" +@send external getFloat64: (t, int) => float = "getFloat64" + +@send external getBigInt64: (t, int) => bigint = "getBigInt64" +@send external getBigUint64: (t, int) => bigint = "getBigUint64" + +@send external setInt8: (t, int, int) => unit = "setInt8" +@send external setUint8: (t, int, int) => unit = "setUint8" +@send external setInt16: (t, int, int) => unit = "setInt16" +@send external setUint16: (t, int, int) => unit = "setUint16" +@send external setInt32: (t, int, int) => unit = "setInt32" +@send external setUint32: (t, int, int) => unit = "setUint32" + +@send external setFloat32: (t, int, float) => unit = "setFloat32" +@send external setFloat64: (t, int, float) => unit = "setFloat64" + +@send external setBigInt64: (t, int, bigint) => unit = "setBigInt64" +@send external setBigUint64: (t, int, bigint) => unit = "setBigUint64" diff --git a/runtime/Date.res b/runtime/Date.res new file mode 100644 index 0000000000..925afcc190 --- /dev/null +++ b/runtime/Date.res @@ -0,0 +1,180 @@ +type t = Js.Date.t + +type msSinceEpoch = float + +type localeOptions = { + dateStyle?: [#full | #long | #medium | #short], + timeStyle?: [#full | #long | #medium | #short], + weekday?: [#long | #short | #narrow], + era?: [#long | #short | #narrow], + year?: [#numeric | #"2-digit"], + month?: [#numeric | #"2-digit" | #long | #short | #narrow], + day?: [#numeric | #"2-digit"], + hour?: [#numeric | #"2-digit"], + minute?: [#numeric | #"2-digit"], + second?: [#numeric | #"2-digit"], + timeZoneName?: [#long | #short], +} + +@new external make: unit => t = "Date" +@new external fromString: string => t = "Date" +@new external fromTime: msSinceEpoch => t = "Date" + +@new external makeWithYM: (~year: int, ~month: int) => t = "Date" +@new external makeWithYMD: (~year: int, ~month: int, ~date: int) => t = "Date" +@new external makeWithYMDH: (~year: int, ~month: int, ~date: int, ~hours: int) => t = "Date" +@new +external makeWithYMDHM: (~year: int, ~month: int, ~date: int, ~hours: int, ~minutes: int) => t = + "Date" +@new +external makeWithYMDHMS: ( + ~year: int, + ~month: int, + ~date: int, + ~hours: int, + ~minutes: int, + ~seconds: int, +) => t = "Date" +@new +external makeWithYMDHMSM: ( + ~year: int, + ~month: int, + ~date: int, + ~hours: int, + ~minutes: int, + ~seconds: int, + ~milliseconds: int, +) => t = "Date" + +module UTC = { + @val external makeWithYM: (~year: int, ~month: int) => msSinceEpoch = "Date.UTC" + @val external makeWithYMD: (~year: int, ~month: int, ~date: int) => msSinceEpoch = "Date.UTC" + @val + external makeWithYMDH: (~year: int, ~month: int, ~date: int, ~hours: int) => msSinceEpoch = + "Date.UTC" + @val + external makeWithYMDHM: ( + ~year: int, + ~month: int, + ~date: int, + ~hours: int, + ~minutes: int, + ) => msSinceEpoch = "Date.UTC" + @val + external makeWithYMDHMS: ( + ~year: int, + ~month: int, + ~date: int, + ~hours: int, + ~minutes: int, + ~seconds: int, + ) => msSinceEpoch = "Date.UTC" + @val + external makeWithYMDHMSM: ( + ~year: int, + ~month: int, + ~date: int, + ~hours: int, + ~minutes: int, + ~seconds: int, + ~milliseconds: int, + ) => msSinceEpoch = "Date.UTC" +} + +@val external now: unit => msSinceEpoch = "Date.now" + +@send external getTime: t => msSinceEpoch = "getTime" +@send external getTimezoneOffset: t => int = "getTimezoneOffset" + +let equal = (a, b) => a->getTime === b->getTime + +let compare = (a, b) => Float.compare(a->getTime, b->getTime) + +// Locale +@send external getFullYear: t => int = "getFullYear" +@send external getMonth: t => int = "getMonth" +@send external getDate: t => int = "getDate" +@send external getHours: t => int = "getHours" +@send external getMinutes: t => int = "getMinutes" +@send external getSeconds: t => int = "getSeconds" +@send external getMilliseconds: t => int = "getMilliseconds" +@send external getDay: t => int = "getDay" + +@send external setFullYear: (t, int) => unit = "setFullYear" +@send external setFullYearM: (t, ~year: int, ~month: int) => unit = "setFullYear" +@send external setFullYearMD: (t, ~year: int, ~month: int, ~date: int) => unit = "setFullYear" +@send external setMonth: (t, int) => unit = "setMonth" +@send external setDate: (t, int) => unit = "setDate" +@send external setHours: (t, int) => unit = "setHours" +@send external setHoursM: (t, ~hours: int, ~minutes: int) => unit = "setHours" +@send external setHoursMS: (t, ~hours: int, ~minutes: int, ~seconds: int) => unit = "setHours" +@send +external setHoursMSMs: (t, ~hours: int, ~minutes: int, ~seconds: int, ~milliseconds: int) => unit = + "setHours" +@send external setMinutes: (t, int) => unit = "setMinutes" +@send external setMinutesS: (t, ~minutes: int, ~seconds: int) => unit = "setMinutes" +@send +external setMinutesSMs: (t, ~minutes: int, ~seconds: int, ~milliseconds: int) => unit = "setMinutes" +@send external setSeconds: (t, int) => unit = "setSeconds" +@send external setSecondsMs: (t, ~seconds: int, ~milliseconds: int) => unit = "setSeconds" +@send external setMilliseconds: (t, int) => unit = "setMilliseconds" + +// UTC +@send external getUTCFullYear: t => int = "getUTCFullYear" +@send external getUTCMonth: t => int = "getUTCMonth" +@send external getUTCDate: t => int = "getUTCDate" +@send external getUTCHours: t => int = "getUTCHours" +@send external getUTCMinutes: t => int = "getUTCMinutes" +@send external getUTCSeconds: t => int = "getUTCSeconds" +@send external getUTCMilliseconds: t => int = "getUTCMilliseconds" +@send external getUTCDay: t => int = "getUTCDay" + +@send external setUTCFullYear: (t, int) => unit = "setUTCFullYear" +@send external setUTCFullYearM: (t, ~year: int, ~month: int) => unit = "setUTCFullYear" +@send +external setUTCFullYearMD: (t, ~year: int, ~month: int, ~date: int) => unit = "setUTCFullYear" +@send external setUTCMonth: (t, int) => unit = "setUTCMonth" +@send external setUTCDate: (t, int) => unit = "setUTCDate" +@send external setUTCHours: (t, int) => unit = "setUTCHours" +@send external setUTCHoursM: (t, ~hours: int, ~minutes: int) => unit = "setUTCHours" +@send +external setUTCHoursMS: (t, ~hours: int, ~minutes: int, ~seconds: int) => unit = "setUTCHours" +@send +external setUTCHoursMSMs: ( + t, + ~hours: int, + ~minutes: int, + ~seconds: int, + ~milliseconds: int, +) => unit = "setUTCHours" +@send external setUTCMinutes: (t, int) => unit = "setUTCMinutes" +@send external setUTCMinutesS: (t, ~minutes: int, ~seconds: int) => unit = "setUTCMinutes" +@send +external setUTCMinutesSMs: (t, ~minutes: int, ~seconds: int, ~milliseconds: int) => unit = + "setUTCMinutes" +@send external setUTCSeconds: (t, int) => unit = "setUTCSeconds" +@send external setUTCSecondsMs: (t, ~seconds: int, ~milliseconds: int) => unit = "setUTCSeconds" +@send external setUTCMilliseconds: (t, int) => unit = "setUTCMilliseconds" + +@send external toDateString: t => string = "toDateString" +@send external toString: t => string = "toString" +@send external toTimeString: t => string = "toTimeString" + +@send external toLocaleDateString: t => string = "toLocaleDateString" +@send external toLocaleDateStringWithLocale: (t, string) => string = "toLocaleDateString" +@send +external toLocaleDateStringWithLocaleAndOptions: (t, string, localeOptions) => string = + "toLocaleDateString" +@send external toLocaleString: t => string = "toLocaleString" +@send external toLocaleStringWithLocale: (t, string) => string = "toLocaleString" +@send +external toLocaleStringWithLocaleAndOptions: (t, string, localeOptions) => string = "toLocaleString" +@send external toLocaleTimeString: t => string = "toLocaleTimeString" +@send external toLocaleTimeStringWithLocale: (t, string) => string = "toLocaleTimeString" +@send +external toLocaleTimeStringWithLocaleAndOptions: (t, string, localeOptions) => string = + "toLocaleTimeString" + +@send external toISOString: t => string = "toISOString" +@send external toUTCString: t => string = "toUTCString" +@return(nullable) @send external toJSON: t => option = "toJSON" diff --git a/runtime/Date.resi b/runtime/Date.resi new file mode 100644 index 0000000000..f0d975ba1a --- /dev/null +++ b/runtime/Date.resi @@ -0,0 +1,1360 @@ +/*** + Functions for interacting with JavaScript Dates. +*/ + +/** +A type representing a JavaScript date. +*/ +type t = Js.Date.t + +/** +Time, in milliseconds, since / until the UNIX epoch (January 1, 1970 00:00:00 UTC). +Positive numbers represent dates after, negative numbers dates before epoch. +*/ +type msSinceEpoch = float + +/** +A type representing date time format options. + +Note: There are some properties missing: +- fractionalSecondDigits +- dayPeriod +- calendar +- numberingSystem +- localeMatcher +- timeZone +- hour12 +- hourCycle +- formatMatcher + +See full spec at https://tc39.es/ecma402/#datetimeformat-objects +*/ +type localeOptions = { + dateStyle?: [#full | #long | #medium | #short], + timeStyle?: [#full | #long | #medium | #short], + weekday?: [#long | #narrow | #short], + era?: [#long | #narrow | #short], + year?: [#"2-digit" | #numeric], + month?: [#"2-digit" | #long | #narrow | #numeric | #short], + day?: [#"2-digit" | #numeric], + hour?: [#"2-digit" | #numeric], + minute?: [#"2-digit" | #numeric], + second?: [#"2-digit" | #numeric], + timeZoneName?: [#long | #short], +} + +/** +`make()` + +Creates a date object with the current date time as value. + +## Examples +```rescript +Date.make() +``` +*/ +@new +external make: unit => t = "Date" + +/** +`fromString(dateTimeString)` + +Creates a date object from given date time string. +The string has to be in the ISO 8601 format YYYY-MM-DDTHH:mm:ss.sssZ (https://tc39.es/ecma262/#sec-date-time-string-format). + +Invalid date time strings will create invalid dates. +You can use the result like any valid date, but many functions like `toString` will return "Invalid Date" or functions like `Date.getTime` will return NaN. + +## Examples +```rescript +Date.fromString("2023") // 2023-01-01T00:00:00.000Z + +Date.fromString("2023-02-20") // 2023-02-20T00:00:00.000Z + +Date.fromString("2023-02-20T16:40:00.00Z") // 2023-02-20T16:40:00.000Z + +Date.fromString("") // Invalid Date + +Date.fromString("")->Date.getTime // NaN +``` +*/ +@new +external fromString: string => t = "Date" + +/** +`fromTime(msSinceEpoch)` + +Creates a date object from the given time in milliseconds since / until UNIX epoch (January 1, 1970 00:00:00 UTC). +Positive numbers create dates after epoch, negative numbers create dates before epoch. + +## Examples +```rescript +Date.fromTime(0.0) +// 1970-01-01T00:00:00.000Z + +Date.fromTime(-86_400_000.0) +// 1969-12-31T00:00:00.000Z + +Date.fromTime(86_400_000.0) +// 1970-01-02T00:00:00.000Z +``` +*/ +@new +external fromTime: msSinceEpoch => t = "Date" + +/** +Creates a date object with the given year and month. +Be aware of using a value for year < 100, because it behaves inconsistent (see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date#interpretation_of_two-digit_years). +Months are 0-indexed (0 = January, 11 = December). +Values, which are out of range, will be carried over to the next bigger unit (s. example). + +## Examples +```rescript +Date.makeWithYM(~year=2023, ~month=0) +// 2023-01-01T00:00:00.000Z + +Date.makeWithYM(~year=2023, ~month=11) +// 2023-12-01T00:00:00.000Z + +Date.makeWithYM(~year=2023, ~month=12) +// 2024-01-01T00:00:00.000Z + +Date.makeWithYM(~year=2023, ~month=-1) +// 2022-12-01T00:00:00.000Z + +// Note: The output depends on your local time zone. +// In nodejs you can change it by using the TZ env (`export TZ='Europe/London' && node index.bs.js`) + +``` +*/ +@new +external makeWithYM: (~year: int, ~month: int) => t = "Date" + +/** +Creates a date object with the given year, month and date (day of month). +Be aware of using a value for year < 100, because it behaves inconsistent (see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date#interpretation_of_two-digit_years). +Months are 0-indexed (0 = January, 11 = December). +Values, which are out of range, will be carried over to the next bigger unit (s. example). + +## Examples +```rescript +Date.makeWithYMD(~year=2023, ~month=1, ~date=20) +// 2023-02-20T00:00:00.000Z + +Date.makeWithYMD(~year=2023, ~month=1, ~date=-1) +// 2022-11-29T00:00:00.000Z + +Date.makeWithYMD(~year=2023, ~month=1, ~date=29) +// 2023-03-01T00:00:00.000Z +``` +*/ +@new +external makeWithYMD: (~year: int, ~month: int, ~date: int) => t = "Date" + +/** +Creates a date object with the given year, month, date (day of month) and hours. +Be aware of using a value for year < 100, because it behaves inconsistent (see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date#interpretation_of_two-digit_years). +Months are 0-indexed (0 = January, 11 = December). +Values, which are out of range, will be carried over to the next bigger unit (s. example). + +## Examples +```rescript +Date.makeWithYMDH(~year=2023, ~month=1, ~date=20, ~hours=16) +// 2023-02-20T16:00:00.000Z + +Date.makeWithYMDH(~year=2023, ~month=1, ~date=20, ~hours=24) +// 2023-02-21T00:00:00.000Z + +Date.makeWithYMDH(~year=2023, ~month=1, ~date=20, ~hours=-1) +// 2023-02-19T23:00:00.000Z + +// Note: The output depends on your local time zone. +// In nodejs you can change it by using the TZ env (`export TZ='Europe/London' && node index.bs.js`) + +``` +*/ +@new +external makeWithYMDH: (~year: int, ~month: int, ~date: int, ~hours: int) => t = "Date" + +/** +Creates a date object with the given year, month, date (day of month), hours and minutes. +Be aware of using a value for year < 100, because it behaves inconsistent (see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date#interpretation_of_two-digit_years). +Months are 0-indexed (0 = January, 11 = December). +Values, which are out of range, will be carried over to the next bigger unit (s. example). + +## Examples +```rescript +Date.makeWithYMDHM(~year=2023, ~month=1, ~date=20, ~hours=16, ~minutes=40) +// 2023-02-20T16:40:00.000Z + +Date.makeWithYMDHM(~year=2023, ~month=1, ~date=20, ~hours=16, ~minutes=60) +// 2023-02-20T17:00:00.000Z + +Date.makeWithYMDHM(~year=2023, ~month=1, ~date=20, ~hours=16, ~minutes=-1) +// 2023-02-20T15:59:00.000Z + +// Note: The output depends on your local time zone. +// In nodejs you can change it by using the TZ env (`export TZ='Europe/London' && node index.bs.js`) + +``` +*/ +@new +external makeWithYMDHM: (~year: int, ~month: int, ~date: int, ~hours: int, ~minutes: int) => t = + "Date" + +/** +Creates a date object with the given year, month, date (day of month), hours, minutes and seconds. +Be aware of using a value for year < 100, because it behaves inconsistent (see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date#interpretation_of_two-digit_years). +Months are 0-indexed (0 = January, 11 = December). +Values, which are out of range, will be carried over to the next bigger unit (s. example). + +## Examples +```rescript +Date.makeWithYMDHMS(~year=2023, ~month=1, ~date=20, ~hours=16, ~minutes=40, ~seconds=0) +// 2023-02-20T16:40:00.000Z + +Date.makeWithYMDHMS(~year=2023, ~month=1, ~date=20, ~hours=16, ~minutes=40, ~seconds=60) +// 2023-02-20T16:41:00.000Z + +Date.makeWithYMDHMS(~year=2023, ~month=1, ~date=20, ~hours=16, ~minutes=40, ~seconds=-1) +// 2023-02-20T16:39:59.000Z + +// Note: The output depends on your local time zone. +// In nodejs you can change it by using the TZ env (`export TZ='Europe/London' && node index.bs.js`) + +``` +*/ +@new +external makeWithYMDHMS: ( + ~year: int, + ~month: int, + ~date: int, + ~hours: int, + ~minutes: int, + ~seconds: int, +) => t = "Date" + +/** +Creates a date object with the given year, month, date (day of month), hours, minutes, seconds and milliseconds. +Be aware of using a value for year < 100, because it behaves inconsistent (see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date#interpretation_of_two-digit_years). +Months are 0-indexed (0 = January, 11 = December). +Values, which are out of range, will be carried over to the next bigger unit (s. example). + +## Examples +```rescript +Date.makeWithYMDHMSM(~year=2023, ~month=1, ~date=20, ~hours=16, ~minutes=40, ~seconds=0, ~milliseconds=0) +// 2023-02-20T16:40:00.000Z + +Date.makeWithYMDHMSM(~year=2023, ~month=1, ~date=20, ~hours=16, ~minutes=40, ~seconds=0, ~milliseconds=1000) +// 2023-02-20T16:40:01.000Z + +Date.makeWithYMDHMSM(~year=2023, ~month=1, ~date=20, ~hours=16, ~minutes=40, ~seconds=0, ~milliseconds=-1) +// 2023-02-20T16:39:59.999Z + +// Note: The output depends on your local time zone. +// In nodejs you can change it by using the TZ env (`export TZ='Europe/London' && node index.bs.js`) + +``` +*/ +@new +external makeWithYMDHMSM: ( + ~year: int, + ~month: int, + ~date: int, + ~hours: int, + ~minutes: int, + ~seconds: int, + ~milliseconds: int, +) => t = "Date" +module UTC: { + /** + Returns the time, in milliseconds, since UNIX epoch (January 1, 1970 00:00:00 UTC). + Be aware of using a value for year < 100, because it behaves inconsistent (see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date#interpretation_of_two-digit_years). + Months are 0-indexed (0 = January, 11 = December). + Values, which are out of range, will be carried over to the next bigger unit (s. example). + + ## Examples + ```rescript + Date.UTC.makeWithYM(~year=2023, ~month=0) + // 1672531200000 + + Date.UTC.makeWithYM(~year=2023, ~month=11) + // 1701388800000 + + Date.UTC.makeWithYM(~year=2023, ~month=12) + // 1704067200000 + + Date.UTC.makeWithYM(~year=2023, ~month=-1) + // 1669852800000 + ``` + */ + @val + external makeWithYM: (~year: int, ~month: int) => msSinceEpoch = "Date.UTC" + + /** + Returns the time, in milliseconds, since UNIX epoch (January 1, 1970 00:00:00 UTC). + Be aware of using a value for year < 100, because it behaves inconsistent (see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date#interpretation_of_two-digit_years). + Months are 0-indexed (0 = January, 11 = December). + Values, which are out of range, will be carried over to the next bigger unit (s. example). + + ## Examples + ```rescript + Date.UTC.makeWithYMD(~year=2023, ~month=1, ~date=20) + // 1676851200000 + + Date.UTC.makeWithYMD(~year=2023, ~month=1, ~date=-1) + // 1675036800000 + + Date.UTC.makeWithYMD(~year=2023, ~month=1, ~date=29) + // 1677628800000 + ``` + */ + @val + external makeWithYMD: (~year: int, ~month: int, ~date: int) => msSinceEpoch = "Date.UTC" + + /** + Returns the time, in milliseconds, since UNIX epoch (January 1, 1970 00:00:00 UTC). + Be aware of using a value for year < 100, because it behaves inconsistent (see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date#interpretation_of_two-digit_years). + Months are 0-indexed (0 = January, 11 = December). + Values, which are out of range, will be carried over to the next bigger unit (s. example). + + ## Examples + ```rescript + Date.UTC.makeWithYMDH(~year=2023, ~month=1, ~date=20, ~hours=16) + // 1676908800000 + + Date.UTC.makeWithYMDH(~year=2023, ~month=1, ~date=20, ~hours=24) + // 1676937600000 + + Date.UTC.makeWithYMDH(~year=2023, ~month=1, ~date=20, ~hours=-1) + // 1676847600000 + ``` + */ + @val + external makeWithYMDH: (~year: int, ~month: int, ~date: int, ~hours: int) => msSinceEpoch = + "Date.UTC" + + /** + Returns the time, in milliseconds, since UNIX epoch (January 1, 1970 00:00:00 UTC). + Be aware of using a value for year < 100, because it behaves inconsistent (see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date#interpretation_of_two-digit_years). + Months are 0-indexed (0 = January, 11 = December). + Values, which are out of range, will be carried over to the next bigger unit (s. example). + + ## Examples + ```rescript + Date.UTC.makeWithYMDHM(~year=2023, ~month=1, ~date=20, ~hours=16, ~minutes=40) + // 1676911200000 + + Date.UTC.makeWithYMDHM(~year=2023, ~month=1, ~date=20, ~hours=16, ~minutes=60) + // 1676912400000 + + Date.UTC.makeWithYMDHM(~year=2023, ~month=1, ~date=20, ~hours=16, ~minutes=-1) + // 1676908740000 + ``` + */ + @val + external makeWithYMDHM: ( + ~year: int, + ~month: int, + ~date: int, + ~hours: int, + ~minutes: int, + ) => msSinceEpoch = "Date.UTC" + + /** + Returns the time, in milliseconds, since UNIX epoch (January 1, 1970 00:00:00 UTC). + Be aware of using a value for year < 100, because it behaves inconsistent (see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date#interpretation_of_two-digit_years). + Months are 0-indexed (0 = January, 11 = December). + Values, which are out of range, will be carried over to the next bigger unit (s. example). + + ## Examples + ```rescript + Date.UTC.makeWithYMDHMS(~year=2023, ~month=1, ~date=20, ~hours=16, ~minutes=40, ~seconds=0) + // 1676911200000 + + Date.UTC.makeWithYMDHMS(~year=2023, ~month=1, ~date=20, ~hours=16, ~minutes=40, ~seconds=60) + // 1676911260000 + + Date.UTC.makeWithYMDHMS(~year=2023, ~month=1, ~date=20, ~hours=16, ~minutes=40, ~seconds=-1) + // 1676911199000 + ``` + */ + @val + external makeWithYMDHMS: ( + ~year: int, + ~month: int, + ~date: int, + ~hours: int, + ~minutes: int, + ~seconds: int, + ) => msSinceEpoch = "Date.UTC" + + /** + Returns the time, in milliseconds, since UNIX epoch (January 1, 1970 00:00:00 UTC). + Be aware of using a value for year < 100, because it behaves inconsistent (see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date#interpretation_of_two-digit_years). + Months are 0-indexed (0 = January, 11 = December). + Values, which are out of range, will be carried over to the next bigger unit (s. example). + + ## Examples + ```rescript + Date.UTC.makeWithYMDHMSM(~year=2023, ~month=1, ~date=20, ~hours=16, ~minutes=40, ~seconds=0, ~milliseconds=0)->Console.log + // 1676911200000 + + Date.UTC.makeWithYMDHMSM(~year=2023, ~month=1, ~date=20, ~hours=16, ~minutes=40, ~seconds=0, ~milliseconds=1000)->Console.log + // 1676911201000 + + Date.UTC.makeWithYMDHMSM(~year=2023, ~month=1, ~date=20, ~hours=16, ~minutes=40, ~seconds=0, ~milliseconds=-1)->Console.log + // 1676911199999 + ``` + */ + @val + external makeWithYMDHMSM: ( + ~year: int, + ~month: int, + ~date: int, + ~hours: int, + ~minutes: int, + ~seconds: int, + ~milliseconds: int, + ) => msSinceEpoch = "Date.UTC" +} + +/** +`now()` + +Returns the time, in milliseconds, between UNIX epoch (January 1, 1970 00:00:00 UTC) and the current date time. +*/ +@val +external now: unit => msSinceEpoch = "Date.now" + +let equal: (t, t) => bool + +let compare: (t, t) => Ordering.t + +/** +`getTime(date)` + +Returns the time, in milliseconds, between UNIX epoch (January 1, 1970 00:00:00 UTC) and the current date time. +Invalid dates will return NaN. +Dates before epoch will return negative numbers. + +## Examples +```rescript +Date.fromString("2023-02-20")->Date.getTime +// 1676851200000 +``` +*/ +@send +external getTime: t => msSinceEpoch = "getTime" + +/** +`getTimezoneOffset(date)` + +Returns the time in minutes between the UTC time and the locale time. +The timezone of the given date doesn't matter. + +## Examples +```rescript +Date.fromString("2023-01-01")->Date.getTimezoneOffset +// -60 with local time zone = Europe/Berlin + +Date.fromString("2023-06-01")->Date.getTimezoneOffset +// -120 with local time zone = Europe/Berlin +``` +*/ +@send +external getTimezoneOffset: t => int = "getTimezoneOffset" + +/** +`getFullYear(date)` + +Returns the year of a given date (according to local time). + +## Examples +```rescript +Date.fromString("2023-02-20")->Date.getFullYear +// 2023 +``` +*/ +@send +external getFullYear: t => int = "getFullYear" + +/** +`getMonth(date)` + +Returns the month (0-indexed) of a given date (according to local time). + +## Examples +```rescript +Date.fromString("2023-01-01")->Date.getMonth +// 0 +``` +*/ +@send +external getMonth: t => int = "getMonth" + +/** +`getDate(date)` + +Returns the date (day of month) of a given date (according to local time). + +## Examples +```rescript +Date.fromString("2023-02-20T16:40:00.00")->Date.getDate +// 20 +``` +*/ +@send +external getDate: t => int = "getDate" + +/** +`getHours(date)` + +Returns the hours of a given date (according to local time). + +## Examples +```rescript +Date.fromString("2023-02-20T16:40:00.00")->Date.getHours +// 16 +``` +*/ +@send +external getHours: t => int = "getHours" + +/** +`getMinutes(date)` + +Returns the minutes of a given date (according to local time). + +## Examples +```rescript +Date.fromString("2023-02-20T16:40:00.00")->Date.getMinutes +// 40 +``` +*/ +@send +external getMinutes: t => int = "getMinutes" + +/** +`getSeconds(date)` + +Returns the seconds of a given date (according to local time). + +## Examples +```rescript +Date.fromString("2023-02-20T16:40:00.00")->Date.getSeconds +// 0 +``` +*/ +@send +external getSeconds: t => int = "getSeconds" + +/** +`getMilliseconds(date)` + +Returns the milliseconds of a given date (according to local time). + +## Examples +```rescript +Date.fromString("2023-02-20T16:40:00.00")->Date.getMilliseconds +// 0 +``` +*/ +@send +external getMilliseconds: t => int = "getMilliseconds" + +/** +`getDay(date)` + +Returns the day of week of a given date (according to local time). +0 = Sunday, 1 = Monday, ... 6 = Saturday + +## Examples +```rescript +Date.fromString("2023-02-20T16:40:00.00")->Date.getDay +// 1 +``` +*/ +@send +external getDay: t => int = "getDay" + +/** +`setFullYear(date, year)` + +Sets the year of a date (according to local time). +Beware this will *mutate* the date. + +## Examples +```rescript +Date.fromString("2023-02-20T16:40:00.00")->Date.setFullYear(2024) +``` +*/ +@send +external setFullYear: (t, int) => unit = "setFullYear" + +/** +`setFullYearM(date, ~year, ~month)` + +Sets the year and month of a date (according to local time). +Beware this will *mutate* the date. + +## Examples +```rescript +Date.fromString("2023-02-20T16:40:00.00")->Date.setFullYearM(~year=2024, ~month=0) +``` +*/ +@send +external setFullYearM: (t, ~year: int, ~month: int) => unit = "setFullYear" + +/** +`setFullYearMD(date, ~year, ~month, ~date)` + +Sets the year, month and date (day of month) of a date (according to local time). +Beware this will *mutate* the date. + +## Examples +```rescript +Date.fromString("2023-02-20T16:40:00.00")->Date.setFullYearMD(~year=2024, ~month=0, ~date=1) +``` +*/ +@send +external setFullYearMD: (t, ~year: int, ~month: int, ~date: int) => unit = "setFullYear" + +/** +`setMonth(date, month)` + +Sets the month of a date (according to local time). +Beware this will *mutate* the date. + +## Examples +```rescript +Date.fromString("2023-02-20T16:40:00.00")->Date.setMonth(0) +``` +*/ +@send +external setMonth: (t, int) => unit = "setMonth" + +/** +`setDate(date, day)` + +Sets the date (day of month) of a date (according to local time). +Beware this will *mutate* the date. + +## Examples +```rescript +Date.fromString("2023-02-20T16:40:00.00")->Date.setDate(1) +``` +*/ +@send +external setDate: (t, int) => unit = "setDate" + +/** +`setHours(date, hours)` + +Sets the hours of a date (according to local time). +Beware this will *mutate* the date. + +## Examples +```rescript +Date.fromString("2023-02-20T16:40:00.00")->Date.setHours(0) +``` +*/ +@send +external setHours: (t, int) => unit = "setHours" + +/** +`setHoursM(date, ~hours, ~minutes)` + +Sets the hours and minutes of a date (according to local time). +Beware this will *mutate* the date. + +## Examples +```rescript +Date.fromString("2023-02-20T16:40:00.00")->Date.setHoursM(~hours=0, ~minutes=0) +``` +*/ +@send +external setHoursM: (t, ~hours: int, ~minutes: int) => unit = "setHours" + +/** +`setHoursMS(date, ~hours, ~minutes, ~seconds)` + +Sets the hours, minutes and seconds of a date (according to local time). +Beware this will *mutate* the date. + +## Examples +```rescript +Date.fromString("2023-02-20T16:40:00.00")->Date.setHoursMS(~hours=0, ~minutes=0, ~seconds=0) +``` +*/ +@send +external setHoursMS: (t, ~hours: int, ~minutes: int, ~seconds: int) => unit = "setHours" + +/** +`setHoursMSMs(date, ~hours, ~minutes, ~seconds, ~milliseconds)` + +Sets the hours, minutes, seconds and milliseconds of a date (according to local time). +Beware this will *mutate* the date. + +## Examples +```rescript +Date.fromString("2023-02-20T16:40:00.00")->Date.setHoursMSMs(~hours=0, ~minutes=0, ~seconds=0, ~milliseconds=0) +``` +*/ +@send +external setHoursMSMs: (t, ~hours: int, ~minutes: int, ~seconds: int, ~milliseconds: int) => unit = + "setHours" + +/** +`setMinutes(date, minutes)` + +Sets the minutes of a date (according to local time). +Beware this will *mutate* the date. + +## Examples +```rescript +Date.fromString("2023-02-20T16:40:00.00")->Date.setMinutes(0) +``` +*/ +@send +external setMinutes: (t, int) => unit = "setMinutes" + +/** +`setMinutesS(date, ~minutes, ~seconds)` + +Sets the minutes and seconds of a date (according to local time). +Beware this will *mutate* the date. + +## Examples +```rescript +Date.fromString("2023-02-20T16:40:00.00")->Date.setMinutesS(~minutes=0, ~seconds=0) +``` +*/ +@send +external setMinutesS: (t, ~minutes: int, ~seconds: int) => unit = "setMinutes" + +/** +`setMinutesSMs(date, ~minutes, ~seconds, ~milliseconds)` + +Sets the minutes, seconds and milliseconds of a date (according to local time). +Beware this will *mutate* the date. + +## Examples +```rescript +Date.fromString("2023-02-20T16:40:00.00")->Date.setMinutesSMs(~minutes=0, ~seconds=0, ~milliseconds=0) +``` +*/ +@send +external setMinutesSMs: (t, ~minutes: int, ~seconds: int, ~milliseconds: int) => unit = "setMinutes" + +/** +`setSeconds(date, seconds)` + +Sets the seconds of a date (according to local time). +Beware this will *mutate* the date. + +## Examples +```rescript +Date.fromString("2023-02-20T16:40:00.00")->Date.setSeconds(0) +``` +*/ +@send +external setSeconds: (t, int) => unit = "setSeconds" + +/** +`setSecondsMs(date, ~seconds, ~milliseconds)` + +Sets the seconds and milliseconds of a date (according to local time). +Beware this will *mutate* the date. + +## Examples +```rescript +Date.fromString("2023-02-20T16:40:00.00")->Date.setSecondsMs(~seconds=0, ~milliseconds=0) +``` +*/ +@send +external setSecondsMs: (t, ~seconds: int, ~milliseconds: int) => unit = "setSeconds" + +/** +`setMilliseconds(date, milliseconds)` + +Sets the milliseconds of a date (according to local time). +Beware this will *mutate* the date. + +## Examples +```rescript +Date.fromString("2023-02-20T16:40:00.00")->Date.setMilliseconds(0) +``` +*/ +@send +external setMilliseconds: (t, int) => unit = "setMilliseconds" + +/** +`getUTCFullYear(date)` + +Returns the year of a given date (according to UTC time). + +## Examples +```rescript +Date.fromString("2023-01-01T00:00:00.00+01:00")->Date.getUTCFullYear // 2022 +``` +*/ +@send +external getUTCFullYear: t => int = "getUTCFullYear" + +/** +`getUTCMonth(date)` + +Returns the month of a given date (according to UTC time). + +## Examples +```rescript +Date.fromString("2023-01-01T00:00:00.00+01:00")->Date.getUTCMonth // 11 +``` +*/ +@send +external getUTCMonth: t => int = "getUTCMonth" + +/** +`getUTCDate(date)` + +Returns the date (day of month) of a given date (according to UTC time). + +## Examples +```rescript +Date.fromString("2023-01-01T00:00:00.00+01:00")->Date.getUTCDate // 31 +``` +*/ +@send +external getUTCDate: t => int = "getUTCDate" + +/** +`getUTCHours(date)` + +Returns the hours of a given date (according to UTC time). + +## Examples +```rescript +Date.fromString("2023-01-01T00:00:00.00+01:00")->Date.getUTCHours // 23 +``` +*/ +@send +external getUTCHours: t => int = "getUTCHours" + +/** +`getUTCMinutes(date)` + +Returns the minutes of a given date (according to UTC time). + +## Examples +```rescript +Date.fromString("2023-01-01T00:00:00.00+01:00")->Date.getUTCMinutes // 0 +``` +*/ +@send +external getUTCMinutes: t => int = "getUTCMinutes" + +/** +`getUTCSeconds(date)` + +Returns the seconds of a given date (according to UTC time). + +## Examples +```rescript +Date.fromString("2023-01-01T00:00:00.00+01:00")->Date.getUTCSeconds // 0 +``` +*/ +@send +external getUTCSeconds: t => int = "getUTCSeconds" + +/** +`getUTCMilliseconds(date)` + +Returns the milliseconds of a given date (according to UTC time). + +## Examples +```rescript +Date.fromString("2023-01-01T00:00:00.00+01:00")->Date.getUTCMilliseconds // 0 +``` +*/ +@send +external getUTCMilliseconds: t => int = "getUTCMilliseconds" + +/** +`getUTCDay(date)` + +Returns the day (day of week) of a given date (according to UTC time). +0 = Sunday, 1 = Monday, ... 6 = Saturday + +## Examples +```rescript +Date.fromString("2023-01-01T00:00:00.00+01:00")->Date.getUTCDay // 6 +``` +*/ +@send +external getUTCDay: t => int = "getUTCDay" + +/** +`setUTCFullYear(date, year)` + +Sets the year of a date (according to UTC time). +Beware this will *mutate* the date. + +## Examples +```rescript +Date.fromString("2023-02-20T16:40:00.00")->Date.setUTCFullYear(2024) +``` +*/ +@send +external setUTCFullYear: (t, int) => unit = "setUTCFullYear" + +/** +`setUTCFullYearM(date, ~year, ~month)` + +Sets the year and month of a date (according to UTC time). +Beware this will *mutate* the date. + +## Examples +```rescript +Date.fromString("2023-02-20T16:40:00.00")->Date.setUTCFullYearM(~year=2024, ~month=0) +``` +*/ +@send +external setUTCFullYearM: (t, ~year: int, ~month: int) => unit = "setUTCFullYear" + +/** +`setUTCFullYearMD(date, ~year, ~month, ~date)` + +Sets the year, month and date (day of month) of a date (according to UTC time). +Beware this will *mutate* the date. + +## Examples +```rescript +Date.fromString("2023-02-20T16:40:00.00")->Date.setUTCFullYearMD(~year=2024, ~month=0, ~date=1) +``` +*/ +@send +external setUTCFullYearMD: (t, ~year: int, ~month: int, ~date: int) => unit = "setUTCFullYear" + +/** +`setUTCMonth(date, month)` + +Sets the month of a date (according to UTC time). +Beware this will *mutate* the date. + +## Examples +```rescript +Date.fromString("2023-02-20T16:40:00.00")->Date.setUTCMonth(0) +``` +*/ +@send +external setUTCMonth: (t, int) => unit = "setUTCMonth" + +/** +`setDate(date, day)` + +Sets the date (day of month) of a date (according to UTC time). +Beware this will *mutate* the date. + +## Examples +```rescript +Date.fromString("2023-02-20T16:40:00.00")->Date.setUTCDate(1) +``` +*/ +@send +external setUTCDate: (t, int) => unit = "setUTCDate" + +/** +`setUTCHours(date, hours)` + +Sets the hours of a date (according to UTC time). +Beware this will *mutate* the date. + +## Examples +```rescript +Date.fromString("2023-02-20T16:40:00.00")->Date.setUTCHours(0) +``` +*/ +@send +external setUTCHours: (t, int) => unit = "setUTCHours" + +/** +`setHoursM(date, ~hours, ~minutes)` + +Sets the hours and minutes of a date (according to UTC time). +Beware this will *mutate* the date. + +## Examples +```rescript +Date.fromString("2023-02-20T16:40:00.00")->Date.setUTCHoursM(~hours=0, ~minutes=0) +``` +*/ +@send +external setUTCHoursM: (t, ~hours: int, ~minutes: int) => unit = "setUTCHours" + +/** +`setUTCHoursMS(date, ~hours, ~minutes, ~seconds)` + +Sets the hours, minutes and seconds of a date (according to UTC time). +Beware this will *mutate* the date. + +## Examples +```rescript +Date.fromString("2023-02-20T16:40:00.00")->Date.setUTCHoursMS(~hours=0, ~minutes=0, ~seconds=0) +``` +*/ +@send +external setUTCHoursMS: (t, ~hours: int, ~minutes: int, ~seconds: int) => unit = "setUTCHours" + +/** +`setUTCHoursMSMs(date, ~hours, ~minutes, ~seconds, ~milliseconds)` + +Sets the hours, minutes, seconds and milliseconds of a date (according to UTC time). +Beware this will *mutate* the date. + +## Examples +```rescript +Date.fromString("2023-02-20T16:40:00.00")->Date.setUTCHoursMSMs(~hours=0, ~minutes=0, ~seconds=0, ~milliseconds=0) +``` +*/ +@send +external setUTCHoursMSMs: ( + t, + ~hours: int, + ~minutes: int, + ~seconds: int, + ~milliseconds: int, +) => unit = "setUTCHours" + +/** +`setUTCMinutes(date, minutes)` + +Sets the minutes of a date (according to UTC time). +Beware this will *mutate* the date. + +## Examples +```rescript +Date.fromString("2023-02-20T16:40:00.00")->Date.setUTCMinutes(0) +``` +*/ +@send +external setUTCMinutes: (t, int) => unit = "setUTCMinutes" + +/** +`setUTCMinutesS(date, ~minutes, ~seconds)` + +Sets the minutes and seconds of a date (according to UTC time). +Beware this will *mutate* the date. + +## Examples +```rescript +Date.fromString("2023-02-20T16:40:00.00")->Date.setUTCMinutesS(~minutes=0, ~seconds=0) +``` +*/ +@send +external setUTCMinutesS: (t, ~minutes: int, ~seconds: int) => unit = "setUTCMinutes" + +/** +`setUTCMinutesSMs(date, ~minutes, ~seconds, ~milliseconds)` + +Sets the minutes, seconds and milliseconds of a date (according to UTC time). +Beware this will *mutate* the date. + +## Examples +```rescript +Date.fromString("2023-02-20T16:40:00.00")->Date.setUTCMinutesSMs(~minutes=0, ~seconds=0, ~milliseconds=0) +``` +*/ +@send +external setUTCMinutesSMs: (t, ~minutes: int, ~seconds: int, ~milliseconds: int) => unit = + "setUTCMinutes" + +/** +`setUTCSeconds(date, seconds)` + +Sets the seconds of a date (according to UTC time). +Beware this will *mutate* the date. + +## Examples +```rescript +Date.fromString("2023-02-20T16:40:00.00")->Date.setUTCSeconds(0) +``` +*/ +@send +external setUTCSeconds: (t, int) => unit = "setUTCSeconds" + +/** +`setUTCSecondsMs(date, ~seconds, ~milliseconds)` + +Sets the seconds and milliseconds of a date (according to UTC time). +Beware this will *mutate* the date. + +## Examples +```rescript +Date.fromString("2023-02-20T16:40:00.00")->Date.setUTCSecondsMs(~seconds=0, ~milliseconds=0) +``` +*/ +@send +external setUTCSecondsMs: (t, ~seconds: int, ~milliseconds: int) => unit = "setUTCSeconds" + +/** +`setUTCMilliseconds(date, milliseconds)` + +Sets the milliseconds of a date (according to UTC time). +Beware this will *mutate* the date. + +## Examples +```rescript +Date.fromString("2023-02-20T16:40:00.00")->Date.setUTCMilliseconds(0) +``` +*/ +@send +external setUTCMilliseconds: (t, int) => unit = "setUTCMilliseconds" + +/** +`toDateString(date)` + +Converts a JavaScript date to a standard date string. The date will be mapped to the current time zone. +If you want to convert it to a localized string, use `Date.toLocaleDateString` instead. + +## Examples +```rescript +Date.fromString("2023-01-01T00:00:00.00+01:00")->Date.toDateString->Console.log +// Sun Jan 01 2023 + +Date.fromString("2023-01-01T00:00:00.00+08:00")->Date.toDateString->Console.log +// Sat Dec 31 2022 +``` +*/ +@send +external toDateString: t => string = "toDateString" + +/** +`toString(date)` + +Converts a JavaScript date to a standard date time string. The date will be mapped to the current time zone. +If you want to convert it to a localized string, use `Date.toLocaleString` instead. + +## Examples +```rescript +Date.fromString("2023-01-01T00:00:00.00+01:00")->Date.toString->Console.log +// Sun Jan 01 2023 00:00:00 GMT+0100 (Central European Standard Time) + +Date.fromString("2023-06-01T00:00:00.00+01:00")->Date.toString->Console.log +// Thu Jun 01 2023 01:00:00 GMT+0200 (Central European Summer Time) +``` +*/ +@send +external toString: t => string = "toString" + +/** +`toTimeString(date)` + +Converts a JavaScript date to a standard time string. The date will be mapped to the current time zone. +If you want to convert it to a localized string, use `Date.toLocaleStimeString` instead. + +## Examples +```rescript +Date.fromString("2023-01-01T00:00:00.00+01:00")->Date.toTimeString->Console.log +// 00:00:00 GMT+0100 (Central European Standard Time) + +Date.fromString("2023-01-01T00:00:00.00+08:00")->Date.toTimeString->Console.log +// 17:00:00 GMT+0100 (Central European Standard Time) +``` +*/ +@send +external toTimeString: t => string = "toTimeString" + +/** +`toLocaleDateString(date)` + +Converts a JavaScript date to a localized date string. It will use the current locale. + +## Examples +```rescript +Date.make()->Date.toLocaleDateString->Console.log +// 2/19/2023 +``` +*/ +@send +external toLocaleDateString: t => string = "toLocaleDateString" + +/** +`toLocaleDateStringWithLocale(date, locale)` + +Converts a JavaScript date to a localized date string. It will use the specified locale. + +## Examples +```rescript +Date.make()->Date.toLocaleDateStringWithLocale("en-US")->Console.log +// 2/19/2023 +``` +*/ +@send +external toLocaleDateStringWithLocale: (t, string) => string = "toLocaleDateString" + +/** +`toLocaleDateStringWithLocaleAndOptions(date, locale, options)` + +Converts a JavaScript date to a localized date string. It will use the specified locale and formatting options. + +## Examples +```rescript +Date.make()->Date.toLocaleDateStringWithLocaleAndOptions("en-US", { dateStyle: #long })->Console.log +// February 19, 2023 + +Date.make()->Date.toLocaleDateStringWithLocaleAndOptions("de", { hour: #"2-digit", minute: #"2-digit" })->Console.log +// 19.2.2023, 15:40 + +Date.make()->Date.toLocaleDateStringWithLocaleAndOptions("de", { year: #numeric })->Console.log +// 2023 +``` +*/ +@send +external toLocaleDateStringWithLocaleAndOptions: (t, string, localeOptions) => string = + "toLocaleDateString" + +/** +`toLocaleString(date)` + +Converts a JavaScript date to a localized date-time string. It will use the current locale. + +## Examples +```rescript +Date.make()->Date.toLocaleString->Console.log +// 2/19/2023, 3:40:00 PM +``` +*/ +@send +external toLocaleString: t => string = "toLocaleString" + +/** +`toLocaleStringWithLocale(date, locale)` + +Converts a JavaScript date to a localized date-time string. It will use the specified locale. + +## Examples +```rescript +Date.make()->Date.toLocaleStringWithLocale("en-US")->Console.log +// 2/19/2023, 3:40:00 PM +``` +*/ +@send +external toLocaleStringWithLocale: (t, string) => string = "toLocaleString" + +/** +`toLocaleStringWithLocaleAndOptions(date, locale, options)` + +Converts a JavaScript date to a localized date-time string. It will use the specified locale and formatting options. + +## Examples +```rescript +Date.make()->Date.toLocaleStringWithLocaleAndOptions("en", { dateStyle: #short, timeStyle: #short })->Console.log +// 2/19/23, 3:40 PM + +Date.make()->Date.toLocaleStringWithLocaleAndOptions("en", { era: #long, year: #numeric, month: #"2-digit", day: #"2-digit", hour: #numeric, timeZoneName: #short })->Console.log +// 02/19/2023 Anno Domini, 3 PM GMT+1 +``` +*/ +@send +external toLocaleStringWithLocaleAndOptions: (t, string, localeOptions) => string = "toLocaleString" + +/** +`toLocaleTimeString(date)` + +Converts a JavaScript date to a localized time string. It will use the current locale. + +## Examples +```rescript +Date.make()->Date.toLocaleTimeString->Console.log +// 3:40:00 PM +``` +*/ +@send +external toLocaleTimeString: t => string = "toLocaleTimeString" + +/** +`toLocaleTimeStringWithLocale(date, locale)` + +Converts a JavaScript date to a localized time string. It will use the specified locale. + +## Examples +```rescript +Date.make()->Date.toLocaleTimeStringWithLocale("en-US")->Console.log +// 3:40:00 PM +``` +*/ +@send +external toLocaleTimeStringWithLocale: (t, string) => string = "toLocaleTimeString" + +/** +`toLocaleTimeStringWithLocaleAndOptions(date, locale, options)` + +Converts a JavaScript date to a localized time string. It will use the specified locale and formatting options. + +## Examples +```rescript +Date.make()->Date.toLocaleTimeStringWithLocaleAndOptions("en-US", { timeStyle: #long })->Console.log +// 3:40:00 PM GMT+1 + +Date.make()->Date.toLocaleTimeStringWithLocaleAndOptions("de", { hour: #"2-digit", minute: #"2-digit" })->Console.log +// 15:40 +``` +*/ +@send +external toLocaleTimeStringWithLocaleAndOptions: (t, string, localeOptions) => string = + "toLocaleTimeString" + +/** +`toISOString(date)` + +Converts a JavaScript date to a ISO 8601 string (YYYY-MM-DDTHH:mm:ss.sssZ). The date will be mapped to the UTC time. + +## Examples +```rescript +Date.fromString("2023-01-01T00:00:00.00+00:00")->Date.toISOString->Console.log +// 2023-01-01T00:00:00.000Z + +Date.fromString("2023-01-01T00:00:00.00+08:00")->Date.toISOString->Console.log +// 2022-12-31T16:00:00.000Z +``` +*/ +@send +external toISOString: t => string = "toISOString" + +/** +`toUTCString(date)` + +Converts a JavaScript date to date time string. The date will be mapped to the UTC time. + +## Examples +```rescript +Date.fromString("2023-01-01T00:00:00.00+00:00")->Date.toUTCString->Console.log +// Sun, 01 Jan 2023 00:00:00 GMT + +Date.fromString("2023-01-01T00:00:00.00+08:00")->Date.toUTCString->Console.log +// Sat, 31 Dec 2022 16:00:00 GMT +``` +*/ +@send +external toUTCString: t => string = "toUTCString" + +/** +`toJSON(date)` + +Converts a JavaScript date to a string. +If the date is valid, the function will return the same result as `Date.toISOString`. +Invalid dates will return `None`. + +## Examples +```rescript +Date.fromString("2023-01-01T00:00:00.00+00:00")->Date.toJSON +// Some("2023-01-01T00:00:00.000Z") + +Date.fromString("")->Date.toJSON +// None +``` +*/ +@return(nullable) +@send +external toJSON: t => option = "toJSON" diff --git a/runtime/Dict.res b/runtime/Dict.res new file mode 100644 index 0000000000..c56ecdc783 --- /dev/null +++ b/runtime/Dict.res @@ -0,0 +1,41 @@ +type t<'a> = Js.Dict.t<'a> + +@get_index external getUnsafe: (t<'a>, string) => 'a = "" +@get_index external get: (t<'a>, string) => option<'a> = "" +@set_index external set: (t<'a>, string, 'a) => unit = "" +@val external delete: 'a => unit = "delete" + +let delete = (dict, string) => { + delete(get(dict, string)) +} + +@obj external make: unit => t<'a> = "" + +@val external fromArray: array<(string, 'a)> => t<'a> = "Object.fromEntries" +@val external fromIterator: Iterator.t<(string, 'a)> => t<'a> = "Object.fromEntries" + +@val external toArray: t<'a> => array<(string, 'a)> = "Object.entries" + +@val external keysToArray: t<'a> => array = "Object.keys" + +@val external valuesToArray: t<'a> => array<'a> = "Object.values" + +@val external assign: (t<'a>, t<'a>) => t<'a> = "Object.assign" + +@val external copy: (@as(json`{}`) _, t<'a>) => t<'a> = "Object.assign" + +let forEach = (dict, f) => { + dict->valuesToArray->Array.forEach(value => f(value)) +} + +let forEachWithKey = (dict, f) => { + dict->toArray->Array.forEach(((key, value)) => f(value, key)) +} + +let mapValues = (dict, f) => { + let target = make() + dict->forEachWithKey((value, key) => { + target->set(key, f(value)) + }) + target +} diff --git a/runtime/Dict.resi b/runtime/Dict.resi new file mode 100644 index 0000000000..2850a12d20 --- /dev/null +++ b/runtime/Dict.resi @@ -0,0 +1,234 @@ +/*** +A mutable dictionary with string keys. + +Compiles to a regular JavaScript object.*/ + +/** +Type representing a dictionary of value `'a`. +*/ +type t<'a> = Js.Dict.t<'a> + +/** +`getUnsafe(dict, key)` Returns the `value` at the provided `key`. + +This is _unsafe_, meaning it will return `undefined` value if `key` does not exist in `dict`. + +Use `Dict.getUnsafe` only when you are sure the key exists (i.e. when iterating `Dict.keys` result). + +## Examples +```rescript +let dict = Dict.fromArray([("key1", "value1"), ("key2", "value2")]) +let value = dict->Dict.getUnsafe("key1") +Console.log(value) // value1 +``` +*/ +@get_index +external getUnsafe: (t<'a>, string) => 'a = "" + +/** +Returns the value at the provided key, if it exists. Returns an option. + +## Examples +```rescript +let dict = Dict.fromArray([("someKey", "someValue")]) + +switch dict->Dict.get("someKey") { +| None => Console.log("Nope, didn't have the key.") +| Some(value) => Console.log(value) +} +``` +*/ +@get_index +external get: (t<'a>, string) => option<'a> = "" + +/** +`set(dictionary, key, value)` sets the value at the provided key to the provided value. + +## Examples +```rescript +let dict = Dict.make() + +dict->Dict.set("someKey", "someValue") +``` +*/ +@set_index +external set: (t<'a>, string, 'a) => unit = "" + +/** +`delete(dictionary, key)` deletes the value at `key`, if it exists. + +## Examples +```rescript +let dict = Dict.fromArray([("someKey", "someValue")]) + +dict->Dict.delete("someKey") +``` +*/ +let delete: (t<'a>, string) => unit + +/** +`make()` creates a new, empty dictionary. + +## Examples +```rescript +let dict1: Dict.t = Dict.make() // You can annotate the type of the values of your dict yourself if you want + +let dict2 = Dict.make() // Or you can let ReScript infer it via usage. +dict2->Dict.set("someKey", 12) +``` +*/ +@obj +external make: unit => t<'a> = "" + +/** +`fromArray(entries)` creates a new dictionary from the provided array of key/value pairs. + +## Examples +```rescript +let dict = Dict.fromArray([("key1", "value1"), ("key2", "value2")]) +``` +*/ +@val +external fromArray: array<(string, 'a)> => t<'a> = "Object.fromEntries" + +/** +`fromIterator(entries)` creates a new dictionary from the provided iterator of key/value pairs. + +## Examples +```rescript +// Pretend we have an iterator of the correct shape +@val external someIterator: Iterator.t<(string, int)> = "someIterator" + +let dict = Dict.fromIterator(someIterator) // Dict.t +``` +*/ +@val +external fromIterator: Iterator.t<(string, 'a)> => t<'a> = "Object.fromEntries" + +/** +`toArray(dictionary)` returns an array of all the key/value pairs of the dictionary. + +## Examples +```rescript +let dict = Dict.make() +dict->Dict.set("someKey", 1) +dict->Dict.set("someKey2", 2) +let asArray = dict->Dict.toArray +Console.log(asArray) // Logs `[["someKey", 1], ["someKey2", 2]]` to the console +``` +*/ +@val +external toArray: t<'a> => array<(string, 'a)> = "Object.entries" + +/** +`keysToArray(dictionary)` returns an array of all the keys of the dictionary. + +## Examples +```rescript +let dict = Dict.make() +dict->Dict.set("someKey", 1) +dict->Dict.set("someKey2", 2) +let keys = dict->Dict.keysToArray +Console.log(keys) // Logs `["someKey", "someKey2"]` to the console +``` +*/ +@val +external keysToArray: t<'a> => array = "Object.keys" + +/** +`valuesToArray(dictionary)` returns an array of all the values of the dictionary. + +## Examples +```rescript +let dict = Dict.make() +dict->Dict.set("someKey", 1) +dict->Dict.set("someKey2", 2) +let values = dict->Dict.valuesToArray +Console.log(values) // Logs `[1, 2]` to the console +``` +*/ +@val +external valuesToArray: t<'a> => array<'a> = "Object.values" + +/** +`assign(dictionary1, dictionary2)` [shallowly](https://developer.mozilla.org/en-US/docs/Glossary/Shallow_copy) merges dictionary2 into dictionary1, and returns dictionary1. + +Beware this will *mutate* dictionary1. If you're looking for a way to copy a dictionary, check out `Dict.copy`. + +## Examples +```rescript +let dict1 = Dict.make() +dict1->Dict.set("firstKey", 1) +Console.log(dict1->Dict.keysToArray) // Logs `["firstKey"]` + +let dict2 = Dict.make() +dict2->Dict.set("someKey", 2) +dict2->Dict.set("someKey2", 3) + +let dict1 = dict1->Dict.assign(dict2) + +Console.log(dict1->Dict.keysToArray) // Logs `["firstKey", "someKey", "someKey2"]` + +``` +*/ +@val +external assign: (t<'a>, t<'a>) => t<'a> = "Object.assign" + +/** +`copy(dictionary)` [shallowly copies](https://developer.mozilla.org/en-US/docs/Glossary/Shallow_copy) the provided dictionary to a new dictionary. + +## Examples +```rescript +let dict = Dict.fromArray([("key1", "value1"), ("key2", "value2")]) +let dict2 = dict->Dict.copy + +// Both log `["key1", "key2"]` here. +Console.log2(dict->Dict.keysToArray, dict2->Dict.keysToArray) +``` +*/ +@val +external copy: (@as(json`{}`) _, t<'a>) => t<'a> = "Object.assign" + +/** +`forEach(dictionary, f)` iterates through all values of the dict. + +> Please note that this is *without the keys*, just the values. If you need the key as well, use `Dict.forEachWithKey`. + +## Examples +```rescript +let dict = Dict.fromArray([("key1", "value1"), ("key2", "value2")]) + +dict->Dict.forEach(value => { + Console.log(value) +}) +``` +*/ +let forEach: (t<'a>, 'a => unit) => unit + +/** +`forEachWithKey(dictionary, f)` iterates through all values of the dict, including the key for each value. + +## Examples +```rescript +let dict = Dict.fromArray([("key1", "value1"), ("key2", "value2")]) + +dict->Dict.forEachWithKey((value, key) => { + Console.log2(value, key) +}) +``` +*/ +let forEachWithKey: (t<'a>, ('a, string) => unit) => unit + +/** +`mapValues(dictionary, f)` returns a new dictionary with the same keys, and `f` applied to each value in the original dictionary. + +## Examples + +```rescript +let dict = Dict.fromArray([("key1", 1), ("key2", 2)]) + +dict->Dict.mapValues(v => v + 10)->Dict.toArray // [("key1", 11), ("key2", 12)] +dict->Dict.mapValues(v => Int.toString(v))->Dict.toArray // [("key1", "1"), ("key2", "2")] +``` +*/ +let mapValues: (t<'a>, 'a => 'b) => t<'b> diff --git a/runtime/Error.res b/runtime/Error.res new file mode 100644 index 0000000000..408b08ff56 --- /dev/null +++ b/runtime/Error.res @@ -0,0 +1,39 @@ +type t = Js.Exn.t + +external fromException: exn => option = "?as_js_exn" +external toException: t => exn = "%identity" + +@get external stack: t => option = "stack" +@get external message: t => option = "message" +@get external name: t => option = "name" +@get external fileName: t => option = "fileName" + +@new external make: string => t = "Error" + +module EvalError = { + @new external make: string => t = "EvalError" +} + +module RangeError = { + @new external make: string => t = "RangeError" +} + +module ReferenceError = { + @new external make: string => t = "ReferenceError" +} + +module SyntaxError = { + @new external make: string => t = "SyntaxError" +} + +module TypeError = { + @new external make: string => t = "TypeError" +} + +module URIError = { + @new external make: string => t = "URIError" +} + +external raise: t => 'a = "%raise" + +let panic = msg => make(`Panic! ${msg}`)->raise diff --git a/runtime/Error.resi b/runtime/Error.resi new file mode 100644 index 0000000000..38b6a97334 --- /dev/null +++ b/runtime/Error.resi @@ -0,0 +1,172 @@ +/*** +Functions for working with JavaScript exceptions. + +See [`Error`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error) on MDN. +*/ + +/** Represents a JavaScript exception. */ +type t = Js.Exn.t + +external fromException: exn => option = "?as_js_exn" + +/** +Turns an `Error.t` into an `exn`. + +## Examples +```rescript +let error = Error.make("Something went wrong.") + +let asExn = error->Error.toException // `asExn` is now type `exn` +``` +*/ +external toException: t => exn = "%identity" + +/** +`stack(error)` retrieves the `stack` property of the error, if it exists. The stack is a list of what functions were called, and what files they are defined in, prior to the error happening. + +See [`Error.prototype.stack`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error/Stack) on MDN. + +## Example +```rescript +let error = Error.make("error") +Console.log(error->Error.stack) // Logs `stack` if it exists on `someError` +``` +*/ +@get +external stack: t => option = "stack" + +/** +`message(error)` retrieves the `message` property of the error, if it exists. + +See [`Error.prototype.message`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error/message) on MDN. + +## Example +```rescript +let error = Error.SyntaxError.make("Some message here") +Console.log(error->Error.message) // Logs "Some message here" to the console +``` +*/ +@get +external message: t => option = "message" + +/** +`name(error)` retrieves the `name` property of the error, if it exists. + +See [`Error.prototype.name`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error/name) on MDN. + +## Example +```rescript +let error = Error.SyntaxError.make("Some message here") +Console.log(error->Error.name) // Logs "SyntaxError" to the console +``` +*/ +@get +external name: t => option = "name" + +/** +`fileName(error)` retrieves the `fileName` property of the error, if it exists. + +See [`Error.prototype.fileName`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error/fileName) on MDN. +*/ +@get +external fileName: t => option = "fileName" + +/** +`make(message)` creates a new error, setting its `message` to the provided value. + +See [`Error`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error/Error) on MDN. + +## Example +```rescript +let error = Error.make("Some message here") +Console.log(error->Error.message) // Logs "Some message here" to the console +Console.log(error->Error.name) // Logs "Error" to the console, because this is a regular error +``` +*/ +@new +external make: string => t = "Error" + +module EvalError: { + /** + Creates a new `EvalError` with the provided `message`. + + See [`EvalError`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/EvalError) on MDN. + */ + @new + external make: string => t = "EvalError" +} +module RangeError: { + /** + Creates a new `RangeError` with the provided `message`. + + See [`RangeError`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RangeError) on MDN. + */ + @new + external make: string => t = "RangeError" +} +module ReferenceError: { + /** + Creates a new `ReferenceError` with the provided `message`. + + See [`ReferenceError`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ReferenceError) on MDN. + */ + @new + external make: string => t = "ReferenceError" +} +module SyntaxError: { + /** + Creates a new `SyntaxError` with the provided `message`. + + See [`SyntaxError`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SyntaxError) on MDN. + */ + @new + external make: string => t = "SyntaxError" +} +module TypeError: { + /** + Creates a new `TypeError` with the provided `message`. + + See [`TypeError`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypeError) on MDN. + */ + @new + external make: string => t = "TypeError" +} +module URIError: { + /** + Creates a new `URIError` with the provided `message`. + + See [`URIError`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/URIError) on MDN. + */ + @new + external make: string => t = "URIError" +} + +/** +Raises (throws in JavaScript language) the provided `Error.t`, which will stop execution. + +## Examples +```rescript +let error = Error.make("Everything is upside down.") + +if 5 > 10 { + error->Error.raise +} else { + Console.log("Phew, sanity still rules.") +} +``` +*/ +external raise: t => 'a = "%raise" + +/** +Raises a panic exception with the given message. + +A panic exception is a native JavaScript exception that is not intended to be caught and +handled. Compared to a ReScript exception this will give a better stack trace and +debugging experience. + +## Examples +```rescript +Error.panic("Uh oh. This was unexpected!") +``` +*/ +let panic: string => 'a diff --git a/runtime/Js_exn.res b/runtime/Exn.res similarity index 100% rename from runtime/Js_exn.res rename to runtime/Exn.res diff --git a/runtime/Js_exn.resi b/runtime/Exn.resi similarity index 100% rename from runtime/Js_exn.resi rename to runtime/Exn.resi diff --git a/runtime/Float.res b/runtime/Float.res new file mode 100644 index 0000000000..8c7c2ad60c --- /dev/null +++ b/runtime/Float.res @@ -0,0 +1,59 @@ +module Constants = { + @val external nan: float = "NaN" + @val external epsilon: float = "Number.EPSILON" + @val external positiveInfinity: float = "Number.POSITIVE_INFINITY" + @val external negativeInfinity: float = "Number.NEGATIVE_INFINITY" + @val external minValue: float = "Number.MIN_VALUE" + @val external maxValue: float = "Number.MAX_VALUE" +} + +external equal: (float, float) => bool = "%equal" + +external compare: (float, float) => Ordering.t = "%compare" + +@val external isNaN: float => bool = "isNaN" +@val external isFinite: float => bool = "isFinite" +@val external parseFloat: 'a => float = "parseFloat" +// parseInt's return type is a float because it can be NaN +@val external parseInt: ('a, ~radix: int=?) => float = "parseInt" +@deprecated("Use `parseInt` instead") @val +external parseIntWithRadix: ('a, ~radix: int) => float = "parseInt" + +@send external toExponential: (float, ~digits: int=?) => string = "toExponential" +@deprecated("Use `toExponential` instead") @send +external toExponentialWithPrecision: (float, ~digits: int) => string = "toExponential" + +@send external toFixed: (float, ~digits: int=?) => string = "toFixed" +@deprecated("Use `toFixed` instead") @send +external toFixedWithPrecision: (float, ~digits: int) => string = "toFixed" + +@send external toPrecision: (float, ~digits: int=?) => string = "toPrecision" +@deprecated("Use `toPrecision` instead") @send +external toPrecisionWithPrecision: (float, ~digits: int) => string = "toPrecision" + +@send external toString: (float, ~radix: int=?) => string = "toString" +@deprecated("Use `toString` instead") @send +external toStringWithRadix: (float, ~radix: int) => string = "toString" +@send external toLocaleString: float => string = "toLocaleString" + +let fromString = i => + switch parseFloat(i) { + | i if isNaN(i) => None + | i => Some(i) + } + +external toInt: float => int = "%intoffloat" +external fromInt: int => float = "%identity" + +@unboxed @noalloc external mod: (float, float) => float = "?fmod_float" + +let clamp = (~min=?, ~max=?, value): float => { + let value = switch max { + | Some(max) if max < value => max + | _ => value + } + switch min { + | Some(min) if min > value => min + | _ => value + } +} diff --git a/runtime/Float.resi b/runtime/Float.resi new file mode 100644 index 0000000000..6569aef560 --- /dev/null +++ b/runtime/Float.resi @@ -0,0 +1,459 @@ +/* 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. */ + +/*** +Functions for interacting with float. +*/ + +/** +Float constants. +*/ +module Constants: { + /** + The special value "Not a Number" + See [`NaN`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/NaN) on MDN. + + ## Examples + + ```rescript + Float.Constants.nan + ``` + */ + @val + external nan: float = "NaN" + + /** + Represents the difference between 1 and the smallest floating point number greater than 1. + See [`Number.EPSILON`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/EPSILON) on MDN. + + ## Examples + + ```rescript + Float.Constants.epsilon + ``` + */ + @val + external epsilon: float = "Number.EPSILON" + + /** + The positive Infinity value + See [`Number.POSITIVE_INFINITY`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/POSITIVE_INFINITY) on MDN. + + ## Examples + + ```rescript + Float.Constants.positiveInfinity + ``` + */ + @val + external positiveInfinity: float = "Number.POSITIVE_INFINITY" + + /** + The negative Infinity value + See [`Number.NEGATIVE_INFINITY`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/NEGATIVE_INFINITY) on MDN. + + ## Examples + + ```rescript + Float.Constants.negativeInfinity + ``` + */ + @val + external negativeInfinity: float = "Number.NEGATIVE_INFINITY" + + /** + The smallest positive numeric value representable in JavaScript. + See [`Number.MIN_VALUE`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/MIN_VALUE) on MDN. + + ## Examples + + ```rescript + Float.Constants.minValue + ``` + */ + @val + external minValue: float = "Number.MIN_VALUE" + + /** + The maximum positive numeric value representable in JavaScript. + See [`Number.MAX_VALUE`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/MAX_VALUE) on MDN. + + ## Examples + + ```rescript + Float.Constants.minValue + ``` + */ + @val + external maxValue: float = "Number.MAX_VALUE" +} + +external equal: (float, float) => bool = "%equal" + +external compare: (float, float) => Ordering.t = "%compare" + +/** +`isNaN(v)` tests if the given `v` is `NaN`. +See [`NaN`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/NaN) on MDN. + +## Examples + +```rescript +Float.isNaN(3.0) // false +Float.isNaN(Float.Constants.nan) // true +``` +*/ +@val +external isNaN: float => bool = "isNaN" + +/** +`isFinite(v)` tests if the given `v` is finite. +See [`isFinite`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/isFinite) on MDN. + +## Examples + +```rescript +Float.isFinite(1.0) // true +Float.isFinite(Float.Constants.nan) // false +Float.isFinite(Float.Constants.positiveInfinity) // false +``` +*/ +@val +external isFinite: float => bool = "isFinite" + +/** +`parseFloat(v)` parse the given `v` and returns a float. Leading whitespace in +`v` is ignored. Returns `NaN` if `v` can't be parsed. Use [`fromString`] to +ensure it returns a valid float and not `NaN`. +See [`parseFloat`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/parseFloat) on MDN. + +## Examples + +```rescript +Float.parseFloat("1.0") // 1.0 +Float.parseFloat(" 3.14 ") // 3.14 +Float.parseFloat("3.0") // 3.0 +Float.parseFloat("3.14some non-digit characters") // 3.14 +Float.parseFloat("error")->Float.isNaN // true +``` +*/ +@val +external parseFloat: string => float = "parseFloat" + +/** +`parseInt(v, ~radix=?)` parse the given `v` and returns a float. Leading +whitespace in this argument `v`is ignored. `radix` specifies the radix base to +use for the formatted number. The value must be in the range [2, 36] (inclusive). +Returns `NaN` if `v` can't be parsed and `radix` is smaller than 2 or bigger +than 36. +See [`parseInt`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/parseInt) on MDN. + +## Examples + +```rescript +Float.parseInt("1.0") // 1.0 +Float.parseInt(" 3.14 ") // 3.0 +Float.parseInt(3) // 3.0 +Float.parseInt("3.14some non-digit characters") // 3.0 +Float.parseInt("error")->Float.isNaN // true +Float.parseInt("10.0", ~radix=2) // 2.0 +Float.parseInt("15 * 3", ~radix=10) // 15.0 +Float.parseInt("12", ~radix=13) // 15.0 +Float.parseInt("17", ~radix=40)->Float.isNaN // true +``` +*/ +@val +external parseInt: ('a, ~radix: int=?) => float = "parseInt" + +/** +`parseIntWithRadix(v, ~radix)` parse the given `v` and returns a float. Leading +whitespace in this argument `v`is ignored. `radix` specifies the radix base to +use for the formatted number. The value must be in the range [2, 36] (inclusive). +Returns `NaN` if `v` can't be parsed and `radix` is smaller than 2 or bigger +than 36. +See [`parseInt`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/parseInt) on MDN. + +## Examples + +```rescript +Float.parseIntWithRadix("10.0", ~radix=2) // 2.0 +Float.parseIntWithRadix("15 * 3", ~radix=10) // 15.0 +Float.parseIntWithRadix("12", ~radix=13) // 15.0 +Float.parseIntWithRadix("17", ~radix=40)->Float.isNaN // true +``` +*/ +@deprecated("Use `parseInt` instead") +@val +external parseIntWithRadix: ('a, ~radix: int) => float = "parseInt" + +/** +`toExponential(v, ~digits=?)` return a `string` representing the given value in +exponential notation. `digits` specifies how many digits should appear after +the decimal point. +See [`Number.toExponential`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toExponential) on MDN. + +## Examples + +```rescript +Float.toExponential(1000.0) // "1e+3" +Float.toExponential(-1000.0) // "-1e+3" +Float.toExponential(77.0, ~digits=2) // "7.70e+1" +Float.toExponential(5678.0, ~digits=2) // "5.68e+3" +``` + +## Exceptions + +- `RangeError`: If `digits` less than 0 or greater than 10. +*/ +@send +external toExponential: (float, ~digits: int=?) => string = "toExponential" + +/** +`toExponential(v, ~digits)` return a `string` representing the given value in +exponential notation. `digits` specifies how many digits should appear after +the decimal point. +See [`Number.toExponential`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toExponential) on MDN. + +## Examples + +```rescript +Float.toExponentialWithPrecision(77.0, ~digits=2) // "7.70e+1" +Float.toExponentialWithPrecision(5678.0, ~digits=2) // "5.68e+3" +``` + +## Exceptions + +- `RangeError`: If `digits` less than 0 or greater than 10. +*/ +@deprecated("Use `toExponential` instead") +@send +external toExponentialWithPrecision: (float, ~digits: int) => string = "toExponential" + +/** +`toFixed(v, ~digits=?)` return a `string` representing the given +value using fixed-point notation. `digits` specifies how many digits should +appear after the decimal point. +See [`Number.toFixed`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toFixed) on MDN. + +## Examples + +```rescript +Float.toFixed(123456.0) // "123456.00" +Float.toFixed(10.0) // "10.00" +Float.toFixed(300.0, ~digits=4) // "300.0000" +Float.toFixed(300.0, ~digits=1) // "300.0" +``` + +## Exceptions + +- `RangeError`: If `digits` is less than 0 or larger than 100. +*/ +@send +external toFixed: (float, ~digits: int=?) => string = "toFixed" + +/** +`toFixedWithPrecision(v, ~digits)` return a `string` representing the given +value using fixed-point notation. `digits` specifies how many digits should +appear after the decimal point. +See [`Number.toFixed`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toFixed) on MDN. + +## Examples + +```rescript +Float.toFixedWithPrecision(300.0, ~digits=4) // "300.0000" +Float.toFixedWithPrecision(300.0, ~digits=1) // "300.0" +``` + +## Exceptions + +- `RangeError`: If `digits` is less than 0 or larger than 100. +*/ +@deprecated("Use `toFixed` instead") +@send +external toFixedWithPrecision: (float, ~digits: int) => string = "toFixed" + +/** +`toPrecision(v, ~digits=?)` return a `string` representing the giver value with +precision. `digits` specifies the number of significant digits. +See [`Number.toPrecision`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toPrecision) on MDN. + +## Examples + +```rescript +Float.toPrecision(100.0) // "100" +Float.toPrecision(1.0) // "1" +Float.toPrecision(100.0, ~digits=2) // "1.0e+2" +Float.toPrecision(1.0, ~digits=1) // "1" +``` + +## Exceptions + +- `RangeError`: If `digits` is not between 1 and 100 (inclusive). +Implementations are allowed to support larger and smaller values as well. +ECMA-262 only requires a precision of up to 21 significant digits. +*/ +@send +external toPrecision: (float, ~digits: int=?) => string = "toPrecision" + +/** +`toPrecisionWithPrecision(v, ~digits)` return a `string` representing the giver value with +precision. `digits` specifies the number of significant digits. +See [`Number.toPrecision`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toPrecision) on MDN. + +## Examples + +```rescript +Float.toPrecisionWithPrecision(100.0, ~digits=2) // "1.0e+2" +Float.toPrecisionWithPrecision(1.0, ~digits=1) // "1" +``` + +## Exceptions + +- `RangeError`: If `digits` is not between 1 and 100 (inclusive). +Implementations are allowed to support larger and smaller values as well. +ECMA-262 only requires a precision of up to 21 significant digits. + +*/ +@deprecated("Use `toPrecision` instead") +@send +external toPrecisionWithPrecision: (float, ~digits: int) => string = "toPrecision" + +/** +`toString(v)` return a `string` representing the given value. +See [`Number.toString`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toString) on MDN. + +## Examples + +```rescript +Float.toString(1000.0) // "1000" +Float.toString(-1000.0) // "-1000" +``` +*/ +@send +external toString: (float, ~radix: int=?) => string = "toString" + +/** +`toStringWithRadix(v, ~radix)` return a `string` representing the given value. +`~radix` specifies the radix base to use for the formatted number. +See [`Number.toString`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toString) on MDN. + +## Examples + +```rescript +Float.toStringWithRadix(6.0, ~radix=2) // "110" +Float.toStringWithRadix(3735928559.0, ~radix=16) // "deadbeef" +Float.toStringWithRadix(123456.0, ~radix=36) // "2n9c" +``` + +## Exceptions + +`RangeError`: if `radix` is less than 2 or greater than 36. +*/ +@deprecated("Use `toString` with `~radix` instead") +@send +external toStringWithRadix: (float, ~radix: int) => string = "toString" + +/** +`toLocaleString(v)` return a `string` with language-sensitive representing the +given value. +See [`Number.toLocaleString`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toLocaleString) on MDN. + +## Examples + +```rescript +// If the application uses English as the default language +Float.toLocaleString(1000.0) // "1,000" + +// If the application uses Portuguese Brazil as the default language +Float.toLocaleString(1000.0) // "1.000" +``` +*/ +@send +external toLocaleString: float => string = "toLocaleString" + +/** +`fromString(str)` return an `option` representing the given value `str`. + +## Examples + +```rescript +Float.fromString("0") == Some(0.0) +Float.fromString("NaN") == None +Float.fromString("6") == Some(6.0) +``` +*/ +let fromString: string => option + +/** +`toInt(v)` returns an int to given float `v`. + +## Examples + +```rescript +Float.toInt(2.0) == 2 +Float.toInt(1.0) == 1 +Float.toInt(1.1) == 1 +Float.toInt(1.6) == 1 +``` +*/ +external toInt: float => int = "%intoffloat" + +/** +`fromInt(v)` returns a float to given int `v`. + +## Examples + +```rescript +Float.fromInt(2) == 2.0 +Float.fromInt(1) == 1.0 +``` +*/ +external fromInt: int => float = "%identity" + +/** +`mod(n1, n2)` calculates the modulo (remainder after division) of two floats. + +## Examples + +```rescript +Float.mod(7.0, 4.0) == 3.0 +``` +*/ +external mod: (float, float) => float = "?fmod_float" + +/** +`clamp(~min=?, ~max=?, value)` returns `value`, optionally bounded by `min` and `max`. + +if `max` < `min` returns `min`. + +## Examples + +```rescript +Float.clamp(4.2) == 4.2 +Float.clamp(4.2, ~min=4.3) == 4.3 +Float.clamp(4.2, ~max=4.1) == 4.1 +Float.clamp(4.2, ~min=4.3, ~max=4.1) == 4.3 +``` +*/ +let clamp: (~min: float=?, ~max: float=?, float) => float diff --git a/runtime/Float32Array.res b/runtime/Float32Array.res new file mode 100644 index 0000000000..6c04d070a8 --- /dev/null +++ b/runtime/Float32Array.res @@ -0,0 +1,53 @@ +/** The `Float32Array` typed array represents an array of 32-bit floating point numbers in platform byte order. See [Float32Array on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Float32Array) +*/ +type t = TypedArray.t + +module Constants = { + /**`bytesPerElement` returns the element size. See [BYTES_PER_ELEMENT on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray/BYTES_PER_ELEMENT) + */ + @val + external bytesPerElement: int = "Float32Array.BYTES_PER_ELEMENT" +} + +/** `fromArray` creates a `Float32Array` from an array of values. See [TypedArray constructor on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Float32Array/Float32Array) +*/ +@new +external fromArray: array => t = "Float32Array" + +/** `fromBuffer` creates a `Float32Array` from an `ArrayBuffer.t`. See [TypedArray constructor on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Float32Array/Float32Array) + +**Note:** This is a potentially unsafe operation. Ensure the buffer is large enough and only accessed within its bounds. +*/ +@new +external fromBuffer: ArrayBuffer.t => t = "Float32Array" + +/** `fromBufferToEnd` creates a `Float32Array` from an `ArrayBuffer.t`, starting at a particular offset and continuing through to the end. See [TypedArray constructor on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Float32Array/Float32Array) + +**Note:** This is a potentially unsafe operation. Ensure the buffer is large enough and only accessed within its bounds. +*/ +@new +external fromBufferToEnd: (ArrayBuffer.t, ~byteOffset: int) => t = "Float32Array" + +/** `fromBufferWithRange` creates a `Float32Array` from an `ArrayBuffer.t`, starting at a particular offset and consuming `length` **bytes**. See [TypedArray constructor on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Float32Array/Float32Array) + +**Note:** This is a potentially unsafe operation. Ensure the buffer is large enough and only accessed within its bounds. +*/ +@new +external fromBufferWithRange: (ArrayBuffer.t, ~byteOffset: int, ~length: int) => t = "Float32Array" + +/** `fromLength` creates a zero-initialized `Float32Array` to hold the specified count of numbers; this is **not** a byte length. See [TypedArray constructor on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Float32Array/Float32Array) + +**Note:** This is a potentially unsafe operation. Ensure the buffer is large enough and only accessed within its bounds. +*/ +@new +external fromLength: int => t = "Float32Array" + +/** `fromArrayLikeOrIterable` creates a `Float32Array` from an array-like or iterable object. See [TypedArray.from on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray/from) +*/ +@val +external fromArrayLikeOrIterable: 'a => t = "Float32Array.from" + +/** `fromArrayLikeOrIterableWithMap` creates a `Float32Array` from an array-like or iterable object and applies the mapping function to each item. The mapping function expects (value, index). See [TypedArray.from on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray/from) +*/ +@val +external fromArrayLikeOrIterableWithMap: ('a, ('b, int) => float) => t = "Float32Array.from" diff --git a/runtime/Float64Array.res b/runtime/Float64Array.res new file mode 100644 index 0000000000..03203eb189 --- /dev/null +++ b/runtime/Float64Array.res @@ -0,0 +1,53 @@ +/** The `Float64Array` typed array represents an array of 64-bit floating point numbers in platform byte order. See [Float64Array on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Float64Array) +*/ +type t = TypedArray.t + +module Constants = { + /**`bytesPerElement` returns the element size. See [BYTES_PER_ELEMENT on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray/BYTES_PER_ELEMENT) + */ + @val + external bytesPerElement: int = "Float64Array.BYTES_PER_ELEMENT" +} + +/** `fromArray` creates a `Float64Array` from an array of values. See [TypedArray constructor on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Float64Array/Float64Array) +*/ +@new +external fromArray: array => t = "Float64Array" + +/** `fromBuffer` creates a `Float64Array` from an `ArrayBuffer.t`. See [TypedArray constructor on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Float64Array/Float64Array) + +**Note:** This is a potentially unsafe operation. Ensure the buffer is large enough and only accessed within its bounds. +*/ +@new +external fromBuffer: ArrayBuffer.t => t = "Float64Array" + +/** `fromBufferToEnd` creates a `Float64Array` from an `ArrayBuffer.t`, starting at a particular offset and continuing through to the end. See [TypedArray constructor on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Float64Array/Float64Array) + +**Note:** This is a potentially unsafe operation. Ensure the buffer is large enough and only accessed within its bounds. +*/ +@new +external fromBufferToEnd: (ArrayBuffer.t, ~byteOffset: int) => t = "Float64Array" + +/** `fromBufferWithRange` creates a `Float64Array` from an `ArrayBuffer.t`, starting at a particular offset and consuming `length` **bytes**. See [TypedArray constructor on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Float64Array/Float64Array) + +**Note:** This is a potentially unsafe operation. Ensure the buffer is large enough and only accessed within its bounds. +*/ +@new +external fromBufferWithRange: (ArrayBuffer.t, ~byteOffset: int, ~length: int) => t = "Float64Array" + +/** `fromLength` creates a zero-initialized `Float64Array` to hold the specified count of numbers; this is **not** a byte length. See [TypedArray constructor on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Float64Array/Float64Array) + +**Note:** This is a potentially unsafe operation. Ensure the buffer is large enough and only accessed within its bounds. +*/ +@new +external fromLength: int => t = "Float64Array" + +/** `fromArrayLikeOrIterable` creates a `Float64Array` from an array-like or iterable object. See [TypedArray.from on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray/from) +*/ +@val +external fromArrayLikeOrIterable: 'a => t = "Float64Array.from" + +/** `fromArrayLikeOrIterableWithMap` creates a `Float64Array` from an array-like or iterable object and applies the mapping function to each item. The mapping function expects (value, index). See [TypedArray.from on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray/from) +*/ +@val +external fromArrayLikeOrIterableWithMap: ('a, ('b, int) => float) => t = "Float64Array.from" diff --git a/runtime/Int.res b/runtime/Int.res new file mode 100644 index 0000000000..44a7a8a0c2 --- /dev/null +++ b/runtime/Int.res @@ -0,0 +1,105 @@ +module Constants = { + @inline let minValue = -2147483648 + @inline let maxValue = 2147483647 +} + +external equal: (int, int) => bool = "%equal" + +external compare: (int, int) => Ordering.t = "%compare" + +@send external toExponential: (int, ~digits: int=?) => string = "toExponential" +@deprecated("Use `toExponential` instead") @send +external toExponentialWithPrecision: (int, ~digits: int) => string = "toExponential" + +@send external toFixed: (int, ~digits: int=?) => string = "toFixed" +@deprecated("Use `toFixed` instead") @send +external toFixedWithPrecision: (int, ~digits: int) => string = "toFixed" + +@send external toPrecision: (int, ~digits: int=?) => string = "toPrecision" +@deprecated("Use `toPrecision` instead") @send +external toPrecisionWithPrecision: (int, ~digits: int) => string = "toPrecision" + +@send external toString: (int, ~radix: int=?) => string = "toString" +@deprecated("Use `toString` instead") @send +external toStringWithRadix: (int, ~radix: int) => string = "toString" +@send external toLocaleString: int => string = "toLocaleString" + +external toFloat: int => float = "%identity" +external fromFloat: float => int = "%intoffloat" + +let fromString = (x, ~radix=?) => { + let maybeInt = switch radix { + | Some(radix) => Float.parseInt(x, ~radix) + | None => Float.parseInt(x) + } + + if Float.isNaN(maybeInt) { + None + } else if maybeInt > Constants.maxValue->toFloat || maybeInt < Constants.minValue->toFloat { + None + } else { + let asInt = fromFloat(maybeInt) + Some(asInt) + } +} + +external mod: (int, int) => int = "%modint" + +type rangeOptions = {step?: int, inclusive?: bool} + +let abs = x => + if x >= 0 { + x + } else { + -x + } + +@val external ceil: float => float = "Math.ceil" + +let range = (start, end, ~options: rangeOptions={}) => { + let isInverted = start > end + + let step = switch options.step { + | None => isInverted ? -1 : 1 + | Some(0) if start !== end => Error.raise(Error.RangeError.make("Incorrect range arguments")) + | Some(n) => n + } + + let length = if isInverted === (step >= 0) { + 0 // infinite because step goes in opposite direction of end + } else if step == 0 { + options.inclusive === Some(true) ? 1 : 0 + } else { + let range = isInverted ? start - end : end - start + let range = options.inclusive === Some(true) ? range + 1 : range + ceil(Float.fromInt(range) /. Float.fromInt(abs(step)))->Float.toInt + } + + Array.fromInitializer(~length, i => start + i * step) +} + +@deprecated("Use `range` instead") @send +let rangeWithOptions = (start, end, options) => range(start, end, ~options) + +let clamp = (~min=?, ~max=?, value): int => { + let value = switch max { + | Some(max) if max < value => max + | _ => value + } + switch min { + | Some(min) if min > value => min + | _ => value + } +} + +module Bitwise = { + external land: (int, int) => int = "%andint" + external lor: (int, int) => int = "%orint" + external lxor: (int, int) => int = "%xorint" + + external lsl: (int, int) => int = "%lslint" + external lsr: (int, int) => int = "%lsrint" + external asr: (int, int) => int = "%asrint" + + let lnot = x => lxor(x, -1) +} diff --git a/runtime/Int.resi b/runtime/Int.resi new file mode 100644 index 0000000000..9e6f48f160 --- /dev/null +++ b/runtime/Int.resi @@ -0,0 +1,468 @@ +/* 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. */ + +/*** +Functions for interacting with JavaScript Number. +See: [`Number`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number). +*/ + +module Constants: { + /** + The smallest positive number represented in JavaScript. + See [`Number.MIN_VALUE`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/MIN_VALUE) + on MDN. + + ## Examples + + ```rescript + Console.log(Int.Constants.minValue) + ``` + */ + @inline + let minValue: int + /** + The largest positive number represented in JavaScript. + See [`Number.MAX_VALUE`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/MAX_VALUE) + on MDN. + + ## Examples + + ```rescript + Console.log(Int.Constants.maxValue) + ``` + */ + @inline + let maxValue: int +} + +external equal: (int, int) => bool = "%equal" + +external compare: (int, int) => Ordering.t = "%compare" + +/** +`toExponential(n, ~digits=?)` return a `string` representing the given value in +exponential notation. `digits` specifies how many digits should appear after +the decimal point. See [`Number.toExponential`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toExponential) + +## Examples + +```rescript +Int.toExponential(1000) // "1e+3" +Int.toExponential(-1000) // "-1e+3" +Int.toExponential(77, ~digits=2) // "7.70e+1" +Int.toExponential(5678, ~digits=2) // "5.68e+3" +``` + +## Exceptions + +- `RangeError`: If `digits` less than 0 or greater than 10. +*/ +@send +external toExponential: (int, ~digits: int=?) => string = "toExponential" + +/** +`toExponential(n, ~digits)` return a `string` representing the given value in +exponential notation. `digits` specifies how many digits should appear after +the decimal point. See [`Number.toExponential`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toExponential) +on MDN. + +## Examples + +```rescript +Int.toExponentialWithPrecision(77, ~digits=2) // "7.70e+1" +Int.toExponentialWithPrecision(5678, ~digits=2) // "5.68e+3" +``` + +## Exceptions + +- `RangeError`: If `digits` less than 0 or greater than 10. +*/ +@deprecated("Use `toExponential` instead") +@send +external toExponentialWithPrecision: (int, ~digits: int) => string = "toExponential" + +/** +`toFixed(n, ~digits=?)` return a `string` representing the given +value using fixed-point notation. `digits` specifies how many digits should +appear after the decimal point. See [`Number.toFixed`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toFixed) +on MDN. + +## Examples + +```rescript +Int.toFixed(123456) // "123456.00" +Int.toFixed(10) // "10.00" +Int.toFixed(300, ~digits=4) // "300.0000" +Int.toFixed(300, ~digits=1) // "300.0" +``` + +## Exceptions + +- `RangeError`: If `digits` is less than 0 or larger than 100. +*/ +@send +external toFixed: (int, ~digits: int=?) => string = "toFixed" + +/** +`toFixedWithPrecision(n, ~digits)` return a `string` representing the given +value using fixed-point notation. `digits` specifies how many digits should +appear after the decimal point. See [`Number.toFixed`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toFixed) +on MDN. + +## Examples + +```rescript +Int.toFixedWithPrecision(300, ~digits=4) // "300.0000" +Int.toFixedWithPrecision(300, ~digits=1) // "300.0" +``` + +## Exceptions + +- `RangeError`: If `digits` is less than 0 or larger than 100. +*/ +@deprecated("Use `toFixed` instead") +@send +external toFixedWithPrecision: (int, ~digits: int) => string = "toFixed" + +/** +`toPrecision(n, ~digits=?)` return a `string` representing the giver value with +precision. `digits` specifies the number of significant digits. See [`Number.toPrecision`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toPrecision) on MDN. + +## Examples + +```rescript +Int.toPrecision(100) // "100" +Int.toPrecision(1) // "1" +Int.toPrecision(100, ~digits=2) // "1.0e+2" +Int.toPrecision(1, ~digits=2) // "1.0" +``` + +## Exceptions + +- `RangeError`: If `digits` is not between 1 and 100 (inclusive). +Implementations are allowed to support larger and smaller values as well. +ECMA-262 only requires a precision of up to 21 significant digits. +*/ +@send +external toPrecision: (int, ~digits: int=?) => string = "toPrecision" + +/** +`toPrecisionWithPrecision(n, ~digits)` return a `string` representing the giver value with +precision. `digits` specifies the number of significant digits. See [`Number.toPrecision`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toPrecision) on MDN. + +## Examples + +```rescript +Int.toPrecisionWithPrecision(100, ~digits=2) // "1.0e+2" +Int.toPrecisionWithPrecision(1, ~digits=2) // "1.0" +``` + +## Exceptions + +- `RangeError`: If `digits` is not between 1 and 100 (inclusive). +Implementations are allowed to support larger and smaller values as well. +ECMA-262 only requires a precision of up to 21 significant digits. + +*/ +@send +@deprecated("Use `toPrecision` instead") +external toPrecisionWithPrecision: (int, ~digits: int) => string = "toPrecision" + +/** +`toString(n, ~radix=?)` return a `string` representing the given value. +`~radix` specifies the radix base to use for the formatted number. +See [`Number.toString`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toString) +on MDN. + +## Examples + +```rescript +Int.toString(1000) // "1000" +Int.toString(-1000) // "-1000" +Int.toString(6, ~radix=2) // "110" +Int.toString(373592855, ~radix=16) // "16449317" +Int.toString(123456, ~radix=36) // "2n9c" +``` + +## Exceptions + +`RangeError`: if `radix` is less than 2 or greater than 36. +*/ +@send +external toString: (int, ~radix: int=?) => string = "toString" + +/** +`toStringWithRadix(n, ~radix)` return a `string` representing the given value. +`~radix` specifies the radix base to use for the formatted number. +See [`Number.toString`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toString) +on MDN. + +## Examples + +```rescript +Int.toStringWithRadix(6, ~radix=2) // "110" +Int.toStringWithRadix(373592855, ~radix=16) // "16449317" +Int.toStringWithRadix(123456, ~radix=36) // "2n9c" +``` + +## Exceptions + +`RangeError`: if `radix` is less than 2 or greater than 36. +*/ +@deprecated("Use `toString` instead") +@send +external toStringWithRadix: (int, ~radix: int) => string = "toString" + +/** +`toLocaleString(n)` return a `string` with language-sensitive representing the +given value. See [`Number.toLocaleString`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toLocaleString) on MDN. + +## Examples + +```rescript +// If the application uses English as the default language +Int.toLocaleString(1000) // "1,000" + +// If the application uses Portuguese Brazil as the default language +Int.toLocaleString(1000) // "1.000" +``` +*/ +@send +external toLocaleString: int => string = "toLocaleString" + +/** +`toFloat(n)` return a `float` representing the given value. + +## Examples + +```rescript +Int.toFloat(100) == 100.0 +Int.toFloat(2) == 2.0 +``` +*/ +external toFloat: int => float = "%identity" + +/** +`fromFloat(n)` return an `int` representing the given value. The conversion is +done by truncating the decimal part. + +## Examples + +```rescript +Int.fromFloat(2.0) == 2 +Int.fromFloat(1.999) == 1 +Int.fromFloat(1.5) == 1 +Int.fromFloat(0.9999) == 0 +``` +*/ +external fromFloat: float => int = "%intoffloat" + +/** +`fromString(str, ~radix=?)` return an `option` representing the given value +`str`. `~radix` specifies the radix base to use for the formatted number. + +## Examples + +```rescript +Int.fromString("0") == Some(0) +Int.fromString("NaN") == None +Int.fromString("6", ~radix=2) == None +``` +*/ +let fromString: (string, ~radix: int=?) => option + +/** +`mod(n1, n2)` calculates the modulo (remainder after division) of two integers. + +## Examples + +```rescript +Int.mod(7, 4) == 3 +``` +*/ +external mod: (int, int) => int = "%modint" + +/** +The options for `range`. +*/ +type rangeOptions = {step?: int, inclusive?: bool} + +/** +`range(start, end, ~options=?)` returns an int array of the sequence of integers in the +range `[start, end)`. That is, including `start` but excluding `end`. + +If `step` is not set and `start < end`, the sequence will be increasing in steps of 1. + +If `step` is not set and `start > end`, the sequence will be decreasing in steps of -1. + +If `step` is set, the sequence will increase or decrease by that amount for each +step. If `start < end` and `step` is negative, or vice versa, an empty array is +returned since the sequence would otherwise never reach or exceed the end value +and hence be infinite. If `step` is `0` and `start !=` end, a `RangeError` is +raised as the sequence would never reach or exceed the end value and hence be +infinite. + +If `inclusive` is set to `true`, the sequence will include `end` if `step` is +set such that the sequence includes it. + +## Examples + +```rescript +Int.range(3, 6) == [3, 4, 5] +Int.range(-3, -1) == [-3, -2] +Int.range(3, 1) == [3, 2] +Int.range(3, 7, ~options={step: 2}) == [3, 5] +Int.range(3, 7, ~options={step: 2, inclusive: true}) == [3, 5, 7] +Int.range(3, 6, ~options={step: -2}) // RangeError +``` + +## Exceptions + +- Raises `RangeError` if `step == 0 && start != end`. +*/ +let range: (int, int, ~options: rangeOptions=?) => array + +/** +`rangeWithOptions(start, end, options)` is like `range`, but with `step` and +`inclusive` options configurable. + +If `step` is set, the sequence will increase or decrease by that amount for each +step. If `start < end` and `step` is negative, or vice versa, an empty array is +returned since the sequence would otherwise never reach or exceed the end value +and hence be infinite. If `step` is `0` and `start !=` end, a `RangeError` is +raised as the sequence would never reach or exceed the end value and hence be +infinite. + +If `inclusive` is set to `true`, the sequence will include `end` if `step` is +set such that the sequence includes it. + +## Examples + +```rescript +Int.rangeWithOptions(3, 7, {step: 2}) == [3, 5] +Int.rangeWithOptions(3, 7, {step: 2, inclusive: true}) == [3, 5, 7] +Int.rangeWithOptions(3, 6, {step: -2}) // RangeError +``` + +## Exceptions + +- Raises `RangeError` if `step == 0 && start != end`. +*/ +@deprecated("Use `range` instead") +let rangeWithOptions: (int, int, rangeOptions) => array + +/** +`clamp(~min=?, ~max=?, value)` returns `value`, optionally bounded by `min` and `max`. + +if `max` < `min` returns `min`. + +## Examples + +```rescript +Int.clamp(42) == 42 +Int.clamp(42, ~min=50) == 50 +Int.clamp(42, ~max=40) == 40 +Int.clamp(42, ~min=50, ~max=40) == 50 +``` +*/ +let clamp: (~min: int=?, ~max: int=?, int) => int + +module Bitwise: { + /** + `land(n1, n2)` calculates the bitwise logical AND of two integers. + + ## Examples + + ```rescript + Int.Bitwise.land(7, 4) == 4 + ``` + */ + external land: (int, int) => int = "%andint" + + /** + `lor(n1, n2)` calculates the bitwise logical OR of two integers. + + ## Examples + + ```rescript + Int.Bitwise.lor(7, 4) == 7 + ``` + */ + external lor: (int, int) => int = "%orint" + + /** + `lxor(n1, n2)` calculates the bitwise logical XOR of two integers. + + ## Examples + + ```rescript + Int.Bitwise.lxor(7, 4) == 3 + ``` + */ + external lxor: (int, int) => int = "%xorint" + + /** + `lnot(n)` calculates the bitwise logical NOT of an integer. + + ## Examples + + ```rescript + Int.Bitwise.lnot(2) == -3 + ``` + */ + let lnot: int => int + + /** + `lsl(n, length)` calculates the bitwise logical left shift of an integer `n` by `length`. + + ## Examples + + ```rescript + Int.Bitwise.lsl(4, 1) == 8 + ``` + */ + external lsl: (int, int) => int = "%lslint" + + /** + `lsr(n, length)` calculates the bitwise logical right shift of an integer `n` by `length`. + + ## Examples + + ```rescript + Int.Bitwise.lsr(8, 1) == 4 + ``` + */ + external lsr: (int, int) => int = "%lsrint" + + /** + `asr(n, length)` calculates the bitwise arithmetic right shift of an integer `n` by `length`. + + ## Examples + + ```rescript + Int.Bitwise.asr(4, 1) == 2 + ``` + */ + external asr: (int, int) => int = "%asrint" +} diff --git a/runtime/Int16Array.res b/runtime/Int16Array.res new file mode 100644 index 0000000000..8fe25cf2ae --- /dev/null +++ b/runtime/Int16Array.res @@ -0,0 +1,53 @@ +/** The `Int16Array` typed array represents an array of twos-complement 16-bit signed integers in platform byte order. See [Int16Array on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Int16Array) +*/ +type t = TypedArray.t + +module Constants = { + /**`bytesPerElement` returns the element size. See [BYTES_PER_ELEMENT on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray/BYTES_PER_ELEMENT) + */ + @val + external bytesPerElement: int = "Int16Array.BYTES_PER_ELEMENT" +} + +/** `fromArray` creates a `Int16Array` from an array of values. See [TypedArray constructor on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Int16Array/Int16Array) +*/ +@new +external fromArray: array => t = "Int16Array" + +/** `fromBuffer` creates a `Int16Array` from an `ArrayBuffer.t`. See [TypedArray constructor on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Int16Array/Int16Array) + +**Note:** This is a potentially unsafe operation. Ensure the buffer is large enough and only accessed within its bounds. +*/ +@new +external fromBuffer: ArrayBuffer.t => t = "Int16Array" + +/** `fromBufferToEnd` creates a `Int16Array` from an `ArrayBuffer.t`, starting at a particular offset and continuing through to the end. See [TypedArray constructor on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Int16Array/Int16Array) + +**Note:** This is a potentially unsafe operation. Ensure the buffer is large enough and only accessed within its bounds. +*/ +@new +external fromBufferToEnd: (ArrayBuffer.t, ~byteOffset: int) => t = "Int16Array" + +/** `fromBufferWithRange` creates a `Int16Array` from an `ArrayBuffer.t`, starting at a particular offset and consuming `length` **bytes**. See [TypedArray constructor on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Int16Array/Int16Array) + +**Note:** This is a potentially unsafe operation. Ensure the buffer is large enough and only accessed within its bounds. +*/ +@new +external fromBufferWithRange: (ArrayBuffer.t, ~byteOffset: int, ~length: int) => t = "Int16Array" + +/** `fromLength` creates a zero-initialized `Int16Array` to hold the specified count of numbers; this is **not** a byte length. See [TypedArray constructor on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Int16Array/Int16Array) + +**Note:** This is a potentially unsafe operation. Ensure the buffer is large enough and only accessed within its bounds. +*/ +@new +external fromLength: int => t = "Int16Array" + +/** `fromArrayLikeOrIterable` creates a `Int16Array` from an array-like or iterable object. See [TypedArray.from on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray/from) +*/ +@val +external fromArrayLikeOrIterable: 'a => t = "Int16Array.from" + +/** `fromArrayLikeOrIterableWithMap` creates a `Int16Array` from an array-like or iterable object and applies the mapping function to each item. The mapping function expects (value, index). See [TypedArray.from on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray/from) +*/ +@val +external fromArrayLikeOrIterableWithMap: ('a, ('b, int) => int) => t = "Int16Array.from" diff --git a/runtime/Int32Array.res b/runtime/Int32Array.res new file mode 100644 index 0000000000..febba5a2c7 --- /dev/null +++ b/runtime/Int32Array.res @@ -0,0 +1,53 @@ +/** The `Int32Array` typed array represents an array of twos-complemenet 32-bit signed integers in platform byte order. See [Int32Array on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Int32Array) +*/ +type t = TypedArray.t + +module Constants = { + /**`bytesPerElement` returns the element size. See [BYTES_PER_ELEMENT on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray/BYTES_PER_ELEMENT) + */ + @val + external bytesPerElement: int = "Int32Array.BYTES_PER_ELEMENT" +} + +/** `fromArray` creates a `Int32Array` from an array of values. See [TypedArray constructor on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Int32Array/Int32Array) +*/ +@new +external fromArray: array => t = "Int32Array" + +/** `fromBuffer` creates a `Int32Array` from an `ArrayBuffer.t`. See [TypedArray constructor on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Int32Array/Int32Array) + +**Note:** This is a potentially unsafe operation. Ensure the buffer is large enough and only accessed within its bounds. +*/ +@new +external fromBuffer: ArrayBuffer.t => t = "Int32Array" + +/** `fromBufferToEnd` creates a `Int32Array` from an `ArrayBuffer.t`, starting at a particular offset and continuing through to the end. See [TypedArray constructor on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Int32Array/Int32Array) + +**Note:** This is a potentially unsafe operation. Ensure the buffer is large enough and only accessed within its bounds. +*/ +@new +external fromBufferToEnd: (ArrayBuffer.t, ~byteOffset: int) => t = "Int32Array" + +/** `fromBufferWithRange` creates a `Int32Array` from an `ArrayBuffer.t`, starting at a particular offset and consuming `length` **bytes**. See [TypedArray constructor on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Int32Array/Int32Array) + +**Note:** This is a potentially unsafe operation. Ensure the buffer is large enough and only accessed within its bounds. +*/ +@new +external fromBufferWithRange: (ArrayBuffer.t, ~byteOffset: int, ~length: int) => t = "Int32Array" + +/** `fromLength` creates a zero-initialized `Int32Array` to hold the specified count of numbers; this is **not** a byte length. See [TypedArray constructor on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Int32Array/Int32Array) + +**Note:** This is a potentially unsafe operation. Ensure the buffer is large enough and only accessed within its bounds. +*/ +@new +external fromLength: int => t = "Int32Array" + +/** `fromArrayLikeOrIterable` creates a `Int32Array` from an array-like or iterable object. See [TypedArray.from on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray/from) +*/ +@val +external fromArrayLikeOrIterable: 'a => t = "Int32Array.from" + +/** `fromArrayLikeOrIterableWithMap` creates a `Int32Array` from an array-like or iterable object and applies the mapping function to each item. The mapping function expects (value, index). See [TypedArray.from on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray/from) +*/ +@val +external fromArrayLikeOrIterableWithMap: ('a, ('b, int) => int) => t = "Int32Array.from" diff --git a/runtime/Int8Array.res b/runtime/Int8Array.res new file mode 100644 index 0000000000..3c8e14ba8b --- /dev/null +++ b/runtime/Int8Array.res @@ -0,0 +1,53 @@ +/** The `Int8Array` typed array represents an array of twos-complement 8-bit signed integers. See [Int8Array on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Int8Array) +*/ +type t = TypedArray.t + +module Constants = { + /**`bytesPerElement` returns the element size. See [BYTES_PER_ELEMENT on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray/BYTES_PER_ELEMENT) + */ + @val + external bytesPerElement: int = "Int8Array.BYTES_PER_ELEMENT" +} + +/** `fromArray` creates a `Int8Array` from an array of values. See [TypedArray constructor on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Int8Array/Int8Array) +*/ +@new +external fromArray: array => t = "Int8Array" + +/** `fromBuffer` creates a `Int8Array` from an `ArrayBuffer.t`. See [TypedArray constructor on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Int8Array/Int8Array) + +**Note:** This is a potentially unsafe operation. Ensure the buffer is large enough and only accessed within its bounds. +*/ +@new +external fromBuffer: ArrayBuffer.t => t = "Int8Array" + +/** `fromBufferToEnd` creates a `Int8Array` from an `ArrayBuffer.t`, starting at a particular offset and continuing through to the end. See [TypedArray constructor on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Int8Array/Int8Array) + +**Note:** This is a potentially unsafe operation. Ensure the buffer is large enough and only accessed within its bounds. +*/ +@new +external fromBufferToEnd: (ArrayBuffer.t, ~byteOffset: int) => t = "Int8Array" + +/** `fromBufferWithRange` creates a `Int8Array` from an `ArrayBuffer.t`, starting at a particular offset and consuming `length` **bytes**. See [TypedArray constructor on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Int8Array/Int8Array) + +**Note:** This is a potentially unsafe operation. Ensure the buffer is large enough and only accessed within its bounds. +*/ +@new +external fromBufferWithRange: (ArrayBuffer.t, ~byteOffset: int, ~length: int) => t = "Int8Array" + +/** `fromLength` creates a zero-initialized `Int8Array` to hold the specified count of numbers; this is **not** a byte length. See [TypedArray constructor on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Int8Array/Int8Array) + +**Note:** This is a potentially unsafe operation. Ensure the buffer is large enough and only accessed within its bounds. +*/ +@new +external fromLength: int => t = "Int8Array" + +/** `fromArrayLikeOrIterable` creates a `Int8Array` from an array-like or iterable object. See [TypedArray.from on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray/from) +*/ +@val +external fromArrayLikeOrIterable: 'a => t = "Int8Array.from" + +/** `fromArrayLikeOrIterableWithMap` creates a `Int8Array` from an array-like or iterable object and applies the mapping function to each item. The mapping function expects (value, index). See [TypedArray.from on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray/from) +*/ +@val +external fromArrayLikeOrIterableWithMap: ('a, ('b, int) => int) => t = "Int8Array.from" diff --git a/runtime/Intl.res b/runtime/Intl.res new file mode 100644 index 0000000000..da9e86c920 --- /dev/null +++ b/runtime/Intl.res @@ -0,0 +1,25 @@ +module Common = Intl_Common +module Collator = Intl_Collator +module DateTimeFormat = Intl_DateTimeFormat +module ListFormat = Intl_ListFormat +module Locale = Intl_Locale +module NumberFormat = Intl_NumberFormat +module PluralRules = Intl_PluralRules +module RelativeTimeFormat = Intl_RelativeTimeFormat +module Segmenter = Intl_Segmenter +module Segments = Intl_Segments + +/** +@throws RangeError +*/ +external getCanonicalLocalesExn: string => array = "Intl.getCanonicalLocales" + +/** +@throws RangeError +*/ +external getCanonicalLocalesManyExn: array => array = "Intl.getCanonicalLocales" + +/** +@throws RangeError +*/ +external supportedValuesOfExn: string => array = "Intl.supportedValuesOf" diff --git a/runtime/Intl_Collator.res b/runtime/Intl_Collator.res new file mode 100644 index 0000000000..352f6252b4 --- /dev/null +++ b/runtime/Intl_Collator.res @@ -0,0 +1,36 @@ +type t + +type usage = [#sort | #search] +type sensitivity = [#base | #accent | #case | #variant] +type caseFirst = [#upper | #lower | #"false"] + +type options = { + localeMatcher?: Intl_Common.localeMatcher, + usage?: usage, + sensitivity?: sensitivity, + ignorePunctuation?: bool, + numeric?: bool, + caseFirst?: caseFirst, +} + +type resolvedOptions = { + locale: string, + usage: usage, + sensitivity: sensitivity, + ignorePunctuation: bool, + collation: [Intl_Common.collation | #default], + numeric?: bool, + caseFirst?: caseFirst, +} + +type supportedLocalesOptions = {localeMatcher: Intl_Common.localeMatcher} + +@new external make: (~locales: array=?, ~options: options=?) => t = "Intl.Collator" + +@val +external supportedLocalesOf: (array, ~options: supportedLocalesOptions=?) => t = + "Intl.Collator.supportedLocalesOf" + +@send external resolvedOptions: t => resolvedOptions = "resolvedOptions" + +@send external compare: (t, string, string) => int = "compare" diff --git a/runtime/Intl_Common.res b/runtime/Intl_Common.res new file mode 100644 index 0000000000..6cc3a6258c --- /dev/null +++ b/runtime/Intl_Common.res @@ -0,0 +1,156 @@ +type localeMatcher = [#lookup | #"best fit"] + +type calendar = [ + | #buddhist + | #chinese + | #coptic + | #dangi + | #ethioaa + | #ethiopic + | #gregory + | #hebrew + | #indian + | #islamic + | #"islamic-umalqura" + | #"islamic-tbla" + | #"islamic-civil" + | #"islamic-rgsa" + | #iso8601 + | #japanese + | #persian + | #roc +] + +type collation = [ + | #compat // (Arabic) + | #dict // (Sinhala) + | #emoji // (root) + | #eor // (root) + | #phonebk // (German) + | #phonetic // (Lingala) + | #pinyin // (Chinese) + | #stroke // (Chinese) + | #trad + | #unihan // (Chinese, Japanese, and Korean; not available in Chrome or Edge) + | #zhuyin +] // (Chinese) + +type numberingSystem = [ + | #adlm + | #ahom + | #arab + | #arabext + | #bali + | #beng + | #bhks + | #brah + | #cakm + | #cham + | #deva + | #diak + | #fullwide + | #gong + | #gonm + | #gujr + | #guru + | #hanidec + | #hmng + | #hmnp + | #java + | #kali + | #kawi + | #khmr + | #knda + | #lana + | #lanatham + | #laoo + | #latn + | #lepc + | #limb + | #mathbold + | #mathdbl + | #mathmono + | #mathsanb + | #mathsans + | #mlym + | #modi + | #mong + | #mroo + | #mtei + | #mymr + | #mymrshan + | #mymrtlng + | #nagm + | #newa + | #nkoo + | #olck + | #orya + | #osma + | #rohg + | #saur + | #segment + | #shrd + | #sind + | #sinh + | #sora + | #sund + | #takr + | #talu + | #tamldec + | #telu + | #thai + | #tibt + | #tirh + | #tnsa + | #vaii + | #wara + | #wcho +] + +type oneTo21 = [ + | #1 + | #2 + | #3 + | #4 + | #5 + | #6 + | #7 + | #8 + | #9 + | #10 + | #11 + | #12 + | #13 + | #14 + | #15 + | #16 + | #17 + | #18 + | #19 + | #20 + | #21 +] + +type zeroTo20 = [ + | #0 + | #1 + | #2 + | #3 + | #4 + | #5 + | #6 + | #7 + | #8 + | #9 + | #10 + | #11 + | #12 + | #13 + | #14 + | #15 + | #16 + | #17 + | #18 + | #19 + | #20 +] diff --git a/runtime/Intl_DateTimeFormat.res b/runtime/Intl_DateTimeFormat.res new file mode 100644 index 0000000000..12738b5e0d --- /dev/null +++ b/runtime/Intl_DateTimeFormat.res @@ -0,0 +1,125 @@ +type t + +type dateStyle = [#full | #long | #medium | #short] +type timeStyle = [#full | #long | #medium | #short] +type dayPeriod = [#narrow | #short | #long] +type weekday = [#narrow | #short | #long] +type era = [#narrow | #short | #long] +type year = [#numeric | #"2-digit"] +type month = [#numeric | #"2-digit" | #narrow | #short | #long] +type day = [#numeric | #"2-digit"] +type hour = [#numeric | #"2-digit"] +type minute = [#numeric | #"2-digit"] +type second = [#numeric | #"2-digit"] + +/** +Firefox also supports IANA time zone names here +Node v19+ supports "shortOffset", "shortGeneric", "longOffset", and "longGeneric". +*/ +type timeZoneName = [ + | #short + | #long + | #shortOffset + | #shortGeneric + | #longOffset + | #longGeneric +] + +type hourCycle = [#h11 | #h12 | #h23 | #h24] +type formatMatcher = [#basic | #"best fit"] +type fractionalSecondDigits = [#0 | #1 | #2 | #3] + +type options = { + dateStyle?: dateStyle, // can be used with timeStyle, but not other options + timeStyle?: timeStyle, // can be used with dateStyle, but not other options + calendar?: Intl_Common.calendar, + dayPeriod?: dayPeriod, // only has an effect if a 12-hour clock is used + numberingSystem?: Intl_Common.numberingSystem, + localeMatcher?: Intl_Common.localeMatcher, + timeZone?: string, + hour12?: bool, + hourCycle?: hourCycle, + formatMatcher?: formatMatcher, + // date-time components + weekday?: weekday, + era?: era, + year?: year, + month?: month, + day?: day, + hour?: hour, + minute?: minute, + second?: second, + fractionalSecondDigits?: fractionalSecondDigits, + timeZoneName?: timeZoneName, +} + +type resolvedOptions = { + dateStyle?: dateStyle, + timeStyle?: timeStyle, + weekday?: weekday, + era?: era, + year?: year, + month?: month, + day?: day, + hour?: hour, + minute?: minute, + second?: second, + fractionalSecondDigits?: fractionalSecondDigits, + timeZoneName?: timeZoneName, + calendar: Intl_Common.calendar, + hour12: bool, + hourCycle: hourCycle, + locale: string, + numberingSystem: Intl_Common.numberingSystem, + timeZone: string, +} + +type supportedLocalesOptions = {localeMatcher: Intl_Common.localeMatcher} + +type dateTimeComponent = [ + | #day + | #dayPeriod + | #era + | #fractionalSecond + | #hour + | #literal + | #minute + | #month + | #relatedYear + | #second + | #timeZone + | #weekday + | #year + | #yearName +] + +type dateTimePart = { + \"type": dateTimeComponent, + value: string, +} + +type dateTimeRangeSource = [#startRange | #shared | #endRange] +type dateTimeRangePart = { + \"type": dateTimeComponent, + value: string, + source: dateTimeRangeSource, +} + +@new external make: (~locales: array=?, ~options: options=?) => t = "Intl.DateTimeFormat" + +@val +external supportedLocalesOf: (array, ~options: supportedLocalesOptions=?) => t = + "Intl.DateTimeFormat.supportedLocalesOf" + +@send external resolvedOptions: t => resolvedOptions = "resolvedOptions" + +@send external format: (t, Date.t) => string = "format" +@send +external formatToParts: (t, Date.t) => array = "formatToParts" + +@send +external formatRange: (t, ~startDate: Date.t, ~endDate: Date.t) => string = "formatRange" + +@send +external formatRangeToParts: (t, ~startDate: Date.t, ~endDate: Date.t) => array = + "formatRangeToParts" diff --git a/runtime/Intl_ListFormat.res b/runtime/Intl_ListFormat.res new file mode 100644 index 0000000000..0de3d99917 --- /dev/null +++ b/runtime/Intl_ListFormat.res @@ -0,0 +1,47 @@ +type t + +type listType = [ + | #conjunction + | #disjunction + | #unit +] +type style = [ + | #long + | #short + | #narrow +] + +type options = { + localeMatcher?: Intl_Common.localeMatcher, + \"type"?: listType, + style?: style, +} + +type listPartComponentType = [ + | #element + | #literal +] + +type listPart = { + \"type": listPartComponentType, + value: string, +} + +type resolvedOptions = { + locale: string, + style: style, + \"type": listType, +} + +type supportedLocalesOptions = {localeMatcher: Intl_Common.localeMatcher} + +@new external make: (~locales: array=?, ~options: options=?) => t = "Intl.ListFormat" + +@val +external supportedLocalesOf: (array, ~options: supportedLocalesOptions=?) => t = + "Intl.ListFormat.supportedLocalesOf" + +@send external resolvedOptions: t => resolvedOptions = "resolvedOptions" + +@send external format: (t, array) => string = "format" +@send external formatToParts: (t, array) => array = "formatToParts" diff --git a/runtime/Intl_Locale.res b/runtime/Intl_Locale.res new file mode 100644 index 0000000000..de82a0aa1c --- /dev/null +++ b/runtime/Intl_Locale.res @@ -0,0 +1,30 @@ +type t + +type options = { + baseName?: string, + calendar?: Intl_Common.calendar, + collation?: Intl_Common.collation, + hourCycle?: [#h11 | #h12 | #h23 | #h24], + caseFirst?: [#upper | #lower | #"false"], + numberingSystem?: Intl_Common.numberingSystem, + numeric?: bool, + language?: string, + script?: string, + region?: string, +} + +@new external make: (string, ~options: options=?) => t = "Intl.Locale" + +@get external baseName: t => string = "baseName" +@get external calendar: t => option = "calendar" +@get external caseFirst: t => option = "caseFirst" +@get external collation: t => option = "collation" +@get external hourCycle: t => option = "hourCycle" +@get external language: t => string = "language" +@get external numberingSystem: t => option = "numberingSystem" +@get external numeric: t => bool = "numeric" +@get external region: t => option = "region" +@get external script: t => option = "script" + +@send external maximize: t => t = "maximize" +@send external minimize: t => t = "minimize" diff --git a/runtime/Intl_NumberFormat.res b/runtime/Intl_NumberFormat.res new file mode 100644 index 0000000000..e6262ea706 --- /dev/null +++ b/runtime/Intl_NumberFormat.res @@ -0,0 +1,211 @@ +module Grouping = Intl_NumberFormat_Grouping + +type t + +/** +An ISO 4217 currency code. e.g. USD, EUR, CNY +*/ +type currency = string +type currencyDisplay = [#symbol | #narrowSymbol | #code | #name] +type currencySign = [#accounting | #standard] +type notation = [#scientific | #standard | #engineering | #compact] + +/** +Used only when notation is #compact +*/ +type compactDisplay = [#short | #long] + +type signDisplay = [ + | #auto + | #always + | #exceptZero + | #never + | #negative +] + +type style = [#decimal | #currency | #percent | #unit] + +/** +Defined in https://tc39.es/proposal-unified-intl-numberformat/section6/locales-currencies-tz_proposed_out.html#sec-issanctionedsimpleunitidentifier +Only used when style is #unit +*/ +type unitSystem = string + +/** +Only used when style is #unit +*/ +type unitDisplay = [#long | #short | #narrow] + +type rounding = [ + | #ceil + | #floor + | #expand + | #trunc + | #halfCeil + | #halfFloor + | #halfExpand + | #halfTrunc + | #halfEven +] + +type roundingPriority = [#auto | #morePrecision | #lessPrecision] + +type roundingIncrement = [ + | #1 + | #2 + | #5 + | #10 + | #20 + | #25 + | #50 + | #100 + | #200 + | #250 + | #500 + | #1000 + | #2000 + | #2500 + | #5000 +] + +type trailingZeroDisplay = [#auto | #stripIfInteger | #lessPrecision] + +type options = { + compactDisplay?: compactDisplay, + numberingSystem?: Intl_Common.numberingSystem, + currency?: currency, + currencyDisplay?: currencyDisplay, + currencySign?: currencySign, + localeMatcher?: Intl_Common.localeMatcher, + notation?: notation, + signDisplay?: signDisplay, + style?: style, + /** + required if style == #unit + */ + unit?: unitSystem, + unitDisplay?: unitDisplay, + useGrouping?: Grouping.t, + roundingMode?: rounding, // not available in firefox v110 + roundingPriority?: roundingPriority, // not available in firefox v110 + roundingIncrement?: roundingIncrement, // not available in firefox v110 + /** + Supported everywhere but Firefox as of v110 + */ + trailingZeroDisplay?: trailingZeroDisplay, + // use either this group + minimumIntegerDigits?: Intl_Common.oneTo21, + minimumFractionDigits?: Intl_Common.zeroTo20, + maximumFractionDigits?: Intl_Common.zeroTo20, + // OR these + minimumSignificantDigits?: Intl_Common.oneTo21, + maximumSignificantDigits?: Intl_Common.oneTo21, +} + +type resolvedOptions = { + // only when style == "currency" + currency?: currency, + currencyDisplay?: currencyDisplay, + currencySign?: currencySign, + // only when notation == "compact" + compactDisplay?: compactDisplay, + // only when style == "unit" + unit: unitSystem, + unitDisplay: unitDisplay, + roundingMode?: rounding, // not available in firefox v110 + roundingPriority?: roundingPriority, // not available in firefox v110 + roundingIncrement?: roundingIncrement, // not available in firefox v110 + // either this group + minimumIntegerDigits?: Intl_Common.oneTo21, + minimumFractionDigits?: Intl_Common.zeroTo20, + maximumFractionDigits?: Intl_Common.zeroTo20, + // OR these + minimumSignificantDigits?: Intl_Common.oneTo21, + maximumSignificantDigits?: Intl_Common.oneTo21, + // always present + locale: string, + notation: notation, + numberingSystem: Intl_Common.numberingSystem, + signDisplay: signDisplay, + style: style, + useGrouping: Grouping.t, +} + +type supportedLocalesOptions = {localeMatcher: Intl_Common.localeMatcher} + +type numberFormatPartType = [ + | #compact + | #currency + | #decimal + | #exponentInteger + | #exponentMinusSign + | #exponentSeparator + | #fraction + | #group + | #infinity + | #integer + | #literal + | #minusSign + | #nan + | #plusSign + | #percentSign + | #unit + | #unknown +] + +type numberFormatPart = { + \"type": numberFormatPartType, + value: string, +} + +type rangeSource = [#startRange | #endRange | #shared] + +type numberFormatRangePart = { + \"type": numberFormatPartType, + value: string, + source: rangeSource, +} + +@new external make: (~locales: array=?, ~options: options=?) => t = "Intl.NumberFormat" + +@val +external supportedLocalesOf: (array, ~options: supportedLocalesOptions=?) => t = + "Intl.NumberFormat.supportedLocalesOf" + +@send external resolvedOptions: t => resolvedOptions = "resolvedOptions" + +@send external format: (t, float) => string = "format" +@send +external formatRange: (t, ~start: float, ~end: float) => array = "formatRange" +@send +external formatToParts: (t, float) => array = "formatToParts" +@send +external formatRangeToParts: (t, ~start: float, ~end: float) => array = + "formatRange" + +@send external formatInt: (t, int) => string = "format" + +@send +external formatIntRange: (t, ~start: int, ~end: int) => array = "formatRange" +@send +external formatIntToParts: (t, int) => array = "formatToParts" + +@send +external formatIntRangeToParts: (t, ~start: int, ~end: int) => array = + "formatRange" + +@send external formatBigInt: (t, bigint) => string = "format" + +@send +external formatBigIntRange: (t, ~start: bigint, ~end: bigint) => array = "formatRange" +@send +external formatBigIntToParts: (t, bigint) => array = "formatToParts" + +@send +external formatBigIntRangeToParts: (t, ~start: bigint, ~end: bigint) => array = + "formatRange" + +@send external formatString: (t, string) => string = "format" + +@send +external formatStringToParts: (t, string) => array = "formatToParts" diff --git a/runtime/Intl_NumberFormat_Grouping.res b/runtime/Intl_NumberFormat_Grouping.res new file mode 100644 index 0000000000..600b06ba1e --- /dev/null +++ b/runtime/Intl_NumberFormat_Grouping.res @@ -0,0 +1,15 @@ +type t + +type parsed = [#bool(bool) | #always | #auto | #min2] + +external fromBool: bool => t = "%identity" +external fromString: [#always | #auto | #min2] => t = "%identity" + +let parseJsValue = value => + switch Type.Classify.classify(value) { + | String("always") => Some(#always) + | String("auto") => Some(#auto) + | String("min2") => Some(#min2) + | Bool(value) => Some(#bool(value)) + | _ => None + } diff --git a/runtime/Intl_PluralRules.res b/runtime/Intl_PluralRules.res new file mode 100644 index 0000000000..9da532bf81 --- /dev/null +++ b/runtime/Intl_PluralRules.res @@ -0,0 +1,62 @@ +type t + +type localeType = [#cardinal | #ordinal] + +type options = { + localeMatcher?: Intl_Common.localeMatcher, + \"type"?: localeType, + // use either this group + minimumIntegerDigits?: Intl_Common.oneTo21, + minimumFractionDigits?: Intl_Common.zeroTo20, + maximumFractionDigits?: Intl_Common.zeroTo20, + // OR this group + minimumSignificantDigits?: Intl_Common.oneTo21, + maximumSignificantDigits?: Intl_Common.oneTo21, +} + +type pluralCategories = [ + | #zero + | #one + | #two + | #few + | #many + | #other +] + +type resolvedOptions = { + locale: string, + pluralCategories: array, + \"type": localeType, + // either this group + minimumIntegerDigits?: Intl_Common.oneTo21, + minimumFractionDigits?: Intl_Common.zeroTo20, + maximumFractionDigits?: Intl_Common.zeroTo20, + // OR this group + minimumSignificantDigits?: Intl_Common.oneTo21, + maximumSignificantDigits?: Intl_Common.oneTo21, +} + +type supportedLocalesOptions = {localeMatcher: Intl_Common.localeMatcher} + +@new external make: (~locales: array=?, ~options: options=?) => t = "Intl.PluralRules" + +@val +external supportedLocalesOf: (array, ~options: supportedLocalesOptions=?) => t = + "Intl.PluralRules.supportedLocalesOf" + +@send external resolvedOptions: t => resolvedOptions = "resolvedOptions" + +type rule = [#zero | #one | #two | #few | #many | #other] + +@send external select: (t, float) => rule = "select" +@send external selectInt: (t, int) => rule = "select" +@send external selectBigInt: (t, bigint) => rule = "select" + +@send +external selectRange: (t, ~start: float, ~end: float) => rule = "selectRange" + +@send +external selectRangeInt: (t, ~start: int, ~end: int) => rule = "selectRange" + +@send +external selectRangeBigInt: (t, ~start: bigint, ~end: bigint) => rule = "selectRange" diff --git a/runtime/Intl_RelativeTimeFormat.res b/runtime/Intl_RelativeTimeFormat.res new file mode 100644 index 0000000000..1d53db642d --- /dev/null +++ b/runtime/Intl_RelativeTimeFormat.res @@ -0,0 +1,40 @@ +type t + +type numeric = [#always | #auto] +type style = [#long | #short | #narrow] +type timeUnit = [#year | #quarter | #month | #week | #day | #hour | #minute | #second] + +type options = { + localeMatcher?: Intl_Common.localeMatcher, + numeric?: numeric, + style?: style, +} + +type supportedLocalesOptions = {localeMatcher: Intl_Common.localeMatcher} + +type resolvedOptions = { + locale: string, + numeric: numeric, + style: style, + numberingSystem: string, +} + +type relativeTimePartComponent = [#literal | #integer] +type relativeTimePart = { + \"type": relativeTimePartComponent, + value: string, + unit?: timeUnit, +} + +@new +external make: (~locales: array=?, ~options: options=?) => t = "Intl.RelativeTimeFormat" + +@val +external supportedLocalesOf: (array, ~options: supportedLocalesOptions=?) => t = + "Intl.RelativeTimeFormat.supportedLocalesOf" + +@send external resolvedOptions: t => resolvedOptions = "resolvedOptions" + +@send external format: (t, int, timeUnit) => string = "format" +@send +external formatToParts: (t, int, timeUnit) => array = "formatToParts" diff --git a/runtime/Intl_Segmenter.res b/runtime/Intl_Segmenter.res new file mode 100644 index 0000000000..cd5306b962 --- /dev/null +++ b/runtime/Intl_Segmenter.res @@ -0,0 +1,34 @@ +/*** +Not supported in Firefox +*/ +type t + +type granularity = [#grapheme | #word | #sentence] + +type options = { + localeMatcher?: Intl_Common.localeMatcher, + granularity?: granularity, +} + +type pluralCategories = [ + | #zero + | #one + | #two + | #few + | #many + | #other +] + +type resolvedOptions = {locale: string, granularity: granularity} + +type supportedLocalesOptions = {localeMatcher: Intl_Common.localeMatcher} + +@new external make: (~locales: array=?, ~options: options=?) => t = "Intl.Segmenter" + +@val +external supportedLocalesOf: (array, ~options: supportedLocalesOptions=?) => t = + "Intl.Segmenter.supportedLocalesOf" + +@send external resolvedOptions: t => resolvedOptions = "resolvedOptions" + +@send external segment: (t, string) => Intl_Segments.t = "segment" diff --git a/runtime/Intl_Segments.res b/runtime/Intl_Segments.res new file mode 100644 index 0000000000..33b06ea177 --- /dev/null +++ b/runtime/Intl_Segments.res @@ -0,0 +1,18 @@ +/*** + A Segments instance is an object that represents the segments of a specific string, subject to the locale and options of its constructing Intl.Segmenter instance. +https://tc39.es/ecma402/#sec-segments-objects +*/ +type t + +type segmentData = { + segment: string, + index: int, + isWordLike: option, + input: string, +} + +@send +external containing: t => segmentData = "containing" + +@send +external containingWithIndex: (t, int) => segmentData = "containing" diff --git a/runtime/Iterator.res b/runtime/Iterator.res new file mode 100644 index 0000000000..80b6829e12 --- /dev/null +++ b/runtime/Iterator.res @@ -0,0 +1,20 @@ +type t<'a> + +type value<'a> = { + done: bool, + value: option<'a>, +} + +@send external next: t<'a> => value<'a> = "next" +external toArray: t<'a> => array<'a> = "Array.from" +external toArrayWithMapper: (t<'a>, 'a => 'b) => array<'b> = "Array.from" + +let forEach = (iterator, f) => { + let iteratorDone = ref(false) + + while !iteratorDone.contents { + let {done, value} = iterator->next + f(value) + iteratorDone := done + } +} diff --git a/runtime/Iterator.resi b/runtime/Iterator.resi new file mode 100644 index 0000000000..300d4fca7b --- /dev/null +++ b/runtime/Iterator.resi @@ -0,0 +1,101 @@ +/*** +Bindings to JavaScript iterators. + +See [`iterator protocols`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols) on MDN. +*/ + +/** +The type representing an iterator. +*/ +type t<'a> + +/** +The current value of an iterator. +*/ +type value<'a> = { + /** + Whether there are more values to iterate on before the iterator is done. + */ + done: bool, + /** + The value of this iteration, if any. + */ + value: option<'a>, +} + +/** +Returns the next value of the iterator, if any. + +See [iterator protocols](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols) on MDN. + +## Examples +```rescript +@val external someIterator: Iterator.t = "someIterator" + +// Pulls out the next value of the iterator +let {Iterator.done, value} = someIterator->Iterator.next +``` +*/ +@send +external next: t<'a> => value<'a> = "next" + +/** +Turns an iterator into an array of the remaining values. +Remember that each invocation of `next` of an iterator consumes a value. `Iterator.toArray` will consume all remaining values of the iterator and return them in an array to you. + +See [iterator protocols](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols) on MDN. + +## Examples +```rescript +let map = Map.make() +map->Map.set("someKey", "someValue") +map->Map.set("someKey2", "someValue2") + +// `Map.keys` returns all keys of the map as an iterator. +let mapKeysAsArray = map->Map.keys->Iterator.toArray + +Console.log(mapKeysAsArray) // Logs ["someKey", "someKey2"] to the console. +``` +*/ +external toArray: t<'a> => array<'a> = "Array.from" + +/** +`toArray(iterator)` turns `iterator` into an array of its remaining values, applying the provided mapper function on each item. +Remember that each invocation of `next` of an iterator consumes a value. `Iterator.toArrayWithMapper` will consume all remaining values of the iterator and return them in an array to you. + +See [iterator protocols](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols) on MDN. + +## Examples +```rescript +let map = Map.make() +map->Map.set("someKey", "someValue") +map->Map.set("someKey2", "someValue2") + +// `Map.keys` returns all keys of the map as an iterator. +let mapKeysAsArray = map + ->Map.keys + ->Iterator.toArrayWithMapper(key => key->String.length) + +Console.log(mapKeysAsArray) // Logs [7, 8] to the console. +``` +*/ +external toArrayWithMapper: (t<'a>, 'a => 'b) => array<'b> = "Array.from" + +/** +`forEach(iterator, fn)` consumes all values in the iterator and runs the callback `fn` for each value. + +See [iterator protocols](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols) on MDN. + +## Examples +```rescript +@val external someIterator: Iterator.t = "someIterator" + +someIterator->Iterator.forEach(value => + switch value { + | Some(value) if value > 10 => Console.log("More than 10!") + | _ => () + } +) +``` +*/ +let forEach: (t<'a>, option<'a> => unit) => unit diff --git a/runtime/JSON.res b/runtime/JSON.res new file mode 100644 index 0000000000..b9ee231e8c --- /dev/null +++ b/runtime/JSON.res @@ -0,0 +1,94 @@ +@unboxed +type rec t = Js.Json.t = + | Boolean(bool) + | @as(null) Null + | String(string) + | Number(float) + | Object(Dict.t) + | Array(array) + +@unboxed +type replacer = Keys(array) | Replacer((string, t) => t) + +@raises @val external parseExn: (string, ~reviver: (string, t) => t=?) => t = "JSON.parse" +@deprecated("Use `parseExn` with optional parameter instead") @raises @val +external parseExnWithReviver: (string, (string, t) => t) => t = "JSON.parse" + +@val external stringify: (t, ~replacer: replacer=?, ~space: int=?) => string = "JSON.stringify" +@deprecated("Use `stringify` with optional parameter instead") @val +external stringifyWithIndent: (t, @as(json`null`) _, int) => string = "JSON.stringify" +@deprecated("Use `stringify` with optional parameter instead") @val +external stringifyWithReplacer: (t, (string, t) => t) => string = "JSON.stringify" +@deprecated("Use `stringify` with optional parameters instead") @val +external stringifyWithReplacerAndIndent: (t, (string, t) => t, int) => string = "JSON.stringify" +@deprecated("Use `stringify` with optional parameter instead") @val +external stringifyWithFilter: (t, array) => string = "JSON.stringify" +@deprecated("Use `stringify` with optional parameters instead") @val +external stringifyWithFilterAndIndent: (t, array, int) => string = "JSON.stringify" + +@raises @val +external stringifyAny: ('a, ~replacer: replacer=?, ~space: int=?) => option = + "JSON.stringify" +@deprecated("Use `stringifyAny` with optional parameter instead") @raises @val +external stringifyAnyWithIndent: ('a, @as(json`null`) _, int) => option = "JSON.stringify" +@deprecated("Use `stringifyAny` with optional parameter instead") @raises @val +external stringifyAnyWithReplacer: ('a, (string, t) => t) => option = "JSON.stringify" +@deprecated("Use `stringifyAny` with optional parameters instead") @raises @val +external stringifyAnyWithReplacerAndIndent: ('a, (string, t) => t, int) => option = + "JSON.stringify" +@deprecated("Use `stringifyAny` with optional parameter instead") @raises @val +external stringifyAnyWithFilter: ('a, array) => string = "JSON.stringify" +@deprecated("Use `stringifyAny` with optional parameters instead") @raises @val +external stringifyAnyWithFilterAndIndent: ('a, array, int) => string = "JSON.stringify" + +module Classify = { + type t = + | Bool(bool) + | Null + | String(string) + | Number(float) + | Object(Dict.t) + | Array(array) + + @val external _internalClass: 'a => string = "Object.prototype.toString.call" + external _asBool: 'a => bool = "%identity" + external _asString: 'a => string = "%identity" + external _asFloat: 'a => float = "%identity" + external _asArray: 'a => array = "%identity" + external _asDict: 'a => Dict.t = "%identity" + + let classify = value => { + switch _internalClass(value) { + | "[object Boolean]" => Bool(_asBool(value)) + | "[object Null]" => Null + | "[object String]" => String(_asString(value)) + | "[object Number]" => Number(_asFloat(value)) + | "[object Array]" => Array(_asArray(value)) + | _ => Object(_asDict(value)) + } + } +} + +module Encode = { + external bool: bool => t = "%identity" + external null: t = "#null" + external string: string => t = "%identity" + external int: int => t = "%identity" + external float: float => t = "%identity" + external object: Dict.t => t = "%identity" + external array: array => t = "%identity" +} + +module Decode = { + let bool = (json: t) => Type.typeof(json) === #boolean ? Some((Obj.magic(json): bool)) : None + let null = (json: t) => Obj.magic(json) === Null.null ? Some(Null.null) : None + let string = (json: t) => Type.typeof(json) === #string ? Some((Obj.magic(json): string)) : None + let float = (json: t) => Type.typeof(json) === #number ? Some((Obj.magic(json): float)) : None + let object = (json: t) => + if Type.typeof(json) === #object && !Array.isArray(json) && !(Obj.magic(json) === Null.null) { + Some((Obj.magic(json): Dict.t)) + } else { + None + } + let array = (json: t) => Array.isArray(json) ? Some((Obj.magic(json): array)) : None +} diff --git a/runtime/JSON.resi b/runtime/JSON.resi new file mode 100644 index 0000000000..eeccc56bad --- /dev/null +++ b/runtime/JSON.resi @@ -0,0 +1,762 @@ +/*** +Functions for interacting with JSON. +*/ + +/** +A type representing a JSON object. +*/ +@unboxed +type rec t = Js.Json.t = + | Boolean(bool) + | @as(null) Null + | String(string) + | Number(float) + | Object(Dict.t) + | Array(array) + +@unboxed +type replacer = Keys(array) | Replacer((string, t) => t) + +/** +`parseExn(string, ~reviver=?)` + +Parses a JSON string or throws a JavaScript exception (SyntaxError), if the string isn't valid. +The reviver describes how the value should be transformed. It is a function which receives a key and a value. +It returns a JSON type. + +## Examples +```rescript +try { + let _ = JSON.parseExn(`{"foo":"bar","hello":"world"}`) + // { foo: 'bar', hello: 'world' } + + let _ = JSON.parseExn("") + // error +} catch { +| Exn.Error(_) => Console.log("error") +} + +let reviver = (_, value: JSON.t) => + switch value { + | String(string) => string->String.toUpperCase->JSON.Encode.string + | Number(number) => (number *. 2.0)->JSON.Encode.float + | _ => value + } + +let jsonString = `{"hello":"world","someNumber":21}` + +try { + JSON.parseExn(jsonString, ~reviver)->Console.log + // { hello: 'WORLD', someNumber: 42 } + + JSON.parseExn("", ~reviver)->Console.log + // error +} catch { +| Exn.Error(_) => Console.log("error") +} +``` + +## Exceptions + +- Raises a SyntaxError (Exn.t) if the string isn't valid JSON. +*/ +@raises(Exn.t) +@val +external parseExn: (string, ~reviver: (string, t) => t=?) => t = "JSON.parse" + +/** +`parseExnWithReviver(string, reviver)` + +Parses a JSON string or throws a JavaScript exception (SyntaxError), if the string isn't valid. +The reviver describes how the value should be transformed. It is a function which receives a key and a value. +It returns a JSON type. + +## Examples +```rescript +let reviver = (_, value: JSON.t) => + switch value { + | String(string) => string->String.toUpperCase->JSON.Encode.string + | Number(number) => (number *. 2.0)->JSON.Encode.float + | _ => value + } + +let jsonString = `{"hello":"world","someNumber":21}` + +try { + JSON.parseExnWithReviver(jsonString, reviver)->Console.log + // { hello: 'WORLD', someNumber: 42 } + + JSON.parseExnWithReviver("", reviver)->Console.log + // error +} catch { +| Exn.Error(_) => Console.log("error") +} +``` + +## Exceptions + +- Raises a SyntaxError if the string isn't valid JSON. +*/ +@deprecated("Use `parseExn` with optional parameter instead") +@raises(Exn.t) +@val +external parseExnWithReviver: (string, (string, t) => t) => t = "JSON.parse" + +/** +`stringify(json, ~replacer=?, ~space=?)` + +Converts a JSON object to a JSON string. +The replacer describes how the value should be transformed. It is a function which receives a key and a value, +or an array of keys which should be included in the output. +If you want to stringify any type, use `JSON.stringifyAny` instead. + +## Examples +```rescript +let json = + Dict.fromArray([ + ("foo", JSON.Encode.string("bar")), + ("hello", JSON.Encode.string("world")), + ("someNumber", JSON.Encode.int(42)), + ])->JSON.Encode.object + +JSON.stringify(json) +// {"foo":"bar","hello":"world","someNumber":42} + +JSON.stringify(json, ~space=2) +// { +// "foo": "bar", +// "hello": "world", +// "someNumber": 42 +// } + +JSON.stringify(json, ~replacer=Keys(["foo", "someNumber"])) +// {"foo":"bar","someNumber":42} + +let replacer = JSON.Replacer((_, value) => { + let decodedValue = value->JSON.Decode.string + + switch decodedValue { + | Some(string) => string->String.toUpperCase->JSON.Encode.string + | None => value + } +}) + +JSON.stringify(json, ~replacer) +// {"foo":"BAR","hello":"WORLD","someNumber":42} +``` +*/ +@val +external stringify: (t, ~replacer: replacer=?, ~space: int=?) => string = "JSON.stringify" + +/** +`stringifyWithIndent(json, indentation)` + +Converts a JSON object to a JSON string. The output will be indented. +If you want to stringify any type, use `JSON.stringifyAnyWithIndent` instead. + +## Examples +```rescript +let json = + Dict.fromArray([ + ("foo", JSON.Encode.string("bar")), + ("hello", JSON.Encode.string("world")), + ("someNumber", JSON.Encode.int(42)), + ])->JSON.Encode.object + +JSON.stringifyWithIndent(json, 2) +// { +// "foo": "bar", +// "hello": "world", +// "someNumber": 42 +// } +``` +*/ +@deprecated("Use `stringify` with optional parameter instead") +@val +external stringifyWithIndent: (t, @as(json`null`) _, int) => string = "JSON.stringify" + +/** +`stringifyWithReplacer(json, replacer)` + +Converts a JSON object to a JSON string. +The replacer describes how the value should be transformed. It is a function which receives a key and a value. +If you want to stringify any type, use `JSON.stringifyAnyWithReplacer` instead. + +## Examples +```rescript +let json = + Dict.fromArray([ + ("foo", JSON.Encode.string("bar")), + ("hello", JSON.Encode.string("world")), + ("someNumber", JSON.Encode.int(42)), + ])->JSON.Encode.object + +let replacer = (_, value) => { + let decodedValue = value->JSON.Decode.string + + switch decodedValue { + | Some(string) => string->String.toUpperCase->JSON.Encode.string + | None => value + } +} + +JSON.stringifyWithReplacer(json, replacer) +// {"foo":"BAR","hello":"WORLD","someNumber":42} +``` +*/ +@deprecated("Use `stringify` with optional parameter instead") +@val +external stringifyWithReplacer: (t, (string, t) => t) => string = "JSON.stringify" + +/** +`stringifyWithReplacerAndIndent(json, replacer, indentation)` + +Converts a JSON object to a JSON string. The output will be indented. +The replacer describes how the value should be transformed. It is a function which receives a key and a value. +If you want to stringify any type, use `JSON.stringifyAnyWithReplacerAndIndent` instead. + +## Examples +```rescript +let json = + Dict.fromArray([ + ("foo", JSON.Encode.string("bar")), + ("hello", JSON.Encode.string("world")), + ("someNumber", JSON.Encode.int(42)), + ])->JSON.Encode.object + +let replacer = (_, value) => { + let decodedValue = value->JSON.Decode.string + + switch decodedValue { + | Some(string) => string->String.toUpperCase->JSON.Encode.string + | None => value + } +} + +JSON.stringifyWithReplacerAndIndent(json, replacer, 2) +// { +// "foo": "BAR", +// "hello": "WORLD", +// "someNumber": 42 +// } +``` +*/ +@deprecated("Use `stringify` with optional parameters instead") +@val +external stringifyWithReplacerAndIndent: (t, (string, t) => t, int) => string = "JSON.stringify" + +/** +`stringifyWithFilter(json, filter)` + +Converts a JSON object to a JSON string. +The filter is an array of keys, which should be included in the output. +If you want to stringify any type, use `JSON.stringifyAnyWithFilter` instead. + +## Examples +```rescript +let json = + Dict.fromArray([ + ("foo", JSON.Encode.string("bar")), + ("hello", JSON.Encode.string("world")), + ("someNumber", JSON.Encode.int(42)), + ])->JSON.Encode.object + +JSON.stringifyWithFilter(json, ["foo", "someNumber"]) +// {"foo":"bar","someNumber":42} +``` +*/ +@deprecated("Use `stringify` with optional parameter instead") +@val +external stringifyWithFilter: (t, array) => string = "JSON.stringify" + +/** +`stringifyWithFilterAndIndent(json, filter, indentation)` + +Converts a JSON object to a JSON string. The output will be indented. +The filter is an array of keys, which should be included in the output. +If you want to stringify any type, use `JSON.stringifyAnyWithFilterAndIndent` instead. + +## Examples +```rescript +let json = + Dict.fromArray([ + ("foo", JSON.Encode.string("bar")), + ("hello", JSON.Encode.string("world")), + ("someNumber", JSON.Encode.int(42)), + ])->JSON.Encode.object + +JSON.stringifyWithFilterAndIndent(json, ["foo", "someNumber"], 2) +// { +// "foo": "bar", +// "someNumber": 42 +// } +``` +*/ +@deprecated("Use `stringify` with optional parameters instead") +@val +external stringifyWithFilterAndIndent: (t, array, int) => string = "JSON.stringify" + +/** +`stringifyAny(any, ~replacer=?, ~space=?)` + +Converts any type to a JSON string. +The replacer describes how the value should be transformed. It is a function which receives a key and a value. +Stringifying a function or `undefined` will return `None`. +If the value contains circular references or `BigInt`s, the function will throw a JavaScript exception (TypeError). +If you want to stringify a JSON object, use `JSON.stringify` instead. + +## Examples +```rescript +let dict = Dict.fromArray([ + ("foo", JSON.Encode.string("bar")), + ("hello", JSON.Encode.string("world")), + ("someNumber", JSON.Encode.int(42)), +]) + +JSON.stringifyAny(dict) +// {"foo":"bar","hello":"world","someNumber":42} + +JSON.stringifyAny(dict, ~space=2) +// { +// "foo": "bar", +// "hello": "world", +// "someNumber": 42 +// } + +JSON.stringifyAny(dict, ~replacer=Keys(["foo", "someNumber"])) +// {"foo":"bar","someNumber":42} + +let replacer = JSON.Replacer((_, value) => { + let decodedValue = value->JSON.Decode.string + + switch decodedValue { + | Some(string) => string->String.toUpperCase->JSON.Encode.string + | None => value + } +}) + +JSON.stringifyAny(dict, ~replacer) +// {"foo":"BAR","hello":"WORLD","someNumber":42} + +JSON.stringifyAny(() => "hello world") +// None + +BigInt.fromInt(0)->JSON.stringifyAny +// exception +``` + +## Exceptions + +- Raises a TypeError if the value contains circular references. +- Raises a TypeError if the value contains `BigInt`s. +*/ +@raises(Exn.t) +@val +external stringifyAny: ('a, ~replacer: replacer=?, ~space: int=?) => option = + "JSON.stringify" + +/** +`stringifyAnyWithIndent(any, indentation)` + +Converts any type to a JSON string. The output will be indented. +Stringifying a function or `undefined` will return `None`. +If the value contains circular references or `BigInt`s, the function will throw a JavaScript exception (TypeError). +If you want to stringify a JSON object, use `JSON.stringifyWithIndent` instead. + +## Examples +```rescript +let dict = Dict.fromArray([ + ("foo", JSON.Encode.string("bar")), + ("hello", JSON.Encode.string("world")), + ("someNumber", JSON.Encode.int(42)), +]) + +JSON.stringifyAnyWithIndent(dict, 2) +// { +// "foo": "bar", +// "hello": "world", +// "someNumber": 42 +// } + +JSON.stringifyAny(() => "hello world") +// None + +BigInt.fromInt(0)->JSON.stringifyAny +// exception +``` + +## Exceptions + +- Raises a TypeError if the value contains circular references. +- Raises a TypeError if the value contains `BigInt`s. +*/ +@deprecated("Use `stringifyAny` with optional parameter instead") +@raises(Exn.t) +@val +external stringifyAnyWithIndent: ('a, @as(json`null`) _, int) => option = "JSON.stringify" + +/** +`stringifyAnyWithReplacer(json, replacer)` + +Converts any type to a JSON string. +The replacer describes how the value should be transformed. It is a function which receives a key and a value. +Stringifying a function or `undefined` will return `None`. +If the value contains circular references or `BigInt`s, the function will throw a JavaScript exception (TypeError). +If you want to stringify a JSON object, use `JSON.stringifyWithReplacer` instead. + +## Examples +```rescript +let dict = Dict.fromArray([ + ("foo", JSON.Encode.string("bar")), + ("hello", JSON.Encode.string("world")), + ("someNumber", JSON.Encode.int(42)), +]) + +let replacer = (_, value) => { + let decodedValue = value->JSON.Decode.string + + switch decodedValue { + | Some(string) => string->String.toUpperCase->JSON.Encode.string + | None => value + } +} + +JSON.stringifyAnyWithReplacer(dict, replacer) +// {"foo":"BAR","hello":"WORLD","someNumber":42} + +JSON.stringifyAny(() => "hello world") +// None + +BigInt.fromInt(0)->JSON.stringifyAny +// exception +``` + +## Exceptions + +- Raises a TypeError if the value contains circular references. +- Raises a TypeError if the value contains `BigInt`s. +*/ +@deprecated("Use `stringifyAny` with optional parameter instead") +@raises +@val +external stringifyAnyWithReplacer: ('a, (string, t) => t) => option = "JSON.stringify" + +/** +`stringifyAnyWithReplacerAndIndent(json, replacer, indentation)` + +Converts any type to a JSON string. The output will be indented. +The replacer describes how the value should be transformed. It is a function which receives a key and a value. +Stringifying a function or `undefined` will return `None`. +If the value contains circular references or `BigInt`s, the function will throw a JavaScript exception (TypeError). +If you want to stringify a JSON object, use `JSON.stringifyWithReplacerAndIndent` instead. + +## Examples +```rescript +let dict = Dict.fromArray([ + ("foo", JSON.Encode.string("bar")), + ("hello", JSON.Encode.string("world")), + ("someNumber", JSON.Encode.int(42)), +]) + +let replacer = (_, value) => { + let decodedValue = value->JSON.Decode.string + + switch decodedValue { + | Some(string) => string->String.toUpperCase->JSON.Encode.string + | None => value + } +} + +JSON.stringifyAnyWithReplacerAndIndent(dict, replacer, 2) +// { +// "foo": "BAR", +// "hello": "WORLD", +// "someNumber": 42 +// } + +JSON.stringifyAny(() => "hello world") +// None + +BigInt.fromInt(0)->JSON.stringifyAny +// exception +``` + +## Exceptions + +- Raises a TypeError if the value contains circular references. +- Raises a TypeError if the value contains `BigInt`s. +*/ +@deprecated("Use `stringifyAny` with optional parameters instead") +@raises +@val +external stringifyAnyWithReplacerAndIndent: ('a, (string, t) => t, int) => option = + "JSON.stringify" + +/** +`stringifyAnyWithFilter(json, filter)` + +Converts any type to a JSON string. +The filter is an array of keys, which should be included in the output. +Stringifying a function or `undefined` will return `None`. +If the value contains circular references or `BigInt`s, the function will throw a JavaScript exception (TypeError). +If you want to stringify a JSON object, use `JSON.stringifyWithFilter` instead. + +## Examples +```rescript +let dict = Dict.fromArray([ + ("foo", JSON.Encode.string("bar")), + ("hello", JSON.Encode.string("world")), + ("someNumber", JSON.Encode.int(42)), +]) + +JSON.stringifyAnyWithFilter(dict, ["foo", "someNumber"]) +// {"foo": "bar","someNumber": 42} + +JSON.stringifyAny(() => "hello world") +// None + +BigInt.fromInt(0)->JSON.stringifyAny +// exception +``` + +## Exceptions + +- Raises a TypeError if the value contains circular references. +- Raises a TypeError if the value contains `BigInt`s. +*/ +@deprecated("Use `stringifyAny` with optional parameter instead") +@raises +@val +external stringifyAnyWithFilter: ('a, array) => string = "JSON.stringify" + +/** +`stringifyAnyWithFilterAndIndent(json, filter, indentation)` + +Converts any type to a JSON string. The output will be indented. +The filter is an array of keys, which should be included in the output. +Stringifying a function or `undefined` will return `None`. +If the value contains circular references or `BigInt`s, the function will throw a JavaScript exception (TypeError). +If you want to stringify a JSON object, use `JSON.stringifyWithFilterAndIndent` instead. + +## Examples +```rescript +let dict = Dict.fromArray([ + ("foo", JSON.Encode.string("bar")), + ("hello", JSON.Encode.string("world")), + ("someNumber", JSON.Encode.int(42)), +]) + +JSON.stringifyAnyWithFilterAndIndent(dict, ["foo", "someNumber"], 2) +// { +// "foo": "bar", +// "someNumber": 42 +// } + +JSON.stringifyAny(() => "hello world") +// None + +BigInt.fromInt(0)->JSON.stringifyAny +// exception +``` + +## Exceptions + +- Raises a TypeError if the value contains circular references. +- Raises a TypeError if the value contains `BigInt`s. +*/ +@deprecated("Use `stringifyAny` with optional parameters instead") +@raises +@val +external stringifyAnyWithFilterAndIndent: ('a, array, int) => string = "JSON.stringify" + +module Classify: { + /** + A type representing a JavaScript type. + */ + type t = + | Bool(bool) + | Null + | String(string) + | Number(float) + | Object(Dict.t) + | Array(array) + + /** + Returns the JSON type of any value. + + ## Examples + ```rescript + JSON.Classify.classify("hello world") + // String("hello world") + + JSON.Classify.classify(42) + // Number(42) + ``` + */ + let classify: 'a => t +} + +module Encode: { + /** + Returns a boolean as a JSON object. + + ## Examples + ```rescript + JSON.Encode.bool(true) + ``` + */ + external bool: bool => t = "%identity" + + /** + Returns null as a JSON object. + + ## Examples + ```rescript + JSON.Encode.null + ``` + */ + external null: t = "#null" + + /** + Returns a string as a JSON object. + + ## Examples + ```rescript + JSON.Encode.string("hello world") + ``` + */ + external string: string => t = "%identity" + + /** + Returns an int as a JSON object. + + ## Examples + ```rescript + JSON.Encode.int(42) + ``` + */ + external int: int => t = "%identity" + + /** + Returns a float as a JSON object. + + ## Examples + ```rescript + JSON.Encode.float(42.0) + ``` + */ + external float: float => t = "%identity" + + /** + Returns a dict as a JSON object. + + ## Examples + ```rescript + let dict = Dict.fromArray([ + ("foo", JSON.Encode.string("bar")), + ("hello", JSON.Encode.string("world")), + ]) + + JSON.Encode.object(dict) + ``` + */ + external object: Dict.t => t = "%identity" + + /** + Returns an array as a JSON object. + + ## Examples + ```rescript + let array = [JSON.Encode.string("hello world"), JSON.Encode.int(42)] + + JSON.Encode.array(array) + ``` + */ + external array: array => t = "%identity" +} + +module Decode: { + /** + Decodes a single JSON value. If the value is a bool, it will return `Some(bool)` - otherwise it will return `None`. + + ## Examples + ```rescript + JSON.parseExn(`true`)->JSON.Decode.bool + // Some(true) + + JSON.parseExn(`"hello world"`)->JSON.Decode.bool + // None + ``` + */ + let bool: t => option + + /** + Decodes a single JSON value. If the value is null, it will return `Some(Null.t)` - otherwise it will return `None`. + + ## Examples + ```rescript + JSON.parseExn(`null`)->JSON.Decode.null + // Some(null) + + JSON.parseExn(`"hello world"`)->JSON.Decode.null + // None + ``` + */ + let null: t => option> + + /** + Decodes a single JSON value. If the value is a string, it will return `Some(string)` - otherwise it will return `None`. + + ## Examples + ```rescript + JSON.parseExn(`"hello world"`)->JSON.Decode.string + // Some("hello world") + + JSON.parseExn(`42`)->JSON.Decode.string + // None + ``` + */ + let string: t => option + + /** + Decodes a single JSON value. If the value is a float, it will return `Some(float)` - otherwise it will return `None`. + + ## Examples + ```rescript + JSON.parseExn(`42.0`)->JSON.Decode.float + // Some(42.0) + + JSON.parseExn(`"hello world"`)->JSON.Decode.float + // None + ``` + */ + let float: t => option + + /** + Decodes a single JSON value. If the value is an object, it will return `Some(Dict.t)` - otherwise it will return `None`. + + ## Examples + ```rescript + JSON.parseExn(`{"foo":"bar"}`)->JSON.Decode.object + // Some({ foo: 'bar' }) + + JSON.parseExn(`"hello world"`)->JSON.Decode.object + // None + ``` + */ + let object: t => option> + + /** + Decodes a single JSON value. If the value is an array, it will return `Some(array)` - otherwise it will return `None`. + + ## Examples + ```rescript + JSON.parseExn(`["foo", "bar"]`)->JSON.Decode.array + // Some([ 'foo', 'bar' ]) + + JSON.parseExn(`"hello world"`)->JSON.Decode.array + // None + ``` + */ + let array: t => option> +} diff --git a/runtime/Js.res b/runtime/Js.res index 72c535cdb6..fbca7efc08 100644 --- a/runtime/Js.res +++ b/runtime/Js.res @@ -86,7 +86,7 @@ module Nullable = Js_null_undefined module Null_undefined = Js_null_undefined /** Provide utilities for dealing with Js exceptions */ -module Exn = Js_exn +module Exn = Exn /** Provide bindings to JS array*/ module Array = Js_array diff --git a/runtime/Js_null.res b/runtime/Js_null.res index 33f73888f2..1943fc60f4 100644 --- a/runtime/Js_null.res +++ b/runtime/Js_null.res @@ -36,7 +36,7 @@ external getUnsafe: t<'a> => 'a = "%identity" let getExn = f => switch toOption(f) { - | None => Js_exn.raiseError("Js.Null.getExn") + | None => Exn.raiseError("Js.Null.getExn") | Some(x) => x } diff --git a/runtime/Js_option.res b/runtime/Js_option.res index 8cb8074247..fb48406df4 100644 --- a/runtime/Js_option.res +++ b/runtime/Js_option.res @@ -86,7 +86,7 @@ If given `None`, it throws a `getExn` exception. */ let getExn = x => switch x { - | None => Js_exn.raiseError("getExn") + | None => Exn.raiseError("getExn") | Some(x) => x } diff --git a/runtime/Js_undefined.res b/runtime/Js_undefined.res index 00924699ee..699004cea6 100644 --- a/runtime/Js_undefined.res +++ b/runtime/Js_undefined.res @@ -37,7 +37,7 @@ external getUnsafe: t<'a> => 'a = "%identity" let getExn = f => switch toOption(f) { - | None => Js_exn.raiseError("Js.Undefined.getExn") + | None => Exn.raiseError("Js.Undefined.getExn") | Some(x) => x } diff --git a/runtime/List.res b/runtime/List.res index 334b2f8937..3edf67117f 100644 --- a/runtime/List.res +++ b/runtime/List.res @@ -1,740 +1,865 @@ -// FIXME: -// This exists for compatibility reason. -// Move this into Pervasives or Core +/* Copyright (C) 2017 Hongbo Zhang, Authors of ReScript + * + * 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. */ + +/* + perf is not everything, there are better memory represenations + + ``` + type 'a cell = { + mutable head : 'a; + mutable tail : 'a opt_cell + } + + and 'a opt_cell = 'a cell Js.null + + and 'a t = { + length : int ; + data : 'a opt_cell + } + ``` + However, + - people use List not because of its perf, but its + convenience, in that case, pattern match and compatibility seems + more attractive, we could keep a mutable list + - The built in types would indicate that + its construtor is immutable, a better optimizer would break such code + + ``` + type 'a t = { + head : 'a; + mutable tail : 'a t | int + } + ``` + In the future, we could come up with a safer version + ``` + type 'a t = + | Nil + | Cons of { hd : 'a ; mutable tail : 'a t } + ``` +*/ -// Below is all deprecated and should be removed in v13 +@@config({flags: ["-bs-noassertfalse"]}) type t<'a> = list<'a> -let rec length_aux = (len, param) => - switch param { - | list{} => len - | list{_, ...l} => length_aux(len + 1, l) +module A = { + @new external makeUninitializedUnsafe: int => array<'a> = "Array" + external min: ('a, 'a) => 'a = "%bs_min" + + let reduceReverseU = (a, x, f) => { + let r = ref(x) + for i in Array.length(a) - 1 downto 0 { + r.contents = f(r.contents, Array.getUnsafe(a, i)) + } + r.contents + } + + let reduceReverse2U = (a, b, x, f) => { + let r = ref(x) + let len = min(Array.length(a), Array.length(b)) + for i in len - 1 downto 0 { + r.contents = f(r.contents, Array.getUnsafe(a, i), Array.getUnsafe(b, i)) + } + r.contents + } +} + +external mutableCell: ('a, t<'a>) => t<'a> = "#makemutablelist" + +/* + `mutableCell x []` == `x` + but tell the compiler that is a mutable cell, so it wont + be mis-inlined in the future + dont inline a binding to mutable cell, it is mutable +*/ +/* INVARIANT: relies on Literals.tl (internal representation) */ +@set external unsafeMutateTail: (t<'a>, t<'a>) => unit = "tl" + +/* + - the cell is not empty +*/ + +let head = x => + switch x { + | list{} => None + | list{x, ..._} => Some(x) + } + +let headExn = x => + switch x { + | list{} => raise(Not_found) + | list{x, ..._} => x + } + +let tail = x => + switch x { + | list{} => None + | list{_, ...xs} => Some(xs) } -let length = l => length_aux(0, l) +let tailExn = x => + switch x { + | list{} => raise(Not_found) + | list{_, ...t} => t + } -let cons = (a, l) => list{a, ...l} +let add = (xs, x) => list{x, ...xs} -let hd = param => - switch param { - | list{} => failwith("hd") - | list{a, ..._} => a +/* Assume `n >=0` */ +let rec nthAux = (x, n) => + switch x { + | list{h, ...t} => + if n == 0 { + Some(h) + } else { + nthAux(t, n - 1) + } + | _ => None } -let tl = param => - switch param { - | list{} => failwith("tl") - | list{_, ...l} => l +let rec nthAuxAssert = (x, n) => + switch x { + | list{h, ...t} => + if n == 0 { + h + } else { + nthAuxAssert(t, n - 1) + } + | _ => raise(Not_found) } -let nth = (l, n) => +let get = (x, n) => if n < 0 { - invalid_arg("List.nth") + None } else { - let rec nth_aux = (l, n) => - switch l { - | list{} => failwith("nth") - | list{a, ...l} => - if n == 0 { - a - } else { - nth_aux(l, n - 1) - } - } - nth_aux(l, n) + nthAux(x, n) } -let nth_opt = (l, n) => +let getExn = (x, n) => if n < 0 { - invalid_arg("List.nth") + raise(Not_found) } else { - let rec nth_aux = (l, n) => - switch l { - | list{} => None - | list{a, ...l} => - if n == 0 { - Some(a) - } else { - nth_aux(l, n - 1) - } - } - nth_aux(l, n) + nthAuxAssert(x, n) } -let append = \"@" +let rec partitionAux = (p, cell, precX, precY) => + switch cell { + | list{} => () + | list{h, ...t} => + let next = mutableCell(h, list{}) + if p(h) { + unsafeMutateTail(precX, next) + partitionAux(p, t, next, precY) + } else { + unsafeMutateTail(precY, next) + partitionAux(p, t, precX, next) + } + } -let rec rev_append = (l1, l2) => - switch l1 { - | list{} => l2 - | list{a, ...l} => rev_append(l, list{a, ...l2}) +let rec splitAux = (cell, precX, precY) => + switch cell { + | list{} => () + | list{(a, b), ...t} => + let nextA = mutableCell(a, list{}) + let nextB = mutableCell(b, list{}) + unsafeMutateTail(precX, nextA) + unsafeMutateTail(precY, nextB) + splitAux(t, nextA, nextB) + } + +/* return the tail pointer so it can continue copy other + list +*/ +let rec copyAuxCont = (cellX, prec) => + switch cellX { + | list{} => prec + | list{h, ...t} => + let next = mutableCell(h, list{}) + unsafeMutateTail(prec, next) + copyAuxCont(t, next) + } + +let rec copyAuxWitFilter = (f, cellX, prec) => + switch cellX { + | list{} => () + | list{h, ...t} => + if f(h) { + let next = mutableCell(h, list{}) + unsafeMutateTail(prec, next) + copyAuxWitFilter(f, t, next) + } else { + copyAuxWitFilter(f, t, prec) + } + } + +let rec copyAuxWithFilterIndex = (f, cellX, prec, i) => + switch cellX { + | list{} => () + | list{h, ...t} => + if f(h, i) { + let next = mutableCell(h, list{}) + unsafeMutateTail(prec, next) + copyAuxWithFilterIndex(f, t, next, i + 1) + } else { + copyAuxWithFilterIndex(f, t, prec, i + 1) + } + } + +let rec copyAuxWitFilterMap = (f, cellX, prec) => + switch cellX { + | list{} => () + | list{h, ...t} => + switch f(h) { + | Some(h) => + let next = mutableCell(h, list{}) + unsafeMutateTail(prec, next) + copyAuxWitFilterMap(f, t, next) + | None => copyAuxWitFilterMap(f, t, prec) + } + } + +let rec removeAssocAuxWithMap = (cellX, x, prec, f) => + switch cellX { + | list{} => false + | list{(a, _) as h, ...t} => + if f(a, x) { + unsafeMutateTail(prec, t) + true + } else { + let next = mutableCell(h, list{}) + unsafeMutateTail(prec, next) + removeAssocAuxWithMap(t, x, next, f) + } + } + +let rec setAssocAuxWithMap = (cellX, x, k, prec, eq) => + switch cellX { + | list{} => false + | list{(a, _) as h, ...t} => + if eq(a, x) { + unsafeMutateTail(prec, list{(x, k), ...t}) + true + } else { + let next = mutableCell(h, list{}) + unsafeMutateTail(prec, next) + setAssocAuxWithMap(t, x, k, next, eq) + } + } + +let rec copyAuxWithMap = (cellX, prec, f) => + switch cellX { + | list{} => () + | list{h, ...t} => + let next = mutableCell(f(h), list{}) + unsafeMutateTail(prec, next) + copyAuxWithMap(t, next, f) + } + +let rec zipAux = (cellX, cellY, prec) => + switch (cellX, cellY) { + | (list{h1, ...t1}, list{h2, ...t2}) => + let next = mutableCell((h1, h2), list{}) + unsafeMutateTail(prec, next) + zipAux(t1, t2, next) + | (list{}, _) | (_, list{}) => () + } + +let rec copyAuxWithMap2 = (f, cellX, cellY, prec) => + switch (cellX, cellY) { + | (list{h1, ...t1}, list{h2, ...t2}) => + let next = mutableCell(f(h1, h2), list{}) + unsafeMutateTail(prec, next) + copyAuxWithMap2(f, t1, t2, next) + | (list{}, _) | (_, list{}) => () + } + +let rec copyAuxWithMapI = (f, i, cellX, prec) => + switch cellX { + | list{h, ...t} => + let next = mutableCell(f(h, i), list{}) + unsafeMutateTail(prec, next) + copyAuxWithMapI(f, i + 1, t, next) + | list{} => () } -let rev = l => rev_append(l, list{}) +let rec takeAux = (n, cell, prec) => + if n == 0 { + true + } else { + switch cell { + | list{} => false + | list{x, ...xs} => + let cell = mutableCell(x, list{}) + unsafeMutateTail(prec, cell) + takeAux(n - 1, xs, cell) + } + } -let rec init_tailrec_aux = (acc, i, n, f) => - if i >= n { - acc +let rec splitAtAux = (n, cell, prec) => + if n == 0 { + Some(cell) } else { - init_tailrec_aux(list{f(i), ...acc}, i + 1, n, f) + switch cell { + | list{} => None + | list{x, ...xs} => + let cell = mutableCell(x, list{}) + unsafeMutateTail(prec, cell) + splitAtAux(n - 1, xs, cell) + } } -let rec init_aux = (i, n, f) => - if i >= n { - list{} +/* invarint `n >= 0` */ +let take = (lst, n) => + if n < 0 { + None + } else if n == 0 { + Some(list{}) } else { - let r = f(i) - list{r, ...init_aux(i + 1, n, f)} + switch lst { + | list{} => None + | list{x, ...xs} => + let cell = mutableCell(x, list{}) + let has = takeAux(n - 1, xs, cell) + if has { + Some(cell) + } else { + None + } + } + } +/* invariant `n >= 0 ` */ +let rec dropAux = (l, n) => + if n == 0 { + Some(l) + } else { + switch l { + | list{_, ...tl} => dropAux(tl, n - 1) + | list{} => None + } } -let init = (len, f) => - if len < 0 { - invalid_arg("List.init") - } else if len > 10_000 { - rev(init_tailrec_aux(list{}, 0, len, f)) +let drop = (lst, n) => + if n < 0 { + None } else { - init_aux(0, len, f) + dropAux(lst, n) } -let rec flatten = param => - switch param { - | list{} => list{} - | list{l, ...r} => \"@"(l, flatten(r)) +let splitAt = (lst, n) => + if n < 0 { + None + } else if n == 0 { + Some(list{}, lst) + } else { + switch lst { + | list{} => None + | list{x, ...xs} => + let cell = mutableCell(x, list{}) + let rest = splitAtAux(n - 1, xs, cell) + switch rest { + | Some(rest) => Some(cell, rest) + | None => None + } + } } -let concat = flatten +let concat = (xs, ys) => + switch xs { + | list{} => ys + | list{h, ...t} => + let cell = mutableCell(h, list{}) + unsafeMutateTail(copyAuxCont(t, cell), ys) + cell + } -let rec map = (f, param) => - switch param { +let map = (xs, f) => + switch xs { | list{} => list{} - | list{a, ...l} => - let r = f(a) - list{r, ...map(f, l)} + | list{h, ...t} => + let cell = mutableCell(f(h), list{}) + copyAuxWithMap(t, cell, f) + cell + } + +let zipBy = (l1, l2, f) => + switch (l1, l2) { + | (list{a1, ...l1}, list{a2, ...l2}) => + let cell = mutableCell(f(a1, a2), list{}) + copyAuxWithMap2(f, l1, l2, cell) + cell + | (list{}, _) | (_, list{}) => list{} } -let rec mapi = (i, f, param) => - switch param { +let mapWithIndex = (xs, f) => + switch xs { | list{} => list{} - | list{a, ...l} => - let r = f(i, a) - list{r, ...mapi(i + 1, f, l)} + | list{h, ...t} => + let cell = mutableCell(f(h, 0), list{}) + copyAuxWithMapI(f, 1, t, cell) + cell } -let mapi = (f, l) => mapi(0, f, l) +let fromInitializer = (~length as n, f) => + if n <= 0 { + list{} + } else { + let headX = mutableCell(f(0), list{}) + let cur = ref(headX) + let i = ref(1) + while i.contents < n { + let v = mutableCell(f(i.contents), list{}) + unsafeMutateTail(cur.contents, v) + cur.contents = v + i.contents = i.contents + 1 + } -let rev_map = (f, l) => { - let rec rmap_f = (accu, param) => - switch param { - | list{} => accu - | list{a, ...l} => rmap_f(list{f(a), ...accu}, l) + headX + } + +let make = (type a, ~length as n, v: a): list => + if n <= 0 { + list{} + } else { + let headX = mutableCell(v, list{}) + let cur = ref(headX) + let i = ref(1) + while i.contents < n { + let v = mutableCell(v, list{}) + unsafeMutateTail(cur.contents, v) + cur.contents = v + i.contents = i.contents + 1 } - rmap_f(list{}, l) + headX + } + +let rec lengthAux = (x, acc) => + switch x { + | list{} => acc + | list{_, ...t} => lengthAux(t, acc + 1) + } + +let length = xs => lengthAux(xs, 0) +let size = length + +let rec fillAux = (arr, i, x) => + switch x { + | list{} => () + | list{h, ...t} => + Array.setUnsafe(arr, i, h) + fillAux(arr, i + 1, t) + } + +let rec fromArrayAux = (a, i, res) => + if i < 0 { + res + } else { + fromArrayAux(a, i - 1, list{Array.getUnsafe(a, i), ...res}) + } + +let fromArray = a => fromArrayAux(a, Array.length(a) - 1, list{}) + +let toArray = (x: t<_>) => { + let len = length(x) + let arr = A.makeUninitializedUnsafe(len) + fillAux(arr, 0, x) + arr +} + +let toShuffled = xs => { + let v = toArray(xs) + Array.shuffle(v) + fromArray(v) } -let rec iter = (f, param) => - switch param { +/* let rec fillAuxMap arr i x f = + match x with + | [] -> () + | h::t -> + A.setUnsafe arr i (f h [@bs]) ; + fillAuxMap arr (i + 1) t f */ + +/* module J = Js_json */ +/* type json = J.t */ +/* let toJson x f = */ +/* let len = length x in */ +/* let arr = Belt_Array.makeUninitializedUnsafe len in */ +/* fillAuxMap arr 0 x f; */ +/* J.array arr */ + +/* TODO: best practice about raising excpetion + 1. raise OCaml exception, no stacktrace + 2. raise JS exception, how to pattern match +*/ + +let rec reverseConcat = (l1, l2) => + switch l1 { + | list{} => l2 + | list{a, ...l} => reverseConcat(l, list{a, ...l2}) + } + +let reverse = l => reverseConcat(l, list{}) + +let rec flatAux = (prec, xs) => + switch xs { + | list{} => unsafeMutateTail(prec, list{}) + | list{h, ...r} => flatAux(copyAuxCont(h, prec), r) + } + +let rec flat = xs => + switch xs { + | list{} => list{} + | list{list{}, ...xs} => flat(xs) + | list{list{h, ...t}, ...r} => + let cell = mutableCell(h, list{}) + flatAux(copyAuxCont(t, cell), r) + cell + } + +let concatMany = xs => + switch xs { + | [] => list{} + | [x] => x + | _ => + let len = Array.length(xs) + let v = ref(Array.getUnsafe(xs, len - 1)) + for i in len - 2 downto 0 { + v.contents = concat(Array.getUnsafe(xs, i), v.contents) + } + v.contents + } + +let rec mapRevAux = (f, accu, xs) => + switch xs { + | list{} => accu + | list{a, ...l} => mapRevAux(f, list{f(a), ...accu}, l) + } + +let mapReverse = (l, f) => mapRevAux(f, list{}, l) + +let rec forEach = (xs, f) => + switch xs { | list{} => () | list{a, ...l} => f(a) - iter(f, l) + forEach(l, f) } -let rec iteri = (i, f, param) => - switch param { +let rec forEachWithIndexAux = (xs, f, i) => + switch xs { | list{} => () | list{a, ...l} => - f(i, a) - iteri(i + 1, f, l) + f(a, i) + forEachWithIndexAux(l, f, i + 1) } -let iteri = (f, l) => iteri(0, f, l) +let forEachWithIndex = (l, f) => forEachWithIndexAux(l, f, 0) -let rec fold_left = (f, accu, l) => +let rec reduce = (l, accu, f) => switch l { | list{} => accu - | list{a, ...l} => fold_left(f, f(accu, a), l) + | list{a, ...l} => reduce(l, f(accu, a), f) } -let rec fold_right = (f, l, accu) => +let rec reduceReverseUnsafe = (l, accu, f) => switch l { | list{} => accu - | list{a, ...l} => f(a, fold_right(f, l, accu)) + | list{a, ...l} => f(reduceReverseUnsafe(l, accu, f), a) } -let rec map2 = (f, l1, l2) => - switch (l1, l2) { - | (list{}, list{}) => list{} - | (list{a1, ...l1}, list{a2, ...l2}) => - let r = f(a1, a2) - list{r, ...map2(f, l1, l2)} - | (_, _) => invalid_arg("List.map2") +let reduceReverse = (type a b, l: list, acc: b, f) => { + let len = length(l) + if len < 1000 { + reduceReverseUnsafe(l, acc, f) + } else { + A.reduceReverseU(toArray(l), acc, f) + } +} + +let rec reduceWithIndexAux = (l, acc, f, i) => + switch l { + | list{} => acc + | list{x, ...xs} => reduceWithIndexAux(xs, f(acc, x, i), f, i + 1) } -let rev_map2 = (f, l1, l2) => { - let rec rmap2_f = (accu, l1, l2) => - switch (l1, l2) { - | (list{}, list{}) => accu - | (list{a1, ...l1}, list{a2, ...l2}) => rmap2_f(list{f(a1, a2), ...accu}, l1, l2) - | (_, _) => invalid_arg("List.rev_map2") - } +let reduceWithIndex = (l, acc, f) => reduceWithIndexAux(l, acc, f, 0) - rmap2_f(list{}, l1, l2) -} +let rec mapRevAux2 = (l1, l2, accu, f) => + switch (l1, l2) { + | (list{a1, ...l1}, list{a2, ...l2}) => mapRevAux2(l1, l2, list{f(a1, a2), ...accu}, f) + | (_, list{}) | (list{}, _) => accu + } -let rec iter2 = (f, l1, l2) => +let mapReverse2 = (l1, l2, f) => mapRevAux2(l1, l2, list{}, f) + +let rec forEach2 = (l1, l2, f) => switch (l1, l2) { - | (list{}, list{}) => () | (list{a1, ...l1}, list{a2, ...l2}) => - f(a1, a2) - iter2(f, l1, l2) - | (_, _) => invalid_arg("List.iter2") + f(a1, a2)->ignore + forEach2(l1, l2, f) + | (list{}, _) | (_, list{}) => () } -let rec fold_left2 = (f, accu, l1, l2) => +let rec reduce2 = (l1, l2, accu, f) => switch (l1, l2) { - | (list{}, list{}) => accu - | (list{a1, ...l1}, list{a2, ...l2}) => fold_left2(f, f(accu, a1, a2), l1, l2) - | (_, _) => invalid_arg("List.fold_left2") + | (list{a1, ...l1}, list{a2, ...l2}) => reduce2(l1, l2, f(accu, a1, a2), f) + | (list{}, _) | (_, list{}) => accu } -let rec fold_right2 = (f, l1, l2, accu) => +let rec reduceReverse2Unsafe = (l1, l2, accu, f) => switch (l1, l2) { | (list{}, list{}) => accu - | (list{a1, ...l1}, list{a2, ...l2}) => f(a1, a2, fold_right2(f, l1, l2, accu)) - | (_, _) => invalid_arg("List.fold_right2") + | (list{a1, ...l1}, list{a2, ...l2}) => f(reduceReverse2Unsafe(l1, l2, accu, f), a1, a2) + | (_, list{}) | (list{}, _) => accu } -let rec for_all = (p, param) => - switch param { +let reduceReverse2 = (type a b c, l1: list, l2: list, acc: c, f) => { + let len = length(l1) + if len < 1000 { + reduceReverse2Unsafe(l1, l2, acc, f) + } else { + A.reduceReverse2U(toArray(l1), toArray(l2), acc, f) + } +} + +let rec every = (xs, p) => + switch xs { | list{} => true - | list{a, ...l} => p(a) && for_all(p, l) + | list{a, ...l} => p(a) && every(l, p) } -let rec exists = (p, param) => - switch param { +let rec some = (xs, p) => + switch xs { | list{} => false - | list{a, ...l} => p(a) || exists(p, l) + | list{a, ...l} => p(a) || some(l, p) } -let rec for_all2 = (p, l1, l2) => +let rec every2 = (l1, l2, p) => switch (l1, l2) { - | (list{}, list{}) => true - | (list{a1, ...l1}, list{a2, ...l2}) => p(a1, a2) && for_all2(p, l1, l2) - | (_, _) => invalid_arg("List.for_all2") + | (_, list{}) | (list{}, _) => true + | (list{a1, ...l1}, list{a2, ...l2}) => p(a1, a2) && every2(l1, l2, p) } -let rec exists2 = (p, l1, l2) => +let rec compareLength = (l1, l2) => switch (l1, l2) { - | (list{}, list{}) => false - | (list{a1, ...l1}, list{a2, ...l2}) => p(a1, a2) || exists2(p, l1, l2) - | (_, _) => invalid_arg("List.exists2") - } - -let rec mem = (x, param) => - switch param { - | list{} => false - | list{a, ...l} => compare(a, x) == 0 || mem(x, l) - } - -let rec memq = (x, param) => - switch param { - | list{} => false - | list{a, ...l} => a === x || memq(x, l) + | (list{}, list{}) => Ordering.equal + | (_, list{}) => Ordering.greater + | (list{}, _) => Ordering.less + | (list{_, ...l1s}, list{_, ...l2s}) => compareLength(l1s, l2s) } -let rec assoc = (x, param) => - switch param { - | list{} => raise(Not_found) - | list{(a, b), ...l} => - if compare(a, x) == 0 { - b +let rec compare = (l1, l2, p) => + switch (l1, l2) { + | (list{}, list{}) => Ordering.equal + | (_, list{}) => Ordering.greater + | (list{}, _) => Ordering.less + | (list{a1, ...l1}, list{a2, ...l2}) => + let c = p(a1, a2) + if c == Ordering.equal { + compare(l1, l2, p) } else { - assoc(x, l) + c } } -let rec assoc_opt = (x, param) => - switch param { - | list{} => None - | list{(a, b), ...l} => - if compare(a, x) == 0 { - Some(b) +let rec equal = (l1, l2, p) => + switch (l1, l2) { + | (list{}, list{}) => true + | (_, list{}) + | (list{}, _) => false + | (list{a1, ...l1}, list{a2, ...l2}) => + if p(a1, a2) { + equal(l1, l2, p) } else { - assoc_opt(x, l) + false } } -let rec assq = (x, param) => - switch param { - | list{} => raise(Not_found) - | list{(a, b), ...l} => - if a === x { - b - } else { - assq(x, l) - } +let rec some2 = (l1, l2, p) => + switch (l1, l2) { + | (list{}, _) | (_, list{}) => false + | (list{a1, ...l1}, list{a2, ...l2}) => p(a1, a2) || some2(l1, l2, p) + } + +let rec has = (xs, x, eq) => + switch xs { + | list{} => false + | list{a, ...l} => eq(a, x) || has(l, x, eq) } -let rec assq_opt = (x, param) => - switch param { +let rec getAssoc = (xs, x, eq) => + switch xs { | list{} => None | list{(a, b), ...l} => - if a === x { + if eq(a, x) { Some(b) } else { - assq_opt(x, l) + getAssoc(l, x, eq) } } -let rec mem_assoc = (x, param) => - switch param { - | list{} => false - | list{(a, _), ...l} => compare(a, x) == 0 || mem_assoc(x, l) - } - -let rec mem_assq = (x, param) => - switch param { +let rec hasAssoc = (xs, x, eq) => + switch xs { | list{} => false - | list{(a, _), ...l} => a === x || mem_assq(x, l) + | list{(a, _), ...l} => eq(a, x) || hasAssoc(l, x, eq) } -let rec remove_assoc = (x, param) => - switch param { +let removeAssoc = (xs, x, eq) => + switch xs { | list{} => list{} | list{(a, _) as pair, ...l} => - if compare(a, x) == 0 { + if eq(a, x) { l } else { - list{pair, ...remove_assoc(x, l)} + let cell = mutableCell(pair, list{}) + let removed = removeAssocAuxWithMap(l, x, cell, eq) + if removed { + cell + } else { + xs + } } } -let rec remove_assq = (x, param) => - switch param { - | list{} => list{} +let setAssoc = (xs, x, k, eq) => + switch xs { + | list{} => list{(x, k)} | list{(a, _) as pair, ...l} => - if a === x { - l + if eq(a, x) { + list{(x, k), ...l} } else { - list{pair, ...remove_assq(x, l)} + let cell = mutableCell(pair, list{}) + let replaced = setAssocAuxWithMap(l, x, k, cell, eq) + if replaced { + cell + } else { + list{(x, k), ...xs} + } } } -let rec find = (p, param) => - switch param { - | list{} => raise(Not_found) - | list{x, ...l} => - if p(x) { - x - } else { - find(p, l) - } - } +let sort = (xs, cmp) => { + let arr = toArray(xs) + Array.sort(arr, cmp) + fromArray(arr) +} -let rec find_opt = (p, param) => - switch param { +let rec find = (xs, p) => + switch xs { | list{} => None | list{x, ...l} => if p(x) { Some(x) } else { - find_opt(p, l) + find(l, p) } } -let find_all = (p, l) => { - let rec find = (accu, param) => - switch param { - | list{} => rev(accu) - | list{x, ...l} => - if p(x) { - find(list{x, ...accu}, l) - } else { - find(accu, l) - } - } - find(list{}, l) -} - -let filter = find_all - -let partition = (p, l) => { - let rec part = (yes, no, param) => - switch param { - | list{} => (rev(yes), rev(no)) - | list{x, ...l} => - if p(x) { - part(list{x, ...yes}, no, l) - } else { - part(yes, list{x, ...no}, l) - } - } - part(list{}, list{}, l) -} - -let rec split = param => - switch param { - | list{} => (list{}, list{}) - | list{(x, y), ...l} => - let (rx, ry) = split(l) - (list{x, ...rx}, list{y, ...ry}) - } - -let rec combine = (l1, l2) => - switch (l1, l2) { - | (list{}, list{}) => list{} - | (list{a1, ...l1}, list{a2, ...l2}) => list{(a1, a2), ...combine(l1, l2)} - | (_, _) => invalid_arg("List.combine") - } - -/* sorting */ - -let rec merge = (cmp, l1, l2) => - switch (l1, l2) { - | (list{}, l2) => l2 - | (l1, list{}) => l1 - | (list{h1, ...t1}, list{h2, ...t2}) => - if cmp(h1, h2) <= 0 { - list{h1, ...merge(cmp, t1, l2)} +let rec filter = (xs, p) => + switch xs { + | list{} => list{} + | list{h, ...t} => + if p(h) { + let cell = mutableCell(h, list{}) + copyAuxWitFilter(p, t, cell) + cell } else { - list{h2, ...merge(cmp, l1, t2)} - } - } - -let rec chop = (k, l) => - if k == 0 { - l - } else { - switch l { - | list{_, ...t} => chop(k - 1, t) - | _ => assert(false) + filter(t, p) } } -let stable_sort = (cmp, l) => { - let rec rev_merge = (l1, l2, accu) => - switch (l1, l2) { - | (list{}, l2) => rev_append(l2, accu) - | (l1, list{}) => rev_append(l1, accu) - | (list{h1, ...t1}, list{h2, ...t2}) => - if cmp(h1, h2) <= 0 { - rev_merge(t1, l2, list{h1, ...accu}) - } else { - rev_merge(l1, t2, list{h2, ...accu}) - } - } - - let rec rev_merge_rev = (l1, l2, accu) => - switch (l1, l2) { - | (list{}, l2) => rev_append(l2, accu) - | (l1, list{}) => rev_append(l1, accu) - | (list{h1, ...t1}, list{h2, ...t2}) => - if cmp(h1, h2) > 0 { - rev_merge_rev(t1, l2, list{h1, ...accu}) - } else { - rev_merge_rev(l1, t2, list{h2, ...accu}) - } - } - - let rec sort = (n, l) => - switch (n, l) { - | (2, list{x1, x2, ..._}) => - if cmp(x1, x2) <= 0 { - list{x1, x2} - } else { - list{x2, x1} - } - | (3, list{x1, x2, x3, ..._}) => - if cmp(x1, x2) <= 0 { - if cmp(x2, x3) <= 0 { - list{x1, x2, x3} - } else if cmp(x1, x3) <= 0 { - list{x1, x3, x2} - } else { - list{x3, x1, x2} - } - } else if cmp(x1, x3) <= 0 { - list{x2, x1, x3} - } else if cmp(x2, x3) <= 0 { - list{x2, x3, x1} +let filterWithIndex = (xs, p) => { + let rec auxFilterWithIndex = (xs, p, i) => + switch xs { + | list{} => list{} + | list{h, ...t} => + if p(h, i) { + let cell = mutableCell(h, list{}) + copyAuxWithFilterIndex(p, t, cell, i + 1) + cell } else { - list{x3, x2, x1} + auxFilterWithIndex(t, p, i + 1) } - | (n, l) => - let n1 = asr(n, 1) - let n2 = n - n1 - let l2 = chop(n1, l) - let s1 = rev_sort(n1, l) - let s2 = rev_sort(n2, l2) - rev_merge_rev(s1, s2, list{}) } - and rev_sort = (n, l) => - switch (n, l) { - | (2, list{x1, x2, ..._}) => - if cmp(x1, x2) > 0 { - list{x1, x2} - } else { - list{x2, x1} - } - | (3, list{x1, x2, x3, ..._}) => - if cmp(x1, x2) > 0 { - if cmp(x2, x3) > 0 { - list{x1, x2, x3} - } else if cmp(x1, x3) > 0 { - list{x1, x3, x2} - } else { - list{x3, x1, x2} - } - } else if cmp(x1, x3) > 0 { - list{x2, x1, x3} - } else if cmp(x2, x3) > 0 { - list{x2, x3, x1} - } else { - list{x3, x2, x1} - } - | (n, l) => - let n1 = asr(n, 1) - let n2 = n - n1 - let l2 = chop(n1, l) - let s1 = sort(n1, l) - let s2 = sort(n2, l2) - rev_merge(s1, s2, list{}) - } - - let len = length(l) - if len < 2 { - l - } else { - sort(len, l) - } + auxFilterWithIndex(xs, p, 0) } -let sort = stable_sort -let fast_sort = stable_sort - -/* Note: on a list of length between about 100000 (depending on the minor - heap size and the type of the list) and Sys.max_array_size, it is - actually faster to use the following, but it might also use more memory - because the argument list cannot be deallocated incrementally. - - Also, there seems to be a bug in this code or in the - implementation of obj_truncate. - -external obj_truncate : 'a array -> int -> unit = "caml_obj_truncate" - -let array_to_list_in_place a = - let l = Array.length a in - let rec loop accu n p = - if p <= 0 then accu else begin - if p = n then begin - obj_truncate a p; - loop (a.(p-1) :: accu) (n-1000) (p-1) - end else begin - loop (a.(p-1) :: accu) n (p-1) - end - end - in - loop [] (l-1000) l - - -let stable_sort cmp l = - let a = Array.of_list l in - Array.stable_sort cmp a; - array_to_list_in_place a - -*/ - -/* sorting + removing duplicates */ - -let sort_uniq = (cmp, l) => { - let rec rev_merge = (l1, l2, accu) => - switch (l1, l2) { - | (list{}, l2) => rev_append(l2, accu) - | (l1, list{}) => rev_append(l1, accu) - | (list{h1, ...t1}, list{h2, ...t2}) => - let c = cmp(h1, h2) - if c == 0 { - rev_merge(t1, t2, list{h1, ...accu}) - } else if c < 0 { - rev_merge(t1, l2, list{h1, ...accu}) - } else { - rev_merge(l1, t2, list{h2, ...accu}) - } - } - - let rec rev_merge_rev = (l1, l2, accu) => - switch (l1, l2) { - | (list{}, l2) => rev_append(l2, accu) - | (l1, list{}) => rev_append(l1, accu) - | (list{h1, ...t1}, list{h2, ...t2}) => - let c = cmp(h1, h2) - if c == 0 { - rev_merge_rev(t1, t2, list{h1, ...accu}) - } else if c > 0 { - rev_merge_rev(t1, l2, list{h1, ...accu}) - } else { - rev_merge_rev(l1, t2, list{h2, ...accu}) - } +let rec filterMap = (xs, p) => + switch xs { + | list{} => list{} + | list{h, ...t} => + switch p(h) { + | Some(h) => + let cell = mutableCell(h, list{}) + copyAuxWitFilterMap(p, t, cell) + cell + | None => filterMap(t, p) } + } - let rec sort = (n, l) => - switch (n, l) { - | (2, list{x1, x2, ..._}) => - let c = cmp(x1, x2) - if c == 0 { - list{x1} - } else if c < 0 { - list{x1, x2} - } else { - list{x2, x1} - } - | (3, list{x1, x2, x3, ..._}) => - let c = cmp(x1, x2) - if c == 0 { - let c = cmp(x2, x3) - if c == 0 { - list{x2} - } else if c < 0 { - list{x2, x3} - } else { - list{x3, x2} - } - } else if c < 0 { - let c = cmp(x2, x3) - if c == 0 { - list{x1, x2} - } else if c < 0 { - list{x1, x2, x3} - } else { - let c = cmp(x1, x3) - if c == 0 { - list{x1, x2} - } else if c < 0 { - list{x1, x3, x2} - } else { - list{x3, x1, x2} - } - } - } else { - let c = cmp(x1, x3) - if c == 0 { - list{x2, x1} - } else if c < 0 { - list{x2, x1, x3} - } else { - let c = cmp(x2, x3) - if c == 0 { - list{x2, x1} - } else if c < 0 { - list{x2, x3, x1} - } else { - list{x3, x2, x1} - } - } - } - | (n, l) => - let n1 = asr(n, 1) - let n2 = n - n1 - let l2 = chop(n1, l) - let s1 = rev_sort(n1, l) - let s2 = rev_sort(n2, l2) - rev_merge_rev(s1, s2, list{}) - } - and rev_sort = (n, l) => - switch (n, l) { - | (2, list{x1, x2, ..._}) => - let c = cmp(x1, x2) - if c == 0 { - list{x1} - } else if c > 0 { - list{x1, x2} - } else { - list{x2, x1} - } - | (3, list{x1, x2, x3, ..._}) => - let c = cmp(x1, x2) - if c == 0 { - let c = cmp(x2, x3) - if c == 0 { - list{x2} - } else if c > 0 { - list{x2, x3} - } else { - list{x3, x2} - } - } else if c > 0 { - let c = cmp(x2, x3) - if c == 0 { - list{x1, x2} - } else if c > 0 { - list{x1, x2, x3} - } else { - let c = cmp(x1, x3) - if c == 0 { - list{x1, x2} - } else if c > 0 { - list{x1, x3, x2} - } else { - list{x3, x1, x2} - } - } - } else { - let c = cmp(x1, x3) - if c == 0 { - list{x2, x1} - } else if c > 0 { - list{x2, x1, x3} - } else { - let c = cmp(x2, x3) - if c == 0 { - list{x2, x1} - } else if c > 0 { - list{x2, x3, x1} - } else { - list{x3, x2, x1} - } - } - } - | (n, l) => - let n1 = asr(n, 1) - let n2 = n - n1 - let l2 = chop(n1, l) - let s1 = sort(n1, l) - let s2 = sort(n2, l2) - rev_merge(s1, s2, list{}) +let partition = (l, p) => + switch l { + | list{} => (list{}, list{}) + | list{h, ...t} => + let nextX = mutableCell(h, list{}) + let nextY = mutableCell(h, list{}) + let b = p(h) + partitionAux(p, t, nextX, nextY) + if b { + ( + nextX, + switch nextY { + | list{_, ...tail} => tail + | list{} => assert(false) + }, + ) + } else { + ( + switch nextX { + | list{_, ...tail} => tail + | list{} => assert(false) + }, + nextY, + ) } - - let len = length(l) - if len < 2 { - l - } else { - sort(len, l) } -} -let rec compare_lengths = (l1, l2) => - switch (l1, l2) { - | (list{}, list{}) => 0 - | (list{}, _) => -1 - | (_, list{}) => 1 - | (list{_, ...l1}, list{_, ...l2}) => compare_lengths(l1, l2) +let unzip = xs => + switch xs { + | list{} => (list{}, list{}) + | list{(x, y), ...l} => + let cellX = mutableCell(x, list{}) + let cellY = mutableCell(y, list{}) + splitAux(l, cellX, cellY) + (cellX, cellY) } -let rec compare_length_with = (l, n) => - switch l { - | list{} => - if n == 0 { - 0 - } else if n > 0 { - -1 - } else { - 1 - } - | list{_, ...l} => - if n <= 0 { - 1 - } else { - compare_length_with(l, n - 1) - } +let zip = (l1, l2) => + switch (l1, l2) { + | (_, list{}) | (list{}, _) => list{} + | (list{a1, ...l1}, list{a2, ...l2}) => + let cell = mutableCell((a1, a2), list{}) + zipAux(l1, l2, cell) + cell } diff --git a/runtime/List.resi b/runtime/List.resi index 1fdfd31f0c..095a31d693 100644 --- a/runtime/List.resi +++ b/runtime/List.resi @@ -1,365 +1,876 @@ -// FIXME: -// This exists for compatibility reason. -// Move this into Pervasives or Core +/* Copyright (C) 2017 Authors of ReScript + * + * 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. */ + +/** +Collection functions for manipulating the `list` data structures, a singly-linked list. + +**Prefer Array** if you need any of the following: + +- Random access of element +- Better interop with JavaScript +- Better memory usage & performance. +*/ +/** `'a t` is compatible with built-in `list` type */ +type t<'a> = list<'a> -// Below is all deprecated and should be removed in v13 +/** +`length(list)` returns the length of `list`. -@deprecated("Use Core instead. This will be removed in v13") -type t<'a> = list<'a> +## Examples + +```rescript +List.length(list{1, 2, 3}) // 3 +``` +*/ +let length: t<'a> => int + +/** +`size(list)`. See [`length`](#length) + +## Examples + +```rescript +List.size(list{1, 2, 3}) // 3 +``` +*/ +let size: t<'a> => int + +/** +`head(list)` returns `Some(value)` where `value` is the first element in the +list, or `None` if `list` is an empty list. + +## Examples + +```rescript +List.head(list{}) // None +List.head(list{1, 2, 3}) // Some(1) +``` +*/ +let head: t<'a> => option<'a> + +/** +`headExn(list)` same as [`head`](#head). + +## Examples + +```rescript +List.headExn(list{1, 2, 3}) // 1 + +List.headExn(list{}) // Raises an Error +``` + +## Exceptions + +- Raises an Error if list is empty. + +*/ +let headExn: t<'a> => 'a + +/** +`tail(list)` returns `None` if `list` is empty, otherwise it returns `Some(tail)` +where `tail` is everything except the first element of `list`. + +## Examples + +```rescript +List.tail(list{1, 2, 3}) // Some(list{2, 3}) + +List.tail(list{}) // None +``` +*/ +let tail: t<'a> => option> + +/** +`tailExn(list)` same as [`tail`](#tail). + +## Examples + +```rescript +List.tailExn(list{1, 2, 3}) // list{2, 3} + +List.tailExn(list{}) // Raises an Error +``` + +## Exceptions + +- Raises an Error if list is empty. +*/ +let tailExn: t<'a> => t<'a> + +/** +`add(list, value)` adds a `value` to the beginning of list `list`. + +## Examples + +```rescript +List.add(list{2, 3}, 1) // list{1, 2, 3} + +List.add(list{"World", "!"}, "Hello") // list{"Hello", "World", "!"} +``` +*/ +let add: (t<'a>, 'a) => t<'a> + +/** +`get(list, index)` return the `index` element in `list`, or `None` if `index` +is larger than the length of list `list`. + +## Examples + +```rescript +let abc = list{"A", "B", "C"} + +abc->List.get(1) // Some("B") + +abc->List.get(4) // None +``` +*/ +let get: (t<'a>, int) => option<'a> + +/** +`getExn(list, index)` same as [`get`](#get). + +## Examples + +```rescript +let abc = list{"A", "B", "C"} + +abc->List.getExn(1) // "B" + +abc->List.getExn(4) // Raises an Error +``` + +## Exceptions + +- Raises an Error if `index` is larger than the length of list. +*/ +let getExn: (t<'a>, int) => 'a + +/** +`make(length, value)` returns a list of length `length` with each element filled +with `value`. Returns an empty list if `value` is negative. + +## Examples + +```rescript +List.make(~length=3, 1) // list{1, 1, 1} +``` +*/ +let make: (~length: int, 'a) => t<'a> + +/** +`makeBy(length, f)` return a list of length `length` with element initialized +with `f`. Returns an empty list if `length` is negative. + +## Examples + +```rescript +List.fromInitializer(~length=5, i => i) // list{0, 1, 2, 3, 4} + +List.fromInitializer(~length=5, i => i * i) // list{0, 1, 4, 9, 16} +``` +*/ +let fromInitializer: (~length: int, int => 'a) => t<'a> + +/** +`toShuffled(list)` returns a new list in random order. + +## Examples + +```rescript +List.toShuffled(list{1, 2, 3}) // list{2, 1, 3} +``` +*/ +let toShuffled: t<'a> => t<'a> + +/** +`drop(list, value)` return a new list, dropping the first `value` element. +Returns `None` if `list` has fewer than `value` elements. + +## Examples + +```rescript +list{1, 2, 3}->List.drop(2) // Some(list{3}) + +list{1, 2, 3}->List.drop(3) // Some(list{}) + +list{1, 2, 3}->List.drop(4) // None +``` +*/ +let drop: (t<'a>, int) => option> + +/** +`take(list, value)` returns a list with the first `value` elements from `list`, +or `None` if `list` has fewer than `value` elements. + +## Examples + +```rescript +list{1, 2, 3}->List.take(1) // Some(list{1}) + +list{1, 2, 3}->List.take(2) // Some(list{1, 2}) + +list{1, 2, 3}->List.take(4) // None +``` +*/ +let take: (t<'a>, int) => option> + +/** +`splitAt(list, n)` split the list `list` at `n`. Returns `None` when the length +of `list` is less than `n`. + +## Examples + +```rescript +list{"Hello", "World"}->List.splitAt(1) // Some((list{"Hello"}, list{"World"})) + +list{0, 1, 2, 3, 4}->List.splitAt(2) // Some((list{0, 1}, list{2, 3, 4})) +``` +*/ +let splitAt: (t<'a>, int) => option<(list<'a>, list<'a>)> + +/** +`concat(list1, list2)` returns the list obtained by adding `list1` after `list2`. + +## Examples + +```rescript +List.concat(list{1, 2, 3}, list{4, 5}) // list{1, 2, 3, 4, 5} +``` +*/ +let concat: (t<'a>, t<'a>) => t<'a> + +/** +`concatMany(arr)` returns the list obtained by concatenating all the lists in +array `arr`, in order. + +## Examples + +```rescript +List.concatMany([list{1, 2, 3}, list{}, list{3}]) // list{1, 2, 3, 3} +``` +*/ +let concatMany: array> => t<'a> + +/** +`reverseConcat(list1, list2)` is equivalent to writing: `concat(reverse(list1, list2)` + +## Examples + +```rescript +List.reverseConcat(list{1, 2}, list{3, 4}) // list{2, 1, 3, 4} +``` +*/ +let reverseConcat: (t<'a>, t<'a>) => t<'a> + +/** +`flat(list)` return the list obtained by concatenating all the lists in +`list`, in order. + +## Examples + +```rescript +List.flat(list{list{1, 2, 3}, list{}, list{3}}) // list{1, 2, 3, 3} +``` +*/ +let flat: t> => t<'a> + +/** +`map(list, f)` returns a new list with `f` applied to each element of `list`. + +## Examples + +```rescript +list{1, 2}->List.map(x => x + 1) // list{3, 4} +``` +*/ +let map: (t<'a>, 'a => 'b) => t<'b> + +/** +`zip(list1, list2)` returns a list of pairs from the two lists with the length +of the shorter list. + +## Examples + +```rescript +List.zip(list{1, 2}, list{3, 4, 5}) // list{(1, 3), (2, 4)} +``` +*/ +let zip: (t<'a>, t<'b>) => t<('a, 'b)> + +/** +`zipBy(list1, list2, f)`. See [`zip`](#zip) + +## Examples + +```rescript +List.zipBy(list{1, 2, 3}, list{4, 5}, (a, b) => 2 * a + b) // list{6, 9} +``` +*/ +let zipBy: (t<'a>, t<'b>, ('a, 'b) => 'c) => t<'c> + +/** +`mapWithIndex(list, f)` applies `f` to each element of `list`. Function `f` +takes two arguments: the index starting from 0 and the element from `list`, in +that order. + +## Examples + +```rescript +list{1, 2, 3}->List.mapWithIndex((x, index) => index + x) // list{1, 3, 5} +``` +*/ +let mapWithIndex: (t<'a>, ('a, int) => 'b) => t<'b> + +/** +`fromArray(arr)` converts the given array `arr` to a list. + +## Examples + +```rescript +List.fromArray([1, 2, 3]) // list{1, 2, 3} +``` +*/ +let fromArray: array<'a> => t<'a> + +/** +`toArray(list)` converts the given list `list` to an array. + +## Examples + +```rescript +List.toArray(list{1, 2, 3}) // [1, 2, 3] +``` +*/ +let toArray: t<'a> => array<'a> + +/* type json = Js_json.t */ + +/* val toJson : 'a t -> ('a -> json [@bs]) -> json */ +/* val fromJson : json -> (json -> 'a [@bs]) -> 'a t */ + +/** +`reverse(list)` returns a new list whose elements are those of `list` in +reversed order. + +## Examples + +```rescript +List.reverse(list{1, 2, 3}) // list{3, 2, 1} +``` +*/ +let reverse: t<'a> => t<'a> + +/** +`mapReverse(list, f)` is equivalent to `map` function. + +## Examples + +```rescript +let f = x => x * x +let l = list{3, 4, 5} + +let withMap = List.map(l, f)->List.reverse +let withMapReverse = l->List.mapReverse(f) + +Console.log(withMap == withMapReverse) // true +``` +*/ +let mapReverse: (t<'a>, 'a => 'b) => t<'b> + +/** +`forEach(list, f)` call `f` on each element of `list` from the beginning to end. +`f` returns `unit`, so no new array is created. Use `forEach` when you are primarily +concerned with repetitively creating side effects. + +## Examples + +```rescript +List.forEach(list{"a", "b", "c"}, x => Console.log("Item: " ++ x)) +/* + prints: + Item: a + Item: b + Item: c +*/ +``` +*/ +let forEach: (t<'a>, 'a => unit) => unit + +/** +`forEachWithIndex(list, f, index)` call `f` on each element of `list` from beginning +to end. Function `f` takes two arguments: the `index` starting from 0 and the +element from `list`. `f` returns `unit`. + +## Examples + +```rescript +List.forEachWithIndex(list{"a", "b", "c"}, (x, index) => { + Console.log("Item " ++ Int.toString(index) ++ " is " ++ x) +}) +/* + prints: + Item 0 is a + Item 1 is b + Item 2 is cc +*/ +``` +*/ +let forEachWithIndex: (t<'a>, ('a, int) => unit) => unit + +/** +`reduce(list, initialValue, f)` applies `f` to each element of `list` from +beginning to end. Function `f` has two parameters: the item from the list and +an "accumulator", which starts with a value of `initialValue`. `reduce` returns +the final value of the accumulator. + +## Examples -/** Return the length (number of elements) of the given list. */ -@deprecated("Use Core instead. This will be removed in v13") -let length: list<'a> => int - -/** Compare the lengths of two lists. [compare_lengths l1 l2] is - equivalent to [compare (length l1) (length l2)], except that - the computation stops after itering on the shortest list. - @since 4.05.0 - */ -@deprecated("Use Core instead. This will be removed in v13") -let compare_lengths: (list<'a>, list<'b>) => int - -/** Compare the length of a list to an integer. [compare_length_with l n] is - equivalent to [compare (length l) n], except that - the computation stops after at most [n] iterations on the list. - @since 4.05.0 -*/ -@deprecated("Use Core instead. This will be removed in v13") -let compare_length_with: (list<'a>, int) => int - -/** [cons x xs] is [x :: xs] - @since 4.03.0 -*/ -@deprecated("Use Core instead. This will be removed in v13") -let cons: ('a, list<'a>) => list<'a> - -/** Return the first element of the given list. Raise - [Failure "hd"] if the list is empty. */ -@deprecated("Use Core instead. This will be removed in v13") -let hd: list<'a> => 'a - -/** Return the given list without its first element. Raise - [Failure "tl"] if the list is empty. */ -@deprecated("Use Core instead. This will be removed in v13") -let tl: list<'a> => list<'a> - -/** Return the [n]-th element of the given list. - The first element (head of the list) is at position 0. - Raise [Failure "nth"] if the list is too short. - Raise [Invalid_argument "List.nth"] if [n] is negative. */ -@deprecated("Use Core instead. This will be removed in v13") -let nth: (list<'a>, int) => 'a - -/** Return the [n]-th element of the given list. - The first element (head of the list) is at position 0. - Return [None] if the list is too short. - Raise [Invalid_argument "List.nth"] if [n] is negative. - @since 4.05 -*/ -@deprecated("Use Core instead. This will be removed in v13") -let nth_opt: (list<'a>, int) => option<'a> - -/** List reversal. */ -@deprecated("Use Core instead. This will be removed in v13") -let rev: list<'a> => list<'a> - -/** [List.init len f] is [f 0; f 1; ...; f (len-1)], evaluated left to right. - - @raise Invalid_argument if len < 0. - @since 4.06.0 -*/ -@deprecated("Use Core instead. This will be removed in v13") -let init: (int, int => 'a) => list<'a> - -/** Concatenate two lists. Same as the infix operator [@]. - Not tail-recursive (length of the first argument). */ -@deprecated("Use Core instead. This will be removed in v13") -let append: (list<'a>, list<'a>) => list<'a> - -/** [List.rev_append l1 l2] reverses [l1] and concatenates it to [l2]. - This is equivalent to {!List.rev}[ l1 @ l2], but [rev_append] is - tail-recursive and more efficient. */ -@deprecated("Use Core instead. This will be removed in v13") -let rev_append: (list<'a>, list<'a>) => list<'a> - -/** Concatenate a list of lists. The elements of the argument are all - concatenated together (in the same order) to give the result. - Not tail-recursive - (length of the argument + length of the longest sub-list). */ -@deprecated("Use Core instead. This will be removed in v13") -let concat: list> => list<'a> - -/** An alias for [concat]. */ -@deprecated("Use Core instead. This will be removed in v13") -let flatten: list> => list<'a> - -/* {1 Iterators} */ - -/** [List.iter f [a1; ...; an]] applies function [f] in turn to - [a1; ...; an]. It is equivalent to - [begin f a1; f a2; ...; f an; () end]. */ -@deprecated("Use Core instead. This will be removed in v13") -let iter: ('a => unit, list<'a>) => unit - -/** Same as {!List.iter}, but the function is applied to the index of - the element as first argument (counting from 0), and the element - itself as second argument. - @since 4.00.0 -*/ -@deprecated("Use Core instead. This will be removed in v13") -let iteri: ((int, 'a) => unit, list<'a>) => unit - -/** [List.map f [a1; ...; an]] applies function [f] to [a1, ..., an], - and builds the list [[f a1; ...; f an]] - with the results returned by [f]. Not tail-recursive. */ -@deprecated("Use Core instead. This will be removed in v13") -let map: ('a => 'b, list<'a>) => list<'b> - -/** Same as {!List.map}, but the function is applied to the index of - the element as first argument (counting from 0), and the element - itself as second argument. Not tail-recursive. - @since 4.00.0 -*/ -@deprecated("Use Core instead. This will be removed in v13") -let mapi: ((int, 'a) => 'b, list<'a>) => list<'b> - -/** [List.rev_map f l] gives the same result as - {!List.rev}[ (]{!List.map}[ f l)], but is tail-recursive and - more efficient. */ -@deprecated("Use Core instead. This will be removed in v13") -let rev_map: ('a => 'b, list<'a>) => list<'b> - -/** [List.fold_left f a [b1; ...; bn]] is - [f (... (f (f a b1) b2) ...) bn]. */ -@deprecated("Use Core instead. This will be removed in v13") -let fold_left: (('a, 'b) => 'a, 'a, list<'b>) => 'a - -/** [List.fold_right f [a1; ...; an] b] is - [f a1 (f a2 (... (f an b) ...))]. Not tail-recursive. */ -@deprecated("Use Core instead. This will be removed in v13") -let fold_right: (('a, 'b) => 'b, list<'a>, 'b) => 'b - -/* {1 Iterators on two lists} */ - -/** [List.iter2 f [a1; ...; an] [b1; ...; bn]] calls in turn - [f a1 b1; ...; f an bn]. - Raise [Invalid_argument] if the two lists are determined - to have different lengths. */ -@deprecated("Use Core instead. This will be removed in v13") -let iter2: (('a, 'b) => unit, list<'a>, list<'b>) => unit - -/** [List.map2 f [a1; ...; an] [b1; ...; bn]] is - [[f a1 b1; ...; f an bn]]. - Raise [Invalid_argument] if the two lists are determined - to have different lengths. Not tail-recursive. */ -@deprecated("Use Core instead. This will be removed in v13") -let map2: (('a, 'b) => 'c, list<'a>, list<'b>) => list<'c> - -/** [List.rev_map2 f l1 l2] gives the same result as - {!List.rev}[ (]{!List.map2}[ f l1 l2)], but is tail-recursive and - more efficient. */ -@deprecated("Use Core instead. This will be removed in v13") -let rev_map2: (('a, 'b) => 'c, list<'a>, list<'b>) => list<'c> - -/** [List.fold_left2 f a [b1; ...; bn] [c1; ...; cn]] is - [f (... (f (f a b1 c1) b2 c2) ...) bn cn]. - Raise [Invalid_argument] if the two lists are determined - to have different lengths. */ -@deprecated("Use Core instead. This will be removed in v13") -let fold_left2: (('a, 'b, 'c) => 'a, 'a, list<'b>, list<'c>) => 'a - -/** [List.fold_right2 f [a1; ...; an] [b1; ...; bn] c] is - [f a1 b1 (f a2 b2 (... (f an bn c) ...))]. - Raise [Invalid_argument] if the two lists are determined - to have different lengths. Not tail-recursive. */ -@deprecated("Use Core instead. This will be removed in v13") -let fold_right2: (('a, 'b, 'c) => 'c, list<'a>, list<'b>, 'c) => 'c - -/* {1 List scanning} */ - -/** [for_all p [a1; ...; an]] checks if all elements of the list - satisfy the predicate [p]. That is, it returns - [(p a1) && (p a2) && ... && (p an)]. */ -@deprecated("Use Core instead. This will be removed in v13") -let for_all: ('a => bool, list<'a>) => bool - -/** [exists p [a1; ...; an]] checks if at least one element of - the list satisfies the predicate [p]. That is, it returns - [(p a1) || (p a2) || ... || (p an)]. */ -@deprecated("Use Core instead. This will be removed in v13") -let exists: ('a => bool, list<'a>) => bool - -/** Same as {!List.for_all}, but for a two-argument predicate. - Raise [Invalid_argument] if the two lists are determined - to have different lengths. */ -@deprecated("Use Core instead. This will be removed in v13") -let for_all2: (('a, 'b) => bool, list<'a>, list<'b>) => bool - -/** Same as {!List.exists}, but for a two-argument predicate. - Raise [Invalid_argument] if the two lists are determined - to have different lengths. */ -@deprecated("Use Core instead. This will be removed in v13") -let exists2: (('a, 'b) => bool, list<'a>, list<'b>) => bool - -/** [mem a l] is true if and only if [a] is equal - to an element of [l]. */ -@deprecated("Use Core instead. This will be removed in v13") -let mem: ('a, list<'a>) => bool - -/** Same as {!List.mem}, but uses physical equality instead of structural - equality to compare list elements. */ -@deprecated("Use Core instead. This will be removed in v13") -let memq: ('a, list<'a>) => bool - -/* {1 List searching} */ - -/** [find p l] returns the first element of the list [l] - that satisfies the predicate [p]. - Raise [Not_found] if there is no value that satisfies [p] in the - list [l]. */ -@deprecated("Use Core instead. This will be removed in v13") -let find: ('a => bool, list<'a>) => 'a - -/** [find_opt p l] returns the first element of the list [l] that - satisfies the predicate [p], or [None] if there is no value that - satisfies [p] in the list [l]. - @since 4.05 */ -@deprecated("Use Core instead. This will be removed in v13") -let find_opt: ('a => bool, list<'a>) => option<'a> - -/** [filter p l] returns all the elements of the list [l] - that satisfy the predicate [p]. The order of the elements - in the input list is preserved. */ -@deprecated("Use Core instead. This will be removed in v13") -let filter: ('a => bool, list<'a>) => list<'a> - -/** [find_all] is another name for {!List.filter}. */ -let find_all: ('a => bool, list<'a>) => list<'a> - -/** [partition p l] returns a pair of lists [(l1, l2)], where - [l1] is the list of all the elements of [l] that - satisfy the predicate [p], and [l2] is the list of all the - elements of [l] that do not satisfy [p]. - The order of the elements in the input list is preserved. */ -@deprecated("Use Core instead. This will be removed in v13") -let partition: ('a => bool, list<'a>) => (list<'a>, list<'a>) - -/* {1 Association lists} */ - -/** [assoc a l] returns the value associated with key [a] in the list of - pairs [l]. That is, - [assoc a [ ...; (a,b); ...] = b] - if [(a,b)] is the leftmost binding of [a] in list [l]. - Raise [Not_found] if there is no value associated with [a] in the - list [l]. */ -@deprecated("Use Core instead. This will be removed in v13") -let assoc: ('a, list<('a, 'b)>) => 'b - -/** [assoc_opt a l] returns the value associated with key [a] in the list of - pairs [l]. That is, - [assoc_opt a [ ...; (a,b); ...] = b] - if [(a,b)] is the leftmost binding of [a] in list [l]. - Returns [None] if there is no value associated with [a] in the - list [l]. - @since 4.05 */ -@deprecated("Use Core instead. This will be removed in v13") -let assoc_opt: ('a, list<('a, 'b)>) => option<'b> - -/** Same as {!List.assoc}, but uses physical equality instead of structural - equality to compare keys. */ -@deprecated("Use Core instead. This will be removed in v13") -let assq: ('a, list<('a, 'b)>) => 'b - -/** Same as {!List.assoc_opt}, but uses physical equality instead of structural - equality to compare keys. - @since 4.05 */ -@deprecated("Use Core instead. This will be removed in v13") -let assq_opt: ('a, list<('a, 'b)>) => option<'b> - -/** Same as {!List.assoc}, but simply return true if a binding exists, - and false if no bindings exist for the given key. */ -@deprecated("Use Core instead. This will be removed in v13") -let mem_assoc: ('a, list<('a, 'b)>) => bool - -/** Same as {!List.mem_assoc}, but uses physical equality instead of - structural equality to compare keys. */ -@deprecated("Use Core instead. This will be removed in v13") -let mem_assq: ('a, list<('a, 'b)>) => bool - -/** [remove_assoc a l] returns the list of - pairs [l] without the first pair with key [a], if any. - Not tail-recursive. */ -@deprecated("Use Core instead. This will be removed in v13") -let remove_assoc: ('a, list<('a, 'b)>) => list<('a, 'b)> - -/** Same as {!List.remove_assoc}, but uses physical equality instead - of structural equality to compare keys. Not tail-recursive. */ -@deprecated("Use Core instead. This will be removed in v13") -let remove_assq: ('a, list<('a, 'b)>) => list<('a, 'b)> - -/* {1 Lists of pairs} */ - -/** Transform a list of pairs into a pair of lists: - [split [(a1,b1); ...; (an,bn)]] is [([a1; ...; an], [b1; ...; bn])]. - Not tail-recursive. -*/ -@deprecated("Use Core instead. This will be removed in v13") -let split: list<('a, 'b)> => (list<'a>, list<'b>) - -/** Transform a pair of lists into a list of pairs: - [combine [a1; ...; an] [b1; ...; bn]] is - [[(a1,b1); ...; (an,bn)]]. - Raise [Invalid_argument] if the two lists - have different lengths. Not tail-recursive. */ -@deprecated("Use Core instead. This will be removed in v13") -let combine: (list<'a>, list<'b>) => list<('a, 'b)> - -/* {1 Sorting} */ - -/** Sort a list in increasing order according to a comparison - function. The comparison function must return 0 if its arguments - compare as equal, a positive integer if the first is greater, - and a negative integer if the first is smaller (see Array.sort for - a complete specification). For example, - {!Pervasives.compare} is a suitable comparison function. - The resulting list is sorted in increasing order. - [List.sort] is guaranteed to run in constant heap space - (in addition to the size of the result list) and logarithmic - stack space. - - The current implementation uses Merge Sort. It runs in constant - heap space and logarithmic stack space. -*/ -@deprecated("Use Core instead. This will be removed in v13") -let sort: (('a, 'a) => int, list<'a>) => list<'a> - -/** Same as {!List.sort}, but the sorting algorithm is guaranteed to - be stable (i.e. elements that compare equal are kept in their - original order) . - - The current implementation uses Merge Sort. It runs in constant - heap space and logarithmic stack space. -*/ -@deprecated("Use Core instead. This will be removed in v13") -let stable_sort: (('a, 'a) => int, list<'a>) => list<'a> - -/** Same as {!List.sort} or {!List.stable_sort}, whichever is faster - on typical input. */ -@deprecated("Use Core instead. This will be removed in v13") -let fast_sort: (('a, 'a) => int, list<'a>) => list<'a> - -/** Same as {!List.sort}, but also remove duplicates. - @since 4.02.0 */ -@deprecated("Use Core instead. This will be removed in v13") -let sort_uniq: (('a, 'a) => int, list<'a>) => list<'a> - -/** Merge two lists: - Assuming that [l1] and [l2] are sorted according to the - comparison function [cmp], [merge cmp l1 l2] will return a - sorted list containing all the elements of [l1] and [l2]. - If several elements compare equal, the elements of [l1] will be - before the elements of [l2]. - Not tail-recursive (sum of the lengths of the arguments). -*/ -@deprecated("Use Core instead. This will be removed in v13") -let merge: (('a, 'a) => int, list<'a>, list<'a>) => list<'a> +```rescript +list{1, 2, 3, 4}->List.reduce(0, (a, b) => a + b) // 10 + +// same as + +list{1, 2, 3, 4}->List.reduce(0, (acc, item) => acc + item) // 10 +``` +*/ +let reduce: (t<'a>, 'b, ('b, 'a) => 'b) => 'b + +/** +`reduceWithIndex(list, initialValue, f)` applies `f` to each element of `list` +from beginning to end. Function `f` has three parameters: the item from the list +and an "accumulator", which starts with a value of `initialValue` and the index +of each element. `reduceWithIndex` returns the final value of the accumulator. + +## Examples + +```rescript +list{1, 2, 3, 4}->List.reduceWithIndex(0, (acc, item, index) => acc + item + index) // 16 +``` +*/ +let reduceWithIndex: (t<'a>, 'b, ('b, 'a, int) => 'b) => 'b + +/** +`reduceReverse(list, initialValue, f)` works like `reduce`, except that +function `f` is applied to each item of `list` from the last back to the first. + +## Examples + +```rescript +list{1, 2, 3, 4}->List.reduceReverse(0, (a, b) => a + b) // 10 + +list{1, 2, 3, 4}->List.reduceReverse(10, (a, b) => a - b) // 0 + +list{1, 2, 3, 4}->List.reduceReverse(list{}, List.add) // list{1, 2, 3, 4} +``` +*/ +let reduceReverse: (t<'a>, 'b, ('b, 'a) => 'b) => 'b + +/** +`mapReverse2(list1, list2, f)` is equivalent to `List.zipBy(list1, list2, f)->List.reverse`. + +## Examples + +```rescript +List.mapReverse2(list{1, 2, 3}, list{1, 2}, (a, b) => a + b) // list{4, 2} +``` +*/ +let mapReverse2: (t<'a>, t<'b>, ('a, 'b) => 'c) => t<'c> + +/** +`forEach2(list1, list2, f)` is similar to `forEach`, but accepts two lists and +stops at the length of the shorter list. + +## Examples + +```rescript +List.forEach2(list{"Z", "Y"}, list{"A", "B", "C"}, (x, y) => Console.log2(x, y)) + +/* + prints: + "Z" "A" + "Y" "B" +*/ +``` +*/ +let forEach2: (t<'a>, t<'b>, ('a, 'b) => 'c) => unit + +/** +`reduce2(list1, list2, initialValue, f)` applies `f` to each element of `list1` +and `list2` from beginning to end. Stops with the shorter list. Function `f` has +three parameters: an accumulator which starts with a value of `initialValue`, an +item from `l1`, and an item from `l2`. `reduce2` returns the final value of the +accumulator. + +## Examples + +```rescript +List.reduce2(list{1, 2, 3}, list{4, 5}, 0, (acc, x, y) => acc + x * x + y) // 0 + (1 * 1 + 4) + (2 * 2 + 5) +``` +*/ +let reduce2: (t<'b>, t<'c>, 'a, ('a, 'b, 'c) => 'a) => 'a + +/** +`reduceReverse2(list1, list2, initialValue, f)` applies `f` to each element of +`list1` and `list2`from end to beginning. Stops with the shorter list. Function +`f` has three parameters: an accumulator which starts with a value of +`initialValue`, an item from `l1`, and an item from `l2`. `reduce2` returns the +final value of the accumulator. + +## Examples + +```rescript +List.reduceReverse2(list{1, 2, 3}, list{4, 5}, 0, (acc, x, y) => acc + x * x + y) // + (1 * 1 + 4) + (2 * 2 + 5) +``` +*/ +let reduceReverse2: (t<'a>, t<'b>, 'c, ('c, 'a, 'b) => 'c) => 'c + +/** +`every(list, f)` returns `true` if all elements in `list` satisfy `f`, where `f` +is a predicate: a function taking an element and returning a bool. + +## Examples + +```rescript +let isBelow10 = value => value < 10 + +list{1, 9, 8, 2}->List.every(isBelow10) // true + +list{1, 99, 8, 2}->List.every(isBelow10) // false +``` +*/ +let every: (t<'a>, 'a => bool) => bool + +/** +`some(list, f)` returns `true` if at least _one_ of the elements in `list` +satisfies `f`, where `f` is a predicate: a function taking an element and +returning a bool. + +## Examples + +```rescript +let isAbove100 = value => value > 100 + +list{101, 1, 2, 3}->List.some(isAbove100) // true + +list{1, 2, 3, 4}->List.some(isAbove100) // false +``` +*/ +let some: (t<'a>, 'a => bool) => bool + +/** +`every2(list1, list2, f)` returns `true` if predicate `f` is `true` for all +pairs of elements up to the shorter length (i.e. `min(length(list1), length(list2))`) + +## Examples + +```rescript +List.every2(list{1, 2, 3}, list{0, 1}, (a, b) => a > b) // true + +List.every2(list{}, list{1}, (a, b) => a > b) // true + +List.every2(list{2, 3}, list{1}, (a, b) => a > b) // true + +List.every2(list{0, 1}, list{5, 0}, (a, b) => a > b) // false +``` +*/ +let every2: (t<'a>, t<'b>, ('a, 'b) => bool) => bool + +/** +`some2(list1, list2, f)` returns `true` if predicate `f` is `true` for any pair +of elements up to the shorter length (i.e. `min(length(list1), length(list2))`) + +## Examples + +```rescript +List.some2(list{1, 2, 3}, list{0, 1}, (a, b) => a > b) // true + +List.some2(list{}, list{1}, (a, b) => a > b) // false + +List.some2(list{2, 3}, list{1}, (a, b) => a > b) // true + +List.some2(list{0, 1}, list{5, 0}, (a, b) => a > b) // true +``` +*/ +let some2: (t<'a>, t<'b>, ('a, 'b) => bool) => bool + +/** +`compareLength(list1, list2)` compare two lists solely by length. Returns `-1.` if +`length(list1)` is less than `length(list2)`, `0.` if `length(list1)` equals +`length(list2)`, and `1.` if `length(list1)` is greater than `length(list2)`. + +## Examples + +```rescript +List.compareLength(list{1, 2}, list{3, 4, 5, 6}) // -1. + +List.compareLength(list{1, 2, 3}, list{4, 5, 6}) // 0. + +List.compareLength(list{1, 2, 3, 4}, list{5, 6}) // 1. +``` +*/ +let compareLength: (t<'a>, t<'a>) => Ordering.t + +/** +`compare(list1, list2, f)` compare elements one by one `f`. `f` returns a negative +number if `list1` is "less than" `list2`, zero if `list1` is "equal to" `list2`, +a positive number if `list1` is "greater than" `list2`. + +The comparison returns the first non-zero result of `f`, or zero if `f` returns +zero for all `list1` and `list2`. + +- If all items have compared equal, but `list1` is exhausted first, return `-1.`. (`list1` is shorter). +- If all items have compared equal, but `list2` is exhausted first, return `1.` (`list1` is longer). + +## Examples + +```rescript +List.compare(list{3}, list{3, 7}, (a, b) => Int.compare(a, b)) // -1. +List.compare(list{5, 3}, list{5}, (a, b) => Int.compare(a, b)) // 1. +List.compare(list{1, 3, 5}, list{1, 4, 2}, (a, b) => Int.compare(a, b)) // -1. +List.compare(list{1, 3, 5}, list{1, 2, 3}, (a, b) => Int.compare(a, b)) // 1. +List.compare(list{1, 3, 5}, list{1, 3, 5}, (a, b) => Int.compare(a, b)) // 0. +``` + +**Please note:** The total ordering of List is different from Array, +for Array, we compare the length first and, only if the lengths are equal, elements one by one. +For lists, we just compare elements one by one. +*/ +let compare: (t<'a>, t<'a>, ('a, 'a) => Ordering.t) => Ordering.t + +/** +`equal(list1, list2, f)` check equality of `list2` and `list2` using `f` for +equality on elements, where `f` is a function that returns `true` if items `x` and +`y` meet some criterion for equality, `false` otherwise. equal `false` if length +of `list1` and `list2` are not the same. + +## Examples + +```rescript +List.equal(list{1, 2, 3}, list{1, 2}, (a, b) => a == b) // false + +List.equal(list{1, 2}, list{1, 2}, (a, b) => a == b) // true + +List.equal(list{1, 2, 3}, list{(-1), (-2), (-3)}, (a, b) => abs(a) == abs(b)) // true +``` +*/ +let equal: (t<'a>, t<'a>, ('a, 'a) => bool) => bool + +/** +`has(list, element, f)` returns `true` if the list contains at least one +`element` for which `f` returns `true'. + +## Examples + +```rescript +list{1, 2, 3}->List.has(2, (a, b) => a == b) // true + +list{1, 2, 3}->List.has(4, (a, b) => a == b) // false + +list{(-1), (-2), (-3)}->List.has(2, (a, b) => abs(a) == abs(b)) // true +``` +*/ +let has: (t<'a>, 'b, ('a, 'b) => bool) => bool + +/** +`find(list, f)` returns `Some(value)` for the first value in `list` that +satisfies the predicate function `f`. Returns `None` if no element satisfies +the function. + +## Examples + +```rescript +List.find(list{1, 4, 3, 2}, x => x > 3) // Some(4) + +List.find(list{1, 4, 3, 2}, x => x > 4) // None +``` +*/ +let find: (t<'a>, 'a => bool) => option<'a> + +/** +`filter(list, f)` returns a list of all elements in `list` which satisfy the +predicate function `f`. + +## Examples + +```rescript +let isEven = x => mod(x, 2) == 0 + +List.filter(list{1, 2, 3, 4}, isEven) // list{2, 4} + +List.filter(list{None, Some(2), Some(3), None}, Option.isSome) // list{Some(2), Some(3)} +``` +*/ +let filter: (t<'a>, 'a => bool) => t<'a> + +/** +`filterWithIndex(list, f)` returns a list of all elements in `list` which +satisfy the predicate function `f`. + +## Examples + +```rescript +let isEven = x => mod(x, 2) == 0 + +List.filterWithIndex(list{1, 2, 3, 4}, (_x, index) => isEven(index)) // list{1, 3} +``` +*/ +let filterWithIndex: (t<'a>, ('a, int) => bool) => t<'a> + +/** +`filterMap(list, f)` applies `f` to each element of `list`. If `f` returns +`Some(value)`, then `value` is _kept_ in the resulting list. If `f` returns +`None`, the element is _not_ retained in the result. + +## Examples + +```rescript +let isEven = x => mod(x, 2) == 0 + +list{1, 2, 3, 4} +->List.filterMap(x => + if (isEven(x)) { + Some(x) + } else { + None + } + ) // list{2, 4} + +list{Some(1), Some(2), None}->List.filterMap(x => x) // list{1, 2} +``` +*/ +let filterMap: (t<'a>, 'a => option<'b>) => t<'b> + +/** +`partition(list, f)` creates a pair of lists; the first list consists of all +elements of `list` that satisfy the predicate function `f`, the second list +consists of all elements of `list` that _do not_ satisfy `f`. + +## Examples + +```rescript +// (elementsThatSatisfies, elementsThatDoesNotSatisfy) + +List.partition(list{1, 2, 3, 4}, x => x > 2) // (list{3, 4}, list{1, 2}) +``` +*/ +let partition: (t<'a>, 'a => bool) => (t<'a>, t<'a>) + +/** +`unzip(list)` takes a list of pairs and creates a pair of lists. The first list +contains all the first items of the pairs, the second list contains all the +second items. + +## Examples + +```rescript +List.unzip(list{(1, 2), (3, 4)}) // (list{1, 3}, list{2, 4}) + +List.unzip(list{("H", "W"), ("e", "o"), ("l", "r"), ("l", "l"), ("o", "d"), (" ", "!")}) +// (list{"H", "e", "l", "l", "o", " "}, list{"W", "o", "r", "l", "d", "!"}) +``` +*/ +let unzip: t<('a, 'b)> => (t<'a>, t<'b>) + +/** +`getAssoc(list, k, f)` return the second element of a pair in `list` where +the first element equals `k` as per the predicate function `f`, or `None` if +not found. + +## Examples + +```rescript +list{(1, "a"), (2, "b"), (3, "c")}->List.getAssoc(3, (a, b) => a == b) // Some("c") + +list{(9, "morning"), (15, "afternoon"), (22, "night")} +->List.getAssoc(15, (k, item) => k /* 15 */ == item /* 9, 5, 22 */) +// Some("afternoon") +``` +*/ +let getAssoc: (t<('a, 'c)>, 'b, ('a, 'b) => bool) => option<'c> + +/** +`hasAssoc(list, k, f)` returns `true` if there is a pair in `list` where the +first element equals `k` as per the predicate function `f`. + +## Examples + +```rescript +list{(1, "a"), (2, "b"), (3, "c")}->List.hasAssoc(1, (a, b) => a == b) // true + +list{(9, "morning"), (15, "afternoon"), (22, "night")} +->List.hasAssoc(25, (k, item) => k /* 25 */ == item /* 9, 5, 22 */) // false +``` +*/ +let hasAssoc: (t<('a, 'c)>, 'b, ('a, 'b) => bool) => bool + +/** +`removeAssoc(list, k, f)` return a list after removing the first pair whose +first value is `k` per the equality predicate `f`, if not found, return a new +list identical to `list`. + +## Examples + +```rescript +list{(1, "a"), (2, "b"), (3, "c")}->List.removeAssoc(1, (a, b) => a == b) // list{(2, "b"), (3, "c")} + +list{(9, "morning"), (15, "afternoon"), (22, "night")} +->List.removeAssoc(9, (k, item) => k /* 9 */ == item /* 9, 5, 22 */) +// list{(15, "afternoon"), (22, "night")} +``` +*/ +let removeAssoc: (t<('a, 'c)>, 'b, ('a, 'b) => bool) => t<('a, 'c)> + +/** +`setAssoc(list, k, v, f)`. If `k` exists in `list` by satisfying the `f` +predicate, return a new list with the key and value replaced by the new `k` and +`v`, otherwise, return a new list with the pair `k`, `v` added to the head of +`list`. + +## Examples + +```rescript +list{(1, "a"), (2, "b"), (3, "c")}->List.setAssoc(2, "x", (a, b) => a == b) // list{(1, "a"), (2, "x"), (3, "c")} + +list{(1, "a"), (3, "c")}->List.setAssoc(2, "b", (a, b) => a == b) // list{(2, "b"), (1, "a"), (3, "c")} + +list{(9, "morning"), (3, "morning?!"), (22, "night")} +->List.setAssoc(15, "afternoon", (a, b) => mod(a, 12) == mod(b, 12)) +// list{(9, "morning"), (15, "afternoon"), (22, "night")} +``` + +**Please note**: In the last example, since: `15 mod 12` equals `3 mod 12`. Both +the key _and_ the value are replaced in the list. +*/ +let setAssoc: (t<('a, 'c)>, 'a, 'c, ('a, 'a) => bool) => t<('a, 'c)> + +/** +`sort(list, f)` returns a sorted list. + +## Examples + +```rescript +List.sort(list{5, 4, 9, 3, 7}, Int.compare) // list{3, 4, 5, 7, 9} +``` +*/ +let sort: (t<'a>, ('a, 'a) => Ordering.t) => t<'a> diff --git a/runtime/Map.res b/runtime/Map.res index b547fe31de..a6fa75344c 100644 --- a/runtime/Map.res +++ b/runtime/Map.res @@ -1,4 +1,21 @@ -// FIXME: -// This exists for compatibility reason. -// Move this into Pervasives or Core +type t<'k, 'v> = Js.Map.t<'k, 'v> +@new external make: unit => t<'k, 'v> = "Map" +@new external fromArray: array<('k, 'v)> => t<'k, 'v> = "Map" +@new external fromIterator: Iterator.t<('k, 'v)> => t<'k, 'v> = "Map" + +@get external size: t<'k, 'v> => int = "size" + +@send external clear: t<'k, 'v> => unit = "clear" + +@send external forEach: (t<'k, 'v>, 'v => unit) => unit = "forEach" +@send external forEachWithKey: (t<'k, 'v>, ('v, 'k) => unit) => unit = "forEach" + +@send external get: (t<'k, 'v>, 'k) => option<'v> = "get" +@send external has: (t<'k, 'v>, 'k) => bool = "has" +@send external set: (t<'k, 'v>, 'k, 'v) => unit = "set" +@send external delete: (t<'k, 'v>, 'k) => bool = "delete" + +@send external keys: t<'k, 'v> => Iterator.t<'k> = "keys" +@send external values: t<'k, 'v> => Iterator.t<'v> = "values" +@send external entries: t<'k, 'v> => Iterator.t<('k, 'v)> = "entries" diff --git a/runtime/Map.resi b/runtime/Map.resi new file mode 100644 index 0000000000..f1067a8abb --- /dev/null +++ b/runtime/Map.resi @@ -0,0 +1,265 @@ +/*** +Bindings to the mutable JavaScript `Map`. + +See [`Map`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) on MDN. +*/ + +/** +Type representing an instance of `Map`. +*/ +type t<'k, 'v> = Js.Map.t<'k, 'v> + +/** +Creates a new, mutable JavaScript `Map`. A `Map` can have any values as both keys and values. + +See [`Map`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) on MDN. + + + +## Examples +```rescript +`make()` +// You can annotate the type of your map if you want to +let myMap: Map.t = Map.make() + +// Or you can let ReScript infer what's in your map +let map = Map.make() +map->Map.set("lang", "ReScript") // Inferred as Map.t +``` + +## Alternatives +A JavaScript `Map` is mutable. If you're looking for an immutable alternative, check out`Belt.Map`. +*/ +@new +external make: unit => t<'k, 'v> = "Map" + +/** +Turns an array of key/value pairs into a Map. + +## Examples +```rescript +type languages = ReScript | JavaScript | TypeScript +let languageRank = [(ReScript, 1), (JavaScript, 2), (TypeScript, 3)] + +let map = Map.fromArray(languageRank) // Map.t + +switch map->Map.get(ReScript) { +| Some(1) => Console.log("Yay, ReScript is #1!") +| _ => Console.log("Uh-oh, something is _terribly_ wrong with this program... abort.") +} +``` +*/ +@new +external fromArray: array<('k, 'v)> => t<'k, 'v> = "Map" + +/** +Turns an iterator in the shape of `('key, 'value)` into a `Map`. + +## Examples +```rescript +// Let's pretend we have an interator in the correct shape +@val external someIterator: Iterator.t<(string, int)> = "someIterator" + +let map = Map.fromIterator(someIterator) // Map.t +``` +*/ +@new +external fromIterator: Iterator.t<('k, 'v)> => t<'k, 'v> = "Map" + +/** +Returns the size, the number of key/value pairs, of the map. + +## Examples +```rescript +let map = Map.make() + +map->Map.set("someKey", "someValue") + +let size = map->Map.size // 1 +``` +*/ +@get +external size: t<'k, 'v> => int = "size" + +/** +Clears all entries in the map. + +## Examples +```rescript +let map = Map.make() + +map->Map.set("someKey", "someValue") +map->Map.size // 1 + +map->Map.clear +map->Map.size // 0 +``` +*/ +@send +external clear: t<'k, 'v> => unit = "clear" + +/** +Iterates through all values of the map. + +> Please note that this is *without the keys*, just the values. If you need the key as well, use `Map.forEachWithKey`. + +## Examples +```rescript +let map = Map.make() +map->Map.set("someKey", "someValue") +map->Map.set("someKey2", "someValue2") + +map->Map.forEach(value => { + Console.log(value) +}) +``` +*/ +@send +external forEach: (t<'k, 'v>, 'v => unit) => unit = "forEach" + +/** +Iterates through all values of the map, including the key for each value. + +## Examples +```rescript +let map = Map.make() +map->Map.set("someKey", "someValue") +map->Map.set("someKey2", "someValue2") + +map->Map.forEachWithKey((value, key) => { + Console.log2(value, key) +}) +``` +*/ +@send +external forEachWithKey: (t<'k, 'v>, ('v, 'k) => unit) => unit = "forEach" + +/** +Returns the value for a key, if a value exists at that key. + +## Examples +```rescript +let map = Map.make() +map->Map.set("someKey", "someValue") + +switch map->Map.get("someKey") { +| None => Console.log("Nope, didn't have it.") +| Some(value) => Console.log2("Yay, had the value, and it's:", value) +} +``` +*/ +@send +external get: (t<'k, 'v>, 'k) => option<'v> = "get" + +/** +Checks whether the map has a specific key. + +## Examples +```rescript +let map = Map.make() +map->Map.set("someKey", "someValue") + +switch map->Map.has("someKey") { +| false => Console.log("Nope, didn't have it.") +| true => Console.log("Yay, we have the value!") +} +``` +*/ +@send +external has: (t<'k, 'v>, 'k) => bool = "has" + +/** +Sets the provided `value` to the provided `key`. + +## Examples +```rescript +let map = Map.make() +map->Map.set("someKey", "someValue") +``` +*/ +@send +external set: (t<'k, 'v>, 'k, 'v) => unit = "set" + +/** +Deletes the provided `key` and its value from the map. Returns a `bool` for whether the key existed, and was deleted. + +## Examples +```rescript +let map = Map.make() +map->Map.set("someKey", "someValue") +let didDeleteKey = map->Map.delete("someKey") +Console.log(didDeleteKey) // Logs `true` to the console, becuase the map had the key, so it was successfully deleted + +let didDeleteKey = map->Map.delete("someNonExistantKey") +Console.log(didDeleteKey) // Logs `false` to the console, becuase the key did not exist +``` +*/ +@send +external delete: (t<'k, 'v>, 'k) => bool = "delete" + +/** +Returns an iterator that holds all keys of the map. + +## Examples +```rescript +let map = Map.make() +map->Map.set("someKey", "someValue") +map->Map.set("anotherKey", "anotherValue") + +let keys = map->Map.keys + +// Logs the first key +Console.log(Iterator.next(keys).value) + +// You can also turn the iterator into an array. +// Remember that an iterator consumes values. We'll need a fresh keys iterator to get an array of all keys, since we consumed a value via `next` above already. +Console.log(map->Map.keys->Iterator.toArray) +``` +*/ +@send +external keys: t<'k, 'v> => Iterator.t<'k> = "keys" + +/** +Returns an iterator that holds all values of the map. + +## Examples +```rescript +let map = Map.make() +map->Map.set("someKey", "someValue") +map->Map.set("anotherKey", "anotherValue") + +let values = map->Map.values + +// Logs the first value +Console.log(Iterator.next(values).value) + +// You can also turn the iterator into an array. +// Remember that an iterator consumes values. We'll need a fresh values iterator to get an array of all values, since we consumed a value via `next` above already. +Console.log(map->Map.values->Iterator.toArray) +``` +*/ +@send +external values: t<'k, 'v> => Iterator.t<'v> = "values" + +/** +Returns an iterator that holds all entries of the map. +An entry is represented as a tuple of `('key, 'value)`, + +## Examples +```rescript +let map = Map.make() +map->Map.set("someKey", "someValue") +map->Map.set("anotherKey", "anotherValue") + +let entries = map->Map.entries + +// Logs the first value +Console.log(Iterator.next(entries).value) + +// You can also turn the iterator into an array. +// Remember that an iterator consumes entries. We'll need a fresh entries iterator to get an array of all entries, since we consumed a value via `next` above already. +Console.log(map->Map.entries->Iterator.toArray) +``` +*/ +@send +external entries: t<'k, 'v> => Iterator.t<('k, 'v)> = "entries" diff --git a/runtime/Math.res b/runtime/Math.res new file mode 100644 index 0000000000..11d17501d1 --- /dev/null +++ b/runtime/Math.res @@ -0,0 +1,62 @@ +module Constants = { + @val external e: float = "Math.E" + @val external ln2: float = "Math.LN2" + @val external ln10: float = "Math.LN10" + @val external log2e: float = "Math.LOG2E" + @val external log10e: float = "Math.LOG10E" + @val external pi: float = "Math.PI" + @val external sqrt1_2: float = "Math.SQRT1_2" + @val external sqrt2: float = "Math.SQRT2" +} + +@val external abs: float => float = "Math.abs" +@val external acos: float => float = "Math.acos" +@val external acosh: float => float = "Math.acosh" +@val external asin: float => float = "Math.asin" +@val external asinh: float => float = "Math.asinh" +@val external atan: float => float = "Math.atan" +@val external atanh: float => float = "Math.atanh" +@val external atan2: (~y: float, ~x: float) => float = "Math.atan2" +@val external cbrt: float => float = "Math.cbrt" +@val external ceil: float => float = "Math.ceil" +@val external cos: float => float = "Math.cos" +@val external cosh: float => float = "Math.cosh" +@val external exp: float => float = "Math.exp" +@val external expm1: float => float = "Math.expm1" +@val external floor: float => float = "Math.floor" +@val external fround: float => float = "Math.fround" +@val external hypot: (float, float) => float = "Math.hypot" +@variadic @val external hypotMany: array => float = "Math.hypot" +@val external log: float => float = "Math.log" +@val external log1p: float => float = "Math.log1p" +@val external log10: float => float = "Math.log10" +@val external log2: float => float = "Math.log2" +@val external min: (float, float) => float = "Math.min" +@variadic @val external minMany: array => float = "Math.min" +@val external max: (float, float) => float = "Math.max" +@variadic @val external maxMany: array => float = "Math.max" +@val external pow: (float, ~exp: float) => float = "Math.pow" +@val external random: unit => float = "Math.random" +@val external round: float => float = "Math.round" +@val external sign: float => float = "Math.sign" +@val external sin: float => float = "Math.sin" +@val external sinh: float => float = "Math.sinh" +@val external sqrt: float => float = "Math.sqrt" +@val external tan: float => float = "Math.tan" +@val external tanh: float => float = "Math.tanh" +@val external trunc: float => float = "Math.trunc" + +module Int = { + @val external abs: int => int = "Math.abs" + @val external clz32: int => int = "Math.clz32" + @val external imul: (int, int) => int = "Math.imul" + @val external min: (int, int) => int = "Math.min" + @variadic @val external minMany: array => int = "Math.min" + @val external max: (int, int) => int = "Math.max" + @variadic @val external maxMany: array => int = "Math.max" + @val external pow: (int, ~exp: int) => int = "Math.pow" + @val external sign: int => int = "Math.sign" + let floor: float => int = f => f->floor->Float.toInt + let ceil: float => int = f => f->ceil->Float.toInt + let random: (int, int) => int = (min, max) => floor(random() *. Int.toFloat(max - min)) + min +} diff --git a/runtime/Math.resi b/runtime/Math.resi new file mode 100644 index 0000000000..ef146f9bcb --- /dev/null +++ b/runtime/Math.resi @@ -0,0 +1,892 @@ +/* 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. */ + +/*** +Functions for interacting with JavaScript Math. +See: [`Math`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math). +*/ + +/** +Mathematical Constants +*/ +module Constants: { + /** + `Math.Constants.e` returns Euler's number, ≈ 2.718281828459045. + See [`Math.E`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/E) on MDN. + + ## Examples + + ```rescript + Math.Constants.e + ``` + */ + @val + external e: float = "Math.E" + + /** + `Math.Constants.ln2` returns 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. + + ## Examples + + ```rescript + Math.Constants.ln2 + ``` + */ + @val + external ln2: float = "Math.LN2" + + /** + `Math.Constants.ln10` returns 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. + + ## Examples + + ```rescript + Math.Constants.ln10 + ``` + */ + @val + external ln10: float = "Math.LN10" + + /** + `Math.Constants.log2e` returns 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. + + ## Examples + + ```rescript + Math.Constants.log2e + ``` + */ + @val + external log2e: float = "Math.LOG2E" + + /** + `Math.Constants.log10e` returns 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. + + ## Examples + + ```rescript + Math.Constants.log10e + ``` + */ + @val + external log10e: float = "Math.LOG10E" + /** + `Math.Constants.pi` returns 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. + + ## Examples + + ```rescript + Math.Constants.pi + ``` + */ + @val + external pi: float = "Math.PI" + /** + `Math.Constants.sqrt1_2` returns 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. + + ## Examples + + ```rescript + Math.Constants.sqrt1_2 + ``` + */ + @val + external sqrt1_2: float = "Math.SQRT1_2" + /** + `Math.Constants.e` returns Absolute value for integer argument. + See [`Math.abs`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/abs) on MDN. + + ## Examples + + ```rescript + Math.Constants.sqrt2 + ``` + */ + @val + external sqrt2: float = "Math.SQRT2" +} + +/** +Provide Math utilities for `int` +*/ +module Int: { + /** + `abs(v)` returns absolute value of `v`. + See [`Math.abs`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/abs) on MDN. + + ## Examples + + ```rescript + Math.Int.abs(-2) // 2 + Math.Int.abs(3) // 3 + ``` + */ + @val + external abs: int => int = "Math.abs" + + /** + `clz32(v)` returns the 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. + + ## Examples + + ```rescript + // 00000000000000000000000000000001 + Math.Int.clz32(1) // 31 + // 00000000000000000000000000000100 + Math.Int.clz32(4) // 29 + ``` + */ + @val + external clz32: int => int = "Math.clz32" + + /** + `imul(a, b)` returns 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. + + ## Examples + + ```rescript + Math.Int.imul(3, 4) // 12 + Math.Int.imul(-5, 12) // 60 + ``` + */ + @val + external imul: (int, int) => int = "Math.imul" + + /** + `min(a, b)` 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. + + ## Examples + + ```rescript + Math.Int.min(1, 2) // 1 + Math.Int.min(-1, -2) // -2 + ``` + */ + @val + external min: (int, int) => int = "Math.min" + + /** + `minMany(arr)` returns the minimum of the integers in the given array `arr`. + Returns `Infinity` if `arr` is empty. + See [`Math.min`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/min) on MDN. + + ## Examples + + ```rescript + Math.Int.minMany([1, 2]) // 1 + Math.Int.minMany([-1, -2]) // -2 + Math.Int.minMany([])->Int.toFloat->Float.isFinite // false + ``` + */ + @variadic + @val + external minMany: array => int = "Math.min" + + /** + `max(a, b)` 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. + + ## Examples + + ```rescript + Math.Int.max(1, 2) // 2 + Math.Int.max(-1, -2) // -1 + ``` + */ + @val + external max: (int, int) => int = "Math.max" + + /** + `maxMany(arr)` returns the maximum of the integers in the given array `arr`. + Returns `Infinity` if `arr` is empty. + See [`Math.max`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/max) on MDN. + + ## Examples + + ```rescript + Math.Int.maxMany([1, 2]) // 2 + Math.Int.maxMany([-1, -2]) // -1 + Math.Int.maxMany([])->Int.toFloat->Float.isFinite // false + ``` + */ + @variadic + @val + external maxMany: array => int = "Math.max" + + /** + `pow(a, ~exp)` raises the given base `a` to the given exponent `exp`. + See [`Math.pow`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/pow) on MDN. + + ## Examples + + ```rescript + Math.Int.pow(2, ~exp=4) // 16 + Math.Int.pow(3, ~exp=4) // 81 + ``` + */ + @val + external pow: (int, ~exp: int) => int = "Math.pow" + + /** + `sign(v)` 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. + + ## Examples + + ```rescript + Math.Int.sign(3) // 1 + Math.Int.sign(-3) // 1 + Math.Int.sign(0) // 0 + ``` + */ + @val + external sign: int => int = "Math.sign" + + /** + floor(v) returns the largest `int` less than or equal to the argument; + See [`Math.floor`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/floor) + on MDN. + + ## Examples + + ```rescript + Math.Int.floor(3.7) == 3 + Math.Int.floor(3.0) == 3 + Math.Int.floor(-3.1) == -4 + ``` + */ + let floor: float => int + + /** + ceil(v) returns the smallest `int` greater than or equal to the argument; + See [`Math.floor`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/floor) + on MDN. + + ## Examples + + ```rescript + Math.Int.ceil(3.7) == 4 + Math.Int.ceil(3.0) == 3 + Math.Int.ceil(-3.1) == -3 + ``` + */ + let ceil: float => int + + /** + `random(minVal, maxVal)` returns a random integer 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. + + ## Examples + + ```rescript + Math.Int.random(2, 5) == 4 + Math.Int.random(505, 2000) == 1276 + Math.Int.random(-7, -2) == -4 + ``` + */ + let random: (int, int) => int +} + +/** +`abs(v)` returns absolute value of `v`. +See [`Math.abs`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/abs) on MDN. + +## Examples + +```rescript +Math.abs(-2.0) // 2.0 +Math.abs(3.0) // 3.0 +``` + */ +@val +external abs: float => float = "Math.abs" + +/** +`acos(v)` returns arccosine (in radians) of argument `v`, 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. + +## Examples + +```rescript +Math.acos(-1.0) // 3.141592653589793 +Math.acos(-3.0)->Float.isNaN // true +``` +*/ +@val +external acos: float => float = "Math.acos" + +/** +`acosh(v)` returns the inverse hyperbolic arccosine (in radians) of argument `v`, +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. + +## Examples + +```rescript +Math.acosh(1.0) // 0.0 +Math.acosh(0.5)->Float.isNaN // true +``` +*/ +@val +external acosh: float => float = "Math.acosh" + +/** +`asin(v)` returns the inverse sine (in radians) of argument `v`, returns `NaN` +if the argument `v` 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. + +## Examples + +```rescript +Math.asin(-1.0) // -1.5707963267948966 +Math.asin(-2.0)->Float.isNaN // true +``` +*/ +@val +external asin: float => float = "Math.asin" + +/** +`asinh(v)` returns the inverse hyperbolic sine of argument `v`. +See [`Math.asinh`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/asinh) on MDN. + +## Examples + +```rescript +Math.asinh(-1.0) // -0.881373587019543 +Math.asinh(-0.0) // -0.0 +``` +*/ +@val +external asinh: float => float = "Math.asinh" + +/** +`atan(v)` returns the inverse tangent (in radians) of argument `v`. +See [`Math.atan`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/atan) on MDN. + +## Examples + +```rescript +Math.atan(-0.0) // -0.0 +Math.atan(0.0) // 0.0 +Math.atan(1.0) // 0.7853981633974483 +``` +*/ +@val +external atan: float => float = "Math.atan" + +/** +`atanh(v)` returns the invert hyperbolic tangent of argument `v`. Returns `NaN` +if the argument `v` is is outside the range [-1.0, 1.0] and `Infinity` if `v` +is `-1.0` or `1.0`. +See [`Math.atanh`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/atanh) on MDN. + +## Examples + +```rescript +Math.atanh(-2.0)->Float.isNaN // true +Math.atanh(-1.0)->Float.isFinite // false +Math.atanh(-0.0) // -0.0 +Math.atanh(0.0) // 0.0 +Math.atanh(0.5) // 0.5493061443340548 +``` +*/ +@val +external atanh: float => float = "Math.atanh" + +/** +`atan2(~y, ~x)` 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) on MDN. + +## Examples + +```rescript +Math.atan2(~y=0.0, ~x=10.0) == 0.0 +Math.atan2(~x=5.0, ~y=5.0) == Math.Constants.pi /. 4.0 +Math.atan2(~x=90.0, ~y=15.0) // 1.4056476493802699 +Math.atan2(~x=15.0, ~y=90.0) // 0.16514867741462683 +``` +*/ +@val +external atan2: (~y: float, ~x: float) => float = "Math.atan2" + +/** +`cbrt(v)` returns the cube root of argument `v`. +See [`Math.cbrt`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/cbrt) on MDN. + +## Examples + +```rescript +Math.cbrt(-1.0) // -1.0 +Math.cbrt(-0.0) // -0.0 +Math.cbrt(0.0) // 0.0 +``` +*/ +@val +external cbrt: float => float = "Math.cbrt" + +/** +`ceil(v)` returns the smallest integral value greater than or equal to the +argument `v`. The result is a `float` and is not restricted to the `int` data +type range. +See [`Math.ceil`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/ceil) on MDN. + +## Examples + +```rescript +Math.ceil(3.1) == 4.0 +Math.ceil(3.0) == 3.0 +Math.ceil(-3.1) == -3.0 +Math.ceil(2_150_000_000.3) == 2_150_000_001.0 +``` +*/ +@val +external ceil: float => float = "Math.ceil" + +/** +`cos(v)` returns the cosine of argument `v`, 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. + +## Examples + +```rescript +Math.cos(-0.0) // 1.0 +Math.cos(0.0) // 1.0 +Math.cos(1.0) // 0.5403023058681398 +``` +*/ +@val +external cos: float => float = "Math.cos" + +/** +`cosh(v)` returns the hyperbolic cosine of argument `v`, 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. + +## Examples + +```rescript +Math.cosh(-1.0) // 1.5430806348152437 +Math.cosh(-0.0) // 1.0 +Math.cosh(0.0) // 1.0 +``` +*/ +@val +external cosh: float => float = "Math.cosh" + +/** +`exp(v)` returns natural exponentional, returns *e* (the base of natural logarithms) +to the power of the given argument `v`. +See [`Math.exp`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/exp) on MDN. + +## Examples + +```rescript +Math.exp(-1.0) // 0.36787944117144233 +Math.exp(0.0) // 1.0 +``` +*/ +@val +external exp: float => float = "Math.exp" + +/** +`expm1(v)` returns *e* (the base of natural logarithms) to the power of the given +argument `v` minus 1. +See [`Math.expm1`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/expm1) on MDN. + +## Examples + +```rescript +Math.expm1(-1.0) // -0.6321205588285577 +Math.expm1(-0.0) // -0 +``` +*/ +@val +external expm1: float => float = "Math.expm1" + +/** +`floor(v)` returns the largest integral value less than or equal to the argument +`v`. 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) on MDN. + +## Examples + +```rescript +Math.floor(-45.95) // -46.0 +Math.floor(-45.05) // -46.0 +Math.floor(-0.0) // -0.0 +``` +*/ +@val +external floor: float => float = "Math.floor" + +/** +`fround(v)` returns the nearest single precision float. +See [`Math.fround`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/fround) on MDN. + +## Examples + +```rescript +Math.fround(5.5) == 5.5 +Math.fround(5.05) == 5.050000190734863 +``` +*/ +@val +external fround: float => float = "Math.fround" + +/** +`hypot(a, b)` 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. + +## Examples + +```rescript +Math.hypot(3.0, 4.0) // 5.0 +Math.hypot(3.0, 5.0) // 5.8309518948453 +``` +*/ +@val +external hypot: (float, float) => float = "Math.hypot" + +/** +`hypotMany(arr)` 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. If `arr` is an empty array then returns `0.0`. +See [`Math.hypot`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/hypot) on MDN. + +## Examples + +```rescript +Math.hypotMany([3.0, 4.0, 5.0]) // 7.0710678118654755 +Math.hypotMany([]) // 0.0 +``` +*/ +@variadic +@val +external hypotMany: array => float = "Math.hypot" + +/** +`log(v)` returns the natural logarithm of argument `v`, this is the number *x* +such that `e^x` equals the argument. Returns `NaN` for negative arguments and +`Infinity` for `0.0` or `-0.0`. +See [`Math.log`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/log) on MDN. + +## Examples + +```rescript +Math.log(-1.0)->Float.isNaN // true +Math.log(-0.0)->Float.isFinite // false +Math.log(0.0)->Float.isFinite // false +Math.log(1.0) // 0 +``` +*/ +@val +external log: float => float = "Math.log" + +/** +`log1p(v)` returns the natural logarithm of one plus the argument `v`. +Returns `NaN` for arguments less than `-1` and `Infinity` if `v` is `-1.0`. +See [`Math.log1p`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/log1p) on MDN. + +## Examples + +```rescript +Math.log1p(-2.0)->Float.isNaN // true +Math.log1p(-1.0)->Float.isFinite // false +Math.log1p(-0.0) // -0 +``` +*/ +@val +external log1p: float => float = "Math.log1p" + +/** +`log10(v)` returns the base 10 logarithm of argument `v`. Returns `NaN` for +negative `v`. If `v` is `-0.0` or `0.0` returns `Infinity`. +See [`Math.log10`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/log10) on MDN. + +## Examples + +```rescript +Math.log10(-2.0)->Float.isNaN // true +Math.log10(-0.0)->Float.isFinite // false +Math.log10(0.0)->Float.isFinite // false +Math.log10(1.0) // 0 +``` +*/ +@val +external log10: float => float = "Math.log10" + +/** +`log2(v)` returns the base 2 logarithm of argument `v`. Returns `NaN` for +negative `v` and `Infinity` if `v` is `-0.0` or `0.0`. +See [`Math.log2`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/log2) on MDN. + +## Examples + +```rescript +Math.log2(-2.0)->Float.isNaN // true +Math.log2(-0.0)->Float.isFinite // false +Math.log2(0.0)->Float.isFinite // false +Math.log2(1.0) // 0.0 +``` +*/ +@val +external log2: float => float = "Math.log2" + +/** +`min(a, b)` returns the minimum of its two float arguments. +See [`Math.min`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/min) on MDN. + +## Examples + +```rescript +Math.min(1.0, 2.0) // 1.0 +Math.min(-1.0, -2.0) // -2.0 +``` +*/ +@val +external min: (float, float) => float = "Math.min" + +/** +`minMany(arr)` returns the minimum of the float in the given array `arr`. +Returns `Infinity` if `arr` is empty. +See [`Math.min`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/min) on MDN. + +## Examples + +```rescript +Math.minMany([1.0, 2.0]) // 1.0 +Math.minMany([-1.0, -2.0]) // -2.0 +Math.minMany([])->Float.isFinite // false +``` +*/ +@variadic +@val +external minMany: array => float = "Math.min" + +/** +`max(a, b)` returns the maximum of its two float arguments. +See [`Math.max`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/max) on MDN. + +## Examples + +```rescript +Math.max(1.0, 2.0) // 2.0 +Math.max(-1.0, -2.0) // -1.0 +``` +*/ +@val +external max: (float, float) => float = "Math.max" + +/** +`maxMany(arr)` returns the maximum of the float in the given array `arr`. +Returns `Infinity` if `arr` is empty. +See [`Math.max`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/max) on MDN. + +## Examples + +```rescript +Math.maxMany([1.0, 2.0]) // 2.0 +Math.maxMany([-1.0, -2.0]) // -1.0 +Math.maxMany([])->Float.isFinite // false +``` +*/ +@variadic +@val +external maxMany: array => float = "Math.max" + +/** +`pow(a, ~exp)` raises the given base `a` to the given exponent `exp`. +See [`Math.pow`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/pow) on MDN. + +## Examples + +```rescript +Math.pow(2.0, ~exp=4.0) // 16.0 +Math.pow(3.0, ~exp=4.0) // 81.0 +``` +*/ +@val +external pow: (float, ~exp: float) => float = "Math.pow" + +/** +`random()` 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. + +## Examples + +```rescript +Math.random() +``` +*/ +@val +external random: unit => float = "Math.random" + +/** +`round(v)` returns then value of `v` rounded to nearest integral value +(expressed as a float). If the fractional portion of the argument `v` is greater +than `0.5`, the argument `v` is rounded to the float with the next higher +absolute value. +See [`Math.round`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/round) on MDN. + +## Examples + +```rescript +Math.round(-20.5) // -20.0 +Math.round(-0.1) // -0.0 +Math.round(0.0) // 0.0 +Math.round(-0.0) // -0.0 +``` +*/ +@val +external round: float => float = "Math.round" + +/** +`sign(v)` returns the sign of its foat 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. + +## Examples + +```rescript +Math.sign(3.0) // 1.0 +Math.sign(-3.0) // 1.0 +Math.sign(0.0) // 0.0 +``` +*/ +@val +external sign: float => float = "Math.sign" + +/** +`sin(v)` returns the sine of argument `v`, 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. + +## Examples + +```rescript +Math.sin(-0.0) // -0.0 +Math.sin(0.0) // 0.0 +Math.sin(1.0) // 0.8414709848078965 +``` +*/ +@val +external sin: float => float = "Math.sin" + +/** +`sinh(v)` returns then hyperbolic sine of argument `v`, 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. + +## Examples + +```rescript +Math.sinh(-0.0) // -0.0 +Math.sinh(0.0) // 0.0 +Math.sinh(1.0) // 1.1752011936438014 +``` +*/ +@val +external sinh: float => float = "Math.sinh" + +/** +`sqrt(v)` returns the square root of `v`. If `v` is negative returns `NaN`. +See [`Math.sqrt`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/sqrt) on MDN. + +## Examples + +```rescript +Math.sqrt(-1.0)->Float.isNaN // true +Math.sqrt(-0.0) // -0.0 +Math.sqrt(0.0) // 0.0 +Math.sqrt(1.0) // 1.0 +Math.sqrt(9.0) // 3.0 +``` +*/ +@val +external sqrt: float => float = "Math.sqrt" + +/** +`tan(v)` returns the tangent of argument `v`, which must be specified in +radians. Returns `NaN` if `v` is positive `Infinity` or negative `Infinity`. +See [`Math.tan`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/tan) on MDN. + +## Examples + +```rescript +Math.tan(-0.0) // -0.0 +Math.tan(0.0) // 0.0 +Math.tan(1.0) // 1.5574077246549023 +``` +*/ +@val +external tan: float => float = "Math.tan" + +/** +`tanh(v)` returns the hyperbolic tangent of argument `v`, 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. + +## Examples + +```rescript +Math.tanh(-0.0) // -0.0 +Math.tanh(0.0) // 0.0 +Math.tanh(1.0) // 0.7615941559557649 +``` +*/ +@val +external tanh: float => float = "Math.tanh" + +/** +`trunc(v)` truncates the argument `v`, i.e., removes fractional digits. +See [`Math.trunc`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/trunc) on MDN. + +## Examples + +```rescript +Math.trunc(0.123) // 0.0 +Math.trunc(1.999) // 1.0 +Math.trunc(13.37) // 13.0 +Math.trunc(42.84) // 42.0 +``` +*/ +@val +external trunc: float => float = "Math.trunc" diff --git a/runtime/Null.res b/runtime/Null.res new file mode 100644 index 0000000000..2bbb9a2ab5 --- /dev/null +++ b/runtime/Null.res @@ -0,0 +1,64 @@ +@unboxed +type t<'a> = Js.Null.t<'a> = + | Value('a) + | @as(null) Null + +external asNullable: t<'a> => Nullable.t<'a> = "%identity" + +external null: t<'a> = "#null" + +external make: 'a => t<'a> = "%identity" + +external toOption: t<'a> => option<'a> = "#null_to_opt" + +let fromOption: option<'a> => t<'a> = option => + switch option { + | Some(x) => make(x) + | None => null + } + +let equal = (a, b, eq) => Option.equal(a->toOption, b->toOption, eq) + +let compare = (a, b, cmp) => Option.compare(a->toOption, b->toOption, cmp) + +let getOr = (value, default) => + switch value->toOption { + | Some(x) => x + | None => default + } + +let getWithDefault = getOr + +let getExn: t<'a> => 'a = value => + switch value->toOption { + | Some(x) => x + | None => raise(Invalid_argument("Null.getExn: value is null")) + } + +external getUnsafe: t<'a> => 'a = "%identity" + +let forEach = (value, f) => + switch value->toOption { + | Some(x) => f(x) + | None => () + } + +let map = (value, f) => + switch value->toOption { + | Some(x) => make(f(x)) + | None => null + } + +let mapOr = (value, default, f) => + switch value->toOption { + | Some(x) => f(x) + | None => default + } + +let mapWithDefault = mapOr + +let flatMap = (value, f) => + switch value->toOption { + | Some(x) => f(x) + | None => null + } diff --git a/runtime/Null.resi b/runtime/Null.resi new file mode 100644 index 0000000000..7d3f6a22fc --- /dev/null +++ b/runtime/Null.resi @@ -0,0 +1,198 @@ +/*** +Functions for handling values that could be `null`. + +If you also need to cover `undefined`, check out `Nullable` instead. +*/ + +/** +A type representing a value that can be either `'a` or `null`. +*/ +@unboxed +type t<'a> = Js.Null.t<'a> = + | Value('a) + | @as(null) Null + +/** +Converts a `Null.t` into a `Nullable.t`. + +## Examples +```rescript +let nullValue = Null.make("Hello") +let asNullable = nullValue->Null.asNullable // Nullable.t +``` +*/ +external asNullable: t<'a> => Nullable.t<'a> = "%identity" + +/** +The value `null`. + +See [`null`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/null) on MDN. + +## Examples +```rescript +Console.log(null) // Logs `null` to the console. +``` +*/ +external null: t<'a> = "#null" + +/** +Creates a new `Null.t` from the provided value. +This means the compiler will enforce null checks for the new value. + +## Examples +```rescript +let myStr = "Hello" +let asNullValue = myStr->Null.make // The compiler now thinks this can be `string` or `null`. +``` +*/ +external make: 'a => t<'a> = "%identity" + +let equal: (t<'a>, t<'b>, ('a, 'b) => bool) => bool + +let compare: (t<'a>, t<'b>, ('a, 'b) => Ordering.t) => Ordering.t + +/** +Converts a nullable value into an option, so it can be pattern matched on. +Will convert `null` to `None`, and a present value to `Some(value)`. + +## Examples +```rescript +let nullStr = Null.make("Hello") + +switch nullStr->Null.toOption { +| Some(str) => Console.log2("Got string:", str) +| None => Console.log("Didn't have a value.") +} +``` +*/ +external toOption: t<'a> => option<'a> = "#null_to_opt" + +/** +Turns an `option` into a `Null.t`. `None` will be converted to `null`. + +## Examples +```rescript +let optString: option = None +let asNull = optString->Null.fromOption // Null.t +Console.log(asNull == Null.null) // Logs `true` to the console. +``` +*/ +let fromOption: option<'a> => t<'a> + +/** +`getOr(value, default)` returns `value` if not `null`, otherwise return +`default`. + +## Examples + +```rescript +Null.getOr(Null.null, "Banana") // Banana +Null.getOr(Null.make("Apple"), "Banana") // Apple + +let greet = (firstName: option) => + "Greetings " ++ firstName->Option.getOr("Anonymous") + +Null.make("Jane")->Null.toOption->greet // "Greetings Jane" +Null.null->Null.toOption->greet // "Greetings Anonymous" +``` +*/ +let getOr: (t<'a>, 'a) => 'a + +@deprecated("Use getOr instead") +let getWithDefault: (t<'a>, 'a) => 'a + +/** +`getExn(value)` raises an exception if `null`, otherwise returns the value. + +```rescript +Null.getExn(Null.make(3)) // 3 +Null.getExn(Null.null) /* Raises an Error */ +``` + +## Exceptions + +- Raises `Invalid_argument` if `value` is `null`, +*/ +let getExn: t<'a> => 'a + +/** +`getUnsafe(value)` returns `value`. + +## Examples + +```rescript +Null.getUnsafe(Null.make(3)) == 3 +Null.getUnsafe(Null.null) // Raises an error +``` + +## Important + +- This is an unsafe operation, it assumes `value` is not `null`. +*/ +external getUnsafe: t<'a> => 'a = "%identity" + +/** +`forEach(value, f)` call `f` on `value`. if `value` is not `null`, then if calls +`f`, otherwise returns `unit`. + +## Examples + +```rescript +Null.forEach(Null.make("thing"), x => Console.log(x)) // logs "thing" +Null.forEach(Null.null, x => Console.log(x)) // logs nothing +``` +*/ +let forEach: (t<'a>, 'a => unit) => unit + +/** +`map(value, f)` returns `f(value)` if `value` is not `null`, otherwise returns +`value` unchanged. + +## Examples + +```rescript +Null.map(Null.make(3), x => x * x) // Null.make(9) +Null.map(Null.null, x => x * x) // null +``` +*/ +let map: (t<'a>, 'a => 'b) => t<'b> + +/** +`mapOr(value, default, f)` returns `f(value)` if `value` is not `null`, +otherwise returns `default`. + +## Examples + +```rescript +let someValue = Null.make(3) +someValue->Null.mapOr(0, x => x + 5) // 8 + +let noneValue = Null.null +noneValue->Null.mapOr(0, x => x + 5) // 0 +``` +*/ +let mapOr: (t<'a>, 'b, 'a => 'b) => 'b + +@deprecated("Use mapOr instead") +let mapWithDefault: (t<'a>, 'b, 'a => 'b) => 'b + +/** +`flatMap(value, f)` returns `f(value)` if `value` is not `null`, otherwise +returns `value` unchanged. + +## Examples + +```rescript +let addIfAboveOne = value => + if (value > 1) { + Null.make(value + 1) + } else { + Null.null + } + +Null.flatMap(Null.make(2), addIfAboveOne) // Null.make(3) +Null.flatMap(Null.make(-4), addIfAboveOne) // null +Null.flatMap(Null.null, addIfAboveOne) // null +``` +*/ +let flatMap: (t<'a>, 'a => t<'b>) => t<'b> diff --git a/runtime/Nullable.res b/runtime/Nullable.res new file mode 100644 index 0000000000..aa08bcb68b --- /dev/null +++ b/runtime/Nullable.res @@ -0,0 +1,67 @@ +@unboxed +type t<'a> = Js.Nullable.t<'a> = + | Value('a) + | @as(null) Null + | @as(undefined) Undefined + +external null: t<'a> = "#null" + +external undefined: t<'a> = "#undefined" + +external isNullable: t<'a> => bool = "#is_nullable" + +external make: 'a => t<'a> = "%identity" + +external toOption: t<'a> => option<'a> = "#nullable_to_opt" + +let fromOption: option<'a> => t<'a> = option => + switch option { + | Some(x) => make(x) + | None => undefined + } + +let equal = (a, b, eq) => Option.equal(a->toOption, b->toOption, eq) + +let compare = (a, b, cmp) => Option.compare(a->toOption, b->toOption, cmp) + +let getOr = (value, default) => + switch value->toOption { + | Some(x) => x + | None => default + } + +let getWithDefault = getOr + +let getExn: t<'a> => 'a = value => + switch value->toOption { + | Some(x) => x + | None => raise(Invalid_argument("Nullable.getExn: value is null or undefined")) + } + +external getUnsafe: t<'a> => 'a = "%identity" + +let forEach = (value, f) => + switch value->toOption { + | Some(x) => f(x) + | None => () + } + +let map = (value, f) => + switch value->toOption { + | Some(x) => make(f(x)) + | None => Obj.magic(value) + } + +let mapOr = (value, default, f) => + switch value->toOption { + | Some(x) => f(x) + | None => default + } + +let mapWithDefault = mapOr + +let flatMap = (value, f) => + switch value->toOption { + | Some(x) => f(x) + | None => Obj.magic(value) + } diff --git a/runtime/Nullable.resi b/runtime/Nullable.resi new file mode 100644 index 0000000000..30d92195e6 --- /dev/null +++ b/runtime/Nullable.resi @@ -0,0 +1,231 @@ +/*** +Functions for handling nullable values. + +Primarily useful when interoping with JavaScript when you don't know whether you'll get a value, `null` or `undefined`. +*/ + +/** +Type representing a nullable value. +A nullable value can be the value `'a`, `null` or `undefined`. +*/ +@unboxed +type t<'a> = Js.Nullable.t<'a> = + | Value('a) + | @as(null) Null + | @as(undefined) Undefined + +/** +The value `null`. + +See [`null`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/null) on MDN. + +## Examples +```rescript +Console.log(Nullable.null) // Logs `null` to the console. +``` +*/ +external null: t<'a> = "#null" + +/** +The value `undefined`. + +See [`undefined`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/undefined) on MDN. + +## Examples +```rescript +Console.log(undefined) // Logs `undefined` to the console. +``` +*/ +external undefined: t<'a> = "#undefined" + +/** +`isNullable(a)` returns `true` if `a` is null or undefined, `false` otherwise. + +## Examples + +```rescript +let myStr = "Hello" +let asNullable = myStr->Nullable.make + +// Can't do the below because we're now forced to check for nullability +// myStr == asNullable + +// Check if asNullable is not null or undefined +switch asNullable->Nullable.isNullable { +| true => assert(false) +| false => assert(true) +} +``` +*/ +external isNullable: t<'a> => bool = "#is_nullable" + +/** +Creates a new nullable value from the provided value. +This means the compiler will enforce null checks for the new value. + +## Examples +```rescript +let myStr = "Hello" +let asNullable = myStr->Nullable.make + +// Can't do the below because we're now forced to check for nullability +// myStr == asNullable + +// Need to do this +switch asNullable->Nullable.toOption { +| Some(value) if value == myStr => Console.log("Yay, values matched!") +| _ => Console.log("Values did not match.") +} +``` +*/ +external make: 'a => t<'a> = "%identity" + +let equal: (t<'a>, t<'b>, ('a, 'b) => bool) => bool + +let compare: (t<'a>, t<'b>, ('a, 'b) => Ordering.t) => Ordering.t + +/** +Converts a nullable value into an option, so it can be pattern matched on. +Will convert both `null` and `undefined` to `None`, and a present value to `Some(value)`. + +## Examples +```rescript +let nullableString = Nullable.make("Hello") + +switch nullableString->Nullable.toOption { +| Some(str) => Console.log2("Got string:", str) +| None => Console.log("Didn't have a value.") +} +``` +*/ +external toOption: t<'a> => option<'a> = "#nullable_to_opt" + +/** +Turns an `option` into a `Nullable.t`. + +## Examples +```rescript +let optString = Some("Hello") +let asNullable = optString->Nullable.fromOption // Nullable.t +``` +*/ +let fromOption: option<'a> => t<'a> + +/** +`getOr(value, default)` returns `value` if not `null` or `undefined`, +otherwise return `default`. + +## Examples + +```rescript +Nullable.getOr(Nullable.null, "Banana") // Banana +Nullable.getOr(Nullable.make("Apple"), "Banana") // Apple + +let greet = (firstName: option) => + "Greetings " ++ firstName->Option.getOr("Anonymous") + +Nullable.make("Jane")->Nullable.toOption->greet // "Greetings Jane" +Nullable.null->Nullable.toOption->greet // "Greetings Anonymous" +``` +*/ +let getOr: (t<'a>, 'a) => 'a + +@deprecated("Use getOr instead") +let getWithDefault: (t<'a>, 'a) => 'a + +/** +`getExn(value)` raises an exception if `null` or `undefined`, otherwise returns the value. + +```rescript +Nullable.getExn(Nullable.make(3)) // 3 +Nullable.getExn(Nullable.null) /* Raises an Error */ +``` + +## Exceptions + +- Raises `Invalid_argument` if `value` is `null` or `undefined` +*/ +let getExn: t<'a> => 'a + +/** +`getUnsafe(value)` returns `value`. + +## Examples + +```rescript +Nullable.getUnsafe(Nullable.make(3)) == 3 +Nullable.getUnsafe(Nullable.null) // Raises an error +``` + +## Important + +- This is an unsafe operation, it assumes `value` is not `null` or `undefined`. +*/ +external getUnsafe: t<'a> => 'a = "%identity" + +/** +`forEach(value, f)` call `f` on `value`. if `value` is not `null` or `undefined`, +then if calls `f`, otherwise returns `unit`. + +## Examples + +```rescript +Nullable.forEach(Nullable.make("thing"), x => Console.log(x)) // logs "thing" +Nullable.forEach(Nullable.null, x => Console.log(x)) // returns () +Nullable.forEach(undefined, x => Console.log(x)) // returns () +``` +*/ +let forEach: (t<'a>, 'a => unit) => unit + +/** +`map(value, f)` returns `f(value)` if `value` is not `null` or `undefined`, +otherwise returns `value` unchanged. + +## Examples + +```rescript +Nullable.map(Nullable.make(3), x => x * x) // Nullable.make(9) +Nullable.map(undefined, x => x * x) // undefined +``` +*/ +let map: (t<'a>, 'a => 'b) => t<'b> + +/** +`mapOr(value, default, f)` returns `f(value)` if `value` is not `null` +or `undefined`, otherwise returns `default`. + +## Examples + +```rescript +let someValue = Nullable.make(3) +someValue->Nullable.mapOr(0, x => x + 5) // 8 + +let noneValue = Nullable.null +noneValue->Nullable.mapOr(0, x => x + 5) // 0 +``` +*/ +let mapOr: (t<'a>, 'b, 'a => 'b) => 'b + +@deprecated("Use mapOr instead") +let mapWithDefault: (t<'a>, 'b, 'a => 'b) => 'b + +/** +`flatMap(value, f)` returns `f(value)` if `value` is not `null` or `undefined`, +otherwise returns `value` unchanged. + +## Examples + +```rescript +let addIfAboveOne = value => + if (value > 1) { + Nullable.make(value + 1) + } else { + Nullable.null + } + +Nullable.flatMap(Nullable.make(2), addIfAboveOne) // Nullable.make(3) +Nullable.flatMap(Nullable.make(-4), addIfAboveOne) // undefined +Nullable.flatMap(Nullable.null, addIfAboveOne) // undefined +``` +*/ +let flatMap: (t<'a>, 'a => t<'b>) => t<'b> diff --git a/runtime/Object.res b/runtime/Object.res new file mode 100644 index 0000000000..434621df86 --- /dev/null +++ b/runtime/Object.res @@ -0,0 +1,281 @@ +/** +`make` create a new object that inherits the properties and methods from the standard built-in Object, such as `toString`. See [Object on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object) + +## Examples + +```rescript +let x = Object.make() +x->Object.keysToArray->Array.length // 0 +x->Object.get("toString")->Option.isSome // true +``` +*/ +@obj +external make: unit => {..} = "" + +/** +`is` determines if two objects are identical in all contexts. Objects, arrays, records, and other non-primitives are only identical if they reference the **exact** same object in memory. Primitives like ints, floats, and strings are identical if they have the same value. `+0` and `-0` are distinct. NaN is equal to itself. See [Object.is on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is) + +In most scenarios use `==` or `===` or the custom `equals` function (if provided) for the type. + +## Examples + +```rescript +Object.is(25, 13) // false +Object.is("abc", "abc") // true +Object.is(undefined, undefined) // true +Object.is(undefined, null) // false +Object.is(-0.0, 0.0) // false +Object.is(list{1, 2}, list{1, 2}) // false + +Object.is([1, 2, 3], [1, 2, 3]) // false +[1, 2, 3] == [1, 2, 3] // true +[1, 2, 3] === [1, 2, 3] // false + +let fruit = {"name": "Apple" } +Object.is(fruit, fruit) // true +Object.is(fruit, {"name": "Apple" }) // false +fruit == {"name": "Apple" } // true +fruit === {"name": "Apple" } // false +``` +*/ +@val +external is: ('a, 'a) => bool = "Object.is" + +/** +`create` creates a new object, using an existing object as the prototype of the new object. See [Object.create on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create) + +**Note:** ReScript provides [first-class support for immutable objects](https://rescript-lang.org/docs/manual/latest/object) and [records](https://rescript-lang.org/docs/manual/latest/record). This is often safer and more convenient than using `create` and other functions in this module. + +## Examples + +```rescript +let x = {"fruit": "banana"} +let y = Object.create(x) +y->Object.get("fruit") // Some("banana") +``` +*/ +@val +external create: {..} => {..} = "Object.create" + +@val external createWithProperties: ({..}, {..}) => {..} = "Object.create" + +@val external createWithNull: (@as(json`null`) _, unit) => {..} = "Object.create" + +@val external createWithNullAndProperties: (@as(json`null`) _, {..}) => {..} = "Object.create" + +/** +`assign(target, source)` copies enumerable own properties from the source to the target, overwriting properties with the same name. It returns the modified target object. A deep clone is not created; properties are copied by reference. + +**Warning:** ReScript provides compile-time support for type-safe access to JavaScript objects. This eliminates common errors such as accessing properties that do not exist, or using a property of type x as if it were a y. Using `assign` can bypass these safety checks and lead to run-time errors (if you are not careful). ReScript provides [first-class support for immutable objects](https://rescript-lang.org/docs/manual/latest/object) and [records](https://rescript-lang.org/docs/manual/latest/record). This is often safer and more convenient than using `assign` and other functions in this module. + +See [Object.assign on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign) or [ECMAScript Language Specification](https://tc39.es/ecma262/multipage/fundamental-objects.html#sec-object.assign). + +## Examples + +```rescript +Object.assign({"a": 1}, {"a": 2}) // {"a": 2} +Object.assign({"a": 1, "b": 2}, {"a": 0}) // {"a": 0, "b": 2} +Object.assign({"a": 1}, {"a": null}) // {"a": null} +``` +*/ +@val +external assign: ({..}, {..}) => {..} = "Object.assign" + +/** +`assignMany(target, sources)` copies enumerable own properties from each source to the target, overwriting properties with the same name. Later sources' properties overwrite earlier ones. It returns the modified target object. A deep clone is not created; properties are copied by reference. + +**Note:** ReScript provides [first-class support for immutable objects](https://rescript-lang.org/docs/manual/latest/object), including spreading one object into another. This is often more convenient than using `assign` or `assignMany`. + +See [Object.assign on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign) or [ECMAScript Language Specification](https://tc39.es/ecma262/multipage/fundamental-objects.html#sec-object.assign). +*/ +@variadic +@val +external assignMany: ({..}, array<{..}>) => {..} = "Object.assign" + +@val external copy: (@as(json`{}`) _, {..} as 'a) => 'a = "Object.assign" + +/** +`get` gets the value of a property by name. Returns `None` if the property does not exist or has the value `undefined`. Otherwise returns `Some`, including if the value is `null`. + +## Examples + +```rescript +{"a": 1}->Object.get("a") // Some(1) +{"a": 1}->Object.get("b") // None +{"a": undefined}->Object.get("a") // None +{"a": null}->Object.get("a") // Some(null) +{"a": 1}->Object.get("toString")->Option.isSome // true +``` +*/ +@get_index +external get: ({..}, string) => option<'a> = "" + +/** +`getSymbol` gets the value of a property by symbol. Returns `None` if the property does not exist or has the value `undefined`. Otherwise returns `Some`, including if the value is `null`. + +## Examples + +```rescript +let fruit = Symbol.make("fruit") +let x = Object.make() +x->Object.setSymbol(fruit, "banana") +x->Object.getSymbol(fruit) // Some("banana") +``` +*/ +@get_index +external getSymbol: ({..}, Symbol.t) => option<'a> = "" + +@get_index external getSymbolUnsafe: ({..}, Symbol.t) => 'a = "" + +/** +`set(name, value)` assigns a value to the named object property, overwriting the previous value if any. See [Working with Objects on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Working_with_Objects#objects_and_properties) + +## Examples + +```rescript +{"a": 1}->Object.set("a", 2) // {"a": 2} +{"a": 1}->Object.set("a", None) // {"a": None} +{"a": 1}->Object.set("b", 2) // {"a": 1, "b": 2} +``` +*/ +@set_index +external set: ({..}, string, 'a) => unit = "" + +@set_index external setSymbol: ({..}, Symbol.t, 'a) => unit = "" + +/** +`keysToArray` returns an array of an object's own enumerable string-keyed property names. See [ECMAScript Language Specification](https://tc39.es/ecma262/multipage/fundamental-objects.html#sec-object.keys) +or [Object.keys on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys). + +## Examples + +```rescript +{"a": 1, "b": 2}->Object.keysToArray // ["a", "b"] +{"a": None}->Object.keysToArray // ["a"] +Object.make()->Object.keysToArray // [] +``` +*/ +@val +external keysToArray: {..} => array = "Object.keys" + +/** +`hasOwnProperty` determines whether the object has the specified property as its **own** property, as opposed to inheriting it. See [hasOwnProperty on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/hasOwnProperty) + +## Examples + +```rescript +let point = {"x": 1, "y": 2} +{"a": 1}->Object.hasOwnProperty("a") // true +{"a": 1}->Object.hasOwnProperty("b") // false +{"a": 1}->Object.hasOwnProperty("toString") // false +``` +*/ +@val +external hasOwnProperty: ({..}, string) => bool = "Object.prototype.hasOwnProperty.call" + +/** +`seal` seals an object. Sealing an object prevents extensions and makes existing properties non-configurable. A sealed object has a fixed set of properties. Unlike `freeze`, values of existing properties can still be changed as long as they are writable. + +**Note:** `seal` returns the same object that was passed in; it does not create a copy. Any attempt to delete or add properties to a sealed object will fail, either silently or by throwing an error. + +See [ECMAScript Language Specification](https://tc39.es/ecma262/multipage/fundamental-objects.html#sec-object.seal) and [Object.seal on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/seal) + +## Examples + +```rescript +let point = {"x": 1, "y": 2} +point->Object.set("x", -7) // succeeds +point->Object.seal->ignore +point->Object.set("z", 9) // fails +point->Object.set("x", 13) // succeeds +``` +*/ +@val +external seal: ({..} as 'a) => 'a = "Object.seal" + +/** +`preventExtensions` prevents new properties from being added to the object. It modifies the object (rather than creating a copy) and returns it. + +See [ECMAScript Language Specification](https://tc39.es/ecma262/multipage/fundamental-objects.html#sec-object.preventextensions) and [Object.preventExtensions on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/preventExtensions) + +## Examples + +```rescript +let obj = {"a": 1} +obj->Object.set("b", 2) // succeeds +obj->Object.preventExtensions->ignore +obj->Object.set("c", 3) // fails +``` +*/ +@val +external preventExtensions: ({..} as 'a) => 'a = "Object.preventExtensions" + +/** +`freeze` freezes an object. Freezing an object makes existing properties non-writable and prevents extensions. Once an object is frozen, new properties cannot be be added, existing properties cannot be removed, and their values cannot be changed. + +**Note:** `freeze` returns the same object that was passed in; it does not create a frozen copy. Any attempt to change a frozen object will fail, either silently or by throwing an exception. + +See [ECMAScript Language Specification](https://tc39.es/ecma262/multipage/fundamental-objects.html#sec-object.isfrozen) and [Object.isFrozen on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/isFrozen). + +## Examples + + ```rescript +let obj = {"a": 1} +obj->Object.set("a", 2) // succeeds +obj->Object.freeze->ignore +obj->Object.set("a", 3) // fails +``` +*/ +@val +external freeze: ({..} as 'a) => 'a = "Object.freeze" + +/** +`isSealed` determines if an object is sealed. A sealed object has a fixed set of properties. + +See [ECMAScript Language Specification](https://tc39.es/ecma262/multipage/fundamental-objects.html#sec-object.issealed) and [Object.isSealed on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/isSealed) + +## Examples + +```rescript +let point = {"x": 1, "y": 3}->Object.seal +let pointIsSealed = point->Object.isSealed // true +let fruit = {"name": "Apple" } +let fruitIsSealed = fruit->Object.isSealed // false + ``` +*/ +@val +external isSealed: 'a => bool = "Object.isSealed" + +/** +`isFrozen` determines if an object is frozen. An object is frozen if an only if it is not extensible, all its properties are non-configurable, and all its data properties are non-writable. + +See [ECMAScript Language Specification](https://tc39.es/ecma262/multipage/fundamental-objects.html#sec-object.isfrozen) and [Object.isFrozen on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/isFrozen). + +## Examples + +```rescript +let point = {"x": 1, "y": 3}->Object.freeze +let pointIsFrozen = point->Object.isFrozen // true +let fruit = {"name": "Apple" } +let fruitIsFrozen = fruit->Object.isFrozen // false + ``` +*/ +@val +external isFrozen: 'a => bool = "Object.isFrozen" + +/** +`isExtensible` determines if an object is extensible (whether it can have new properties added to it). + +See [ECMAScript Language Specification](https://tc39.es/ecma262/multipage/fundamental-objects.html#sec-object.isextensible) and [Object.isExtensible on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/isExtensible) + +## Examples + +```rescript +let obj = {"a": 1} +obj->Object.isExtensible // true +obj->Object.preventExtensions->ignore +obj->Object.isExtensible // false +``` +*/ +@val +external isExtensible: 'a => bool = "Object.isExtensible" diff --git a/runtime/Option.res b/runtime/Option.res new file mode 100644 index 0000000000..4fcc8cfbb2 --- /dev/null +++ b/runtime/Option.res @@ -0,0 +1,106 @@ +/* Copyright (C) 2017 Hongbo Zhang, Authors of ReScript + * + * 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 filter = (opt, p) => + switch opt { + | Some(x) as option if p(x) => option + | _ => None + } + +let forEach = (opt, f) => + switch opt { + | Some(x) => f(x) + | None => () + } + +let getExn = (x, ~message=?) => + switch x { + | Some(x) => x + | None => + Error.panic( + switch message { + | None => "Option.getExn called for None value" + | Some(message) => message + }, + ) + } + +external getUnsafe: option<'a> => 'a = "%identity" + +let mapOr = (opt, default, f) => + switch opt { + | Some(x) => f(x) + | None => default + } + +let mapWithDefault = mapOr + +let map = (opt, f) => + switch opt { + | Some(x) => Some(f(x)) + | None => None + } + +let flatMap = (opt, f) => + switch opt { + | Some(x) => f(x) + | None => None + } + +let getOr = (opt, default) => + switch opt { + | Some(x) => x + | None => default + } + +let getWithDefault = getOr + +let orElse = (opt, other) => + switch opt { + | Some(_) as some => some + | None => other + } + +let isSome = x => + switch x { + | Some(_) => true + | None => false + } + +let isNone = x => x == None + +let equal = (a, b, eq) => + switch (a, b) { + | (Some(a), Some(b)) => eq(a, b) + | (None, None) => true + | (None, Some(_)) | (Some(_), None) => false + } + +let compare = (a, b, cmp) => + switch (a, b) { + | (Some(a), Some(b)) => cmp(a, b) + | (None, Some(_)) => Ordering.less + | (Some(_), None) => Ordering.greater + | (None, None) => Ordering.equal + } diff --git a/runtime/Option.resi b/runtime/Option.resi new file mode 100644 index 0000000000..16efdba52c --- /dev/null +++ b/runtime/Option.resi @@ -0,0 +1,255 @@ +/* Copyright (C) 2017 Authors of ReScript + * + * 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. */ + +/*** +We represent the existence and nonexistence of a value by wrapping it with +the `option` type. In order to make it a bit more convenient to work with +option-types, we provide utility-functions for it. + +The `option` type is a part of the ReScript standard library which is defined +like this: + +```rescript +type option<'a> = None | Some('a) +``` + +```rescript +let someString: option = Some("hello") +``` +*/ + +/** +`filter(opt, f)` applies `f` to `opt`, if `f` returns `true`, then it returns `Some(value)`, otherwise returns `None`. + +## Examples + +```rescript +Option.filter(Some(10), x => x > 5) // Some(10) +Option.filter(Some(4), x => x > 5) // None +Option.filter(None, x => x > 5) // None +``` +*/ +let filter: (option<'a>, 'a => bool) => option<'a> + +/** +`forEach(opt, f)` call `f` on `opt`. if `opt` is `Some(value)`, then if calls +`f`, otherwise returns `unit`. + +## Examples + +```rescript +Option.forEach(Some("thing"), x => Console.log(x)) // logs "thing" +Option.forEach(None, x => Console.log(x)) // returns () +``` +*/ +let forEach: (option<'a>, 'a => unit) => unit + +/** +`getExn(opt, ~message=?)` returns `value` if `opt` is `Some(value)`, otherwise raises an exception with the message provided, or a generic message if no message was provided. + +```rescript +Option.getExn(Some(3)) // 3 +Option.getExn(None) /* Raises an Error */ +Option.getExn(None, ~message="was None!") /* Raises an Error with the message "was None!" */ +``` + +## Exceptions + +- Raises an error if `opt` is `None` +*/ +let getExn: (option<'a>, ~message: string=?) => 'a + +/** +`getUnsafe(opt)` returns `value` if `opt` is `Some(value)`, otherwise `undefined`. + +## Examples + +```rescript +Option.getUnsafe(Some(3)) == 3 +Option.getUnsafe(None: option) // Returns `undefined`, which is not a valid `int` +``` + +## Notes + +- This is an unsafe operation. It assumes `value` is not `None`, and may cause undefined behaviour if it is. +*/ +external getUnsafe: option<'a> => 'a = "%identity" + +/** +`mapOr(opt, default, f)` returns `f(value)` if `opt` is `Some(value)`, otherwise `default`. + +## Examples + +```rescript +let someValue = Some(3) +someValue->Option.mapOr(0, x => x + 5) // 8 + +let noneValue = None +noneValue->Option.mapOr(0, x => x + 5) // 0 +``` +*/ +let mapOr: (option<'a>, 'b, 'a => 'b) => 'b + +@deprecated("Use mapOr instead") +let mapWithDefault: (option<'a>, 'b, 'a => 'b) => 'b + +/** +`map(opt, f)` returns `Some(f(value))` if `opt` is `Some(value)`, otherwise `None`. + +## Examples + +```rescript +Option.map(Some(3), x => x * x) // Some(9) +Option.map(None, x => x * x) // None +``` +*/ +let map: (option<'a>, 'a => 'b) => option<'b> + +/** +`flatMap(opt, f)` returns `f(value)` if `opt` is `Some(value)`, otherwise `None`. + +## Examples + +```rescript +let addIfAboveOne = value => + if (value > 1) { + Some(value + 1) + } else { + None + } + +Option.flatMap(Some(2), addIfAboveOne) // Some(3) +Option.flatMap(Some(-4), addIfAboveOne) // None +Option.flatMap(None, addIfAboveOne) // None +``` +*/ +let flatMap: (option<'a>, 'a => option<'b>) => option<'b> + +/** +`getOr(opt, default)` returns `value` if `opt` is `Some(value)`, otherwise `default`. + +## Examples + +```rescript +Option.getOr(None, "Banana") // Banana +Option.getOr(Some("Apple"), "Banana") // Apple + +let greet = (firstName: option) => + "Greetings " ++ firstName->Option.getOr("Anonymous") + +Some("Jane")->greet // "Greetings Jane" +None->greet // "Greetings Anonymous" +``` +*/ +let getOr: (option<'a>, 'a) => 'a + +@deprecated("Use getOr instead") +let getWithDefault: (option<'a>, 'a) => 'a + +/** +`orElse(opt1, opt2)` returns `opt2` if `opt1` is `None`, otherwise `opt1`. + +## Examples + +```rescript +Option.orElse(Some(1812), Some(1066)) == Some(1812) +Option.orElse(None, Some(1066)) == Some(1066) +Option.orElse(None, None) == None +``` +*/ +let orElse: (option<'a>, option<'a>) => option<'a> + +/** +`isSome(opt)` returns `true` if `opt` is `Some(value)`, otherwise returns `false`. + +## Examples + +```rescript +Option.isSome(None) // false +Option.isSome(Some(1)) // true +``` +*/ +let isSome: option<'a> => bool + +/** +`isNone(opt)` returns `true` if `opt` is `None`, false otherwise. + +## Examples + +```rescript +Option.isNone(None) // true +Option.isNone(Some(1)) // false +``` +*/ +let isNone: option<'a> => bool + +/** +`equal(opt1, opt2, f)` evaluates two optional values for equality with respect to a predicate function `f`. If both `opt1` and `opt2` are `None`, returns `true`. +If one of the arguments is `Some(value)` and the other is `None`, returns +`false`. +If arguments are `Some(value1)` and `Some(value2)`, returns the result of +`f(value1, value2)`, the predicate function `f` must return a bool. + +## Examples + +```rescript +let clockEqual = (a, b) => mod(a, 12) == mod(b, 12) + +open Option + +equal(Some(3), Some(15), clockEqual) // true +equal(Some(3), None, clockEqual) // false +equal(None, Some(3), clockEqual) // false +equal(None, None, clockEqual) // true +``` +*/ +let equal: (option<'a>, option<'b>, ('a, 'b) => bool) => bool + +/** +`compare(opt1, opt2, f)` compares two optional values with respect to given `f`. + +If both `opt1` and `opt2` are `None`, it returns `0.`. If the first argument is `Some(value1)` and the second is `None`, returns `1.` (something is greater than nothing). + +If the first argument is `None` and the second is `Some(value2)`, returns `-1.` +(nothing is less than something). + +If the arguments are `Some(value1)` and `Some(value2)`, returns the result of +`f(value1, value2)`, `f` takes two arguments and returns `-1.` if the first +argument is less than the second, `0.` if the arguments are equal, and `1.` if +the first argument is greater than the second. + +## Examples + +```rescript +let clockCompare = (a, b) => Int.compare(mod(a, 12), mod(b, 12)) + +Option.compare(Some(3), Some(15), clockCompare) // 0. +Option.compare(Some(3), Some(14), clockCompare) // 1. +Option.compare(Some(2), Some(15), clockCompare) // (-1.) +Option.compare(None, Some(15), clockCompare) // (-1.) +Option.compare(Some(14), None, clockCompare) // 1. +Option.compare(None, None, clockCompare) // 0. +``` +*/ +let compare: (option<'a>, option<'b>, ('a, 'b) => Ordering.t) => Ordering.t diff --git a/runtime/Ordering.res b/runtime/Ordering.res new file mode 100644 index 0000000000..c22a9ec4cb --- /dev/null +++ b/runtime/Ordering.res @@ -0,0 +1,13 @@ +type t = float + +@inline let less = -1. +@inline let equal = 0. +@inline let greater = 1. + +let isLess = ord => ord < equal +let isEqual = ord => ord == equal +let isGreater = ord => ord > equal + +let invert = ord => -.ord + +let fromInt = n => n < 0 ? less : n > 0 ? greater : equal diff --git a/runtime/Pervasives.res b/runtime/Pervasives.res index 603d2d811a..d8873a1f13 100644 --- a/runtime/Pervasives.res +++ b/runtime/Pervasives.res @@ -6,313 +6,555 @@ If the type exported here is also exported in modules from others, you will get a type not equivalent. */ -module Pervasives = { - /* Internal */ - @deprecated("Do not use. This will be removed in v13") - external __unsafe_cast: 'a => 'b = "%identity" +@deprecated("Do not use. This will be removed in v13") +external /* Internal */ - /* Exceptions */ +__unsafe_cast: 'a => 'b = "%identity" - external raise: exn => 'a = "%raise" +/* Exceptions */ - @deprecated("Use custom exception instead") - let failwith = s => raise(Failure(s)) +external raise: exn => 'a = "%raise" - @deprecated("Use custom exception instead") - let invalid_arg = s => raise(Invalid_argument(s)) +@deprecated("Use custom exception instead") +let failwith = s => raise(Failure(s)) - @deprecated("Use custom exception instead") exception Exit +@deprecated("Use custom exception instead") +let invalid_arg = s => raise(Invalid_argument(s)) - /* Composition operators */ +@deprecated("Use custom exception instead") exception Exit - external \"|>": ('a, 'a => 'b) => 'b = "%revapply" - external \"@@": ('a => 'b, 'a) => 'b = "%apply" +/* Composition operators */ - /* Debugging */ +external \"|>": ('a, 'a => 'b) => 'b = "%revapply" +external \"@@": ('a => 'b, 'a) => 'b = "%apply" - external __LOC__: string = "%loc_LOC" - external __FILE__: string = "%loc_FILE" - external __LINE__: int = "%loc_LINE" - external __MODULE__: string = "%loc_MODULE" - external __POS__: (string, int, int, int) = "%loc_POS" +/* Debugging */ - external __LOC_OF__: 'a => (string, 'a) = "%loc_LOC" - external __LINE_OF__: 'a => (int, 'a) = "%loc_LINE" - external __POS_OF__: 'a => ((string, int, int, int), 'a) = "%loc_POS" +external __LOC__: string = "%loc_LOC" +external __FILE__: string = "%loc_FILE" +external __LINE__: int = "%loc_LINE" +external __MODULE__: string = "%loc_MODULE" +external __POS__: (string, int, int, int) = "%loc_POS" - /* Comparisons */ +external __LOC_OF__: 'a => (string, 'a) = "%loc_LOC" +external __LINE_OF__: 'a => (int, 'a) = "%loc_LINE" +external __POS_OF__: 'a => ((string, int, int, int), 'a) = "%loc_POS" - external \"=": ('a, 'a) => bool = "%equal" - external \"<>": ('a, 'a) => bool = "%notequal" - external \"<": ('a, 'a) => bool = "%lessthan" - external \">": ('a, 'a) => bool = "%greaterthan" - external \"<=": ('a, 'a) => bool = "%lessequal" - external \">=": ('a, 'a) => bool = "%greaterequal" - external compare: ('a, 'a) => int = "%compare" - external min: ('a, 'a) => 'a = "%min" - external max: ('a, 'a) => 'a = "%max" - external \"==": ('a, 'a) => bool = "%eq" - external \"!=": ('a, 'a) => bool = "%noteq" +/* Comparisons */ - /* Boolean operations */ +external \"=": ('a, 'a) => bool = "%equal" +external \"<>": ('a, 'a) => bool = "%notequal" +external \"<": ('a, 'a) => bool = "%lessthan" +external \">": ('a, 'a) => bool = "%greaterthan" +external \"<=": ('a, 'a) => bool = "%lessequal" +external \">=": ('a, 'a) => bool = "%greaterequal" +external compare: ('a, 'a) => int = "%compare" +external min: ('a, 'a) => 'a = "%min" +external max: ('a, 'a) => 'a = "%max" +external \"==": ('a, 'a) => bool = "%eq" +external \"!=": ('a, 'a) => bool = "%noteq" - external not: bool => bool = "%boolnot" +/* Boolean operations */ - external \"&&": (bool, bool) => bool = "%sequand" +external not: bool => bool = "%boolnot" - external \"||": (bool, bool) => bool = "%sequor" +external \"&&": (bool, bool) => bool = "%sequand" - /* Integer operations */ +external \"||": (bool, bool) => bool = "%sequor" - external \"~-": int => int = "%negint" - external \"~+": int => int = "%identity" - external succ: int => int = "%succint" - external pred: int => int = "%predint" - external \"+": (int, int) => int = "%addint" - external \"-": (int, int) => int = "%subint" - external \"*": (int, int) => int = "%mulint" - external \"/": (int, int) => int = "%divint" - external mod: (int, int) => int = "%modint" +/* Integer operations */ - @deprecated("Use Core instead. This will be removed in v13") - let abs = x => - if x >= 0 { - x - } else { - -x - } +external \"~-": int => int = "%negint" +external \"~+": int => int = "%identity" +external succ: int => int = "%succint" +external pred: int => int = "%predint" +external \"+": (int, int) => int = "%addint" +external \"-": (int, int) => int = "%subint" +external \"*": (int, int) => int = "%mulint" +external \"/": (int, int) => int = "%divint" +external mod: (int, int) => int = "%modint" + +@deprecated("Use Core instead. This will be removed in v13") +let abs = x => + if x >= 0 { + x + } else { + -x + } - external land: (int, int) => int = "%andint" - external lor: (int, int) => int = "%orint" - external lxor: (int, int) => int = "%xorint" +external land: (int, int) => int = "%andint" +external lor: (int, int) => int = "%orint" +external lxor: (int, int) => int = "%xorint" - let lnot = x => lxor(x, -1) +let lnot = x => lxor(x, -1) - external lsl: (int, int) => int = "%lslint" - external lsr: (int, int) => int = "%lsrint" - external asr: (int, int) => int = "%asrint" +external lsl: (int, int) => int = "%lslint" +external lsr: (int, int) => int = "%lsrint" +external asr: (int, int) => int = "%asrint" - @deprecated("Use Core instead. This will be removed in v13") - let max_int = lsr(-1, 1) +@deprecated("Use Core instead. This will be removed in v13") +let max_int = lsr(-1, 1) - @deprecated("Use Core instead. This will be removed in v13") - let min_int = - max_int + 1 +@deprecated("Use Core instead. This will be removed in v13") +let min_int = + max_int + 1 - /* Floating-point operations */ +/* Floating-point operations */ - external \"~-.": float => float = "%negfloat" - external \"~+.": float => float = "%identity" - external \"+.": (float, float) => float = "%addfloat" - external \"-.": (float, float) => float = "%subfloat" - external \"*.": (float, float) => float = "%mulfloat" - external \"/.": (float, float) => float = "%divfloat" +external \"~-.": float => float = "%negfloat" +external \"~+.": float => float = "%identity" +external \"+.": (float, float) => float = "%addfloat" +external \"-.": (float, float) => float = "%subfloat" +external \"*.": (float, float) => float = "%mulfloat" +external \"/.": (float, float) => float = "%divfloat" - @deprecated("Use Core instead. This will be removed in v13") @val @scope("Math") - external \"**": (float, float) => float = "pow" +@deprecated("Use Core instead. This will be removed in v13") @val @scope("Math") +external \"**": (float, float) => float = "pow" - @deprecated("Use Core instead. This will be removed in v13") @val @scope("Math") - external exp: float => float = "exp" +@deprecated("Use Core instead. This will be removed in v13") @val @scope("Math") +external exp: float => float = "exp" - @deprecated("Use Core instead. This will be removed in v13") @val @scope("Math") - external acos: float => float = "acos" +@deprecated("Use Core instead. This will be removed in v13") @val @scope("Math") +external acos: float => float = "acos" - @deprecated("Use Core instead. This will be removed in v13") @val @scope("Math") - external asin: float => float = "asin" +@deprecated("Use Core instead. This will be removed in v13") @val @scope("Math") +external asin: float => float = "asin" - @deprecated("Use Core instead. This will be removed in v13") @val @scope("Math") - external atan: float => float = "atan" +@deprecated("Use Core instead. This will be removed in v13") @val @scope("Math") +external atan: float => float = "atan" - @deprecated("Use Core instead. This will be removed in v13") @val @scope("Math") - external atan2: (float, float) => float = "atan2" +@deprecated("Use Core instead. This will be removed in v13") @val @scope("Math") +external atan2: (float, float) => float = "atan2" - @deprecated("Use Core instead. This will be removed in v13") @val @scope("Math") - external cos: float => float = "cos" +@deprecated("Use Core instead. This will be removed in v13") @val @scope("Math") +external cos: float => float = "cos" - @deprecated("Use Core instead. This will be removed in v13") @val @scope("Math") - external cosh: float => float = "cosh" +@deprecated("Use Core instead. This will be removed in v13") @val @scope("Math") +external cosh: float => float = "cosh" - @deprecated("Use Core instead. This will be removed in v13") @val @scope("Math") - external log: float => float = "log" +@deprecated("Use Core instead. This will be removed in v13") @val @scope("Math") +external log: float => float = "log" - @deprecated("Use Core instead. This will be removed in v13") @val @scope("Math") - external log10: float => float = "log10" +@deprecated("Use Core instead. This will be removed in v13") @val @scope("Math") +external log10: float => float = "log10" - @deprecated("Use Core instead. This will be removed in v13") @val @scope("Math") - external log1p: float => float = "log1p" +@deprecated("Use Core instead. This will be removed in v13") @val @scope("Math") +external log1p: float => float = "log1p" - @deprecated("Use Core instead. This will be removed in v13") @val @scope("Math") - external sin: float => float = "sin" +@deprecated("Use Core instead. This will be removed in v13") @val @scope("Math") +external sin: float => float = "sin" - @deprecated("Use Core instead. This will be removed in v13") @val @scope("Math") - external sinh: float => float = "sinh" +@deprecated("Use Core instead. This will be removed in v13") @val @scope("Math") +external sinh: float => float = "sinh" - @deprecated("Use Core instead. This will be removed in v13") @val @scope("Math") - external sqrt: float => float = "sqrt" +@deprecated("Use Core instead. This will be removed in v13") @val @scope("Math") +external sqrt: float => float = "sqrt" - @deprecated("Use Core instead. This will be removed in v13") @val @scope("Math") - external tan: float => float = "tan" +@deprecated("Use Core instead. This will be removed in v13") @val @scope("Math") +external tan: float => float = "tan" - @deprecated("Use Core instead. This will be removed in v13") @val @scope("Math") - external tanh: float => float = "tanh" +@deprecated("Use Core instead. This will be removed in v13") @val @scope("Math") +external tanh: float => float = "tanh" - @deprecated("Use Core instead. This will be removed in v13") @val @scope("Math") - external ceil: float => float = "ceil" +@deprecated("Use Core instead. This will be removed in v13") @val @scope("Math") +external ceil: float => float = "ceil" - @deprecated("Use Core instead. This will be removed in v13") @val @scope("Math") - external floor: float => float = "floor" +@deprecated("Use Core instead. This will be removed in v13") @val @scope("Math") +external floor: float => float = "floor" - @deprecated("Use Core instead. This will be removed in v13") @val @scope("Math") - external abs_float: float => float = "abs" +@deprecated("Use Core instead. This will be removed in v13") @val @scope("Math") +external abs_float: float => float = "abs" - @deprecated("Use Core instead. This will be removed in v13") - external mod_float: float => float = "%modfloat" +@deprecated("Use Core instead. This will be removed in v13") +external mod_float: float => float = "%modfloat" - @deprecated("Use Core instead. This will be removed in v13") - external float: int => float = "%floatofint" +@deprecated("Use Core instead. This will be removed in v13") +external float: int => float = "%floatofint" - @deprecated("Use Core instead. This will be removed in v13") - external float_of_int: int => float = "%floatofint" +@deprecated("Use Core instead. This will be removed in v13") +external float_of_int: int => float = "%floatofint" - @deprecated("Use Core instead. This will be removed in v13") - external truncate: float => int = "%intoffloat" +@deprecated("Use Core instead. This will be removed in v13") +external truncate: float => int = "%intoffloat" - @deprecated("Use Core instead. This will be removed in v13") - external int_of_float: float => int = "%intoffloat" +@deprecated("Use Core instead. This will be removed in v13") +external int_of_float: float => int = "%intoffloat" - @deprecated("Use Core instead. This will be removed in v13") - let infinity = 0x1p2047 +@deprecated("Use Core instead. This will be removed in v13") +let infinity = 0x1p2047 - @deprecated("Use Core instead. This will be removed in v13") - let neg_infinity = -0x1p2047 +@deprecated("Use Core instead. This will be removed in v13") +let neg_infinity = -0x1p2047 - @deprecated("Use Core instead. This will be removed in v13") @val @scope("Number") - external nan: float = "NaN" +@deprecated("Use Core instead. This will be removed in v13") @val @scope("Number") +external nan: float = "NaN" - @deprecated("Use Core instead. This will be removed in v13") - let max_float = 1.79769313486231571e+308 /* 0x1.ffff_ffff_ffff_fp+1023 */ +@deprecated("Use Core instead. This will be removed in v13") +let max_float = 1.79769313486231571e+308 /* 0x1.ffff_ffff_ffff_fp+1023 */ - @deprecated("Use Core instead. This will be removed in v13") - let min_float = 2.22507385850720138e-308 /* 0x1p-1022 */ +@deprecated("Use Core instead. This will be removed in v13") +let min_float = 2.22507385850720138e-308 /* 0x1p-1022 */ - @deprecated("Use Core instead. This will be removed in v13") - let epsilon_float = 2.22044604925031308e-16 /* 0x1p-52 */ +@deprecated("Use Core instead. This will be removed in v13") +let epsilon_float = 2.22044604925031308e-16 /* 0x1p-52 */ - @deprecated("Do not use. This will be removed in v13") - type fpclass = - | FP_normal - | FP_subnormal - | FP_zero - | FP_infinite - | FP_nan +@deprecated("Do not use. This will be removed in v13") +type fpclass = + | FP_normal + | FP_subnormal + | FP_zero + | FP_infinite + | FP_nan - @deprecated("Do not use. This will be removed in v13") - let classify_float = (x: float): fpclass => - if (%raw(`isFinite`): _ => _)(x) { - if abs_float(x) >= /* 0x1p-1022 */ /* 2.22507385850720138e-308 */ min_float { - FP_normal - } else if x != 0. { - FP_subnormal - } else { - FP_zero - } - } else if (%raw(`isNaN`): _ => _)(x) { - FP_nan +@deprecated("Do not use. This will be removed in v13") +let classify_float = (x: float): fpclass => + if (%raw(`isFinite`): _ => _)(x) { + if abs_float(x) >= /* 0x1p-1022 */ /* 2.22507385850720138e-308 */ min_float { + FP_normal + } else if x != 0. { + FP_subnormal } else { - FP_infinite + FP_zero } + } else if (%raw(`isNaN`): _ => _)(x) { + FP_nan + } else { + FP_infinite + } - /* String and byte sequence operations -- more in modules String and Bytes */ +/* String and byte sequence operations -- more in modules String and Bytes */ - external \"^": (string, string) => string = "%string_concat" +external \"^": (string, string) => string = "%string_concat" - /* Character operations -- more in module Char */ +/* Character operations -- more in module Char */ - @deprecated("Use Core instead. This will be removed in v13") - external int_of_char: char => int = "%identity" +@deprecated("Use Core instead. This will be removed in v13") +external int_of_char: char => int = "%identity" - @deprecated("Use Core instead. This will be removed in v13") - external unsafe_char_of_int: int => char = "%identity" +@deprecated("Use Core instead. This will be removed in v13") +external unsafe_char_of_int: int => char = "%identity" - @deprecated("Use Core instead. This will be removed in v13") - let char_of_int = n => - if n < 0 || n > 255 { - invalid_arg("char_of_int") - } else { - unsafe_char_of_int(n) - } +@deprecated("Use Core instead. This will be removed in v13") +let char_of_int = n => + if n < 0 || n > 255 { + invalid_arg("char_of_int") + } else { + unsafe_char_of_int(n) + } - /* Unit operations */ +/* Unit operations */ - external ignore: 'a => unit = "%ignore" +external ignore: 'a => unit = "%ignore" - /* Pair operations */ +/* Pair operations */ - external fst: (('a, 'b)) => 'a = "%field0" - external snd: (('a, 'b)) => 'b = "%field1" +external fst: (('a, 'b)) => 'a = "%field0" +external snd: (('a, 'b)) => 'b = "%field1" - /* References */ +/* References */ - type ref<'a> = {mutable contents: 'a} - external ref: 'a => ref<'a> = "%makeref" - external \"!": ref<'a> => 'a = "%refget" - external \":=": (ref<'a>, 'a) => unit = "%refset" - external incr: ref => unit = "%incr" - external decr: ref => unit = "%decr" +type ref<'a> = {mutable contents: 'a} +external ref: 'a => ref<'a> = "%makeref" +external \"!": ref<'a> => 'a = "%refget" +external \":=": (ref<'a>, 'a) => unit = "%refset" +external incr: ref => unit = "%incr" +external decr: ref => unit = "%decr" - /* String conversion functions */ +/* String conversion functions */ - @deprecated("Use Core instead. This will be removed in v13") - let string_of_bool = b => - if b { - "true" - } else { - "false" - } +@deprecated("Use Core instead. This will be removed in v13") +let string_of_bool = b => + if b { + "true" + } else { + "false" + } - @deprecated("Use Core instead. This will be removed in v13") - let bool_of_string = param => - switch param { - | "true" => true - | "false" => false - | _ => invalid_arg("bool_of_string") - } +@deprecated("Use Core instead. This will be removed in v13") +let bool_of_string = param => + switch param { + | "true" => true + | "false" => false + | _ => invalid_arg("bool_of_string") + } - @deprecated("Use Core instead. This will be removed in v13") - let bool_of_string_opt = param => - switch param { - | "true" => Some(true) - | "false" => Some(false) - | _ => None - } +@deprecated("Use Core instead. This will be removed in v13") +let bool_of_string_opt = param => + switch param { + | "true" => Some(true) + | "false" => Some(false) + | _ => None + } - @deprecated("Use Core instead. This will be removed in v13") - external string_of_int: int => string = "String" +@deprecated("Use Core instead. This will be removed in v13") +external string_of_int: int => string = "String" - @deprecated("Use Core instead. This will be removed in v13") @scope("Number") - external int_of_string: string => int = "parseInt" +@deprecated("Use Core instead. This will be removed in v13") @scope("Number") +external int_of_string: string => int = "parseInt" - let int_of_string_opt = s => - switch int_of_string(s) { - | n if n == %raw("NaN") => None - | n => Some(n) - } +let int_of_string_opt = s => + switch int_of_string(s) { + | n if n == %raw("NaN") => None + | n => Some(n) + } - @deprecated("Use Core instead. This will be removed in v13") - external string_get: (string, int) => char = "%string_safe_get" +@deprecated("Use Core instead. This will be removed in v13") +external string_get: (string, int) => char = "%string_safe_get" - /* List operations -- more in module List */ +/* List operations -- more in module List */ - @deprecated("Use Core instead. This will be removed in v13") - let rec \"@" = (l1, l2) => - switch l1 { - | list{} => l2 - | list{hd, ...tl} => list{hd, ...\"@"(tl, l2)} - } +@deprecated("Use Core instead. This will be removed in v13") +let rec \"@" = (l1, l2) => + switch l1 { + | list{} => l2 + | list{hd, ...tl} => list{hd, ...\"@"(tl, l2)} + } + +/* Miscellaneous */ - /* Miscellaneous */ +type int32 = int + +/*** +Bindings to functions available in the global JavaScript scope. +*/ + +/** +An `id` representing a timeout started via `setTimeout`. + +See [`setTimeout`](https://developer.mozilla.org/en-US/docs/Web/API/setTimeout) on MDN. +*/ +type timeoutId = Js_global.timeoutId + +/** +`setTimeout(callback, durationInMilliseconds)` starts a timer that will execute `callback` after `durationInMilliseconds`. + +See [`setTimeout`](https://developer.mozilla.org/en-US/docs/Web/API/setTimeout) on MDN. + +## Examples +```rescript +// Log to the console after 2 seconds (2000 milliseconds). +let timeoutId = setTimeout(() => { + Console.log("This prints in 2 seconds.") +}, 2000) +``` +*/ +@val +external setTimeout: (unit => unit, int) => timeoutId = "setTimeout" - type int32 = int +/** +`setTimeoutFloat(callback, durationInMilliseconds)` starts a timer that will execute `callback` after `durationInMilliseconds`. + +The same as `setTimeout`, but allows you to pass a `float` instead of an `int` for the duration. + +See [`setTimeout`](https://developer.mozilla.org/en-US/docs/Web/API/setTimeout) on MDN. + +## Examples +```rescript +// Log to the console after 2 seconds (2000 milliseconds). +let timeoutId = setTimeoutFloat(() => { + Console.log("This prints in 2 seconds.") +}, 2000.) +``` +*/ +@val +external setTimeoutFloat: (unit => unit, float) => timeoutId = "setTimeout" + +/** +`clearTimeout(timeoutId)` clears a scheduled timeout if it hasn't already executed. + +See [`clearTimeout`](https://developer.mozilla.org/en-US/docs/Web/API/clearTimeout) on MDN. + +## Examples +```rescript +let timeoutId = setTimeout(() => { + Console.log("This prints in 2 seconds.") +}, 2000) + +// Clearing the timeout right away, before 2 seconds has passed, means that the above callback logging to the console will never run. +clearTimeout(timeoutId) +``` +*/ +@val +external clearTimeout: timeoutId => unit = "clearTimeout" + +/** +An `id` representing an interval started via `setInterval`. + +See [`setInterval`](https://developer.mozilla.org/en-US/docs/Web/API/setInterval) on MDN. +*/ +type intervalId = Js_global.intervalId + +/** +`setInterval(callback, intervalInMilliseconds)` starts an interval that will execute `callback` every `durationInMilliseconds` milliseconds. + +See [`setInterval`](https://developer.mozilla.org/en-US/docs/Web/API/setInterval) on MDN. + +## Examples +```rescript +// Log to the console ever 2 seconds (2000 milliseconds). +let intervalId = setInterval(() => { + Console.log("This prints every 2 seconds.") +}, 2000) +``` +*/ +@val +external setInterval: (unit => unit, int) => intervalId = "setInterval" + +/** +`setIntervalFloat(callback, intervalInMilliseconds)` starts an interval that will execute `callback` every `durationInMilliseconds` milliseconds. + +The same as `setInterval`, but allows you to pass a `float` instead of an `int` for the duration. + +See [`setInterval`](https://developer.mozilla.org/en-US/docs/Web/API/setInterval) on MDN. + +## Examples +```rescript +// Log to the console ever 2 seconds (2000 milliseconds). +let intervalId = setIntervalFloat(() => { + Console.log("This prints every 2 seconds.") +}, 2000.) +``` +*/ +@val +external setIntervalFloat: (unit => unit, float) => intervalId = "setInterval" + +/** +`clearInterval(intervalId)` clears a scheduled interval. + +See [`clearInterval`](https://developer.mozilla.org/en-US/docs/Web/API/clearInterval) on MDN. + +## Examples +```rescript +let intervalId = setInterval(() => { + Console.log("This prints in 2 seconds.") +}, 2000) + +// Stop the interval after 10 seconds +let timeoutId = setTimeout(() => { + clearInterval(intervalId) +}, 10000) +``` +*/ +@val +external clearInterval: intervalId => unit = "clearInterval" + +/** +Encodes a URI by replacing characters in the provided string that aren't valid in a URL. + +This is intended to operate on full URIs, so it encodes fewer characters than what `encodeURIComponent` does. +If you're looking to encode just parts of a URI, like a query parameter, prefer `encodeURIComponent`. + +See [`encodeURI`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURI) on MDN. + +## Examples +```rescript +Console.log(encodeURI("https://rescript-lang.org?array=[someValue]")) +// Logs "https://rescript-lang.org?array=%5BsomeValue%5D" to the console. +``` + +*/ +@val +external encodeURI: string => string = "encodeURI" + +/** +Decodes a previously encoded URI back to a regular string. + +This is intended to operate on full URIs, so it decodes fewer characters than what `decodeURIComponent` does. +If you're looking to decode just parts of a URI, like a query parameter, prefer `decodeURIComponent`. + +See [`decodeURI`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/decodeURI) on MDN. + +## Examples +```rescript +Console.log(decodeURI("https://rescript-lang.org?array=%5BsomeValue%5D")) +// Logs "https://rescript-lang.org?array=[someValue]" to the console. +``` +*/ +@val +external decodeURI: string => string = "decodeURI" + +/** +Encodes a string so it can be used as part of a URI. + +See [`encodeURIComponent`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent) on MDN. + +## Examples +```rescript +Console.log(encodeURIComponent("array=[someValue]")) +// Logs "array%3D%5BsomeValue%5D" to the console. +``` +*/ +@val +external encodeURIComponent: string => string = "encodeURIComponent" + +/** +Decodes a previously URI encoded string back to its original form. + +See [`decodeURIComponent`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/decodeURIComponent) on MDN. + +## Examples +```rescript +Console.log(decodeURIComponent("array%3D%5BsomeValue%5D")) +// Logs "array=[someValue]" to the console. +``` +*/ +@val +external decodeURIComponent: string => string = "decodeURIComponent" + +@val external window: Dom.window = "window" +@val external document: Dom.document = "document" +@val external globalThis: {..} = "globalThis" + +external null: Js.Nullable.t<'a> = "#null" +external undefined: Js.Nullable.t<'a> = "#undefined" +external typeof: 'a => Type.t = "#typeof" + +/** +`import(value)` dynamically import a value or function from a ReScript +module. The import call will return a `promise`, resolving to the dynamically loaded +value. + +## Examples + +`Array.res` file: + +```rescript +@send external indexOf: (array<'a>, 'a) => int = "indexOf" + +let indexOfOpt = (arr, item) => + switch arr->indexOf(item) { + | -1 => None + | index => Some(index) + } +``` +In other file you can import the `indexOfOpt` value defined in `Array.res` + +```rescript +let main = async () => { + let indexOfOpt = await import(Array.indexOfOpt) + let index = indexOfOpt([1, 2], 2) + Console.log(index) } +``` + +Compiles to: + +```javascript +async function main() { + var add = await import("./Array.mjs").then(function(m) { + return m.indexOfOpt; + }); + var index = indexOfOpt([1, 2], 2); + console.log(index); +} +``` +*/ +external import: 'a => promise<'a> = "#import" + +type null<+'a> = Js.null<'a> + +type undefined<+'a> = Js.undefined<'a> + +type nullable<+'a> = Js.nullable<'a> -include Pervasives +let panic = Error.panic diff --git a/runtime/Pervasives_mini.res b/runtime/Pervasives_mini.res new file mode 100644 index 0000000000..9c62e80ffe --- /dev/null +++ b/runtime/Pervasives_mini.res @@ -0,0 +1,79 @@ +/* Exceptions */ +external raise: exn => 'a = "%raise" + +/* Debugging */ + +external __LOC__: string = "%loc_LOC" +external __FILE__: string = "%loc_FILE" +external __LINE__: int = "%loc_LINE" +external __MODULE__: string = "%loc_MODULE" +external __POS__: (string, int, int, int) = "%loc_POS" + +external __LOC_OF__: 'a => (string, 'a) = "%loc_LOC" +external __LINE_OF__: 'a => (int, 'a) = "%loc_LINE" +external __POS_OF__: 'a => ((string, int, int, int), 'a) = "%loc_POS" + +/* Comparisons */ + +external \"=": ('a, 'a) => bool = "%equal" +external \"<>": ('a, 'a) => bool = "%notequal" +external \"<": ('a, 'a) => bool = "%lessthan" +external \">": ('a, 'a) => bool = "%greaterthan" +external \"<=": ('a, 'a) => bool = "%lessequal" +external \">=": ('a, 'a) => bool = "%greaterequal" +external compare: ('a, 'a) => int = "%compare" +external min: ('a, 'a) => 'a = "%min" +external max: ('a, 'a) => 'a = "%max" +external \"==": ('a, 'a) => bool = "%eq" +external \"!=": ('a, 'a) => bool = "%noteq" + +/* Boolean operations */ + +external not: bool => bool = "%boolnot" + +external \"&&": (bool, bool) => bool = "%sequand" + +external \"||": (bool, bool) => bool = "%sequor" + +/* Integer operations */ + +external \"~-": int => int = "%negint" +external \"~+": int => int = "%identity" +external succ: int => int = "%succint" +external pred: int => int = "%predint" +external \"+": (int, int) => int = "%addint" +external \"-": (int, int) => int = "%subint" +external \"*": (int, int) => int = "%mulint" +external \"/": (int, int) => int = "%divint" +external mod: (int, int) => int = "%modint" + +external land: (int, int) => int = "%andint" +external lor: (int, int) => int = "%orint" +external lxor: (int, int) => int = "%xorint" + +external lsl: (int, int) => int = "%lslint" +external lsr: (int, int) => int = "%lsrint" +external asr: (int, int) => int = "%asrint" + +/* Floating-point operations */ + +external \"~-.": float => float = "%negfloat" +external \"~+.": float => float = "%identity" +external \"+.": (float, float) => float = "%addfloat" +external \"-.": (float, float) => float = "%subfloat" +external \"*.": (float, float) => float = "%mulfloat" +external \"/.": (float, float) => float = "%divfloat" + +/* String operations */ + +external \"^": (string, string) => string = "%string_concat" + +/* Unit operations */ + +external ignore: 'a => unit = "%ignore" + +/* References */ + +type ref<'a> = {mutable contents: 'a} +external ref: 'a => ref<'a> = "%makeref" +external \":=": (ref<'a>, 'a) => unit = "%refset" diff --git a/runtime/Promise.res b/runtime/Promise.res new file mode 100644 index 0000000000..8a4418d2fd --- /dev/null +++ b/runtime/Promise.res @@ -0,0 +1,112 @@ +type t<+'a> = promise<'a> + +@new +external make: (('a => unit, 'e => unit) => unit) => t<'a> = "Promise" + +type promiseAndResolvers<'a> = { + promise: t<'a>, + resolve: 'a => unit, + reject: exn => unit, +} + +@scope("Promise") @val +external withResolvers: unit => promiseAndResolvers<_> = "withResolvers" + +@scope("Promise") @val +external resolve: 'a => t<'a> = "resolve" + +@send external then: (t<'a>, 'a => t<'b>) => t<'b> = "then" + +@send +external thenResolve: (t<'a>, 'a => 'b) => t<'b> = "then" + +@send external finally: (t<'a>, unit => unit) => t<'a> = "finally" + +@scope("Promise") @val +external reject: exn => t<_> = "reject" + +@scope("Promise") @val +external all: array> => t> = "all" + +@scope("Promise") @val +external all2: ((t<'a>, t<'b>)) => t<('a, 'b)> = "all" + +@scope("Promise") @val +external all3: ((t<'a>, t<'b>, t<'c>)) => t<('a, 'b, 'c)> = "all" + +@scope("Promise") @val +external all4: ((t<'a>, t<'b>, t<'c>, t<'d>)) => t<('a, 'b, 'c, 'd)> = "all" + +@scope("Promise") @val +external all5: ((t<'a>, t<'b>, t<'c>, t<'d>, t<'e>)) => t<('a, 'b, 'c, 'd, 'e)> = "all" + +@scope("Promise") @val +external all6: ((t<'a>, t<'b>, t<'c>, t<'d>, t<'e>, t<'f>)) => t<('a, 'b, 'c, 'd, 'e, 'f)> = "all" + +@tag("status") +type settledResult<+'a> = + | @as("fulfilled") Fulfilled({value: 'a}) | @as("rejected") Rejected({reason: exn}) + +@scope("Promise") @val +external allSettled: array> => promise>> = "allSettled" + +@scope("Promise") @val +external allSettled2: ((promise<'a0>, promise<'a1>)) => promise<( + settledResult<'a0>, + settledResult<'a1>, +)> = "allSettled" + +@scope("Promise") @val +external allSettled3: ((promise<'a0>, promise<'a1>, promise<'a2>)) => promise<( + settledResult<'a0>, + settledResult<'a1>, + settledResult<'a2>, +)> = "allSettled" + +@scope("Promise") @val +external allSettled4: ((promise<'a0>, promise<'a1>, promise<'a2>, promise<'a3>)) => promise<( + settledResult<'a0>, + settledResult<'a1>, + settledResult<'a2>, + settledResult<'a3>, +)> = "allSettled" + +@scope("Promise") @val +external allSettled5: ( + (promise<'a0>, promise<'a1>, promise<'a2>, promise<'a3>, promise<'a4>) +) => promise<( + settledResult<'a0>, + settledResult<'a1>, + settledResult<'a2>, + settledResult<'a3>, + settledResult<'a4>, +)> = "allSettled" + +@scope("Promise") @val +external allSettled6: ( + (promise<'a0>, promise<'a1>, promise<'a2>, promise<'a3>, promise<'a4>, promise<'a5>) +) => promise<( + settledResult<'a0>, + settledResult<'a1>, + settledResult<'a2>, + settledResult<'a3>, + settledResult<'a4>, + settledResult<'a5>, +)> = "allSettled" + +@send +external _catch: (t<'a>, exn => t<'a>) => t<'a> = "catch" + +let catch = (promise: promise<'a>, callback: exn => promise<'a>): promise<'a> => { + _catch(promise, err => { + callback(Js.Exn.anyToExnInternal(err)) + }) +} + +@scope("Promise") @val +external race: array> => t<'a> = "race" + +@scope("Promise") @val +external any: array> => t<'a> = "any" + +external done: promise<'a> => unit = "%ignore" diff --git a/runtime/Promise.resi b/runtime/Promise.resi new file mode 100644 index 0000000000..5468bf9370 --- /dev/null +++ b/runtime/Promise.resi @@ -0,0 +1,445 @@ +// The +'a marks the abstract type parameter as covariant, which essentially means that +// a value of type 'a is immutable and may not be used in some mutable context. +// +// This makes sense for promises, since according to their specification, once a promise has +// been resolved (with a specific value), it will never change its resolved value. +// +// More details about polymorphism / invariance / covariance,... can be found here: +// https://caml.inria.fr/pub/docs/manual-ocaml/polymorphism.html#ss:variance:abstract-data-types + +/*** +Functions for interacting with JavaScript Promise. +See: [`Promise`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise). +*/ + +type t<+'a> = promise<'a> + +/** +`resolve(value)` creates a resolved Promise with a given `value`. +See [`Promise.resolve`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/resolve) on MDN. + +## Examples + +```rescript +let p = Promise.resolve(5) // promise +``` +*/ +@val +@scope("Promise") +external resolve: 'a => t<'a> = "resolve" + +/** +`reject(exn)` reject a Promise. +See [`Promise.reject`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/reject) on MDN. + +## Examples + +```rescript +exception TestError(string) + +let p = Promise.reject(TestError("some rejected value")) +``` +*/ +@scope("Promise") +@val +external reject: exn => t<_> = "reject" + +/** +`make(callback)` creates a new Promise based on a `callback` that receives two +uncurried functions `resolve` and `reject` for defining the Promise's result. + +## Examples + +```rescript +open Promise + +let n = 4 +Promise.make((resolve, reject) => { + if(n < 5) { + resolve(. "success") + } + else { + reject(. "failed") + } +}) +->then(str => { + Console.log(str)->resolve +}) +->catch(_ => { + Console.log("Error occurred") + resolve() +}) +->ignore +``` +*/ +@new +external make: (('a => unit, 'e => unit) => unit) => t<'a> = "Promise" + +type promiseAndResolvers<'a> = { + promise: t<'a>, + resolve: 'a => unit, + reject: exn => unit, +} + +/** +`withResolvers()` returns a object containing a new promise with functions to resolve or reject it. See [`Promise.withResolvers`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/withResolvers) on MDN. + +## Examples + +```rescript +open Promise + +let {promise, resolve, _} = Promise.withResolvers() + +setTimeout(() => { + resolve(. "success") +}, 1000)->ignore + +promise +->thenResolve(str => { + Console.log(str) +}) +->ignore +``` +*/ +@scope("Promise") +@val +external withResolvers: unit => promiseAndResolvers<_> = "withResolvers" + +/** +`catch(promise, errorCallback)` registers an exception handler in a promise chain. +The `errorCallback` receives an `exn` value that can later be refined into a JS +error or ReScript error. The `errorCallback` needs to return a promise with the +same type as the consumed promise. See [`Promise.catch`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/catch) on MDN. + +## Examples + +```rescript +open Promise + +exception SomeError(string) + +reject(SomeError("this is an error")) +->then(_ => { + Ok("This result will never be returned")->resolve +}) +->catch(e => { + let msg = switch(e) { + | SomeError(msg) => "ReScript error occurred: " ++ msg + | Exn.Error(obj) => + switch Exn.message(obj) { + | Some(msg) => "JS exception occurred: " ++ msg + | None => "Some other JS value has been thrown" + } + | _ => "Unexpected error occurred" + } + + Error(msg)->resolve +}) +->then(result => { + switch result { + | Ok(r) => Console.log2("Operation successful: ", r) + | Error(msg) => Console.log2("Operation failed: ", msg) + }->resolve +}) +->ignore // Ignore needed for side-effects +``` + +In case you want to return another promise in your `callback`, consider using +`then` instead. +*/ +let catch: (t<'a>, exn => t<'a>) => t<'a> + +/** +`then(promise, callback)` returns a new promise based on the result of `promise`'s +value. The `callback` needs to explicitly return a new promise via `resolve`. +It is **not allowed** to resolve a nested promise (like `resolve(resolve(1))`). +See [`Promise.then`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then) on MDN. +## Examples + +```rescript +open Promise +resolve(5) +->then(num => { + resolve(num + 5) +}) +->then(num => { + Console.log2("Your lucky number is: ", num) + resolve() +}) +->ignore +``` +*/ +@send +external then: (t<'a>, 'a => t<'b>) => t<'b> = "then" + +/** +`thenResolve(promise, callback)` converts an encapsulated value of a promise +into another promise wrapped value. It is **not allowed** to return a promise +within the provided callback (e.g. `thenResolve(value => resolve(value))`). + +## Examples + +```rescript +open Promise +resolve("Anna") +->thenResolve(str => { + "Hello " ++ str +}) +->thenResolve(str => { + Console.log(str) +}) +->ignore // Ignore needed for side-effects +``` + +In case you want to return another promise in your `callback`, consider using +`then` instead. +*/ +@send +external thenResolve: (t<'a>, 'a => 'b) => t<'b> = "then" + +/** +`finally(promise, callback)` is used to execute a function that is called no +matter if a promise was resolved or rejected. It will return the same `promise` +it originally received. See [`Promise.finally`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/finally) on MDN. + +## Examples + +```rescript +open Promise +exception SomeError(string) +let isDone = ref(false) + +resolve(5) +->then(_ => { + reject(SomeError("test")) +}) +->then(v => { + Console.log2("final result", v) + resolve() +}) +->catch(_ => { + Console.log("Error handled") + resolve() +}) +->finally(() => { + Console.log("finally") + isDone := true +}) +->then(() => { + Console.log2("isDone:", isDone.contents) + resolve() +}) +->ignore +``` +*/ +@send +external finally: (t<'a>, unit => unit) => t<'a> = "finally" + +/** +`race(arr)` runs all promises concurrently and returns promise settles with the eventual state of the first promise that settles. See [`Promise.race`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/race) on MDN. + +## Examples + +```rescript +open Promise +let racer = (ms, name) => { + Promise.make((resolve, _) => { + setTimeout(() => { + resolve(name) + }, ms)->ignore + }) +} + +let promises = [racer(1000, "Turtle"), racer(500, "Hare"), racer(100, "Eagle")] + +race(promises)->then(winner => { + Console.log("The winner is " ++ winner) + resolve() +}) +``` +*/ +@scope("Promise") +@val +external race: array> => t<'a> = "race" + +/** +`any(arr)` runs all promises concurrently and returns promise fulfills when any of the input's promises fulfills, with this first fulfillment value. See [`Promise.any`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/any) on MDN. + +## Examples + +```rescript +open Promise +let racer = (ms, name) => { + Promise.make((resolve, _) => { + setTimeout(() => { + resolve(name) + }, ms)->ignore + }) +} + +let promises = [racer(1000, "Turtle"), racer(500, "Hare"), racer(100, "Eagle")] + +any(promises)->then(winner => { + Console.log("The winner is " ++ winner) + resolve() +}) +``` +*/ +@scope("Promise") +@val +external any: array> => t<'a> = "any" + +/** +`all(promises)` runs all promises concurrently and returns a promise fulfills when all of the input's promises fulfill, with an array of the fulfillment values. See [`Promise.all`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all) on MDN. + +```rescript +open Promise +let promises = [resolve(1), resolve(2), resolve(3)] + +all(promises) +->then((results) => { + results->Array.forEach(num => { + Console.log2("Number: ", num) + }) + + resolve() +}) +->ignore +``` +*/ +@scope("Promise") +@val +external all: array> => t> = "all" + +/** +`all2((p1, p2))`. Like `all()`, but with a fixed size tuple of 2 +*/ +@scope("Promise") +@val +external all2: ((t<'a>, t<'b>)) => t<('a, 'b)> = "all" + +/** +`all3((p1, p2, p3))`. Like `all()`, but with a fixed size tuple of 3 +*/ +@scope("Promise") +@val +external all3: ((t<'a>, t<'b>, t<'c>)) => t<('a, 'b, 'c)> = "all" + +/** +`all4((p1, p2, p3, p4))`. Like `all()`, but with a fixed size tuple of 4 +*/ +@scope("Promise") +@val +external all4: ((t<'a>, t<'b>, t<'c>, t<'d>)) => t<('a, 'b, 'c, 'd)> = "all" + +/** +`all5((p1, p2, p3, p4, p5))`. Like `all()`, but with a fixed size tuple of 5 +*/ +@scope("Promise") +@val +external all5: ((t<'a>, t<'b>, t<'c>, t<'d>, t<'e>)) => t<('a, 'b, 'c, 'd, 'e)> = "all" + +/** +`all6((p1, p2, p4, p5, p6))`. Like `all()`, but with a fixed size tuple of 6 +")*/ +@scope("Promise") +@val +external all6: ((t<'a>, t<'b>, t<'c>, t<'d>, t<'e>, t<'f>)) => t<('a, 'b, 'c, 'd, 'e, 'f)> = "all" + +@tag("status") +type settledResult<+'a> = + | @as("fulfilled") Fulfilled({value: 'a}) | @as("rejected") Rejected({reason: exn}) + +/** +`allSettled(promises)` runs all promises concurrently and returns promise fulfills when all of the input's promises settle with an array of objects that describe the outcome of each promise. See [`Promise.allSettled`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/allSettled) on MDN. + +```rescript +open Promise + +exception TestError(string) + +let promises = [resolve(1), resolve(2), reject(TestError("some rejected promise"))] + +allSettled(promises) +->then((results) => { + results->Array.forEach((result) => { + switch result { + | Fulfilled({value: num}) => + Console.log2("Number: ", num) + | Rejected({reason}) => + Console.log(reason) + } + }) + + resolve() +}) +->ignore +``` +*/ +@scope("Promise") +@val +external allSettled: array> => t>> = "allSettled" + +/** +`allSettled2((p1, p2))`. Like `allSettled()`, but with a fixed size tuple of 2 +*/ +@scope("Promise") +@val +external allSettled2: ((t<'a>, t<'b>)) => t<(settledResult<'a>, settledResult<'b>)> = "allSettled" + +/** +`allSettled3((p1, p2, p3))`. Like `allSettled()`, but with a fixed size tuple of 3 +*/ +@scope("Promise") +@val +external allSettled3: ((t<'a>, t<'b>, t<'c>)) => t<( + settledResult<'a>, + settledResult<'b>, + settledResult<'c>, +)> = "allSettled" + +/** +`allSettled4((p1, p2, p3, p4))`. Like `allSettled()`, but with a fixed size tuple of 4 +*/ +@scope("Promise") +@val +external allSettled4: ((t<'a>, t<'b>, t<'c>, t<'d>)) => t<( + settledResult<'a>, + settledResult<'b>, + settledResult<'c>, + settledResult<'d>, +)> = "allSettled" + +/** +`allSettled5((p1, p2, p3, p4, p5))`. Like `allSettled()`, but with a fixed size tuple of 5 +*/ +@scope("Promise") +@val +external allSettled5: ((t<'a>, t<'b>, t<'c>, t<'d>, t<'e>)) => t<( + settledResult<'a>, + settledResult<'b>, + settledResult<'c>, + settledResult<'d>, + settledResult<'e>, +)> = "allSettled" + +/** +`allSettled6((p1, p2, p4, p5, p6))`. Like `allSettled()`, but with a fixed size tuple of 6 +")*/ +@scope("Promise") +@val +external allSettled6: ((t<'a>, t<'b>, t<'c>, t<'d>, t<'e>, t<'f>)) => t<( + settledResult<'a>, + settledResult<'b>, + settledResult<'c>, + settledResult<'d>, + settledResult<'e>, + settledResult<'f>, +)> = "allSettled" + +/** +`done(p)` is a safe way to ignore a promise. If a value is anything else than a +promise, it will raise a type error. +*/ +external done: promise<'a> => unit = "%ignore" diff --git a/runtime/RegExp.res b/runtime/RegExp.res new file mode 100644 index 0000000000..9f19af81ab --- /dev/null +++ b/runtime/RegExp.res @@ -0,0 +1,24 @@ +type t = Js.Re.t + +module Result = { + type t = array> + @get_index external fullMatch: (t, @as(0) _) => string = "" + @send external matches: (t, @as(1) _) => array = "slice" + @get external index: t => int = "index" + @get external input: t => string = "input" +} + +@new external fromString: string => t = "RegExp" +@new external fromStringWithFlags: (string, ~flags: string) => t = "RegExp" + +@send external test: (t, string) => bool = "test" +@return(nullable) @send external exec: (t, string) => option = "exec" + +@get external lastIndex: t => int = "lastIndex" +@set external setLastIndex: (t, int) => unit = "lastIndex" +@get external ignoreCase: t => bool = "ignoreCase" +@get external global: t => bool = "global" +@get external multiline: t => bool = "multiline" +@get external source: t => string = "source" +@get external sticky: t => bool = "sticky" +@get external unicode: t => bool = "unicode" diff --git a/runtime/RegExp.resi b/runtime/RegExp.resi new file mode 100644 index 0000000000..3e12daef52 --- /dev/null +++ b/runtime/RegExp.resi @@ -0,0 +1,290 @@ +/*** +Functions for handling RegExp's in ReScript. + +See [`RegExp`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp) on MDN. +*/ + +/** +Type representing an instantiated `RegExp`. +*/ +type t = Js.Re.t + +module Result: { + /** + Type representing the result of a `RegExp` execution. + */ + type t = array> + + /** + `fullMatch(regExpResult)` returns the full string that matched in this result. + + ## Examples + ```rescript + // Match the first two words separated by a space + let regexp = RegExp.fromString("(\\w+) (\\w+)") + + switch regexp->RegExp.exec("ReScript is pretty cool, right?") { + | None => Console.log("Nope, no match...") + | Some(result) => Console.log(result->RegExp.Result.fullMatch) // Prints the full string that matched, "ReScript is" + } + ``` + */ + @get_index + external fullMatch: (t, @as(0) _) => string = "" + + /** + `matches(regExpResult)` returns all matches for `regExpResult`. + + ## Examples + ```rescript + // Match the first two words separated by a space + let regexp = RegExp.fromString("(\\w+) (\\w+)") + + // This below will log "ReScript" and "is" to the console. + switch regexp->RegExp.exec("ReScript is pretty cool, right?") { + | None => Console.log("Nope, no match...") + | Some(result) => switch result->RegExp.Result.matches { + | [firstWord, secondWord] => Console.log2(firstWord, secondWord) + | _ => Console.log("Didn't find exactly two words...") + } + } + ``` + */ + @send + external matches: (t, @as(1) _) => array = "slice" + @get external index: t => int = "index" + + /** + `input(regExpResult)` returns the full input string that was passed to what produced the `RegExp.Result.t`. + + ## Examples + ```rescript + // Match the first two words separated by a space + let regexp = RegExp.fromString("(\\w+) (\\w+)") + + // This below will log the full input string "ReScript is pretty cool, right?" to the console. + switch regexp->RegExp.exec("ReScript is pretty cool, right?") { + | None => Console.log("Nope, no match...") + | Some(result) => Console.log(result->RegExp.Result.input) + } + ``` + */ + @get + external input: t => string = "input" +} + +/** +`fromString(string)` creates a `RegExp.t` from the provided string. This can then be used to match on strings using `RegExp.exec`. + +See [`RegExp`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/RegExp) on MDN. + +## Examples +```rescript +// Match the first word in a sentence +let regexp = RegExp.fromString("\\w+") + +switch regexp->RegExp.exec("ReScript is pretty cool, right?") { +| None => Console.log("Nope, no match...") +| Some(result) => Console.log(result->RegExp.Result.fullMatch) // Prints "ReScript" +} +``` +*/ +@new +external fromString: string => t = "RegExp" + +/** +`fromStringWithFlags(string)` creates a `RegExp.t` from the provided string, using the provided `flags`. This can then be used to match on strings using `RegExp.exec`. + +See [`RegExp parameters`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/RegExp#parameters) on MDN. + +## Examples +```rescript +// Match the first word in a sentence +let regexp = RegExp.fromStringWithFlags("\\w+", ~flags="g") + +switch regexp->RegExp.exec("ReScript is pretty cool, right?") { +| None => Console.log("Nope, no match...") +| Some(result) => Console.log(result->RegExp.Result.fullMatch) // Prints "ReScript" +} +``` +*/ +@new +external fromStringWithFlags: (string, ~flags: string) => t = "RegExp" + +/** +`test(regexp, string)` tests whether the provided `regexp` matches on the provided string. + +See [`RegExp.test`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/test) on MDN. + +## Examples +```rescript +// Match the first word in a sentence +let regexp = RegExp.fromString("\\w+") + +if regexp->RegExp.test("ReScript is cool!") { + Console.log("Yay, there's a word in there.") +} +``` +*/ +@send +external test: (t, string) => bool = "test" + +/** +`exec(regexp, string)` executes the provided regexp on the provided string, optionally returning a `RegExp.Result.t` if the regexp matches on the string. + +See [`RegExp.exec`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/exec) on MDN. + +## Examples +```rescript +// Match the first word in a sentence +let regexp = RegExp.fromString("\\w+") + +switch regexp->RegExp.exec("ReScript is pretty cool, right?") { +| None => Console.log("Nope, no match...") +| Some(result) => Console.log(result->RegExp.Result.fullMatch) // Prints "ReScript" +} +``` +*/ +@return(nullable) +@send +external exec: (t, string) => option = "exec" + +/** +`lastIndex(regexp)` returns the index the next match will start from. + +See [`RegExp.lastIndex`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/lastIndex) on MDN. + +## Examples +```rescript +// Match the first word in a sentence +let regexp = RegExp.fromString("\\w+") +let someStr = "Many words here." + +Console.log(regexp->RegExp.lastIndex) // Logs `0` to the console + +regexp->RegExp.exec(someStr)->ignore + +Console.log(regexp->RegExp.lastIndex) // Logs `4` to the console +``` +*/ +@get +external lastIndex: t => int = "lastIndex" + +/** +`setLastIndex(regexp, index)` set the index the next match will start from. + +See [`RegExp.lastIndex`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/lastIndex) on MDN. + +## Examples +```rescript +// Match the first word in a sentence +let regexp = RegExp.fromString("\\w+") +let someStr = "Many words here." + +regexp->RegExp.setLastIndex(4) +regexp->RegExp.exec(someStr)->ignore + +Console.log(regexp->RegExp.lastIndex) // Logs `10` to the console +``` +*/ +@set +external setLastIndex: (t, int) => unit = "lastIndex" + +/** +`ignoreCase(regexp)` returns whether the ignore case (`i`) flag is set on this `RegExp`. + +See [`RegExp.ignoreCase`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/ignoreCase) on MDN. + +## Examples +```rescript +let regexp1 = RegExp.fromStringWithFlags("\\w+", ~flags="g") +Console.log(regexp1->RegExp.ignoreCase) // Logs `false`, since `i` is not set + +let regexp2 = RegExp.fromStringWithFlags("\\w+", ~flags="i") +Console.log(regexp2->RegExp.ignoreCase) // Logs `true`, since `i` is set +``` +*/ +@get +external ignoreCase: t => bool = "ignoreCase" + +/** +`global(regexp)` returns whether the global (`g`) flag is set on this `RegExp`. + +See [`RegExp.global`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/global) on MDN. + +## Examples +```rescript +let regexp1 = RegExp.fromStringWithFlags("\\w+", ~flags="g") +Console.log(regexp1->RegExp.global) // Logs `true`, since `g` is set + +let regexp2 = RegExp.fromStringWithFlags("\\w+", ~flags="i") +Console.log(regexp2->RegExp.global) // Logs `false`, since `g` is not set +``` +*/ +@get +external global: t => bool = "global" + +/** +`multiline(regexp)` returns whether the multiline (`m`) flag is set on this `RegExp`. + +See [`RegExp.multiline`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/multiline) on MDN. + +## Examples +```rescript +let regexp1 = RegExp.fromStringWithFlags("\\w+", ~flags="g") +Console.log(regexp1->RegExp.multiline) // Logs `false`, since `m` is not set + +let regexp2 = RegExp.fromStringWithFlags("\\w+", ~flags="mi") +Console.log(regexp2->RegExp.multiline) // Logs `true`, since `m` is set +``` +*/ +@get +external multiline: t => bool = "multiline" + +/** +`source(regexp)` returns the source text for this `RegExp`, without the two forward slashes (if present), and without any set flags. + +See [`RegExp.source`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/source) on MDN. + +## Examples +```rescript +let regexp = RegExp.fromStringWithFlags("\\w+", ~flags="g") +Console.log(regexp->RegExp.source) // Logs `\w+`, the source text of the `RegExp` +``` +*/ +@get +external source: t => string = "source" + +/** +`sticky(regexp)` returns whether the sticky (`y`) flag is set on this `RegExp`. + +See [`RegExp.sticky`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/sticky) on MDN. + +## Examples +```rescript +let regexp1 = RegExp.fromStringWithFlags("\\w+", ~flags="g") +Console.log(regexp1->RegExp.unicode) // Logs `false`, since `y` is not set + +let regexp2 = RegExp.fromStringWithFlags("\\w+", ~flags="my") +Console.log(regexp2->RegExp.unicode) // Logs `true`, since `y` is set +``` +*/ +@get +external sticky: t => bool = "sticky" + +/** +`unicode(regexp)` returns whether the unicode (`y`) flag is set on this `RegExp`. + +See [`RegExp.unicode`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/unicode) on MDN. + +## Examples +```rescript +let regexp1 = RegExp.fromStringWithFlags("\\w+", ~flags="g") +Console.log(regexp1->RegExp.unicode) // Logs `false`, since `u` is not set + +let regexp2 = RegExp.fromStringWithFlags("\\w+", ~flags="mu") +Console.log(regexp2->RegExp.unicode) // Logs `true`, since `u` is set +``` +*/ +@get +external unicode: t => bool = "unicode" diff --git a/runtime/Result.res b/runtime/Result.res new file mode 100644 index 0000000000..f9307b59f4 --- /dev/null +++ b/runtime/Result.res @@ -0,0 +1,97 @@ +/* Copyright (C) 2017 Hongbo Zhang, Authors of ReScript + * + * 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 getExn = x => + switch x { + | Ok(x) => x + | Error(_) => raise(Not_found) + } + +let mapOr = (opt, default, f) => + switch opt { + | Ok(x) => f(x) + | Error(_) => default + } + +let mapWithDefault = mapOr + +let map = (opt, f) => + switch opt { + | Ok(x) => Ok(f(x)) + | Error(_) as result => result + } + +let flatMap = (opt, f) => + switch opt { + | Ok(x) => f(x) + | Error(_) as result => result + } + +let getOr = (opt, default) => + switch opt { + | Ok(x) => x + | Error(_) => default + } + +let getWithDefault = getOr + +let isOk = x => + switch x { + | Ok(_) => true + | Error(_) => false + } + +let isError = x => + switch x { + | Ok(_) => false + | Error(_) => true + } + +let equal = (a, b, f) => + switch (a, b) { + | (Ok(a), Ok(b)) => f(a, b) + | (Error(_), Ok(_)) + | (Ok(_), Error(_)) => false + | (Error(_), Error(_)) => true + } + +let compare = (a, b, f) => + switch (a, b) { + | (Ok(a), Ok(b)) => f(a, b) + | (Error(_), Ok(_)) => Ordering.less + | (Ok(_), Error(_)) => Ordering.greater + | (Error(_), Error(_)) => Ordering.equal + } + +let forEach = (r, f) => + switch r { + | Ok(ok) => f(ok) + | Error(_) => () + } + +let mapError = (r, f) => + switch r { + | Ok(_) as result => result + | Error(e) => Error(f(e)) + } diff --git a/runtime/Result.resi b/runtime/Result.resi new file mode 100644 index 0000000000..ac31649e7c --- /dev/null +++ b/runtime/Result.resi @@ -0,0 +1,236 @@ +/* Copyright (C) 2017 Authors of ReScript + * + * 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. */ + +/** + Result types are really useful to describe the result of a certain operation + without relying on exceptions or `option` types. + + This module gives you useful utilities to create and combine `Result` data. +*/ +/** + The type `Result.t(result, err)` describes a variant of two states: + `Ok(someResult)` represents a successful operation, whereby + ``Error(someError)` signals an erronous operation. + + In this concrete example, we are defining our own `Result` type to reflect an HTTP like + query operation: + + ```res example + type responseError = NotAvailable | NotFound + type queryResult = result + + let failQueryUser = (username: string): queryResult => { + Error(NotAvailable) + } +``` +*/ +/** + `getExn(res)`: when `res` is `Ok(n)`, returns `n` when `res` is `Error(m)`, raise an exception + + ```res example + Result.getExn(Result.Ok(42)) == 42 + + Result.getExn(Result.Error("Invalid data")) /* raises exception */ + ``` +*/ +let getExn: result<'a, 'b> => 'a + +/** +`mapOr(res, default, f)`: When res is `Ok(n)`, returns `f(n)`, otherwise `default`. + +## Examples + +```rescript +let ok = Ok(42) +Result.mapOr(ok, 0, (x) => x / 2) == 21 + +let error = Error("Invalid data") +Result.mapOr(error, 0, (x) => x / 2) == 0 +``` +*/ +let mapOr: (result<'a, 'c>, 'b, 'a => 'b) => 'b + +@deprecated("Use mapOr instead") +let mapWithDefault: (result<'a, 'c>, 'b, 'a => 'b) => 'b + +/** +`map(res, f)`: When res is `Ok(n)`, returns `Ok(f(n))`. Otherwise returns res +unchanged. Function `f` takes a value of the same type as `n` and returns an +ordinary value. + +## Examples + +```rescript +let f = (x) => sqrt(Int.toFloat(x)) + +Result.map(Ok(64), f) == Ok(8.0) + +Result.map(Error("Invalid data"), f) == Error("Invalid data") +``` +*/ +let map: (result<'a, 'c>, 'a => 'b) => result<'b, 'c> + +/** +`flatMap(res, f)`: When res is `Ok(n)`, returns `f(n)`. Otherwise, returns res +unchanged. Function `f` takes a value of the same type as `n` and returns a +`Result`. + +## Examples + +```rescript +let recip = (x) => + if (x !== 0.0) { + Ok(1.0 /. x) + } else { + Error("Divide by zero") + } + +Result.flatMap(Ok(2.0), recip) == Ok(0.5) + +Result.flatMap(Ok(0.0), recip) == Error("Divide by zero") + +Result.flatMap(Error("Already bad"), recip) == Error("Already bad") +``` +*/ +let flatMap: (result<'a, 'c>, 'a => result<'b, 'c>) => result<'b, 'c> + +/** +`getOr(res, defaultValue)`: If `res` is `Ok(n)`, returns `n`, otherwise `default` + +## Examples + +```rescript +Result.getOr(Ok(42), 0) == 42 + +Result.getOr(Error("Invalid Data"), 0) == 0 +``` +*/ +let getOr: (result<'a, 'b>, 'a) => 'a + +@deprecated("Use getOr instead") +let getWithDefault: (result<'a, 'b>, 'a) => 'a + +/** +`isOk(res)`: Returns `true` if `res` is of the form `Ok(n)`, `false` if it is the `Error(e)` variant. +*/ +let isOk: result<'a, 'b> => bool + +/** +`isError(res)`: Returns `true` if `res` is of the form `Error(e)`, `false` if it is the `Ok(n)` variant. +*/ +let isError: result<'a, 'b> => bool + +/** +`equal(res1, res2, f)`: Determine if two `Result` variables are equal with +respect to an equality function. If `res1` and `res2` are of the form `Ok(n)` +and `Ok(m)`, return the result of `f(n, m)`. If one of `res1` and `res2` are of +the form `Error(e)`, return false If both `res1` and `res2` are of the form +`Error(e)`, return true + +## Examples + +```rescript +let good1 = Ok(42) + +let good2 = Ok(32) + +let bad1 = Error("invalid") + +let bad2 = Error("really invalid") + +let mod10equal = (a, b) => mod(a, 10) === mod(b, 10) + +Result.equal(good1, good2, mod10equal) == true + +Result.equal(good1, bad1, mod10equal) == false + +Result.equal(bad2, good2, mod10equal) == false + +Result.equal(bad1, bad2, mod10equal) == true +``` +*/ +let equal: (result<'a, 'c>, result<'b, 'd>, ('a, 'b) => bool) => bool + +/** +`compare(res1, res2, f)`: Compare two `Result` variables with respect to a +comparison function. The comparison function returns -1. if the first variable +is "less than" the second, 0. if the two variables are equal, and 1. if the first +is "greater than" the second. + +If `res1` and `res2` are of the form `Ok(n)` and `Ok(m)`, return the result of +`f(n, m)`. If `res1` is of the form `Error(e)` and `res2` of the form `Ok(n)`, +return -1. (nothing is less than something) If `res1` is of the form `Ok(n)` and +`res2` of the form `Error(e)`, return 1. (something is greater than nothing) If +both `res1` and `res2` are of the form `Error(e)`, return 0. (equal) + +## Examples + +```rescript +let good1 = Ok(59) + +let good2 = Ok(37) + +let bad1 = Error("invalid") + +let bad2 = Error("really invalid") + +let mod10cmp = (a, b) => Int.compare(mod(a, 10), mod(b, 10)) + +Result.compare(Ok(39), Ok(57), mod10cmp) == 1. + +Result.compare(Ok(57), Ok(39), mod10cmp) == (-1.) + +Result.compare(Ok(39), Error("y"), mod10cmp) == 1. + +Result.compare(Error("x"), Ok(57), mod10cmp) == (-1.) + +Result.compare(Error("x"), Error("y"), mod10cmp) == 0. +``` +*/ +let compare: (result<'a, 'c>, result<'b, 'd>, ('a, 'b) => Ordering.t) => Ordering.t + +/** +`forEach(res, f)` runs the provided function `f` on the `Ok` value. If `res` is `Error`, nothing happens. + +## Examples + +```rescript +Result.forEach(Ok(3), Console.log) // Logs "3", returns () +Result.forEach(Error("x"), Console.log) // Does nothing, returns () +``` +*/ +let forEach: (result<'a, 'b>, 'a => unit) => unit + +/** +`mapError(r, f)` generates a new `result` by applying the function `f` to the `Error` value. If the source is `Ok`, return it as-is. + +## Examples + +```rescript +let format = n => `Error code: ${n->Int.toString}` +Result.mapError(Error(14), format) // Error("Error code: 14") +Result.mapError(Ok("abc"), format) // Ok("abc") +``` +*/ +let mapError: (result<'a, 'b>, 'b => 'c) => result<'a, 'c> diff --git a/runtime/Set.res b/runtime/Set.res index b547fe31de..00de67d662 100644 --- a/runtime/Set.res +++ b/runtime/Set.res @@ -1,4 +1,27 @@ -// FIXME: -// This exists for compatibility reason. -// Move this into Pervasives or Core +type t<'a> = Js.Set.t<'a> +@new external make: unit => t<'a> = "Set" +@new external fromArray: array<'a> => t<'a> = "Set" +@new external fromIterator: Iterator.t<'a> => t<'a> = "Set" + +@get external size: t<'a> => int = "size" + +@send external clear: t<'a> => unit = "clear" + +@send external add: (t<'a>, 'a) => unit = "add" +@send external delete: (t<'a>, 'a) => bool = "delete" +@send external has: (t<'a>, 'a) => bool = "has" + +@send external forEach: (t<'a>, 'a => unit) => unit = "forEach" + +@send external values: t<'a> => Iterator.t<'a> = "values" + +@send external difference: (t<'a>, t<'a>) => t<'a> = "difference" +@send external intersection: (t<'a>, t<'a>) => t<'a> = "intersection" +@send external union: (t<'a>, t<'a>) => t<'a> = "union" +@send external symmetricDifference: (t<'a>, t<'a>) => t<'a> = "symmetricDifference" +@send external isSubsetOf: (t<'a>, t<'a>) => bool = "isSubsetOf" +@send external isSupersetOf: (t<'a>, t<'a>) => bool = "isSupersetOf" +@send external isDisjointFrom: (t<'a>, t<'a>) => bool = "isDisjointFrom" + +external toArray: t<'a> => array<'a> = "Array.from" diff --git a/runtime/Set.resi b/runtime/Set.resi new file mode 100644 index 0000000000..e1246faef6 --- /dev/null +++ b/runtime/Set.resi @@ -0,0 +1,318 @@ +/*** +Bindings to the mutable JavaScript `Set`. + +See [`Set`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set) on MDN. +*/ + +/** +Type representing an instance of `Set`. +*/ +type t<'a> = Js.Set.t<'a> + +/** +Creates a new, mutable JavaScript `Set`. A `Set` is a collection of unique values. + +See [`Set`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set) on MDN. + + + +## Examples +```rescript +// You can annotate the type of your set if you want to +let mySet: Set.t = Set.make() + +// Or you can let ReScript infer what's in your Set +let set = Set.make() +set->Set.add("Fine name") // Inferred as Set.t +``` + +## Alternatives +A JavaScript `Set` is mutable. If you're looking for an immutable alternative, check out `Belt.Set`. +*/ +@new +external make: unit => t<'a> = "Set" + +/** +Turns an array of values into a Set. Meaning only unique values are preserved. + +## Examples +```rescript +type languages = ReScript | JavaScript | TypeScript +let languageRank = [ReScript, JavaScript, TypeScript] + +let set = Set.fromArray(languageRank) // Set.t + +switch set->Set.has(ReScript) { +| true => Console.log("Yay, ReScript is in there!") +| false => Console.log("Uh-oh, something is _terribly_ wrong with this program... abort.") +} +``` +*/ +@new +external fromArray: array<'a> => t<'a> = "Set" + +/** +Turns an iterator into a `Set`. + +## Examples +```rescript +// Let's pretend we have an interator +@val external someIterator: Iterator.t = "someIterator" + +let set = Set.fromIterator(someIterator) // Set.t +``` +*/ +@new +external fromIterator: Iterator.t<'a> => t<'a> = "Set" + +/** +Returns the size, the number of unique values, of the set. + +See [`Set.prototype.size`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/size) on MDN. + +## Examples +```rescript +let set = Set.make() + +set->Set.add("someValue") +set->Set.add("someValue") +set->Set.add("someValue2") + +let size = set->Set.size // 2 +``` +*/ +@get +external size: t<'a> => int = "size" + +/** +Clears all entries in the set. + +See [`Set.clear`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/clear) on MDN. + +## Examples +```rescript +let set = Set.make() + +set->Set.add("someKey") +set->Set.size // 1 + +set->Set.clear +set->Set.size // 0 +``` +*/ +@send +external clear: t<'a> => unit = "clear" + +/** +Adds a new value to the set. + +See [`Set.add`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/add) on MDN. + +## Examples +```rescript +let set = Set.make() +set->Set.add("someValue") +``` +*/ +@send +external add: (t<'a>, 'a) => unit = "add" + +/** +Deletes the provided `value` from the set. Returns a `bool` for whether the value existed, and was deleted. + +See [`Set.delete`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/delete) on MDN. + +## Examples +```rescript +let set = Set.make() +set->Set.add("someValue") +let didDeleteValue = set->Set.delete("someValue") +Console.log(didDeleteValue) // Logs `true` to the console, becuase the set had the value, so it was successfully deleted + +let didDeleteValue = set->Set.delete("someNonExistantKey") +Console.log(didDeleteValue) // Logs `false` to the console, becuase the value did not exist in the set +``` +*/ +@send +external delete: (t<'a>, 'a) => bool = "delete" + +/** +Checks whether the set has a specific value. + +See [`Set.has`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/has) on MDN. + +## Examples +```rescript +let set = Set.make() +set->Set.add("someValue") + +switch set->Set.has("someValue") { +| false => Console.log("Nope, didn't have it.") +| true => Console.log("Yay, we have the value!") +} +``` +*/ +@send +external has: (t<'a>, 'a) => bool = "has" + +/** +Iterates through all values of the set. + +See [`Set.forEach`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/forEach) on MDN. + +## Examples +```rescript +let set = Set.make() +set->Set.add("someValue") +set->Set.add("someValue2") + +set->Set.forEach(value => { + Console.log(value) +}) +``` +*/ +@send +external forEach: (t<'a>, 'a => unit) => unit = "forEach" + +/** +Returns an iterator that holds all values of the set. + +See [`Set.values`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/values) on MDN. + +## Examples +```rescript +let set = Set.make() +set->Set.add("someValue") +set->Set.add("anotherValue") + +let values = set->Set.values + +// Logs the first value +Console.log(Iterator.next(values).value) + +// You can also turn the iterator into an array. +// Remember that an iterator consumes values. We'll need a fresh values iterator to get an array of all values, since we consumed a value via `next` above already. +Console.log(set->Set.values->Iterator.toArray) +``` +*/ +@send +external values: t<'a> => Iterator.t<'a> = "values" + +/** +Returns a new set with the values of the set that are not in the other set. + +See [`Set.difference`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/difference) on MDN. + +## Examples +```rescript +let set1 = Set.fromArray(["apple", "orange", "banana"]) +let set2 = Set.fromArray(["apple", "banana", "pear"]) +set1->Set.difference(set2) // Set.fromArray(["orange"]) +``` +*/ +@send +external difference: (t<'a>, t<'a>) => t<'a> = "difference" + +/** +Returns a new set with the values containing the values which are in either the set, but not in both. + +See [`Set.symmetricDifference`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/symmetricDifference) on MDN. + +## Examples +```rescript +let set1 = Set.fromArray(["apple", "orange", "banana"]) +let set2 = Set.fromArray(["apple", "banana", "pear"]) +set1->Set.symmetricDifference(set2) // Set.fromArray(["orange", "pear"]) +``` + +*/ +@send +external symmetricDifference: (t<'a>, t<'a>) => t<'a> = "symmetricDifference" + +/** +Returns a new set with the values containing the values which are in both the set and the other set. + +See [`Set.intersection`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/intersection) on MDN. + +## Examples +```rescript +let set1 = Set.fromArray(["apple", "orange", "banana"]) +let set2 = Set.fromArray(["apple", "banana", "pear"]) +set1->Set.intersection(set2) // Set.fromArray(["apple", "banana"]) +``` +*/ +@send +external intersection: (t<'a>, t<'a>) => t<'a> = "intersection" + +/** +Returns a bool indicating if this set has no elements in common with the given set. + +See [`Set.isDisjointFrom`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/isDisjointFrom) on MDN. + +## Examples +```rescript +let set1 = Set.fromArray(["apple", "orange", "banana"]) +let set2 = Set.fromArray(["kiwi", "melon", "pear"]) +set1->Set.isDisjointFrom(set2) // true +``` +*/ +@send +external isDisjointFrom: (t<'a>, t<'a>) => bool = "isDisjointFrom" + +/** +Returns a bool indicating if the all values in the set are in the given set. + +See [`Set.isSubsetOf`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/isSubsetOf) on MDN. + +## Examples +```rescript +let set1 = Set.fromArray(["apple", "banana"]) +let set2 = Set.fromArray(["apple", "banana", "pear"]) +set1->Set.isSubsetOf(set2) // true +``` + */ +@send +external isSubsetOf: (t<'a>, t<'a>) => bool = "isSubsetOf" + +/** +Returns a bool indicating if the all values in the given set are in the set. + +See [`Set.isSupersetOf`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/isSupersetOf) on MDN. + +## Examples +```rescript +let set1 = Set.fromArray(["apple", "banana", "pear"]) +let set2 = Set.fromArray(["apple", "banana"]) +set1->Set.isSupersetOf(set2) // true + ``` +*/ +@send +external isSupersetOf: (t<'a>, t<'a>) => bool = "isSupersetOf" + +/** + Returns a new set with the values of the set that are in both the set and the other set. + +See [`Set.union`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/union) on MDN. + +## Examples +```rescript +let set1 = Set.fromArray(["apple", "orange", "banana"]) +let set2 = Set.fromArray(["apple", "banana", "pear"]) +set1->Set.union(set2) // Set.fromArray(["apple", "orange", "banana", "pear"]) +``` +*/ +@send +external union: (t<'a>, t<'a>) => t<'a> = "union" + +/** +`toArray(set)` returns an array of all values of the set. + +See [`Array.from`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/from) on MDN. + +## Examples +```rescript +let set = Set.fromArray(["apple", "orange", "apple", "banana"]) +set->Set.toArray // ["apple", "orange", "banana"] +``` +*/ +external toArray: t<'a> => array<'a> = "Array.from" diff --git a/runtime/String.res b/runtime/String.res index 3613f1dde4..cab2376a60 100644 --- a/runtime/String.res +++ b/runtime/String.res @@ -1,223 +1,133 @@ -// FIXME: -// This exists for compatibility reason. -// Move this into Pervasives or Core +@val external make: 'a => string = "String" -// Below is all deprecated and should be removed in v13 +@val external fromCharCode: int => string = "String.fromCharCode" +@variadic @val external fromCharCodeMany: array => string = "String.fromCharCode" -type t = string +@val external fromCodePoint: int => string = "String.fromCodePoint" +@variadic @val external fromCodePointMany: array => string = "String.fromCodePoint" -module B = { - include Array +external equal: (string, string) => bool = "%equal" - let uppercase_ascii = bytes => map(Char.uppercase_ascii, bytes) - let lowercase_ascii = bytes => map(Char.lowercase_ascii, bytes) +external compare: (string, string) => Ordering.t = "%compare" - let apply1 = (f, bytes) => - if length(bytes) == 0 { - bytes - } else { - let r = copy(bytes) - unsafe_set(r, 0, f(unsafe_get(bytes, 0))) - r - } - let capitalize_ascii = bytes => apply1(Char.uppercase_ascii, bytes) - let uncapitalize_ascii = bytes => apply1(Char.lowercase_ascii, bytes) +@get external length: string => int = "length" +@get_index external get: (string, int) => option = "" +@get_index external getUnsafe: (string, int) => string = "" +@send external charAt: (string, int) => string = "charAt" - let escaped = bytes => map(Char.escaped, bytes) -} +@send external charCodeAt: (string, int) => float = "charCodeAt" +@send external codePointAt: (string, int) => option = "codePointAt" -@send external join: (array, string) => string = "join" +@send external concat: (string, string) => string = "concat" +@variadic @send external concatMany: (string, array) => string = "concat" -let concat = (sep: string, xs: list) => xs->Array.of_list->join(sep) +@send external endsWith: (string, string) => bool = "endsWith" +@send external endsWithFrom: (string, string, int) => bool = "endsWith" -external length: string => int = "%string_length" +@send external includes: (string, string) => bool = "includes" +@send external includesFrom: (string, string, int) => bool = "includes" -@send external get: (string, int) => char = "codePointAt" - -@send external unsafe_get: (string, int) => char = "codePointAt" - -@scope("Array") external bos: string => array = "from" -let bos = str => B.map(str => str->unsafe_get(0), str->bos) - -@scope("String") @variadic -external bts: array => string = "fromCodePoint" - -let make = (len, ch) => Primitive_string_extern.fromChar(ch)->Primitive_string_extern.repeat(len) - -let init = (len, f) => Array.init(len, i => Primitive_string_extern.fromChar(f(i)))->join("") - -let sub = (s, ofs, len) => bts(B.sub(bos(s), ofs, len)) - -external compare: (t, t) => int = "%compare" - -external equal: (t, t) => bool = "%equal" - -let iter = (f, s) => - for i in 0 to length(s) - 1 { - f(unsafe_get(s, i)) - } - -let iteri = (f, s) => - for i in 0 to length(s) - 1 { - f(i, unsafe_get(s, i)) +@send external indexOf: (string, string) => int = "indexOf" +let indexOfOpt = (s, search) => + switch indexOf(s, search) { + | -1 => None + | index => Some(index) } +@send external indexOfFrom: (string, string, int) => int = "indexOf" -let map = (f, s) => bts(B.map(f, bos(s))) -let mapi = (f, s) => bts(B.mapi(f, bos(s))) - -@send external trim: string => string = "trim" - -let escaped = s => { - let rec needs_escape = i => - if i >= length(s) { - false - } else { - switch unsafe_get(s, i) { - | '"' | '\\' | '\n' | '\t' | '\r' | '\b' => true - | ' ' .. '~' => needs_escape(i + 1) - | _ => true - } - } - - if needs_escape(0) { - join(B.escaped(bos(s)), "") - } else { - s +@send external lastIndexOf: (string, string) => int = "lastIndexOf" +let lastIndexOfOpt = (s, search) => + switch lastIndexOf(s, search) { + | -1 => None + | index => Some(index) } -} - -/* duplicated in bytes.ml */ -let rec index_rec = (s, lim, i, c) => - if i >= lim { - raise(Not_found) - } else if unsafe_get(s, i) == c { - i - } else { - index_rec(s, lim, i + 1, c) +@send external lastIndexOfFrom: (string, string, int) => int = "lastIndexOf" + +@return(nullable) @send +external match: (string, RegExp.t) => option = "match" + +type normalizeForm = [#NFC | #NFD | #NFKC | #NFKD] +@send external normalize: string => string = "normalize" +@send external normalizeByForm: (string, normalizeForm) => string = "normalize" + +@send external repeat: (string, int) => string = "repeat" + +@send external replace: (string, string, string) => string = "replace" +@send external replaceRegExp: (string, RegExp.t, string) => string = "replace" +@send external replaceAll: (string, string, string) => string = "replaceAll" +@send external replaceAllRegExp: (string, RegExp.t, string) => string = "replaceAll" + +@send +external unsafeReplaceRegExpBy0: ( + string, + RegExp.t, + (~match: string, ~offset: int, ~input: string) => string, +) => string = "replace" + +@send +external unsafeReplaceRegExpBy1: ( + string, + RegExp.t, + (~match: string, ~group1: string, ~offset: int, ~input: string) => string, +) => string = "replace" + +@send +external unsafeReplaceRegExpBy2: ( + string, + RegExp.t, + (~match: string, ~group1: string, ~group2: string, ~offset: int, ~input: string) => string, +) => string = "replace" + +@send +external unsafeReplaceRegExpBy3: ( + string, + RegExp.t, + ( + ~match: string, + ~group1: string, + ~group2: string, + ~group3: string, + ~offset: int, + ~input: string, + ) => string, +) => string = "replace" + +@send external search: (string, RegExp.t) => int = "search" +let searchOpt = (s, re) => + switch search(s, re) { + | -1 => None + | index => Some(index) } -/* duplicated in bytes.ml */ -let index = (s, c) => index_rec(s, length(s), 0, c) - -/* duplicated in bytes.ml */ -let rec index_rec_opt = (s, lim, i, c) => - if i >= lim { - None - } else if unsafe_get(s, i) == c { - Some(i) - } else { - index_rec_opt(s, lim, i + 1, c) - } +@send external slice: (string, ~start: int, ~end: int) => string = "slice" +@send external sliceToEnd: (string, ~start: int) => string = "slice" -/* duplicated in bytes.ml */ -let index_opt = (s, c) => index_rec_opt(s, length(s), 0, c) +@send external split: (string, string) => array = "split" +@send external splitAtMost: (string, string, ~limit: int) => array = "split" +@send external splitByRegExp: (string, RegExp.t) => array> = "split" +@send +external splitByRegExpAtMost: (string, RegExp.t, ~limit: int) => array> = "split" -/* duplicated in bytes.ml */ -let index_from = (s, i, c) => { - let l = length(s) - if i < 0 || i > l { - invalid_arg("String.index_from / Bytes.index_from") - } else { - index_rec(s, l, i, c) - } -} - -/* duplicated in bytes.ml */ -let index_from_opt = (s, i, c) => { - let l = length(s) - if i < 0 || i > l { - invalid_arg("String.index_from_opt / Bytes.index_from_opt") - } else { - index_rec_opt(s, l, i, c) - } -} - -/* duplicated in bytes.ml */ -let rec rindex_rec = (s, i, c) => - if i < 0 { - raise(Not_found) - } else if unsafe_get(s, i) == c { - i - } else { - rindex_rec(s, i - 1, c) - } +@send external startsWith: (string, string) => bool = "startsWith" +@send external startsWithFrom: (string, string, int) => bool = "startsWith" -/* duplicated in bytes.ml */ -let rindex = (s, c) => rindex_rec(s, length(s) - 1, c) +@send external substring: (string, ~start: int, ~end: int) => string = "substring" +@send external substringToEnd: (string, ~start: int) => string = "substring" -/* duplicated in bytes.ml */ -let rindex_from = (s, i, c) => - if i < -1 || i >= length(s) { - invalid_arg("String.rindex_from / Bytes.rindex_from") - } else { - rindex_rec(s, i, c) - } +@send external toLowerCase: string => string = "toLowerCase" +@send external toLocaleLowerCase: string => string = "toLocaleLowerCase" +@send external toUpperCase: string => string = "toUpperCase" +@send external toLocaleUpperCase: string => string = "toLocaleUpperCase" -/* duplicated in bytes.ml */ -let rec rindex_rec_opt = (s, i, c) => - if i < 0 { - None - } else if unsafe_get(s, i) == c { - Some(i) - } else { - rindex_rec_opt(s, i - 1, c) - } - -/* duplicated in bytes.ml */ -let rindex_opt = (s, c) => rindex_rec_opt(s, length(s) - 1, c) +@send external trim: string => string = "trim" +@send external trimStart: string => string = "trimStart" +@send external trimEnd: string => string = "trimEnd" -/* duplicated in bytes.ml */ -let rindex_from_opt = (s, i, c) => - if i < -1 || i >= length(s) { - invalid_arg("String.rindex_from_opt / Bytes.rindex_from_opt") - } else { - rindex_rec_opt(s, i, c) - } +@send external padStart: (string, int, string) => string = "padStart" +@send external padEnd: (string, int, string) => string = "padEnd" -/* duplicated in bytes.ml */ -let contains_from = (s, i, c) => { - let l = length(s) - if i < 0 || i > l { - invalid_arg("String.contains_from / Bytes.contains_from") - } else { - try { - ignore(index_rec(s, l, i, c)) - true - } catch { - | Not_found => false - } - } -} - -/* duplicated in bytes.ml */ -let contains = (s, c) => contains_from(s, 0, c) - -/* duplicated in bytes.ml */ -let rcontains_from = (s, i, c) => - if i < 0 || i >= length(s) { - invalid_arg("String.rcontains_from / Bytes.rcontains_from") - } else { - try { - ignore(rindex_rec(s, i, c)) - true - } catch { - | Not_found => false - } - } +@get_index external getSymbol: (string, Symbol.t) => option<'a> = "" +@get_index external getSymbolUnsafe: (string, Symbol.t) => 'a = "" +@set_index external setSymbol: (string, Symbol.t, 'a) => unit = "" -let uppercase_ascii = s => bts(B.uppercase_ascii(bos(s))) -let lowercase_ascii = s => bts(B.lowercase_ascii(bos(s))) -let capitalize_ascii = s => bts(B.capitalize_ascii(bos(s))) -let uncapitalize_ascii = s => bts(B.uncapitalize_ascii(bos(s))) - -let split_on_char = (sep, s) => { - let r = ref(list{}) - let j = ref(length(s)) - for i in length(s) - 1 downto 0 { - if unsafe_get(s, i) == sep { - r := list{sub(s, i + 1, j.contents - i - 1), ...r.contents} - j := i - } - } - list{sub(s, 0, j.contents), ...r.contents} -} +@send external localeCompare: (string, string) => float = "localeCompare" diff --git a/runtime/String.resi b/runtime/String.resi index a5bc660235..c9121179fb 100644 --- a/runtime/String.resi +++ b/runtime/String.resi @@ -1,250 +1,1025 @@ -// FIXME: -// This exists for compatibility reason. -// Move this into Pervasives or Core - -// Below is all deprecated and should be removed in v13 - -/** Return the length (number of characters) of the given string. */ -@deprecated("Use Core instead. This will be removed in v13") -external length: string => int = "%string_length" - -/** [String.get s n] returns the character at index [n] in string [s]. - You can also write [s.[n]] instead of [String.get s n]. - - Raise [Invalid_argument] if [n] not a valid index in [s]. */ -@deprecated("Use Core instead. This will be removed in v13") -@send -external get: (string, int) => char = "codePointAt" - -/** [String.make n c] returns a fresh string of length [n], - filled with the character [c]. */ -@deprecated("Use Core instead. This will be removed in v13") -let make: (int, char) => string - -/** [String.init n f] returns a string of length [n], with character - [i] initialized to the result of [f i] (called in increasing - index order). -*/ -@deprecated("Use Core instead. This will be removed in v13") -let init: (int, int => char) => string - -/** [String.sub s start len] returns a fresh string of length [len], - containing the substring of [s] that starts at position [start] and - has length [len]. - - Raise [Invalid_argument] if [start] and [len] do not - designate a valid substring of [s]. */ -@deprecated("Use Core instead. This will be removed in v13") -let sub: (string, int, int) => string - -/** [String.concat sep sl] concatenates the list of strings [sl], - inserting the separator string [sep] between each. - - Raise [Invalid_argument] if the result is longer than - {!Sys.max_string_length} bytes. */ -@deprecated("Use Core instead. This will be removed in v13") -let concat: (string, list) => string - -/** [String.iter f s] applies function [f] in turn to all - the characters of [s]. It is equivalent to - [f s.[0]; f s.[1]; ...; f s.[String.length s - 1]; ()]. */ -@deprecated("Use Core instead. This will be removed in v13") -let iter: (char => unit, string) => unit - -/** Same as {!String.iter}, but the - function is applied to the index of the element as first argument - (counting from 0), and the character itself as second argument. - @since 4.00.0 */ -@deprecated("Use Core instead. This will be removed in v13") -let iteri: ((int, char) => unit, string) => unit - -/** [String.map f s] applies function [f] in turn to all the - characters of [s] (in increasing index order) and stores the - results in a new string that is returned. - @since 4.00.0 */ -@deprecated("Use Core instead. This will be removed in v13") -let map: (char => char, string) => string - -/** [String.mapi f s] calls [f] with each character of [s] and its - index (in increasing index order) and stores the results in a new - string that is returned. - @since 4.02.0 */ -@deprecated("Use Core instead. This will be removed in v13") -let mapi: ((int, char) => char, string) => string - -/** Return a copy of the argument, without leading and trailing - whitespace. The characters regarded as whitespace are: [' '], - ['\x0c'], ['\n'], ['\r'], and ['\t']. If there is neither leading nor - trailing whitespace character in the argument, return the original - string itself, not a copy. - @since 4.00.0 */ -@deprecated("Use Core instead. This will be removed in v13") +/* 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. */ + +/*** +Functions for interacting with JavaScript strings. +See: [`String`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String). +*/ + +/** +`make(value)` converts the given value to a `string`. + +## Examples + +```rescript +String.make(3.5) == "3.5" +String.make([1, 2, 3]) == "1,2,3" +``` +*/ +@val +external make: 'a => string = "String" + +/** +`fromCharCode(n)` creates a `string` containing the character corresponding to +that number, `n` ranges from 0 to 65535. If out of range, the lower 16 bits of +the value are used. Thus, `fromCharCode(0x1F63A)` gives the same result as +`fromCharCode(0xF63A)`. +See [`String.fromCharCode`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/fromCharCode) on MDN. + +## Examples + +```rescript +String.fromCharCode(65) == "A" +String.fromCharCode(0x3c8) == `ψ` +String.fromCharCode(0xd55c) == `한` +String.fromCharCode(-64568) == `ψ` +``` +*/ +@val +external fromCharCode: int => string = "String.fromCharCode" + +/** +`fromCharCodeMany([n1, n2, n3])` creates a `string` from the characters +corresponding to the given numbers, using the same rules as `fromCharCode`. +See [`String.fromCharCode`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/fromCharCode) on MDN. + +## Examples + +```rescript +String.fromCharCodeMany([189, 43, 190, 61]) == "½+¾=" +String.fromCharCodeMany([65, 66, 67]) == "ABC" +``` +*/ +@variadic +@val +external fromCharCodeMany: array => string = "String.fromCharCode" + +/** +`fromCodePoint(n)` creates a `string` containing the character corresponding to +that numeric code point. +See [`String.fromCodePoint`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/fromCodePoint) on MDN. + +## Examples + +```rescript +String.fromCodePoint(65) == "A" +String.fromCodePoint(0x3c8) == `ψ` +String.fromCodePoint(0xd55c) == `한` +String.fromCodePoint(0x1f63a) == `😺` +``` + +## Exceptions + +- `RangeError`: If the number is not a valid code point, like `fromCharCode(-5)`. +*/ +@val +external fromCodePoint: int => string = "String.fromCodePoint" + +/** +`fromCodePointMany([n1, n2, n3])` creates a `string` from the characters +corresponding to the given code point numbers, using the same rules as +`fromCodePoint`. +See [`String.fromCodePoint`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/fromCodePoint) on MDN. + +## Examples + +```rescript +String.fromCodePointMany([0xd55c, 0xae00, 0x1f63a]) == `한글😺` +``` + +## Exceptions + +- `RangeError`: If one of the number is not a valid code point, like +`fromCharCode([1, -5])`. + +*/ +@variadic +@val +external fromCodePointMany: array => string = "String.fromCodePoint" + +external equal: (string, string) => bool = "%equal" + +external compare: (string, string) => Ordering.t = "%compare" + +/** +`length(str)` returns the length of the given `string`. +See [`String.length`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/length) on MDN. + +## Examples + +```rescript +String.length("abcd") == 4 +``` +*/ +@get +external length: string => int = "length" + +/** +`get(str, index)` returns an `option` at the given `index` number. If +`index` is out of range, this function returns `None`. + +## Examples + +```rescript +String.get("ReScript", 0) == Some("R") +String.get("Hello", 4) == Some("o") +String.get(`JS`, 4) == None +``` +*/ +@get_index +external get: (string, int) => option = "" + +/** +`getUnsafe(str, index)` returns an `string` at the given `index` number. + +This is _unsafe_, meaning it will return `undefined` value if `index` does not exist in `string`. + +Use `String.getUnsafe` only when you are sure the `index` exists. +## Examples + +```rescript +String.getUnsafe("ReScript", 0) == "R" +String.getUnsafe("Hello", 4) == "o" +``` +*/ +@get_index +external getUnsafe: (string, int) => string = "" + +/** +`charAt(str, index)` gets the character at `index` within string `str`. If +`index` is negative or greater than the length of `str`, it returns the empty +string. If the string contains characters outside the range \u0000-\uffff, it +will return the first 16-bit value at that position in the string. +See [`String.charAt`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/charAt) on MDN. + +## Examples + +```rescript +String.charAt("ReScript", 0) == "R" +String.charAt("Hello", 12) == "" +String.charAt(`JS`, 5) == "" +``` +*/ +@send +external charAt: (string, int) => string = "charAt" + +/** +`charCodeAt(str, index)` returns the character code at position `index` in +string `str` the result is in the range 0-65535, unlike `codePointAt`, so it +will not work correctly for characters with code points greater than or equal +to 0x10000. The return type is `float` because this function returns NaN if +`index` is less than zero or greater than the length of the string. +See [`String.charCodeAt`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/charCodeAt) on MDN. + +## Examples + +```rescript +String.charCodeAt(`😺`, 0) == 0xd83d->Int.toFloat +String.codePointAt(`😺`, 0) == Some(0x1f63a) +``` +*/ +@send +external charCodeAt: (string, int) => float = "charCodeAt" + +/** +`codePointAt(str, index)` returns the code point at position `index` within +string `str` as a `Some(value)`. The return value handles code points greater +than or equal to 0x10000. If there is no code point at the given position, the +function returns `None`. +See [`String.codePointAt`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/codePointAt) on MDN. + +## Examples + +```rescript +String.codePointAt(`¿😺?`, 1) == Some(0x1f63a) +String.codePointAt("abc", 5) == None +``` +*/ +@send +external codePointAt: (string, int) => option = "codePointAt" + +/** +`concat(original, append)` returns a new `string` with `append` added after +`original`. +See [`String.concat`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/concat) on MDN. + +## Examples + +```rescript +String.concat("cow", "bell") == "cowbell" +String.concat("Re", "Script") == "ReScript" +``` +*/ +@send +external concat: (string, string) => string = "concat" + +/** +`concatMany(original, arr)` returns a new `string` consisting of each item of an +array of strings added to the `original` string. +See [`String.concat`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/concat) on MDN. + +## Examples + +```rescript +String.concatMany("1st", ["2nd", "3rd", "4th"]) == "1st2nd3rd4th" +``` +*/ +@variadic +@send +external concatMany: (string, array) => string = "concat" + +/** +`endsWith(str, substr)` returns `true` if the `str` ends with `substr`, `false` +otherwise. +See [`String.endsWith`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/endsWith) on MDN. + +## Examples + +```rescript +String.endsWith("BuckleScript", "Script") == true +String.endsWith("BuckleShoes", "Script") == false +``` +*/ +@send +external endsWith: (string, string) => bool = "endsWith" + +// NOTE: Honestly, this should have been named endsWithAt, but oh well +/** +`endsWithFrom(str, ending, len)` returns `true` if the first len characters of +`str` end with `ending`, `false` otherwise. If `len` is greater than or equal +to the length of `str`, then it works like `endsWith`. +See [`String.endsWith`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/endsWith) on MDN. + +## Examples + +```rescript +String.endsWithFrom("abcd", "cd", 4) == true +String.endsWithFrom("abcde", "cd", 3) == false +String.endsWithFrom("abcde", "cde", 99) == true +String.endsWithFrom("example.dat", "ple", 7) == true +``` +*/ +@send +external endsWithFrom: (string, string, int) => bool = "endsWith" + +/** +`includes(str, searchValue)` returns `true` if `searchValue` is found anywhere +within `str`, `false` otherwise. +See [`String.includes`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/includes) on MDN. + +## Examples + +```rescript +String.includes("programmer", "gram") == true +String.includes("programmer", "er") == true +String.includes("programmer", "pro") == true +String.includes("programmer.dat", "xyz") == false +``` +*/ +@send +external includes: (string, string) => bool = "includes" + +/** +`includesFrom(str, searchValue, start)` returns `true` if `searchValue` is found +anywhere within `str` starting at character number `start` (where 0 is the +first character), `false` otherwise. +See [`String.includes`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/includes) on MDN. + +## Examples + +```rescript +String.includesFrom("programmer", "gram", 1) == true +String.includesFrom("programmer", "gram", 4) == false +String.includesFrom(`대한민국`, `한`, 1) == true +``` +*/ +@send +external includesFrom: (string, string, int) => bool = "includes" + +/** +`indexOf(str, searchValue)` returns the position at which `searchValue` was +first found within `str`, or `-1` if `searchValue` is not in `str`. +See [`String.indexOf`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/indexOf) on MDN. + +## Examples + +```rescript +String.indexOf("bookseller", "ok") == 2 +String.indexOf("bookseller", "sell") == 4 +String.indexOf("beekeeper", "ee") == 1 +String.indexOf("bookseller", "xyz") == -1 +``` +*/ +@send +external indexOf: (string, string) => int = "indexOf" + +/** +`indexOfOpt(str, searchValue)`. Like `indexOf`, but return an `option`. + +## Examples + +```rescript +String.indexOfOpt("bookseller", "ok") == Some(2) +String.indexOfOpt("bookseller", "xyz") == None +``` +*/ +let indexOfOpt: (string, string) => option + +/** +`indexOfFrom(str, searchValue, start)` returns the position at which +`searchValue` was found within `str` starting at character position `start`, or +`-1` if `searchValue` is not found in that portion of `str`. The return value is +relative to the beginning of the string, no matter where the search started +from. +See [`String.indexOf`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/indexOf) on MDN. + +## Examples + +```rescript +String.indexOfFrom("bookseller", "ok", 1) == 2 +String.indexOfFrom("bookseller", "sell", 2) == 4 +String.indexOfFrom("bookseller", "sell", 5) == -1 +``` +*/ +@send +external indexOfFrom: (string, string, int) => int = "indexOf" + +/** +`lastIndexOf(str, searchValue)` returns the position of the last occurrence of +`searchValue` within `str`, searching backwards from the end of the string. +Returns `-1` if `searchValue` is not in `str`. The return value is always +relative to the beginning of the string. +See [`String.lastIndexOf`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/lastIndexOf) on MDN. + +## Examples + +```rescript +String.lastIndexOf("bookseller", "ok") == 2 +String.lastIndexOf("beekeeper", "ee") == 4 +String.lastIndexOf("abcdefg", "xyz") == -1 +``` +*/ +@send +external lastIndexOf: (string, string) => int = "lastIndexOf" + +/** +`lastIndexOfOpt(str, searchValue)`. Like `lastIndexOfOpt`, but return an +`option`. + +## Examples + +```rescript +String.lastIndexOfOpt("bookseller", "ok") == Some(2) +String.lastIndexOfOpt("beekeeper", "ee") == Some(4) +String.lastIndexOfOpt("abcdefg", "xyz") == None +``` +*/ +let lastIndexOfOpt: (string, string) => option + +/** +`lastIndexOfFrom(str, searchValue, start)` returns the position of the last +occurrence of `searchValue` within `str`, searching backwards from the given +start position. Returns `-1` if `searchValue` is not in `str`. The return value +is always relative to the beginning of the string. +See [`String.lastIndexOf`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/lastIndexOf) on MDN. + +## Examples + +```rescript +String.lastIndexOfFrom("bookseller", "ok", 6) == 2 +String.lastIndexOfFrom("beekeeper", "ee", 8) == 4 +String.lastIndexOfFrom("beekeeper", "ee", 3) == 1 +String.lastIndexOfFrom("abcdefg", "xyz", 4) == -1 +``` +*/ +@send +external lastIndexOfFrom: (string, string, int) => int = "lastIndexOf" + +/** +`match(str, regexp)` matches a `string` against the given `regexp`. If there is +no match, it returns `None`. For regular expressions without the g modifier, if +there is a match, the return value is `Some(array)` where the array contains: +- The entire matched string +- Any capture groups if the regexp had parentheses +For regular expressions with the g modifier, a matched expression returns +`Some(array)` with all the matched substrings and no capture groups. +See [`String.match`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/match) on MDN. + +## Examples + +```rescript +String.match("The better bats", %re("/b[aeiou]t/")) == Some([Some("bet")]) +String.match("The better bats", %re("/b[aeiou]t/g")) == Some([Some("bet"), Some("bat")]) +String.match("Today is 2018-04-05.", %re("/(\d+)-(\d+)-(\d+)/")) == + Some([Some("2018-04-05"), Some("2018"), Some("04"), Some("05")]) +String.match("The optional example", %re("/(foo)?(example)/")) == Some([Some("example"), None, Some("example")]) +String.match("The large container.", %re("/b[aeiou]g/")) == None +``` +*/ +@return(nullable) +@send +external match: (string, RegExp.t) => option = "match" + +/** +`normalize(str)` returns the normalized Unicode string using Normalization Form +Canonical (NFC) Composition. Consider the character ã, which can be represented +as the single codepoint \u00e3 or the combination of a lower case letter A +\u0061 and a combining tilde \u0303. Normalization ensures that both can be +stored in an equivalent binary representation. +See [`String.normalize`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/normalize) on MDN. +See also [Unicode technical report #15](https://unicode.org/reports/tr15/) for details. + +## Examples + +```rescript +let string1 = "\uFB00" +let string2 = "\u0066\u0066" +Console.log(string1 === string2) // false + +let normalizeString1 = String.normalize(string1) +let normalizeString2 = String.normalize(string2) +assert(normalizeString1 === normalizeString2) +``` +*/ +@send +external normalize: string => string = "normalize" + +/** +`normalizeByForm(str, form)` returns the normalized Unicode string using the +specified form of normalization, which may be one of: +- "NFC" — Normalization Form Canonical Composition. +- "NFD" — Normalization Form Canonical Decomposition. +- "NFKC" — Normalization Form Compatibility Composition. +- "NFKD" — Normalization Form Compatibility Decomposition. +See [`String.normalize`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/normalize) on MDN. +See also [Unicode technical report #15](https://unicode.org/reports/tr15/) for +details. + +## Examples + +```rescript +let string1 = "\uFB00" +let string2 = "\u0066\u0066" +Console.log(string1 == string2) // false + +let normalizeString1 = String.normalizeByForm(string1, #NFKD) +let normalizeString2 = String.normalizeByForm(string2, #NFKD) +Console.log(normalizeString1 == normalizeString2) // true +``` +*/ +type normalizeForm = [#NFC | #NFD | #NFKC | #NFKD] +@send +external normalizeByForm: (string, normalizeForm) => string = "normalize" + +/** +`repeat(str, n)` returns a `string` that consists of `n` repetitions of `str`. +See [`String.repeat`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/repeat) on MDN. + +## Examples + +```rescript +String.repeat("ha", 3) == "hahaha" +String.repeat("empty", 0) == "" +``` + +## Exceptions + +- `RangeError`: if `n` is negative. +*/ +@send +external repeat: (string, int) => string = "repeat" + +/** +`replace(str, substr, newSubstr)` returns a new `string` which is +identical to `str` except with the first matching instance of `substr` replaced +by `newSubstr`. `substr` is treated as a verbatim string to match, not a +regular expression. +See [`String.replace`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replace) on MDN. + +## Examples + +```rescript +String.replace("old string", "old", "new") == "new string" +String.replace("the cat and the dog", "the", "this") == "this cat and the dog" +``` +*/ +@send +external replace: (string, string, string) => string = "replace" + +/** +`replaceRegExp(str, regex, replacement)` returns a new `string` where +occurrences matching regex have been replaced by `replacement`. +See [`String.replace`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replace) on MDN. + +## Examples + +```rescript +String.replaceRegExp("vowels be gone", %re("/[aeiou]/g"), "x") == "vxwxls bx gxnx" +String.replaceRegExp("Juan Fulano", %re("/(\w+) (\w+)/"), "$2, $1") == "Fulano, Juan" +``` +*/ +@send +external replaceRegExp: (string, RegExp.t, string) => string = "replace" + +/** +`replaceAll(str, substr, newSubstr)` returns a new `string` which is +identical to `str` except with all matching instances of `substr` replaced +by `newSubstr`. `substr` is treated as a verbatim string to match, not a +regular expression. +See [`String.replaceAll`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replaceAll) on MDN. + +## Examples + +```rescript +String.replaceAll("old old string", "old", "new") == "new new string" +String.replaceAll("the cat and the dog", "the", "this") == "this cat and this dog" +``` +*/ +@send +external replaceAll: (string, string, string) => string = "replaceAll" + +/** +`replaceAllRegExp(str, regex, replacement)` returns a new `string` where +all occurrences matching regex have been replaced by `replacement`. +The pattern must include the global (`g`) flag or a runtime TypeError will be thrown. +See [`String.replaceAll`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replaceAll) on MDN. + +## Examples + +```rescript +String.replaceAllRegExp("vowels be gone", %re("/[aeiou]/g"), "x") == "vxwxls bx gxnx" +String.replaceAllRegExp("aabbcc", %re("/b/g"), ".") == "aa..cc" +``` +*/ +@send +external replaceAllRegExp: (string, RegExp.t, string) => string = "replaceAll" + +/** +`unsafeReplaceRegExpBy0(str, regex, f)` returns a new `string` with some or all +matches of a pattern with no capturing parentheses replaced by the value +returned from the given function. The function receives as its parameters the +matched string, the offset at which the match begins, and the whole string being +matched. +See [`String.replace`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replace) on MDN. + +## Examples + +```rescript +let str = "beautiful vowels" +let re = %re("/[aeiou]/g") +let matchFn = (~match, ~offset as _, ~input as _) => String.toUpperCase(match) +String.unsafeReplaceRegExpBy0(str, re, matchFn) == "bEAUtIfUl vOwEls" +``` +*/ +@send +external unsafeReplaceRegExpBy0: ( + string, + RegExp.t, + (~match: string, ~offset: int, ~input: string) => string, +) => string = "replace" + +/** +`unsafeReplaceRegExpBy1(str, regexp, f)`. Like `unsafeReplaceRegExpBy0`, but `f` +has `group1` parameter. +See [`String.replace`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replace) on MDN. + +## Examples + +```rescript +let str = "Jony is 40" +let re = %re("/(Jony is )\d+/g") +let matchFn = (~match as _, ~group1, ~offset as _, ~input as _) => { + group1 ++ "41" +} +String.unsafeReplaceRegExpBy1(str, re, matchFn) == "Jony is 41" +``` +*/ +@send +external unsafeReplaceRegExpBy1: ( + string, + RegExp.t, + (~match: string, ~group1: string, ~offset: int, ~input: string) => string, +) => string = "replace" + +/** +`unsafeReplaceRegExpBy2(str, regexp, f)`. Like `unsafeReplaceRegExpBy1`, but `f` +has two group parameters. +See [`String.replace`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replace) on MDN. + +## Examples + +```rescript +let str = "7 times 6" +let re = %re("/(\d+) times (\d+)/") +let matchFn = (~match as _, ~group1, ~group2, ~offset as _, ~input as _) => { + switch (Int.fromString(group1), Int.fromString(group2)) { + | (Some(x), Some(y)) => Int.toString(x * y) + | _ => "???" + } +} +String.unsafeReplaceRegExpBy2(str, re, matchFn) == "42" +``` +*/ +@send +external unsafeReplaceRegExpBy2: ( + string, + RegExp.t, + (~match: string, ~group1: string, ~group2: string, ~offset: int, ~input: string) => string, +) => string = "replace" + +/** +`unsafeReplaceRegExpBy3(str, regexp, f)`. Like `unsafeReplaceRegExpBy1`, but `f` +has three group parameters. +See [`String.replace`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replace) on MDN. +*/ +@send +external unsafeReplaceRegExpBy3: ( + string, + RegExp.t, + ( + ~match: string, + ~group1: string, + ~group2: string, + ~group3: string, + ~offset: int, + ~input: string, + ) => string, +) => string = "replace" + +/** +`search(str, regexp)` returns the starting position of the first match of +`regexp` in the given `str`, or -1 if there is no match. +See [`String.search`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/search) on MDN. + +## Examples + +```rescript +String.search("testing 1 2 3", %re("/\d+/")) == 8 +String.search("no numbers", %re("/\d+/")) == -1 +``` +*/ +@send +external search: (string, RegExp.t) => int = "search" + +/** +`searchOpt(str, regexp)`. Like `search`, but return an `option`. + +## Examples + +```rescript +String.searchOpt("testing 1 2 3", %re("/\d+/")) == Some(8) +String.searchOpt("no numbers", %re("/\d+/")) == None +``` +*/ +let searchOpt: (string, RegExp.t) => option + +/** +`slice(str, ~start, ~end)` returns the substring of `str` starting at +character `start` up to but not including `end`. +- If either `start` or `end` is negative, then it is evaluated as +`length(str - start)` or `length(str - end)`. +- If `end` is greater than the length of `str`, then it is treated as +`length(str)`. +- If `start` is greater than `end`, slice returns the empty string. +See [`String.slice`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/slice) on MDN. + +## Examples + +```rescript +String.slice("abcdefg", ~start=2, ~end=5) == "cde" +String.slice("abcdefg", ~start=2, ~end=9) == "cdefg" +String.slice("abcdefg", ~start=-4, ~end=-2) == "de" +String.slice("abcdefg", ~start=5, ~end=1) == "" +``` +*/ +@send +external slice: (string, ~start: int, ~end: int) => string = "slice" + +/** +`sliceToEnd(str, ~start)` returns the substring of `str` starting at character +`start` to the end of the string. +- If `start` is negative, then it is evaluated as `length(str - start)`. +- If `start` is greater than the length of `str`, then sliceToEnd returns the empty string. +See [`String.slice`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/slice) on MDN. + +## Examples + +```rescript +String.sliceToEnd("abcdefg", ~start=4) == "efg" +String.sliceToEnd("abcdefg", ~start=-2) == "fg" +String.sliceToEnd("abcdefg", ~start=7) == "" +``` +*/ +@send +external sliceToEnd: (string, ~start: int) => string = "slice" + +/** +`split(str, delimiter)` splits the given `str` at every occurrence of +`delimiter` and returns an array of the resulting substrings. +See [`String.split`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/split) on MDN. + +## Examples + +```rescript +String.split("2018-01-02", "-") == ["2018", "01", "02"] +String.split("a,b,,c", ",") == ["a", "b", "", "c"] +String.split("good::bad as great::awful", "::") == ["good", "bad as great", "awful"] +String.split("has-no-delimiter", ";") == ["has-no-delimiter"] +``` +*/ +@send +external split: (string, string) => array = "split" + +/** +`splitAtMost(str, delimiter, ~limit)` splits the given `str` at every +occurrence of `delimiter` and returns an array of the first `limit` resulting +substrings. If `limit` is negative or greater than the number of substrings, +the array will contain all the substrings. + +## Examples + +```rescript +String.splitAtMost("ant/bee/cat/dog/elk", "/", ~limit=3) == ["ant", "bee", "cat"] +String.splitAtMost("ant/bee/cat/dog/elk", "/", ~limit=0) == [] +String.splitAtMost("ant/bee/cat/dog/elk", "/", ~limit=9) == ["ant", "bee", "cat", "dog", "elk"] +``` +*/ +@send +external splitAtMost: (string, string, ~limit: int) => array = "split" + +/** +`splitByRegExp(str, regexp)` splits the given `str` at every occurrence of +`regexp` and returns an array of the resulting substrings. +See [`String.split`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/split) on MDN. + +## Examples + +```rescript +String.splitByRegExp("Jan,Feb,Mar", %re("/,/")) == [Some("Jan"), Some("Feb"), Some("Mar")] +``` +*/ +@send +external splitByRegExp: (string, RegExp.t) => array> = "split" + +/** +`splitByRegExpAtMost(str, regexp, ~limit)` splits the given `str` at every +occurrence of `regexp` and returns an array of the first `limit` resulting +substrings. If `limit` is negative or greater than the number of substrings, the +array will contain all the substrings. +See [`String.split`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/split) on MDN. + +## Examples + +```rescript +String.splitByRegExpAtMost("Hello World. How are you doing?", %re("/ /"), ~limit=3) == [ + Some("Hello"), + Some("World."), + Some("How"), +] +``` +*/ +@send +external splitByRegExpAtMost: (string, RegExp.t, ~limit: int) => array> = "split" + +/** +`startsWith(str, substr)` returns `true` if the `str` starts with `substr`, +`false` otherwise. +See [`String.startsWith`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/startsWith) on MDN. + +## Examples + +```rescript +String.startsWith("BuckleScript", "Buckle") == true +String.startsWith("BuckleScript", "") == true +String.startsWith("JavaScript", "Buckle") == false +``` +*/ +@send +external startsWith: (string, string) => bool = "startsWith" + +/** +`startsWithFrom(str, substr, n)` returns `true` if the `str` starts +with `substr` starting at position `n`, `false` otherwise. If `n` is negative, +the search starts at the beginning of `str`. +See [`String.startsWith`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/startsWith) on MDN. + +## Examples + +```rescript +String.startsWithFrom("BuckleScript", "kle", 3) == true +String.startsWithFrom("BuckleScript", "", 3) == true +String.startsWithFrom("JavaScript", "Buckle", 2) == false +``` +*/ +@send +external startsWithFrom: (string, string, int) => bool = "startsWith" + +/** +`substring(str, ~start, ~end)` returns characters `start` up to but not +including end from `str`. +- If `start` is less than zero, it is treated as zero. +- If `end` is zero or negative, the empty string is returned. +- If `start` is greater than `end`, the `start` and `end` points are swapped. +See [`String.substring`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/substring) on MDN. + +## Examples + +```rescript +String.substring("playground", ~start=3, ~end=6) == "ygr" +String.substring("playground", ~start=6, ~end=3) == "ygr" +String.substring("playground", ~start=4, ~end=12) == "ground" +``` +*/ +@send +external substring: (string, ~start: int, ~end: int) => string = "substring" + +/** +`substringToEnd(str, ~start)` returns the substring of `str` from position +`start` to the end. +- If `start` is less than or equal to zero, the entire string is returned. +- If `start` is greater than or equal to the length of `str`, the empty string +is returned. +See [`String.substring`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/substring) on MDN. + +## Examples + +```rescript +String.substringToEnd("playground", ~start=4) == "ground" +String.substringToEnd("playground", ~start=-3) == "playground" +String.substringToEnd("playground", ~start=12) == "" +``` +*/ +@send +external substringToEnd: (string, ~start: int) => string = "substring" + +/** +`toLowerCase(str)` converts `str` to lower case using the locale-insensitive +case mappings in the Unicode Character Database. Notice that the conversion can +give different results depending upon context, for example with the Greek +letter sigma, which has two different lower case forms, one when it is the last +character in a string and another when it is not. +See [`String.toLowerCase`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/toLowerCase) on MDN. + +## Examples + +```rescript +String.toLowerCase("ABC") == "abc" +String.toLowerCase(`ΣΠ`) == `σπ` +String.toLowerCase(`ΠΣ`) == `πς` +``` +*/ +@send +external toLowerCase: string => string = "toLowerCase" + +/** +`toLocaleLowerCase(str)` converts `str` to lower case using the current locale. +See [`String.toLocaleLowerCase`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/toLocaleLowerCase) on MDN. +*/ +@send +external toLocaleLowerCase: string => string = "toLocaleLowerCase" + +/** +`toUpperCase(str)` converts `str` to upper case using the locale-insensitive +case mappings in the Unicode Character Database. Notice that the conversion can +expand the number of letters in the result, for example the German ß +capitalizes to two Ses in a row. +See [`String.toUpperCase`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/toUpperCase) on MDN. + +## Examples + +```rescript +String.toUpperCase("abc") == "ABC" +String.toUpperCase(`Straße`) == `STRASSE` +String.toUpperCase(`πς`) == `ΠΣ` +``` +*/ +@send +external toUpperCase: string => string = "toUpperCase" + +/** +`toLocaleUpperCase(str)` converts `str` to upper case using the current locale. +See [`String.toLocaleUpperCase`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/toLocaleUpperCase) on MDN. +*/ +@send +external toLocaleUpperCase: string => string = "toLocaleUpperCase" + +/** +`trim(str)` returns a string that is `str` with whitespace stripped from both +ends. Internal whitespace is not removed. +See [`String.trim`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/trim) on MDN. + +## Examples + +```rescript +String.trim(" abc def ") == "abc def" +String.trim("\n\r\t abc def \n\n\t\r ") == "abc def" +``` +*/ @send external trim: string => string = "trim" -/** Return a copy of the argument, with special characters - represented by escape sequences, following the lexical - conventions of OCaml. - All characters outside the ASCII printable range (32..126) are - escaped, as well as backslash and double-quote. +/** +`trimStart(str)` returns a string that is `str` with whitespace stripped from +the beginning of a string. Internal whitespace is not removed. +See [`String.trimStart`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/trimStart) on MDN. + +## Examples + +```rescript +String.trimStart(" Hello world! ") == "Hello world! " +String.trimStart(" Hello world! ") == "Hello world! " +``` +*/ +@send +external trimStart: string => string = "trimStart" + +/** +`trinEnd(str)` returns a string that is `str` with whitespace stripped from the +end of a string. Internal whitespace is not removed. +See [`String.trimEnd`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/trimEnd) on MDN. + +## Examples - If there is no special character in the argument that needs - escaping, return the original string itself, not a copy. - */ -@deprecated("Use Core instead. This will be removed in v13") -let escaped: string => string - -/** [String.index s c] returns the index of the first - occurrence of character [c] in string [s]. - - Raise [Not_found] if [c] does not occur in [s]. */ -@deprecated("Use Core instead. This will be removed in v13") -let index: (string, char) => int - -/** [String.index_opt s c] returns the index of the first - occurrence of character [c] in string [s], or - [None] if [c] does not occur in [s]. - @since 4.05 */ -@deprecated("Use Core instead. This will be removed in v13") -let index_opt: (string, char) => option - -/** [String.rindex s c] returns the index of the last - occurrence of character [c] in string [s]. - - Raise [Not_found] if [c] does not occur in [s]. */ -@deprecated("Use Core instead. This will be removed in v13") -let rindex: (string, char) => int - -/** [String.rindex_opt s c] returns the index of the last occurrence - of character [c] in string [s], or [None] if [c] does not occur in - [s]. - @since 4.05 */ -@deprecated("Use Core instead. This will be removed in v13") -let rindex_opt: (string, char) => option - -/** [String.index_from s i c] returns the index of the - first occurrence of character [c] in string [s] after position [i]. - [String.index s c] is equivalent to [String.index_from s 0 c]. - - Raise [Invalid_argument] if [i] is not a valid position in [s]. - Raise [Not_found] if [c] does not occur in [s] after position [i]. */ -@deprecated("Use Core instead. This will be removed in v13") -let index_from: (string, int, char) => int - -/** [String.index_from_opt s i c] returns the index of the - first occurrence of character [c] in string [s] after position [i] - or [None] if [c] does not occur in [s] after position [i]. - - [String.index_opt s c] is equivalent to [String.index_from_opt s 0 c]. - Raise [Invalid_argument] if [i] is not a valid position in [s]. - - @since 4.05 -*/ -@deprecated("Use Core instead. This will be removed in v13") -let index_from_opt: (string, int, char) => option - -/** [String.rindex_from s i c] returns the index of the - last occurrence of character [c] in string [s] before position [i+1]. - [String.rindex s c] is equivalent to - [String.rindex_from s (String.length s - 1) c]. - - Raise [Invalid_argument] if [i+1] is not a valid position in [s]. - Raise [Not_found] if [c] does not occur in [s] before position [i+1]. */ -@deprecated("Use Core instead. This will be removed in v13") -let rindex_from: (string, int, char) => int - -/** [String.rindex_from_opt s i c] returns the index of the - last occurrence of character [c] in string [s] before position [i+1] - or [None] if [c] does not occur in [s] before position [i+1]. - - [String.rindex_opt s c] is equivalent to - [String.rindex_from_opt s (String.length s - 1) c]. - - Raise [Invalid_argument] if [i+1] is not a valid position in [s]. - - @since 4.05 -*/ -@deprecated("Use Core instead. This will be removed in v13") -let rindex_from_opt: (string, int, char) => option - -/** [String.contains s c] tests if character [c] - appears in the string [s]. */ -@deprecated("Use Core instead. This will be removed in v13") -let contains: (string, char) => bool - -/** [String.contains_from s start c] tests if character [c] - appears in [s] after position [start]. - [String.contains s c] is equivalent to - [String.contains_from s 0 c]. - - Raise [Invalid_argument] if [start] is not a valid position in [s]. */ -@deprecated("Use Core instead. This will be removed in v13") -let contains_from: (string, int, char) => bool - -/** [String.rcontains_from s stop c] tests if character [c] - appears in [s] before position [stop+1]. - - Raise [Invalid_argument] if [stop < 0] or [stop+1] is not a valid - position in [s]. */ -@deprecated("Use Core instead. This will be removed in v13") -let rcontains_from: (string, int, char) => bool - -/** Return a copy of the argument, with all lowercase letters - translated to uppercase, using the US-ASCII character set. - @since 4.03.0 */ -@deprecated("Use Core instead. This will be removed in v13") -let uppercase_ascii: string => string - -/** Return a copy of the argument, with all uppercase letters - translated to lowercase, using the US-ASCII character set. - @since 4.03.0 */ -@deprecated("Use Core instead. This will be removed in v13") -let lowercase_ascii: string => string - -/** Return a copy of the argument, with the first character set to uppercase, - using the US-ASCII character set. - @since 4.03.0 */ -@deprecated("Use Core instead. This will be removed in v13") -let capitalize_ascii: string => string - -/** Return a copy of the argument, with the first character set to lowercase, - using the US-ASCII character set. - @since 4.03.0 */ -@deprecated("Use Core instead. This will be removed in v13") -let uncapitalize_ascii: string => string - -/** An alias for the type of strings. */ -@deprecated("Use `string` instead. This will be removed in v13") -type t = string - -/** The comparison function for strings, with the same specification as - {!Pervasives.compare}. Along with the type [t], this function [compare] - allows the module [String] to be passed as argument to the functors - {!Set.Make} and {!Map.Make}. */ -@deprecated("Use Core instead. This will be removed in v13") -external compare: (t, t) => int = "%compare" - -/** The equal function for strings. - @since 4.03.0 */ -@deprecated("Use Core instead. This will be removed in v13") -external equal: (t, t) => bool = "%equal" - -/** [String.split_on_char sep s] returns the list of all (possibly empty) - substrings of [s] that are delimited by the [sep] character. - - The function's output is specified by the following invariants: +```rescript +String.trimEnd(" Hello world! ") == " Hello world!" +String.trimEnd(" Hello world! ") == " Hello world!" +``` +*/ +@send +external trimEnd: string => string = "trimEnd" + +/** +`padStart(str, n, padStr)` returns a string that has been padded with `padStr` +(multiple times, if needed) until the resulting string reaches the given `n` +length. The padding is applied from the start of the current string. +See [`String.padStart`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/padStart) on MDN. + +## Examples + +```rescript +String.padStart("abc", 5, " ") == " abc" +String.padStart("abc", 6, "123465") == "123abc" +``` +*/ +@send +external padStart: (string, int, string) => string = "padStart" + +/** +`padEnd(str, n, padStr)` returns a string that has been padded with `padStr` +(multiple times, if needed) until the resulting string reaches the given `n` +length. The padding is applied from the end of the current string. +See [`String.padEnd`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/padEnd) on MDN. + +## Examples - - The list is not empty. - - Concatenating its elements using [sep] as a separator returns a - string equal to the input ([String.concat (String.make 1 sep) - (String.split_on_char sep s) = s]). - - No string in the result contains the [sep] character. - - @since 4.04.0 -*/ -@deprecated("Use Core instead. This will be removed in v13") -let split_on_char: (char, string) => list - -/* The following is for system use only. Do not call directly. */ -@deprecated("Use Core instead. This will be removed in v13") @send -external unsafe_get: (string, int) => char = "codePointAt" +```rescript +String.padEnd("Hello", 10, ".") == "Hello....." +String.padEnd("abc", 1, "") == "abc" +``` +*/ +@send +external padEnd: (string, int, string) => string = "padEnd" + +// TODO: add docs +@get_index external getSymbol: (string, Symbol.t) => option<'a> = "" +@get_index external getSymbolUnsafe: (string, Symbol.t) => 'a = "" +@set_index external setSymbol: (string, Symbol.t, 'a) => unit = "" + +/** +`localeCompare(referenceStr, compareStr)` returns a float than indicatings +whether a reference string comes before or after, or is the same as the given +string in sort order. If `referenceStr` occurs before `compareStr` positive if +the `referenceStr` occurs after `compareStr`, `0` if they are equivalent. +Do not rely on exact return values of `-1` or `1` +See [`String.localeCompare`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/localeCompare) on MDN. + +## Examples + +```rescript +String.localeCompare("a", "c") < 0.0 == true +String.localeCompare("a", "a") == 0.0 +``` +*/ +@send +external localeCompare: (string, string) => float = "localeCompare" diff --git a/runtime/Symbol.res b/runtime/Symbol.res new file mode 100644 index 0000000000..8b4c1b218d --- /dev/null +++ b/runtime/Symbol.res @@ -0,0 +1,19 @@ +type t = Js.Types.symbol + +@val external make: string => t = "Symbol" +@val external getFor: string => t = "Symbol.for" +@val external keyFor: t => option = "Symbol.keyFor" + +@val external asyncIterator: t = "Symbol.asyncIterator" +@val external hasInstance: t = "Symbol.hasInstance" +@val external isConcatSpreadable: t = "Symbol.isConcatSpreadable" +@val external iterator: t = "Symbol.iterator" +@val external match: t = "Symbol.match" +@val external matchAll: t = "Symbol.matchAll" +@val external replace: t = "Symbol.replace" +@val external search: t = "Symbol.search" +@val external species: t = "Symbol.species" +@val external split: t = "Symbol.split" +@val external toPrimitive: t = "Symbol.toPrimitive" +@val external toStringTag: t = "Symbol.toStringTag" +@val external unscopables: t = "Symbol.unscopables" diff --git a/runtime/Type.res b/runtime/Type.res new file mode 100644 index 0000000000..d29bb28c78 --- /dev/null +++ b/runtime/Type.res @@ -0,0 +1,45 @@ +type t = [#undefined | #object | #boolean | #number | #bigint | #string | #symbol | #function] + +external typeof: 'a => t = "#typeof" + +module Classify = { + type function = Js.Types.function_val + type object = Js.Types.obj_val + + type t = + | Bool(bool) + | Null + | Undefined + | String(string) + | Number(float) + | Object(object) + | Function(function) + | Symbol(Symbol.t) + | BigInt(bigint) + + @val external _internalClass: 'a => string = "Object.prototype.toString.call" + external _asBool: 'a => bool = "%identity" + external _asString: 'a => string = "%identity" + external _asFloat: 'a => float = "%identity" + external _asObject: 'a => object = "%identity" + external _asFunction: 'a => function = "%identity" + external _asSymbol: 'a => Symbol.t = "%identity" + external _asBigInt: 'a => bigint = "%identity" + + let classify = value => { + switch _internalClass(value) { + | "[object Boolean]" => Bool(_asBool(value)) + | "[object Null]" => Null + | "[object Undefined]" => Undefined + | "[object String]" => String(_asString(value)) + | "[object Number]" => Number(_asFloat(value)) + | "[object Function]" + | "[object GeneratorFunction]" + | "[object AsyncFunction]" => + Function(_asFunction(value)) + | "[object Symbol]" => Symbol(_asSymbol(value)) + | "[object BigInt]" => BigInt(_asBigInt(value)) + | _ => Object(_asObject(value)) + } + } +} diff --git a/runtime/Type.resi b/runtime/Type.resi new file mode 100644 index 0000000000..ee6519b653 --- /dev/null +++ b/runtime/Type.resi @@ -0,0 +1,77 @@ +/*** +Utilities for classifying the type of JavaScript values at runtime. +*/ + +/** +The possible types of JavaScript values. +*/ +type t = [#undefined | #object | #boolean | #number | #bigint | #string | #symbol | #function] + +/** +`typeof(someValue)` + +Returns the underlying JavaScript type of any runtime value. + +See [`typeof`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/typeof) on MDN. + +## Examples +```rescript +Console.log(Type.typeof("Hello")) // Logs "string" to the console. + +let someVariable = true + +switch someVariable->Type.typeof { +| #boolean => Console.log("This is a bool, yay!") +| _ => Console.log("Oh, not a bool sadly...") +} +``` +*/ +external typeof: 'a => t = "#typeof" + +module Classify: { + /*** + Classifies JavaScript runtime values. + */ + + /** + An abstract type representing a JavaScript function. + + See [`function`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function) on MDN. + */ + type function + + /** + An abstract type representing a JavaScript object. + + See [`object`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object) on MDN. + */ + type object + + /** + The type representing a classified JavaScript value. + */ + type t = + | Bool(bool) + | Null + | Undefined + | String(string) + | Number(float) + | Object(object) + | Function(function) + | Symbol(Symbol.t) + | BigInt(bigint) + + /** +`classify(anyValue)` +Classifies a JavaScript value. + +## Examples +```rescript +switch %raw(`null`)->Type.Classify.classify { +| Null => Console.log("Yup, that's null.") +| _ => Console.log("This doesn't actually appear to be null...") +} +``` +*/ + let classify: 'a => t +} diff --git a/runtime/TypedArray.res b/runtime/TypedArray.res new file mode 100644 index 0000000000..35ccbc4fa3 --- /dev/null +++ b/runtime/TypedArray.res @@ -0,0 +1,77 @@ +type t<'a> + +@get_index external get: (t<'a>, int) => option<'a> = "" +@set_index external set: (t<'a>, int, 'a) => unit = "" + +@get external buffer: t<'a> => ArrayBuffer.t = "buffer" +@get external byteLength: t<'a> => int = "byteLength" +@get external byteOffset: t<'a> => int = "byteOffset" + +@send external setArray: (t<'a>, array<'a>) => unit = "set" +@send external setArrayFrom: (t<'a>, array<'a>, int) => unit = "set" + +@get external length: t<'a> => int = "length" + +@send external copyAllWithin: (t<'a>, ~target: int) => array<'a> = "copyWithin" +@send external copyWithinToEnd: (t<'a>, ~target: int, ~start: int) => array<'a> = "copyWithin" +@send +external copyWithin: (t<'a>, ~target: int, ~start: int, ~end: int) => array<'a> = "copyWithin" + +@send external fillAll: (t<'a>, 'a) => t<'a> = "fill" +@send external fillToEnd: (t<'a>, 'a, ~start: int) => t<'a> = "fill" +@send external fill: (t<'a>, 'a, ~start: int, ~end: int) => t<'a> = "fill" + +@send external reverse: t<'a> => unit = "reverse" +@send external toReversed: t<'a> => t<'a> = "toReversed" + +@send external sort: (t<'a>, ('a, 'a) => Ordering.t) => unit = "sort" +@send external toSorted: (t<'a>, ('a, 'a) => Ordering.t) => t<'a> = "toSorted" + +@send external with: (t<'a>, int, 'a) => t<'a> = "with" + +@send external includes: (t<'a>, 'a) => bool = "includes" + +@send external indexOf: (t<'a>, 'a) => int = "indexOf" +@send external indexOfFrom: (t<'a>, 'a, int) => int = "indexOf" + +@send external joinWith: (t<'a>, string) => string = "join" + +@send external lastIndexOf: (t<'a>, 'a) => int = "lastIndexOf" +@send external lastIndexOfFrom: (t<'a>, 'a, int) => int = "lastIndexOf" + +@send external slice: (t<'a>, ~start: int, ~end: int) => t<'a> = "slice" +@send external sliceToEnd: (t<'a>, ~start: int) => t<'a> = "slice" +@send external copy: t<'a> => t<'a> = "slice" + +@send external subarray: (t<'a>, ~start: int, ~end: int) => t<'a> = "subarray" +@send external subarrayToEnd: (t<'a>, ~start: int) => t<'a> = "subarray" + +@send external toString: t<'a> => string = "toString" +@send external toLocaleString: t<'a> => string = "toLocaleString" + +@send external every: (t<'a>, 'a => bool) => bool = "every" +@send external everyWithIndex: (t<'a>, ('a, int) => bool) => bool = "every" + +@send external filter: (t<'a>, 'a => bool) => t<'a> = "filter" +@send external filterWithIndex: (t<'a>, ('a, int) => bool) => t<'a> = "filter" + +@send external find: (t<'a>, 'a => bool) => option<'a> = "find" +@send external findWithIndex: (t<'a>, ('a, int) => bool) => option<'a> = "find" + +@send external findIndex: (t<'a>, 'a => bool) => int = "findIndex" +@send external findIndexWithIndex: (t<'a>, ('a, int) => bool) => int = "findIndex" + +@send external forEach: (t<'a>, 'a => unit) => unit = "forEach" +@send external forEachWithIndex: (t<'a>, ('a, int) => unit) => unit = "forEach" + +@send external map: (t<'a>, 'a => 'b) => t<'b> = "map" +@send external mapWithIndex: (t<'a>, ('a, int) => 'b) => t<'b> = "map" + +@send external reduce: (t<'a>, ('b, 'a) => 'b, 'b) => 'b = "reduce" +@send external reduceWithIndex: (t<'a>, ('b, 'a, int) => 'b, 'b) => 'b = "reduce" + +@send external reduceRight: (t<'a>, ('b, 'a) => 'b, 'b) => 'b = "reduceRight" +@send external reduceRightWithIndex: (t<'a>, ('b, 'a, int) => 'b, 'b) => 'b = "reduceRight" + +@send external some: (t<'a>, 'a => bool) => bool = "some" +@send external someWithIndex: (t<'a>, ('a, int) => bool) => bool = "some" diff --git a/runtime/Uint16Array.res b/runtime/Uint16Array.res new file mode 100644 index 0000000000..115caf8a2f --- /dev/null +++ b/runtime/Uint16Array.res @@ -0,0 +1,53 @@ +/** The `Uint16Array` typed array represents an array of 16-bit unsigned integers in platform byte order. See [Uint16Array on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint16Array) +*/ +type t = TypedArray.t + +module Constants = { + /**`bytesPerElement` returns the element size. See [BYTES_PER_ELEMENT on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray/BYTES_PER_ELEMENT) + */ + @val + external bytesPerElement: int = "Uint16Array.BYTES_PER_ELEMENT" +} + +/** `fromArray` creates a `Uint16Array` from an array of values. See [TypedArray constructor on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint16Array/Uint16Array) +*/ +@new +external fromArray: array => t = "Uint16Array" + +/** `fromBuffer` creates a `Uint16Array` from an `ArrayBuffer.t`. See [TypedArray constructor on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint16Array/Uint16Array) + +**Note:** This is a potentially unsafe operation. Ensure the buffer is large enough and only accessed within its bounds. +*/ +@new +external fromBuffer: ArrayBuffer.t => t = "Uint16Array" + +/** `fromBufferToEnd` creates a `Uint16Array` from an `ArrayBuffer.t`, starting at a particular offset and continuing through to the end. See [TypedArray constructor on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint16Array/Uint16Array) + +**Note:** This is a potentially unsafe operation. Ensure the buffer is large enough and only accessed within its bounds. +*/ +@new +external fromBufferToEnd: (ArrayBuffer.t, ~byteOffset: int) => t = "Uint16Array" + +/** `fromBufferWithRange` creates a `Uint16Array` from an `ArrayBuffer.t`, starting at a particular offset and consuming `length` **bytes**. See [TypedArray constructor on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint16Array/Uint16Array) + +**Note:** This is a potentially unsafe operation. Ensure the buffer is large enough and only accessed within its bounds. +*/ +@new +external fromBufferWithRange: (ArrayBuffer.t, ~byteOffset: int, ~length: int) => t = "Uint16Array" + +/** `fromLength` creates a zero-initialized `Uint16Array` to hold the specified count of numbers; this is **not** a byte length. See [TypedArray constructor on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint16Array/Uint16Array) + +**Note:** This is a potentially unsafe operation. Ensure the buffer is large enough and only accessed within its bounds. +*/ +@new +external fromLength: int => t = "Uint16Array" + +/** `fromArrayLikeOrIterable` creates a `Uint16Array` from an array-like or iterable object. See [TypedArray.from on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray/from) +*/ +@val +external fromArrayLikeOrIterable: 'a => t = "Uint16Array.from" + +/** `fromArrayLikeOrIterableWithMap` creates a `Uint16Array` from an array-like or iterable object and applies the mapping function to each item. The mapping function expects (value, index). See [TypedArray.from on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray/from) +*/ +@val +external fromArrayLikeOrIterableWithMap: ('a, ('b, int) => int) => t = "Uint16Array.from" diff --git a/runtime/Uint32Array.res b/runtime/Uint32Array.res new file mode 100644 index 0000000000..ba6693054a --- /dev/null +++ b/runtime/Uint32Array.res @@ -0,0 +1,53 @@ +/** The `Uint32Array` typed array represents an array of 32-bit unsigned integers in platform byte order. See [Uint32Array on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint32Array) +*/ +type t = TypedArray.t + +module Constants = { + /**`bytesPerElement` returns the element size. See [BYTES_PER_ELEMENT on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray/BYTES_PER_ELEMENT) + */ + @val + external bytesPerElement: int = "Uint32Array.BYTES_PER_ELEMENT" +} + +/** `fromArray` creates a `Uint32Array` from an array of values. See [TypedArray constructor on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint32Array/Uint32Array) +*/ +@new +external fromArray: array => t = "Uint32Array" + +/** `fromBuffer` creates a `Uint32Array` from an `ArrayBuffer.t`. See [TypedArray constructor on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint32Array/Uint32Array) + +**Note:** This is a potentially unsafe operation. Ensure the buffer is large enough and only accessed within its bounds. +*/ +@new +external fromBuffer: ArrayBuffer.t => t = "Uint32Array" + +/** `fromBufferToEnd` creates a `Uint32Array` from an `ArrayBuffer.t`, starting at a particular offset and continuing through to the end. See [TypedArray constructor on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint32Array/Uint32Array) + +**Note:** This is a potentially unsafe operation. Ensure the buffer is large enough and only accessed within its bounds. +*/ +@new +external fromBufferToEnd: (ArrayBuffer.t, ~byteOffset: int) => t = "Uint32Array" + +/** `fromBufferWithRange` creates a `Uint32Array` from an `ArrayBuffer.t`, starting at a particular offset and consuming `length` **bytes**. See [TypedArray constructor on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint32Array/Uint32Array) + +**Note:** This is a potentially unsafe operation. Ensure the buffer is large enough and only accessed within its bounds. +*/ +@new +external fromBufferWithRange: (ArrayBuffer.t, ~byteOffset: int, ~length: int) => t = "Uint32Array" + +/** `fromLength` creates a zero-initialized `Uint32Array` to hold the specified count of numbers; this is **not** a byte length. See [TypedArray constructor on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint32Array/Uint32Array) + +**Note:** This is a potentially unsafe operation. Ensure the buffer is large enough and only accessed within its bounds. +*/ +@new +external fromLength: int => t = "Uint32Array" + +/** `fromArrayLikeOrIterable` creates a `Uint32Array` from an array-like or iterable object. See [TypedArray.from on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray/from) +*/ +@val +external fromArrayLikeOrIterable: 'a => t = "Uint32Array.from" + +/** `fromArrayLikeOrIterableWithMap` creates a `Uint32Array` from an array-like or iterable object and applies the mapping function to each item. The mapping function expects (value, index). See [TypedArray.from on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray/from) +*/ +@val +external fromArrayLikeOrIterableWithMap: ('a, ('b, int) => int) => t = "Uint32Array.from" diff --git a/runtime/Uint8Array.res b/runtime/Uint8Array.res new file mode 100644 index 0000000000..2233a039b3 --- /dev/null +++ b/runtime/Uint8Array.res @@ -0,0 +1,53 @@ +/** The `Uint8Array` typed array represents an array of 8-bit unsigned integers. See [Uint8Array on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array) +*/ +type t = TypedArray.t + +module Constants = { + /**`bytesPerElement` returns the element size. See [BYTES_PER_ELEMENT on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray/BYTES_PER_ELEMENT) + */ + @val + external bytesPerElement: int = "Uint8Array.BYTES_PER_ELEMENT" +} + +/** `fromArray` creates a `Uint8Array` from an array of values. See [TypedArray constructor on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array/Uint8Array) +*/ +@new +external fromArray: array => t = "Uint8Array" + +/** `fromBuffer` creates a `Uint8Array` from an `ArrayBuffer.t`. See [TypedArray constructor on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array/Uint8Array) + +**Note:** This is a potentially unsafe operation. Ensure the buffer is large enough and only accessed within its bounds. +*/ +@new +external fromBuffer: ArrayBuffer.t => t = "Uint8Array" + +/** `fromBufferToEnd` creates a `Uint8Array` from an `ArrayBuffer.t`, starting at a particular offset and continuing through to the end. See [TypedArray constructor on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array/Uint8Array) + +**Note:** This is a potentially unsafe operation. Ensure the buffer is large enough and only accessed within its bounds. +*/ +@new +external fromBufferToEnd: (ArrayBuffer.t, ~byteOffset: int) => t = "Uint8Array" + +/** `fromBufferWithRange` creates a `Uint8Array` from an `ArrayBuffer.t`, starting at a particular offset and consuming `length` **bytes**. See [TypedArray constructor on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array/Uint8Array) + +**Note:** This is a potentially unsafe operation. Ensure the buffer is large enough and only accessed within its bounds. +*/ +@new +external fromBufferWithRange: (ArrayBuffer.t, ~byteOffset: int, ~length: int) => t = "Uint8Array" + +/** `fromLength` creates a zero-initialized `Uint8Array` to hold the specified count of numbers; this is **not** a byte length. See [TypedArray constructor on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array/Uint8Array) + +**Note:** This is a potentially unsafe operation. Ensure the buffer is large enough and only accessed within its bounds. +*/ +@new +external fromLength: int => t = "Uint8Array" + +/** `fromArrayLikeOrIterable` creates a `Uint8Array` from an array-like or iterable object. See [TypedArray.from on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray/from) +*/ +@val +external fromArrayLikeOrIterable: 'a => t = "Uint8Array.from" + +/** `fromArrayLikeOrIterableWithMap` creates a `Uint8Array` from an array-like or iterable object and applies the mapping function to each item. The mapping function expects (value, index). See [TypedArray.from on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray/from) +*/ +@val +external fromArrayLikeOrIterableWithMap: ('a, ('b, int) => int) => t = "Uint8Array.from" diff --git a/runtime/Uint8ClampedArray.res b/runtime/Uint8ClampedArray.res new file mode 100644 index 0000000000..633dd4ca18 --- /dev/null +++ b/runtime/Uint8ClampedArray.res @@ -0,0 +1,54 @@ +/** The `Uint8ClampedArray` typed array represents an array of 8-bit unsigned integers clamped to 0-255. See [Uint8ClampedArray on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8ClampedArray) +*/ +type t = TypedArray.t + +module Constants = { + /**`bytesPerElement` returns the element size. See [BYTES_PER_ELEMENT on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray/BYTES_PER_ELEMENT) + */ + @val + external bytesPerElement: int = "Uint8ClampedArray.BYTES_PER_ELEMENT" +} + +/** `fromArray` creates a `Uint8ClampedArray` from an array of values. See [TypedArray constructor on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8ClampedArray/Uint8ClampedArray) +*/ +@new +external fromArray: array => t = "Uint8ClampedArray" + +/** `fromBuffer` creates a `Uint8ClampedArray` from an `ArrayBuffer.t`. See [TypedArray constructor on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8ClampedArray/Uint8ClampedArray) + +**Note:** This is a potentially unsafe operation. Ensure the buffer is large enough and only accessed within its bounds. +*/ +@new +external fromBuffer: ArrayBuffer.t => t = "Uint8ClampedArray" + +/** `fromBufferToEnd` creates a `Uint8ClampedArray` from an `ArrayBuffer.t`, starting at a particular offset and continuing through to the end. See [TypedArray constructor on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8ClampedArray/Uint8ClampedArray) + +**Note:** This is a potentially unsafe operation. Ensure the buffer is large enough and only accessed within its bounds. +*/ +@new +external fromBufferToEnd: (ArrayBuffer.t, ~byteOffset: int) => t = "Uint8ClampedArray" + +/** `fromBufferWithRange` creates a `Uint8ClampedArray` from an `ArrayBuffer.t`, starting at a particular offset and consuming `length` **bytes**. See [TypedArray constructor on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8ClampedArray/Uint8ClampedArray) + +**Note:** This is a potentially unsafe operation. Ensure the buffer is large enough and only accessed within its bounds. +*/ +@new +external fromBufferWithRange: (ArrayBuffer.t, ~byteOffset: int, ~length: int) => t = + "Uint8ClampedArray" + +/** `fromLength` creates a zero-initialized `Uint8ClampedArray` to hold the specified count of numbers; this is **not** a byte length. See [TypedArray constructor on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8ClampedArray/Uint8ClampedArray) + +**Note:** This is a potentially unsafe operation. Ensure the buffer is large enough and only accessed within its bounds. +*/ +@new +external fromLength: int => t = "Uint8ClampedArray" + +/** `fromArrayLikeOrIterable` creates a `Uint8ClampedArray` from an array-like or iterable object. See [TypedArray.from on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray/from) +*/ +@val +external fromArrayLikeOrIterable: 'a => t = "Uint8ClampedArray.from" + +/** `fromArrayLikeOrIterableWithMap` creates a `Uint8ClampedArray` from an array-like or iterable object and applies the mapping function to each item. The mapping function expects (value, index). See [TypedArray.from on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray/from) +*/ +@val +external fromArrayLikeOrIterableWithMap: ('a, ('b, int) => int) => t = "Uint8ClampedArray.from" diff --git a/runtime/WeakMap.res b/runtime/WeakMap.res new file mode 100644 index 0000000000..4bc91810da --- /dev/null +++ b/runtime/WeakMap.res @@ -0,0 +1,8 @@ +type t<'k, 'v> = Js.WeakMap.t<'k, 'v> + +@new external make: unit => t<'k, 'v> = "WeakMap" + +@send external get: (t<'k, 'v>, 'k) => option<'v> = "get" +@send external has: (t<'k, 'v>, 'k) => bool = "has" +@send external set: (t<'k, 'v>, 'k, 'v) => t<'k, 'v> = "set" +@send external delete: (t<'k, 'v>, 'k) => bool = "delete" diff --git a/runtime/WeakSet.res b/runtime/WeakSet.res new file mode 100644 index 0000000000..851329c80d --- /dev/null +++ b/runtime/WeakSet.res @@ -0,0 +1,7 @@ +type t<'a> = Js.WeakSet.t<'a> + +@new external make: unit => t<'a> = "WeakSet" + +@send external add: (t<'a>, 'a) => t<'a> = "add" +@send external delete: (t<'a>, 'a) => bool = "delete" +@send external has: (t<'a>, 'a) => bool = "has" diff --git a/runtime/rescript.json b/runtime/rescript.json index 2ec055d9db..abb683bc73 100644 --- a/runtime/rescript.json +++ b/runtime/rescript.json @@ -9,7 +9,7 @@ "-make-runtime", "-nostdlib", "-nopervasives", - "-open Pervasives", + "-open Pervasives_mini", "-no-keep-locs", "-no-alias-deps", "-bs-no-version-header", diff --git a/scripts/buildRuntime.sh b/scripts/buildRuntime.sh index 17ab6f13dc..8cf8ad5e92 100755 --- a/scripts/buildRuntime.sh +++ b/scripts/buildRuntime.sh @@ -2,14 +2,16 @@ set -e shopt -s extglob +(cd runtime && ../cli/rescript clean) + rm -f lib/es6/*.js lib/js/*.js lib/ocaml/* mkdir -p lib/es6 lib/js lib/ocaml mkdir -p runtime/lib/es6 runtime/lib/js (cd runtime && ../cli/rescript build) -cp runtime/lib/es6/*.js lib/es6 -cp runtime/lib/js/*.js lib/js -cp runtime/lib/bs/!(belt_internal*).cmi lib/ocaml/ -cp runtime/lib/bs/*.@(cmj|cmt|cmti) lib/ocaml/ -cp runtime/*.@(res|resi) lib/ocaml/ +cp runtime/lib/es6/!(Pervasives_mini).js lib/es6 +cp runtime/lib/js/!(Pervasives_mini).js lib/js +cp runtime/lib/bs/!(Pervasives_mini|Belt_internal*).cmi lib/ocaml/ +cp runtime/lib/bs/!(Pervasives_mini).@(cmi|cmj|cmt|cmti) lib/ocaml/ +cp runtime/!(Pervasives_mini).@(res|resi) lib/ocaml/ diff --git a/tests/tests/src/UntaggedVariants.js b/tests/tests/src/UntaggedVariants.js index f464f089b0..c819b5b3c7 100644 --- a/tests/tests/src/UntaggedVariants.js +++ b/tests/tests/src/UntaggedVariants.js @@ -600,6 +600,8 @@ let MergeCases = { can_merge: can_merge }; +let $$Array; + let i = 42; let i2 = 42.5; @@ -613,6 +615,7 @@ let w = { y: "" }; +exports.$$Array = $$Array; exports.i = i; exports.i2 = i2; exports.s = s; diff --git a/tests/tests/src/UntaggedVariants.res b/tests/tests/src/UntaggedVariants.res index 3972053a72..2644c010d6 100644 --- a/tests/tests/src/UntaggedVariants.res +++ b/tests/tests/src/UntaggedVariants.res @@ -1,3 +1,5 @@ +module Array = Ocaml_Array + @unboxed type t = A | I(int) | S(string) @unboxed diff --git a/tests/tests/src/alias_test.res b/tests/tests/src/alias_test.res index d72b52c547..40b333461e 100644 --- a/tests/tests/src/alias_test.res +++ b/tests/tests/src/alias_test.res @@ -1,3 +1,5 @@ +module String = Ocaml_String + let a0 = "hello " let a1 = a0 diff --git a/tests/tests/src/array_safe_get.js b/tests/tests/src/array_safe_get.js index 0ba0e474b1..1f08bf078c 100644 --- a/tests/tests/src/array_safe_get.js +++ b/tests/tests/src/array_safe_get.js @@ -23,6 +23,9 @@ try { } } +let $$Array; + +exports.$$Array = $$Array; exports.x = x; exports.y = y; /* y Not a pure module */ diff --git a/tests/tests/src/array_safe_get.res b/tests/tests/src/array_safe_get.res index 436efebb50..50113f5b9d 100644 --- a/tests/tests/src/array_safe_get.res +++ b/tests/tests/src/array_safe_get.res @@ -1,3 +1,5 @@ +module Array = Ocaml_Array + let x = [1, 2] let y = try x[3] catch { | Invalid_argument(msg) => diff --git a/tests/tests/src/array_subtle_test.js b/tests/tests/src/array_subtle_test.js index 2046a8ac88..c8d11befb2 100644 --- a/tests/tests/src/array_subtle_test.js +++ b/tests/tests/src/array_subtle_test.js @@ -36,34 +36,34 @@ let v = [ 3 ]; -eq("File \"array_subtle_test.res\", line 14, characters 12-19", [ +eq("File \"array_subtle_test.res\", line 16, characters 12-19", [ 4, v.length ]); -eq("File \"array_subtle_test.res\", line 17, characters 5-12", [ +eq("File \"array_subtle_test.res\", line 19, characters 5-12", [ 5, v.push(3) ]); -eq("File \"array_subtle_test.res\", line 18, characters 5-12", [ +eq("File \"array_subtle_test.res\", line 20, characters 5-12", [ 5, v.length ]); -eq("File \"array_subtle_test.res\", line 19, characters 5-12", [ +eq("File \"array_subtle_test.res\", line 21, characters 5-12", [ 5, v.length ]); -eq("File \"array_subtle_test.res\", line 23, characters 5-12", [ +eq("File \"array_subtle_test.res\", line 25, characters 5-12", [ 3, Primitive_array.get(v, 2) ]); Primitive_array.set(v, 2, 4); -eq("File \"array_subtle_test.res\", line 25, characters 5-12", [ +eq("File \"array_subtle_test.res\", line 27, characters 5-12", [ 4, Primitive_array.get(v, 2) ]); @@ -72,7 +72,7 @@ while (v.length > 0) { v.pop(); }; -eq("File \"array_subtle_test.res\", line 32, characters 5-12", [ +eq("File \"array_subtle_test.res\", line 34, characters 5-12", [ 0, v.length ]); @@ -111,23 +111,26 @@ function fff4(x) { } } -eq("File \"array_subtle_test.res\", line 64, characters 3-10", [ +eq("File \"array_subtle_test.res\", line 66, characters 3-10", [ fff3([]), 1 ]); -eq("File \"array_subtle_test.res\", line 65, characters 3-10", [ +eq("File \"array_subtle_test.res\", line 67, characters 3-10", [ fff4([]), 2 ]); -eq("File \"array_subtle_test.res\", line 66, characters 3-10", [ +eq("File \"array_subtle_test.res\", line 68, characters 3-10", [ fff4([1]), 1 ]); Mt.from_pair_suites("Array_subtle_test", suites.contents); +let $$Array; + +exports.$$Array = $$Array; exports.suites = suites; exports.test_id = test_id; exports.eq = eq; diff --git a/tests/tests/src/array_subtle_test.res b/tests/tests/src/array_subtle_test.res index a24b8a460e..eccff87e3f 100644 --- a/tests/tests/src/array_subtle_test.res +++ b/tests/tests/src/array_subtle_test.res @@ -1,3 +1,5 @@ +module Array = Ocaml_Array + let suites: ref = ref(list{}) let test_id = ref(0) let eq = (loc, (x, y)) => { diff --git a/tests/tests/src/async_await.js b/tests/tests/src/async_await.js index 6bc2c04245..670f6a7869 100644 --- a/tests/tests/src/async_await.js +++ b/tests/tests/src/async_await.js @@ -1,7 +1,6 @@ // Generated by ReScript, PLEASE EDIT WITH CARE 'use strict'; -let Primitive_array = require("rescript/lib/js/Primitive_array.js"); function next(n) { return n + 1 | 0; @@ -30,7 +29,7 @@ let arr = [ let toplevelAwait = await topFoo(); -let toplevelAwait2 = Primitive_array.get(arr, await topFoo()); +let toplevelAwait2 = arr[await topFoo()]; async function f(value) { return await Promise.resolve(1); diff --git a/tests/tests/src/bdd.js b/tests/tests/src/bdd.js index b09df2a166..60d94b46e7 100644 --- a/tests/tests/src/bdd.js +++ b/tests/tests/src/bdd.js @@ -72,7 +72,7 @@ function resize(newSize) { RE_EXN_ID: "Assert_failure", _1: [ "bdd.res", - 60, + 62, 13 ], Error: new Error() @@ -82,7 +82,7 @@ function resize(newSize) { RE_EXN_ID: "Assert_failure", _1: [ "bdd.res", - 60, + 62, 13 ], Error: new Error() @@ -148,7 +148,7 @@ function mkNode(low, v, high) { RE_EXN_ID: "Assert_failure", _1: [ "bdd.res", - 121, + 123, 15 ], Error: new Error() @@ -158,7 +158,7 @@ function mkNode(low, v, high) { RE_EXN_ID: "Assert_failure", _1: [ "bdd.res", - 121, + 123, 15 ], Error: new Error() @@ -403,7 +403,7 @@ function main() { RE_EXN_ID: "Assert_failure", _1: [ "bdd.res", - 302, + 304, 2 ], Error: new Error() @@ -412,6 +412,8 @@ function main() { main(); +let $$Array; + let initSize_1 = 8191; let zero = "Zero"; @@ -420,6 +422,7 @@ let one = "One"; let cacheSize = 1999; +exports.$$Array = $$Array; exports.$$eval = $$eval; exports.getId = getId; exports.initSize_1 = initSize_1; diff --git a/tests/tests/src/bdd.res b/tests/tests/src/bdd.res index 3b22084a5e..e956cf2050 100644 --- a/tests/tests/src/bdd.res +++ b/tests/tests/src/bdd.res @@ -15,6 +15,8 @@ /* Translated to Caml by Xavier Leroy */ /* Original code written in SML by ... */ +module Array = Ocaml_Array + type rec bdd = One | Zero | Node(bdd, int, int, bdd) let rec eval = (bdd, vars) => diff --git a/tests/tests/src/belt_hashmap_test.js b/tests/tests/src/belt_hashmap_test.js index 1352ab03ec..7feb63329e 100644 --- a/tests/tests/src/belt_hashmap_test.js +++ b/tests/tests/src/belt_hashmap_test.js @@ -3,10 +3,10 @@ let Mocha = require("mocha"); let Belt_Id = require("rescript/lib/js/Belt_Id.js"); -let Hashtbl = require("rescript/lib/js/Hashtbl.js"); let Belt_Array = require("rescript/lib/js/Belt_Array.js"); let Test_utils = require("./test_utils.js"); let Belt_HashMap = require("rescript/lib/js/Belt_HashMap.js"); +let Ocaml_Hashtbl = require("./ocaml_compat/Ocaml_Hashtbl.js"); let Primitive_int = require("rescript/lib/js/Primitive_int.js"); let Belt_SortArray = require("rescript/lib/js/Belt_SortArray.js"); let Array_data_util = require("./array_data_util.js"); @@ -15,7 +15,7 @@ function intEq(x, y) { return x === y; } -let intHash = Hashtbl.hash; +let intHash = Ocaml_Hashtbl.hash; let cmp = Primitive_int.compare; @@ -28,8 +28,8 @@ Mocha.describe("Belt_hashmap_test", () => { let u = Belt_Array.concat(Array_data_util.randomRange(30, 100), Array_data_util.randomRange(40, 120)); let v = Belt_Array.zip(u, u); let xx = Belt_HashMap.fromArray(v, Y); - Test_utils.eq("File \"belt_hashmap_test.res\", line 21, characters 7-14", Belt_HashMap.size(xx), 91); - Test_utils.eq("File \"belt_hashmap_test.res\", line 22, characters 7-14", Belt_SortArray.stableSortBy(Belt_HashMap.keysToArray(xx), cmp), Array_data_util.range(30, 120)); + Test_utils.eq("File \"belt_hashmap_test.res\", line 22, characters 7-14", Belt_HashMap.size(xx), 91); + Test_utils.eq("File \"belt_hashmap_test.res\", line 23, characters 7-14", Belt_SortArray.stableSortBy(Belt_HashMap.keysToArray(xx), cmp), Array_data_util.range(30, 120)); }); Mocha.test("mergeMany", () => { Belt_HashMap.mergeMany(empty, [ @@ -50,26 +50,28 @@ Mocha.describe("Belt_hashmap_test", () => { 2 ] ]); - Test_utils.eq("File \"belt_hashmap_test.res\", line 27, characters 7-14", Belt_HashMap.get(empty, 2), 2); - Test_utils.eq("File \"belt_hashmap_test.res\", line 28, characters 7-14", Belt_HashMap.size(empty), 3); + Test_utils.eq("File \"belt_hashmap_test.res\", line 28, characters 7-14", Belt_HashMap.get(empty, 2), 2); + Test_utils.eq("File \"belt_hashmap_test.res\", line 29, characters 7-14", Belt_HashMap.size(empty), 3); }); Mocha.test("remove", () => { let u = Belt_Array.concat(Array_data_util.randomRange(0, 100000), Array_data_util.randomRange(0, 100)); let v = Belt_HashMap.make(40, Y); Belt_HashMap.mergeMany(v, Belt_Array.zip(u, u)); - Test_utils.eq("File \"belt_hashmap_test.res\", line 35, characters 7-14", Belt_HashMap.size(v), 100001); + Test_utils.eq("File \"belt_hashmap_test.res\", line 36, characters 7-14", Belt_HashMap.size(v), 100001); for (let i = 0; i <= 1000; ++i) { Belt_HashMap.remove(v, i); } - Test_utils.eq("File \"belt_hashmap_test.res\", line 39, characters 7-14", Belt_HashMap.size(v), 99000); + Test_utils.eq("File \"belt_hashmap_test.res\", line 40, characters 7-14", Belt_HashMap.size(v), 99000); for (let i$1 = 0; i$1 <= 2000; ++i$1) { Belt_HashMap.remove(v, i$1); } - Test_utils.eq("File \"belt_hashmap_test.res\", line 43, characters 7-14", Belt_HashMap.size(v), 98000); - Test_utils.ok("File \"belt_hashmap_test.res\", line 44, characters 7-14", Belt_Array.every(Array_data_util.range(2001, 100000), x => Belt_HashMap.has(v, x))); + Test_utils.eq("File \"belt_hashmap_test.res\", line 44, characters 7-14", Belt_HashMap.size(v), 98000); + Test_utils.ok("File \"belt_hashmap_test.res\", line 45, characters 7-14", Belt_Array.every(Array_data_util.range(2001, 100000), x => Belt_HashMap.has(v, x))); }); }); +let Hashtbl; + let N; let S; @@ -80,6 +82,7 @@ let A; let So; +exports.Hashtbl = Hashtbl; exports.N = N; exports.S = S; exports.I = I; diff --git a/tests/tests/src/belt_hashmap_test.res b/tests/tests/src/belt_hashmap_test.res index fe53ee54ed..d9253f3f46 100644 --- a/tests/tests/src/belt_hashmap_test.res +++ b/tests/tests/src/belt_hashmap_test.res @@ -1,6 +1,7 @@ open Mocha open Test_utils +module Hashtbl = Ocaml_Hashtbl module N = Belt.HashMap module S = Belt.Map.Int module I = Array_data_util diff --git a/tests/tests/src/bs_mutable_set_test.js b/tests/tests/src/bs_mutable_set_test.js index b895202553..68c62db52d 100644 --- a/tests/tests/src/bs_mutable_set_test.js +++ b/tests/tests/src/bs_mutable_set_test.js @@ -27,21 +27,21 @@ function b(loc, x) { let u = Belt_MutableSetInt.fromArray(Array_data_util.range(0, 30)); -b("File \"bs_mutable_set_test.res\", line 21, characters 8-15", Belt_MutableSetInt.removeCheck(u, 0)); +b("File \"bs_mutable_set_test.res\", line 22, characters 8-15", Belt_MutableSetInt.removeCheck(u, 0)); -b("File \"bs_mutable_set_test.res\", line 22, characters 8-15", !Belt_MutableSetInt.removeCheck(u, 0)); +b("File \"bs_mutable_set_test.res\", line 23, characters 8-15", !Belt_MutableSetInt.removeCheck(u, 0)); -b("File \"bs_mutable_set_test.res\", line 23, characters 8-15", Belt_MutableSetInt.removeCheck(u, 30)); +b("File \"bs_mutable_set_test.res\", line 24, characters 8-15", Belt_MutableSetInt.removeCheck(u, 30)); -b("File \"bs_mutable_set_test.res\", line 24, characters 8-15", Belt_MutableSetInt.removeCheck(u, 20)); +b("File \"bs_mutable_set_test.res\", line 25, characters 8-15", Belt_MutableSetInt.removeCheck(u, 20)); -eq("File \"bs_mutable_set_test.res\", line 25, characters 9-16", Belt_MutableSetInt.size(u), 28); +eq("File \"bs_mutable_set_test.res\", line 26, characters 9-16", Belt_MutableSetInt.size(u), 28); let r = Array_data_util.randomRange(0, 30); -b("File \"bs_mutable_set_test.res\", line 27, characters 8-15", 29 === Belt_MutableSetInt.maxUndefined(u)); +b("File \"bs_mutable_set_test.res\", line 28, characters 8-15", 29 === Belt_MutableSetInt.maxUndefined(u)); -b("File \"bs_mutable_set_test.res\", line 28, characters 8-15", 1 === Belt_MutableSetInt.minUndefined(u)); +b("File \"bs_mutable_set_test.res\", line 29, characters 8-15", 1 === Belt_MutableSetInt.minUndefined(u)); Belt_MutableSetInt.add(u, 3); @@ -49,7 +49,7 @@ for (let i = 0, i_finish = r.length; i < i_finish; ++i) { Belt_MutableSetInt.remove(u, r[i]); } -b("File \"bs_mutable_set_test.res\", line 33, characters 8-15", Belt_MutableSetInt.isEmpty(u)); +b("File \"bs_mutable_set_test.res\", line 34, characters 8-15", Belt_MutableSetInt.isEmpty(u)); Belt_MutableSetInt.add(u, 0); @@ -59,47 +59,47 @@ Belt_MutableSetInt.add(u, 2); Belt_MutableSetInt.add(u, 0); -eq("File \"bs_mutable_set_test.res\", line 38, characters 9-16", Belt_MutableSetInt.size(u), 3); +eq("File \"bs_mutable_set_test.res\", line 39, characters 9-16", Belt_MutableSetInt.size(u), 3); -b("File \"bs_mutable_set_test.res\", line 39, characters 8-15", !Belt_MutableSetInt.isEmpty(u)); +b("File \"bs_mutable_set_test.res\", line 40, characters 8-15", !Belt_MutableSetInt.isEmpty(u)); for (let i$1 = 0; i$1 <= 3; ++i$1) { Belt_MutableSetInt.remove(u, i$1); } -b("File \"bs_mutable_set_test.res\", line 43, characters 8-15", Belt_MutableSetInt.isEmpty(u)); +b("File \"bs_mutable_set_test.res\", line 44, characters 8-15", Belt_MutableSetInt.isEmpty(u)); Belt_MutableSetInt.mergeMany(u, Array_data_util.randomRange(0, 20000)); Belt_MutableSetInt.mergeMany(u, Array_data_util.randomRange(0, 200)); -eq("File \"bs_mutable_set_test.res\", line 46, characters 9-16", Belt_MutableSetInt.size(u), 20001); +eq("File \"bs_mutable_set_test.res\", line 47, characters 9-16", Belt_MutableSetInt.size(u), 20001); Belt_MutableSetInt.removeMany(u, Array_data_util.randomRange(0, 200)); -eq("File \"bs_mutable_set_test.res\", line 48, characters 9-16", Belt_MutableSetInt.size(u), 19800); +eq("File \"bs_mutable_set_test.res\", line 49, characters 9-16", Belt_MutableSetInt.size(u), 19800); Belt_MutableSetInt.removeMany(u, Array_data_util.randomRange(0, 1000)); -eq("File \"bs_mutable_set_test.res\", line 50, characters 9-16", Belt_MutableSetInt.size(u), 19000); +eq("File \"bs_mutable_set_test.res\", line 51, characters 9-16", Belt_MutableSetInt.size(u), 19000); Belt_MutableSetInt.removeMany(u, Array_data_util.randomRange(0, 1000)); -eq("File \"bs_mutable_set_test.res\", line 52, characters 9-16", Belt_MutableSetInt.size(u), 19000); +eq("File \"bs_mutable_set_test.res\", line 53, characters 9-16", Belt_MutableSetInt.size(u), 19000); Belt_MutableSetInt.removeMany(u, Array_data_util.randomRange(1000, 10000)); -eq("File \"bs_mutable_set_test.res\", line 54, characters 9-16", Belt_MutableSetInt.size(u), 10000); +eq("File \"bs_mutable_set_test.res\", line 55, characters 9-16", Belt_MutableSetInt.size(u), 10000); Belt_MutableSetInt.removeMany(u, Array_data_util.randomRange(10000, 19999)); -eq("File \"bs_mutable_set_test.res\", line 56, characters 9-16", Belt_MutableSetInt.size(u), 1); +eq("File \"bs_mutable_set_test.res\", line 57, characters 9-16", Belt_MutableSetInt.size(u), 1); -b("File \"bs_mutable_set_test.res\", line 57, characters 8-15", Belt_MutableSetInt.has(u, 20000)); +b("File \"bs_mutable_set_test.res\", line 58, characters 8-15", Belt_MutableSetInt.has(u, 20000)); Belt_MutableSetInt.removeMany(u, Array_data_util.randomRange(10000, 30000)); -b("File \"bs_mutable_set_test.res\", line 59, characters 8-15", Belt_MutableSetInt.isEmpty(u)); +b("File \"bs_mutable_set_test.res\", line 60, characters 8-15", Belt_MutableSetInt.isEmpty(u)); let v = Belt_MutableSetInt.fromArray(Array_data_util.randomRange(1000, 2000)); @@ -113,9 +113,9 @@ let indeedRemoved = Belt_Array.reduce(bs, 0, (acc, x) => { } }); -eq("File \"bs_mutable_set_test.res\", line 72, characters 9-16", indeedRemoved, 500); +eq("File \"bs_mutable_set_test.res\", line 73, characters 9-16", indeedRemoved, 500); -eq("File \"bs_mutable_set_test.res\", line 73, characters 9-16", Belt_MutableSetInt.size(v), 501); +eq("File \"bs_mutable_set_test.res\", line 74, characters 9-16", Belt_MutableSetInt.size(v), 501); let cs = Belt_Array.map(Array_data_util.randomRange(500, 2000), x => Belt_MutableSetInt.addCheck(v, x)); @@ -127,31 +127,31 @@ let indeedAded = Belt_Array.reduce(cs, 0, (acc, x) => { } }); -eq("File \"bs_mutable_set_test.res\", line 82, characters 9-16", indeedAded, 1000); +eq("File \"bs_mutable_set_test.res\", line 83, characters 9-16", indeedAded, 1000); -eq("File \"bs_mutable_set_test.res\", line 83, characters 9-16", Belt_MutableSetInt.size(v), 1501); +eq("File \"bs_mutable_set_test.res\", line 84, characters 9-16", Belt_MutableSetInt.size(v), 1501); -b("File \"bs_mutable_set_test.res\", line 84, characters 8-15", Belt_MutableSetInt.isEmpty(Belt_MutableSetInt.make())); +b("File \"bs_mutable_set_test.res\", line 85, characters 8-15", Belt_MutableSetInt.isEmpty(Belt_MutableSetInt.make())); -eq("File \"bs_mutable_set_test.res\", line 85, characters 9-16", Belt_MutableSetInt.minimum(v), 500); +eq("File \"bs_mutable_set_test.res\", line 86, characters 9-16", Belt_MutableSetInt.minimum(v), 500); -eq("File \"bs_mutable_set_test.res\", line 86, characters 9-16", Belt_MutableSetInt.maximum(v), 2000); +eq("File \"bs_mutable_set_test.res\", line 87, characters 9-16", Belt_MutableSetInt.maximum(v), 2000); -eq("File \"bs_mutable_set_test.res\", line 87, characters 9-16", Belt_MutableSetInt.minUndefined(v), 500); +eq("File \"bs_mutable_set_test.res\", line 88, characters 9-16", Belt_MutableSetInt.minUndefined(v), 500); -eq("File \"bs_mutable_set_test.res\", line 88, characters 9-16", Belt_MutableSetInt.maxUndefined(v), 2000); +eq("File \"bs_mutable_set_test.res\", line 89, characters 9-16", Belt_MutableSetInt.maxUndefined(v), 2000); -eq("File \"bs_mutable_set_test.res\", line 89, characters 9-16", Belt_MutableSetInt.reduce(v, 0, (x, y) => x + y | 0), 1876250); +eq("File \"bs_mutable_set_test.res\", line 90, characters 9-16", Belt_MutableSetInt.reduce(v, 0, (x, y) => x + y | 0), 1876250); -b("File \"bs_mutable_set_test.res\", line 90, characters 8-15", Belt_List.eq(Belt_MutableSetInt.toList(v), Belt_List.makeBy(1501, i => i + 500 | 0), (x, y) => x === y)); +b("File \"bs_mutable_set_test.res\", line 91, characters 8-15", Belt_List.eq(Belt_MutableSetInt.toList(v), Belt_List.makeBy(1501, i => i + 500 | 0), (x, y) => x === y)); -eq("File \"bs_mutable_set_test.res\", line 91, characters 9-16", Belt_MutableSetInt.toArray(v), Array_data_util.range(500, 2000)); +eq("File \"bs_mutable_set_test.res\", line 92, characters 9-16", Belt_MutableSetInt.toArray(v), Array_data_util.range(500, 2000)); Belt_MutableSetInt.checkInvariantInternal(v); -eq("File \"bs_mutable_set_test.res\", line 93, characters 9-16", Belt_MutableSetInt.get(v, 3), undefined); +eq("File \"bs_mutable_set_test.res\", line 94, characters 9-16", Belt_MutableSetInt.get(v, 3), undefined); -eq("File \"bs_mutable_set_test.res\", line 94, characters 9-16", Belt_MutableSetInt.get(v, 1200), 1200); +eq("File \"bs_mutable_set_test.res\", line 95, characters 9-16", Belt_MutableSetInt.get(v, 1200), 1200); let match = Belt_MutableSetInt.split(v, 1000); @@ -161,21 +161,21 @@ let bb = match$1[1]; let aa = match$1[0]; -b("File \"bs_mutable_set_test.res\", line 96, characters 8-15", match[1]); +b("File \"bs_mutable_set_test.res\", line 97, characters 8-15", match[1]); -b("File \"bs_mutable_set_test.res\", line 97, characters 8-15", Belt_Array.eq(Belt_MutableSetInt.toArray(aa), Array_data_util.range(500, 999), (x, y) => x === y)); +b("File \"bs_mutable_set_test.res\", line 98, characters 8-15", Belt_Array.eq(Belt_MutableSetInt.toArray(aa), Array_data_util.range(500, 999), (x, y) => x === y)); -b("File \"bs_mutable_set_test.res\", line 98, characters 8-15", Belt_Array.eq(Belt_MutableSetInt.toArray(bb), Array_data_util.range(1001, 2000), (prim0, prim1) => prim0 === prim1)); +b("File \"bs_mutable_set_test.res\", line 99, characters 8-15", Belt_Array.eq(Belt_MutableSetInt.toArray(bb), Array_data_util.range(1001, 2000), (prim0, prim1) => prim0 === prim1)); -b("File \"bs_mutable_set_test.res\", line 99, characters 8-15", Belt_MutableSetInt.subset(aa, v)); +b("File \"bs_mutable_set_test.res\", line 100, characters 8-15", Belt_MutableSetInt.subset(aa, v)); -b("File \"bs_mutable_set_test.res\", line 100, characters 8-15", Belt_MutableSetInt.subset(bb, v)); +b("File \"bs_mutable_set_test.res\", line 101, characters 8-15", Belt_MutableSetInt.subset(bb, v)); -b("File \"bs_mutable_set_test.res\", line 101, characters 8-15", Belt_MutableSetInt.isEmpty(Belt_MutableSetInt.intersect(aa, bb))); +b("File \"bs_mutable_set_test.res\", line 102, characters 8-15", Belt_MutableSetInt.isEmpty(Belt_MutableSetInt.intersect(aa, bb))); let c = Belt_MutableSetInt.removeCheck(v, 1000); -b("File \"bs_mutable_set_test.res\", line 103, characters 8-15", c); +b("File \"bs_mutable_set_test.res\", line 104, characters 8-15", c); let match$2 = Belt_MutableSetInt.split(v, 1000); @@ -185,17 +185,17 @@ let bb$1 = match$3[1]; let aa$1 = match$3[0]; -b("File \"bs_mutable_set_test.res\", line 105, characters 8-15", !match$2[1]); +b("File \"bs_mutable_set_test.res\", line 106, characters 8-15", !match$2[1]); -b("File \"bs_mutable_set_test.res\", line 106, characters 8-15", Belt_Array.eq(Belt_MutableSetInt.toArray(aa$1), Array_data_util.range(500, 999), (prim0, prim1) => prim0 === prim1)); +b("File \"bs_mutable_set_test.res\", line 107, characters 8-15", Belt_Array.eq(Belt_MutableSetInt.toArray(aa$1), Array_data_util.range(500, 999), (prim0, prim1) => prim0 === prim1)); -b("File \"bs_mutable_set_test.res\", line 107, characters 8-15", Belt_Array.eq(Belt_MutableSetInt.toArray(bb$1), Array_data_util.range(1001, 2000), (prim0, prim1) => prim0 === prim1)); +b("File \"bs_mutable_set_test.res\", line 108, characters 8-15", Belt_Array.eq(Belt_MutableSetInt.toArray(bb$1), Array_data_util.range(1001, 2000), (prim0, prim1) => prim0 === prim1)); -b("File \"bs_mutable_set_test.res\", line 108, characters 8-15", Belt_MutableSetInt.subset(aa$1, v)); +b("File \"bs_mutable_set_test.res\", line 109, characters 8-15", Belt_MutableSetInt.subset(aa$1, v)); -b("File \"bs_mutable_set_test.res\", line 109, characters 8-15", Belt_MutableSetInt.subset(bb$1, v)); +b("File \"bs_mutable_set_test.res\", line 110, characters 8-15", Belt_MutableSetInt.subset(bb$1, v)); -b("File \"bs_mutable_set_test.res\", line 110, characters 8-15", Belt_MutableSetInt.isEmpty(Belt_MutableSetInt.intersect(aa$1, bb$1))); +b("File \"bs_mutable_set_test.res\", line 111, characters 8-15", Belt_MutableSetInt.isEmpty(Belt_MutableSetInt.intersect(aa$1, bb$1))); let aa$2 = Belt_MutableSetInt.fromArray(Array_data_util.randomRange(0, 100)); @@ -203,19 +203,19 @@ let bb$2 = Belt_MutableSetInt.fromArray(Array_data_util.randomRange(40, 120)); let cc = Belt_MutableSetInt.union(aa$2, bb$2); -b("File \"bs_mutable_set_test.res\", line 120, characters 8-15", Belt_MutableSetInt.eq(cc, Belt_MutableSetInt.fromArray(Array_data_util.randomRange(0, 120)))); +b("File \"bs_mutable_set_test.res\", line 121, characters 8-15", Belt_MutableSetInt.eq(cc, Belt_MutableSetInt.fromArray(Array_data_util.randomRange(0, 120)))); -b("File \"bs_mutable_set_test.res\", line 123, characters 8-15", Belt_MutableSetInt.eq(Belt_MutableSetInt.union(Belt_MutableSetInt.fromArray(Array_data_util.randomRange(0, 20)), Belt_MutableSetInt.fromArray(Array_data_util.randomRange(21, 40))), Belt_MutableSetInt.fromArray(Array_data_util.randomRange(0, 40)))); +b("File \"bs_mutable_set_test.res\", line 124, characters 8-15", Belt_MutableSetInt.eq(Belt_MutableSetInt.union(Belt_MutableSetInt.fromArray(Array_data_util.randomRange(0, 20)), Belt_MutableSetInt.fromArray(Array_data_util.randomRange(21, 40))), Belt_MutableSetInt.fromArray(Array_data_util.randomRange(0, 40)))); let dd = Belt_MutableSetInt.intersect(aa$2, bb$2); -b("File \"bs_mutable_set_test.res\", line 127, characters 8-15", Belt_MutableSetInt.eq(dd, Belt_MutableSetInt.fromArray(Array_data_util.randomRange(40, 100)))); +b("File \"bs_mutable_set_test.res\", line 128, characters 8-15", Belt_MutableSetInt.eq(dd, Belt_MutableSetInt.fromArray(Array_data_util.randomRange(40, 100)))); -b("File \"bs_mutable_set_test.res\", line 129, characters 8-15", Belt_MutableSetInt.eq(Belt_MutableSetInt.intersect(Belt_MutableSetInt.fromArray(Array_data_util.randomRange(0, 20)), Belt_MutableSetInt.fromArray(Array_data_util.randomRange(21, 40))), Belt_MutableSetInt.make())); +b("File \"bs_mutable_set_test.res\", line 130, characters 8-15", Belt_MutableSetInt.eq(Belt_MutableSetInt.intersect(Belt_MutableSetInt.fromArray(Array_data_util.randomRange(0, 20)), Belt_MutableSetInt.fromArray(Array_data_util.randomRange(21, 40))), Belt_MutableSetInt.make())); -b("File \"bs_mutable_set_test.res\", line 136, characters 8-15", Belt_MutableSetInt.eq(Belt_MutableSetInt.intersect(Belt_MutableSetInt.fromArray(Array_data_util.randomRange(21, 40)), Belt_MutableSetInt.fromArray(Array_data_util.randomRange(0, 20))), Belt_MutableSetInt.make())); +b("File \"bs_mutable_set_test.res\", line 137, characters 8-15", Belt_MutableSetInt.eq(Belt_MutableSetInt.intersect(Belt_MutableSetInt.fromArray(Array_data_util.randomRange(21, 40)), Belt_MutableSetInt.fromArray(Array_data_util.randomRange(0, 20))), Belt_MutableSetInt.make())); -b("File \"bs_mutable_set_test.res\", line 142, characters 8-15", Belt_MutableSetInt.eq(Belt_MutableSetInt.intersect(Belt_MutableSetInt.fromArray([ +b("File \"bs_mutable_set_test.res\", line 143, characters 8-15", Belt_MutableSetInt.eq(Belt_MutableSetInt.intersect(Belt_MutableSetInt.fromArray([ 1, 3, 4, @@ -234,15 +234,15 @@ b("File \"bs_mutable_set_test.res\", line 142, characters 8-15", Belt_MutableSet 5 ]))); -b("File \"bs_mutable_set_test.res\", line 143, characters 8-15", Belt_MutableSetInt.eq(Belt_MutableSetInt.diff(aa$2, bb$2), Belt_MutableSetInt.fromArray(Array_data_util.randomRange(0, 39)))); +b("File \"bs_mutable_set_test.res\", line 144, characters 8-15", Belt_MutableSetInt.eq(Belt_MutableSetInt.diff(aa$2, bb$2), Belt_MutableSetInt.fromArray(Array_data_util.randomRange(0, 39)))); -b("File \"bs_mutable_set_test.res\", line 144, characters 8-15", Belt_MutableSetInt.eq(Belt_MutableSetInt.diff(bb$2, aa$2), Belt_MutableSetInt.fromArray(Array_data_util.randomRange(101, 120)))); +b("File \"bs_mutable_set_test.res\", line 145, characters 8-15", Belt_MutableSetInt.eq(Belt_MutableSetInt.diff(bb$2, aa$2), Belt_MutableSetInt.fromArray(Array_data_util.randomRange(101, 120)))); -b("File \"bs_mutable_set_test.res\", line 146, characters 8-15", Belt_MutableSetInt.eq(Belt_MutableSetInt.diff(Belt_MutableSetInt.fromArray(Array_data_util.randomRange(21, 40)), Belt_MutableSetInt.fromArray(Array_data_util.randomRange(0, 20))), Belt_MutableSetInt.fromArray(Array_data_util.randomRange(21, 40)))); +b("File \"bs_mutable_set_test.res\", line 147, characters 8-15", Belt_MutableSetInt.eq(Belt_MutableSetInt.diff(Belt_MutableSetInt.fromArray(Array_data_util.randomRange(21, 40)), Belt_MutableSetInt.fromArray(Array_data_util.randomRange(0, 20))), Belt_MutableSetInt.fromArray(Array_data_util.randomRange(21, 40)))); -b("File \"bs_mutable_set_test.res\", line 153, characters 8-15", Belt_MutableSetInt.eq(Belt_MutableSetInt.diff(Belt_MutableSetInt.fromArray(Array_data_util.randomRange(0, 20)), Belt_MutableSetInt.fromArray(Array_data_util.randomRange(21, 40))), Belt_MutableSetInt.fromArray(Array_data_util.randomRange(0, 20)))); +b("File \"bs_mutable_set_test.res\", line 154, characters 8-15", Belt_MutableSetInt.eq(Belt_MutableSetInt.diff(Belt_MutableSetInt.fromArray(Array_data_util.randomRange(0, 20)), Belt_MutableSetInt.fromArray(Array_data_util.randomRange(21, 40))), Belt_MutableSetInt.fromArray(Array_data_util.randomRange(0, 20)))); -b("File \"bs_mutable_set_test.res\", line 161, characters 8-15", Belt_MutableSetInt.eq(Belt_MutableSetInt.diff(Belt_MutableSetInt.fromArray(Array_data_util.randomRange(0, 20)), Belt_MutableSetInt.fromArray(Array_data_util.randomRange(0, 40))), Belt_MutableSetInt.fromArray(Array_data_util.randomRange(0, -1)))); +b("File \"bs_mutable_set_test.res\", line 162, characters 8-15", Belt_MutableSetInt.eq(Belt_MutableSetInt.diff(Belt_MutableSetInt.fromArray(Array_data_util.randomRange(0, 20)), Belt_MutableSetInt.fromArray(Array_data_util.randomRange(0, 40))), Belt_MutableSetInt.fromArray(Array_data_util.randomRange(0, -1)))); let a0 = Belt_MutableSetInt.fromArray(Array_data_util.randomRange(0, 1000)); @@ -256,9 +256,9 @@ let a4 = match$4[1]; let a3 = match$4[0]; -b("File \"bs_mutable_set_test.res\", line 173, characters 8-15", Belt_MutableSetInt.eq(a1, a3)); +b("File \"bs_mutable_set_test.res\", line 174, characters 8-15", Belt_MutableSetInt.eq(a1, a3)); -b("File \"bs_mutable_set_test.res\", line 174, characters 8-15", Belt_MutableSetInt.eq(a2, a4)); +b("File \"bs_mutable_set_test.res\", line 175, characters 8-15", Belt_MutableSetInt.eq(a2, a4)); Belt_List.forEach({ hd: a0, @@ -285,9 +285,9 @@ for (let i$2 = 0; i$2 <= 100000; ++i$2) { Belt_MutableSetInt.checkInvariantInternal(v$1); -b("File \"bs_mutable_set_test.res\", line 188, characters 10-17", Belt_Range.every(0, 100000, i => Belt_MutableSetInt.has(v$1, i))); +b("File \"bs_mutable_set_test.res\", line 189, characters 10-17", Belt_Range.every(0, 100000, i => Belt_MutableSetInt.has(v$1, i))); -eq("File \"bs_mutable_set_test.res\", line 189, characters 5-12", Belt_MutableSetInt.size(v$1), 100001); +eq("File \"bs_mutable_set_test.res\", line 190, characters 5-12", Belt_MutableSetInt.size(v$1), 100001); let u$1 = Belt_Array.concat(Array_data_util.randomRange(30, 100), Array_data_util.randomRange(40, 120)); @@ -295,15 +295,15 @@ let v$2 = Belt_MutableSetInt.make(); Belt_MutableSetInt.mergeMany(v$2, u$1); -eq("File \"bs_mutable_set_test.res\", line 196, characters 5-12", Belt_MutableSetInt.size(v$2), 91); +eq("File \"bs_mutable_set_test.res\", line 197, characters 5-12", Belt_MutableSetInt.size(v$2), 91); -eq("File \"bs_mutable_set_test.res\", line 197, characters 5-12", Belt_MutableSetInt.toArray(v$2), Array_data_util.range(30, 120)); +eq("File \"bs_mutable_set_test.res\", line 198, characters 5-12", Belt_MutableSetInt.toArray(v$2), Array_data_util.range(30, 120)); let u$2 = Belt_Array.concat(Array_data_util.randomRange(0, 100000), Array_data_util.randomRange(0, 100)); let v$3 = Belt_MutableSetInt.fromArray(u$2); -eq("File \"bs_mutable_set_test.res\", line 203, characters 5-12", Belt_MutableSetInt.size(v$3), 100001); +eq("File \"bs_mutable_set_test.res\", line 204, characters 5-12", Belt_MutableSetInt.size(v$3), 100001); let u$3 = Array_data_util.randomRange(50000, 80000); @@ -311,7 +311,7 @@ for (let i$3 = 0, i_finish$1 = u$3.length; i$3 < i_finish$1; ++i$3) { Belt_MutableSetInt.remove(v$3, i$3); } -eq("File \"bs_mutable_set_test.res\", line 210, characters 5-12", Belt_MutableSetInt.size(v$3), 70000); +eq("File \"bs_mutable_set_test.res\", line 211, characters 5-12", Belt_MutableSetInt.size(v$3), 70000); let vv = Array_data_util.randomRange(0, 100000); @@ -319,9 +319,9 @@ for (let i$4 = 0, i_finish$2 = vv.length; i$4 < i_finish$2; ++i$4) { Belt_MutableSetInt.remove(v$3, Primitive_array.get(vv, i$4)); } -eq("File \"bs_mutable_set_test.res\", line 216, characters 5-12", Belt_MutableSetInt.size(v$3), 0); +eq("File \"bs_mutable_set_test.res\", line 217, characters 5-12", Belt_MutableSetInt.size(v$3), 0); -b("File \"bs_mutable_set_test.res\", line 217, characters 4-11", Belt_MutableSetInt.isEmpty(v$3)); +b("File \"bs_mutable_set_test.res\", line 218, characters 4-11", Belt_MutableSetInt.isEmpty(v$3)); let v$4 = Belt_MutableSetInt.fromArray(Belt_Array.makeBy(30, i => i)); @@ -329,13 +329,13 @@ Belt_MutableSetInt.remove(v$4, 30); Belt_MutableSetInt.remove(v$4, 29); -b("File \"bs_mutable_set_test.res\", line 224, characters 4-11", 28 === Belt_MutableSetInt.maxUndefined(v$4)); +b("File \"bs_mutable_set_test.res\", line 225, characters 4-11", 28 === Belt_MutableSetInt.maxUndefined(v$4)); Belt_MutableSetInt.remove(v$4, 0); -b("File \"bs_mutable_set_test.res\", line 226, characters 4-11", 1 === Belt_MutableSetInt.minUndefined(v$4)); +b("File \"bs_mutable_set_test.res\", line 227, characters 4-11", 1 === Belt_MutableSetInt.minUndefined(v$4)); -eq("File \"bs_mutable_set_test.res\", line 227, characters 5-12", Belt_MutableSetInt.size(v$4), 28); +eq("File \"bs_mutable_set_test.res\", line 228, characters 5-12", Belt_MutableSetInt.size(v$4), 28); let vv$1 = Array_data_util.randomRange(1, 28); @@ -343,7 +343,7 @@ for (let i$5 = 0, i_finish$3 = vv$1.length; i$5 < i_finish$3; ++i$5) { Belt_MutableSetInt.remove(v$4, Primitive_array.get(vv$1, i$5)); } -eq("File \"bs_mutable_set_test.res\", line 232, characters 5-12", Belt_MutableSetInt.size(v$4), 0); +eq("File \"bs_mutable_set_test.res\", line 233, characters 5-12", Belt_MutableSetInt.size(v$4), 0); function id(loc, x) { let u = Belt_MutableSetInt.fromSortedArrayUnsafe(x); @@ -351,29 +351,29 @@ function id(loc, x) { b(loc, Belt_Array.every2(Belt_MutableSetInt.toArray(u), x, (prim0, prim1) => prim0 === prim1)); } -id("File \"bs_mutable_set_test.res\", line 242, characters 5-12", []); +id("File \"bs_mutable_set_test.res\", line 243, characters 5-12", []); -id("File \"bs_mutable_set_test.res\", line 243, characters 5-12", [0]); +id("File \"bs_mutable_set_test.res\", line 244, characters 5-12", [0]); -id("File \"bs_mutable_set_test.res\", line 244, characters 5-12", [ +id("File \"bs_mutable_set_test.res\", line 245, characters 5-12", [ 0, 1 ]); -id("File \"bs_mutable_set_test.res\", line 245, characters 5-12", [ +id("File \"bs_mutable_set_test.res\", line 246, characters 5-12", [ 0, 1, 2 ]); -id("File \"bs_mutable_set_test.res\", line 246, characters 5-12", [ +id("File \"bs_mutable_set_test.res\", line 247, characters 5-12", [ 0, 1, 2, 3 ]); -id("File \"bs_mutable_set_test.res\", line 247, characters 5-12", [ +id("File \"bs_mutable_set_test.res\", line 248, characters 5-12", [ 0, 1, 2, @@ -381,7 +381,7 @@ id("File \"bs_mutable_set_test.res\", line 247, characters 5-12", [ 4 ]); -id("File \"bs_mutable_set_test.res\", line 248, characters 5-12", [ +id("File \"bs_mutable_set_test.res\", line 249, characters 5-12", [ 0, 1, 2, @@ -390,7 +390,7 @@ id("File \"bs_mutable_set_test.res\", line 248, characters 5-12", [ 5 ]); -id("File \"bs_mutable_set_test.res\", line 249, characters 5-12", [ +id("File \"bs_mutable_set_test.res\", line 250, characters 5-12", [ 0, 1, 2, @@ -399,7 +399,7 @@ id("File \"bs_mutable_set_test.res\", line 249, characters 5-12", [ 6 ]); -id("File \"bs_mutable_set_test.res\", line 250, characters 5-12", [ +id("File \"bs_mutable_set_test.res\", line 251, characters 5-12", [ 0, 1, 2, @@ -409,7 +409,7 @@ id("File \"bs_mutable_set_test.res\", line 250, characters 5-12", [ 7 ]); -id("File \"bs_mutable_set_test.res\", line 251, characters 5-12", [ +id("File \"bs_mutable_set_test.res\", line 252, characters 5-12", [ 0, 1, 2, @@ -420,7 +420,7 @@ id("File \"bs_mutable_set_test.res\", line 251, characters 5-12", [ 8 ]); -id("File \"bs_mutable_set_test.res\", line 252, characters 5-12", [ +id("File \"bs_mutable_set_test.res\", line 253, characters 5-12", [ 0, 1, 2, @@ -432,7 +432,7 @@ id("File \"bs_mutable_set_test.res\", line 252, characters 5-12", [ 9 ]); -id("File \"bs_mutable_set_test.res\", line 253, characters 5-12", Array_data_util.range(0, 1000)); +id("File \"bs_mutable_set_test.res\", line 254, characters 5-12", Array_data_util.range(0, 1000)); let v$5 = Belt_MutableSetInt.fromArray(Array_data_util.randomRange(0, 1000)); @@ -446,15 +446,15 @@ for (let i$6 = 0; i$6 <= 200; ++i$6) { Belt_MutableSetInt.remove(v$5, i$6); } -eq("File \"bs_mutable_set_test.res\", line 264, characters 5-12", Belt_MutableSetInt.size(copyV), 126); +eq("File \"bs_mutable_set_test.res\", line 265, characters 5-12", Belt_MutableSetInt.size(copyV), 126); -eq("File \"bs_mutable_set_test.res\", line 265, characters 5-12", Belt_MutableSetInt.toArray(copyV), Belt_Array.makeBy(126, i => (i << 3))); +eq("File \"bs_mutable_set_test.res\", line 266, characters 5-12", Belt_MutableSetInt.toArray(copyV), Belt_Array.makeBy(126, i => (i << 3))); -eq("File \"bs_mutable_set_test.res\", line 266, characters 5-12", Belt_MutableSetInt.size(v$5), 800); +eq("File \"bs_mutable_set_test.res\", line 267, characters 5-12", Belt_MutableSetInt.size(v$5), 800); -b("File \"bs_mutable_set_test.res\", line 267, characters 4-11", Belt_MutableSetInt.eq(copyV, match$5[0])); +b("File \"bs_mutable_set_test.res\", line 268, characters 4-11", Belt_MutableSetInt.eq(copyV, match$5[0])); -b("File \"bs_mutable_set_test.res\", line 268, characters 4-11", Belt_MutableSetInt.eq(cc$1, match$5[1])); +b("File \"bs_mutable_set_test.res\", line 269, characters 4-11", Belt_MutableSetInt.eq(cc$1, match$5[1])); let v$6 = Belt_MutableSetInt.fromArray(Array_data_util.randomRange(0, 1000)); @@ -462,9 +462,9 @@ let match$6 = Belt_MutableSetInt.split(v$6, 400); let match$7 = match$6[0]; -b("File \"bs_mutable_set_test.res\", line 274, characters 4-11", Belt_MutableSetInt.eq(match$7[0], Belt_MutableSetInt.fromArray(Array_data_util.randomRange(0, 399)))); +b("File \"bs_mutable_set_test.res\", line 275, characters 4-11", Belt_MutableSetInt.eq(match$7[0], Belt_MutableSetInt.fromArray(Array_data_util.randomRange(0, 399)))); -b("File \"bs_mutable_set_test.res\", line 275, characters 4-11", Belt_MutableSetInt.eq(match$7[1], Belt_MutableSetInt.fromArray(Array_data_util.randomRange(401, 1000)))); +b("File \"bs_mutable_set_test.res\", line 276, characters 4-11", Belt_MutableSetInt.eq(match$7[1], Belt_MutableSetInt.fromArray(Array_data_util.randomRange(401, 1000)))); let d = Belt_MutableSetInt.fromArray(Belt_Array.map(Array_data_util.randomRange(0, 1000), x => (x << 1))); @@ -472,9 +472,9 @@ let match$8 = Belt_MutableSetInt.split(d, 1001); let match$9 = match$8[0]; -b("File \"bs_mutable_set_test.res\", line 278, characters 4-11", Belt_MutableSetInt.eq(match$9[0], Belt_MutableSetInt.fromArray(Belt_Array.makeBy(501, x => (x << 1))))); +b("File \"bs_mutable_set_test.res\", line 279, characters 4-11", Belt_MutableSetInt.eq(match$9[0], Belt_MutableSetInt.fromArray(Belt_Array.makeBy(501, x => (x << 1))))); -b("File \"bs_mutable_set_test.res\", line 279, characters 4-11", Belt_MutableSetInt.eq(match$9[1], Belt_MutableSetInt.fromArray(Belt_Array.makeBy(500, x => 1002 + (x << 1) | 0)))); +b("File \"bs_mutable_set_test.res\", line 280, characters 4-11", Belt_MutableSetInt.eq(match$9[1], Belt_MutableSetInt.fromArray(Belt_Array.makeBy(500, x => 1002 + (x << 1) | 0)))); let aa$3 = Belt_MutableSetInt.fromArray(Array_data_util.randomRange(0, 100)); @@ -482,19 +482,19 @@ let bb$3 = Belt_MutableSetInt.fromArray(Array_data_util.randomRange(40, 120)); let cc$2 = Belt_MutableSetInt.union(aa$3, bb$3); -b("File \"bs_mutable_set_test.res\", line 289, characters 4-11", Belt_MutableSetInt.eq(cc$2, Belt_MutableSetInt.fromArray(Array_data_util.randomRange(0, 120)))); +b("File \"bs_mutable_set_test.res\", line 290, characters 4-11", Belt_MutableSetInt.eq(cc$2, Belt_MutableSetInt.fromArray(Array_data_util.randomRange(0, 120)))); -b("File \"bs_mutable_set_test.res\", line 292, characters 4-11", Belt_MutableSetInt.eq(Belt_MutableSetInt.union(Belt_MutableSetInt.fromArray(Array_data_util.randomRange(0, 20)), Belt_MutableSetInt.fromArray(Array_data_util.randomRange(21, 40))), Belt_MutableSetInt.fromArray(Array_data_util.randomRange(0, 40)))); +b("File \"bs_mutable_set_test.res\", line 293, characters 4-11", Belt_MutableSetInt.eq(Belt_MutableSetInt.union(Belt_MutableSetInt.fromArray(Array_data_util.randomRange(0, 20)), Belt_MutableSetInt.fromArray(Array_data_util.randomRange(21, 40))), Belt_MutableSetInt.fromArray(Array_data_util.randomRange(0, 40)))); let dd$1 = Belt_MutableSetInt.intersect(aa$3, bb$3); -b("File \"bs_mutable_set_test.res\", line 296, characters 4-11", Belt_MutableSetInt.eq(dd$1, Belt_MutableSetInt.fromArray(Array_data_util.randomRange(40, 100)))); +b("File \"bs_mutable_set_test.res\", line 297, characters 4-11", Belt_MutableSetInt.eq(dd$1, Belt_MutableSetInt.fromArray(Array_data_util.randomRange(40, 100)))); -b("File \"bs_mutable_set_test.res\", line 298, characters 4-11", Belt_MutableSetInt.eq(Belt_MutableSetInt.intersect(Belt_MutableSetInt.fromArray(Array_data_util.randomRange(0, 20)), Belt_MutableSetInt.fromArray(Array_data_util.randomRange(21, 40))), Belt_MutableSetInt.make())); +b("File \"bs_mutable_set_test.res\", line 299, characters 4-11", Belt_MutableSetInt.eq(Belt_MutableSetInt.intersect(Belt_MutableSetInt.fromArray(Array_data_util.randomRange(0, 20)), Belt_MutableSetInt.fromArray(Array_data_util.randomRange(21, 40))), Belt_MutableSetInt.make())); -b("File \"bs_mutable_set_test.res\", line 302, characters 4-11", Belt_MutableSetInt.eq(Belt_MutableSetInt.intersect(Belt_MutableSetInt.fromArray(Array_data_util.randomRange(21, 40)), Belt_MutableSetInt.fromArray(Array_data_util.randomRange(0, 20))), Belt_MutableSetInt.make())); +b("File \"bs_mutable_set_test.res\", line 303, characters 4-11", Belt_MutableSetInt.eq(Belt_MutableSetInt.intersect(Belt_MutableSetInt.fromArray(Array_data_util.randomRange(21, 40)), Belt_MutableSetInt.fromArray(Array_data_util.randomRange(0, 20))), Belt_MutableSetInt.make())); -b("File \"bs_mutable_set_test.res\", line 305, characters 4-11", Belt_MutableSetInt.eq(Belt_MutableSetInt.intersect(Belt_MutableSetInt.fromArray([ +b("File \"bs_mutable_set_test.res\", line 306, characters 4-11", Belt_MutableSetInt.eq(Belt_MutableSetInt.intersect(Belt_MutableSetInt.fromArray([ 1, 3, 4, @@ -513,20 +513,22 @@ b("File \"bs_mutable_set_test.res\", line 305, characters 4-11", Belt_MutableSet 5 ]))); -b("File \"bs_mutable_set_test.res\", line 306, characters 4-11", Belt_MutableSetInt.eq(Belt_MutableSetInt.diff(aa$3, bb$3), Belt_MutableSetInt.fromArray(Array_data_util.randomRange(0, 39)))); +b("File \"bs_mutable_set_test.res\", line 307, characters 4-11", Belt_MutableSetInt.eq(Belt_MutableSetInt.diff(aa$3, bb$3), Belt_MutableSetInt.fromArray(Array_data_util.randomRange(0, 39)))); -b("File \"bs_mutable_set_test.res\", line 307, characters 4-11", Belt_MutableSetInt.eq(Belt_MutableSetInt.diff(bb$3, aa$3), Belt_MutableSetInt.fromArray(Array_data_util.randomRange(101, 120)))); +b("File \"bs_mutable_set_test.res\", line 308, characters 4-11", Belt_MutableSetInt.eq(Belt_MutableSetInt.diff(bb$3, aa$3), Belt_MutableSetInt.fromArray(Array_data_util.randomRange(101, 120)))); -b("File \"bs_mutable_set_test.res\", line 309, characters 4-11", Belt_MutableSetInt.eq(Belt_MutableSetInt.diff(Belt_MutableSetInt.fromArray(Array_data_util.randomRange(21, 40)), Belt_MutableSetInt.fromArray(Array_data_util.randomRange(0, 20))), Belt_MutableSetInt.fromArray(Array_data_util.randomRange(21, 40)))); +b("File \"bs_mutable_set_test.res\", line 310, characters 4-11", Belt_MutableSetInt.eq(Belt_MutableSetInt.diff(Belt_MutableSetInt.fromArray(Array_data_util.randomRange(21, 40)), Belt_MutableSetInt.fromArray(Array_data_util.randomRange(0, 20))), Belt_MutableSetInt.fromArray(Array_data_util.randomRange(21, 40)))); -b("File \"bs_mutable_set_test.res\", line 316, characters 4-11", Belt_MutableSetInt.eq(Belt_MutableSetInt.diff(Belt_MutableSetInt.fromArray(Array_data_util.randomRange(0, 20)), Belt_MutableSetInt.fromArray(Array_data_util.randomRange(21, 40))), Belt_MutableSetInt.fromArray(Array_data_util.randomRange(0, 20)))); +b("File \"bs_mutable_set_test.res\", line 317, characters 4-11", Belt_MutableSetInt.eq(Belt_MutableSetInt.diff(Belt_MutableSetInt.fromArray(Array_data_util.randomRange(0, 20)), Belt_MutableSetInt.fromArray(Array_data_util.randomRange(21, 40))), Belt_MutableSetInt.fromArray(Array_data_util.randomRange(0, 20)))); -b("File \"bs_mutable_set_test.res\", line 324, characters 4-11", Belt_MutableSetInt.eq(Belt_MutableSetInt.diff(Belt_MutableSetInt.fromArray(Array_data_util.randomRange(0, 20)), Belt_MutableSetInt.fromArray(Array_data_util.randomRange(0, 40))), Belt_MutableSetInt.fromArray(Array_data_util.randomRange(0, -1)))); +b("File \"bs_mutable_set_test.res\", line 325, characters 4-11", Belt_MutableSetInt.eq(Belt_MutableSetInt.diff(Belt_MutableSetInt.fromArray(Array_data_util.randomRange(0, 20)), Belt_MutableSetInt.fromArray(Array_data_util.randomRange(0, 40))), Belt_MutableSetInt.fromArray(Array_data_util.randomRange(0, -1)))); Mt.from_pair_suites("Bs_mutable_set_test", suites.contents); let N; +let $$Array; + let I; let R; @@ -550,6 +552,7 @@ exports.test_id = test_id; exports.eq = eq; exports.b = b; exports.N = N; +exports.$$Array = $$Array; exports.I = I; exports.R = R; exports.A = A; diff --git a/tests/tests/src/bs_mutable_set_test.res b/tests/tests/src/bs_mutable_set_test.res index 0c89a357d4..bfab257666 100644 --- a/tests/tests/src/bs_mutable_set_test.res +++ b/tests/tests/src/bs_mutable_set_test.res @@ -4,6 +4,7 @@ let eq = (loc, x, y) => Mt.eq_suites(~test_id, ~suites, loc, x, y) let b = (loc, x) => Mt.bool_suites(~test_id, ~suites, loc, x) module N = Belt.MutableSet.Int +module Array = Ocaml_Array module I = Array_data_util module R = Belt.Range diff --git a/tests/tests/src/chn_test.js b/tests/tests/src/chn_test.js index ac33b6aabe..97e5f6699e 100644 --- a/tests/tests/src/chn_test.js +++ b/tests/tests/src/chn_test.js @@ -41,7 +41,7 @@ function convert(s) { RE_EXN_ID: "Assert_failure", _1: [ "chn_test.res", - 23, + 24, 16 ], Error: new Error() @@ -49,9 +49,9 @@ function convert(s) { })); } -eq("File \"chn_test.res\", line 31, characters 4-11", "你好,\n世界", "你好,\n世界"); +eq("File \"chn_test.res\", line 32, characters 4-11", "你好,\n世界", "你好,\n世界"); -eq("File \"chn_test.res\", line 37, characters 4-11", convert("汉字是世界上最美丽的character"), { +eq("File \"chn_test.res\", line 38, characters 4-11", convert("汉字是世界上最美丽的character"), { hd: 27721, tl: { hd: 23383, @@ -110,7 +110,7 @@ eq("File \"chn_test.res\", line 37, characters 4-11", convert("汉字是世界 } }); -eq("File \"chn_test.res\", line 61, characters 5-12", convert("\x3f\x3fa"), { +eq("File \"chn_test.res\", line 62, characters 5-12", convert("\x3f\x3fa"), { hd: 63, tl: { hd: 63, @@ -121,7 +121,7 @@ eq("File \"chn_test.res\", line 61, characters 5-12", convert("\x3f\x3fa"), { } }); -eq("File \"chn_test.res\", line 62, characters 5-12", convert("??a"), { +eq("File \"chn_test.res\", line 63, characters 5-12", convert("??a"), { hd: 63, tl: { hd: 63, @@ -132,7 +132,7 @@ eq("File \"chn_test.res\", line 62, characters 5-12", convert("??a"), { } }); -eq("File \"chn_test.res\", line 63, characters 5-12", convert("\u003f\x3fa"), { +eq("File \"chn_test.res\", line 64, characters 5-12", convert("\u003f\x3fa"), { hd: 63, tl: { hd: 63, @@ -143,7 +143,7 @@ eq("File \"chn_test.res\", line 63, characters 5-12", convert("\u003f\x3fa"), { } }); -eq("File \"chn_test.res\", line 64, characters 5-12", convert("🚀🚀a"), { +eq("File \"chn_test.res\", line 65, characters 5-12", convert("🚀🚀a"), { hd: 128640, tl: { hd: 128640, @@ -154,7 +154,7 @@ eq("File \"chn_test.res\", line 64, characters 5-12", convert("🚀🚀a"), { } }); -eq("File \"chn_test.res\", line 65, characters 5-12", convert("\uD83D\uDE80a"), { +eq("File \"chn_test.res\", line 66, characters 5-12", convert("\uD83D\uDE80a"), { hd: 128640, tl: { hd: 97, @@ -162,7 +162,7 @@ eq("File \"chn_test.res\", line 65, characters 5-12", convert("\uD83D\uDE80a"), } }); -eq("File \"chn_test.res\", line 66, characters 5-12", convert("\uD83D\uDE80\x3f"), { +eq("File \"chn_test.res\", line 67, characters 5-12", convert("\uD83D\uDE80\x3f"), { hd: 128640, tl: { hd: 63, @@ -170,7 +170,7 @@ eq("File \"chn_test.res\", line 66, characters 5-12", convert("\uD83D\uDE80\x3f" } }); -eq("File \"chn_test.res\", line 70, characters 5-12", convert("\uD83D\uDE80\uD83D\uDE80a"), { +eq("File \"chn_test.res\", line 71, characters 5-12", convert("\uD83D\uDE80\uD83D\uDE80a"), { hd: 128640, tl: { hd: 128640, @@ -183,16 +183,16 @@ eq("File \"chn_test.res\", line 70, characters 5-12", convert("\uD83D\uDE80\uD83 eq("No inline string length", "\uD83D\uDE80\0".length, 3); -eq("File \"chn_test.res\", line 77, characters 4-11", "\uD83D\uDE80\0".codePointAt(0), 128640); +eq("File \"chn_test.res\", line 78, characters 4-11", "\uD83D\uDE80\0".codePointAt(0), 128640); -eq("File \"chn_test.res\", line 82, characters 5-12", "🚀".codePointAt(0), 128640); +eq("File \"chn_test.res\", line 83, characters 5-12", "🚀".codePointAt(0), 128640); -eq("File \"chn_test.res\", line 87, characters 5-12", convert("\uD83D\uDE80"), { +eq("File \"chn_test.res\", line 88, characters 5-12", convert("\uD83D\uDE80"), { hd: 128640, tl: /* [] */0 }); -eq("File \"chn_test.res\", line 88, characters 5-12", convert("\uD83D\uDE80\uD83D\uDE80"), { +eq("File \"chn_test.res\", line 89, characters 5-12", convert("\uD83D\uDE80\uD83D\uDE80"), { hd: 128640, tl: { hd: 128640, @@ -200,7 +200,7 @@ eq("File \"chn_test.res\", line 88, characters 5-12", convert("\uD83D\uDE80\uD83 } }); -eq("File \"chn_test.res\", line 89, characters 5-12", convert(" \b\t\n\v\f\ra"), { +eq("File \"chn_test.res\", line 90, characters 5-12", convert(" \b\t\n\v\f\ra"), { hd: 32, tl: { hd: 8, @@ -226,7 +226,7 @@ eq("File \"chn_test.res\", line 89, characters 5-12", convert(" \b\t\n\v\f\ra"), } }); -eq("File \"chn_test.res\", line 95, characters 5-12", convert(" \b\t\n\v\f\r\"'\\\0a"), { +eq("File \"chn_test.res\", line 96, characters 5-12", convert(" \b\t\n\v\f\r\"'\\\0a"), { hd: 32, tl: { hd: 8, @@ -266,6 +266,9 @@ eq("File \"chn_test.res\", line 95, characters 5-12", convert(" \b\t\n\v\f\r\"'\ Mt.from_pair_suites("Chn_test", suites.contents); +let $$String; + +exports.$$String = $$String; exports.suites = suites; exports.test_id = test_id; exports.eq = eq; diff --git a/tests/tests/src/chn_test.res b/tests/tests/src/chn_test.res index 9e9b743245..cb11cdaabd 100644 --- a/tests/tests/src/chn_test.res +++ b/tests/tests/src/chn_test.res @@ -1,4 +1,5 @@ open Belt +module String = Ocaml_String let suites: ref = ref(list{}) let test_id = ref(0) diff --git a/tests/tests/src/const_block_test.res b/tests/tests/src/const_block_test.res index 7d6b9fc1cf..d28cfe5a08 100644 --- a/tests/tests/src/const_block_test.res +++ b/tests/tests/src/const_block_test.res @@ -1,3 +1,5 @@ +module Array = Ocaml_Array + let a = [0., 1., 2.] let b = [0, 1, 2] let c = [0, 1, 2, 3, 4, 5] diff --git a/tests/tests/src/cps_test.js b/tests/tests/src/cps_test.js index 888da302e1..6136c08066 100644 --- a/tests/tests/src/cps_test.js +++ b/tests/tests/src/cps_test.js @@ -3,7 +3,6 @@ let Mt = require("./mt.js"); let Belt_Array = require("rescript/lib/js/Belt_Array.js"); -let Primitive_array = require("rescript/lib/js/Primitive_array.js"); function test() { let v = { @@ -34,7 +33,7 @@ function test_closure() { }; let arr = Belt_Array.make(6, x => x); for (let i = 0; i <= 5; ++i) { - Primitive_array.set(arr, i, param => i); + arr[i] = param => i; } Belt_Array.forEach(arr, i => { v.contents = v.contents + i(0) | 0; @@ -49,7 +48,7 @@ function test_closure2() { let arr = Belt_Array.make(6, x => x); for (let i = 0; i <= 5; ++i) { let j = i + i | 0; - Primitive_array.set(arr, i, param => j); + arr[i] = param => j; } Belt_Array.forEach(arr, i => { v.contents = v.contents + i(0) | 0; diff --git a/tests/tests/src/custom_error_test.js b/tests/tests/src/custom_error_test.js index 37400226b7..12e8246a47 100644 --- a/tests/tests/src/custom_error_test.js +++ b/tests/tests/src/custom_error_test.js @@ -1,7 +1,7 @@ // Generated by ReScript, PLEASE EDIT WITH CARE 'use strict'; -let Js_exn = require("rescript/lib/js/Js_exn.js"); +let Exn = require("rescript/lib/js/Exn.js"); let Primitive_exceptions = require("rescript/lib/js/Primitive_exceptions.js"); function test_js_error() { @@ -10,7 +10,7 @@ function test_js_error() { e = JSON.parse(" {\"x\" : }"); } catch (raw_err) { let err = Primitive_exceptions.internalToException(raw_err); - if (err.RE_EXN_ID === Js_exn.$$Error) { + if (err.RE_EXN_ID === Exn.$$Error) { console.log(err._1.stack); return; } @@ -24,7 +24,7 @@ function test_js_error2() { return JSON.parse(" {\"x\" : }"); } catch (raw_e) { let e = Primitive_exceptions.internalToException(raw_e); - if (e.RE_EXN_ID === Js_exn.$$Error) { + if (e.RE_EXN_ID === Exn.$$Error) { console.log(e._1.stack); throw e; } @@ -38,7 +38,7 @@ function example1() { v = JSON.parse(" {\"x\" }"); } catch (raw_err) { let err = Primitive_exceptions.internalToException(raw_err); - if (err.RE_EXN_ID === Js_exn.$$Error) { + if (err.RE_EXN_ID === Exn.$$Error) { console.log(err._1.stack); return; } @@ -52,7 +52,7 @@ function example2() { return JSON.parse(" {\"x\"}"); } catch (raw_exn) { let exn = Primitive_exceptions.internalToException(raw_exn); - if (exn.RE_EXN_ID === Js_exn.$$Error) { + if (exn.RE_EXN_ID === Exn.$$Error) { return; } throw exn; diff --git a/tests/tests/src/equal_exception_test.js b/tests/tests/src/equal_exception_test.js index 5f17e0185b..4179bf287a 100644 --- a/tests/tests/src/equal_exception_test.js +++ b/tests/tests/src/equal_exception_test.js @@ -15,7 +15,7 @@ function is_equal() { RE_EXN_ID: "Assert_failure", _1: [ "equal_exception_test.res", - 4, + 6, 2 ], Error: new Error() @@ -116,7 +116,7 @@ if (Primitive_object.equal(e, { RE_EXN_ID: "Assert_failure", _1: [ "equal_exception_test.res", - 45, + 47, 0 ], Error: new Error() @@ -128,7 +128,7 @@ if (Not_found === "Not_found" !== false) { RE_EXN_ID: "Assert_failure", _1: [ "equal_exception_test.res", - 46, + 48, 0 ], Error: new Error() @@ -137,6 +137,9 @@ if (Not_found === "Not_found" !== false) { Mt.from_suites("exception", suites); +let $$String; + +exports.$$String = $$String; exports.v = v; exports.is_equal = is_equal; exports.is_exception = is_exception; diff --git a/tests/tests/src/equal_exception_test.res b/tests/tests/src/equal_exception_test.res index dd7d77e301..5b673bf1fc 100644 --- a/tests/tests/src/equal_exception_test.res +++ b/tests/tests/src/equal_exception_test.res @@ -1,3 +1,5 @@ +module String = Ocaml_String + let v = "gso" let is_equal = () => { diff --git a/tests/tests/src/exception_raise_test.js b/tests/tests/src/exception_raise_test.js index 622bf8e091..4b7f7b2fba 100644 --- a/tests/tests/src/exception_raise_test.js +++ b/tests/tests/src/exception_raise_test.js @@ -2,7 +2,7 @@ 'use strict'; let Mt = require("./mt.js"); -let Js_exn = require("rescript/lib/js/Js_exn.js"); +let Exn = require("rescript/lib/js/Exn.js"); let Belt_List = require("rescript/lib/js/Belt_List.js"); let Primitive_exceptions = require("rescript/lib/js/Primitive_exceptions.js"); @@ -90,7 +90,7 @@ try { a0 = (function (){throw 2} ()); } catch (raw_x$3) { let x$3 = Primitive_exceptions.internalToException(raw_x$3); - if (x$3.RE_EXN_ID === A || x$3.RE_EXN_ID === Js_exn.$$Error) { + if (x$3.RE_EXN_ID === A || x$3.RE_EXN_ID === Exn.$$Error) { a0 = x$3._1; } else { throw { @@ -145,7 +145,7 @@ let suites = { hd: [ "File \"exception_raise_test.res\", line 123, characters 6-13", () => { - if (a1.RE_EXN_ID === Js_exn.$$Error) { + if (a1.RE_EXN_ID === Exn.$$Error) { return { TAG: "Eq", _0: a1._1, @@ -180,7 +180,7 @@ try { ((()=>{throw 2})()); } catch (raw_e$2) { let e = Primitive_exceptions.internalToException(raw_e$2); - eq("File \"exception_raise_test.res\", line 137, characters 10-17", Js_exn.asJsExn(e) !== undefined, true); + eq("File \"exception_raise_test.res\", line 137, characters 10-17", Exn.asJsExn(e) !== undefined, true); } try { @@ -190,7 +190,7 @@ try { }; } catch (raw_e$3) { let e$1 = Primitive_exceptions.internalToException(raw_e$3); - eq("File \"exception_raise_test.res\", line 141, characters 10-17", Js_exn.asJsExn(e$1) !== undefined, false); + eq("File \"exception_raise_test.res\", line 141, characters 10-17", Exn.asJsExn(e$1) !== undefined, false); } function fff0(x, g) { diff --git a/tests/tests/src/exception_value_test.js b/tests/tests/src/exception_value_test.js index d84820c514..dccedce368 100644 --- a/tests/tests/src/exception_value_test.js +++ b/tests/tests/src/exception_value_test.js @@ -1,7 +1,7 @@ // Generated by ReScript, PLEASE EDIT WITH CARE 'use strict'; -let Js_exn = require("rescript/lib/js/Js_exn.js"); +let Exn = require("rescript/lib/js/Exn.js"); let Primitive_exceptions = require("rescript/lib/js/Primitive_exceptions.js"); function f() { @@ -61,7 +61,7 @@ function test_js_error2() { return JSON.parse(" {\"x\" : }"); } catch (raw_e) { let e = Primitive_exceptions.internalToException(raw_e); - if (e.RE_EXN_ID === Js_exn.$$Error) { + if (e.RE_EXN_ID === Exn.$$Error) { console.log(e._1.stack); throw e; } diff --git a/tests/tests/src/ext_pervasives_test.res b/tests/tests/src/ext_pervasives_test.res index daea9db334..a70b890a87 100644 --- a/tests/tests/src/ext_pervasives_test.res +++ b/tests/tests/src/ext_pervasives_test.res @@ -22,6 +22,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +module String = Ocaml_String + external reraise: exn => 'a = "%raise" let finally = (v, action, f) => diff --git a/tests/tests/src/flexible_array_test.js b/tests/tests/src/flexible_array_test.js index d8a611d854..34b52f9366 100644 --- a/tests/tests/src/flexible_array_test.js +++ b/tests/tests/src/flexible_array_test.js @@ -145,7 +145,7 @@ function lorem(tr) { RE_EXN_ID: "Assert_failure", _1: [ "flexible_array_test.res", - 80, + 82, 9 ], Error: new Error() @@ -303,7 +303,7 @@ if (!$eq$tilde(sort(u), [ RE_EXN_ID: "Assert_failure", _1: [ "flexible_array_test.res", - 184, + 186, 2 ], Error: new Error() @@ -314,6 +314,9 @@ let v = Belt_Array.init(500, i => 500 - i | 0); $eq$tilde(sort(of_array(v)), Belt_Array.init(500, i => i + 1 | 0)); +let $$Array; + +exports.$$Array = $$Array; exports.sub = sub; exports.update = update; exports.$$delete = $$delete; diff --git a/tests/tests/src/flexible_array_test.res b/tests/tests/src/flexible_array_test.res index 5508abf8bd..0704e270a8 100644 --- a/tests/tests/src/flexible_array_test.res +++ b/tests/tests/src/flexible_array_test.res @@ -1,3 +1,5 @@ +module Array = Ocaml_Array + type rec tree<'a> = | Lf | Br('a, tree<'a>, tree<'a>) diff --git a/tests/tests/src/for_loop_test.js b/tests/tests/src/for_loop_test.js index ddf65b2f77..4dfe8ec842 100644 --- a/tests/tests/src/for_loop_test.js +++ b/tests/tests/src/for_loop_test.js @@ -3,7 +3,6 @@ let Belt_List = require("rescript/lib/js/Belt_List.js"); let Belt_Array = require("rescript/lib/js/Belt_Array.js"); -let Primitive_array = require("rescript/lib/js/Primitive_array.js"); function for_3(x) { let v = { @@ -12,9 +11,9 @@ function for_3(x) { let arr = Belt_Array.map(x, param => (() => {})); for (let i = 0, i_finish = x.length; i < i_finish; ++i) { let j = (i << 1); - Primitive_array.set(arr, i, () => { + arr[i] = () => { v.contents = v.contents + j | 0; - }); + }; } Belt_Array.forEach(arr, x => x()); return v.contents; @@ -28,9 +27,9 @@ function for_4(x) { for (let i = 0, i_finish = x.length; i < i_finish; ++i) { let j = (i << 1); let k = (j << 1); - Primitive_array.set(arr, i, () => { + arr[i] = () => { v.contents = v.contents + k | 0; - }); + }; } Belt_Array.forEach(arr, x => x()); return v.contents; @@ -43,9 +42,9 @@ function for_5(x, u) { let arr = Belt_Array.map(x, param => (() => {})); for (let i = 0, i_finish = x.length; i < i_finish; ++i) { let k = Math.imul((u << 1), u); - Primitive_array.set(arr, i, () => { + arr[i] = () => { v.contents = v.contents + k | 0; - }); + }; } Belt_Array.forEach(arr, x => x()); return v.contents; @@ -73,9 +72,9 @@ function for_6(x, u) { let k = Math.imul((u << 1), u); let h = (v5.contents << 1); v2.contents = v2.contents + 1 | 0; - Primitive_array.set(arr, i, () => { + arr[i] = () => { v.contents = (((((v.contents + k | 0) + v2.contents | 0) + v4.contents | 0) + v5.contents | 0) + h | 0) + u | 0; - }); + }; } inspect_3 = v2.contents; } @@ -95,9 +94,9 @@ function for_7() { let arr = Belt_Array.make(21, () => {}); for (let i = 0; i <= 6; ++i) { for (let j = 0; j <= 2; ++j) { - Primitive_array.set(arr, Math.imul(i, 3) + j | 0, () => { + arr[Math.imul(i, 3) + j | 0] = () => { v.contents = (v.contents + i | 0) + j | 0; - }); + }; } } Belt_Array.forEach(arr, f => f()); @@ -113,9 +112,9 @@ function for_8() { let k = (i << 1); for (let j = 0; j <= 2; ++j) { let h = i + j | 0; - Primitive_array.set(arr, Math.imul(i, 3) + j | 0, () => { + arr[Math.imul(i, 3) + j | 0] = () => { v.contents = (((v.contents + i | 0) + j | 0) + h | 0) + k | 0; - }); + }; } } Belt_Array.forEach(arr, f => f()); @@ -148,13 +147,13 @@ function for_9() { for (let j = 0; j <= 1; ++j) { v$1.contents = v$1.contents + 1 | 0; collect(v$1.contents); - Primitive_array.set(arr, (i << 1) + j | 0, () => { + arr[(i << 1) + j | 0] = () => { vv.contents = vv.contents + v$1.contents | 0; - }); + }; } - Primitive_array.set(arr2, i, () => { + arr2[i] = () => { vv2.contents = vv2.contents + v$1.contents | 0; - }); + }; } Belt_Array.forEach(arr, f => f()); Belt_Array.forEach(arr2, f => f()); diff --git a/tests/tests/src/hash_test.js b/tests/tests/src/hash_test.js index 49dcf1992b..d0573d3860 100644 --- a/tests/tests/src/hash_test.js +++ b/tests/tests/src/hash_test.js @@ -2,9 +2,9 @@ 'use strict'; let Mt = require("./mt.js"); -let Hashtbl = require("rescript/lib/js/Hashtbl.js"); let Mt_global = require("./mt_global.js"); let Belt_Array = require("rescript/lib/js/Belt_Array.js"); +let Ocaml_Hashtbl = require("./ocaml_compat/Ocaml_Hashtbl.js"); let suites = { contents: /* [] */0 @@ -60,19 +60,22 @@ function normalize(x) { } function caml_hash(x) { - return Hashtbl.hash(x) & 1073741823; + return Ocaml_Hashtbl.hash(x) & 1073741823; } -eq("File \"hash_test.res\", line 46, characters 12-19", Belt_Array.map(test_strings, caml_hash), test_strings_hash_results); +eq("File \"hash_test.res\", line 48, characters 12-19", Belt_Array.map(test_strings, caml_hash), test_strings_hash_results); -eq("File \"hash_test.res\", line 48, characters 12-19", Hashtbl.hash(0) & 1073741823, 129913994); +eq("File \"hash_test.res\", line 50, characters 12-19", Ocaml_Hashtbl.hash(0) & 1073741823, 129913994); -eq("File \"hash_test.res\", line 50, characters 12-19", Hashtbl.hash("x") & 1073741823, 780510073); +eq("File \"hash_test.res\", line 52, characters 12-19", Ocaml_Hashtbl.hash("x") & 1073741823, 780510073); -eq("File \"hash_test.res\", line 52, characters 12-19", Hashtbl.hash("xy") & 1073741823, 194127723); +eq("File \"hash_test.res\", line 54, characters 12-19", Ocaml_Hashtbl.hash("xy") & 1073741823, 194127723); Mt.from_pair_suites("Hash_test", suites.contents); +let Hashtbl; + +exports.Hashtbl = Hashtbl; exports.suites = suites; exports.test_id = test_id; exports.eq = eq; diff --git a/tests/tests/src/hash_test.res b/tests/tests/src/hash_test.res index ba578bbb28..86a1150475 100644 --- a/tests/tests/src/hash_test.res +++ b/tests/tests/src/hash_test.res @@ -1,5 +1,7 @@ open Belt +module Hashtbl = Ocaml_Hashtbl + let suites: ref = ref(list{}) let test_id = ref(0) let eq = (f, x, y) => Mt_global.collect_eq(test_id, suites, f, x, y) diff --git a/tests/tests/src/inline_regression_test.js b/tests/tests/src/inline_regression_test.js index 60abed5b40..ca32d92e24 100644 --- a/tests/tests/src/inline_regression_test.js +++ b/tests/tests/src/inline_regression_test.js @@ -54,6 +54,9 @@ let suites = { Mt.from_pair_suites("Inline_regression_test", suites); +let $$String; + +exports.$$String = $$String; exports.generic_basename = generic_basename; exports.basename = basename; exports.suites = suites; diff --git a/tests/tests/src/inline_regression_test.res b/tests/tests/src/inline_regression_test.res index 4b197bf34b..ce53ef4958 100644 --- a/tests/tests/src/inline_regression_test.res +++ b/tests/tests/src/inline_regression_test.res @@ -1,3 +1,5 @@ +module String = Ocaml_String + let generic_basename = (is_dir_sep, current_dir_name, name) => { let rec find_end = n => if n < 0 { diff --git a/tests/tests/src/int_overflow_test.js b/tests/tests/src/int_overflow_test.js index 68ae7452db..b484e987bd 100644 --- a/tests/tests/src/int_overflow_test.js +++ b/tests/tests/src/int_overflow_test.js @@ -92,7 +92,7 @@ Mt.from_pair_suites("Int_overflow_test", { ], tl: { hd: [ - "File \"int_overflow_test.res\", line 72, characters 5-12", + "File \"int_overflow_test.res\", line 74, characters 5-12", () => ({ TAG: "Eq", _0: hash_variant2("xxyyzzuuxxzzyy00112233"), @@ -101,7 +101,7 @@ Mt.from_pair_suites("Int_overflow_test", { ], tl: { hd: [ - "File \"int_overflow_test.res\", line 73, characters 5-12", + "File \"int_overflow_test.res\", line 75, characters 5-12", () => ({ TAG: "Eq", _0: hash_variant2("xxyyzxzzyy"), @@ -128,7 +128,7 @@ Mt.from_pair_suites("Int_overflow_test", { ], tl: { hd: [ - "File \"int_overflow_test.res\", line 76, characters 5-12", + "File \"int_overflow_test.res\", line 78, characters 5-12", () => ({ TAG: "Eq", _0: Number("3") | 0, @@ -137,7 +137,7 @@ Mt.from_pair_suites("Int_overflow_test", { ], tl: { hd: [ - "File \"int_overflow_test.res\", line 78, characters 5-12", + "File \"int_overflow_test.res\", line 80, characters 5-12", () => ({ TAG: "Eq", _0: Number("3.2") | 0, @@ -158,10 +158,13 @@ Mt.from_pair_suites("Int_overflow_test", { } }); +let $$String; + let max_int = 2147483647; let min_int = -2147483648; +exports.$$String = $$String; exports.max_int = max_int; exports.min_int = min_int; exports.hash_variant = hash_variant; diff --git a/tests/tests/src/int_overflow_test.res b/tests/tests/src/int_overflow_test.res index 018a004720..8a949d089f 100644 --- a/tests/tests/src/int_overflow_test.res +++ b/tests/tests/src/int_overflow_test.res @@ -1,5 +1,7 @@ @@warning("-107") +module String = Ocaml_String + let max_int = 2147483647 // 0x80000000 let min_int = -2147483648 // 0x7FFFFFFF diff --git a/tests/tests/src/js_exception_catch_test.js b/tests/tests/src/js_exception_catch_test.js index 54f13628b4..60a773a8a0 100644 --- a/tests/tests/src/js_exception_catch_test.js +++ b/tests/tests/src/js_exception_catch_test.js @@ -2,7 +2,7 @@ 'use strict'; let Mt = require("./mt.js"); -let Js_exn = require("rescript/lib/js/Js_exn.js"); +let Exn = require("rescript/lib/js/Exn.js"); let Pervasives = require("rescript/lib/js/Pervasives.js"); let Primitive_exceptions = require("rescript/lib/js/Primitive_exceptions.js"); @@ -57,7 +57,7 @@ try { exit = 1; } catch (raw_x) { let x = Primitive_exceptions.internalToException(raw_x); - if (x.RE_EXN_ID === Js_exn.$$Error) { + if (x.RE_EXN_ID === Exn.$$Error) { add_test("File \"js_exception_catch_test.res\", line 18, characters 37-44", () => ({ TAG: "Ok", _0: true @@ -108,7 +108,7 @@ function test(f) { } else { return "C"; } - } else if (e.RE_EXN_ID === Js_exn.$$Error) { + } else if (e.RE_EXN_ID === Exn.$$Error) { return "Js_error"; } else { return "Any"; @@ -170,7 +170,7 @@ eq("File \"js_exception_catch_test.res\", line 52, characters 5-12", test(() => }; }), "C_any"); -eq("File \"js_exception_catch_test.res\", line 53, characters 5-12", test(() => Js_exn.raiseError("x")), "Js_error"); +eq("File \"js_exception_catch_test.res\", line 53, characters 5-12", test(() => Exn.raiseError("x")), "Js_error"); eq("File \"js_exception_catch_test.res\", line 54, characters 5-12", test(() => Pervasives.failwith("x")), "Any"); diff --git a/tests/tests/src/js_json_test.js b/tests/tests/src/js_json_test.js index 26c369b56b..c4ca3be08c 100644 --- a/tests/tests/src/js_json_test.js +++ b/tests/tests/src/js_json_test.js @@ -53,7 +53,7 @@ function true_(loc) { let v = JSON.parse(" { \"x\" : [1, 2, 3 ] } "); -add_test("File \"js_json_test.res\", line 22, characters 11-18", () => { +add_test("File \"js_json_test.res\", line 23, characters 11-18", () => { let ty = Js_json.classify(v); if (typeof ty !== "object") { return { @@ -94,7 +94,7 @@ add_test("File \"js_json_test.res\", line 22, characters 11-18", () => { RE_EXN_ID: "Assert_failure", _1: [ "js_json_test.res", - 38, + 39, 21 ], Error: new Error() @@ -107,7 +107,7 @@ add_test("File \"js_json_test.res\", line 22, characters 11-18", () => { RE_EXN_ID: "Assert_failure", _1: [ "js_json_test.res", - 38, + 39, 21 ], Error: new Error() @@ -119,7 +119,7 @@ add_test("File \"js_json_test.res\", line 22, characters 11-18", () => { }; }); -eq("File \"js_json_test.res\", line 50, characters 5-12", Js_json.test(v, "Object"), true); +eq("File \"js_json_test.res\", line 51, characters 5-12", Js_json.test(v, "Object"), true); let json = JSON.parse(JSON.stringify(null)); @@ -127,20 +127,20 @@ let ty = Js_json.classify(json); if (typeof ty !== "object") { if (ty === "JSONNull") { - add_test("File \"js_json_test.res\", line 57, characters 24-31", () => ({ + add_test("File \"js_json_test.res\", line 58, characters 24-31", () => ({ TAG: "Ok", _0: true })); } else { console.log(ty); - add_test("File \"js_json_test.res\", line 60, characters 11-18", () => ({ + add_test("File \"js_json_test.res\", line 61, characters 11-18", () => ({ TAG: "Ok", _0: false })); } } else { console.log(ty); - add_test("File \"js_json_test.res\", line 60, characters 11-18", () => ({ + add_test("File \"js_json_test.res\", line 61, characters 11-18", () => ({ TAG: "Ok", _0: false })); @@ -151,14 +151,14 @@ let json$1 = JSON.parse(JSON.stringify("test string")); let ty$1 = Js_json.classify(json$1); if (typeof ty$1 !== "object") { - add_test("File \"js_json_test.res\", line 70, characters 16-23", () => ({ + add_test("File \"js_json_test.res\", line 71, characters 16-23", () => ({ TAG: "Ok", _0: false })); } else if (ty$1.TAG === "JSONString") { - eq("File \"js_json_test.res\", line 69, characters 26-33", ty$1._0, "test string"); + eq("File \"js_json_test.res\", line 70, characters 26-33", ty$1._0, "test string"); } else { - add_test("File \"js_json_test.res\", line 70, characters 16-23", () => ({ + add_test("File \"js_json_test.res\", line 71, characters 16-23", () => ({ TAG: "Ok", _0: false })); @@ -173,11 +173,11 @@ let exit = 0; if (typeof ty$2 !== "object" || ty$2.TAG !== "JSONNumber") { exit = 1; } else { - eq("File \"js_json_test.res\", line 79, characters 26-33", ty$2._0, 1.23456789); + eq("File \"js_json_test.res\", line 80, characters 26-33", ty$2._0, 1.23456789); } if (exit === 1) { - add_test("File \"js_json_test.res\", line 80, characters 18-25", () => ({ + add_test("File \"js_json_test.res\", line 81, characters 18-25", () => ({ TAG: "Ok", _0: false })); @@ -192,11 +192,11 @@ let exit$1 = 0; if (typeof ty$3 !== "object" || ty$3.TAG !== "JSONNumber") { exit$1 = 1; } else { - eq("File \"js_json_test.res\", line 89, characters 26-33", ty$3._0 | 0, -1347440721); + eq("File \"js_json_test.res\", line 90, characters 26-33", ty$3._0 | 0, -1347440721); } if (exit$1 === 1) { - add_test("File \"js_json_test.res\", line 90, characters 18-25", () => ({ + add_test("File \"js_json_test.res\", line 91, characters 18-25", () => ({ TAG: "Ok", _0: false })); @@ -206,18 +206,18 @@ function test(v) { let json = JSON.parse(JSON.stringify(v)); let ty = Js_json.classify(json); if (typeof ty === "object") { - return add_test("File \"js_json_test.res\", line 102, characters 18-25", () => ({ + return add_test("File \"js_json_test.res\", line 103, characters 18-25", () => ({ TAG: "Ok", _0: false })); } switch (ty) { case "JSONFalse" : - return eq("File \"js_json_test.res\", line 101, characters 24-31", false, v); + return eq("File \"js_json_test.res\", line 102, characters 24-31", false, v); case "JSONTrue" : - return eq("File \"js_json_test.res\", line 100, characters 23-30", true, v); + return eq("File \"js_json_test.res\", line 101, characters 23-30", true, v); default: - return add_test("File \"js_json_test.res\", line 102, characters 18-25", () => ({ + return add_test("File \"js_json_test.res\", line 103, characters 18-25", () => ({ TAG: "Ok", _0: false })); @@ -236,7 +236,7 @@ function option_get(x) { RE_EXN_ID: "Assert_failure", _1: [ "js_json_test.res", - 113, + 114, 12 ], Error: new Error() @@ -254,7 +254,7 @@ let json$4 = JSON.parse(JSON.stringify(dict)); let ty$4 = Js_json.classify(json$4); if (typeof ty$4 !== "object") { - add_test("File \"js_json_test.res\", line 144, characters 16-23", () => ({ + add_test("File \"js_json_test.res\", line 145, characters 16-23", () => ({ TAG: "Ok", _0: false })); @@ -262,45 +262,45 @@ if (typeof ty$4 !== "object") { let x = ty$4._0; let ta = Js_json.classify(option_get(Js_dict.get(x, "a"))); if (typeof ta !== "object") { - add_test("File \"js_json_test.res\", line 142, characters 18-25", () => ({ + add_test("File \"js_json_test.res\", line 143, characters 18-25", () => ({ TAG: "Ok", _0: false })); } else if (ta.TAG === "JSONString") { if (ta._0 !== "test string") { - add_test("File \"js_json_test.res\", line 133, characters 15-22", () => ({ + add_test("File \"js_json_test.res\", line 134, characters 15-22", () => ({ TAG: "Ok", _0: false })); } else { let ty$5 = Js_json.classify(option_get(Js_dict.get(x, "b"))); if (typeof ty$5 !== "object") { - add_test("File \"js_json_test.res\", line 139, characters 22-29", () => ({ + add_test("File \"js_json_test.res\", line 140, characters 22-29", () => ({ TAG: "Ok", _0: false })); } else if (ty$5.TAG === "JSONNumber") { let b = ty$5._0; - add_test("File \"js_json_test.res\", line 138, characters 38-45", () => ({ + add_test("File \"js_json_test.res\", line 139, characters 38-45", () => ({ TAG: "Approx", _0: 123.0, _1: b })); } else { - add_test("File \"js_json_test.res\", line 139, characters 22-29", () => ({ + add_test("File \"js_json_test.res\", line 140, characters 22-29", () => ({ TAG: "Ok", _0: false })); } } } else { - add_test("File \"js_json_test.res\", line 142, characters 18-25", () => ({ + add_test("File \"js_json_test.res\", line 143, characters 18-25", () => ({ TAG: "Ok", _0: false })); } } else { - add_test("File \"js_json_test.res\", line 144, characters 16-23", () => ({ + add_test("File \"js_json_test.res\", line 145, characters 16-23", () => ({ TAG: "Ok", _0: false })); @@ -424,11 +424,11 @@ let json$5 = JSON.parse(JSON.stringify(Belt_Array.map([ "string 2" ], prim => prim))); -eq_at_i("File \"js_json_test.res\", line 198, characters 10-17", json$5, 0, "String", "string 0"); +eq_at_i("File \"js_json_test.res\", line 199, characters 10-17", json$5, 0, "String", "string 0"); -eq_at_i("File \"js_json_test.res\", line 199, characters 10-17", json$5, 1, "String", "string 1"); +eq_at_i("File \"js_json_test.res\", line 200, characters 10-17", json$5, 1, "String", "string 1"); -eq_at_i("File \"js_json_test.res\", line 200, characters 10-17", json$5, 2, "String", "string 2"); +eq_at_i("File \"js_json_test.res\", line 201, characters 10-17", json$5, 2, "String", "string 2"); let json$6 = JSON.parse(JSON.stringify([ "string 0", @@ -436,11 +436,11 @@ let json$6 = JSON.parse(JSON.stringify([ "string 2" ])); -eq_at_i("File \"js_json_test.res\", line 207, characters 10-17", json$6, 0, "String", "string 0"); +eq_at_i("File \"js_json_test.res\", line 208, characters 10-17", json$6, 0, "String", "string 0"); -eq_at_i("File \"js_json_test.res\", line 208, characters 10-17", json$6, 1, "String", "string 1"); +eq_at_i("File \"js_json_test.res\", line 209, characters 10-17", json$6, 1, "String", "string 1"); -eq_at_i("File \"js_json_test.res\", line 209, characters 10-17", json$6, 2, "String", "string 2"); +eq_at_i("File \"js_json_test.res\", line 210, characters 10-17", json$6, 2, "String", "string 2"); let a = [ 1.0000001, @@ -450,11 +450,11 @@ let a = [ let json$7 = JSON.parse(JSON.stringify(a)); -eq_at_i("File \"js_json_test.res\", line 218, characters 10-17", json$7, 0, "Number", Primitive_array.get(a, 0)); +eq_at_i("File \"js_json_test.res\", line 219, characters 10-17", json$7, 0, "Number", Primitive_array.get(a, 0)); -eq_at_i("File \"js_json_test.res\", line 219, characters 10-17", json$7, 1, "Number", Primitive_array.get(a, 1)); +eq_at_i("File \"js_json_test.res\", line 220, characters 10-17", json$7, 1, "Number", Primitive_array.get(a, 1)); -eq_at_i("File \"js_json_test.res\", line 220, characters 10-17", json$7, 2, "Number", Primitive_array.get(a, 2)); +eq_at_i("File \"js_json_test.res\", line 221, characters 10-17", json$7, 2, "Number", Primitive_array.get(a, 2)); let a$1 = [ 0, @@ -464,11 +464,11 @@ let a$1 = [ let json$8 = JSON.parse(JSON.stringify(Belt_Array.map(a$1, prim => prim))); -eq_at_i("File \"js_json_test.res\", line 229, characters 10-17", json$8, 0, "Number", Primitive_array.get(a$1, 0)); +eq_at_i("File \"js_json_test.res\", line 230, characters 10-17", json$8, 0, "Number", Primitive_array.get(a$1, 0)); -eq_at_i("File \"js_json_test.res\", line 230, characters 10-17", json$8, 1, "Number", Primitive_array.get(a$1, 1)); +eq_at_i("File \"js_json_test.res\", line 231, characters 10-17", json$8, 1, "Number", Primitive_array.get(a$1, 1)); -eq_at_i("File \"js_json_test.res\", line 231, characters 10-17", json$8, 2, "Number", Primitive_array.get(a$1, 2)); +eq_at_i("File \"js_json_test.res\", line 232, characters 10-17", json$8, 2, "Number", Primitive_array.get(a$1, 2)); let a$2 = [ true, @@ -478,11 +478,11 @@ let a$2 = [ let json$9 = JSON.parse(JSON.stringify(a$2)); -eq_at_i("File \"js_json_test.res\", line 240, characters 10-17", json$9, 0, "Boolean", Primitive_array.get(a$2, 0)); +eq_at_i("File \"js_json_test.res\", line 241, characters 10-17", json$9, 0, "Boolean", Primitive_array.get(a$2, 0)); -eq_at_i("File \"js_json_test.res\", line 241, characters 10-17", json$9, 1, "Boolean", Primitive_array.get(a$2, 1)); +eq_at_i("File \"js_json_test.res\", line 242, characters 10-17", json$9, 1, "Boolean", Primitive_array.get(a$2, 1)); -eq_at_i("File \"js_json_test.res\", line 242, characters 10-17", json$9, 2, "Boolean", Primitive_array.get(a$2, 2)); +eq_at_i("File \"js_json_test.res\", line 243, characters 10-17", json$9, 2, "Boolean", Primitive_array.get(a$2, 2)); function make_d(s, i) { let d = {}; @@ -501,40 +501,40 @@ let json$10 = JSON.parse(JSON.stringify(a$3)); let ty$6 = Js_json.classify(json$10); if (typeof ty$6 !== "object") { - add_test("File \"js_json_test.res\", line 270, characters 16-23", () => ({ + add_test("File \"js_json_test.res\", line 271, characters 16-23", () => ({ TAG: "Ok", _0: false })); } else if (ty$6.TAG === "JSONArray") { let ty$7 = Js_json.classify(Primitive_array.get(ty$6._0, 1)); if (typeof ty$7 !== "object") { - add_test("File \"js_json_test.res\", line 268, characters 18-25", () => ({ + add_test("File \"js_json_test.res\", line 269, characters 18-25", () => ({ TAG: "Ok", _0: false })); } else if (ty$7.TAG === "JSONObject") { let ty$8 = Js_json.classify(option_get(Js_dict.get(ty$7._0, "a"))); if (typeof ty$8 !== "object") { - add_test("File \"js_json_test.res\", line 266, characters 20-27", () => ({ + add_test("File \"js_json_test.res\", line 267, characters 20-27", () => ({ TAG: "Ok", _0: false })); } else if (ty$8.TAG === "JSONString") { - eq("File \"js_json_test.res\", line 265, characters 35-42", ty$8._0, "bbb"); + eq("File \"js_json_test.res\", line 266, characters 35-42", ty$8._0, "bbb"); } else { - add_test("File \"js_json_test.res\", line 266, characters 20-27", () => ({ + add_test("File \"js_json_test.res\", line 267, characters 20-27", () => ({ TAG: "Ok", _0: false })); } } else { - add_test("File \"js_json_test.res\", line 268, characters 18-25", () => ({ + add_test("File \"js_json_test.res\", line 269, characters 18-25", () => ({ TAG: "Ok", _0: false })); } } else { - add_test("File \"js_json_test.res\", line 270, characters 16-23", () => ({ + add_test("File \"js_json_test.res\", line 271, characters 16-23", () => ({ TAG: "Ok", _0: false })); @@ -542,24 +542,24 @@ if (typeof ty$6 !== "object") { try { JSON.parse("{{ A}"); - add_test("File \"js_json_test.res\", line 278, characters 11-18", () => ({ + add_test("File \"js_json_test.res\", line 279, characters 11-18", () => ({ TAG: "Ok", _0: false })); } catch (exn) { - add_test("File \"js_json_test.res\", line 280, characters 17-24", () => ({ + add_test("File \"js_json_test.res\", line 281, characters 17-24", () => ({ TAG: "Ok", _0: true })); } -eq("File \"js_json_test.res\", line 286, characters 12-19", JSON.stringify([ +eq("File \"js_json_test.res\", line 287, characters 12-19", JSON.stringify([ 1, 2, 3 ]), "[1,2,3]"); -eq("File \"js_json_test.res\", line 289, characters 2-9", JSON.stringify({ +eq("File \"js_json_test.res\", line 290, characters 2-9", JSON.stringify({ foo: 1, bar: "hello", baz: { @@ -567,88 +567,88 @@ eq("File \"js_json_test.res\", line 289, characters 2-9", JSON.stringify({ } }), "{\"foo\":1,\"bar\":\"hello\",\"baz\":{\"baaz\":10}}"); -eq("File \"js_json_test.res\", line 294, characters 12-19", JSON.stringify(null), "null"); +eq("File \"js_json_test.res\", line 295, characters 12-19", JSON.stringify(null), "null"); -eq("File \"js_json_test.res\", line 296, characters 12-19", JSON.stringify(undefined), undefined); +eq("File \"js_json_test.res\", line 297, characters 12-19", JSON.stringify(undefined), undefined); -eq("File \"js_json_test.res\", line 299, characters 5-12", Js_json.decodeString("test"), "test"); +eq("File \"js_json_test.res\", line 300, characters 5-12", Js_json.decodeString("test"), "test"); -eq("File \"js_json_test.res\", line 300, characters 5-12", Js_json.decodeString(true), undefined); +eq("File \"js_json_test.res\", line 301, characters 5-12", Js_json.decodeString(true), undefined); -eq("File \"js_json_test.res\", line 301, characters 5-12", Js_json.decodeString([]), undefined); +eq("File \"js_json_test.res\", line 302, characters 5-12", Js_json.decodeString([]), undefined); -eq("File \"js_json_test.res\", line 302, characters 5-12", Js_json.decodeString(null), undefined); +eq("File \"js_json_test.res\", line 303, characters 5-12", Js_json.decodeString(null), undefined); -eq("File \"js_json_test.res\", line 303, characters 5-12", Js_json.decodeString({}), undefined); +eq("File \"js_json_test.res\", line 304, characters 5-12", Js_json.decodeString({}), undefined); -eq("File \"js_json_test.res\", line 304, characters 5-12", Js_json.decodeString(1.23), undefined); +eq("File \"js_json_test.res\", line 305, characters 5-12", Js_json.decodeString(1.23), undefined); -eq("File \"js_json_test.res\", line 308, characters 5-12", Js_json.decodeNumber("test"), undefined); +eq("File \"js_json_test.res\", line 309, characters 5-12", Js_json.decodeNumber("test"), undefined); -eq("File \"js_json_test.res\", line 309, characters 5-12", Js_json.decodeNumber(true), undefined); +eq("File \"js_json_test.res\", line 310, characters 5-12", Js_json.decodeNumber(true), undefined); -eq("File \"js_json_test.res\", line 310, characters 5-12", Js_json.decodeNumber([]), undefined); +eq("File \"js_json_test.res\", line 311, characters 5-12", Js_json.decodeNumber([]), undefined); -eq("File \"js_json_test.res\", line 311, characters 5-12", Js_json.decodeNumber(null), undefined); +eq("File \"js_json_test.res\", line 312, characters 5-12", Js_json.decodeNumber(null), undefined); -eq("File \"js_json_test.res\", line 312, characters 5-12", Js_json.decodeNumber({}), undefined); +eq("File \"js_json_test.res\", line 313, characters 5-12", Js_json.decodeNumber({}), undefined); -eq("File \"js_json_test.res\", line 313, characters 5-12", Js_json.decodeNumber(1.23), 1.23); +eq("File \"js_json_test.res\", line 314, characters 5-12", Js_json.decodeNumber(1.23), 1.23); -eq("File \"js_json_test.res\", line 317, characters 5-12", Js_json.decodeObject("test"), undefined); +eq("File \"js_json_test.res\", line 318, characters 5-12", Js_json.decodeObject("test"), undefined); -eq("File \"js_json_test.res\", line 318, characters 5-12", Js_json.decodeObject(true), undefined); +eq("File \"js_json_test.res\", line 319, characters 5-12", Js_json.decodeObject(true), undefined); -eq("File \"js_json_test.res\", line 319, characters 5-12", Js_json.decodeObject([]), undefined); +eq("File \"js_json_test.res\", line 320, characters 5-12", Js_json.decodeObject([]), undefined); -eq("File \"js_json_test.res\", line 320, characters 5-12", Js_json.decodeObject(null), undefined); +eq("File \"js_json_test.res\", line 321, characters 5-12", Js_json.decodeObject(null), undefined); -eq("File \"js_json_test.res\", line 321, characters 5-12", Js_json.decodeObject({}), {}); +eq("File \"js_json_test.res\", line 322, characters 5-12", Js_json.decodeObject({}), {}); -eq("File \"js_json_test.res\", line 322, characters 5-12", Js_json.decodeObject(1.23), undefined); +eq("File \"js_json_test.res\", line 323, characters 5-12", Js_json.decodeObject(1.23), undefined); -eq("File \"js_json_test.res\", line 326, characters 5-12", Js_json.decodeArray("test"), undefined); +eq("File \"js_json_test.res\", line 327, characters 5-12", Js_json.decodeArray("test"), undefined); -eq("File \"js_json_test.res\", line 327, characters 5-12", Js_json.decodeArray(true), undefined); +eq("File \"js_json_test.res\", line 328, characters 5-12", Js_json.decodeArray(true), undefined); -eq("File \"js_json_test.res\", line 328, characters 5-12", Js_json.decodeArray([]), []); +eq("File \"js_json_test.res\", line 329, characters 5-12", Js_json.decodeArray([]), []); -eq("File \"js_json_test.res\", line 329, characters 5-12", Js_json.decodeArray(null), undefined); +eq("File \"js_json_test.res\", line 330, characters 5-12", Js_json.decodeArray(null), undefined); -eq("File \"js_json_test.res\", line 330, characters 5-12", Js_json.decodeArray({}), undefined); +eq("File \"js_json_test.res\", line 331, characters 5-12", Js_json.decodeArray({}), undefined); -eq("File \"js_json_test.res\", line 331, characters 5-12", Js_json.decodeArray(1.23), undefined); +eq("File \"js_json_test.res\", line 332, characters 5-12", Js_json.decodeArray(1.23), undefined); -eq("File \"js_json_test.res\", line 335, characters 5-12", Js_json.decodeBoolean("test"), undefined); +eq("File \"js_json_test.res\", line 336, characters 5-12", Js_json.decodeBoolean("test"), undefined); -eq("File \"js_json_test.res\", line 336, characters 5-12", Js_json.decodeBoolean(true), true); +eq("File \"js_json_test.res\", line 337, characters 5-12", Js_json.decodeBoolean(true), true); -eq("File \"js_json_test.res\", line 337, characters 5-12", Js_json.decodeBoolean([]), undefined); +eq("File \"js_json_test.res\", line 338, characters 5-12", Js_json.decodeBoolean([]), undefined); -eq("File \"js_json_test.res\", line 338, characters 5-12", Js_json.decodeBoolean(null), undefined); +eq("File \"js_json_test.res\", line 339, characters 5-12", Js_json.decodeBoolean(null), undefined); -eq("File \"js_json_test.res\", line 339, characters 5-12", Js_json.decodeBoolean({}), undefined); +eq("File \"js_json_test.res\", line 340, characters 5-12", Js_json.decodeBoolean({}), undefined); -eq("File \"js_json_test.res\", line 340, characters 5-12", Js_json.decodeBoolean(1.23), undefined); +eq("File \"js_json_test.res\", line 341, characters 5-12", Js_json.decodeBoolean(1.23), undefined); -eq("File \"js_json_test.res\", line 344, characters 5-12", Js_json.decodeNull("test"), undefined); +eq("File \"js_json_test.res\", line 345, characters 5-12", Js_json.decodeNull("test"), undefined); -eq("File \"js_json_test.res\", line 345, characters 5-12", Js_json.decodeNull(true), undefined); +eq("File \"js_json_test.res\", line 346, characters 5-12", Js_json.decodeNull(true), undefined); -eq("File \"js_json_test.res\", line 346, characters 5-12", Js_json.decodeNull([]), undefined); +eq("File \"js_json_test.res\", line 347, characters 5-12", Js_json.decodeNull([]), undefined); -eq("File \"js_json_test.res\", line 347, characters 5-12", Js_json.decodeNull(null), null); +eq("File \"js_json_test.res\", line 348, characters 5-12", Js_json.decodeNull(null), null); -eq("File \"js_json_test.res\", line 348, characters 5-12", Js_json.decodeNull({}), undefined); +eq("File \"js_json_test.res\", line 349, characters 5-12", Js_json.decodeNull({}), undefined); -eq("File \"js_json_test.res\", line 349, characters 5-12", Js_json.decodeNull(1.23), undefined); +eq("File \"js_json_test.res\", line 350, characters 5-12", Js_json.decodeNull(1.23), undefined); function id(obj) { return Js_json.deserializeUnsafe(Js_json.serializeExn(obj)); } function idtest(obj) { - eq("File \"js_json_test.res\", line 354, characters 23-30", obj, Js_json.deserializeUnsafe(Js_json.serializeExn(obj))); + eq("File \"js_json_test.res\", line 355, characters 23-30", obj, Js_json.deserializeUnsafe(Js_json.serializeExn(obj))); } idtest(undefined); @@ -682,8 +682,11 @@ Mt.from_pair_suites("Js_json_test", suites.contents); let J; +let $$Array; + exports.suites = suites; exports.J = J; +exports.$$Array = $$Array; exports.add_test = add_test; exports.eq = eq; exports.false_ = false_; diff --git a/tests/tests/src/js_json_test.res b/tests/tests/src/js_json_test.res index 58e03d5e80..15558f9aeb 100644 --- a/tests/tests/src/js_json_test.res +++ b/tests/tests/src/js_json_test.res @@ -1,5 +1,6 @@ let suites: ref = ref(list{}) module J = Js.Json +module Array = Ocaml_Array let add_test = { let counter = ref(0) diff --git a/tests/tests/src/js_re_test.js b/tests/tests/src/js_re_test.js index 1d84b0fc9e..c202252c06 100644 --- a/tests/tests/src/js_re_test.js +++ b/tests/tests/src/js_re_test.js @@ -272,5 +272,8 @@ let suites = { Mt.from_pair_suites("Js_re_test", suites); +let $$Array; + +exports.$$Array = $$Array; exports.suites = suites; /* Not a pure module */ diff --git a/tests/tests/src/js_re_test.res b/tests/tests/src/js_re_test.res index 21a0e6b550..925cf2c385 100644 --- a/tests/tests/src/js_re_test.res +++ b/tests/tests/src/js_re_test.res @@ -1,3 +1,5 @@ +module Array = Ocaml_Array + let suites = { open Mt list{ diff --git a/tests/tests/src/module_missing_conversion.js b/tests/tests/src/module_missing_conversion.js index a581664ab4..79576d6618 100644 --- a/tests/tests/src/module_missing_conversion.js +++ b/tests/tests/src/module_missing_conversion.js @@ -88,7 +88,10 @@ let u = [$$String]; let hh = "x".length; +let $$Array; + +exports.$$Array = $$Array; exports.XX = XX; exports.u = u; exports.hh = hh; -/* No side effect */ +/* hh Not a pure module */ diff --git a/tests/tests/src/module_missing_conversion.res b/tests/tests/src/module_missing_conversion.res index 840637ee29..1265746701 100644 --- a/tests/tests/src/module_missing_conversion.res +++ b/tests/tests/src/module_missing_conversion.res @@ -1,3 +1,5 @@ +module Array = Ocaml_Array + module type S = module type of String module XX = { diff --git a/tests/tests/src/module_parameter_test.js b/tests/tests/src/module_parameter_test.js index 029ab2d8d6..d34dbf1226 100644 --- a/tests/tests/src/module_parameter_test.js +++ b/tests/tests/src/module_parameter_test.js @@ -53,4 +53,4 @@ exports.N = N; exports.v0 = v0; exports.v = v; exports.suites = suites; -/* Not a pure module */ +/* v0 Not a pure module */ diff --git a/tests/tests/src/ocaml_compat/Ocaml_Array.js b/tests/tests/src/ocaml_compat/Ocaml_Array.js new file mode 100644 index 0000000000..15cf696cd9 --- /dev/null +++ b/tests/tests/src/ocaml_compat/Ocaml_Array.js @@ -0,0 +1,480 @@ +// Generated by ReScript, PLEASE EDIT WITH CARE +'use strict'; + +let Ocaml_List = require("./Ocaml_List.js"); +let Pervasives = require("rescript/lib/js/Pervasives.js"); +let Primitive_array = require("rescript/lib/js/Primitive_array.js"); +let Primitive_exceptions = require("rescript/lib/js/Primitive_exceptions.js"); + +let init = ((length, f) => Array.from({ length }, f)); + +function make(len, x) { + return init(len, param => x); +} + +function unsafe_sub(array, offset, length) { + return array.slice(offset, offset + length | 0); +} + +function concat(list) { + return Ocaml_List.fold_left((arr1, arr2) => arr1.concat(arr2), [], list); +} + +function create_float(len) { + return init(len, param => 0.0); +} + +function make_matrix(sx, sy, init$1) { + let x = []; + let res = init(sx, param => x); + for (let x$1 = 0; x$1 < sx; ++x$1) { + res[x$1] = init(sy, param => init$1); + } + return res; +} + +function append(a1, a2) { + let l1 = a1.length; + if (l1 === 0) { + return a2.slice(); + } else if (a2.length === 0) { + return unsafe_sub(a1, 0, l1); + } else { + return a1.concat(a2); + } +} + +function sub(a, ofs, len) { + if (ofs < 0 || len < 0 || ofs > (a.length - len | 0)) { + return Pervasives.invalid_arg("Array.sub"); + } else { + return unsafe_sub(a, ofs, len); + } +} + +function fill(a, ofs, len, v) { + if (ofs < 0 || len < 0 || ofs > (a.length - len | 0)) { + return Pervasives.invalid_arg("Array.fill"); + } + for (let i = ofs, i_finish = ofs + len | 0; i < i_finish; ++i) { + a[i] = v; + } +} + +function blit(a1, ofs1, a2, ofs2, len) { + if (len < 0 || ofs1 < 0 || ofs1 > (a1.length - len | 0) || ofs2 < 0 || ofs2 > (a2.length - len | 0)) { + return Pervasives.invalid_arg("Array.blit"); + } else { + for (let i = 0; i < len; ++i) { + a2[ofs2 + i | 0] = a1[ofs1 + i | 0]; + } + return; + } +} + +function iter(f, a) { + for (let i = 0, i_finish = a.length; i < i_finish; ++i) { + f(a[i]); + } +} + +function iter2(f, a, b) { + if (a.length !== b.length) { + return Pervasives.invalid_arg("Array.iter2: arrays must have the same length"); + } + for (let i = 0, i_finish = a.length; i < i_finish; ++i) { + f(a[i], b[i]); + } +} + +function map(f, a) { + let l = a.length; + if (l === 0) { + return []; + } + let x = f(a[0]); + let r = init(l, param => x); + for (let i = 1; i < l; ++i) { + r[i] = f(a[i]); + } + return r; +} + +function map2(f, a, b) { + let la = a.length; + let lb = b.length; + if (la !== lb) { + return Pervasives.invalid_arg("Array.map2: arrays must have the same length"); + } + if (la === 0) { + return []; + } + let x = f(a[0], b[0]); + let r = init(la, param => x); + for (let i = 1; i < la; ++i) { + r[i] = f(a[i], b[i]); + } + return r; +} + +function iteri(f, a) { + for (let i = 0, i_finish = a.length; i < i_finish; ++i) { + f(i, a[i]); + } +} + +function mapi(f, a) { + let l = a.length; + if (l === 0) { + return []; + } + let x = f(0, a[0]); + let r = init(l, param => x); + for (let i = 1; i < l; ++i) { + r[i] = f(i, a[i]); + } + return r; +} + +function to_list(a) { + let _i = a.length - 1 | 0; + let _res = /* [] */0; + while (true) { + let res = _res; + let i = _i; + if (i < 0) { + return res; + } + _res = { + hd: a[i], + tl: res + }; + _i = i - 1 | 0; + continue; + }; +} + +function list_length(_accu, _param) { + while (true) { + let param = _param; + let accu = _accu; + if (!param) { + return accu; + } + _param = param.tl; + _accu = accu + 1 | 0; + continue; + }; +} + +function of_list(param) { + if (!param) { + return []; + } + let hd = param.hd; + let len = list_length(0, param); + let a = init(len, param => hd); + let _i = 1; + let _param = param.tl; + while (true) { + let param$1 = _param; + let i = _i; + if (!param$1) { + return a; + } + a[i] = param$1.hd; + _param = param$1.tl; + _i = i + 1 | 0; + continue; + }; +} + +function fold_left(f, x, a) { + let r = x; + for (let i = 0, i_finish = a.length; i < i_finish; ++i) { + r = f(r, a[i]); + } + return r; +} + +function fold_right(f, a, x) { + let r = x; + for (let i = a.length - 1 | 0; i >= 0; --i) { + r = f(a[i], r); + } + return r; +} + +function exists(p, a) { + let n = a.length; + let _i = 0; + while (true) { + let i = _i; + if (i === n) { + return false; + } + if (p(a[i])) { + return true; + } + _i = i + 1 | 0; + continue; + }; +} + +function for_all(p, a) { + let n = a.length; + let _i = 0; + while (true) { + let i = _i; + if (i === n) { + return true; + } + if (!p(a[i])) { + return false; + } + _i = i + 1 | 0; + continue; + }; +} + +function mem(x, a) { + let n = a.length; + let _i = 0; + while (true) { + let i = _i; + if (i === n) { + return false; + } + if (a[i] === x) { + return true; + } + _i = i + 1 | 0; + continue; + }; +} + +function memq(x, a) { + let n = a.length; + let _i = 0; + while (true) { + let i = _i; + if (i === n) { + return false; + } + if (x === a[i]) { + return true; + } + _i = i + 1 | 0; + continue; + }; +} + +let Bottom = /* @__PURE__ */Primitive_exceptions.create("Ocaml_Array.Bottom"); + +function sort(cmp, a) { + let maxson = (l, i) => { + let i31 = ((i + i | 0) + i | 0) + 1 | 0; + let x = i31; + if ((i31 + 2 | 0) < l) { + if (cmp(Primitive_array.get(a, i31), Primitive_array.get(a, i31 + 1 | 0)) < 0) { + x = i31 + 1 | 0; + } + if (cmp(Primitive_array.get(a, x), Primitive_array.get(a, i31 + 2 | 0)) < 0) { + x = i31 + 2 | 0; + } + return x; + } + if ((i31 + 1 | 0) < l && cmp(Primitive_array.get(a, i31), Primitive_array.get(a, i31 + 1 | 0)) < 0) { + return i31 + 1 | 0; + } + if (i31 < l) { + return i31; + } + throw { + RE_EXN_ID: Bottom, + _1: i, + Error: new Error() + }; + }; + let trickle = (l, i, e) => { + try { + let _i = i; + while (true) { + let i$1 = _i; + let j = maxson(l, i$1); + if (cmp(Primitive_array.get(a, j), e) <= 0) { + return Primitive_array.set(a, i$1, e); + } + Primitive_array.set(a, i$1, Primitive_array.get(a, j)); + _i = j; + continue; + }; + } catch (raw_i) { + let i$2 = Primitive_exceptions.internalToException(raw_i); + if (i$2.RE_EXN_ID === Bottom) { + return Primitive_array.set(a, i$2._1, e); + } + throw i$2; + } + }; + let bubble = (l, i) => { + try { + let _i = i; + while (true) { + let i$1 = _i; + let j = maxson(l, i$1); + Primitive_array.set(a, i$1, Primitive_array.get(a, j)); + _i = j; + continue; + }; + } catch (raw_i) { + let i$2 = Primitive_exceptions.internalToException(raw_i); + if (i$2.RE_EXN_ID === Bottom) { + return i$2._1; + } + throw i$2; + } + }; + let trickleup = (_i, e) => { + while (true) { + let i = _i; + let father = (i - 1 | 0) / 3 | 0; + if (i === father) { + throw { + RE_EXN_ID: "Assert_failure", + _1: [ + "Ocaml_Array.res", + 296, + 4 + ], + Error: new Error() + }; + } + if (cmp(Primitive_array.get(a, father), e) >= 0) { + return Primitive_array.set(a, i, e); + } + Primitive_array.set(a, i, Primitive_array.get(a, father)); + if (father <= 0) { + return Primitive_array.set(a, 0, e); + } + _i = father; + continue; + }; + }; + let l = a.length; + for (let i = ((l + 1 | 0) / 3 | 0) - 1 | 0; i >= 0; --i) { + trickle(l, i, Primitive_array.get(a, i)); + } + for (let i$1 = l - 1 | 0; i$1 >= 2; --i$1) { + let e = Primitive_array.get(a, i$1); + Primitive_array.set(a, i$1, Primitive_array.get(a, 0)); + trickleup(bubble(i$1, 0), e); + } + if (l <= 1) { + return; + } + let e$1 = Primitive_array.get(a, 1); + Primitive_array.set(a, 1, Primitive_array.get(a, 0)); + Primitive_array.set(a, 0, e$1); +} + +function stable_sort(cmp, a) { + let merge = (src1ofs, src1len, src2, src2ofs, src2len, dst, dstofs) => { + let src1r = src1ofs + src1len | 0; + let src2r = src2ofs + src2len | 0; + let _i1 = src1ofs; + let _s1 = Primitive_array.get(a, src1ofs); + let _i2 = src2ofs; + let _s2 = Primitive_array.get(src2, src2ofs); + let _d = dstofs; + while (true) { + let d = _d; + let s2 = _s2; + let i2 = _i2; + let s1 = _s1; + let i1 = _i1; + if (cmp(s1, s2) <= 0) { + Primitive_array.set(dst, d, s1); + let i1$1 = i1 + 1 | 0; + if (i1$1 >= src1r) { + return blit(src2, i2, dst, d + 1 | 0, src2r - i2 | 0); + } + _d = d + 1 | 0; + _s1 = Primitive_array.get(a, i1$1); + _i1 = i1$1; + continue; + } + Primitive_array.set(dst, d, s2); + let i2$1 = i2 + 1 | 0; + if (i2$1 >= src2r) { + return blit(a, i1, dst, d + 1 | 0, src1r - i1 | 0); + } + _d = d + 1 | 0; + _s2 = Primitive_array.get(src2, i2$1); + _i2 = i2$1; + continue; + }; + }; + let isortto = (srcofs, dst, dstofs, len) => { + for (let i = 0; i < len; ++i) { + let e = Primitive_array.get(a, srcofs + i | 0); + let j = (dstofs + i | 0) - 1 | 0; + while (j >= dstofs && cmp(Primitive_array.get(dst, j), e) > 0) { + Primitive_array.set(dst, j + 1 | 0, Primitive_array.get(dst, j)); + j = j - 1 | 0; + }; + Primitive_array.set(dst, j + 1 | 0, e); + } + }; + let sortto = (srcofs, dst, dstofs, len) => { + if (len <= 5) { + return isortto(srcofs, dst, dstofs, len); + } + let l1 = len / 2 | 0; + let l2 = len - l1 | 0; + sortto(srcofs + l1 | 0, dst, dstofs + l1 | 0, l2); + sortto(srcofs, a, srcofs + l2 | 0, l1); + merge(srcofs + l2 | 0, l1, dst, dstofs + l1 | 0, l2, dst, dstofs); + }; + let l = a.length; + if (l <= 5) { + return isortto(0, a, 0, l); + } + let l1 = l / 2 | 0; + let l2 = l - l1 | 0; + let x = Primitive_array.get(a, 0); + let t = init(l2, param => x); + sortto(l1, t, 0, l2); + sortto(0, a, l2, l1); + merge(l2, l1, t, 0, l2, a, 0); +} + +let fast_sort = stable_sort; + +exports.make = make; +exports.create_float = create_float; +exports.init = init; +exports.make_matrix = make_matrix; +exports.append = append; +exports.concat = concat; +exports.sub = sub; +exports.fill = fill; +exports.blit = blit; +exports.to_list = to_list; +exports.of_list = of_list; +exports.iter = iter; +exports.iteri = iteri; +exports.map = map; +exports.mapi = mapi; +exports.fold_left = fold_left; +exports.fold_right = fold_right; +exports.iter2 = iter2; +exports.map2 = map2; +exports.for_all = for_all; +exports.exists = exists; +exports.mem = mem; +exports.memq = memq; +exports.sort = sort; +exports.stable_sort = stable_sort; +exports.fast_sort = fast_sort; +/* No side effect */ diff --git a/tests/tests/src/ocaml_compat/Ocaml_Array.res b/tests/tests/src/ocaml_compat/Ocaml_Array.res new file mode 100644 index 0000000000..a72920bd5f --- /dev/null +++ b/tests/tests/src/ocaml_compat/Ocaml_Array.res @@ -0,0 +1,385 @@ +// FIXME: +// This exists for compatibility reason. +// Move this into Pervasives or Core + +module List = Ocaml_List + +// Caution: `Array.get` is implicitly used by `array[idx]` syntax +external get: (array<'a>, int) => 'a = "%array_safe_get" + +// Caution: `Array.set` is implicitly used by `array[idx]` syntax +external set: (array<'a>, int, 'a) => unit = "%array_safe_set" + +// Below is all deprecated and should be removed in v13 + +external length: array<'a> => int = "%array_length" + +external unsafe_get: (array<'a>, int) => 'a = "%array_unsafe_get" + +external unsafe_set: (array<'a>, int, 'a) => unit = "%array_unsafe_set" + +let init: (int, int => 'a) => array<'a> = %raw(`(length, f) => Array.from({ length }, f)`) + +let make = (len, x) => init(len, _ => x) + +@send external slice: (array<'a>, int, int) => array<'a> = "slice" +let unsafe_sub = (array, offset, length) => array->slice(offset, offset + length) + +@send external concat: (array<'a>, array<'a>) => array<'a> = "concat" +@send external append_prim: (array<'a>, array<'a>) => array<'a> = "concat" + +let concat = list => { + List.fold_left((arr1, arr2) => arr1->concat(arr2), [], list) +} + +let unsafe_blit = (srcArray, srcOffset, destArray, destOffset, len) => { + for i in 0 to len - 1 { + destArray->unsafe_set(destOffset + i, srcArray->unsafe_get(srcOffset + i)) + } +} + +let create_float = len => make(len, 0.0) + +let make_matrix = (sx, sy, init) => { + let res = make(sx, []) + for x in 0 to pred(sx) { + unsafe_set(res, x, make(sy, init)) + } + res +} + +@send external copy: array<'a> => array<'a> = "slice" + +let append = (a1, a2) => { + let l1 = length(a1) + if l1 == 0 { + copy(a2) + } else if length(a2) == 0 { + unsafe_sub(a1, 0, l1) + } else { + append_prim(a1, a2) + } +} + +let sub = (a, ofs, len) => + if ofs < 0 || (len < 0 || ofs > length(a) - len) { + invalid_arg("Array.sub") + } else { + unsafe_sub(a, ofs, len) + } + +let fill = (a, ofs, len, v) => + if ofs < 0 || (len < 0 || ofs > length(a) - len) { + invalid_arg("Array.fill") + } else { + for i in ofs to ofs + len - 1 { + unsafe_set(a, i, v) + } + } + +let blit = (a1, ofs1, a2, ofs2, len) => + if len < 0 || (ofs1 < 0 || (ofs1 > length(a1) - len || (ofs2 < 0 || ofs2 > length(a2) - len))) { + invalid_arg("Array.blit") + } else { + unsafe_blit(a1, ofs1, a2, ofs2, len) + } + +let iter = (f, a) => + for i in 0 to length(a) - 1 { + f(unsafe_get(a, i)) + } + +let iter2 = (f, a, b) => + if length(a) != length(b) { + invalid_arg("Array.iter2: arrays must have the same length") + } else { + for i in 0 to length(a) - 1 { + f(unsafe_get(a, i), unsafe_get(b, i)) + } + } + +let map = (f, a) => { + let l = length(a) + if l == 0 { + [] + } else { + let r = make(l, f(unsafe_get(a, 0))) + for i in 1 to l - 1 { + unsafe_set(r, i, f(unsafe_get(a, i))) + } + r + } +} + +let map2 = (f, a, b) => { + let la = length(a) + let lb = length(b) + if la != lb { + invalid_arg("Array.map2: arrays must have the same length") + } else if la == 0 { + [] + } else { + let r = make(la, f(unsafe_get(a, 0), unsafe_get(b, 0))) + for i in 1 to la - 1 { + unsafe_set(r, i, f(unsafe_get(a, i), unsafe_get(b, i))) + } + r + } +} + +let iteri = (f, a) => + for i in 0 to length(a) - 1 { + f(i, unsafe_get(a, i)) + } + +let mapi = (f, a) => { + let l = length(a) + if l == 0 { + [] + } else { + let r = make(l, f(0, unsafe_get(a, 0))) + for i in 1 to l - 1 { + unsafe_set(r, i, f(i, unsafe_get(a, i))) + } + r + } +} + +let to_list = a => { + let rec tolist = (i, res) => + if i < 0 { + res + } else { + tolist(i - 1, list{unsafe_get(a, i), ...res}) + } + tolist(length(a) - 1, list{}) +} + +/* Cannot use List.length here because the List module depends on Array. */ +let rec list_length = (accu, param) => + switch param { + | list{} => accu + | list{_, ...t} => list_length(succ(accu), t) + } + +let of_list = param => + switch param { + | list{} => [] + | list{hd, ...tl} as l => + let a = make(list_length(0, l), hd) + let rec fill = (i, param) => + switch param { + | list{} => a + | list{hd, ...tl} => + unsafe_set(a, i, hd) + fill(i + 1, tl) + } + fill(1, tl) + } + +let fold_left = (f, x, a) => { + let r = ref(x) + for i in 0 to length(a) - 1 { + r := f(r.contents, unsafe_get(a, i)) + } + r.contents +} + +let fold_right = (f, a, x) => { + let r = ref(x) + for i in length(a) - 1 downto 0 { + r := f(unsafe_get(a, i), r.contents) + } + r.contents +} + +let exists = (p, a) => { + let n = length(a) + let rec loop = i => + if i == n { + false + } else if p(unsafe_get(a, i)) { + true + } else { + loop(succ(i)) + } + loop(0) +} + +let for_all = (p, a) => { + let n = length(a) + let rec loop = i => + if i == n { + true + } else if p(unsafe_get(a, i)) { + loop(succ(i)) + } else { + false + } + loop(0) +} + +let mem = (x, a) => { + let n = length(a) + let rec loop = i => + if i == n { + false + } else if compare(unsafe_get(a, i), x) == 0 { + true + } else { + loop(succ(i)) + } + loop(0) +} + +let memq = (x, a) => { + let n = length(a) + let rec loop = i => + if i == n { + false + } else if x === unsafe_get(a, i) { + true + } else { + loop(succ(i)) + } + loop(0) +} + +exception Bottom(int) +let sort = (cmp, a) => { + let maxson = (l, i) => { + let i31 = i + i + i + 1 + let x = ref(i31) + if i31 + 2 < l { + if cmp(get(a, i31), get(a, i31 + 1)) < 0 { + x := i31 + 1 + } + if cmp(get(a, x.contents), get(a, i31 + 2)) < 0 { + x := i31 + 2 + } + x.contents + } else if i31 + 1 < l && cmp(get(a, i31), get(a, i31 + 1)) < 0 { + i31 + 1 + } else if i31 < l { + i31 + } else { + raise(Bottom(i)) + } + } + + let rec trickledown = (l, i, e) => { + let j = maxson(l, i) + if cmp(get(a, j), e) > 0 { + set(a, i, get(a, j)) + trickledown(l, j, e) + } else { + set(a, i, e) + } + } + + let trickle = (l, i, e) => + try trickledown(l, i, e) catch { + | Bottom(i) => set(a, i, e) + } + let rec bubbledown = (l, i) => { + let j = maxson(l, i) + set(a, i, get(a, j)) + bubbledown(l, j) + } + + let bubble = (l, i) => + try bubbledown(l, i) catch { + | Bottom(i) => i + } + let rec trickleup = (i, e) => { + let father = (i - 1) / 3 + assert(i != father) + if cmp(get(a, father), e) < 0 { + set(a, i, get(a, father)) + if father > 0 { + trickleup(father, e) + } else { + set(a, 0, e) + } + } else { + set(a, i, e) + } + } + + let l = length(a) + for i in (l + 1) / 3 - 1 downto 0 { + trickle(l, i, get(a, i)) + } + for i in l - 1 downto 2 { + let e = get(a, i) + set(a, i, get(a, 0)) + trickleup(bubble(i, 0), e) + } + if l > 1 { + let e = get(a, 1) + set(a, 1, get(a, 0)) + set(a, 0, e) + } +} + +let cutoff = 5 +let stable_sort = (cmp, a) => { + let merge = (src1ofs, src1len, src2, src2ofs, src2len, dst, dstofs) => { + let src1r = src1ofs + src1len and src2r = src2ofs + src2len + let rec loop = (i1, s1, i2, s2, d) => + if cmp(s1, s2) <= 0 { + set(dst, d, s1) + let i1 = i1 + 1 + if i1 < src1r { + loop(i1, get(a, i1), i2, s2, d + 1) + } else { + blit(src2, i2, dst, d + 1, src2r - i2) + } + } else { + set(dst, d, s2) + let i2 = i2 + 1 + if i2 < src2r { + loop(i1, s1, i2, get(src2, i2), d + 1) + } else { + blit(a, i1, dst, d + 1, src1r - i1) + } + } + loop(src1ofs, get(a, src1ofs), src2ofs, get(src2, src2ofs), dstofs) + } + + let isortto = (srcofs, dst, dstofs, len) => + for i in 0 to len - 1 { + let e = get(a, srcofs + i) + let j = ref(dstofs + i - 1) + while j.contents >= dstofs && cmp(get(dst, j.contents), e) > 0 { + set(dst, j.contents + 1, get(dst, j.contents)) + decr(j) + } + set(dst, j.contents + 1, e) + } + + let rec sortto = (srcofs, dst, dstofs, len) => + if len <= cutoff { + isortto(srcofs, dst, dstofs, len) + } else { + let l1 = len / 2 + let l2 = len - l1 + sortto(srcofs + l1, dst, dstofs + l1, l2) + sortto(srcofs, a, srcofs + l2, l1) + merge(srcofs + l2, l1, dst, dstofs + l1, l2, dst, dstofs) + } + + let l = length(a) + if l <= cutoff { + isortto(0, a, 0, l) + } else { + let l1 = l / 2 + let l2 = l - l1 + let t = make(l2, get(a, 0)) + sortto(l1, t, 0, l2) + sortto(0, a, l2, l1) + merge(l2, l1, t, 0, l2, a, 0) + } +} + +let fast_sort = stable_sort diff --git a/tests/tests/src/ocaml_compat/Ocaml_Array.resi b/tests/tests/src/ocaml_compat/Ocaml_Array.resi new file mode 100644 index 0000000000..74a7c24724 --- /dev/null +++ b/tests/tests/src/ocaml_compat/Ocaml_Array.resi @@ -0,0 +1,249 @@ +// FIXME: +// This exists for compatibility reason. +// Move this into Pervasives or Core + +// Caution: `Array.get` is implicitly used by `array[idx]` syntax +external get: (array<'a>, int) => 'a = "%array_safe_get" + +// Caution: `Array.set` is implicitly used by `array[idx]` syntax +external set: (array<'a>, int, 'a) => unit = "%array_safe_set" + +// Below is all deprecated and should be removed in v13 + +/** Return the length (number of elements) of the given array. */ +@deprecated("Use Core instead. This will be removed in v13") +external length: array<'a> => int = "%array_length" + +/** [Array.make n x] returns a fresh array of length [n], + initialized with [x]. + All the elements of this new array are initially + physically equal to [x] (in the sense of the [==] predicate). + Consequently, if [x] is mutable, it is shared among all elements + of the array, and modifying [x] through one of the array entries + will modify all other entries at the same time. + + Raise [Invalid_argument] if [n < 0] or [n > Sys.max_array_length]. + If the value of [x] is a floating-point number, then the maximum + size is only [Sys.max_array_length / 2].*/ +@deprecated("Use Core instead. This will be removed in v13") +let make: (int, 'a) => array<'a> + +/** [Array.create_float n] returns a fresh float array of length [n], + with uninitialized data. + @since 4.03 */ +@deprecated("Use Core instead. This will be removed in v13") +let create_float: int => array + +/** [Array.init n f] returns a fresh array of length [n], + with element number [i] initialized to the result of [f i]. + In other terms, [Array.init n f] tabulates the results of [f] + applied to the integers [0] to [n-1]. + + Raise [Invalid_argument] if [n < 0] or [n > Sys.max_array_length]. + If the return type of [f] is [float], then the maximum + size is only [Sys.max_array_length / 2].*/ +@deprecated("Use Core instead. This will be removed in v13") +let init: (int, int => 'a) => array<'a> + +/** [Array.make_matrix dimx dimy e] returns a two-dimensional array + (an array of arrays) with first dimension [dimx] and + second dimension [dimy]. All the elements of this new matrix + are initially physically equal to [e]. + The element ([x,y]) of a matrix [m] is accessed + with the notation [m.(x).(y)]. + + Raise [Invalid_argument] if [dimx] or [dimy] is negative or + greater than {!Sys.max_array_length}. + If the value of [e] is a floating-point number, then the maximum + size is only [Sys.max_array_length / 2]. */ +@deprecated("Use Core instead. This will be removed in v13") +let make_matrix: (int, int, 'a) => array> + +/** [Array.append v1 v2] returns a fresh array containing the + concatenation of the arrays [v1] and [v2]. */ +@deprecated("Use Core instead. This will be removed in v13") +let append: (array<'a>, array<'a>) => array<'a> + +/** Same as {!Array.append}, but concatenates a list of arrays. */ +@deprecated("Use Core instead. This will be removed in v13") +let concat: list> => array<'a> + +/** [Array.sub a start len] returns a fresh array of length [len], + containing the elements number [start] to [start + len - 1] + of array [a]. + + Raise [Invalid_argument "Array.sub"] if [start] and [len] do not + designate a valid subarray of [a]; that is, if + [start < 0], or [len < 0], or [start + len > Array.length a]. */ +@deprecated("Use Core instead. This will be removed in v13") +let sub: (array<'a>, int, int) => array<'a> + +/** [Array.copy a] returns a copy of [a], that is, a fresh array + containing the same elements as [a]. */ +@deprecated("Use Core instead. This will be removed in v13") +@send +external copy: array<'a> => array<'a> = "slice" + +/** [Array.fill a ofs len x] modifies the array [a] in place, + storing [x] in elements number [ofs] to [ofs + len - 1]. + + Raise [Invalid_argument "Array.fill"] if [ofs] and [len] do not + designate a valid subarray of [a]. */ +@deprecated("Use Core instead. This will be removed in v13") +let fill: (array<'a>, int, int, 'a) => unit + +/** [Array.blit v1 o1 v2 o2 len] copies [len] elements + from array [v1], starting at element number [o1], to array [v2], + starting at element number [o2]. It works correctly even if + [v1] and [v2] are the same array, and the source and + destination chunks overlap. + + Raise [Invalid_argument "Array.blit"] if [o1] and [len] do not + designate a valid subarray of [v1], or if [o2] and [len] do not + designate a valid subarray of [v2]. */ +@deprecated("Use Core instead. This will be removed in v13") +let blit: (array<'a>, int, array<'a>, int, int) => unit + +/** [Array.to_list a] returns the list of all the elements of [a]. */ +@deprecated("Use Core instead. This will be removed in v13") +let to_list: array<'a> => list<'a> + +/** [Array.of_list l] returns a fresh array containing the elements + of [l]. */ +@deprecated("Use Core instead. This will be removed in v13") +let of_list: list<'a> => array<'a> + +/* {1 Iterators} */ + +/** [Array.iter f a] applies function [f] in turn to all + the elements of [a]. It is equivalent to + [f a.(0); f a.(1); ...; f a.(Array.length a - 1); ()]. */ +@deprecated("Use Core instead. This will be removed in v13") +let iter: ('a => unit, array<'a>) => unit + +/** Same as {!Array.iter}, but the + function is applied with the index of the element as first argument, + and the element itself as second argument. */ +@deprecated("Use Core instead. This will be removed in v13") +let iteri: ((int, 'a) => unit, array<'a>) => unit + +/** [Array.map f a] applies function [f] to all the elements of [a], + and builds an array with the results returned by [f]: + [[| f a.(0); f a.(1); ...; f a.(Array.length a - 1) |]]. */ +@deprecated("Use Core instead. This will be removed in v13") +let map: ('a => 'b, array<'a>) => array<'b> + +/** Same as {!Array.map}, but the + function is applied to the index of the element as first argument, + and the element itself as second argument. */ +@deprecated("Use Core instead. This will be removed in v13") +let mapi: ((int, 'a) => 'b, array<'a>) => array<'b> + +/** [Array.fold_left f x a] computes + [f (... (f (f x a.(0)) a.(1)) ...) a.(n-1)], + where [n] is the length of the array [a]. */ +@deprecated("Use Core instead. This will be removed in v13") +let fold_left: (('a, 'b) => 'a, 'a, array<'b>) => 'a + +/** [Array.fold_right f a x] computes + [f a.(0) (f a.(1) ( ... (f a.(n-1) x) ...))], + where [n] is the length of the array [a]. */ +@deprecated("Use Core instead. This will be removed in v13") +let fold_right: (('b, 'a) => 'a, array<'b>, 'a) => 'a + +/* {1 Iterators on two arrays} */ + +/** [Array.iter2 f a b] applies function [f] to all the elements of [a] + and [b]. + Raise [Invalid_argument] if the arrays are not the same size. + @since 4.03.0 */ +@deprecated("Use Core instead. This will be removed in v13") +let iter2: (('a, 'b) => unit, array<'a>, array<'b>) => unit + +/** [Array.map2 f a b] applies function [f] to all the elements of [a] + and [b], and builds an array with the results returned by [f]: + [[| f a.(0) b.(0); ...; f a.(Array.length a - 1) b.(Array.length b - 1)|]]. + Raise [Invalid_argument] if the arrays are not the same size. + @since 4.03.0 */ +@deprecated("Use Core instead. This will be removed in v13") +let map2: (('a, 'b) => 'c, array<'a>, array<'b>) => array<'c> + +/* {1 Array scanning} */ + +/** [Array.for_all p [|a1; ...; an|]] checks if all elements of the array + satisfy the predicate [p]. That is, it returns + [(p a1) && (p a2) && ... && (p an)]. + @since 4.03.0 */ +@deprecated("Use Core instead. This will be removed in v13") +let for_all: ('a => bool, array<'a>) => bool + +/** [Array.exists p [|a1; ...; an|]] checks if at least one element of + the array satisfies the predicate [p]. That is, it returns + [(p a1) || (p a2) || ... || (p an)]. + @since 4.03.0 */ +@deprecated("Use Core instead. This will be removed in v13") +let exists: ('a => bool, array<'a>) => bool + +/** [mem a l] is true if and only if [a] is equal + to an element of [l]. + @since 4.03.0 */ +@deprecated("Use Core instead. This will be removed in v13") +let mem: ('a, array<'a>) => bool + +/** Same as {!Array.mem}, but uses physical equality instead of structural + equality to compare array elements. + @since 4.03.0 */ +@deprecated("Use Core instead. This will be removed in v13") +let memq: ('a, array<'a>) => bool + +/* {1 Sorting} */ + +/** Sort an array in increasing order according to a comparison + function. The comparison function must return 0 if its arguments + compare as equal, a positive integer if the first is greater, + and a negative integer if the first is smaller (see below for a + complete specification). For example, {!Pervasives.compare} is + a suitable comparison function, provided there are no floating-point + NaN values in the data. After calling [Array.sort], the + array is sorted in place in increasing order. + [Array.sort] is guaranteed to run in constant heap space + and (at most) logarithmic stack space. + + The current implementation uses Heap Sort. It runs in constant + stack space. + + Specification of the comparison function: + Let [a] be the array and [cmp] the comparison function. The following + must be true for all x, y, z in a : +- [cmp x y] > 0 if and only if [cmp y x] < 0 +- if [cmp x y] >= 0 and [cmp y z] >= 0 then [cmp x z] >= 0 + + When [Array.sort] returns, [a] contains the same elements as before, + reordered in such a way that for all i and j valid indices of [a] : +- [cmp a.(i) a.(j)] >= 0 if and only if i >= j +*/ +@deprecated("Use Core instead. This will be removed in v13") +let sort: (('a, 'a) => int, array<'a>) => unit + +/** Same as {!Array.sort}, but the sorting algorithm is stable (i.e. + elements that compare equal are kept in their original order) and + not guaranteed to run in constant heap space. + + The current implementation uses Merge Sort. It uses [n/2] + words of heap space, where [n] is the length of the array. + It is usually faster than the current implementation of {!Array.sort}. +*/ +@deprecated("Use Core instead. This will be removed in v13") +let stable_sort: (('a, 'a) => int, array<'a>) => unit + +/** Same as {!Array.sort} or {!Array.stable_sort}, whichever is faster + on typical input. +*/ +@deprecated("Use Core instead. This will be removed in v13") +let fast_sort: (('a, 'a) => int, array<'a>) => unit + +@deprecated("Use Core instead. This will be removed in v13") +external unsafe_get: (array<'a>, int) => 'a = "%array_unsafe_get" + +@deprecated("Use Core instead. This will be removed in v13") +external unsafe_set: (array<'a>, int, 'a) => unit = "%array_unsafe_set" diff --git a/lib/js/Hashtbl.js b/tests/tests/src/ocaml_compat/Ocaml_Hashtbl.js similarity index 52% rename from lib/js/Hashtbl.js rename to tests/tests/src/ocaml_compat/Ocaml_Hashtbl.js index 90e167d498..bdc1ba676a 100644 --- a/lib/js/Hashtbl.js +++ b/tests/tests/src/ocaml_compat/Ocaml_Hashtbl.js @@ -1,6 +1,7 @@ +// Generated by ReScript, PLEASE EDIT WITH CARE 'use strict'; -let Primitive_hash = require("./Primitive_hash.js"); +let Primitive_hash = require("rescript/lib/js/Primitive_hash.js"); function hash(x) { return Primitive_hash.hash(10, 100, 0, x); diff --git a/runtime/Hashtbl.res b/tests/tests/src/ocaml_compat/Ocaml_Hashtbl.res similarity index 100% rename from runtime/Hashtbl.res rename to tests/tests/src/ocaml_compat/Ocaml_Hashtbl.res diff --git a/runtime/Hashtbl.resi b/tests/tests/src/ocaml_compat/Ocaml_Hashtbl.resi similarity index 100% rename from runtime/Hashtbl.resi rename to tests/tests/src/ocaml_compat/Ocaml_Hashtbl.resi diff --git a/tests/tests/src/ocaml_compat/Ocaml_List.js b/tests/tests/src/ocaml_compat/Ocaml_List.js new file mode 100644 index 0000000000..e0dbc3d73e --- /dev/null +++ b/tests/tests/src/ocaml_compat/Ocaml_List.js @@ -0,0 +1,1629 @@ +// Generated by ReScript, PLEASE EDIT WITH CARE +'use strict'; + +let Pervasives = require("rescript/lib/js/Pervasives.js"); +let Primitive_option = require("rescript/lib/js/Primitive_option.js"); + +function length(l) { + let _len = 0; + let _param = l; + while (true) { + let param = _param; + let len = _len; + if (!param) { + return len; + } + _param = param.tl; + _len = len + 1 | 0; + continue; + }; +} + +function cons(a, l) { + return { + hd: a, + tl: l + }; +} + +function hd(param) { + if (param) { + return param.hd; + } else { + return Pervasives.failwith("hd"); + } +} + +function tl(param) { + if (param) { + return param.tl; + } else { + return Pervasives.failwith("tl"); + } +} + +function nth(l, n) { + if (n < 0) { + return Pervasives.invalid_arg("List.nth"); + } + let _l = l; + let _n = n; + while (true) { + let n$1 = _n; + let l$1 = _l; + if (!l$1) { + return Pervasives.failwith("nth"); + } + if (n$1 === 0) { + return l$1.hd; + } + _n = n$1 - 1 | 0; + _l = l$1.tl; + continue; + }; +} + +function nth_opt(l, n) { + if (n < 0) { + return Pervasives.invalid_arg("List.nth"); + } + let _l = l; + let _n = n; + while (true) { + let n$1 = _n; + let l$1 = _l; + if (!l$1) { + return; + } + if (n$1 === 0) { + return Primitive_option.some(l$1.hd); + } + _n = n$1 - 1 | 0; + _l = l$1.tl; + continue; + }; +} + +function rev_append(_l1, _l2) { + while (true) { + let l2 = _l2; + let l1 = _l1; + if (!l1) { + return l2; + } + _l2 = { + hd: l1.hd, + tl: l2 + }; + _l1 = l1.tl; + continue; + }; +} + +function rev(l) { + return rev_append(l, /* [] */0); +} + +function init_tailrec_aux(_acc, _i, n, f) { + while (true) { + let i = _i; + let acc = _acc; + if (i >= n) { + return acc; + } + _i = i + 1 | 0; + _acc = { + hd: f(i), + tl: acc + }; + continue; + }; +} + +function init_aux(i, n, f) { + if (i >= n) { + return /* [] */0; + } + let r = f(i); + return { + hd: r, + tl: init_aux(i + 1 | 0, n, f) + }; +} + +function init(len, f) { + if (len < 0) { + return Pervasives.invalid_arg("List.init"); + } else if (len > 10000) { + return rev_append(init_tailrec_aux(/* [] */0, 0, len, f), /* [] */0); + } else { + return init_aux(0, len, f); + } +} + +function flatten(param) { + if (param) { + return Pervasives.$at(param.hd, flatten(param.tl)); + } else { + return /* [] */0; + } +} + +function map(f, param) { + if (!param) { + return /* [] */0; + } + let r = f(param.hd); + return { + hd: r, + tl: map(f, param.tl) + }; +} + +function mapi(i, f, param) { + if (!param) { + return /* [] */0; + } + let r = f(i, param.hd); + return { + hd: r, + tl: mapi(i + 1 | 0, f, param.tl) + }; +} + +function mapi$1(f, l) { + return mapi(0, f, l); +} + +function rev_map(f, l) { + let _accu = /* [] */0; + let _param = l; + while (true) { + let param = _param; + let accu = _accu; + if (!param) { + return accu; + } + _param = param.tl; + _accu = { + hd: f(param.hd), + tl: accu + }; + continue; + }; +} + +function iter(f, _param) { + while (true) { + let param = _param; + if (!param) { + return; + } + f(param.hd); + _param = param.tl; + continue; + }; +} + +function iteri(f, l) { + let _i = 0; + let _param = l; + while (true) { + let param = _param; + let i = _i; + if (!param) { + return; + } + f(i, param.hd); + _param = param.tl; + _i = i + 1 | 0; + continue; + }; +} + +function fold_left(f, _accu, _l) { + while (true) { + let l = _l; + let accu = _accu; + if (!l) { + return accu; + } + _l = l.tl; + _accu = f(accu, l.hd); + continue; + }; +} + +function fold_right(f, l, accu) { + if (l) { + return f(l.hd, fold_right(f, l.tl, accu)); + } else { + return accu; + } +} + +function map2(f, l1, l2) { + if (!l1) { + if (l2) { + return Pervasives.invalid_arg("List.map2"); + } else { + return /* [] */0; + } + } + if (!l2) { + return Pervasives.invalid_arg("List.map2"); + } + let r = f(l1.hd, l2.hd); + return { + hd: r, + tl: map2(f, l1.tl, l2.tl) + }; +} + +function rev_map2(f, l1, l2) { + let _accu = /* [] */0; + let _l1 = l1; + let _l2 = l2; + while (true) { + let l2$1 = _l2; + let l1$1 = _l1; + let accu = _accu; + if (!l1$1) { + if (l2$1) { + return Pervasives.invalid_arg("List.rev_map2"); + } else { + return accu; + } + } + if (!l2$1) { + return Pervasives.invalid_arg("List.rev_map2"); + } + _l2 = l2$1.tl; + _l1 = l1$1.tl; + _accu = { + hd: f(l1$1.hd, l2$1.hd), + tl: accu + }; + continue; + }; +} + +function iter2(f, _l1, _l2) { + while (true) { + let l2 = _l2; + let l1 = _l1; + if (!l1) { + if (l2) { + return Pervasives.invalid_arg("List.iter2"); + } else { + return; + } + } + if (!l2) { + return Pervasives.invalid_arg("List.iter2"); + } + f(l1.hd, l2.hd); + _l2 = l2.tl; + _l1 = l1.tl; + continue; + }; +} + +function fold_left2(f, _accu, _l1, _l2) { + while (true) { + let l2 = _l2; + let l1 = _l1; + let accu = _accu; + if (!l1) { + if (l2) { + return Pervasives.invalid_arg("List.fold_left2"); + } else { + return accu; + } + } + if (!l2) { + return Pervasives.invalid_arg("List.fold_left2"); + } + _l2 = l2.tl; + _l1 = l1.tl; + _accu = f(accu, l1.hd, l2.hd); + continue; + }; +} + +function fold_right2(f, l1, l2, accu) { + if (l1) { + if (l2) { + return f(l1.hd, l2.hd, fold_right2(f, l1.tl, l2.tl, accu)); + } else { + return Pervasives.invalid_arg("List.fold_right2"); + } + } else if (l2) { + return Pervasives.invalid_arg("List.fold_right2"); + } else { + return accu; + } +} + +function for_all(p, _param) { + while (true) { + let param = _param; + if (!param) { + return true; + } + if (!p(param.hd)) { + return false; + } + _param = param.tl; + continue; + }; +} + +function exists(p, _param) { + while (true) { + let param = _param; + if (!param) { + return false; + } + if (p(param.hd)) { + return true; + } + _param = param.tl; + continue; + }; +} + +function for_all2(p, _l1, _l2) { + while (true) { + let l2 = _l2; + let l1 = _l1; + if (!l1) { + if (l2) { + return Pervasives.invalid_arg("List.for_all2"); + } else { + return true; + } + } + if (!l2) { + return Pervasives.invalid_arg("List.for_all2"); + } + if (!p(l1.hd, l2.hd)) { + return false; + } + _l2 = l2.tl; + _l1 = l1.tl; + continue; + }; +} + +function exists2(p, _l1, _l2) { + while (true) { + let l2 = _l2; + let l1 = _l1; + if (!l1) { + if (l2) { + return Pervasives.invalid_arg("List.exists2"); + } else { + return false; + } + } + if (!l2) { + return Pervasives.invalid_arg("List.exists2"); + } + if (p(l1.hd, l2.hd)) { + return true; + } + _l2 = l2.tl; + _l1 = l1.tl; + continue; + }; +} + +function mem(x, _param) { + while (true) { + let param = _param; + if (!param) { + return false; + } + if (param.hd === x) { + return true; + } + _param = param.tl; + continue; + }; +} + +function memq(x, _param) { + while (true) { + let param = _param; + if (!param) { + return false; + } + if (param.hd === x) { + return true; + } + _param = param.tl; + continue; + }; +} + +function assoc(x, _param) { + while (true) { + let param = _param; + if (param) { + let match = param.hd; + if (match[0] === x) { + return match[1]; + } + _param = param.tl; + continue; + } + throw { + RE_EXN_ID: "Not_found", + Error: new Error() + }; + }; +} + +function assoc_opt(x, _param) { + while (true) { + let param = _param; + if (!param) { + return; + } + let match = param.hd; + if (match[0] === x) { + return Primitive_option.some(match[1]); + } + _param = param.tl; + continue; + }; +} + +function assq(x, _param) { + while (true) { + let param = _param; + if (param) { + let match = param.hd; + if (match[0] === x) { + return match[1]; + } + _param = param.tl; + continue; + } + throw { + RE_EXN_ID: "Not_found", + Error: new Error() + }; + }; +} + +function assq_opt(x, _param) { + while (true) { + let param = _param; + if (!param) { + return; + } + let match = param.hd; + if (match[0] === x) { + return Primitive_option.some(match[1]); + } + _param = param.tl; + continue; + }; +} + +function mem_assoc(x, _param) { + while (true) { + let param = _param; + if (!param) { + return false; + } + if (param.hd[0] === x) { + return true; + } + _param = param.tl; + continue; + }; +} + +function mem_assq(x, _param) { + while (true) { + let param = _param; + if (!param) { + return false; + } + if (param.hd[0] === x) { + return true; + } + _param = param.tl; + continue; + }; +} + +function remove_assoc(x, param) { + if (!param) { + return /* [] */0; + } + let l = param.tl; + let pair = param.hd; + if (pair[0] === x) { + return l; + } else { + return { + hd: pair, + tl: remove_assoc(x, l) + }; + } +} + +function remove_assq(x, param) { + if (!param) { + return /* [] */0; + } + let l = param.tl; + let pair = param.hd; + if (pair[0] === x) { + return l; + } else { + return { + hd: pair, + tl: remove_assq(x, l) + }; + } +} + +function find(p, _param) { + while (true) { + let param = _param; + if (param) { + let x = param.hd; + if (p(x)) { + return x; + } + _param = param.tl; + continue; + } + throw { + RE_EXN_ID: "Not_found", + Error: new Error() + }; + }; +} + +function find_opt(p, _param) { + while (true) { + let param = _param; + if (!param) { + return; + } + let x = param.hd; + if (p(x)) { + return Primitive_option.some(x); + } + _param = param.tl; + continue; + }; +} + +function find_all(p, l) { + let _accu = /* [] */0; + let _param = l; + while (true) { + let param = _param; + let accu = _accu; + if (!param) { + return rev_append(accu, /* [] */0); + } + let l$1 = param.tl; + let x = param.hd; + if (p(x)) { + _param = l$1; + _accu = { + hd: x, + tl: accu + }; + continue; + } + _param = l$1; + continue; + }; +} + +function partition(p, l) { + let _yes = /* [] */0; + let _no = /* [] */0; + let _param = l; + while (true) { + let param = _param; + let no = _no; + let yes = _yes; + if (!param) { + return [ + rev_append(yes, /* [] */0), + rev_append(no, /* [] */0) + ]; + } + let l$1 = param.tl; + let x = param.hd; + if (p(x)) { + _param = l$1; + _yes = { + hd: x, + tl: yes + }; + continue; + } + _param = l$1; + _no = { + hd: x, + tl: no + }; + continue; + }; +} + +function split(param) { + if (!param) { + return [ + /* [] */0, + /* [] */0 + ]; + } + let match = param.hd; + let match$1 = split(param.tl); + return [ + { + hd: match[0], + tl: match$1[0] + }, + { + hd: match[1], + tl: match$1[1] + } + ]; +} + +function combine(l1, l2) { + if (l1) { + if (l2) { + return { + hd: [ + l1.hd, + l2.hd + ], + tl: combine(l1.tl, l2.tl) + }; + } else { + return Pervasives.invalid_arg("List.combine"); + } + } else if (l2) { + return Pervasives.invalid_arg("List.combine"); + } else { + return /* [] */0; + } +} + +function merge(cmp, l1, l2) { + if (!l1) { + return l2; + } + if (!l2) { + return l1; + } + let h2 = l2.hd; + let h1 = l1.hd; + if (cmp(h1, h2) <= 0) { + return { + hd: h1, + tl: merge(cmp, l1.tl, l2) + }; + } else { + return { + hd: h2, + tl: merge(cmp, l1, l2.tl) + }; + } +} + +function chop(_k, _l) { + while (true) { + let l = _l; + let k = _k; + if (k === 0) { + return l; + } + if (l) { + _l = l.tl; + _k = k - 1 | 0; + continue; + } + throw { + RE_EXN_ID: "Assert_failure", + _1: [ + "Ocaml_List.res", + 411, + 11 + ], + Error: new Error() + }; + }; +} + +function stable_sort(cmp, l) { + let sort = (n, l) => { + if (n !== 2) { + if (n === 3 && l) { + let match = l.tl; + if (match) { + let match$1 = match.tl; + if (match$1) { + let x3 = match$1.hd; + let x2 = match.hd; + let x1 = l.hd; + if (cmp(x1, x2) <= 0) { + if (cmp(x2, x3) <= 0) { + return { + hd: x1, + tl: { + hd: x2, + tl: { + hd: x3, + tl: /* [] */0 + } + } + }; + } else if (cmp(x1, x3) <= 0) { + return { + hd: x1, + tl: { + hd: x3, + tl: { + hd: x2, + tl: /* [] */0 + } + } + }; + } else { + return { + hd: x3, + tl: { + hd: x1, + tl: { + hd: x2, + tl: /* [] */0 + } + } + }; + } + } else if (cmp(x1, x3) <= 0) { + return { + hd: x2, + tl: { + hd: x1, + tl: { + hd: x3, + tl: /* [] */0 + } + } + }; + } else if (cmp(x2, x3) <= 0) { + return { + hd: x2, + tl: { + hd: x3, + tl: { + hd: x1, + tl: /* [] */0 + } + } + }; + } else { + return { + hd: x3, + tl: { + hd: x2, + tl: { + hd: x1, + tl: /* [] */0 + } + } + }; + } + } + + } + + } + + } else if (l) { + let match$2 = l.tl; + if (match$2) { + let x2$1 = match$2.hd; + let x1$1 = l.hd; + if (cmp(x1$1, x2$1) <= 0) { + return { + hd: x1$1, + tl: { + hd: x2$1, + tl: /* [] */0 + } + }; + } else { + return { + hd: x2$1, + tl: { + hd: x1$1, + tl: /* [] */0 + } + }; + } + } + + } + let n1 = (n >> 1); + let n2 = n - n1 | 0; + let l2 = chop(n1, l); + let s1 = rev_sort(n1, l); + let s2 = rev_sort(n2, l2); + let _l1 = s1; + let _l2 = s2; + let _accu = /* [] */0; + while (true) { + let accu = _accu; + let l2$1 = _l2; + let l1 = _l1; + if (!l1) { + return rev_append(l2$1, accu); + } + if (!l2$1) { + return rev_append(l1, accu); + } + let h2 = l2$1.hd; + let h1 = l1.hd; + if (cmp(h1, h2) > 0) { + _accu = { + hd: h1, + tl: accu + }; + _l1 = l1.tl; + continue; + } + _accu = { + hd: h2, + tl: accu + }; + _l2 = l2$1.tl; + continue; + }; + }; + let rev_sort = (n, l) => { + if (n !== 2) { + if (n === 3 && l) { + let match = l.tl; + if (match) { + let match$1 = match.tl; + if (match$1) { + let x3 = match$1.hd; + let x2 = match.hd; + let x1 = l.hd; + if (cmp(x1, x2) > 0) { + if (cmp(x2, x3) > 0) { + return { + hd: x1, + tl: { + hd: x2, + tl: { + hd: x3, + tl: /* [] */0 + } + } + }; + } else if (cmp(x1, x3) > 0) { + return { + hd: x1, + tl: { + hd: x3, + tl: { + hd: x2, + tl: /* [] */0 + } + } + }; + } else { + return { + hd: x3, + tl: { + hd: x1, + tl: { + hd: x2, + tl: /* [] */0 + } + } + }; + } + } else if (cmp(x1, x3) > 0) { + return { + hd: x2, + tl: { + hd: x1, + tl: { + hd: x3, + tl: /* [] */0 + } + } + }; + } else if (cmp(x2, x3) > 0) { + return { + hd: x2, + tl: { + hd: x3, + tl: { + hd: x1, + tl: /* [] */0 + } + } + }; + } else { + return { + hd: x3, + tl: { + hd: x2, + tl: { + hd: x1, + tl: /* [] */0 + } + } + }; + } + } + + } + + } + + } else if (l) { + let match$2 = l.tl; + if (match$2) { + let x2$1 = match$2.hd; + let x1$1 = l.hd; + if (cmp(x1$1, x2$1) > 0) { + return { + hd: x1$1, + tl: { + hd: x2$1, + tl: /* [] */0 + } + }; + } else { + return { + hd: x2$1, + tl: { + hd: x1$1, + tl: /* [] */0 + } + }; + } + } + + } + let n1 = (n >> 1); + let n2 = n - n1 | 0; + let l2 = chop(n1, l); + let s1 = sort(n1, l); + let s2 = sort(n2, l2); + let _l1 = s1; + let _l2 = s2; + let _accu = /* [] */0; + while (true) { + let accu = _accu; + let l2$1 = _l2; + let l1 = _l1; + if (!l1) { + return rev_append(l2$1, accu); + } + if (!l2$1) { + return rev_append(l1, accu); + } + let h2 = l2$1.hd; + let h1 = l1.hd; + if (cmp(h1, h2) <= 0) { + _accu = { + hd: h1, + tl: accu + }; + _l1 = l1.tl; + continue; + } + _accu = { + hd: h2, + tl: accu + }; + _l2 = l2$1.tl; + continue; + }; + }; + let len = length(l); + if (len < 2) { + return l; + } else { + return sort(len, l); + } +} + +function sort_uniq(cmp, l) { + let sort = (n, l) => { + if (n !== 2) { + if (n === 3 && l) { + let match = l.tl; + if (match) { + let match$1 = match.tl; + if (match$1) { + let x3 = match$1.hd; + let x2 = match.hd; + let x1 = l.hd; + let c = cmp(x1, x2); + if (c === 0) { + let c$1 = cmp(x2, x3); + if (c$1 === 0) { + return { + hd: x2, + tl: /* [] */0 + }; + } else if (c$1 < 0) { + return { + hd: x2, + tl: { + hd: x3, + tl: /* [] */0 + } + }; + } else { + return { + hd: x3, + tl: { + hd: x2, + tl: /* [] */0 + } + }; + } + } + if (c < 0) { + let c$2 = cmp(x2, x3); + if (c$2 === 0) { + return { + hd: x1, + tl: { + hd: x2, + tl: /* [] */0 + } + }; + } + if (c$2 < 0) { + return { + hd: x1, + tl: { + hd: x2, + tl: { + hd: x3, + tl: /* [] */0 + } + } + }; + } + let c$3 = cmp(x1, x3); + if (c$3 === 0) { + return { + hd: x1, + tl: { + hd: x2, + tl: /* [] */0 + } + }; + } else if (c$3 < 0) { + return { + hd: x1, + tl: { + hd: x3, + tl: { + hd: x2, + tl: /* [] */0 + } + } + }; + } else { + return { + hd: x3, + tl: { + hd: x1, + tl: { + hd: x2, + tl: /* [] */0 + } + } + }; + } + } + let c$4 = cmp(x1, x3); + if (c$4 === 0) { + return { + hd: x2, + tl: { + hd: x1, + tl: /* [] */0 + } + }; + } + if (c$4 < 0) { + return { + hd: x2, + tl: { + hd: x1, + tl: { + hd: x3, + tl: /* [] */0 + } + } + }; + } + let c$5 = cmp(x2, x3); + if (c$5 === 0) { + return { + hd: x2, + tl: { + hd: x1, + tl: /* [] */0 + } + }; + } else if (c$5 < 0) { + return { + hd: x2, + tl: { + hd: x3, + tl: { + hd: x1, + tl: /* [] */0 + } + } + }; + } else { + return { + hd: x3, + tl: { + hd: x2, + tl: { + hd: x1, + tl: /* [] */0 + } + } + }; + } + } + + } + + } + + } else if (l) { + let match$2 = l.tl; + if (match$2) { + let x2$1 = match$2.hd; + let x1$1 = l.hd; + let c$6 = cmp(x1$1, x2$1); + if (c$6 === 0) { + return { + hd: x1$1, + tl: /* [] */0 + }; + } else if (c$6 < 0) { + return { + hd: x1$1, + tl: { + hd: x2$1, + tl: /* [] */0 + } + }; + } else { + return { + hd: x2$1, + tl: { + hd: x1$1, + tl: /* [] */0 + } + }; + } + } + + } + let n1 = (n >> 1); + let n2 = n - n1 | 0; + let l2 = chop(n1, l); + let s1 = rev_sort(n1, l); + let s2 = rev_sort(n2, l2); + let _l1 = s1; + let _l2 = s2; + let _accu = /* [] */0; + while (true) { + let accu = _accu; + let l2$1 = _l2; + let l1 = _l1; + if (!l1) { + return rev_append(l2$1, accu); + } + if (!l2$1) { + return rev_append(l1, accu); + } + let t2 = l2$1.tl; + let h2 = l2$1.hd; + let t1 = l1.tl; + let h1 = l1.hd; + let c$7 = cmp(h1, h2); + if (c$7 === 0) { + _accu = { + hd: h1, + tl: accu + }; + _l2 = t2; + _l1 = t1; + continue; + } + if (c$7 > 0) { + _accu = { + hd: h1, + tl: accu + }; + _l1 = t1; + continue; + } + _accu = { + hd: h2, + tl: accu + }; + _l2 = t2; + continue; + }; + }; + let rev_sort = (n, l) => { + if (n !== 2) { + if (n === 3 && l) { + let match = l.tl; + if (match) { + let match$1 = match.tl; + if (match$1) { + let x3 = match$1.hd; + let x2 = match.hd; + let x1 = l.hd; + let c = cmp(x1, x2); + if (c === 0) { + let c$1 = cmp(x2, x3); + if (c$1 === 0) { + return { + hd: x2, + tl: /* [] */0 + }; + } else if (c$1 > 0) { + return { + hd: x2, + tl: { + hd: x3, + tl: /* [] */0 + } + }; + } else { + return { + hd: x3, + tl: { + hd: x2, + tl: /* [] */0 + } + }; + } + } + if (c > 0) { + let c$2 = cmp(x2, x3); + if (c$2 === 0) { + return { + hd: x1, + tl: { + hd: x2, + tl: /* [] */0 + } + }; + } + if (c$2 > 0) { + return { + hd: x1, + tl: { + hd: x2, + tl: { + hd: x3, + tl: /* [] */0 + } + } + }; + } + let c$3 = cmp(x1, x3); + if (c$3 === 0) { + return { + hd: x1, + tl: { + hd: x2, + tl: /* [] */0 + } + }; + } else if (c$3 > 0) { + return { + hd: x1, + tl: { + hd: x3, + tl: { + hd: x2, + tl: /* [] */0 + } + } + }; + } else { + return { + hd: x3, + tl: { + hd: x1, + tl: { + hd: x2, + tl: /* [] */0 + } + } + }; + } + } + let c$4 = cmp(x1, x3); + if (c$4 === 0) { + return { + hd: x2, + tl: { + hd: x1, + tl: /* [] */0 + } + }; + } + if (c$4 > 0) { + return { + hd: x2, + tl: { + hd: x1, + tl: { + hd: x3, + tl: /* [] */0 + } + } + }; + } + let c$5 = cmp(x2, x3); + if (c$5 === 0) { + return { + hd: x2, + tl: { + hd: x1, + tl: /* [] */0 + } + }; + } else if (c$5 > 0) { + return { + hd: x2, + tl: { + hd: x3, + tl: { + hd: x1, + tl: /* [] */0 + } + } + }; + } else { + return { + hd: x3, + tl: { + hd: x2, + tl: { + hd: x1, + tl: /* [] */0 + } + } + }; + } + } + + } + + } + + } else if (l) { + let match$2 = l.tl; + if (match$2) { + let x2$1 = match$2.hd; + let x1$1 = l.hd; + let c$6 = cmp(x1$1, x2$1); + if (c$6 === 0) { + return { + hd: x1$1, + tl: /* [] */0 + }; + } else if (c$6 > 0) { + return { + hd: x1$1, + tl: { + hd: x2$1, + tl: /* [] */0 + } + }; + } else { + return { + hd: x2$1, + tl: { + hd: x1$1, + tl: /* [] */0 + } + }; + } + } + + } + let n1 = (n >> 1); + let n2 = n - n1 | 0; + let l2 = chop(n1, l); + let s1 = sort(n1, l); + let s2 = sort(n2, l2); + let _l1 = s1; + let _l2 = s2; + let _accu = /* [] */0; + while (true) { + let accu = _accu; + let l2$1 = _l2; + let l1 = _l1; + if (!l1) { + return rev_append(l2$1, accu); + } + if (!l2$1) { + return rev_append(l1, accu); + } + let t2 = l2$1.tl; + let h2 = l2$1.hd; + let t1 = l1.tl; + let h1 = l1.hd; + let c$7 = cmp(h1, h2); + if (c$7 === 0) { + _accu = { + hd: h1, + tl: accu + }; + _l2 = t2; + _l1 = t1; + continue; + } + if (c$7 < 0) { + _accu = { + hd: h1, + tl: accu + }; + _l1 = t1; + continue; + } + _accu = { + hd: h2, + tl: accu + }; + _l2 = t2; + continue; + }; + }; + let len = length(l); + if (len < 2) { + return l; + } else { + return sort(len, l); + } +} + +function compare_lengths(_l1, _l2) { + while (true) { + let l2 = _l2; + let l1 = _l1; + if (!l1) { + if (l2) { + return -1; + } else { + return 0; + } + } + if (!l2) { + return 1; + } + _l2 = l2.tl; + _l1 = l1.tl; + continue; + }; +} + +function compare_length_with(_l, _n) { + while (true) { + let n = _n; + let l = _l; + if (!l) { + if (n === 0) { + return 0; + } else if (n > 0) { + return -1; + } else { + return 1; + } + } + if (n <= 0) { + return 1; + } + _n = n - 1 | 0; + _l = l.tl; + continue; + }; +} + +let append = Pervasives.$at; + +let concat = flatten; + +let filter = find_all; + +let sort = stable_sort; + +let fast_sort = stable_sort; + +exports.length = length; +exports.compare_lengths = compare_lengths; +exports.compare_length_with = compare_length_with; +exports.cons = cons; +exports.hd = hd; +exports.tl = tl; +exports.nth = nth; +exports.nth_opt = nth_opt; +exports.rev = rev; +exports.init = init; +exports.append = append; +exports.rev_append = rev_append; +exports.concat = concat; +exports.flatten = flatten; +exports.iter = iter; +exports.iteri = iteri; +exports.map = map; +exports.mapi = mapi$1; +exports.rev_map = rev_map; +exports.fold_left = fold_left; +exports.fold_right = fold_right; +exports.iter2 = iter2; +exports.map2 = map2; +exports.rev_map2 = rev_map2; +exports.fold_left2 = fold_left2; +exports.fold_right2 = fold_right2; +exports.for_all = for_all; +exports.exists = exists; +exports.for_all2 = for_all2; +exports.exists2 = exists2; +exports.mem = mem; +exports.memq = memq; +exports.find = find; +exports.find_opt = find_opt; +exports.filter = filter; +exports.find_all = find_all; +exports.partition = partition; +exports.assoc = assoc; +exports.assoc_opt = assoc_opt; +exports.assq = assq; +exports.assq_opt = assq_opt; +exports.mem_assoc = mem_assoc; +exports.mem_assq = mem_assq; +exports.remove_assoc = remove_assoc; +exports.remove_assq = remove_assq; +exports.split = split; +exports.combine = combine; +exports.sort = sort; +exports.stable_sort = stable_sort; +exports.fast_sort = fast_sort; +exports.sort_uniq = sort_uniq; +exports.merge = merge; +/* No side effect */ diff --git a/tests/tests/src/ocaml_compat/Ocaml_List.res b/tests/tests/src/ocaml_compat/Ocaml_List.res new file mode 100644 index 0000000000..334b2f8937 --- /dev/null +++ b/tests/tests/src/ocaml_compat/Ocaml_List.res @@ -0,0 +1,740 @@ +// FIXME: +// This exists for compatibility reason. +// Move this into Pervasives or Core + +// Below is all deprecated and should be removed in v13 + +type t<'a> = list<'a> + +let rec length_aux = (len, param) => + switch param { + | list{} => len + | list{_, ...l} => length_aux(len + 1, l) + } + +let length = l => length_aux(0, l) + +let cons = (a, l) => list{a, ...l} + +let hd = param => + switch param { + | list{} => failwith("hd") + | list{a, ..._} => a + } + +let tl = param => + switch param { + | list{} => failwith("tl") + | list{_, ...l} => l + } + +let nth = (l, n) => + if n < 0 { + invalid_arg("List.nth") + } else { + let rec nth_aux = (l, n) => + switch l { + | list{} => failwith("nth") + | list{a, ...l} => + if n == 0 { + a + } else { + nth_aux(l, n - 1) + } + } + nth_aux(l, n) + } + +let nth_opt = (l, n) => + if n < 0 { + invalid_arg("List.nth") + } else { + let rec nth_aux = (l, n) => + switch l { + | list{} => None + | list{a, ...l} => + if n == 0 { + Some(a) + } else { + nth_aux(l, n - 1) + } + } + nth_aux(l, n) + } + +let append = \"@" + +let rec rev_append = (l1, l2) => + switch l1 { + | list{} => l2 + | list{a, ...l} => rev_append(l, list{a, ...l2}) + } + +let rev = l => rev_append(l, list{}) + +let rec init_tailrec_aux = (acc, i, n, f) => + if i >= n { + acc + } else { + init_tailrec_aux(list{f(i), ...acc}, i + 1, n, f) + } + +let rec init_aux = (i, n, f) => + if i >= n { + list{} + } else { + let r = f(i) + list{r, ...init_aux(i + 1, n, f)} + } + +let init = (len, f) => + if len < 0 { + invalid_arg("List.init") + } else if len > 10_000 { + rev(init_tailrec_aux(list{}, 0, len, f)) + } else { + init_aux(0, len, f) + } + +let rec flatten = param => + switch param { + | list{} => list{} + | list{l, ...r} => \"@"(l, flatten(r)) + } + +let concat = flatten + +let rec map = (f, param) => + switch param { + | list{} => list{} + | list{a, ...l} => + let r = f(a) + list{r, ...map(f, l)} + } + +let rec mapi = (i, f, param) => + switch param { + | list{} => list{} + | list{a, ...l} => + let r = f(i, a) + list{r, ...mapi(i + 1, f, l)} + } + +let mapi = (f, l) => mapi(0, f, l) + +let rev_map = (f, l) => { + let rec rmap_f = (accu, param) => + switch param { + | list{} => accu + | list{a, ...l} => rmap_f(list{f(a), ...accu}, l) + } + + rmap_f(list{}, l) +} + +let rec iter = (f, param) => + switch param { + | list{} => () + | list{a, ...l} => + f(a) + iter(f, l) + } + +let rec iteri = (i, f, param) => + switch param { + | list{} => () + | list{a, ...l} => + f(i, a) + iteri(i + 1, f, l) + } + +let iteri = (f, l) => iteri(0, f, l) + +let rec fold_left = (f, accu, l) => + switch l { + | list{} => accu + | list{a, ...l} => fold_left(f, f(accu, a), l) + } + +let rec fold_right = (f, l, accu) => + switch l { + | list{} => accu + | list{a, ...l} => f(a, fold_right(f, l, accu)) + } + +let rec map2 = (f, l1, l2) => + switch (l1, l2) { + | (list{}, list{}) => list{} + | (list{a1, ...l1}, list{a2, ...l2}) => + let r = f(a1, a2) + list{r, ...map2(f, l1, l2)} + | (_, _) => invalid_arg("List.map2") + } + +let rev_map2 = (f, l1, l2) => { + let rec rmap2_f = (accu, l1, l2) => + switch (l1, l2) { + | (list{}, list{}) => accu + | (list{a1, ...l1}, list{a2, ...l2}) => rmap2_f(list{f(a1, a2), ...accu}, l1, l2) + | (_, _) => invalid_arg("List.rev_map2") + } + + rmap2_f(list{}, l1, l2) +} + +let rec iter2 = (f, l1, l2) => + switch (l1, l2) { + | (list{}, list{}) => () + | (list{a1, ...l1}, list{a2, ...l2}) => + f(a1, a2) + iter2(f, l1, l2) + | (_, _) => invalid_arg("List.iter2") + } + +let rec fold_left2 = (f, accu, l1, l2) => + switch (l1, l2) { + | (list{}, list{}) => accu + | (list{a1, ...l1}, list{a2, ...l2}) => fold_left2(f, f(accu, a1, a2), l1, l2) + | (_, _) => invalid_arg("List.fold_left2") + } + +let rec fold_right2 = (f, l1, l2, accu) => + switch (l1, l2) { + | (list{}, list{}) => accu + | (list{a1, ...l1}, list{a2, ...l2}) => f(a1, a2, fold_right2(f, l1, l2, accu)) + | (_, _) => invalid_arg("List.fold_right2") + } + +let rec for_all = (p, param) => + switch param { + | list{} => true + | list{a, ...l} => p(a) && for_all(p, l) + } + +let rec exists = (p, param) => + switch param { + | list{} => false + | list{a, ...l} => p(a) || exists(p, l) + } + +let rec for_all2 = (p, l1, l2) => + switch (l1, l2) { + | (list{}, list{}) => true + | (list{a1, ...l1}, list{a2, ...l2}) => p(a1, a2) && for_all2(p, l1, l2) + | (_, _) => invalid_arg("List.for_all2") + } + +let rec exists2 = (p, l1, l2) => + switch (l1, l2) { + | (list{}, list{}) => false + | (list{a1, ...l1}, list{a2, ...l2}) => p(a1, a2) || exists2(p, l1, l2) + | (_, _) => invalid_arg("List.exists2") + } + +let rec mem = (x, param) => + switch param { + | list{} => false + | list{a, ...l} => compare(a, x) == 0 || mem(x, l) + } + +let rec memq = (x, param) => + switch param { + | list{} => false + | list{a, ...l} => a === x || memq(x, l) + } + +let rec assoc = (x, param) => + switch param { + | list{} => raise(Not_found) + | list{(a, b), ...l} => + if compare(a, x) == 0 { + b + } else { + assoc(x, l) + } + } + +let rec assoc_opt = (x, param) => + switch param { + | list{} => None + | list{(a, b), ...l} => + if compare(a, x) == 0 { + Some(b) + } else { + assoc_opt(x, l) + } + } + +let rec assq = (x, param) => + switch param { + | list{} => raise(Not_found) + | list{(a, b), ...l} => + if a === x { + b + } else { + assq(x, l) + } + } + +let rec assq_opt = (x, param) => + switch param { + | list{} => None + | list{(a, b), ...l} => + if a === x { + Some(b) + } else { + assq_opt(x, l) + } + } + +let rec mem_assoc = (x, param) => + switch param { + | list{} => false + | list{(a, _), ...l} => compare(a, x) == 0 || mem_assoc(x, l) + } + +let rec mem_assq = (x, param) => + switch param { + | list{} => false + | list{(a, _), ...l} => a === x || mem_assq(x, l) + } + +let rec remove_assoc = (x, param) => + switch param { + | list{} => list{} + | list{(a, _) as pair, ...l} => + if compare(a, x) == 0 { + l + } else { + list{pair, ...remove_assoc(x, l)} + } + } + +let rec remove_assq = (x, param) => + switch param { + | list{} => list{} + | list{(a, _) as pair, ...l} => + if a === x { + l + } else { + list{pair, ...remove_assq(x, l)} + } + } + +let rec find = (p, param) => + switch param { + | list{} => raise(Not_found) + | list{x, ...l} => + if p(x) { + x + } else { + find(p, l) + } + } + +let rec find_opt = (p, param) => + switch param { + | list{} => None + | list{x, ...l} => + if p(x) { + Some(x) + } else { + find_opt(p, l) + } + } + +let find_all = (p, l) => { + let rec find = (accu, param) => + switch param { + | list{} => rev(accu) + | list{x, ...l} => + if p(x) { + find(list{x, ...accu}, l) + } else { + find(accu, l) + } + } + find(list{}, l) +} + +let filter = find_all + +let partition = (p, l) => { + let rec part = (yes, no, param) => + switch param { + | list{} => (rev(yes), rev(no)) + | list{x, ...l} => + if p(x) { + part(list{x, ...yes}, no, l) + } else { + part(yes, list{x, ...no}, l) + } + } + part(list{}, list{}, l) +} + +let rec split = param => + switch param { + | list{} => (list{}, list{}) + | list{(x, y), ...l} => + let (rx, ry) = split(l) + (list{x, ...rx}, list{y, ...ry}) + } + +let rec combine = (l1, l2) => + switch (l1, l2) { + | (list{}, list{}) => list{} + | (list{a1, ...l1}, list{a2, ...l2}) => list{(a1, a2), ...combine(l1, l2)} + | (_, _) => invalid_arg("List.combine") + } + +/* sorting */ + +let rec merge = (cmp, l1, l2) => + switch (l1, l2) { + | (list{}, l2) => l2 + | (l1, list{}) => l1 + | (list{h1, ...t1}, list{h2, ...t2}) => + if cmp(h1, h2) <= 0 { + list{h1, ...merge(cmp, t1, l2)} + } else { + list{h2, ...merge(cmp, l1, t2)} + } + } + +let rec chop = (k, l) => + if k == 0 { + l + } else { + switch l { + | list{_, ...t} => chop(k - 1, t) + | _ => assert(false) + } + } + +let stable_sort = (cmp, l) => { + let rec rev_merge = (l1, l2, accu) => + switch (l1, l2) { + | (list{}, l2) => rev_append(l2, accu) + | (l1, list{}) => rev_append(l1, accu) + | (list{h1, ...t1}, list{h2, ...t2}) => + if cmp(h1, h2) <= 0 { + rev_merge(t1, l2, list{h1, ...accu}) + } else { + rev_merge(l1, t2, list{h2, ...accu}) + } + } + + let rec rev_merge_rev = (l1, l2, accu) => + switch (l1, l2) { + | (list{}, l2) => rev_append(l2, accu) + | (l1, list{}) => rev_append(l1, accu) + | (list{h1, ...t1}, list{h2, ...t2}) => + if cmp(h1, h2) > 0 { + rev_merge_rev(t1, l2, list{h1, ...accu}) + } else { + rev_merge_rev(l1, t2, list{h2, ...accu}) + } + } + + let rec sort = (n, l) => + switch (n, l) { + | (2, list{x1, x2, ..._}) => + if cmp(x1, x2) <= 0 { + list{x1, x2} + } else { + list{x2, x1} + } + | (3, list{x1, x2, x3, ..._}) => + if cmp(x1, x2) <= 0 { + if cmp(x2, x3) <= 0 { + list{x1, x2, x3} + } else if cmp(x1, x3) <= 0 { + list{x1, x3, x2} + } else { + list{x3, x1, x2} + } + } else if cmp(x1, x3) <= 0 { + list{x2, x1, x3} + } else if cmp(x2, x3) <= 0 { + list{x2, x3, x1} + } else { + list{x3, x2, x1} + } + | (n, l) => + let n1 = asr(n, 1) + let n2 = n - n1 + let l2 = chop(n1, l) + let s1 = rev_sort(n1, l) + let s2 = rev_sort(n2, l2) + rev_merge_rev(s1, s2, list{}) + } + and rev_sort = (n, l) => + switch (n, l) { + | (2, list{x1, x2, ..._}) => + if cmp(x1, x2) > 0 { + list{x1, x2} + } else { + list{x2, x1} + } + | (3, list{x1, x2, x3, ..._}) => + if cmp(x1, x2) > 0 { + if cmp(x2, x3) > 0 { + list{x1, x2, x3} + } else if cmp(x1, x3) > 0 { + list{x1, x3, x2} + } else { + list{x3, x1, x2} + } + } else if cmp(x1, x3) > 0 { + list{x2, x1, x3} + } else if cmp(x2, x3) > 0 { + list{x2, x3, x1} + } else { + list{x3, x2, x1} + } + | (n, l) => + let n1 = asr(n, 1) + let n2 = n - n1 + let l2 = chop(n1, l) + let s1 = sort(n1, l) + let s2 = sort(n2, l2) + rev_merge(s1, s2, list{}) + } + + let len = length(l) + if len < 2 { + l + } else { + sort(len, l) + } +} + +let sort = stable_sort +let fast_sort = stable_sort + +/* Note: on a list of length between about 100000 (depending on the minor + heap size and the type of the list) and Sys.max_array_size, it is + actually faster to use the following, but it might also use more memory + because the argument list cannot be deallocated incrementally. + + Also, there seems to be a bug in this code or in the + implementation of obj_truncate. + +external obj_truncate : 'a array -> int -> unit = "caml_obj_truncate" + +let array_to_list_in_place a = + let l = Array.length a in + let rec loop accu n p = + if p <= 0 then accu else begin + if p = n then begin + obj_truncate a p; + loop (a.(p-1) :: accu) (n-1000) (p-1) + end else begin + loop (a.(p-1) :: accu) n (p-1) + end + end + in + loop [] (l-1000) l + + +let stable_sort cmp l = + let a = Array.of_list l in + Array.stable_sort cmp a; + array_to_list_in_place a + +*/ + +/* sorting + removing duplicates */ + +let sort_uniq = (cmp, l) => { + let rec rev_merge = (l1, l2, accu) => + switch (l1, l2) { + | (list{}, l2) => rev_append(l2, accu) + | (l1, list{}) => rev_append(l1, accu) + | (list{h1, ...t1}, list{h2, ...t2}) => + let c = cmp(h1, h2) + if c == 0 { + rev_merge(t1, t2, list{h1, ...accu}) + } else if c < 0 { + rev_merge(t1, l2, list{h1, ...accu}) + } else { + rev_merge(l1, t2, list{h2, ...accu}) + } + } + + let rec rev_merge_rev = (l1, l2, accu) => + switch (l1, l2) { + | (list{}, l2) => rev_append(l2, accu) + | (l1, list{}) => rev_append(l1, accu) + | (list{h1, ...t1}, list{h2, ...t2}) => + let c = cmp(h1, h2) + if c == 0 { + rev_merge_rev(t1, t2, list{h1, ...accu}) + } else if c > 0 { + rev_merge_rev(t1, l2, list{h1, ...accu}) + } else { + rev_merge_rev(l1, t2, list{h2, ...accu}) + } + } + + let rec sort = (n, l) => + switch (n, l) { + | (2, list{x1, x2, ..._}) => + let c = cmp(x1, x2) + if c == 0 { + list{x1} + } else if c < 0 { + list{x1, x2} + } else { + list{x2, x1} + } + | (3, list{x1, x2, x3, ..._}) => + let c = cmp(x1, x2) + if c == 0 { + let c = cmp(x2, x3) + if c == 0 { + list{x2} + } else if c < 0 { + list{x2, x3} + } else { + list{x3, x2} + } + } else if c < 0 { + let c = cmp(x2, x3) + if c == 0 { + list{x1, x2} + } else if c < 0 { + list{x1, x2, x3} + } else { + let c = cmp(x1, x3) + if c == 0 { + list{x1, x2} + } else if c < 0 { + list{x1, x3, x2} + } else { + list{x3, x1, x2} + } + } + } else { + let c = cmp(x1, x3) + if c == 0 { + list{x2, x1} + } else if c < 0 { + list{x2, x1, x3} + } else { + let c = cmp(x2, x3) + if c == 0 { + list{x2, x1} + } else if c < 0 { + list{x2, x3, x1} + } else { + list{x3, x2, x1} + } + } + } + | (n, l) => + let n1 = asr(n, 1) + let n2 = n - n1 + let l2 = chop(n1, l) + let s1 = rev_sort(n1, l) + let s2 = rev_sort(n2, l2) + rev_merge_rev(s1, s2, list{}) + } + and rev_sort = (n, l) => + switch (n, l) { + | (2, list{x1, x2, ..._}) => + let c = cmp(x1, x2) + if c == 0 { + list{x1} + } else if c > 0 { + list{x1, x2} + } else { + list{x2, x1} + } + | (3, list{x1, x2, x3, ..._}) => + let c = cmp(x1, x2) + if c == 0 { + let c = cmp(x2, x3) + if c == 0 { + list{x2} + } else if c > 0 { + list{x2, x3} + } else { + list{x3, x2} + } + } else if c > 0 { + let c = cmp(x2, x3) + if c == 0 { + list{x1, x2} + } else if c > 0 { + list{x1, x2, x3} + } else { + let c = cmp(x1, x3) + if c == 0 { + list{x1, x2} + } else if c > 0 { + list{x1, x3, x2} + } else { + list{x3, x1, x2} + } + } + } else { + let c = cmp(x1, x3) + if c == 0 { + list{x2, x1} + } else if c > 0 { + list{x2, x1, x3} + } else { + let c = cmp(x2, x3) + if c == 0 { + list{x2, x1} + } else if c > 0 { + list{x2, x3, x1} + } else { + list{x3, x2, x1} + } + } + } + | (n, l) => + let n1 = asr(n, 1) + let n2 = n - n1 + let l2 = chop(n1, l) + let s1 = sort(n1, l) + let s2 = sort(n2, l2) + rev_merge(s1, s2, list{}) + } + + let len = length(l) + if len < 2 { + l + } else { + sort(len, l) + } +} + +let rec compare_lengths = (l1, l2) => + switch (l1, l2) { + | (list{}, list{}) => 0 + | (list{}, _) => -1 + | (_, list{}) => 1 + | (list{_, ...l1}, list{_, ...l2}) => compare_lengths(l1, l2) + } + +let rec compare_length_with = (l, n) => + switch l { + | list{} => + if n == 0 { + 0 + } else if n > 0 { + -1 + } else { + 1 + } + | list{_, ...l} => + if n <= 0 { + 1 + } else { + compare_length_with(l, n - 1) + } + } diff --git a/tests/tests/src/ocaml_compat/Ocaml_List.resi b/tests/tests/src/ocaml_compat/Ocaml_List.resi new file mode 100644 index 0000000000..1fdfd31f0c --- /dev/null +++ b/tests/tests/src/ocaml_compat/Ocaml_List.resi @@ -0,0 +1,365 @@ +// FIXME: +// This exists for compatibility reason. +// Move this into Pervasives or Core + +// Below is all deprecated and should be removed in v13 + +@deprecated("Use Core instead. This will be removed in v13") +type t<'a> = list<'a> + +/** Return the length (number of elements) of the given list. */ +@deprecated("Use Core instead. This will be removed in v13") +let length: list<'a> => int + +/** Compare the lengths of two lists. [compare_lengths l1 l2] is + equivalent to [compare (length l1) (length l2)], except that + the computation stops after itering on the shortest list. + @since 4.05.0 + */ +@deprecated("Use Core instead. This will be removed in v13") +let compare_lengths: (list<'a>, list<'b>) => int + +/** Compare the length of a list to an integer. [compare_length_with l n] is + equivalent to [compare (length l) n], except that + the computation stops after at most [n] iterations on the list. + @since 4.05.0 +*/ +@deprecated("Use Core instead. This will be removed in v13") +let compare_length_with: (list<'a>, int) => int + +/** [cons x xs] is [x :: xs] + @since 4.03.0 +*/ +@deprecated("Use Core instead. This will be removed in v13") +let cons: ('a, list<'a>) => list<'a> + +/** Return the first element of the given list. Raise + [Failure "hd"] if the list is empty. */ +@deprecated("Use Core instead. This will be removed in v13") +let hd: list<'a> => 'a + +/** Return the given list without its first element. Raise + [Failure "tl"] if the list is empty. */ +@deprecated("Use Core instead. This will be removed in v13") +let tl: list<'a> => list<'a> + +/** Return the [n]-th element of the given list. + The first element (head of the list) is at position 0. + Raise [Failure "nth"] if the list is too short. + Raise [Invalid_argument "List.nth"] if [n] is negative. */ +@deprecated("Use Core instead. This will be removed in v13") +let nth: (list<'a>, int) => 'a + +/** Return the [n]-th element of the given list. + The first element (head of the list) is at position 0. + Return [None] if the list is too short. + Raise [Invalid_argument "List.nth"] if [n] is negative. + @since 4.05 +*/ +@deprecated("Use Core instead. This will be removed in v13") +let nth_opt: (list<'a>, int) => option<'a> + +/** List reversal. */ +@deprecated("Use Core instead. This will be removed in v13") +let rev: list<'a> => list<'a> + +/** [List.init len f] is [f 0; f 1; ...; f (len-1)], evaluated left to right. + + @raise Invalid_argument if len < 0. + @since 4.06.0 +*/ +@deprecated("Use Core instead. This will be removed in v13") +let init: (int, int => 'a) => list<'a> + +/** Concatenate two lists. Same as the infix operator [@]. + Not tail-recursive (length of the first argument). */ +@deprecated("Use Core instead. This will be removed in v13") +let append: (list<'a>, list<'a>) => list<'a> + +/** [List.rev_append l1 l2] reverses [l1] and concatenates it to [l2]. + This is equivalent to {!List.rev}[ l1 @ l2], but [rev_append] is + tail-recursive and more efficient. */ +@deprecated("Use Core instead. This will be removed in v13") +let rev_append: (list<'a>, list<'a>) => list<'a> + +/** Concatenate a list of lists. The elements of the argument are all + concatenated together (in the same order) to give the result. + Not tail-recursive + (length of the argument + length of the longest sub-list). */ +@deprecated("Use Core instead. This will be removed in v13") +let concat: list> => list<'a> + +/** An alias for [concat]. */ +@deprecated("Use Core instead. This will be removed in v13") +let flatten: list> => list<'a> + +/* {1 Iterators} */ + +/** [List.iter f [a1; ...; an]] applies function [f] in turn to + [a1; ...; an]. It is equivalent to + [begin f a1; f a2; ...; f an; () end]. */ +@deprecated("Use Core instead. This will be removed in v13") +let iter: ('a => unit, list<'a>) => unit + +/** Same as {!List.iter}, but the function is applied to the index of + the element as first argument (counting from 0), and the element + itself as second argument. + @since 4.00.0 +*/ +@deprecated("Use Core instead. This will be removed in v13") +let iteri: ((int, 'a) => unit, list<'a>) => unit + +/** [List.map f [a1; ...; an]] applies function [f] to [a1, ..., an], + and builds the list [[f a1; ...; f an]] + with the results returned by [f]. Not tail-recursive. */ +@deprecated("Use Core instead. This will be removed in v13") +let map: ('a => 'b, list<'a>) => list<'b> + +/** Same as {!List.map}, but the function is applied to the index of + the element as first argument (counting from 0), and the element + itself as second argument. Not tail-recursive. + @since 4.00.0 +*/ +@deprecated("Use Core instead. This will be removed in v13") +let mapi: ((int, 'a) => 'b, list<'a>) => list<'b> + +/** [List.rev_map f l] gives the same result as + {!List.rev}[ (]{!List.map}[ f l)], but is tail-recursive and + more efficient. */ +@deprecated("Use Core instead. This will be removed in v13") +let rev_map: ('a => 'b, list<'a>) => list<'b> + +/** [List.fold_left f a [b1; ...; bn]] is + [f (... (f (f a b1) b2) ...) bn]. */ +@deprecated("Use Core instead. This will be removed in v13") +let fold_left: (('a, 'b) => 'a, 'a, list<'b>) => 'a + +/** [List.fold_right f [a1; ...; an] b] is + [f a1 (f a2 (... (f an b) ...))]. Not tail-recursive. */ +@deprecated("Use Core instead. This will be removed in v13") +let fold_right: (('a, 'b) => 'b, list<'a>, 'b) => 'b + +/* {1 Iterators on two lists} */ + +/** [List.iter2 f [a1; ...; an] [b1; ...; bn]] calls in turn + [f a1 b1; ...; f an bn]. + Raise [Invalid_argument] if the two lists are determined + to have different lengths. */ +@deprecated("Use Core instead. This will be removed in v13") +let iter2: (('a, 'b) => unit, list<'a>, list<'b>) => unit + +/** [List.map2 f [a1; ...; an] [b1; ...; bn]] is + [[f a1 b1; ...; f an bn]]. + Raise [Invalid_argument] if the two lists are determined + to have different lengths. Not tail-recursive. */ +@deprecated("Use Core instead. This will be removed in v13") +let map2: (('a, 'b) => 'c, list<'a>, list<'b>) => list<'c> + +/** [List.rev_map2 f l1 l2] gives the same result as + {!List.rev}[ (]{!List.map2}[ f l1 l2)], but is tail-recursive and + more efficient. */ +@deprecated("Use Core instead. This will be removed in v13") +let rev_map2: (('a, 'b) => 'c, list<'a>, list<'b>) => list<'c> + +/** [List.fold_left2 f a [b1; ...; bn] [c1; ...; cn]] is + [f (... (f (f a b1 c1) b2 c2) ...) bn cn]. + Raise [Invalid_argument] if the two lists are determined + to have different lengths. */ +@deprecated("Use Core instead. This will be removed in v13") +let fold_left2: (('a, 'b, 'c) => 'a, 'a, list<'b>, list<'c>) => 'a + +/** [List.fold_right2 f [a1; ...; an] [b1; ...; bn] c] is + [f a1 b1 (f a2 b2 (... (f an bn c) ...))]. + Raise [Invalid_argument] if the two lists are determined + to have different lengths. Not tail-recursive. */ +@deprecated("Use Core instead. This will be removed in v13") +let fold_right2: (('a, 'b, 'c) => 'c, list<'a>, list<'b>, 'c) => 'c + +/* {1 List scanning} */ + +/** [for_all p [a1; ...; an]] checks if all elements of the list + satisfy the predicate [p]. That is, it returns + [(p a1) && (p a2) && ... && (p an)]. */ +@deprecated("Use Core instead. This will be removed in v13") +let for_all: ('a => bool, list<'a>) => bool + +/** [exists p [a1; ...; an]] checks if at least one element of + the list satisfies the predicate [p]. That is, it returns + [(p a1) || (p a2) || ... || (p an)]. */ +@deprecated("Use Core instead. This will be removed in v13") +let exists: ('a => bool, list<'a>) => bool + +/** Same as {!List.for_all}, but for a two-argument predicate. + Raise [Invalid_argument] if the two lists are determined + to have different lengths. */ +@deprecated("Use Core instead. This will be removed in v13") +let for_all2: (('a, 'b) => bool, list<'a>, list<'b>) => bool + +/** Same as {!List.exists}, but for a two-argument predicate. + Raise [Invalid_argument] if the two lists are determined + to have different lengths. */ +@deprecated("Use Core instead. This will be removed in v13") +let exists2: (('a, 'b) => bool, list<'a>, list<'b>) => bool + +/** [mem a l] is true if and only if [a] is equal + to an element of [l]. */ +@deprecated("Use Core instead. This will be removed in v13") +let mem: ('a, list<'a>) => bool + +/** Same as {!List.mem}, but uses physical equality instead of structural + equality to compare list elements. */ +@deprecated("Use Core instead. This will be removed in v13") +let memq: ('a, list<'a>) => bool + +/* {1 List searching} */ + +/** [find p l] returns the first element of the list [l] + that satisfies the predicate [p]. + Raise [Not_found] if there is no value that satisfies [p] in the + list [l]. */ +@deprecated("Use Core instead. This will be removed in v13") +let find: ('a => bool, list<'a>) => 'a + +/** [find_opt p l] returns the first element of the list [l] that + satisfies the predicate [p], or [None] if there is no value that + satisfies [p] in the list [l]. + @since 4.05 */ +@deprecated("Use Core instead. This will be removed in v13") +let find_opt: ('a => bool, list<'a>) => option<'a> + +/** [filter p l] returns all the elements of the list [l] + that satisfy the predicate [p]. The order of the elements + in the input list is preserved. */ +@deprecated("Use Core instead. This will be removed in v13") +let filter: ('a => bool, list<'a>) => list<'a> + +/** [find_all] is another name for {!List.filter}. */ +let find_all: ('a => bool, list<'a>) => list<'a> + +/** [partition p l] returns a pair of lists [(l1, l2)], where + [l1] is the list of all the elements of [l] that + satisfy the predicate [p], and [l2] is the list of all the + elements of [l] that do not satisfy [p]. + The order of the elements in the input list is preserved. */ +@deprecated("Use Core instead. This will be removed in v13") +let partition: ('a => bool, list<'a>) => (list<'a>, list<'a>) + +/* {1 Association lists} */ + +/** [assoc a l] returns the value associated with key [a] in the list of + pairs [l]. That is, + [assoc a [ ...; (a,b); ...] = b] + if [(a,b)] is the leftmost binding of [a] in list [l]. + Raise [Not_found] if there is no value associated with [a] in the + list [l]. */ +@deprecated("Use Core instead. This will be removed in v13") +let assoc: ('a, list<('a, 'b)>) => 'b + +/** [assoc_opt a l] returns the value associated with key [a] in the list of + pairs [l]. That is, + [assoc_opt a [ ...; (a,b); ...] = b] + if [(a,b)] is the leftmost binding of [a] in list [l]. + Returns [None] if there is no value associated with [a] in the + list [l]. + @since 4.05 */ +@deprecated("Use Core instead. This will be removed in v13") +let assoc_opt: ('a, list<('a, 'b)>) => option<'b> + +/** Same as {!List.assoc}, but uses physical equality instead of structural + equality to compare keys. */ +@deprecated("Use Core instead. This will be removed in v13") +let assq: ('a, list<('a, 'b)>) => 'b + +/** Same as {!List.assoc_opt}, but uses physical equality instead of structural + equality to compare keys. + @since 4.05 */ +@deprecated("Use Core instead. This will be removed in v13") +let assq_opt: ('a, list<('a, 'b)>) => option<'b> + +/** Same as {!List.assoc}, but simply return true if a binding exists, + and false if no bindings exist for the given key. */ +@deprecated("Use Core instead. This will be removed in v13") +let mem_assoc: ('a, list<('a, 'b)>) => bool + +/** Same as {!List.mem_assoc}, but uses physical equality instead of + structural equality to compare keys. */ +@deprecated("Use Core instead. This will be removed in v13") +let mem_assq: ('a, list<('a, 'b)>) => bool + +/** [remove_assoc a l] returns the list of + pairs [l] without the first pair with key [a], if any. + Not tail-recursive. */ +@deprecated("Use Core instead. This will be removed in v13") +let remove_assoc: ('a, list<('a, 'b)>) => list<('a, 'b)> + +/** Same as {!List.remove_assoc}, but uses physical equality instead + of structural equality to compare keys. Not tail-recursive. */ +@deprecated("Use Core instead. This will be removed in v13") +let remove_assq: ('a, list<('a, 'b)>) => list<('a, 'b)> + +/* {1 Lists of pairs} */ + +/** Transform a list of pairs into a pair of lists: + [split [(a1,b1); ...; (an,bn)]] is [([a1; ...; an], [b1; ...; bn])]. + Not tail-recursive. +*/ +@deprecated("Use Core instead. This will be removed in v13") +let split: list<('a, 'b)> => (list<'a>, list<'b>) + +/** Transform a pair of lists into a list of pairs: + [combine [a1; ...; an] [b1; ...; bn]] is + [[(a1,b1); ...; (an,bn)]]. + Raise [Invalid_argument] if the two lists + have different lengths. Not tail-recursive. */ +@deprecated("Use Core instead. This will be removed in v13") +let combine: (list<'a>, list<'b>) => list<('a, 'b)> + +/* {1 Sorting} */ + +/** Sort a list in increasing order according to a comparison + function. The comparison function must return 0 if its arguments + compare as equal, a positive integer if the first is greater, + and a negative integer if the first is smaller (see Array.sort for + a complete specification). For example, + {!Pervasives.compare} is a suitable comparison function. + The resulting list is sorted in increasing order. + [List.sort] is guaranteed to run in constant heap space + (in addition to the size of the result list) and logarithmic + stack space. + + The current implementation uses Merge Sort. It runs in constant + heap space and logarithmic stack space. +*/ +@deprecated("Use Core instead. This will be removed in v13") +let sort: (('a, 'a) => int, list<'a>) => list<'a> + +/** Same as {!List.sort}, but the sorting algorithm is guaranteed to + be stable (i.e. elements that compare equal are kept in their + original order) . + + The current implementation uses Merge Sort. It runs in constant + heap space and logarithmic stack space. +*/ +@deprecated("Use Core instead. This will be removed in v13") +let stable_sort: (('a, 'a) => int, list<'a>) => list<'a> + +/** Same as {!List.sort} or {!List.stable_sort}, whichever is faster + on typical input. */ +@deprecated("Use Core instead. This will be removed in v13") +let fast_sort: (('a, 'a) => int, list<'a>) => list<'a> + +/** Same as {!List.sort}, but also remove duplicates. + @since 4.02.0 */ +@deprecated("Use Core instead. This will be removed in v13") +let sort_uniq: (('a, 'a) => int, list<'a>) => list<'a> + +/** Merge two lists: + Assuming that [l1] and [l2] are sorted according to the + comparison function [cmp], [merge cmp l1 l2] will return a + sorted list containing all the elements of [l1] and [l2]. + If several elements compare equal, the elements of [l1] will be + before the elements of [l2]. + Not tail-recursive (sum of the lengths of the arguments). +*/ +@deprecated("Use Core instead. This will be removed in v13") +let merge: (('a, 'a) => int, list<'a>, list<'a>) => list<'a> diff --git a/tests/tests/src/ocaml_compat/Ocaml_String.js b/tests/tests/src/ocaml_compat/Ocaml_String.js new file mode 100644 index 0000000000..8e38ceb32d --- /dev/null +++ b/tests/tests/src/ocaml_compat/Ocaml_String.js @@ -0,0 +1,303 @@ +// Generated by ReScript, PLEASE EDIT WITH CARE +'use strict'; + +let Char = require("rescript/lib/js/Char.js"); +let Pervasives = require("rescript/lib/js/Pervasives.js"); +let Ocaml_Array = require("./Ocaml_Array.js"); +let Primitive_exceptions = require("rescript/lib/js/Primitive_exceptions.js"); + +function apply1(f, bytes) { + if (bytes.length === 0) { + return bytes; + } + let r = bytes.slice(); + r[0] = f(bytes[0]); + return r; +} + +function concat(sep, xs) { + return Ocaml_Array.of_list(xs).join(sep); +} + +function bos(str) { + return Ocaml_Array.map(str => str.codePointAt(0), Array.from(str)); +} + +function make(len, ch) { + return String.fromCodePoint(ch).repeat(len); +} + +function init(len, f) { + return Ocaml_Array.init(len, i => String.fromCodePoint(f(i))).join(""); +} + +function sub(s, ofs, len) { + return String.fromCodePoint(...Ocaml_Array.sub(bos(s), ofs, len)); +} + +function iter(f, s) { + for (let i = 0, i_finish = s.length; i < i_finish; ++i) { + f(s.codePointAt(i)); + } +} + +function iteri(f, s) { + for (let i = 0, i_finish = s.length; i < i_finish; ++i) { + f(i, s.codePointAt(i)); + } +} + +function map(f, s) { + return String.fromCodePoint(...Ocaml_Array.map(f, bos(s))); +} + +function mapi(f, s) { + return String.fromCodePoint(...Ocaml_Array.mapi(f, bos(s))); +} + +function escaped(s) { + let needs_escape = _i => { + while (true) { + let i = _i; + if (i >= s.length) { + return false; + } + let match = s.codePointAt(i); + if (match < 32) { + return true; + } + if (match > 92 || match < 34) { + if (match >= 127) { + return true; + } + _i = i + 1 | 0; + continue; + } + if (match > 91 || match < 35) { + return true; + } + _i = i + 1 | 0; + continue; + }; + }; + if (!needs_escape(0)) { + return s; + } + let bytes = bos(s); + return Ocaml_Array.map(Char.escaped, bytes).join(""); +} + +function index_rec(s, lim, _i, c) { + while (true) { + let i = _i; + if (i >= lim) { + throw { + RE_EXN_ID: "Not_found", + Error: new Error() + }; + } + if (s.codePointAt(i) === c) { + return i; + } + _i = i + 1 | 0; + continue; + }; +} + +function index(s, c) { + return index_rec(s, s.length, 0, c); +} + +function index_rec_opt(s, lim, _i, c) { + while (true) { + let i = _i; + if (i >= lim) { + return; + } + if (s.codePointAt(i) === c) { + return i; + } + _i = i + 1 | 0; + continue; + }; +} + +function index_opt(s, c) { + return index_rec_opt(s, s.length, 0, c); +} + +function index_from(s, i, c) { + let l = s.length; + if (i < 0 || i > l) { + return Pervasives.invalid_arg("String.index_from / Bytes.index_from"); + } else { + return index_rec(s, l, i, c); + } +} + +function index_from_opt(s, i, c) { + let l = s.length; + if (i < 0 || i > l) { + return Pervasives.invalid_arg("String.index_from_opt / Bytes.index_from_opt"); + } else { + return index_rec_opt(s, l, i, c); + } +} + +function rindex_rec(s, _i, c) { + while (true) { + let i = _i; + if (i < 0) { + throw { + RE_EXN_ID: "Not_found", + Error: new Error() + }; + } + if (s.codePointAt(i) === c) { + return i; + } + _i = i - 1 | 0; + continue; + }; +} + +function rindex(s, c) { + return rindex_rec(s, s.length - 1 | 0, c); +} + +function rindex_from(s, i, c) { + if (i < -1 || i >= s.length) { + return Pervasives.invalid_arg("String.rindex_from / Bytes.rindex_from"); + } else { + return rindex_rec(s, i, c); + } +} + +function rindex_rec_opt(s, _i, c) { + while (true) { + let i = _i; + if (i < 0) { + return; + } + if (s.codePointAt(i) === c) { + return i; + } + _i = i - 1 | 0; + continue; + }; +} + +function rindex_opt(s, c) { + return rindex_rec_opt(s, s.length - 1 | 0, c); +} + +function rindex_from_opt(s, i, c) { + if (i < -1 || i >= s.length) { + return Pervasives.invalid_arg("String.rindex_from_opt / Bytes.rindex_from_opt"); + } else { + return rindex_rec_opt(s, i, c); + } +} + +function contains_from(s, i, c) { + let l = s.length; + if (i < 0 || i > l) { + return Pervasives.invalid_arg("String.contains_from / Bytes.contains_from"); + } + try { + index_rec(s, l, i, c); + return true; + } catch (raw_exn) { + let exn = Primitive_exceptions.internalToException(raw_exn); + if (exn.RE_EXN_ID === "Not_found") { + return false; + } + throw exn; + } +} + +function contains(s, c) { + return contains_from(s, 0, c); +} + +function rcontains_from(s, i, c) { + if (i < 0 || i >= s.length) { + return Pervasives.invalid_arg("String.rcontains_from / Bytes.rcontains_from"); + } + try { + rindex_rec(s, i, c); + return true; + } catch (raw_exn) { + let exn = Primitive_exceptions.internalToException(raw_exn); + if (exn.RE_EXN_ID === "Not_found") { + return false; + } + throw exn; + } +} + +function uppercase_ascii(s) { + let bytes = bos(s); + return String.fromCodePoint(...Ocaml_Array.map(Char.uppercase_ascii, bytes)); +} + +function lowercase_ascii(s) { + let bytes = bos(s); + return String.fromCodePoint(...Ocaml_Array.map(Char.lowercase_ascii, bytes)); +} + +function capitalize_ascii(s) { + let bytes = bos(s); + return String.fromCodePoint(...apply1(Char.uppercase_ascii, bytes)); +} + +function uncapitalize_ascii(s) { + let bytes = bos(s); + return String.fromCodePoint(...apply1(Char.lowercase_ascii, bytes)); +} + +function split_on_char(sep, s) { + let r = /* [] */0; + let j = s.length; + for (let i = s.length - 1 | 0; i >= 0; --i) { + if (s.codePointAt(i) === sep) { + r = { + hd: sub(s, i + 1 | 0, (j - i | 0) - 1 | 0), + tl: r + }; + j = i; + } + + } + return { + hd: sub(s, 0, j), + tl: r + }; +} + +exports.make = make; +exports.init = init; +exports.sub = sub; +exports.concat = concat; +exports.iter = iter; +exports.iteri = iteri; +exports.map = map; +exports.mapi = mapi; +exports.escaped = escaped; +exports.index = index; +exports.index_opt = index_opt; +exports.rindex = rindex; +exports.rindex_opt = rindex_opt; +exports.index_from = index_from; +exports.index_from_opt = index_from_opt; +exports.rindex_from = rindex_from; +exports.rindex_from_opt = rindex_from_opt; +exports.contains = contains; +exports.contains_from = contains_from; +exports.rcontains_from = rcontains_from; +exports.uppercase_ascii = uppercase_ascii; +exports.lowercase_ascii = lowercase_ascii; +exports.capitalize_ascii = capitalize_ascii; +exports.uncapitalize_ascii = uncapitalize_ascii; +exports.split_on_char = split_on_char; +/* No side effect */ diff --git a/tests/tests/src/ocaml_compat/Ocaml_String.res b/tests/tests/src/ocaml_compat/Ocaml_String.res new file mode 100644 index 0000000000..2c0f049e68 --- /dev/null +++ b/tests/tests/src/ocaml_compat/Ocaml_String.res @@ -0,0 +1,225 @@ +// FIXME: +// This exists for compatibility reason. +// Move this into Pervasives or Core + +// Below is all deprecated and should be removed in v13 + +module Array = Ocaml_Array + +type t = string + +module B = { + include Array + + let uppercase_ascii = bytes => map(Char.uppercase_ascii, bytes) + let lowercase_ascii = bytes => map(Char.lowercase_ascii, bytes) + + let apply1 = (f, bytes) => + if length(bytes) == 0 { + bytes + } else { + let r = copy(bytes) + unsafe_set(r, 0, f(unsafe_get(bytes, 0))) + r + } + let capitalize_ascii = bytes => apply1(Char.uppercase_ascii, bytes) + let uncapitalize_ascii = bytes => apply1(Char.lowercase_ascii, bytes) + + let escaped = bytes => map(Char.escaped, bytes) +} + +@send external join: (array, string) => string = "join" + +let concat = (sep: string, xs: list) => xs->Array.of_list->join(sep) + +external length: string => int = "%string_length" + +@send external get: (string, int) => char = "codePointAt" + +@send external unsafe_get: (string, int) => char = "codePointAt" + +@scope("Array") external bos: string => array = "from" +let bos = str => B.map(str => str->unsafe_get(0), str->bos) + +@scope("String") @variadic +external bts: array => string = "fromCodePoint" + +let make = (len, ch) => Primitive_string_extern.fromChar(ch)->Primitive_string_extern.repeat(len) + +let init = (len, f) => Array.init(len, i => Primitive_string_extern.fromChar(f(i)))->join("") + +let sub = (s, ofs, len) => bts(B.sub(bos(s), ofs, len)) + +external compare: (t, t) => int = "%compare" + +external equal: (t, t) => bool = "%equal" + +let iter = (f, s) => + for i in 0 to length(s) - 1 { + f(unsafe_get(s, i)) + } + +let iteri = (f, s) => + for i in 0 to length(s) - 1 { + f(i, unsafe_get(s, i)) + } + +let map = (f, s) => bts(B.map(f, bos(s))) +let mapi = (f, s) => bts(B.mapi(f, bos(s))) + +@send external trim: string => string = "trim" + +let escaped = s => { + let rec needs_escape = i => + if i >= length(s) { + false + } else { + switch unsafe_get(s, i) { + | '"' | '\\' | '\n' | '\t' | '\r' | '\b' => true + | ' ' .. '~' => needs_escape(i + 1) + | _ => true + } + } + + if needs_escape(0) { + join(B.escaped(bos(s)), "") + } else { + s + } +} + +/* duplicated in bytes.ml */ +let rec index_rec = (s, lim, i, c) => + if i >= lim { + raise(Not_found) + } else if unsafe_get(s, i) == c { + i + } else { + index_rec(s, lim, i + 1, c) + } + +/* duplicated in bytes.ml */ +let index = (s, c) => index_rec(s, length(s), 0, c) + +/* duplicated in bytes.ml */ +let rec index_rec_opt = (s, lim, i, c) => + if i >= lim { + None + } else if unsafe_get(s, i) == c { + Some(i) + } else { + index_rec_opt(s, lim, i + 1, c) + } + +/* duplicated in bytes.ml */ +let index_opt = (s, c) => index_rec_opt(s, length(s), 0, c) + +/* duplicated in bytes.ml */ +let index_from = (s, i, c) => { + let l = length(s) + if i < 0 || i > l { + invalid_arg("String.index_from / Bytes.index_from") + } else { + index_rec(s, l, i, c) + } +} + +/* duplicated in bytes.ml */ +let index_from_opt = (s, i, c) => { + let l = length(s) + if i < 0 || i > l { + invalid_arg("String.index_from_opt / Bytes.index_from_opt") + } else { + index_rec_opt(s, l, i, c) + } +} + +/* duplicated in bytes.ml */ +let rec rindex_rec = (s, i, c) => + if i < 0 { + raise(Not_found) + } else if unsafe_get(s, i) == c { + i + } else { + rindex_rec(s, i - 1, c) + } + +/* duplicated in bytes.ml */ +let rindex = (s, c) => rindex_rec(s, length(s) - 1, c) + +/* duplicated in bytes.ml */ +let rindex_from = (s, i, c) => + if i < -1 || i >= length(s) { + invalid_arg("String.rindex_from / Bytes.rindex_from") + } else { + rindex_rec(s, i, c) + } + +/* duplicated in bytes.ml */ +let rec rindex_rec_opt = (s, i, c) => + if i < 0 { + None + } else if unsafe_get(s, i) == c { + Some(i) + } else { + rindex_rec_opt(s, i - 1, c) + } + +/* duplicated in bytes.ml */ +let rindex_opt = (s, c) => rindex_rec_opt(s, length(s) - 1, c) + +/* duplicated in bytes.ml */ +let rindex_from_opt = (s, i, c) => + if i < -1 || i >= length(s) { + invalid_arg("String.rindex_from_opt / Bytes.rindex_from_opt") + } else { + rindex_rec_opt(s, i, c) + } + +/* duplicated in bytes.ml */ +let contains_from = (s, i, c) => { + let l = length(s) + if i < 0 || i > l { + invalid_arg("String.contains_from / Bytes.contains_from") + } else { + try { + ignore(index_rec(s, l, i, c)) + true + } catch { + | Not_found => false + } + } +} + +/* duplicated in bytes.ml */ +let contains = (s, c) => contains_from(s, 0, c) + +/* duplicated in bytes.ml */ +let rcontains_from = (s, i, c) => + if i < 0 || i >= length(s) { + invalid_arg("String.rcontains_from / Bytes.rcontains_from") + } else { + try { + ignore(rindex_rec(s, i, c)) + true + } catch { + | Not_found => false + } + } + +let uppercase_ascii = s => bts(B.uppercase_ascii(bos(s))) +let lowercase_ascii = s => bts(B.lowercase_ascii(bos(s))) +let capitalize_ascii = s => bts(B.capitalize_ascii(bos(s))) +let uncapitalize_ascii = s => bts(B.uncapitalize_ascii(bos(s))) + +let split_on_char = (sep, s) => { + let r = ref(list{}) + let j = ref(length(s)) + for i in length(s) - 1 downto 0 { + if unsafe_get(s, i) == sep { + r := list{sub(s, i + 1, j.contents - i - 1), ...r.contents} + j := i + } + } + list{sub(s, 0, j.contents), ...r.contents} +} diff --git a/tests/tests/src/ocaml_compat/Ocaml_String.resi b/tests/tests/src/ocaml_compat/Ocaml_String.resi new file mode 100644 index 0000000000..a5bc660235 --- /dev/null +++ b/tests/tests/src/ocaml_compat/Ocaml_String.resi @@ -0,0 +1,250 @@ +// FIXME: +// This exists for compatibility reason. +// Move this into Pervasives or Core + +// Below is all deprecated and should be removed in v13 + +/** Return the length (number of characters) of the given string. */ +@deprecated("Use Core instead. This will be removed in v13") +external length: string => int = "%string_length" + +/** [String.get s n] returns the character at index [n] in string [s]. + You can also write [s.[n]] instead of [String.get s n]. + + Raise [Invalid_argument] if [n] not a valid index in [s]. */ +@deprecated("Use Core instead. This will be removed in v13") +@send +external get: (string, int) => char = "codePointAt" + +/** [String.make n c] returns a fresh string of length [n], + filled with the character [c]. */ +@deprecated("Use Core instead. This will be removed in v13") +let make: (int, char) => string + +/** [String.init n f] returns a string of length [n], with character + [i] initialized to the result of [f i] (called in increasing + index order). +*/ +@deprecated("Use Core instead. This will be removed in v13") +let init: (int, int => char) => string + +/** [String.sub s start len] returns a fresh string of length [len], + containing the substring of [s] that starts at position [start] and + has length [len]. + + Raise [Invalid_argument] if [start] and [len] do not + designate a valid substring of [s]. */ +@deprecated("Use Core instead. This will be removed in v13") +let sub: (string, int, int) => string + +/** [String.concat sep sl] concatenates the list of strings [sl], + inserting the separator string [sep] between each. + + Raise [Invalid_argument] if the result is longer than + {!Sys.max_string_length} bytes. */ +@deprecated("Use Core instead. This will be removed in v13") +let concat: (string, list) => string + +/** [String.iter f s] applies function [f] in turn to all + the characters of [s]. It is equivalent to + [f s.[0]; f s.[1]; ...; f s.[String.length s - 1]; ()]. */ +@deprecated("Use Core instead. This will be removed in v13") +let iter: (char => unit, string) => unit + +/** Same as {!String.iter}, but the + function is applied to the index of the element as first argument + (counting from 0), and the character itself as second argument. + @since 4.00.0 */ +@deprecated("Use Core instead. This will be removed in v13") +let iteri: ((int, char) => unit, string) => unit + +/** [String.map f s] applies function [f] in turn to all the + characters of [s] (in increasing index order) and stores the + results in a new string that is returned. + @since 4.00.0 */ +@deprecated("Use Core instead. This will be removed in v13") +let map: (char => char, string) => string + +/** [String.mapi f s] calls [f] with each character of [s] and its + index (in increasing index order) and stores the results in a new + string that is returned. + @since 4.02.0 */ +@deprecated("Use Core instead. This will be removed in v13") +let mapi: ((int, char) => char, string) => string + +/** Return a copy of the argument, without leading and trailing + whitespace. The characters regarded as whitespace are: [' '], + ['\x0c'], ['\n'], ['\r'], and ['\t']. If there is neither leading nor + trailing whitespace character in the argument, return the original + string itself, not a copy. + @since 4.00.0 */ +@deprecated("Use Core instead. This will be removed in v13") +@send +external trim: string => string = "trim" + +/** Return a copy of the argument, with special characters + represented by escape sequences, following the lexical + conventions of OCaml. + All characters outside the ASCII printable range (32..126) are + escaped, as well as backslash and double-quote. + + If there is no special character in the argument that needs + escaping, return the original string itself, not a copy. + */ +@deprecated("Use Core instead. This will be removed in v13") +let escaped: string => string + +/** [String.index s c] returns the index of the first + occurrence of character [c] in string [s]. + + Raise [Not_found] if [c] does not occur in [s]. */ +@deprecated("Use Core instead. This will be removed in v13") +let index: (string, char) => int + +/** [String.index_opt s c] returns the index of the first + occurrence of character [c] in string [s], or + [None] if [c] does not occur in [s]. + @since 4.05 */ +@deprecated("Use Core instead. This will be removed in v13") +let index_opt: (string, char) => option + +/** [String.rindex s c] returns the index of the last + occurrence of character [c] in string [s]. + + Raise [Not_found] if [c] does not occur in [s]. */ +@deprecated("Use Core instead. This will be removed in v13") +let rindex: (string, char) => int + +/** [String.rindex_opt s c] returns the index of the last occurrence + of character [c] in string [s], or [None] if [c] does not occur in + [s]. + @since 4.05 */ +@deprecated("Use Core instead. This will be removed in v13") +let rindex_opt: (string, char) => option + +/** [String.index_from s i c] returns the index of the + first occurrence of character [c] in string [s] after position [i]. + [String.index s c] is equivalent to [String.index_from s 0 c]. + + Raise [Invalid_argument] if [i] is not a valid position in [s]. + Raise [Not_found] if [c] does not occur in [s] after position [i]. */ +@deprecated("Use Core instead. This will be removed in v13") +let index_from: (string, int, char) => int + +/** [String.index_from_opt s i c] returns the index of the + first occurrence of character [c] in string [s] after position [i] + or [None] if [c] does not occur in [s] after position [i]. + + [String.index_opt s c] is equivalent to [String.index_from_opt s 0 c]. + Raise [Invalid_argument] if [i] is not a valid position in [s]. + + @since 4.05 +*/ +@deprecated("Use Core instead. This will be removed in v13") +let index_from_opt: (string, int, char) => option + +/** [String.rindex_from s i c] returns the index of the + last occurrence of character [c] in string [s] before position [i+1]. + [String.rindex s c] is equivalent to + [String.rindex_from s (String.length s - 1) c]. + + Raise [Invalid_argument] if [i+1] is not a valid position in [s]. + Raise [Not_found] if [c] does not occur in [s] before position [i+1]. */ +@deprecated("Use Core instead. This will be removed in v13") +let rindex_from: (string, int, char) => int + +/** [String.rindex_from_opt s i c] returns the index of the + last occurrence of character [c] in string [s] before position [i+1] + or [None] if [c] does not occur in [s] before position [i+1]. + + [String.rindex_opt s c] is equivalent to + [String.rindex_from_opt s (String.length s - 1) c]. + + Raise [Invalid_argument] if [i+1] is not a valid position in [s]. + + @since 4.05 +*/ +@deprecated("Use Core instead. This will be removed in v13") +let rindex_from_opt: (string, int, char) => option + +/** [String.contains s c] tests if character [c] + appears in the string [s]. */ +@deprecated("Use Core instead. This will be removed in v13") +let contains: (string, char) => bool + +/** [String.contains_from s start c] tests if character [c] + appears in [s] after position [start]. + [String.contains s c] is equivalent to + [String.contains_from s 0 c]. + + Raise [Invalid_argument] if [start] is not a valid position in [s]. */ +@deprecated("Use Core instead. This will be removed in v13") +let contains_from: (string, int, char) => bool + +/** [String.rcontains_from s stop c] tests if character [c] + appears in [s] before position [stop+1]. + + Raise [Invalid_argument] if [stop < 0] or [stop+1] is not a valid + position in [s]. */ +@deprecated("Use Core instead. This will be removed in v13") +let rcontains_from: (string, int, char) => bool + +/** Return a copy of the argument, with all lowercase letters + translated to uppercase, using the US-ASCII character set. + @since 4.03.0 */ +@deprecated("Use Core instead. This will be removed in v13") +let uppercase_ascii: string => string + +/** Return a copy of the argument, with all uppercase letters + translated to lowercase, using the US-ASCII character set. + @since 4.03.0 */ +@deprecated("Use Core instead. This will be removed in v13") +let lowercase_ascii: string => string + +/** Return a copy of the argument, with the first character set to uppercase, + using the US-ASCII character set. + @since 4.03.0 */ +@deprecated("Use Core instead. This will be removed in v13") +let capitalize_ascii: string => string + +/** Return a copy of the argument, with the first character set to lowercase, + using the US-ASCII character set. + @since 4.03.0 */ +@deprecated("Use Core instead. This will be removed in v13") +let uncapitalize_ascii: string => string + +/** An alias for the type of strings. */ +@deprecated("Use `string` instead. This will be removed in v13") +type t = string + +/** The comparison function for strings, with the same specification as + {!Pervasives.compare}. Along with the type [t], this function [compare] + allows the module [String] to be passed as argument to the functors + {!Set.Make} and {!Map.Make}. */ +@deprecated("Use Core instead. This will be removed in v13") +external compare: (t, t) => int = "%compare" + +/** The equal function for strings. + @since 4.03.0 */ +@deprecated("Use Core instead. This will be removed in v13") +external equal: (t, t) => bool = "%equal" + +/** [String.split_on_char sep s] returns the list of all (possibly empty) + substrings of [s] that are delimited by the [sep] character. + + The function's output is specified by the following invariants: + + - The list is not empty. + - Concatenating its elements using [sep] as a separator returns a + string equal to the input ([String.concat (String.make 1 sep) + (String.split_on_char sep s) = s]). + - No string in the result contains the [sep] character. + + @since 4.04.0 +*/ +@deprecated("Use Core instead. This will be removed in v13") +let split_on_char: (char, string) => list + +/* The following is for system use only. Do not call directly. */ +@deprecated("Use Core instead. This will be removed in v13") @send +external unsafe_get: (string, int) => char = "codePointAt" diff --git a/tests/tests/src/string_bound_get_test.js b/tests/tests/src/string_bound_get_test.js index ce4117cece..f175f52790 100644 --- a/tests/tests/src/string_bound_get_test.js +++ b/tests/tests/src/string_bound_get_test.js @@ -4,16 +4,16 @@ let v = "ghos"; -let u_a = v.codePointAt(0); +let u_a = v[0]; function u_b() { - return v.codePointAt(-1); + return v[-1]; } -let u_c = "ghos".codePointAt(0); +let u_c = "ghos"[0]; function u_d() { - return "ghos".codePointAt(-1); + return "ghos"[-1]; } exports.v = v; diff --git a/tests/tests/src/string_set.js b/tests/tests/src/string_set.js index 2b1fdb6bbe..b5262a9fb0 100644 --- a/tests/tests/src/string_set.js +++ b/tests/tests/src/string_set.js @@ -280,6 +280,8 @@ function invariant(t) { return Set_gen.is_ordered(compare_elt, t); } +let $$String; + let empty = Set_gen.empty; let is_empty = Set_gen.is_empty; @@ -312,6 +314,7 @@ let of_sorted_list = Set_gen.of_sorted_list; let of_sorted_array = Set_gen.of_sorted_array; +exports.$$String = $$String; exports.compare_elt = compare_elt; exports.empty = empty; exports.is_empty = is_empty; diff --git a/tests/tests/src/string_set.res b/tests/tests/src/string_set.res index 493e3aabcd..14334124f3 100644 --- a/tests/tests/src/string_set.res +++ b/tests/tests/src/string_set.res @@ -22,6 +22,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +module String = Ocaml_String + type elt = string let compare_elt = String.compare type t = Set_gen.t diff --git a/tests/tests/src/tagged_template_test.js b/tests/tests/src/tagged_template_test.js index 5de91d68c8..457d8894e6 100644 --- a/tests/tests/src/tagged_template_test.js +++ b/tests/tests/src/tagged_template_test.js @@ -99,8 +99,11 @@ Mt.from_pair_suites("tagged templates", { } }); +let $$Array; + let extraLength = 10; +exports.$$Array = $$Array; exports.Pg = Pg; exports.table = table; exports.id = id; diff --git a/tests/tests/src/tagged_template_test.res b/tests/tests/src/tagged_template_test.res index 6ed29697d4..92c798724a 100644 --- a/tests/tests/src/tagged_template_test.res +++ b/tests/tests/src/tagged_template_test.res @@ -1,3 +1,5 @@ +module Array = Ocaml_Array + module Pg = { @module("./tagged_template_lib.js") @taggedTemplate external sql: (array, array) => string = "sql" diff --git a/tests/tests/src/tailcall_inline_test.js b/tests/tests/src/tailcall_inline_test.js index 7171478bb0..ca75e120e6 100644 --- a/tests/tests/src/tailcall_inline_test.js +++ b/tests/tests/src/tailcall_inline_test.js @@ -3,7 +3,6 @@ let Mt = require("./mt.js"); let Belt_Array = require("rescript/lib/js/Belt_Array.js"); -let Primitive_array = require("rescript/lib/js/Primitive_array.js"); function f() { let f$1 = (_acc, _n) => { @@ -20,7 +19,7 @@ function f() { }; let v = Belt_Array.make(10, 0); for (let i = 0; i <= 9; ++i) { - Primitive_array.set(v, i, f$1(0, i)); + v[i] = f$1(0, i); } return v; } diff --git a/tests/tests/src/test_closure.js b/tests/tests/src/test_closure.js index a44fb463e0..f428a3f74d 100644 --- a/tests/tests/src/test_closure.js +++ b/tests/tests/src/test_closure.js @@ -2,7 +2,6 @@ 'use strict'; let Belt_Array = require("rescript/lib/js/Belt_Array.js"); -let Primitive_array = require("rescript/lib/js/Primitive_array.js"); let v = { contents: 0 @@ -11,9 +10,9 @@ let v = { function f() { let arr = Belt_Array.make(10, param => {}); for (let i = 0; i <= 9; ++i) { - Primitive_array.set(arr, i, param => { + arr[i] = param => { v.contents = v.contents + i | 0; - }); + }; } return arr; } diff --git a/tests/tests/src/test_cps.js b/tests/tests/src/test_cps.js index 4c2e3b333f..67b6c0f289 100644 --- a/tests/tests/src/test_cps.js +++ b/tests/tests/src/test_cps.js @@ -2,7 +2,6 @@ 'use strict'; let Belt_Array = require("rescript/lib/js/Belt_Array.js"); -let Primitive_array = require("rescript/lib/js/Primitive_array.js"); function f(_n, _acc) { while (true) { @@ -23,7 +22,7 @@ function f(_n, _acc) { function test_closure() { let arr = Belt_Array.make(6, x => x); for (let i = 0; i <= 6; ++i) { - Primitive_array.set(arr, i, param => i); + arr[i] = param => i; } return arr; } diff --git a/tests/tests/src/test_for_loop.js b/tests/tests/src/test_for_loop.js index 3e1c842f68..44ee773e42 100644 --- a/tests/tests/src/test_for_loop.js +++ b/tests/tests/src/test_for_loop.js @@ -2,17 +2,16 @@ 'use strict'; let Belt_Array = require("rescript/lib/js/Belt_Array.js"); -let Primitive_array = require("rescript/lib/js/Primitive_array.js"); function for_(x) { for (let i = 0, i_finish = (console.log("hi"), x.length); i <= i_finish; ++i) { - console.log(Primitive_array.get(x, i)); + console.log(x[i]); } } function for_2(x) { for (let i = 0, i_finish = x.length; i <= i_finish; ++i) { - console.log(Primitive_array.get(x, i)); + console.log(x[i]); } } @@ -23,9 +22,9 @@ function for_3(x) { let arr = Belt_Array.map(x, param => (() => {})); for (let i = 0, i_finish = x.length; i <= i_finish; ++i) { let j = (i << 1); - Primitive_array.set(arr, i, () => { + arr[i] = () => { v.contents = v.contents + j | 0; - }); + }; } Belt_Array.forEach(arr, x => x()); return v.contents; @@ -39,9 +38,9 @@ function for_4(x) { for (let i = 0, i_finish = x.length; i <= i_finish; ++i) { let j = (i << 1); let k = (j << 1); - Primitive_array.set(arr, i, () => { + arr[i] = () => { v.contents = v.contents + k | 0; - }); + }; } Belt_Array.forEach(arr, x => x()); return v.contents; @@ -54,9 +53,9 @@ function for_5(x, u) { let arr = Belt_Array.map(x, param => (() => {})); for (let i = 0, i_finish = x.length; i <= i_finish; ++i) { let k = Math.imul((u << 1), u); - Primitive_array.set(arr, i, () => { + arr[i] = () => { v.contents = v.contents + k | 0; - }); + }; } Belt_Array.forEach(arr, x => x()); return v.contents; @@ -83,9 +82,9 @@ function for_6(x, u) { let k = Math.imul((u << 1), u); let h = (v5.contents << 1); v2.contents = v2.contents + 1 | 0; - Primitive_array.set(arr, i, () => { + arr[i] = () => { v.contents = (((((v.contents + k | 0) + v2.contents | 0) + u | 0) + v4.contents | 0) + v5.contents | 0) + h | 0; - }); + }; } } Belt_Array.forEach(arr, x => x()); diff --git a/tests/tests/src/test_google_closure.js b/tests/tests/src/test_google_closure.js index c4a99fd263..ec2b89005b 100644 --- a/tests/tests/src/test_google_closure.js +++ b/tests/tests/src/test_google_closure.js @@ -2,7 +2,6 @@ 'use strict'; let Belt_Array = require("rescript/lib/js/Belt_Array.js"); -let Primitive_array = require("rescript/lib/js/Primitive_array.js"); function f(a, b, param) { return a + b | 0; @@ -24,7 +23,7 @@ let arr = Belt_Array.init(2, param => 0); for (let i = 0; i <= 1; ++i) { let f3$1 = extra => i + 1 | 0; - Primitive_array.set(arr, i, f3$1(2)); + arr[i] = f3$1(2); } console.log([ diff --git a/tests/tests/src/test_literals.js b/tests/tests/src/test_literals.js index bb9b374c58..6497150fe4 100644 --- a/tests/tests/src/test_literals.js +++ b/tests/tests/src/test_literals.js @@ -11,4 +11,4 @@ let bsconfig_json = "bsconfig.json"; exports.node_modules = node_modules; exports.node_modules_length = node_modules_length; exports.bsconfig_json = bsconfig_json; -/* No side effect */ +/* node_modules_length Not a pure module */ diff --git a/tests/tests/src/test_pervasive.js b/tests/tests/src/test_pervasive.js index 05b423e121..6ec9dcd090 100644 --- a/tests/tests/src/test_pervasive.js +++ b/tests/tests/src/test_pervasive.js @@ -4,44 +4,6 @@ let Belt_List = require("rescript/lib/js/Belt_List.js"); let Pervasives = require("rescript/lib/js/Pervasives.js"); -let $at = Pervasives.Pervasives.$at; - -let Pervasives_failwith = Pervasives.Pervasives.failwith; - -let Pervasives_invalid_arg = Pervasives.Pervasives.invalid_arg; - -let Pervasives_Exit = Pervasives.Pervasives.Exit; - -let Pervasives_abs = Pervasives.Pervasives.abs; - -let Pervasives_lnot = Pervasives.Pervasives.lnot; - -let Pervasives_max_int = Pervasives.Pervasives.max_int; - -let Pervasives_min_int = Pervasives.Pervasives.min_int; - -let Pervasives_infinity = Pervasives.Pervasives.infinity; - -let Pervasives_neg_infinity = Pervasives.Pervasives.neg_infinity; - -let Pervasives_max_float = Pervasives.Pervasives.max_float; - -let Pervasives_min_float = Pervasives.Pervasives.min_float; - -let Pervasives_epsilon_float = Pervasives.Pervasives.epsilon_float; - -let Pervasives_classify_float = Pervasives.Pervasives.classify_float; - -let Pervasives_char_of_int = Pervasives.Pervasives.char_of_int; - -let Pervasives_string_of_bool = Pervasives.Pervasives.string_of_bool; - -let Pervasives_bool_of_string = Pervasives.Pervasives.bool_of_string; - -let Pervasives_bool_of_string_opt = Pervasives.Pervasives.bool_of_string_opt; - -let Pervasives_int_of_string_opt = Pervasives.Pervasives.int_of_string_opt; - let Pervasives$1 = { length: Belt_List.length, size: Belt_List.size, @@ -131,25 +93,26 @@ let Pervasives$1 = { setAssoc: Belt_List.setAssoc, sortU: Belt_List.sortU, sort: Belt_List.sort, - failwith: Pervasives_failwith, - invalid_arg: Pervasives_invalid_arg, - Exit: Pervasives_Exit, - abs: Pervasives_abs, - lnot: Pervasives_lnot, - max_int: Pervasives_max_int, - min_int: Pervasives_min_int, - infinity: Pervasives_infinity, - neg_infinity: Pervasives_neg_infinity, - max_float: Pervasives_max_float, - min_float: Pervasives_min_float, - epsilon_float: Pervasives_epsilon_float, - classify_float: Pervasives_classify_float, - char_of_int: Pervasives_char_of_int, - string_of_bool: Pervasives_string_of_bool, - bool_of_string: Pervasives_bool_of_string, - bool_of_string_opt: Pervasives_bool_of_string_opt, - int_of_string_opt: Pervasives_int_of_string_opt, - $at: $at + failwith: Pervasives.failwith, + invalid_arg: Pervasives.invalid_arg, + Exit: Pervasives.Exit, + abs: Pervasives.abs, + lnot: Pervasives.lnot, + max_int: Pervasives.max_int, + min_int: Pervasives.min_int, + infinity: Pervasives.infinity, + neg_infinity: Pervasives.neg_infinity, + max_float: Pervasives.max_float, + min_float: Pervasives.min_float, + epsilon_float: Pervasives.epsilon_float, + classify_float: Pervasives.classify_float, + char_of_int: Pervasives.char_of_int, + string_of_bool: Pervasives.string_of_bool, + bool_of_string: Pervasives.bool_of_string, + bool_of_string_opt: Pervasives.bool_of_string_opt, + int_of_string_opt: Pervasives.int_of_string_opt, + $at: Pervasives.$at, + panic: Pervasives.panic }; function a0(prim) { @@ -228,7 +191,7 @@ function a18(prim0, prim1) { return Math.pow(prim0, prim1); } -let f = $at; +let f = Pervasives.$at; exports.Pervasives = Pervasives$1; exports.f = f; diff --git a/tests/tests/src/test_pervasives3.js b/tests/tests/src/test_pervasives3.js index 50877f8288..3288799e75 100644 --- a/tests/tests/src/test_pervasives3.js +++ b/tests/tests/src/test_pervasives3.js @@ -4,64 +4,27 @@ let Belt_List = require("rescript/lib/js/Belt_List.js"); let Pervasives = require("rescript/lib/js/Pervasives.js"); -let $at = Pervasives.Pervasives.$at; - -let Pervasives_failwith = Pervasives.Pervasives.failwith; - -let Pervasives_invalid_arg = Pervasives.Pervasives.invalid_arg; - -let Pervasives_Exit = Pervasives.Pervasives.Exit; - -let Pervasives_abs = Pervasives.Pervasives.abs; - -let Pervasives_lnot = Pervasives.Pervasives.lnot; - -let Pervasives_max_int = Pervasives.Pervasives.max_int; - -let Pervasives_min_int = Pervasives.Pervasives.min_int; - -let Pervasives_infinity = Pervasives.Pervasives.infinity; - -let Pervasives_neg_infinity = Pervasives.Pervasives.neg_infinity; - -let Pervasives_max_float = Pervasives.Pervasives.max_float; - -let Pervasives_min_float = Pervasives.Pervasives.min_float; - -let Pervasives_epsilon_float = Pervasives.Pervasives.epsilon_float; - -let Pervasives_classify_float = Pervasives.Pervasives.classify_float; - -let Pervasives_char_of_int = Pervasives.Pervasives.char_of_int; - -let Pervasives_string_of_bool = Pervasives.Pervasives.string_of_bool; - -let Pervasives_bool_of_string = Pervasives.Pervasives.bool_of_string; - -let Pervasives_bool_of_string_opt = Pervasives.Pervasives.bool_of_string_opt; - -let Pervasives_int_of_string_opt = Pervasives.Pervasives.int_of_string_opt; - let Pervasives$1 = { - failwith: Pervasives_failwith, - invalid_arg: Pervasives_invalid_arg, - Exit: Pervasives_Exit, - abs: Pervasives_abs, - lnot: Pervasives_lnot, - max_int: Pervasives_max_int, - min_int: Pervasives_min_int, - infinity: Pervasives_infinity, - neg_infinity: Pervasives_neg_infinity, - max_float: Pervasives_max_float, - min_float: Pervasives_min_float, - epsilon_float: Pervasives_epsilon_float, - classify_float: Pervasives_classify_float, - char_of_int: Pervasives_char_of_int, - string_of_bool: Pervasives_string_of_bool, - bool_of_string: Pervasives_bool_of_string, - bool_of_string_opt: Pervasives_bool_of_string_opt, - int_of_string_opt: Pervasives_int_of_string_opt, - $at: $at, + failwith: Pervasives.failwith, + invalid_arg: Pervasives.invalid_arg, + Exit: Pervasives.Exit, + abs: Pervasives.abs, + lnot: Pervasives.lnot, + max_int: Pervasives.max_int, + min_int: Pervasives.min_int, + infinity: Pervasives.infinity, + neg_infinity: Pervasives.neg_infinity, + max_float: Pervasives.max_float, + min_float: Pervasives.min_float, + epsilon_float: Pervasives.epsilon_float, + classify_float: Pervasives.classify_float, + char_of_int: Pervasives.char_of_int, + string_of_bool: Pervasives.string_of_bool, + bool_of_string: Pervasives.bool_of_string, + bool_of_string_opt: Pervasives.bool_of_string_opt, + int_of_string_opt: Pervasives.int_of_string_opt, + $at: Pervasives.$at, + panic: Pervasives.panic, length: Belt_List.length, size: Belt_List.size, head: Belt_List.head, @@ -152,7 +115,7 @@ let Pervasives$1 = { sort: Belt_List.sort }; -let v = $at; +let v = Pervasives.$at; exports.Pervasives = Pervasives$1; exports.v = v; diff --git a/tests/tests/src/test_primitive.js b/tests/tests/src/test_primitive.js index 5131f8dad1..e5367cca65 100644 --- a/tests/tests/src/test_primitive.js +++ b/tests/tests/src/test_primitive.js @@ -2,7 +2,6 @@ 'use strict'; let Lazy = require("rescript/lib/js/Lazy.js"); -let Primitive_array = require("rescript/lib/js/Primitive_array.js"); function a4(prim) { return [ @@ -41,7 +40,7 @@ let v = [ let xxx = "a"; -let a = xxx.codePointAt(0); +let a = xxx[0]; function u(b) { if (b) { @@ -56,7 +55,7 @@ function f2(h, b, param) { return h(b ? 32 : 7); } -Primitive_array.set(v, 1, 3.0); +v[1] = 3.0; let unboxed_x = { u: 0, diff --git a/tests/tests/src/test_runtime_encoding.js b/tests/tests/src/test_runtime_encoding.js index 70454ad5e9..6bef667b3e 100644 --- a/tests/tests/src/test_runtime_encoding.js +++ b/tests/tests/src/test_runtime_encoding.js @@ -1,7 +1,6 @@ // Generated by ReScript, PLEASE EDIT WITH CARE 'use strict'; -let Primitive_array = require("rescript/lib/js/Primitive_array.js"); function g(x) { return [ @@ -25,11 +24,11 @@ function fff(vv, uu) { } function a(x) { - return Primitive_array.get(x, 0); + return x[0]; } function aa(x) { - return Primitive_array.get(x, 0); + return x[0]; } function aaa(x) { @@ -42,7 +41,7 @@ function aaaa(x) { function f(x) { for (let i = 0; i <= 10; ++i) { - Primitive_array.set(x, i, i); + x[i] = i; } } diff --git a/tests/tests/src/test_string.js b/tests/tests/src/test_string.js index a2db7217af..c850635499 100644 --- a/tests/tests/src/test_string.js +++ b/tests/tests/src/test_string.js @@ -13,7 +13,7 @@ function f(x) { RE_EXN_ID: "Assert_failure", _1: [ "test_string.res", - 5, + 7, 17 ], Error: new Error() @@ -39,6 +39,9 @@ function h(s) { return s.codePointAt(0) === /* 'a' */97; } +let $$String; + +exports.$$String = $$String; exports.f = f; exports.a = a; exports.b = b; diff --git a/tests/tests/src/test_string.res b/tests/tests/src/test_string.res index c458f95f00..05b4711917 100644 --- a/tests/tests/src/test_string.res +++ b/tests/tests/src/test_string.res @@ -1,3 +1,5 @@ +module String = Ocaml_String + let f = x => switch x { | "aaaabb" => 0 diff --git a/tests/tests/src/test_string_const.js b/tests/tests/src/test_string_const.js index 98f22306ad..a5c39aa243 100644 --- a/tests/tests/src/test_string_const.js +++ b/tests/tests/src/test_string_const.js @@ -19,6 +19,9 @@ try { } } +let $$String; + +exports.$$String = $$String; exports.f = f; exports.hh = hh; /* f Not a pure module */ diff --git a/tests/tests/src/test_string_const.res b/tests/tests/src/test_string_const.res index e9b89d5f35..613e183d58 100644 --- a/tests/tests/src/test_string_const.res +++ b/tests/tests/src/test_string_const.res @@ -1,3 +1,5 @@ +module String = Ocaml_String + let f = String.get("ghsogh", 3) let hh = try String.get("ghsogh", -3) catch { diff --git a/tests/tests/src/test_while_closure.js b/tests/tests/src/test_while_closure.js index 6cf6e7cc09..cc31ce3aca 100644 --- a/tests/tests/src/test_while_closure.js +++ b/tests/tests/src/test_while_closure.js @@ -2,7 +2,6 @@ 'use strict'; let Belt_Array = require("rescript/lib/js/Belt_Array.js"); -let Primitive_array = require("rescript/lib/js/Primitive_array.js"); let v = { contents: 0 @@ -14,9 +13,9 @@ function f() { let n = 0; while (n < 10) { let j = n; - Primitive_array.set(arr, j, () => { + arr[j] = () => { v.contents = v.contents + j | 0; - }); + }; n = n + 1 | 0; }; }