diff --git a/CHANGELOG.md b/CHANGELOG.md index 26772eaae69..59304bff50e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ #### :boom: Breaking Change - Support for `break` and `continue` in loops. `break` and `continue` are new keywords. https://github.com/rescript-lang/rescript/pull/8348 +- Fix iterator / iterable typedefs, add generator typedefs. https://github.com/rescript-lang/rescript/pull/8355 #### :eyeglasses: Spec Compliance diff --git a/compiler/gentype/TranslateTypeExprFromTypes.ml b/compiler/gentype/TranslateTypeExprFromTypes.ml index beea6c83cea..3bf09ca0fae 100644 --- a/compiler/gentype/TranslateTypeExprFromTypes.ml +++ b/compiler/gentype/TranslateTypeExprFromTypes.ml @@ -149,15 +149,156 @@ let translate_constr ~config ~params_translation ~(path : Path.t) ~type_env = {dependencies = []; type_ = ident ("Intl." ^ intl_module)} | (["Stdlib"; "Error"; "t"] | ["Stdlib"; "JsError"; "t"]), [] -> {dependencies = []; type_ = ident "Error"} - | ["Stdlib"; "Iterator"; "t"], [param_translation] -> + | (["Stdlib"; "Iterable"; "t"] | ["iterable"]), [param_translation] -> { dependencies = param_translation.dependencies; - type_ = ident ~type_args:[param_translation.type_] "Iterator"; + type_ = ident ~type_args:[param_translation.type_] "Iterable"; } - | ["Stdlib"; "AsyncIterator"; "t"], [param_translation] -> + | ( ["Stdlib"; "Iterator"; "t"], + [yield_translation; return_translation; next_translation] ) -> + { + dependencies = + List.concat + [ + yield_translation.dependencies; + return_translation.dependencies; + next_translation.dependencies; + ]; + type_ = + ident + ~type_args: + [ + yield_translation.type_; + return_translation.type_; + next_translation.type_; + ] + "Iterator"; + } + | ( ["Stdlib"; "IteratorObject"; "t"], + [yield_translation; return_translation; next_translation] ) -> + { + dependencies = + List.concat + [ + yield_translation.dependencies; + return_translation.dependencies; + next_translation.dependencies; + ]; + type_ = + ident + ~type_args: + [ + yield_translation.type_; + return_translation.type_; + next_translation.type_; + ] + "IteratorObject"; + } + | ( ["Stdlib"; "IterableIterator"; "t"], + [yield_translation; return_translation; next_translation] ) -> + { + dependencies = + List.concat + [ + yield_translation.dependencies; + return_translation.dependencies; + next_translation.dependencies; + ]; + type_ = + ident + ~type_args: + [ + yield_translation.type_; + return_translation.type_; + next_translation.type_; + ] + "IterableIterator"; + } + | ( ["Stdlib"; "Generator"; "t"], + [yield_translation; return_translation; next_translation] ) -> + { + dependencies = + List.concat + [ + yield_translation.dependencies; + return_translation.dependencies; + next_translation.dependencies; + ]; + type_ = + ident + ~type_args: + [ + yield_translation.type_; + return_translation.type_; + next_translation.type_; + ] + "Generator"; + } + | (["Stdlib"; "AsyncIterable"; "t"] | ["asyncIterable"]), [param_translation] + -> { dependencies = param_translation.dependencies; - type_ = ident ~type_args:[param_translation.type_] "AsyncIterator"; + type_ = ident ~type_args:[param_translation.type_] "AsyncIterable"; + } + | ( ["Stdlib"; "AsyncIterator"; "t"], + [yield_translation; return_translation; next_translation] ) -> + { + dependencies = + List.concat + [ + yield_translation.dependencies; + return_translation.dependencies; + next_translation.dependencies; + ]; + type_ = + ident + ~type_args: + [ + yield_translation.type_; + return_translation.type_; + next_translation.type_; + ] + "AsyncIterator"; + } + | ( ["Stdlib"; "AsyncIterableIterator"; "t"], + [yield_translation; return_translation; next_translation] ) -> + { + dependencies = + List.concat + [ + yield_translation.dependencies; + return_translation.dependencies; + next_translation.dependencies; + ]; + type_ = + ident + ~type_args: + [ + yield_translation.type_; + return_translation.type_; + next_translation.type_; + ] + "AsyncIterableIterator"; + } + | ( ["Stdlib"; "AsyncGenerator"; "t"], + [yield_translation; return_translation; next_translation] ) -> + { + dependencies = + List.concat + [ + yield_translation.dependencies; + return_translation.dependencies; + next_translation.dependencies; + ]; + type_ = + ident + ~type_args: + [ + yield_translation.type_; + return_translation.type_; + next_translation.type_; + ] + "AsyncGenerator"; } | ["Stdlib"; "Ordering"; "t"], [] -> {dependencies = []; type_ = number_t} | ["unit"], [] -> {dependencies = []; type_ = unit_t} diff --git a/compiler/ml/predef.ml b/compiler/ml/predef.ml index 5913791eff9..fb5e4271128 100644 --- a/compiler/ml/predef.ml +++ b/compiler/ml/predef.ml @@ -43,6 +43,10 @@ and ident_exn = ident_create "exn" and ident_array = ident_create "array" +and ident_iterable = ident_create "iterable" + +and ident_async_iterable = ident_create "asyncIterable" + and ident_list = ident_create "list" and ident_option = ident_create "option" @@ -86,6 +90,10 @@ and path_exn = Pident ident_exn and path_array = Pident ident_array +and path_iterable = Pident ident_iterable + +and path_async_iterable = Pident ident_async_iterable + and path_list = Pident ident_list and path_option = Pident ident_option @@ -118,6 +126,11 @@ and type_exn = newgenty (Tconstr (path_exn, [], ref Mnil)) and type_array t = newgenty (Tconstr (path_array, [t], ref Mnil)) +and type_iterable t = newgenty (Tconstr (path_iterable, [t], ref Mnil)) + +and type_async_iterable t = + newgenty (Tconstr (path_async_iterable, [t], ref Mnil)) + and type_list t = newgenty (Tconstr (path_list, [t], ref Mnil)) and type_option t = newgenty (Tconstr (path_option, [t], ref Mnil)) @@ -245,6 +258,22 @@ let common_initial_env add_type add_extension empty_env = type_arity = 1; type_variance = [Variance.full]; } + and decl_iterable = + let tvar = newgenvar () in + { + decl_abstr with + type_params = [tvar]; + type_arity = 1; + type_variance = [Variance.covariant]; + } + and decl_async_iterable = + let tvar = newgenvar () in + { + decl_abstr with + type_params = [tvar]; + type_arity = 1; + type_variance = [Variance.covariant]; + } and decl_list = let tvar = newgenvar () in { @@ -369,6 +398,8 @@ let common_initial_env add_type add_extension empty_env = |> add_type ident_result decl_result |> add_type ident_promise decl_promise |> add_type ident_array decl_array + |> add_type ident_iterable decl_iterable + |> add_type ident_async_iterable decl_async_iterable |> add_type ident_list decl_list |> add_type ident_dict decl_dict |> add_type ident_unknown decl_unknown diff --git a/compiler/ml/predef.mli b/compiler/ml/predef.mli index 8e3330fe43c..e274ea1cac2 100644 --- a/compiler/ml/predef.mli +++ b/compiler/ml/predef.mli @@ -25,6 +25,8 @@ val type_bool : type_expr val type_unit : type_expr val type_exn : type_expr val type_array : type_expr -> type_expr +val type_iterable : type_expr -> type_expr +val type_async_iterable : type_expr -> type_expr val type_list : type_expr -> type_expr val type_option : type_expr -> type_expr val type_result : type_expr -> type_expr -> type_expr @@ -41,6 +43,8 @@ val path_bool : Path.t val path_unit : Path.t val path_exn : Path.t val path_array : Path.t +val path_iterable : Path.t +val path_async_iterable : Path.t val path_list : Path.t val path_option : Path.t val path_result : Path.t diff --git a/packages/@rescript/runtime/Stdlib.res b/packages/@rescript/runtime/Stdlib.res index 52f2771c699..2f4ab98f529 100644 --- a/packages/@rescript/runtime/Stdlib.res +++ b/packages/@rescript/runtime/Stdlib.res @@ -31,8 +31,15 @@ module String = Stdlib_String module Symbol = Stdlib_Symbol module Type = Stdlib_Type +module Iterable = Stdlib_Iterable module Iterator = Stdlib_Iterator +module IteratorObject = Stdlib_IteratorObject +module IterableIterator = Stdlib_IterableIterator +module Generator = Stdlib_Generator +module AsyncIterable = Stdlib_AsyncIterable module AsyncIterator = Stdlib_AsyncIterator +module AsyncIterableIterator = Stdlib_AsyncIterableIterator +module AsyncGenerator = Stdlib_AsyncGenerator module Map = Stdlib_Map module WeakMap = Stdlib_WeakMap module Set = Stdlib_Set diff --git a/packages/@rescript/runtime/Stdlib_Array.res b/packages/@rescript/runtime/Stdlib_Array.res index e610826780e..71ea2057e0a 100644 --- a/packages/@rescript/runtime/Stdlib_Array.res +++ b/packages/@rescript/runtime/Stdlib_Array.res @@ -8,7 +8,10 @@ external setUnsafe: (array<'a>, int, 'a) => unit = "%array_unsafe_set" external unsafe_get: (array<'a>, int) => 'a = "%array_unsafe_get" -@val external fromIterator: Stdlib_Iterator.t<'a> => array<'a> = "Array.from" +external asIterable: array<'a> => Stdlib_Iterable.t<'a> = "%identity" + +@val +external fromIterable: Stdlib_Iterable.t<'a> => array<'a> = "Array.from" @val external fromArrayLike: arrayLike<'a> => array<'a> = "Array.from" @val external fromArrayLikeWithMap: (arrayLike<'a>, 'a => 'b) => array<'b> = "Array.from" @@ -406,7 +409,7 @@ let last = a => a->get(a->length - 1) external ignore: array<'a> => unit = "%ignore" @send -external entries: array<'a> => Stdlib_Iterator.t<(int, 'a)> = "entries" +external entries: array<'a> => Stdlib_IteratorObject.t<(int, 'a), unit, unknown> = "entries" @send -external values: array<'a> => Stdlib_Iterator.t<'a> = "values" +external values: array<'a> => Stdlib_IteratorObject.t<'a, unit, unknown> = "values" diff --git a/packages/@rescript/runtime/Stdlib_Array.resi b/packages/@rescript/runtime/Stdlib_Array.resi index 3a0b69bf356..3a2196ec37c 100644 --- a/packages/@rescript/runtime/Stdlib_Array.resi +++ b/packages/@rescript/runtime/Stdlib_Array.resi @@ -11,18 +11,27 @@ type t<'a> = array<'a> type arrayLike<'a> /** -`fromIterator(iterator)` creates an array from the provided `iterator` +`asIterable(array)` views `array` as an `Iterable.t`. + +This is useful when passing an array to APIs that consume iterables, such as +`Array.from` or `for...of` in JavaScript. +*/ +external asIterable: array<'a> => Stdlib_Iterable.t<'a> = "%identity" + +/** +`fromIterable(iterable)` creates an array from the provided `iterable` ## Examples ```rescript Map.fromArray([("foo", 1), ("bar", 2)]) ->Map.values -->Array.fromIterator == [1, 2] +->IteratorObject.asIterable +->Array.fromIterable == [1, 2] ``` */ @val -external fromIterator: Stdlib_Iterator.t<'a> => array<'a> = "Array.from" +external fromIterable: Stdlib_Iterable.t<'a> => array<'a> = "Array.from" /** `fromArrayLike(source)` converts an array-like value (anything with indexed items and a `length`) into a regular array. @@ -1661,13 +1670,12 @@ See [Array.prototype.entries](https://developer.mozilla.org/en-US/docs/Web/JavaS ```rescript let array = [5, 6, 7] -let iterator: Iterator.t<(int, int)> = array->Array.entries -iterator->Iterator.next == {done: false, value: Some((0, 5))} -iterator->Iterator.next == {done: false, value: Some((1, 6))} +let iterator: IteratorObject.t<(int, int), unit, unknown> = array->Array.entries +iterator->IteratorObject.toArray == [(0, 5), (1, 6), (2, 7)] ``` */ @send -external entries: array<'a> => Stdlib_Iterator.t<(int, 'a)> = "entries" +external entries: array<'a> => Stdlib_IteratorObject.t<(int, 'a), unit, unknown> = "entries" /** `values(array)` returns a new array iterator object that contains the values for each index in the array. @@ -1678,10 +1686,9 @@ See [Array.prototype.values](https://developer.mozilla.org/en-US/docs/Web/JavaSc ```rescript let array = [5, 6, 7] -let iterator: Iterator.t = array->Array.values -iterator->Iterator.next == {done: false, value: Some(5)} -iterator->Iterator.next == {done: false, value: Some(6)} +let iterator: IteratorObject.t = array->Array.values +iterator->IteratorObject.toArray == [5, 6, 7] ``` */ @send -external values: array<'a> => Stdlib_Iterator.t<'a> = "values" +external values: array<'a> => Stdlib_IteratorObject.t<'a, unit, unknown> = "values" diff --git a/packages/@rescript/runtime/Stdlib_AsyncGenerator.res b/packages/@rescript/runtime/Stdlib_AsyncGenerator.res new file mode 100644 index 00000000000..82b684b2609 --- /dev/null +++ b/packages/@rescript/runtime/Stdlib_AsyncGenerator.res @@ -0,0 +1,36 @@ +type t<'yield, 'return, 'next> = Stdlib_AsyncIterable.t<'yield> + +external asAsyncIterable: t<'yield, 'return, 'next> => Stdlib_AsyncIterable.t<'yield> = "%identity" +external asAsyncIterableIterator: t<'yield, 'return, 'next> => Stdlib_AsyncIterableIterator.t< + 'yield, + 'return, + 'next, +> = "%identity" +external asAsyncIterator: t<'yield, 'return, 'next> => Stdlib_AsyncIterator.t< + 'yield, + 'return, + 'next, +> = "%identity" + +let next = generator => generator->asAsyncIterator->Stdlib_AsyncIterator.next + +let nextValue = (generator, value) => + generator->asAsyncIterator->Stdlib_AsyncIterator.nextValue(value) + +@send +external returnValueRaw: ( + t<'yield, 'return, 'next>, + 'return, +) => promise> = "return" + +let returnValue = async (generator, value) => + Stdlib_AsyncIterator.normalizeResult(await generator->returnValueRaw(value)) + +@send +external throwErrorRaw: ( + t<'yield, 'return, 'next>, + exn, +) => promise> = "throw" + +let throwError = async (generator, error) => + Stdlib_AsyncIterator.normalizeResult(await generator->throwErrorRaw(error)) diff --git a/packages/@rescript/runtime/Stdlib_AsyncGenerator.resi b/packages/@rescript/runtime/Stdlib_AsyncGenerator.resi new file mode 100644 index 00000000000..a61859ad495 --- /dev/null +++ b/packages/@rescript/runtime/Stdlib_AsyncGenerator.resi @@ -0,0 +1,65 @@ +/*** +A JavaScript async generator object. + +Async generators are built-in async iterable iterators with additional +`return()` and `throw()` capabilities. + +See [`AsyncGenerator`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/AsyncGenerator) on MDN. +*/ + +/** +Type representing an async generator object. +*/ +type t<'yield, 'return, 'next> = private Stdlib_AsyncIterable.t<'yield> + +/** +`asAsyncIterable(generator)` views `generator` as an `AsyncIterable.t`. +*/ +external asAsyncIterable: t<'yield, 'return, 'next> => Stdlib_AsyncIterable.t<'yield> = "%identity" + +/** +`asAsyncIterableIterator(generator)` views `generator` as an `AsyncIterableIterator.t`. +*/ +external asAsyncIterableIterator: t<'yield, 'return, 'next> => Stdlib_AsyncIterableIterator.t< + 'yield, + 'return, + 'next, +> = "%identity" + +/** +`asAsyncIterator(generator)` views `generator` as an `AsyncIterator.t`. +*/ +external asAsyncIterator: t<'yield, 'return, 'next> => Stdlib_AsyncIterator.t< + 'yield, + 'return, + 'next, +> = "%identity" + +/** +`next(generator)` advances `generator` without sending a value back in. +*/ +let next: t<'yield, 'return, 'next> => promise> + +/** +`nextValue(generator, value)` advances `generator`, sending `value` back into it. +*/ +let nextValue: ( + t<'yield, 'return, 'next>, + 'next, +) => promise> + +/** +`returnValue(generator, value)` completes `generator` with the final return `value`. +*/ +let returnValue: ( + t<'yield, 'return, 'next>, + 'return, +) => promise> + +/** +`throwError(generator, error)` throws `error` into `generator`. +*/ +let throwError: ( + t<'yield, 'return, 'next>, + exn, +) => promise> diff --git a/packages/@rescript/runtime/Stdlib_AsyncIterable.res b/packages/@rescript/runtime/Stdlib_AsyncIterable.res new file mode 100644 index 00000000000..15ebd6bd334 --- /dev/null +++ b/packages/@rescript/runtime/Stdlib_AsyncIterable.res @@ -0,0 +1,3 @@ +type t<'yield> = asyncIterable<'yield> + +external ignore: t<'yield> => unit = "%ignore" diff --git a/packages/@rescript/runtime/Stdlib_AsyncIterable.resi b/packages/@rescript/runtime/Stdlib_AsyncIterable.resi new file mode 100644 index 00000000000..a4321b5015e --- /dev/null +++ b/packages/@rescript/runtime/Stdlib_AsyncIterable.resi @@ -0,0 +1,18 @@ +/*** +A JavaScript async iterable. + +Values of this type implement the async iterable protocol and can be consumed +by `for await...of` and other JavaScript APIs that expect async iterables. + +See [`AsyncIterator`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/AsyncIterator) on MDN. +*/ + +/** +Type representing an async iterable that yields values of type `'yield`. +*/ +type t<'yield> = asyncIterable<'yield> + +/** +`ignore(asyncIterable)` marks `asyncIterable` as intentionally unused. +*/ +external ignore: t<'yield> => unit = "%ignore" diff --git a/packages/@rescript/runtime/Stdlib_AsyncIterableIterator.res b/packages/@rescript/runtime/Stdlib_AsyncIterableIterator.res new file mode 100644 index 00000000000..56ecbca2f39 --- /dev/null +++ b/packages/@rescript/runtime/Stdlib_AsyncIterableIterator.res @@ -0,0 +1,39 @@ +type t<'yield, 'return, 'next> = Stdlib_AsyncIterable.t<'yield> + +let make: (unit => promise>) => t< + 'yield, + 'return, + unit, +> = %raw(`function makeAsyncIterableIterator(next) { + return { + next, + [Symbol.asyncIterator]() { + return this; + } + } +}`) + +external asAsyncIterable: t<'yield, 'return, 'next> => Stdlib_AsyncIterable.t<'yield> = "%identity" +external asAsyncIterator: t<'yield, 'return, 'next> => Stdlib_AsyncIterator.t< + 'yield, + 'return, + 'next, +> = "%identity" + +let next = iterator => iterator->asAsyncIterator->Stdlib_AsyncIterator.next + +let nextValue = (iterator, value) => + iterator->asAsyncIterator->Stdlib_AsyncIterator.nextValue(value) + +let forEach = async (iterator, f) => { + let iteratorDone = ref(false) + + while !iteratorDone.contents { + switch await iterator->next { + | Yield({value}) => f(value) + | Return(_) => iteratorDone := true + } + } +} + +external ignore: t<'yield, 'return, 'next> => unit = "%ignore" diff --git a/packages/@rescript/runtime/Stdlib_AsyncIterableIterator.resi b/packages/@rescript/runtime/Stdlib_AsyncIterableIterator.resi new file mode 100644 index 00000000000..0ee87335f4e --- /dev/null +++ b/packages/@rescript/runtime/Stdlib_AsyncIterableIterator.resi @@ -0,0 +1,82 @@ +/*** +A JavaScript async iterable iterator. + +This models values that satisfy both the async iterable and async iterator +protocols without assuming any additional helper methods are available. + +See [`AsyncIterator`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/AsyncIterator) on MDN. +*/ + +/** +Type representing an async iterable iterator. +*/ +type t<'yield, 'return, 'next> = private Stdlib_AsyncIterable.t<'yield> + +/** +`make(nextFn)` creates an async iterable iterator from a function returning the next result. + +The returned value is both an async iterator and an async iterable. + +## Examples + +```rescript +let current = ref(0) + +let asyncIterableIterator = AsyncIterableIterator.make(async () => { + let value = current.contents + current := value + 1 + + if value >= 3 { + AsyncIterator.done() + } else { + AsyncIterator.value(value) + } +}) + +let main = async () => + await asyncIterableIterator->AsyncIterableIterator.forEach(value => Console.log(value)) + +main()->ignore +``` +*/ +let make: (unit => promise>) => t<'yield, 'return, unit> + +/** +`asAsyncIterable(value)` views `value` as an `AsyncIterable.t`. +*/ +external asAsyncIterable: t<'yield, 'return, 'next> => Stdlib_AsyncIterable.t<'yield> = "%identity" + +/** +`asAsyncIterator(value)` views `value` as an `AsyncIterator.t`. +*/ +external asAsyncIterator: t<'yield, 'return, 'next> => Stdlib_AsyncIterator.t< + 'yield, + 'return, + 'next, +> = "%identity" + +/** +`next(iterator)` advances `iterator` without sending a value back in. +*/ +let next: t<'yield, 'return, 'next> => promise> + +/** +`nextValue(iterator, value)` advances `iterator`, sending `value` back into it. +*/ +let nextValue: ( + t<'yield, 'return, 'next>, + 'next, +) => promise> + +/** +`forEach(iterator, f)` consumes all yielded values in `iterator` and runs `f` +for each yielded value. + +The final return value is not passed to `f`. +*/ +let forEach: (t<'yield, 'return, 'next>, 'yield => unit) => promise + +/** +`ignore(iterator)` marks `iterator` as intentionally unused. +*/ +external ignore: t<'yield, 'return, 'next> => unit = "%ignore" diff --git a/packages/@rescript/runtime/Stdlib_AsyncIterator.res b/packages/@rescript/runtime/Stdlib_AsyncIterator.res index b62128c8214..1d2a4ea5d04 100644 --- a/packages/@rescript/runtime/Stdlib_AsyncIterator.res +++ b/packages/@rescript/runtime/Stdlib_AsyncIterator.res @@ -1,40 +1,49 @@ @notUndefined -type t<'a> +type t<'yield, 'return, 'next> -type value<'a> = { - done: bool, - value: option<'a>, -} +type rawResult<'yield, 'return> -let value = v => { - done: false, - value: Some(v), -} +type result<'yield, 'return> = Stdlib_Iterator.result<'yield, 'return> -let done = (~finalValue=?) => { - done: true, - value: finalValue, -} +let value: 'yield => result<'yield, 'return> = %raw(`value => ({done: false, value})`) +let done: unit => result<'yield, unit> = %raw(`() => ({done: true, value: undefined})`) +let doneWithValue: 'return => result<'yield, 'return> = %raw(`value => ({done: true, value})`) + +let normalizeResult: rawResult<'yield, 'return> => result< + 'yield, + 'return, +> = %raw(`result => result.done ? {done: true, value: result.value} : {done: false, value: result.value}`) + +@send +external nextRaw: t<'yield, 'return, 'next> => promise> = "next" -@send external next: t<'a> => promise> = "next" +let next = async iterator => normalizeResult(await iterator->nextRaw) + +@send +external nextValueRaw: (t<'yield, 'return, 'next>, 'next) => promise> = + "next" + +let nextValue = async (iterator, value) => normalizeResult(await iterator->nextValueRaw(value)) let forEach = async (iterator, f) => { let iteratorDone = ref(false) while !iteratorDone.contents { - let {done, value} = await iterator->next - f(value) - iteratorDone := done + switch await iterator->next { + | Yield({value}) => f(value) + | Return(_) => iteratorDone := true + } } } -let make: (unit => promise>) => t<'value> = %raw(`function makeAsyncIterator(next) { +let make: (unit => promise>) => t< + 'yield, + 'return, + unit, +> = %raw(`function makeAsyncIterator(next) { return { - next, - [Symbol.asyncIterator]() { - return this; - } + next } }`) -external ignore: t<'a> => unit = "%ignore" +external ignore: t<'yield, 'return, 'next> => unit = "%ignore" diff --git a/packages/@rescript/runtime/Stdlib_AsyncIterator.resi b/packages/@rescript/runtime/Stdlib_AsyncIterator.resi index 7befd027170..760e2b06519 100644 --- a/packages/@rescript/runtime/Stdlib_AsyncIterator.resi +++ b/packages/@rescript/runtime/Stdlib_AsyncIterator.resi @@ -1,197 +1,158 @@ /*** -Bindings to async iterators, a way to do async iteration in JavaScript. +A JavaScript async iterator protocol object. -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.*/ +This models the async iterator protocol: an object with a `next()` method that +returns a promise resolving to an iterator result. -/** -The type representing an async iterator. +See [`AsyncIterator`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/AsyncIterator) on MDN. */ -@notUndefined -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. +Type representing an async iterator protocol object. -## Examples - -- A simple example, creating an async iterator that returns 1, 2, 3: +- `'yield` is the type produced while iterating +- `'return` is the final completion value once iteration is done +- `'next` is the type that can be sent back into `next(value)` +*/ +@notUndefined +type t<'yield, 'return, 'next> -```rescript -let context = ref(0) +/** +Result returned by `AsyncIterator.next`. +*/ +type result<'yield, 'return> = Stdlib_Iterator.result<'yield, 'return> -let asyncIterator = AsyncIterator.make(async () => { - let currentValue = context.contents - // Increment current value - context := currentValue + 1 +type rawResult<'yield, 'return> - { - AsyncIterator.value: Some(currentValue), - done: currentValue >= 3, - } -}) - -// This will log 1, 2, 3 -let main = async () => - await asyncIterator->AsyncIterator.forEach(value => - switch value { - | Some(value) => Console.log(value) - | None => () - } - ) +/** +Low-level raw JavaScript async iterator result shape. -main()->ignore -``` +This is mainly intended for internal use and protocol-level interop. Prefer +`AsyncIterator.result`, `AsyncIterator.next`, and `AsyncIterator.nextValue` in +normal ReScript code. */ -let make: (unit => promise>) => t<'value> +let normalizeResult: rawResult<'yield, 'return> => result<'yield, 'return> /** -`value(value)` - -Shorthand for creating a value object with the provided value, and the `done` property set to false. +`value(value)` creates a yielded iterator result. ## Examples ```rescript -let context = ref(0) +let current = ref(0) -let asyncIterator = AsyncIterator.make(async () => { - let currentValue = context.contents - // Increment current value - context := currentValue + 1 +let asyncIterableIterator = AsyncIterator.make(async () => { + let value = current.contents + current := value + 1 - if currentValue >= 3 { + if value >= 3 { AsyncIterator.done() } else { - AsyncIterator.value(currentValue) + AsyncIterator.value(value) } }) ``` */ -let value: 'value => value<'value> +let value: 'yield => result<'yield, 'return> /** - `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> +`done()` creates a completed iterator result with `unit` as the final value. +*/ +let done: unit => result<'yield, unit> /** -`next(asyncIterator)` +`doneWithValue(value)` creates a completed iterator result with the provided final value. +*/ +let doneWithValue: 'return => result<'yield, 'return> -Returns the next value of the iterator, if any. +/** +`nextRaw(asyncIterator)` advances `asyncIterator` and returns a promise for the raw +JavaScript iterator result object. -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. +This is mainly intended for internal use and protocol-level interop. +*/ +let nextRaw: t<'yield, 'return, 'next> => promise> -## Examples +/** +`next(asyncIterator)` advances `asyncIterator` without sending a value back in. -- A simple example, getting the next value: +## Examples ```rescript -let asyncIterator: AsyncIterator.t<(string, string)> = %raw(` - (() => { - var map1 = new Map(); +let asyncIterator: AsyncIterator.t = %raw(`({ + current: 0, + next() { + if (this.current < 2) { + return Promise.resolve({done: false, value: this.current++}) + } + return Promise.resolve({done: true, value: undefined}) + } +})`) - map1.set('first', '1'); - map1.set('second', '2'); +let process = async () => { + switch await asyncIterator->AsyncIterator.next { + | Yield({value: 0}) => () + | _ => () + } +} - var iterator1 = map1[Symbol.iterator](); - return iterator1; - })() -`) +process()->ignore +``` +*/ +let next: t<'yield, 'return, 'next> => promise> -let processMyAsyncIterator = async () => { - // ReScript doesn't have `for ... of` loops, but it's easy to mimic using a while loop. - let break_ = ref(false) +/** +`nextValueRaw(asyncIterator, value)` advances `asyncIterator`, sends `value` back +into it, and returns a promise for the raw JavaScript iterator result object. - while !break_.contents { - // Await the next iterator value - let {value, done} = await asyncIterator->AsyncIterator.next +This is mainly intended for internal use and protocol-level interop. +*/ +let nextValueRaw: (t<'yield, 'return, 'next>, 'next) => promise> - // Exit the while loop if the iterator says it's done - break_ := done +/** +`nextValue(asyncIterator, value)` advances `asyncIterator`, sending `value` back into it. +*/ +let nextValue: (t<'yield, 'return, 'next>, 'next) => promise> - if done { - value->Option.isNone == true - } - } -} +/** +`forEach(asyncIterator, f)` consumes all yielded values in `asyncIterator` and runs `f` +for each yielded value. -processMyAsyncIterator()->ignore -``` +The final return value is not passed to `f`. */ -@send -external next: t<'a> => promise> = "next" +let forEach: (t<'yield, 'return, 'next>, 'yield => unit) => promise /** -`forEach(iterator, fn)` consumes all values in the async iterator and runs the callback `fn` for each value. +`make(nextFn)` creates an async iterator protocol object from a function returning +the next result. -See [iterator protocols](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols) on MDN. +The returned value is not automatically async iterable. ## Examples ```rescript -// Let's pretend we get an async iterator returning ints from somewhere. -let asyncIterator: AsyncIterator.t<(string, string)> = %raw(` - (() => { - var map1 = new Map(); +let current = ref(0) - map1.set('first', '1'); - map1.set('second', '2'); +let asyncIterator = AsyncIterator.make(async () => { + let value = current.contents + current := value + 1 - var iterator1 = map1[Symbol.iterator](); - return iterator1; - })() -`) + if value >= 3 { + AsyncIterator.done() + } else { + AsyncIterator.value(value) + } +}) let main = async () => - await asyncIterator->AsyncIterator.forEach(v => { - switch v { - | Some(("second", value)) => value == "2" - | _ => () - } - }) + await asyncIterator->AsyncIterator.forEach(value => Console.log(value)) main()->ignore ``` */ -let forEach: (t<'a>, option<'a> => unit) => promise +let make: (unit => promise>) => t<'yield, 'return, unit> /** - `ignore(iterator)` ignores the provided async iterator and returns unit. - - This helper is useful when you want to discard a value (for example, the result of an operation with side effects) - without having to store or process it further. - +`ignore(asyncIterator)` marks `asyncIterator` as intentionally unused. */ -external ignore: t<'a> => unit = "%ignore" +external ignore: t<'yield, 'return, 'next> => unit = "%ignore" diff --git a/packages/@rescript/runtime/Stdlib_Dict.res b/packages/@rescript/runtime/Stdlib_Dict.res index 7a146b30eca..82e99788740 100644 --- a/packages/@rescript/runtime/Stdlib_Dict.res +++ b/packages/@rescript/runtime/Stdlib_Dict.res @@ -12,7 +12,8 @@ let delete = (dict, string) => { @obj external make: unit => dict<'a> = "" @val external fromArray: array<(string, 'a)> => dict<'a> = "Object.fromEntries" -@val external fromIterator: Stdlib_Iterator.t<(string, 'a)> => dict<'a> = "Object.fromEntries" +@val +external fromIterable: Stdlib_Iterable.t<(string, 'a)> => dict<'a> = "Object.fromEntries" @val external toArray: dict<'a> => array<(string, 'a)> = "Object.entries" diff --git a/packages/@rescript/runtime/Stdlib_Dict.resi b/packages/@rescript/runtime/Stdlib_Dict.resi index e9636381960..198f547275c 100644 --- a/packages/@rescript/runtime/Stdlib_Dict.resi +++ b/packages/@rescript/runtime/Stdlib_Dict.resi @@ -122,27 +122,19 @@ let dict = Dict.fromArray([("key1", "value1"), ("key2", "value2")]) external fromArray: array<(string, 'a)> => dict<'a> = "Object.fromEntries" /** -`fromIterator(entries)` creates a new dictionary from the provided iterator of key/value pairs. +`fromIterable(entries)` creates a new dictionary from the provided iterable of key/value pairs. ## Examples ```rescript -let iterator: Iterator.t<(string, int)> = %raw(` - (() => { - var map1 = new Map(); - map1.set('first', 1); - map1.set('second', 2); - var iterator1 = map1[Symbol.iterator](); - return iterator1; - })() -`) -iterator -->Dict.fromIterator +let iterable: Iterable.t<(string, int)> = [("first", 1), ("second", 2)]->Array.asIterable +iterable +->Dict.fromIterable ->Dict.valuesToArray == [1, 2] ``` */ @val -external fromIterator: Stdlib_Iterator.t<(string, 'a)> => dict<'a> = "Object.fromEntries" +external fromIterable: Stdlib_Iterable.t<(string, 'a)> => dict<'a> = "Object.fromEntries" /** `toArray(dictionary)` returns an array of all the key/value pairs of the dictionary. diff --git a/packages/@rescript/runtime/Stdlib_Generator.res b/packages/@rescript/runtime/Stdlib_Generator.res new file mode 100644 index 00000000000..a58e745e74e --- /dev/null +++ b/packages/@rescript/runtime/Stdlib_Generator.res @@ -0,0 +1,32 @@ +type t<'yield, 'return, 'next> = Stdlib_Iterable.t<'yield> + +external asIterator: t<'yield, 'return, 'next> => Stdlib_Iterator.t<'yield, 'return, 'next> = + "%identity" +external asIterable: t<'yield, 'return, 'next> => Stdlib_Iterable.t<'yield> = "%identity" +external asIteratorObject: t<'yield, 'return, 'next> => Stdlib_IteratorObject.t< + 'yield, + 'return, + 'next, +> = "%identity" + +let next = generator => generator->asIterator->Stdlib_Iterator.next + +let nextValue = (generator, value) => generator->asIterator->Stdlib_Iterator.nextValue(value) + +@send +external returnValueRaw: ( + t<'yield, 'return, 'next>, + 'return, +) => Stdlib_Iterator.rawResult<'yield, 'return> = "return" + +let returnValue = (generator, value) => + generator->returnValueRaw(value)->Stdlib_Iterator.normalizeResult + +@send +external throwErrorRaw: ( + t<'yield, 'return, 'next>, + exn, +) => Stdlib_Iterator.rawResult<'yield, 'return> = "throw" + +let throwError = (generator, error) => + generator->throwErrorRaw(error)->Stdlib_Iterator.normalizeResult diff --git a/packages/@rescript/runtime/Stdlib_Generator.resi b/packages/@rescript/runtime/Stdlib_Generator.resi new file mode 100644 index 00000000000..54a1d93089f --- /dev/null +++ b/packages/@rescript/runtime/Stdlib_Generator.resi @@ -0,0 +1,53 @@ +/*** +A JavaScript generator object. + +Generators are built-in iterable iterators with additional `return()` and +`throw()` capabilities. + +See [`Generator`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Generator) on MDN. +*/ + +/** +Type representing a generator object. +*/ +type t<'yield, 'return, 'next> = private Stdlib_Iterable.t<'yield> + +/** +`asIterator(generator)` views `generator` as an `Iterator.t`. +*/ +external asIterator: t<'yield, 'return, 'next> => Stdlib_Iterator.t<'yield, 'return, 'next> = + "%identity" + +/** +`asIterable(generator)` views `generator` as an `Iterable.t`. +*/ +external asIterable: t<'yield, 'return, 'next> => Stdlib_Iterable.t<'yield> = "%identity" + +/** +`asIteratorObject(generator)` views `generator` as an `IteratorObject.t`. +*/ +external asIteratorObject: t<'yield, 'return, 'next> => Stdlib_IteratorObject.t< + 'yield, + 'return, + 'next, +> = "%identity" + +/** +`next(generator)` advances `generator` without sending a value back in. +*/ +let next: t<'yield, 'return, 'next> => Stdlib_Iterator.result<'yield, 'return> + +/** +`nextValue(generator, value)` advances `generator`, sending `value` back into it. +*/ +let nextValue: (t<'yield, 'return, 'next>, 'next) => Stdlib_Iterator.result<'yield, 'return> + +/** +`returnValue(generator, value)` completes `generator` with the final return `value`. +*/ +let returnValue: (t<'yield, 'return, 'next>, 'return) => Stdlib_Iterator.result<'yield, 'return> + +/** +`throwError(generator, error)` throws `error` into `generator`. +*/ +let throwError: (t<'yield, 'return, 'next>, exn) => Stdlib_Iterator.result<'yield, 'return> diff --git a/packages/@rescript/runtime/Stdlib_Iterable.res b/packages/@rescript/runtime/Stdlib_Iterable.res new file mode 100644 index 00000000000..6a76298b174 --- /dev/null +++ b/packages/@rescript/runtime/Stdlib_Iterable.res @@ -0,0 +1,3 @@ +type t<'a> = iterable<'a> + +external ignore: t<'a> => unit = "%ignore" diff --git a/packages/@rescript/runtime/Stdlib_Iterable.resi b/packages/@rescript/runtime/Stdlib_Iterable.resi new file mode 100644 index 00000000000..839b122bd51 --- /dev/null +++ b/packages/@rescript/runtime/Stdlib_Iterable.resi @@ -0,0 +1,18 @@ +/*** +A JavaScript iterable. + +Values of this type implement the iterable protocol and can be consumed by +`for...of`, `Array.from`, and other JavaScript APIs that expect iterables. + +See [Iteration protocols](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols) on MDN. +*/ + +/** +Type representing an iterable that yields values of type `'a`. +*/ +type t<'a> = iterable<'a> + +/** +`ignore(iterable)` marks `iterable` as intentionally unused. +*/ +external ignore: t<'a> => unit = "%ignore" diff --git a/packages/@rescript/runtime/Stdlib_IterableIterator.res b/packages/@rescript/runtime/Stdlib_IterableIterator.res new file mode 100644 index 00000000000..fc6939510e9 --- /dev/null +++ b/packages/@rescript/runtime/Stdlib_IterableIterator.res @@ -0,0 +1,28 @@ +type t<'yield, 'return, 'next> = Stdlib_Iterable.t<'yield> + +let make: (unit => Stdlib_Iterator.result<'yield, 'return>) => t< + 'yield, + 'return, + unit, +> = %raw(`function makeIterableIterator(next) { + return { + next, + [Symbol.iterator]() { + return this; + } + } +}`) + +external asIterator: t<'yield, 'return, 'next> => Stdlib_Iterator.t<'yield, 'return, 'next> = + "%identity" +external asIterable: t<'yield, 'return, 'next> => Stdlib_Iterable.t<'yield> = "%identity" + +let next = iterator => iterator->asIterator->Stdlib_Iterator.next + +let nextValue = (iterator, value) => iterator->asIterator->Stdlib_Iterator.nextValue(value) + +@val +external toArrayWithMapper: (t<'yield, 'return, 'next>, 'yield => 'mapped) => array<'mapped> = + "Array.from" + +external ignore: t<'yield, 'return, 'next> => unit = "%ignore" diff --git a/packages/@rescript/runtime/Stdlib_IterableIterator.resi b/packages/@rescript/runtime/Stdlib_IterableIterator.resi new file mode 100644 index 00000000000..d45566b0df0 --- /dev/null +++ b/packages/@rescript/runtime/Stdlib_IterableIterator.resi @@ -0,0 +1,77 @@ +/*** +A JavaScript iterable iterator. + +This models values that satisfy both the iterable and iterator protocols +without assuming iterator helper methods are available. + +Unlike `IteratorObject.t`, this is only the iterable iterator protocol shape. It +does not imply that iterator helper methods such as `map`, `filter`, or +`toArray` are available. + +See [Iteration protocols](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols) on MDN. +*/ + +/** +Type representing an iterable iterator. +*/ +type t<'yield, 'return, 'next> = private Stdlib_Iterable.t<'yield> + +/** +`make(nextFn)` creates an iterable iterator from a function returning the next result. + +The returned value is both an iterator and an iterable. + +## Examples + +```rescript +let current = ref(0) + +let iterableIterator = IterableIterator.make(() => { + let value = current.contents + current := value + 1 + + if value >= 2 { + Iterator.doneWithValue("done") + } else { + Iterator.value(value) + } +}) + +iterableIterator->IterableIterator.next == Yield({value: 0}) +``` +*/ +let make: (unit => Stdlib_Iterator.result<'yield, 'return>) => t<'yield, 'return, unit> + +/** +`asIterator(value)` views an iterable iterator as an `Iterator.t`. +*/ +external asIterator: t<'yield, 'return, 'next> => Stdlib_Iterator.t<'yield, 'return, 'next> = + "%identity" + +/** +`asIterable(value)` views an iterable iterator as an `Iterable.t`. +*/ +external asIterable: t<'yield, 'return, 'next> => Stdlib_Iterable.t<'yield> = "%identity" + +/** +`next(iterator)` advances `iterator` without sending a value back in. +*/ +let next: t<'yield, 'return, 'next> => Stdlib_Iterator.result<'yield, 'return> + +/** +`nextValue(iterator, value)` advances `iterator`, sending `value` back into it. +*/ +let nextValue: (t<'yield, 'return, 'next>, 'next) => Stdlib_Iterator.result<'yield, 'return> + +/** +`toArrayWithMapper(iterator, mapper)` consumes `iterator`, applies `mapper` to each yielded +value, and returns the mapped values as an array. +*/ +@val +external toArrayWithMapper: (t<'yield, 'return, 'next>, 'yield => 'mapped) => array<'mapped> = + "Array.from" + +/** +`ignore(iterator)` marks `iterator` as intentionally unused. +*/ +external ignore: t<'yield, 'return, 'next> => unit = "%ignore" diff --git a/packages/@rescript/runtime/Stdlib_Iterator.res b/packages/@rescript/runtime/Stdlib_Iterator.res index 1ef310d3555..b160f94f4b7 100644 --- a/packages/@rescript/runtime/Stdlib_Iterator.res +++ b/packages/@rescript/runtime/Stdlib_Iterator.res @@ -1,44 +1,40 @@ @notUndefined -type t<'a> +type t<'yield, 'return, 'next> -type value<'a> = { - done: bool, - value: option<'a>, -} +type rawResult<'yield, 'return> -@send external next: t<'a> => value<'a> = "next" -@send -external toArray: t<'a> => array<'a> = "toArray" -external toArrayWithMapper: (t<'a>, 'a => 'b) => array<'b> = "Array.from" - -@send -external forEach: (t<'a>, 'a => unit) => unit = "forEach" - -external ignore: t<'a> => unit = "%ignore" - -@send -external drop: (t<'a>, int) => t<'a> = "drop" +@tag("done") +type result<'yield, 'return> = + | @as(false) Yield({value: 'yield}) + | @as(true) Return({value: 'return}) -@send -external every: (t<'a>, 'a => bool) => bool = "every" +let normalizeResult: rawResult<'yield, 'return> => result< + 'yield, + 'return, +> = %raw(`result => result.done ? {done: true, value: result.value} : {done: false, value: result.value}`) -@send -external filter: (t<'a>, 'a => bool) => t<'a> = "filter" +let value: 'yield => result<'yield, 'return> = %raw(`value => ({done: false, value})`) +let done: unit => result<'yield, unit> = %raw(`() => ({done: true, value: undefined})`) +let doneWithValue: 'return => result<'yield, 'return> = %raw(`value => ({done: true, value})`) @send -external find: (t<'a>, 'a => bool) => option<'a> = "find" +external nextRaw: t<'yield, 'return, 'next> => rawResult<'yield, 'return> = "next" -@send -external flatMap: (t<'a>, 'a => t<'b>) => t<'b> = "flatMap" +let next = iterator => iterator->nextRaw->normalizeResult @send -external map: (t<'a>, 'a => 'b) => t<'b> = "map" +external nextValueRaw: (t<'yield, 'return, 'next>, 'next) => rawResult<'yield, 'return> = "next" -@send -external reduce: (t<'a>, ('acc, 'a) => 'acc, ~initialValue: 'acc=?) => 'acc = "reduce" +let nextValue = (iterator, value) => iterator->nextValueRaw(value)->normalizeResult -@send -external some: (t<'a>, 'a => bool) => bool = "some" +let make: (unit => result<'yield, 'return>) => t< + 'yield, + 'return, + unit, +> = %raw(`function makeIterator(next) { + return { + next + } +}`) -@send -external take: (t<'a>, int) => t<'a> = "take" +external ignore: t<'yield, 'return, 'next> => unit = "%ignore" diff --git a/packages/@rescript/runtime/Stdlib_Iterator.resi b/packages/@rescript/runtime/Stdlib_Iterator.resi index 35c9b851073..ad22ec0d708 100644 --- a/packages/@rescript/runtime/Stdlib_Iterator.resi +++ b/packages/@rescript/runtime/Stdlib_Iterator.resi @@ -1,327 +1,124 @@ /*** -Bindings to JavaScript iterators. +A JavaScript iterator protocol object. + +This is the minimal protocol shape: an object with a `next()` method that +produces yielded values until it eventually completes with a final return value. See [`Iterator`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Iterator) on MDN. */ /** -The type representing an iterator. +Type representing an iterator protocol object. + +- `'yield` is the type produced while iterating +- `'return` is the final completion value once iteration is done +- `'next` is the type that can be sent back into `next(value)` */ @notUndefined -type t<'a> +type t<'yield, 'return, 'next> /** -The current value of an iterator. +Result returned by `Iterator.next`. */ -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. +@tag("done") +type result<'yield, 'return> = + | @as(false) Yield({value: 'yield}) + | @as(true) Return({value: 'return}) -See [iterator protocols](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols) on MDN. - -## Examples - -```rescript -let iterator: Iterator.t = %raw(` - (() => { - var array1 = ['a']; - var iterator1 = array1[Symbol.iterator](); - return iterator1 - })() -`) -(iterator->Iterator.next).done == false -(iterator->Iterator.next).done == true -``` -*/ -@send -external next: t<'a> => value<'a> = "next" +type rawResult<'yield, 'return> /** -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. +Low-level raw JavaScript iterator result shape. -See [Iterator.prototype.toArray](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Iterator/toArray) 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 - -mapKeysAsArray == ["someKey", "someKey2"] -``` - -## Remark - -Since March 2025, this feature works across the latest devices and browser versions. -This feature might not work in older devices or browsers. +This is mainly intended for internal use and protocol-level interop. Prefer +`Iterator.result`, `Iterator.next`, and `Iterator.nextValue` in normal ReScript code. */ -@send -external toArray: t<'a> => array<'a> = "toArray" +let normalizeResult: rawResult<'yield, 'return> => result<'yield, 'return> /** -`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.prototype.toArray](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Iterator/toArray) 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) - -mapKeysAsArray == [7, 8] -``` +`value(value)` creates a yielded iterator result. */ -external toArrayWithMapper: (t<'a>, 'a => 'b) => array<'b> = "Array.from" +let value: 'yield => result<'yield, 'return> /** -`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 -let iterator: Iterator.t = ["a", "b", "c"]->Array.values -let acc = ref("") -iterator->Iterator.forEach(v => { - acc := acc.contents ++ v -}) - -acc.contents == "abc" -``` - -## Remark - -Since March 2025, this feature works across the latest devices and browser versions. -This feature might not work in older devices or browsers. +`done()` creates a completed iterator result with `unit` as the final value. */ -@send -external forEach: (t<'a>, 'a => unit) => unit = "forEach" +let done: unit => result<'yield, unit> /** - `ignore(iterator)` ignores the provided iterator and returns unit. - - This helper is useful when you want to discard a value (for example, the result of an operation with side effects) - without having to store or process it further. +`doneWithValue(value)` creates a completed iterator result with the provided final value. */ -external ignore: t<'a> => unit = "%ignore" +let doneWithValue: 'return => result<'yield, 'return> /** -`drop(iterator, n)` returns a new iterator helper object that skips the given number of elements at the start of this iterator. +`nextRaw(iterator)` advances `iterator` and returns the raw JavaScript iterator result object. -See [Iterator.prototype.drop](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Iterator/drop) on MDN. - -## Examples -```rescript -let fibonacci: Iterator.t = [1, 1, 2, 3, 5, 8, 13, 21]->Array.values - -let seq = fibonacci->Iterator.drop(2) -seq->Iterator.next == {done: false, value: Some(2)} -seq->Iterator.next == {done: false, value: Some(3)} -``` - -## Remark - -Since March 2025, this feature works across the latest devices and browser versions. -This feature might not work in older devices or browsers. +This is mainly intended for internal use and protocol-level interop. */ -@send -external drop: (t<'a>, int) => t<'a> = "drop" +let nextRaw: t<'yield, 'return, 'next> => rawResult<'yield, 'return> /** -`every(iterator, fn)` tests whether all elements in the iterator pass the test implemented by the provided function. - -See [Iterator.prototype.every](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Iterator/every) on MDN. +`next(iterator)` advances `iterator` without sending a value back in. ## Examples -```rescript -let fibonacci: Iterator.t = [1, 1, 2, 3, 5, 8, 13, 21]->Array.values -let areAllEven = fibonacci->Iterator.every(n => n % 2 == 0) -areAllEven == false +```rescript +let iterator: Iterator.t = %raw(`({ + current: 0, + next() { + if (this.current < 2) { + return {done: false, value: this.current++} + } + return {done: true, value: "done"} + } +})`) + +iterator->Iterator.next == Yield({value: 0}) ``` - -## Remark - -Since March 2025, this feature works across the latest devices and browser versions. -This feature might not work in older devices or browsers. */ -@send -external every: (t<'a>, 'a => bool) => bool = "every" +let next: t<'yield, 'return, 'next> => result<'yield, 'return> /** -`filter(iterator, fn)` returns a new iterator helper object that contains the elements of the original iterator that pass the test implemented by the provided function. - -See [Iterator.prototype.filter](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Iterator/filter) on MDN. - -## Examples -```rescript -let fibonacci: Iterator.t = [1, 1, 2, 3, 5, 8, 13, 21]->Array.values - -let seq = fibonacci->Iterator.filter(n => n % 2 == 0) -seq->Iterator.next == {done: false, value: Some(2)} -seq->Iterator.next == {done: false, value: Some(8)} -``` - -## Remark +`nextValueRaw(iterator, value)` advances `iterator`, sending `value` back into it, +and returns the raw JavaScript iterator result object. -Since March 2025, this feature works across the latest devices and browser versions. -This feature might not work in older devices or browsers. +This is mainly intended for internal use and protocol-level interop. */ -@send -external filter: (t<'a>, 'a => bool) => t<'a> = "filter" +let nextValueRaw: (t<'yield, 'return, 'next>, 'next) => rawResult<'yield, 'return> /** -`find(iterator, fn)` returns the value of the first element in the iterator that satisfies the provided testing function. - -See [Iterator.prototype.find](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Iterator/find) on MDN. - -## Examples -```rescript -let fibonacci: Iterator.t = [1, 1, 2, 3, 5, 8, 13, 21]->Array.values - -let seq = fibonacci->Iterator.find(n => n % 2 == 0) -seq == Some(2) -``` - -## Remark - -Since March 2025, this feature works across the latest devices and browser versions. -This feature might not work in older devices or browsers. +`nextValue(iterator, value)` advances `iterator`, sending `value` back into it. */ -@send -external find: (t<'a>, 'a => bool) => option<'a> = "find" +let nextValue: (t<'yield, 'return, 'next>, 'next) => result<'yield, 'return> /** -`flatMap(iterator, fn)` returns a new iterator helper object that contains the elements of the original iterator that pass the test implemented by the provided function. +`make(nextFn)` creates a bare iterator protocol object from a function returning +the next result. -See [Iterator.prototype.flatMap](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Iterator/flatMap) on MDN. +The returned value is not automatically iterable. ## Examples -```rescript -let map1 = Map.fromArray([("a", 1), ("b", 2), ("c", 3)]) -let map2 = Map.fromArray([("d", 4), ("e", 5), ("f", 6)]) -let letters = - [map1, map2] - ->Array.values - ->Iterator.flatMap(m => Map.keys(m)) - ->Array.fromIterator -letters == ["a", "b", "c", "d", "e", "f"] -``` - -## Remark - -Since March 2025, this feature works across the latest devices and browser versions. -This feature might not work in older devices or browsers. - */ -@send -external flatMap: (t<'a>, 'a => t<'b>) => t<'b> = "flatMap" - -/** -`map(iterator, fn)` returns a new iterator helper object that yields elements of the iterator, each transformed by a mapping function. - -See [Iterator.prototype.map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Iterator/map) on MDN. - -## Examples ```rescript -let map = Map.fromArray([("a", 1), ("b", 2), ("c", 3)]) -let letters = map->Map.keys->Iterator.map(v => v->String.toUpperCase)->Array.fromIterator -letters == ["A", "B", "C"] -``` - -## Remark - -Since March 2025, this feature works across the latest devices and browser versions. -This feature might not work in older devices or browsers. -*/ -@send -external map: (t<'a>, 'a => 'b) => t<'b> = "map" +let current = ref(0) -/** -`reduce(iterator, fn, initialValue)` applies a function against an accumulator and each element in the iterator (from left to right) to reduce it to a single value. - -See [Iterator.prototype.reduce](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Iterator/reduce) on MDN. +let iterator = Iterator.make(() => { + let value = current.contents + current := value + 1 -## Examples -```rescript -let numbers: Iterator.t = [1, 2, 3]->Array.values + if value >= 2 { + Iterator.doneWithValue("done") + } else { + Iterator.value(value) + } +}) -let sum = numbers->Iterator.reduce((acc, n) => acc + n, ~initialValue=0) -sum == 6 +iterator->Iterator.next == Yield({value: 0}) ``` - -## Remark - -Since March 2025, this feature works across the latest devices and browser versions. -This feature might not work in older devices or browsers. */ -@send -external reduce: (t<'a>, ('acc, 'a) => 'acc, ~initialValue: 'acc=?) => 'acc = "reduce" +let make: (unit => result<'yield, 'return>) => t<'yield, 'return, unit> /** -`some(iterator, fn)` The some() method of Iterator instances is similar to Array.some: -it tests whether at least one element produced by the iterator passes the test implemented by the provided function. -It returns a boolean value. - -See [Iterator.prototype.some](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Iterator/some) on MDN. - -## Examples -```rescript -let numbers: Iterator.t = [1, 2, 3]->Array.values - -let hasEven = numbers->Iterator.some(n => n % 2 == 0) -hasEven == true -``` - -## Remark - -Since March 2025, this feature works across the latest devices and browser versions. -This feature might not work in older devices or browsers. - */ -@send -external some: (t<'a>, 'a => bool) => bool = "some" - -/** -`take((iterator, n))` returns a new iterator helper object that contains the first `n` elements of this iterator. - -See [Iterator.prototype.take](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Iterator/take) on MDN. - -## Examples -```rescript -let fibonacci: Iterator.t = [1, 1, 2, 3, 5, 8, 13, 21]->Array.values - -let seq = fibonacci->Iterator.take(2) -seq->Iterator.next == {done: false, value: Some(1)} -seq->Iterator.next == {done: false, value: Some(1)} -seq->Iterator.next == {done: true, value: None} -``` - -## Remark - -Since March 2025, this feature works across the latest devices and browser versions. -This feature might not work in older devices or browsers. +`ignore(iterator)` marks `iterator` as intentionally unused. */ -@send -external take: (t<'a>, int) => t<'a> = "take" +external ignore: t<'yield, 'return, 'next> => unit = "%ignore" diff --git a/packages/@rescript/runtime/Stdlib_IteratorObject.res b/packages/@rescript/runtime/Stdlib_IteratorObject.res new file mode 100644 index 00000000000..b474d21a76c --- /dev/null +++ b/packages/@rescript/runtime/Stdlib_IteratorObject.res @@ -0,0 +1,58 @@ +type t<'yield, 'return, 'next> = Stdlib_Iterable.t<'yield> + +type result<'yield, 'return> = Stdlib_Iterator.result<'yield, 'return> + +external asIterator: t<'yield, 'return, 'next> => Stdlib_Iterator.t<'yield, 'return, 'next> = + "%identity" +external asIterable: t<'yield, 'return, 'next> => Stdlib_Iterable.t<'yield> = "%identity" + +let next = iteratorObject => iteratorObject->asIterator->Stdlib_Iterator.next + +let nextValue = (iteratorObject, value) => + iteratorObject->asIterator->Stdlib_Iterator.nextValue(value) + +@send +external toArray: t<'yield, 'return, 'next> => array<'yield> = "toArray" + +@val +external toArrayWithMapper: (t<'yield, 'return, 'next>, 'yield => 'mapped) => array<'mapped> = + "Array.from" + +@send +external forEach: (t<'yield, 'return, 'next>, 'yield => unit) => unit = "forEach" + +external ignore: t<'yield, 'return, 'next> => unit = "%ignore" + +@send +external drop: (t<'yield, 'return, 'next>, int) => t<'yield, unit, unknown> = "drop" + +@send +external every: (t<'yield, 'return, 'next>, 'yield => bool) => bool = "every" + +@send +external filter: (t<'yield, 'return, 'next>, 'yield => bool) => t<'yield, unit, unknown> = "filter" + +@send +external find: (t<'yield, 'return, 'next>, 'yield => bool) => option<'yield> = "find" + +@send +external flatMap: ( + t<'yield, 'return, 'next>, + 'yield => Stdlib_Iterable.t<'mapped>, +) => t<'mapped, unit, unknown> = "flatMap" + +@send +external map: (t<'yield, 'return, 'next>, 'yield => 'mapped) => t<'mapped, unit, unknown> = "map" + +@send +external reduce: ( + t<'yield, 'return, 'next>, + ('acc, 'yield) => 'acc, + ~initialValue: 'acc=?, +) => 'acc = "reduce" + +@send +external some: (t<'yield, 'return, 'next>, 'yield => bool) => bool = "some" + +@send +external take: (t<'yield, 'return, 'next>, int) => t<'yield, unit, unknown> = "take" diff --git a/packages/@rescript/runtime/Stdlib_IteratorObject.resi b/packages/@rescript/runtime/Stdlib_IteratorObject.resi new file mode 100644 index 00000000000..3764a4161c6 --- /dev/null +++ b/packages/@rescript/runtime/Stdlib_IteratorObject.resi @@ -0,0 +1,137 @@ +/*** +A JavaScript iterator object that inherits from `Iterator.prototype`. + +This models a helper-enabled iterator object that conforms to the iterator +protocol and also inherits from `Iterator.prototype`, providing the standard +iterator helper methods. This is stricter than `IterableIterator.t`, which only +models the structural protocol shape. + +See [`Iterator`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Iterator) on MDN. +*/ + +/** +Type representing an `IteratorObject` instance. +*/ +type t<'yield, 'return, 'next> = private Stdlib_Iterable.t<'yield> + +/** +Result returned by `IteratorObject.next`. +*/ +type result<'yield, 'return> = Stdlib_Iterator.result<'yield, 'return> + +/** +`asIterator(iteratorObject)` views `iteratorObject` as a bare `Iterator.t`. +*/ +external asIterator: t<'yield, 'return, 'next> => Stdlib_Iterator.t<'yield, 'return, 'next> = + "%identity" + +/** +`asIterable(iteratorObject)` views `iteratorObject` as an `Iterable.t`. +*/ +external asIterable: t<'yield, 'return, 'next> => Stdlib_Iterable.t<'yield> = "%identity" + +/** +`next(iteratorObject)` advances `iteratorObject` without sending a value back in. +*/ +let next: t<'yield, 'return, 'next> => Stdlib_Iterator.result<'yield, 'return> + +/** +`nextValue(iteratorObject, value)` advances `iteratorObject`, sending `value` back into it. +*/ +let nextValue: (t<'yield, 'return, 'next>, 'next) => Stdlib_Iterator.result<'yield, 'return> + +/** +`toArray(iteratorObject)` consumes `iteratorObject` and returns its yielded values as an array. +*/ +@send +external toArray: t<'yield, 'return, 'next> => array<'yield> = "toArray" + +/** +`toArrayWithMapper(iteratorObject, mapper)` consumes `iteratorObject`, applies `mapper` +to each yielded value, and returns the mapped values as an array. +*/ +@val +external toArrayWithMapper: (t<'yield, 'return, 'next>, 'yield => 'mapped) => array<'mapped> = + "Array.from" + +/** +`forEach(iteratorObject, f)` consumes `iteratorObject` and runs `f` for each yielded value. +*/ +@send +external forEach: (t<'yield, 'return, 'next>, 'yield => unit) => unit = "forEach" + +/** +`ignore(iteratorObject)` marks `iteratorObject` as intentionally unused. +*/ +external ignore: t<'yield, 'return, 'next> => unit = "%ignore" + +/** +`drop(iteratorObject, count)` returns a new iterator helper that skips the first `count` +yielded values. +*/ +@send +external drop: (t<'yield, 'return, 'next>, int) => t<'yield, unit, unknown> = "drop" + +/** +`every(iteratorObject, predicate)` returns `true` if `predicate` is true for every yielded value. +*/ +@send +external every: (t<'yield, 'return, 'next>, 'yield => bool) => bool = "every" + +/** +`filter(iteratorObject, predicate)` returns a new iterator helper containing only the +yielded values that satisfy `predicate`. +*/ +@send +external filter: (t<'yield, 'return, 'next>, 'yield => bool) => t<'yield, unit, unknown> = "filter" + +/** +`find(iteratorObject, predicate)` returns the first yielded value that satisfies +`predicate`, or `None` if nothing matches. +*/ +@send +external find: (t<'yield, 'return, 'next>, 'yield => bool) => option<'yield> = "find" + +/** +`flatMap(iteratorObject, f)` maps each yielded value to another iterable and flattens the result. +*/ +@send +external flatMap: ( + t<'yield, 'return, 'next>, + 'yield => Stdlib_Iterable.t<'mapped>, +) => t<'mapped, unit, unknown> = "flatMap" + +/** +`map(iteratorObject, f)` returns a new iterator helper whose yielded values are +produced by applying `f`. +*/ +@send +external map: (t<'yield, 'return, 'next>, 'yield => 'mapped) => t<'mapped, unit, unknown> = "map" + +/** +`reduce(iteratorObject, reducer, ~initialValue)` combines all yielded values using +`reducer`. + +If `~initialValue` is omitted, the first yielded value becomes the initial accumulator, +so the accumulator type must match the yielded value type. +*/ +@send +external reduce: ( + t<'yield, 'return, 'next>, + ('acc, 'yield) => 'acc, + ~initialValue: 'acc=?, +) => 'acc = "reduce" + +/** +`some(iteratorObject, predicate)` returns `true` if at least one yielded value +satisfies `predicate`. +*/ +@send +external some: (t<'yield, 'return, 'next>, 'yield => bool) => bool = "some" + +/** +`take(iteratorObject, count)` returns a new iterator helper that yields at most `count` +values. +*/ +@send +external take: (t<'yield, 'return, 'next>, int) => t<'yield, unit, unknown> = "take" diff --git a/packages/@rescript/runtime/Stdlib_Map.res b/packages/@rescript/runtime/Stdlib_Map.res index 2c821c00212..706132cc007 100644 --- a/packages/@rescript/runtime/Stdlib_Map.res +++ b/packages/@rescript/runtime/Stdlib_Map.res @@ -1,9 +1,12 @@ @notUndefined type t<'k, 'v> +external asIterable: t<'k, 'v> => Stdlib_Iterable.t<('k, 'v)> = "%identity" + @new external make: unit => t<'k, 'v> = "Map" @new external fromArray: array<('k, 'v)> => t<'k, 'v> = "Map" -@new external fromIterator: Stdlib_Iterator.t<('k, 'v)> => t<'k, 'v> = "Map" +@new +external fromIterable: Stdlib_Iterable.t<('k, 'v)> => t<'k, 'v> = "Map" @get external size: t<'k, 'v> => int = "size" @@ -19,8 +22,9 @@ let isEmpty = map => map->size === 0 @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> => Stdlib_Iterator.t<'k> = "keys" -@send external values: t<'k, 'v> => Stdlib_Iterator.t<'v> = "values" -@send external entries: t<'k, 'v> => Stdlib_Iterator.t<('k, 'v)> = "entries" +@send external keys: t<'k, 'v> => Stdlib_IteratorObject.t<'k, unit, unknown> = "keys" +@send external values: t<'k, 'v> => Stdlib_IteratorObject.t<'v, unit, unknown> = "values" +@send +external entries: t<'k, 'v> => Stdlib_IteratorObject.t<('k, 'v), unit, unknown> = "entries" external ignore: t<'k, 'v> => unit = "%ignore" diff --git a/packages/@rescript/runtime/Stdlib_Map.resi b/packages/@rescript/runtime/Stdlib_Map.resi index 8068ab91093..f0930383dc4 100644 --- a/packages/@rescript/runtime/Stdlib_Map.resi +++ b/packages/@rescript/runtime/Stdlib_Map.resi @@ -10,6 +10,11 @@ Type representing an instance of `Map`. @notUndefined type t<'k, 'v> +/** +`asIterable(map)` views `map` as an `Iterable.t` of key/value pairs. +*/ +external asIterable: t<'k, 'v> => Stdlib_Iterable.t<('k, 'v)> = "%identity" + /** Creates a new, mutable JavaScript `Map`. A `Map` can have any values as both keys and values. @@ -54,31 +59,20 @@ switch map->Map.get(ReScript) { external fromArray: array<('k, 'v)> => t<'k, 'v> = "Map" /** -Turns an iterator in the shape of `('key, 'value)` into a `Map`. +Turns an iterable in the shape of `('key, 'value)` into a `Map`. ## Examples ```rescript -// Let's pretend we have an interator in the correct shape -let iterator: Iterator.t<(string, string)> = %raw(` - (() => { - var map1 = new Map(); - - map1.set('first', '1'); - map1.set('second', '2'); +let iterable: Iterable.t<(string, string)> = [("first", "1"), ("second", "2")]->Array.asIterable - var iterator1 = map1[Symbol.iterator](); - return iterator1; - })() -`) - -iterator -->Map.fromIterator +iterable +->Map.fromIterable ->Map.size == 2 ``` */ @new -external fromIterator: Stdlib_Iterator.t<('k, 'v)> => t<'k, 'v> = "Map" +external fromIterable: Stdlib_Iterable.t<('k, 'v)> => t<'k, 'v> = "Map" /** Returns the size, the number of key/value pairs, of the map. @@ -242,15 +236,17 @@ map->Map.set("anotherKey", "anotherValue") let keys = map->Map.keys // Logs the first key -Console.log(Iterator.next(keys).value) +switch keys->IteratorObject.next { +| Yield({value}) => Console.log(value) +| Return(_) => () +} -// 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) +// You can also turn the iterator into an array. Remember that iterators are consumed, so use a fresh one. +Console.log(map->Map.keys->IteratorObject.toArray) ``` */ @send -external keys: t<'k, 'v> => Stdlib_Iterator.t<'k> = "keys" +external keys: t<'k, 'v> => Stdlib_IteratorObject.t<'k, unit, unknown> = "keys" /** Returns an iterator that holds all values of the map. @@ -264,15 +260,17 @@ map->Map.set("anotherKey", "anotherValue") let values = map->Map.values // Logs the first value -Console.log(Iterator.next(values).value) +switch values->IteratorObject.next { +| Yield({value}) => Console.log(value) +| Return(_) => () +} -// 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) +// You can also turn the iterator into an array. Remember that iterators are consumed, so use a fresh one. +Console.log(map->Map.values->IteratorObject.toArray) ``` */ @send -external values: t<'k, 'v> => Stdlib_Iterator.t<'v> = "values" +external values: t<'k, 'v> => Stdlib_IteratorObject.t<'v, unit, unknown> = "values" /** Returns an iterator that holds all entries of the map. @@ -287,15 +285,17 @@ map->Map.set("anotherKey", "anotherValue") let entries = map->Map.entries // Logs the first value -Console.log(Iterator.next(entries).value) +switch entries->IteratorObject.next { +| Yield({value}) => Console.log(value) +| Return(_) => () +} -// 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) +// You can also turn the iterator into an array. Remember that iterators are consumed, so use a fresh one. +Console.log(map->Map.entries->IteratorObject.toArray) ``` */ @send -external entries: t<'k, 'v> => Stdlib_Iterator.t<('k, 'v)> = "entries" +external entries: t<'k, 'v> => Stdlib_IteratorObject.t<('k, 'v), unit, unknown> = "entries" /** `ignore(map)` ignores the provided map and returns unit. diff --git a/packages/@rescript/runtime/Stdlib_Set.res b/packages/@rescript/runtime/Stdlib_Set.res index 02a21ad1c9c..3a2beee3ef3 100644 --- a/packages/@rescript/runtime/Stdlib_Set.res +++ b/packages/@rescript/runtime/Stdlib_Set.res @@ -1,9 +1,11 @@ @notUndefined type t<'a> +external asIterable: t<'a> => Stdlib_Iterable.t<'a> = "%identity" + @new external make: unit => t<'a> = "Set" @new external fromArray: array<'a> => t<'a> = "Set" -@new external fromIterator: Stdlib_Iterator.t<'a> => t<'a> = "Set" +@new external fromIterable: Stdlib_Iterable.t<'a> => t<'a> = "Set" @get external size: t<'a> => int = "size" @@ -17,7 +19,7 @@ let isEmpty = set => set->size === 0 @send external forEach: (t<'a>, 'a => unit) => unit = "forEach" -@send external values: t<'a> => Stdlib_Iterator.t<'a> = "values" +@send external values: t<'a> => Stdlib_IteratorObject.t<'a, unit, unknown> = "values" @send external difference: (t<'a>, t<'a>) => t<'a> = "difference" @send external intersection: (t<'a>, t<'a>) => t<'a> = "intersection" diff --git a/packages/@rescript/runtime/Stdlib_Set.resi b/packages/@rescript/runtime/Stdlib_Set.resi index 5f9ca186682..497070c1240 100644 --- a/packages/@rescript/runtime/Stdlib_Set.resi +++ b/packages/@rescript/runtime/Stdlib_Set.resi @@ -10,6 +10,11 @@ Type representing an instance of `Set`. @notUndefined type t<'a> +/** +`asIterable(set)` views `set` as an `Iterable.t`. +*/ +external asIterable: t<'a> => Stdlib_Iterable.t<'a> = "%identity" + /** Creates a new, mutable JavaScript `Set`. A `Set` is a collection of unique values. @@ -53,27 +58,20 @@ switch set->Set.has(ReScript) { external fromArray: array<'a> => t<'a> = "Set" /** -Turns an iterator into a `Set`. +Turns an iterable into a `Set`. ## Examples ```rescript -// Let's pretend we have an interator -let iterator: Iterator.t = %raw(` - (() => { - var array1 = ['a', 'b', 'c']; - var iterator1 = array1[Symbol.iterator](); - return iterator1 - })() -`) - -iterator -->Set.fromIterator +let iterable: Iterable.t = ["a", "b", "c"]->Array.asIterable + +iterable +->Set.fromIterable ->Set.size == 3 ``` */ @new -external fromIterator: Stdlib_Iterator.t<'a> => t<'a> = "Set" +external fromIterable: Stdlib_Iterable.t<'a> => t<'a> = "Set" /** Returns the size, the number of unique values, of the set. @@ -217,15 +215,17 @@ set->Set.add("anotherValue") let values = set->Set.values // Logs the first value -Console.log(Iterator.next(values).value) +switch values->IteratorObject.next { +| Yield({value}) => Console.log(value) +| Return(_) => () +} -// 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) +// You can also turn the iterator into an array. Remember that iterators are consumed, so use a fresh one. +Console.log(set->Set.values->IteratorObject.toArray) ``` */ @send -external values: t<'a> => Stdlib_Iterator.t<'a> = "values" +external values: t<'a> => Stdlib_IteratorObject.t<'a, unit, unknown> = "values" /** Returns a new set with the values of the set that are not in the other set. diff --git a/packages/@rescript/runtime/Stdlib_String.res b/packages/@rescript/runtime/Stdlib_String.res index 2c52ac486f3..40c533509ce 100644 --- a/packages/@rescript/runtime/Stdlib_String.res +++ b/packages/@rescript/runtime/Stdlib_String.res @@ -201,4 +201,6 @@ let capitalize = s => external ignore: string => unit = "%ignore" +external asIterable: string => Stdlib_Iterable.t = "%identity" + @get_index external getSymbolUnsafe: (string, Stdlib_Symbol.t) => 'a = "" diff --git a/packages/@rescript/runtime/Stdlib_String.resi b/packages/@rescript/runtime/Stdlib_String.resi index 0c682aabb4b..275bdcd1646 100644 --- a/packages/@rescript/runtime/Stdlib_String.resi +++ b/packages/@rescript/runtime/Stdlib_String.resi @@ -1209,13 +1209,19 @@ external localeCompare: ( */ external ignore: string => unit = "%ignore" +/** +`asIterable(str)` views `str` as an `Iterable.t` where each yielded +value is one string element. +*/ +external asIterable: string => Stdlib_Iterable.t = "%identity" + /** `getSymbolUnsafe(str, symbol)` returns the value of the symbol property of a string. ## Examples ```rescript -let it: Iterator.t = ("foo"->String.getSymbolUnsafe(Symbol.iterator))() +let it: IteratorObject.t = ("foo"->String.getSymbolUnsafe(Symbol.iterator))() Nullable.make(it)->Nullable.isNullable == false ``` diff --git a/packages/@rescript/runtime/lib/es6/Stdlib.mjs b/packages/@rescript/runtime/lib/es6/Stdlib.mjs index 28ccab5bbc2..12c56413de9 100644 --- a/packages/@rescript/runtime/lib/es6/Stdlib.mjs +++ b/packages/@rescript/runtime/lib/es6/Stdlib.mjs @@ -12,7 +12,7 @@ function assertEqual(a, b) { RE_EXN_ID: "Assert_failure", _1: [ "Stdlib.res", - 153, + 160, 4 ], Error: new Error() @@ -83,10 +83,24 @@ let $$Symbol; let Type; +let Iterable; + let $$Iterator; +let IteratorObject; + +let IterableIterator; + +let $$Generator; + +let AsyncIterable; + let $$AsyncIterator; +let AsyncIterableIterator; + +let $$AsyncGenerator; + let $$Map; let $$WeakMap; @@ -156,8 +170,15 @@ export { $$String, $$Symbol, Type, + Iterable, $$Iterator, + IteratorObject, + IterableIterator, + $$Generator, + AsyncIterable, $$AsyncIterator, + AsyncIterableIterator, + $$AsyncGenerator, $$Map, $$WeakMap, $$Set, diff --git a/packages/@rescript/runtime/lib/es6/Stdlib_AsyncGenerator.mjs b/packages/@rescript/runtime/lib/es6/Stdlib_AsyncGenerator.mjs new file mode 100644 index 00000000000..87dd9d75ec8 --- /dev/null +++ b/packages/@rescript/runtime/lib/es6/Stdlib_AsyncGenerator.mjs @@ -0,0 +1,23 @@ + + +import * as Stdlib_AsyncIterator from "./Stdlib_AsyncIterator.mjs"; + +let next = Stdlib_AsyncIterator.next; + +let nextValue = Stdlib_AsyncIterator.nextValue; + +async function returnValue(generator, value) { + return Stdlib_AsyncIterator.normalizeResult(await generator.return(value)); +} + +async function throwError(generator, error) { + return Stdlib_AsyncIterator.normalizeResult(await generator.throw(error)); +} + +export { + next, + nextValue, + returnValue, + throwError, +} +/* No side effect */ diff --git a/packages/@rescript/runtime/lib/es6/Stdlib_AsyncIterable.mjs b/packages/@rescript/runtime/lib/es6/Stdlib_AsyncIterable.mjs new file mode 100644 index 00000000000..ae1b9f17e65 --- /dev/null +++ b/packages/@rescript/runtime/lib/es6/Stdlib_AsyncIterable.mjs @@ -0,0 +1 @@ +/* This output is empty. Its source's type definitions, externals and/or unused code got optimized away. */ diff --git a/packages/@rescript/runtime/lib/es6/Stdlib_AsyncIterableIterator.mjs b/packages/@rescript/runtime/lib/es6/Stdlib_AsyncIterableIterator.mjs new file mode 100644 index 00000000000..47875e8577f --- /dev/null +++ b/packages/@rescript/runtime/lib/es6/Stdlib_AsyncIterableIterator.mjs @@ -0,0 +1,36 @@ + + +import * as Stdlib_AsyncIterator from "./Stdlib_AsyncIterator.mjs"; + +let make = (function makeAsyncIterableIterator(next) { + return { + next, + [Symbol.asyncIterator]() { + return this; + } + } +}); + +let next = Stdlib_AsyncIterator.next; + +let nextValue = Stdlib_AsyncIterator.nextValue; + +async function forEach(iterator, f) { + let iteratorDone = false; + while (!iteratorDone) { + let match = await Stdlib_AsyncIterator.next(iterator); + if (match.done === false) { + f(match.value); + } else { + iteratorDone = true; + } + }; +} + +export { + make, + next, + nextValue, + forEach, +} +/* No side effect */ diff --git a/packages/@rescript/runtime/lib/es6/Stdlib_AsyncIterator.mjs b/packages/@rescript/runtime/lib/es6/Stdlib_AsyncIterator.mjs index 2f4535ab469..bb1345d9d3d 100644 --- a/packages/@rescript/runtime/lib/es6/Stdlib_AsyncIterator.mjs +++ b/packages/@rescript/runtime/lib/es6/Stdlib_AsyncIterator.mjs @@ -1,43 +1,58 @@ -import * as Primitive_option from "./Primitive_option.mjs"; -function value(v) { - return { - done: false, - value: Primitive_option.some(v) - }; +let value = (value => ({done: false, value})); + +let done = (() => ({done: true, value: undefined})); + +let doneWithValue = (value => ({done: true, value})); + +let normalizeResult = (result => result.done ? {done: true, value: result.value} : {done: false, value: result.value}); + +async function next(iterator) { + return normalizeResult(await iterator.next()); } -function done(finalValue) { - return { - done: true, - value: finalValue - }; +async function nextValue(iterator, value) { + return normalizeResult(await iterator.next(value)); } async function forEach(iterator, f) { let iteratorDone = false; while (!iteratorDone) { - let match = await iterator.next(); - f(match.value); - iteratorDone = match.done; + let match = await next(iterator); + if (match.done === false) { + f(match.value); + } else { + iteratorDone = true; + } }; } let make = (function makeAsyncIterator(next) { return { - next, - [Symbol.asyncIterator]() { - return this; - } + next } }); +function nextRaw(prim) { + return prim.next(); +} + +function nextValueRaw(prim0, prim1) { + return prim0.next(prim1); +} + export { - make, + normalizeResult, value, done, + doneWithValue, + nextRaw, + next, + nextValueRaw, + nextValue, forEach, + make, } /* No side effect */ diff --git a/packages/@rescript/runtime/lib/es6/Stdlib_Generator.mjs b/packages/@rescript/runtime/lib/es6/Stdlib_Generator.mjs new file mode 100644 index 00000000000..053bb05a610 --- /dev/null +++ b/packages/@rescript/runtime/lib/es6/Stdlib_Generator.mjs @@ -0,0 +1,23 @@ + + +import * as Stdlib_Iterator from "./Stdlib_Iterator.mjs"; + +let next = Stdlib_Iterator.next; + +let nextValue = Stdlib_Iterator.nextValue; + +function returnValue(generator, value) { + return Stdlib_Iterator.normalizeResult(generator.return(value)); +} + +function throwError(generator, error) { + return Stdlib_Iterator.normalizeResult(generator.throw(error)); +} + +export { + next, + nextValue, + returnValue, + throwError, +} +/* No side effect */ diff --git a/packages/@rescript/runtime/lib/es6/Stdlib_Iterable.mjs b/packages/@rescript/runtime/lib/es6/Stdlib_Iterable.mjs new file mode 100644 index 00000000000..ae1b9f17e65 --- /dev/null +++ b/packages/@rescript/runtime/lib/es6/Stdlib_Iterable.mjs @@ -0,0 +1 @@ +/* This output is empty. Its source's type definitions, externals and/or unused code got optimized away. */ diff --git a/packages/@rescript/runtime/lib/es6/Stdlib_IterableIterator.mjs b/packages/@rescript/runtime/lib/es6/Stdlib_IterableIterator.mjs new file mode 100644 index 00000000000..ee558c6f476 --- /dev/null +++ b/packages/@rescript/runtime/lib/es6/Stdlib_IterableIterator.mjs @@ -0,0 +1,23 @@ + + +import * as Stdlib_Iterator from "./Stdlib_Iterator.mjs"; + +let make = (function makeIterableIterator(next) { + return { + next, + [Symbol.iterator]() { + return this; + } + } +}); + +let next = Stdlib_Iterator.next; + +let nextValue = Stdlib_Iterator.nextValue; + +export { + make, + next, + nextValue, +} +/* No side effect */ diff --git a/packages/@rescript/runtime/lib/es6/Stdlib_Iterator.mjs b/packages/@rescript/runtime/lib/es6/Stdlib_Iterator.mjs index ae1b9f17e65..b4ce6d86f22 100644 --- a/packages/@rescript/runtime/lib/es6/Stdlib_Iterator.mjs +++ b/packages/@rescript/runtime/lib/es6/Stdlib_Iterator.mjs @@ -1 +1,45 @@ -/* This output is empty. Its source's type definitions, externals and/or unused code got optimized away. */ + + + +let normalizeResult = (result => result.done ? {done: true, value: result.value} : {done: false, value: result.value}); + +let value = (value => ({done: false, value})); + +let done = (() => ({done: true, value: undefined})); + +let doneWithValue = (value => ({done: true, value})); + +function next(iterator) { + return normalizeResult(iterator.next()); +} + +function nextValue(iterator, value) { + return normalizeResult(iterator.next(value)); +} + +let make = (function makeIterator(next) { + return { + next + } +}); + +function nextRaw(prim) { + return prim.next(); +} + +function nextValueRaw(prim0, prim1) { + return prim0.next(prim1); +} + +export { + normalizeResult, + value, + done, + doneWithValue, + nextRaw, + next, + nextValueRaw, + nextValue, + make, +} +/* No side effect */ diff --git a/packages/@rescript/runtime/lib/es6/Stdlib_IteratorObject.mjs b/packages/@rescript/runtime/lib/es6/Stdlib_IteratorObject.mjs new file mode 100644 index 00000000000..d44e6e1ef99 --- /dev/null +++ b/packages/@rescript/runtime/lib/es6/Stdlib_IteratorObject.mjs @@ -0,0 +1,13 @@ + + +import * as Stdlib_Iterator from "./Stdlib_Iterator.mjs"; + +let next = Stdlib_Iterator.next; + +let nextValue = Stdlib_Iterator.nextValue; + +export { + next, + nextValue, +} +/* No side effect */ diff --git a/packages/@rescript/runtime/lib/js/Stdlib.cjs b/packages/@rescript/runtime/lib/js/Stdlib.cjs index a36bc7bc7fc..9426a9ba890 100644 --- a/packages/@rescript/runtime/lib/js/Stdlib.cjs +++ b/packages/@rescript/runtime/lib/js/Stdlib.cjs @@ -12,7 +12,7 @@ function assertEqual(a, b) { RE_EXN_ID: "Assert_failure", _1: [ "Stdlib.res", - 153, + 160, 4 ], Error: new Error() @@ -83,10 +83,24 @@ let $$Symbol; let Type; +let Iterable; + let $$Iterator; +let IteratorObject; + +let IterableIterator; + +let $$Generator; + +let AsyncIterable; + let $$AsyncIterator; +let AsyncIterableIterator; + +let $$AsyncGenerator; + let $$Map; let $$WeakMap; @@ -155,8 +169,15 @@ exports.Result = Result; exports.$$String = $$String; exports.$$Symbol = $$Symbol; exports.Type = Type; +exports.Iterable = Iterable; exports.$$Iterator = $$Iterator; +exports.IteratorObject = IteratorObject; +exports.IterableIterator = IterableIterator; +exports.$$Generator = $$Generator; +exports.AsyncIterable = AsyncIterable; exports.$$AsyncIterator = $$AsyncIterator; +exports.AsyncIterableIterator = AsyncIterableIterator; +exports.$$AsyncGenerator = $$AsyncGenerator; exports.$$Map = $$Map; exports.$$WeakMap = $$WeakMap; exports.$$Set = $$Set; diff --git a/packages/@rescript/runtime/lib/js/Stdlib_AsyncGenerator.cjs b/packages/@rescript/runtime/lib/js/Stdlib_AsyncGenerator.cjs new file mode 100644 index 00000000000..15e3276726a --- /dev/null +++ b/packages/@rescript/runtime/lib/js/Stdlib_AsyncGenerator.cjs @@ -0,0 +1,21 @@ +'use strict'; + +let Stdlib_AsyncIterator = require("./Stdlib_AsyncIterator.cjs"); + +let next = Stdlib_AsyncIterator.next; + +let nextValue = Stdlib_AsyncIterator.nextValue; + +async function returnValue(generator, value) { + return Stdlib_AsyncIterator.normalizeResult(await generator.return(value)); +} + +async function throwError(generator, error) { + return Stdlib_AsyncIterator.normalizeResult(await generator.throw(error)); +} + +exports.next = next; +exports.nextValue = nextValue; +exports.returnValue = returnValue; +exports.throwError = throwError; +/* No side effect */ diff --git a/packages/@rescript/runtime/lib/js/Stdlib_AsyncIterable.cjs b/packages/@rescript/runtime/lib/js/Stdlib_AsyncIterable.cjs new file mode 100644 index 00000000000..ae1b9f17e65 --- /dev/null +++ b/packages/@rescript/runtime/lib/js/Stdlib_AsyncIterable.cjs @@ -0,0 +1 @@ +/* This output is empty. Its source's type definitions, externals and/or unused code got optimized away. */ diff --git a/packages/@rescript/runtime/lib/js/Stdlib_AsyncIterableIterator.cjs b/packages/@rescript/runtime/lib/js/Stdlib_AsyncIterableIterator.cjs new file mode 100644 index 00000000000..1e9b46738b2 --- /dev/null +++ b/packages/@rescript/runtime/lib/js/Stdlib_AsyncIterableIterator.cjs @@ -0,0 +1,34 @@ +'use strict'; + +let Stdlib_AsyncIterator = require("./Stdlib_AsyncIterator.cjs"); + +let make = (function makeAsyncIterableIterator(next) { + return { + next, + [Symbol.asyncIterator]() { + return this; + } + } +}); + +let next = Stdlib_AsyncIterator.next; + +let nextValue = Stdlib_AsyncIterator.nextValue; + +async function forEach(iterator, f) { + let iteratorDone = false; + while (!iteratorDone) { + let match = await Stdlib_AsyncIterator.next(iterator); + if (match.done === false) { + f(match.value); + } else { + iteratorDone = true; + } + }; +} + +exports.make = make; +exports.next = next; +exports.nextValue = nextValue; +exports.forEach = forEach; +/* No side effect */ diff --git a/packages/@rescript/runtime/lib/js/Stdlib_AsyncIterator.cjs b/packages/@rescript/runtime/lib/js/Stdlib_AsyncIterator.cjs index b82ebea6a29..78036c2f9d2 100644 --- a/packages/@rescript/runtime/lib/js/Stdlib_AsyncIterator.cjs +++ b/packages/@rescript/runtime/lib/js/Stdlib_AsyncIterator.cjs @@ -1,41 +1,56 @@ 'use strict'; -let Primitive_option = require("./Primitive_option.cjs"); -function value(v) { - return { - done: false, - value: Primitive_option.some(v) - }; +let value = (value => ({done: false, value})); + +let done = (() => ({done: true, value: undefined})); + +let doneWithValue = (value => ({done: true, value})); + +let normalizeResult = (result => result.done ? {done: true, value: result.value} : {done: false, value: result.value}); + +async function next(iterator) { + return normalizeResult(await iterator.next()); } -function done(finalValue) { - return { - done: true, - value: finalValue - }; +async function nextValue(iterator, value) { + return normalizeResult(await iterator.next(value)); } async function forEach(iterator, f) { let iteratorDone = false; while (!iteratorDone) { - let match = await iterator.next(); - f(match.value); - iteratorDone = match.done; + let match = await next(iterator); + if (match.done === false) { + f(match.value); + } else { + iteratorDone = true; + } }; } let make = (function makeAsyncIterator(next) { return { - next, - [Symbol.asyncIterator]() { - return this; - } + next } }); -exports.make = make; +function nextRaw(prim) { + return prim.next(); +} + +function nextValueRaw(prim0, prim1) { + return prim0.next(prim1); +} + +exports.normalizeResult = normalizeResult; exports.value = value; exports.done = done; +exports.doneWithValue = doneWithValue; +exports.nextRaw = nextRaw; +exports.next = next; +exports.nextValueRaw = nextValueRaw; +exports.nextValue = nextValue; exports.forEach = forEach; +exports.make = make; /* No side effect */ diff --git a/packages/@rescript/runtime/lib/js/Stdlib_Generator.cjs b/packages/@rescript/runtime/lib/js/Stdlib_Generator.cjs new file mode 100644 index 00000000000..2ff54603bac --- /dev/null +++ b/packages/@rescript/runtime/lib/js/Stdlib_Generator.cjs @@ -0,0 +1,21 @@ +'use strict'; + +let Stdlib_Iterator = require("./Stdlib_Iterator.cjs"); + +let next = Stdlib_Iterator.next; + +let nextValue = Stdlib_Iterator.nextValue; + +function returnValue(generator, value) { + return Stdlib_Iterator.normalizeResult(generator.return(value)); +} + +function throwError(generator, error) { + return Stdlib_Iterator.normalizeResult(generator.throw(error)); +} + +exports.next = next; +exports.nextValue = nextValue; +exports.returnValue = returnValue; +exports.throwError = throwError; +/* No side effect */ diff --git a/packages/@rescript/runtime/lib/js/Stdlib_Iterable.cjs b/packages/@rescript/runtime/lib/js/Stdlib_Iterable.cjs new file mode 100644 index 00000000000..ae1b9f17e65 --- /dev/null +++ b/packages/@rescript/runtime/lib/js/Stdlib_Iterable.cjs @@ -0,0 +1 @@ +/* This output is empty. Its source's type definitions, externals and/or unused code got optimized away. */ diff --git a/packages/@rescript/runtime/lib/js/Stdlib_IterableIterator.cjs b/packages/@rescript/runtime/lib/js/Stdlib_IterableIterator.cjs new file mode 100644 index 00000000000..98fbfeaf0a0 --- /dev/null +++ b/packages/@rescript/runtime/lib/js/Stdlib_IterableIterator.cjs @@ -0,0 +1,21 @@ +'use strict'; + +let Stdlib_Iterator = require("./Stdlib_Iterator.cjs"); + +let make = (function makeIterableIterator(next) { + return { + next, + [Symbol.iterator]() { + return this; + } + } +}); + +let next = Stdlib_Iterator.next; + +let nextValue = Stdlib_Iterator.nextValue; + +exports.make = make; +exports.next = next; +exports.nextValue = nextValue; +/* No side effect */ diff --git a/packages/@rescript/runtime/lib/js/Stdlib_Iterator.cjs b/packages/@rescript/runtime/lib/js/Stdlib_Iterator.cjs index ae1b9f17e65..49fdfdee3c6 100644 --- a/packages/@rescript/runtime/lib/js/Stdlib_Iterator.cjs +++ b/packages/@rescript/runtime/lib/js/Stdlib_Iterator.cjs @@ -1 +1,43 @@ -/* This output is empty. Its source's type definitions, externals and/or unused code got optimized away. */ +'use strict'; + + +let normalizeResult = (result => result.done ? {done: true, value: result.value} : {done: false, value: result.value}); + +let value = (value => ({done: false, value})); + +let done = (() => ({done: true, value: undefined})); + +let doneWithValue = (value => ({done: true, value})); + +function next(iterator) { + return normalizeResult(iterator.next()); +} + +function nextValue(iterator, value) { + return normalizeResult(iterator.next(value)); +} + +let make = (function makeIterator(next) { + return { + next + } +}); + +function nextRaw(prim) { + return prim.next(); +} + +function nextValueRaw(prim0, prim1) { + return prim0.next(prim1); +} + +exports.normalizeResult = normalizeResult; +exports.value = value; +exports.done = done; +exports.doneWithValue = doneWithValue; +exports.nextRaw = nextRaw; +exports.next = next; +exports.nextValueRaw = nextValueRaw; +exports.nextValue = nextValue; +exports.make = make; +/* No side effect */ diff --git a/packages/@rescript/runtime/lib/js/Stdlib_IteratorObject.cjs b/packages/@rescript/runtime/lib/js/Stdlib_IteratorObject.cjs new file mode 100644 index 00000000000..3f28ba18fb2 --- /dev/null +++ b/packages/@rescript/runtime/lib/js/Stdlib_IteratorObject.cjs @@ -0,0 +1,11 @@ +'use strict'; + +let Stdlib_Iterator = require("./Stdlib_Iterator.cjs"); + +let next = Stdlib_Iterator.next; + +let nextValue = Stdlib_Iterator.nextValue; + +exports.next = next; +exports.nextValue = nextValue; +/* No side effect */ diff --git a/packages/artifacts.json b/packages/artifacts.json index a024c5ebc4e..09009e3f972 100644 --- a/packages/artifacts.json +++ b/packages/artifacts.json @@ -133,6 +133,9 @@ "lib/es6/Stdlib.mjs", "lib/es6/Stdlib_Array.mjs", "lib/es6/Stdlib_ArrayBuffer.mjs", + "lib/es6/Stdlib_AsyncGenerator.mjs", + "lib/es6/Stdlib_AsyncIterable.mjs", + "lib/es6/Stdlib_AsyncIterableIterator.mjs", "lib/es6/Stdlib_AsyncIterator.mjs", "lib/es6/Stdlib_BigInt.mjs", "lib/es6/Stdlib_BigInt64Array.mjs", @@ -147,6 +150,7 @@ "lib/es6/Stdlib_Float.mjs", "lib/es6/Stdlib_Float32Array.mjs", "lib/es6/Stdlib_Float64Array.mjs", + "lib/es6/Stdlib_Generator.mjs", "lib/es6/Stdlib_Global.mjs", "lib/es6/Stdlib_Int.mjs", "lib/es6/Stdlib_Int16Array.mjs", @@ -164,7 +168,10 @@ "lib/es6/Stdlib_Intl_RelativeTimeFormat.mjs", "lib/es6/Stdlib_Intl_Segmenter.mjs", "lib/es6/Stdlib_Intl_Segments.mjs", + "lib/es6/Stdlib_Iterable.mjs", + "lib/es6/Stdlib_IterableIterator.mjs", "lib/es6/Stdlib_Iterator.mjs", + "lib/es6/Stdlib_IteratorObject.mjs", "lib/es6/Stdlib_JSON.mjs", "lib/es6/Stdlib_JsError.mjs", "lib/es6/Stdlib_JsExn.mjs", @@ -307,6 +314,9 @@ "lib/js/Stdlib.cjs", "lib/js/Stdlib_Array.cjs", "lib/js/Stdlib_ArrayBuffer.cjs", + "lib/js/Stdlib_AsyncGenerator.cjs", + "lib/js/Stdlib_AsyncIterable.cjs", + "lib/js/Stdlib_AsyncIterableIterator.cjs", "lib/js/Stdlib_AsyncIterator.cjs", "lib/js/Stdlib_BigInt.cjs", "lib/js/Stdlib_BigInt64Array.cjs", @@ -321,6 +331,7 @@ "lib/js/Stdlib_Float.cjs", "lib/js/Stdlib_Float32Array.cjs", "lib/js/Stdlib_Float64Array.cjs", + "lib/js/Stdlib_Generator.cjs", "lib/js/Stdlib_Global.cjs", "lib/js/Stdlib_Int.cjs", "lib/js/Stdlib_Int16Array.cjs", @@ -338,7 +349,10 @@ "lib/js/Stdlib_Intl_RelativeTimeFormat.cjs", "lib/js/Stdlib_Intl_Segmenter.cjs", "lib/js/Stdlib_Intl_Segments.cjs", + "lib/js/Stdlib_Iterable.cjs", + "lib/js/Stdlib_IterableIterator.cjs", "lib/js/Stdlib_Iterator.cjs", + "lib/js/Stdlib_IteratorObject.cjs", "lib/js/Stdlib_JSON.cjs", "lib/js/Stdlib_JsError.cjs", "lib/js/Stdlib_JsExn.cjs", @@ -942,6 +956,24 @@ "lib/ocaml/Stdlib_ArrayBuffer.cmti", "lib/ocaml/Stdlib_ArrayBuffer.res", "lib/ocaml/Stdlib_ArrayBuffer.resi", + "lib/ocaml/Stdlib_AsyncGenerator.cmi", + "lib/ocaml/Stdlib_AsyncGenerator.cmj", + "lib/ocaml/Stdlib_AsyncGenerator.cmt", + "lib/ocaml/Stdlib_AsyncGenerator.cmti", + "lib/ocaml/Stdlib_AsyncGenerator.res", + "lib/ocaml/Stdlib_AsyncGenerator.resi", + "lib/ocaml/Stdlib_AsyncIterable.cmi", + "lib/ocaml/Stdlib_AsyncIterable.cmj", + "lib/ocaml/Stdlib_AsyncIterable.cmt", + "lib/ocaml/Stdlib_AsyncIterable.cmti", + "lib/ocaml/Stdlib_AsyncIterable.res", + "lib/ocaml/Stdlib_AsyncIterable.resi", + "lib/ocaml/Stdlib_AsyncIterableIterator.cmi", + "lib/ocaml/Stdlib_AsyncIterableIterator.cmj", + "lib/ocaml/Stdlib_AsyncIterableIterator.cmt", + "lib/ocaml/Stdlib_AsyncIterableIterator.cmti", + "lib/ocaml/Stdlib_AsyncIterableIterator.res", + "lib/ocaml/Stdlib_AsyncIterableIterator.resi", "lib/ocaml/Stdlib_AsyncIterator.cmi", "lib/ocaml/Stdlib_AsyncIterator.cmj", "lib/ocaml/Stdlib_AsyncIterator.cmt", @@ -1018,6 +1050,12 @@ "lib/ocaml/Stdlib_Float64Array.cmj", "lib/ocaml/Stdlib_Float64Array.cmt", "lib/ocaml/Stdlib_Float64Array.res", + "lib/ocaml/Stdlib_Generator.cmi", + "lib/ocaml/Stdlib_Generator.cmj", + "lib/ocaml/Stdlib_Generator.cmt", + "lib/ocaml/Stdlib_Generator.cmti", + "lib/ocaml/Stdlib_Generator.res", + "lib/ocaml/Stdlib_Generator.resi", "lib/ocaml/Stdlib_Global.cmi", "lib/ocaml/Stdlib_Global.cmj", "lib/ocaml/Stdlib_Global.cmt", @@ -1090,12 +1128,30 @@ "lib/ocaml/Stdlib_Intl_Segments.cmj", "lib/ocaml/Stdlib_Intl_Segments.cmt", "lib/ocaml/Stdlib_Intl_Segments.res", + "lib/ocaml/Stdlib_Iterable.cmi", + "lib/ocaml/Stdlib_Iterable.cmj", + "lib/ocaml/Stdlib_Iterable.cmt", + "lib/ocaml/Stdlib_Iterable.cmti", + "lib/ocaml/Stdlib_Iterable.res", + "lib/ocaml/Stdlib_Iterable.resi", + "lib/ocaml/Stdlib_IterableIterator.cmi", + "lib/ocaml/Stdlib_IterableIterator.cmj", + "lib/ocaml/Stdlib_IterableIterator.cmt", + "lib/ocaml/Stdlib_IterableIterator.cmti", + "lib/ocaml/Stdlib_IterableIterator.res", + "lib/ocaml/Stdlib_IterableIterator.resi", "lib/ocaml/Stdlib_Iterator.cmi", "lib/ocaml/Stdlib_Iterator.cmj", "lib/ocaml/Stdlib_Iterator.cmt", "lib/ocaml/Stdlib_Iterator.cmti", "lib/ocaml/Stdlib_Iterator.res", "lib/ocaml/Stdlib_Iterator.resi", + "lib/ocaml/Stdlib_IteratorObject.cmi", + "lib/ocaml/Stdlib_IteratorObject.cmj", + "lib/ocaml/Stdlib_IteratorObject.cmt", + "lib/ocaml/Stdlib_IteratorObject.cmti", + "lib/ocaml/Stdlib_IteratorObject.res", + "lib/ocaml/Stdlib_IteratorObject.resi", "lib/ocaml/Stdlib_JSON.cmi", "lib/ocaml/Stdlib_JSON.cmj", "lib/ocaml/Stdlib_JSON.cmt", diff --git a/rewatch/testrepo/.yarn/patches/@rescript-webapi-npm-0.1.0-experimental-73e6a0d-288a2072f7.patch b/rewatch/testrepo/.yarn/patches/@rescript-webapi-npm-0.1.0-experimental-73e6a0d-288a2072f7.patch new file mode 100644 index 00000000000..d34bb5830b9 --- /dev/null +++ b/rewatch/testrepo/.yarn/patches/@rescript-webapi-npm-0.1.0-experimental-73e6a0d-288a2072f7.patch @@ -0,0 +1,28 @@ +diff --git a/src/URLAPI/URLSearchParams.res b/src/URLAPI/URLSearchParams.res +index 9f0f7132a0630782aa2f98bc7c86454ae07831a4..0ac1b61b93923355682ec189d0857d140cb6b918 100644 +--- a/src/URLAPI/URLSearchParams.res ++++ b/src/URLAPI/URLSearchParams.res +@@ -43,7 +43,7 @@ Returns key/value pairs in the same order as they appear in the query string. + [Read more on MDN](https://developer.mozilla.org/docs/Web/API/URLSearchParams/entries) + */ + @send +-external entries: urlSearchParams => Iterator.t<(string, string)> = "entries" ++external entries: urlSearchParams => IteratorObject.t<(string, string), unit, unknown> = "entries" + + /** + Returns the first value associated to the given search parameter. +@@ -71,7 +71,7 @@ Returns an iterator allowing iteration through all keys contained in this object + [Read more on MDN](https://developer.mozilla.org/docs/Web/API/URLSearchParams/keys) + */ + @send +-external keys: urlSearchParams => Iterator.t = "keys" ++external keys: urlSearchParams => IteratorObject.t = "keys" + + /** + Sets the value associated to a given search parameter to the given value. If there were several values, delete the others. +@@ -98,4 +98,4 @@ Returns an iterator allowing iteration through all values contained in this obje + [Read more on MDN](https://developer.mozilla.org/docs/Web/API/URLSearchParams/values) + */ + @send +-external values: urlSearchParams => Iterator.t = "values" ++external values: urlSearchParams => IteratorObject.t = "values" diff --git a/rewatch/testrepo/.yarn/patches/rescript-bun-npm-2.1.0-d9adc91a04.patch b/rewatch/testrepo/.yarn/patches/rescript-bun-npm-2.1.0-d9adc91a04.patch new file mode 100644 index 00000000000..d38b6b50913 --- /dev/null +++ b/rewatch/testrepo/.yarn/patches/rescript-bun-npm-2.1.0-d9adc91a04.patch @@ -0,0 +1,152 @@ +diff --git a/src/Bun.res b/src/Bun.res +index c5dbb6b991d19dd138aec65e4208ff4aec194e3c..2c313b1ff7c08f71aa64159ed430bd1872786f14 100644 +--- a/src/Bun.res ++++ b/src/Bun.res +@@ -3159,7 +3159,7 @@ module Glob = { + * ``` + */ + @send +- external scan: (t, ~options: globScanOptions=?) => AsyncIterator.t = "scan" ++ external scan: (t, ~options: globScanOptions=?) => AsyncIterator.t = "scan" + + /** + * Scan a root directory recursively for files that match this glob pattern. Returns an async iterator. +@@ -3181,7 +3181,7 @@ module Glob = { + * ``` + */ + @send +- external scanFromCwd: (t, string) => AsyncIterator.t = "scan" ++ external scanFromCwd: (t, string) => AsyncIterator.t = "scan" + + /** + * Synchronously scan a root directory recursively for files that match this glob pattern. Returns an iterator. +@@ -3203,7 +3203,8 @@ module Glob = { + * ``` + */ + @send +- external scanSync: (t, ~options: globScanOptions=?) => Iterator.t = "scanSync" ++ external scanSync: (t, ~options: globScanOptions=?) => IteratorObject.t = ++ "scanSync" + + /** + * Synchronously scan a root directory recursively for files that match this glob pattern. Returns an iterator. +@@ -3225,7 +3226,7 @@ module Glob = { + * ``` + */ + @send +- external scanFromCwdSync: (t, string) => Iterator.t = "scanSync" ++ external scanFromCwdSync: (t, string) => IteratorObject.t = "scanSync" + + /** + * Match the glob against a string +diff --git a/src/BunSqlite.res b/src/BunSqlite.res +index a4c414214153e64bb5d98a55da0af0e781fe7ce8..8efca631ae17f48ec10a1ef6f1962ba2ededc93c 100644 +--- a/src/BunSqlite.res ++++ b/src/BunSqlite.res +@@ -27,7 +27,7 @@ module Statement = { + + /** Runs a query and returns an iterator over the results as raw JSON. */ + @send +- external iterate: (t, {..}) => Iterator.t = "iterate" ++ external iterate: (t, {..}) => IteratorObject.t = "iterate" + + /** Destroys the statement, freeing up resources. */ + @send +diff --git a/src/CookieMap.res b/src/CookieMap.res +index a71a6648ed36cb57849fc77a050117da8d6e438f..a253551552458d668d8ace7013f9ee1678e79c23 100644 +--- a/src/CookieMap.res ++++ b/src/CookieMap.res +@@ -26,7 +26,7 @@ external fromString: string => t = "CookieMap" + @send external delete: (t, cookieStoreDeleteOptions) => unit = "delete" + @send external toJSON: t => dict = "toJSON" + @get external size: t => int = "size" +-@send external entries: t => Iterator.t<(string, string)> = "entries" +-@send external keys: t => Iterator.t = "entries" +-@send external values: t => Iterator.t = "entries" ++@send external entries: t => IteratorObject.t<(string, string), unit, unknown> = "entries" ++@send external keys: t => IteratorObject.t = "entries" ++@send external values: t => IteratorObject.t = "entries" + @send external forEach: (t, (string, string, t) => unit) => unit = "forEach" +diff --git a/src/Globals.res b/src/Globals.res +index 8a19eb175c173d06fc19686f3f7171210960a6b8..cb2b967407f318e0783101e7e57c79db7717d978 100644 +--- a/src/Globals.res ++++ b/src/Globals.res +@@ -145,9 +145,9 @@ module Headers = { + @return(nullable) @send external get: (t, string) => option = "get" + @send external has: (t, string) => bool = "has" + @send external set: (t, string, string) => unit = "set" +- @send external entries: t => Iterator.t<(string, string)> = "entries" +- @send external keys: t => Iterator.t = "keys" +- @send external values: t => Iterator.t = "values" ++ @send external entries: t => IteratorObject.t<(string, string), unit, unknown> = "entries" ++ @send external keys: t => IteratorObject.t = "keys" ++ @send external values: t => IteratorObject.t = "values" + @send external forEach: (t, (string, string, t) => unit) => unit = "forEach" + + /** +@@ -222,9 +222,10 @@ module FormData = { + @send external delete: (t, string) => unit = "delete" + @send external has: (t, string) => bool = "has" + @send external set: (t, string, stringOrBlob, ~fileName: string=?) => unit = "set" +- @send external keys: t => Iterator.t = "keys" +- @send external values: t => Iterator.t = "values" +- @send external entries: t => Iterator.t<(string, formDataEntryValue)> = "entries" ++ @send external keys: t => IteratorObject.t = "keys" ++ @send external values: t => IteratorObject.t = "values" ++ @send external entries: t => IteratorObject.t<(string, formDataEntryValue), unit, unknown> = ++ "entries" + @send external forEach: ((formDataEntryValue, string, t) => unit) => unit = "forEach" + } + +@@ -462,7 +463,9 @@ module ReadableStream = { + @send external tee: t<'t> => (t<'t>, t<'t>) = "tee" + + type valuesOptions = {preventCancel: bool} +- @send external values: (t<'t>, ~options: valuesOptions=?) => AsyncIterator.t<'t> = "values" ++ @send ++ external values: (t<'t>, ~options: valuesOptions=?) => AsyncIterator.t<'t, unit, unknown> = ++ "values" + + @new + external make: ( +@@ -689,15 +692,15 @@ module URLSearchParams = { + + /** Returns an iterator allowing to go through all entries of the key/value pairs. */ + @send +- external entries: t => Iterator.t<(string, string)> = "entries" ++ external entries: t => IteratorObject.t<(string, string), unit, unknown> = "entries" + + /** Returns an iterator allowing to go through all keys of the key/value pairs of this search parameter. */ + @send +- external keys: t => Iterator.t = "keys" ++ external keys: t => IteratorObject.t = "keys" + + /** Returns an iterator allowing to go through all values of the key/value pairs of this search parameter. */ + @send +- external values: t => Iterator.t = "values" ++ external values: t => IteratorObject.t = "values" + + /** Executes a provided function once for each key/value pair. */ + @send +@@ -2130,7 +2133,7 @@ module ShellPromise = { + * Automatically calls {@link quiet} to disable echoing to stdout. + */ + @send +- external lines: t => AsyncIterator.t = "lines" ++ external lines: t => AsyncIterator.t = "lines" + + /** + * Read from stdout as a string +diff --git a/src/HTMLRewriter.res b/src/HTMLRewriter.res +index 5260b585d144bd1a51074f5f3811501ba4efc47e..8e2cbdc5b5ab1e3516be81b56dd952bfc43c1a56 100644 +--- a/src/HTMLRewriter.res ++++ b/src/HTMLRewriter.res +@@ -17,7 +17,7 @@ module Types = { + + type rec element = { + mutable tagName: string, +- attributes: Iterator.t>, ++ attributes: IteratorObject.t, unit, unknown>, + removed: bool, + /** Whether the element is explicitly self-closing, e.g. `` */ + selfClosing: bool, diff --git a/rewatch/testrepo/packages/nohoist/package.json b/rewatch/testrepo/packages/nohoist/package.json index b8a409f831c..2e69503b4d9 100644 --- a/rewatch/testrepo/packages/nohoist/package.json +++ b/rewatch/testrepo/packages/nohoist/package.json @@ -2,6 +2,6 @@ "name": "@testrepo/nohoist", "dependencies": { "rescript": "12.0.0-beta.3", - "rescript-bun": "2.1.0" + "rescript-bun": "patch:rescript-bun@npm%3A2.1.0#~/.yarn/patches/rescript-bun-npm-2.1.0-d9adc91a04.patch" } } diff --git a/rewatch/testrepo/packages/with-dev-deps/package.json b/rewatch/testrepo/packages/with-dev-deps/package.json index 7fa2d4b3b60..612bc3627f9 100644 --- a/rewatch/testrepo/packages/with-dev-deps/package.json +++ b/rewatch/testrepo/packages/with-dev-deps/package.json @@ -7,7 +7,7 @@ "author": "", "license": "MIT", "devDependencies": { - "@rescript/webapi": "0.1.0-experimental-73e6a0d" + "@rescript/webapi": "patch:@rescript/webapi@npm%3A0.1.0-experimental-73e6a0d#~/.yarn/patches/@rescript-webapi-npm-0.1.0-experimental-73e6a0d-288a2072f7.patch" }, "dependencies": { "rescript-nodejs": "patch:rescript-nodejs@npm%3A16.1.0#~/.yarn/patches/rescript-nodejs-npm-16.1.0-1841fa6174.patch" diff --git a/rewatch/testrepo/yarn.lock b/rewatch/testrepo/yarn.lock index 3bca8d3d04c..3a9bc8450d7 100644 --- a/rewatch/testrepo/yarn.lock +++ b/rewatch/testrepo/yarn.lock @@ -70,6 +70,15 @@ __metadata: languageName: node linkType: hard +"@rescript/webapi@patch:@rescript/webapi@npm%3A0.1.0-experimental-73e6a0d#~/.yarn/patches/@rescript-webapi-npm-0.1.0-experimental-73e6a0d-288a2072f7.patch": + version: 0.1.0-experimental-73e6a0d + resolution: "@rescript/webapi@patch:@rescript/webapi@npm%3A0.1.0-experimental-73e6a0d#~/.yarn/patches/@rescript-webapi-npm-0.1.0-experimental-73e6a0d-288a2072f7.patch::version=0.1.0-experimental-73e6a0d&hash=eb9117" + dependencies: + rescript: "npm:^12.0.0-alpha.13" + checksum: 10c0/83df59606d6a76a1bcecf3e556ccddc734c41f74cf90f37268e5d9bbdaa5c5ec579deca223f5685426da5d928ec0ea5295ca9ae4daee38bc72c9cdf8a657d10e + languageName: node + linkType: hard + "@rescript/win32-x64@npm:12.0.0-beta.1": version: 12.0.0-beta.1 resolution: "@rescript/win32-x64@npm:12.0.0-beta.1" @@ -141,7 +150,7 @@ __metadata: resolution: "@testrepo/nohoist@workspace:packages/nohoist" dependencies: rescript: "npm:12.0.0-beta.3" - rescript-bun: "npm:2.1.0" + rescript-bun: "patch:rescript-bun@npm%3A2.1.0#~/.yarn/patches/rescript-bun-npm-2.1.0-d9adc91a04.patch" languageName: unknown linkType: soft @@ -169,7 +178,7 @@ __metadata: version: 0.0.0-use.local resolution: "@testrepo/with-dev-deps@workspace:packages/with-dev-deps" dependencies: - "@rescript/webapi": "npm:0.1.0-experimental-73e6a0d" + "@rescript/webapi": "patch:@rescript/webapi@npm%3A0.1.0-experimental-73e6a0d#~/.yarn/patches/@rescript-webapi-npm-0.1.0-experimental-73e6a0d-288a2072f7.patch" rescript-nodejs: "patch:rescript-nodejs@npm%3A16.1.0#~/.yarn/patches/rescript-nodejs-npm-16.1.0-1841fa6174.patch" languageName: unknown linkType: soft @@ -193,6 +202,15 @@ __metadata: languageName: node linkType: hard +"rescript-bun@patch:rescript-bun@npm%3A2.1.0#~/.yarn/patches/rescript-bun-npm-2.1.0-d9adc91a04.patch": + version: 2.1.0 + resolution: "rescript-bun@patch:rescript-bun@npm%3A2.1.0#~/.yarn/patches/rescript-bun-npm-2.1.0-d9adc91a04.patch::version=2.1.0&hash=685f4a" + peerDependencies: + rescript: ">= 12.0.0-alpha.4" + checksum: 10c0/d7d8ee95a3e8fa66ffa63f17bd90d88c4ea9029246dcd9c0519787de5bbc1ca73b061cc1052cd6239e53e2dff3d2ae298fcef244f5e167b6cda35692bdd64337 + languageName: node + linkType: hard + "rescript-nodejs@npm:16.1.0": version: 16.1.0 resolution: "rescript-nodejs@npm:16.1.0" diff --git a/tests/analysis_tests/tests/src/expected/Completion.res.txt b/tests/analysis_tests/tests/src/expected/Completion.res.txt index 31a934d68a1..5254a5f4590 100644 --- a/tests/analysis_tests/tests/src/expected/Completion.res.txt +++ b/tests/analysis_tests/tests/src/expected/Completion.res.txt @@ -356,8 +356,8 @@ Path Array. "label": "entries", "kind": 12, "tags": [], - "detail": "array<'a> => Iterator.t<(int, 'a)>", - "documentation": {"kind": "markdown", "value": "\n`entries(array)` returns a new array iterator object that contains the key/value pairs for each index in the array.\n\nSee [Array.prototype.entries](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/entries) on MDN.\n\n## Examples\n\n```rescript\nlet array = [5, 6, 7]\nlet iterator: Iterator.t<(int, int)> = array->Array.entries\niterator->Iterator.next == {done: false, value: Some((0, 5))}\niterator->Iterator.next == {done: false, value: Some((1, 6))}\n```\n"} + "detail": "array<'a> => IteratorObject.t<(int, 'a), unit, unknown>", + "documentation": {"kind": "markdown", "value": "\n`entries(array)` returns a new array iterator object that contains the key/value pairs for each index in the array.\n\nSee [Array.prototype.entries](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/entries) on MDN.\n\n## Examples\n\n```rescript\nlet array = [5, 6, 7]\nlet iterator: IteratorObject.t<(int, int), unit, unknown> = array->Array.entries\niterator->IteratorObject.toArray == [(0, 5), (1, 6), (2, 7)]\n```\n"} }, { "label": "unshiftMany", "kind": 12, @@ -370,6 +370,12 @@ Path Array. "tags": [], "detail": "(array<'a>, 'a, ~from: int=?) => int", "documentation": {"kind": "markdown", "value": "\n`lastIndexOf(array, item, ~from)` returns the last index of the provided `item` in `array`, searching backwards from `from`. Uses [strict check for equality](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Strict_equality) when comparing items.\n\nReturns `-1` if the item isn't found. Check out `Array.lastIndexOfOpt` for a version that returns `None` instead of `-1` if the item does not exist.\n\nSee [`Array.lastIndexOf`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/lastIndexOf) on MDN.\n\n## Examples\n\n```rescript\n[1, 2, 1, 2]->Array.lastIndexOf(2) == 3\n[1, 2]->Array.lastIndexOf(3) == -1\n[1, 2, 1, 2]->Array.lastIndexOf(2, ~from=2) == 1\n\n[{\"language\": \"ReScript\"}]->Array.lastIndexOf({\"language\": \"ReScript\"}) == -1 // -1, because of strict equality\n```\n"} + }, { + "label": "fromIterable", + "kind": 12, + "tags": [], + "detail": "Iterable.t<'a> => array<'a>", + "documentation": {"kind": "markdown", "value": "\n`fromIterable(iterable)` creates an array from the provided `iterable`\n\n## Examples\n\n```rescript\nMap.fromArray([(\"foo\", 1), (\"bar\", 2)])\n->Map.values\n->IteratorObject.asIterable\n->Array.fromIterable == [1, 2]\n```\n"} }, { "label": "filter", "kind": 12, @@ -410,8 +416,8 @@ Path Array. "label": "values", "kind": 12, "tags": [], - "detail": "array<'a> => Iterator.t<'a>", - "documentation": {"kind": "markdown", "value": "\n`values(array)` returns a new array iterator object that contains the values for each index in the array.\n\nSee [Array.prototype.values](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/values) on MDN.\n\n## Examples\n\n```rescript\nlet array = [5, 6, 7]\nlet iterator: Iterator.t = array->Array.values\niterator->Iterator.next == {done: false, value: Some(5)}\niterator->Iterator.next == {done: false, value: Some(6)}\n```\n "} + "detail": "array<'a> => IteratorObject.t<'a, unit, unknown>", + "documentation": {"kind": "markdown", "value": "\n`values(array)` returns a new array iterator object that contains the values for each index in the array.\n\nSee [Array.prototype.values](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/values) on MDN.\n\n## Examples\n\n```rescript\nlet array = [5, 6, 7]\nlet iterator: IteratorObject.t = array->Array.values\niterator->IteratorObject.toArray == [5, 6, 7]\n```\n "} }, { "label": "indexOfOpt", "kind": 12, @@ -586,6 +592,12 @@ Path Array. "tags": [], "detail": "(array<'a>, int) => option<'a>", "documentation": {"kind": "markdown", "value": "\n`get(array, index)` returns the element at `index` of `array`.\n\nReturns `None` if the index does not exist in the array. Equivalent to doing `array[index]` in JavaScript.\n\n## Examples\n\n```rescript\nlet array = [\"Hello\", \"Hi\", \"Good bye\"]\n\narray->Array.get(0) == Some(\"Hello\")\n\narray->Array.get(3) == None\n```\n"} + }, { + "label": "asIterable", + "kind": 12, + "tags": [], + "detail": "array<'a> => Iterable.t<'a>", + "documentation": {"kind": "markdown", "value": "\n`asIterable(array)` views `array` as an `Iterable.t`.\n\nThis is useful when passing an array to APIs that consume iterables, such as\n`Array.from` or `for...of` in JavaScript.\n"} }, { "label": "removeInPlace", "kind": 12, @@ -610,12 +622,6 @@ Path Array. "tags": [], "detail": "array<('a, 'b)> => (t<'a>, array<'b>)", "documentation": {"kind": "markdown", "value": "\n`unzip(a)` takes an array of pairs and creates a pair of arrays. The first array\ncontains all the first items of the pairs; the second array contains all the\nsecond items.\n\n## Examples\n\n```rescript\nArray.unzip([(1, 2), (3, 4)]) == ([1, 3], [2, 4])\n\nArray.unzip([(1, 2), (3, 4), (5, 6), (7, 8)]) == ([1, 3, 5, 7], [2, 4, 6, 8])\n```\n"} - }, { - "label": "fromIterator", - "kind": 12, - "tags": [], - "detail": "Iterator.t<'a> => array<'a>", - "documentation": {"kind": "markdown", "value": "\n`fromIterator(iterator)` creates an array from the provided `iterator`\n\n## Examples\n\n```rescript\nMap.fromArray([(\"foo\", 1), (\"bar\", 2)])\n->Map.values\n->Array.fromIterator == [1, 2]\n```\n"} }, { "label": "forEach", "kind": 12, @@ -1282,12 +1288,30 @@ Path As "tags": [], "detail": "Asterix", "documentation": {"kind": "markdown", "value": "```rescript\nAsterix\n```\n\n```rescript\ntype z = Allo | Asterix | Baba\n```"} + }, { + "label": "AsyncIterable", + "kind": 9, + "tags": [], + "detail": "module AsyncIterable", + "documentation": null }, { "label": "AsyncIterator", "kind": 9, "tags": [], "detail": "module AsyncIterator", "documentation": null + }, { + "label": "AsyncGenerator", + "kind": 9, + "tags": [], + "detail": "module AsyncGenerator", + "documentation": null + }, { + "label": "AsyncIterableIterator", + "kind": 9, + "tags": [], + "detail": "module AsyncIterableIterator", + "documentation": null }] Complete src/Completion.res 182:17 diff --git a/tests/analysis_tests/tests/src/expected/CompletionJsx.res.txt b/tests/analysis_tests/tests/src/expected/CompletionJsx.res.txt index 4ef9123b446..5fd5b129993 100644 --- a/tests/analysis_tests/tests/src/expected/CompletionJsx.res.txt +++ b/tests/analysis_tests/tests/src/expected/CompletionJsx.res.txt @@ -550,6 +550,12 @@ Path a "tags": [], "detail": "(array<'a>, int) => option<'a>", "documentation": {"kind": "markdown", "value": "\n`at(array, index)`\n\nGet an element by its index. Negative indices count backwards from the last item.\n\n## Examples\n\n```rescript\n[\"a\", \"b\", \"c\"]->Array.at(0) == Some(\"a\")\n[\"a\", \"b\", \"c\"]->Array.at(2) == Some(\"c\")\n[\"a\", \"b\", \"c\"]->Array.at(3) == None\n[\"a\", \"b\", \"c\"]->Array.at(-1) == Some(\"c\")\n[\"a\", \"b\", \"c\"]->Array.at(-3) == Some(\"a\")\n[\"a\", \"b\", \"c\"]->Array.at(-4) == None\n```\n"} + }, { + "label": "Array.asIterable", + "kind": 12, + "tags": [], + "detail": "array<'a> => Iterable.t<'a>", + "documentation": {"kind": "markdown", "value": "\n`asIterable(array)` views `array` as an `Iterable.t`.\n\nThis is useful when passing an array to APIs that consume iterables, such as\n`Array.from` or `for...of` in JavaScript.\n"} }] Complete src/CompletionJsx.res 30:12 diff --git a/tests/gentype_tests/stdlib-no-shims/src/StdlibNoShims.gen.tsx b/tests/gentype_tests/stdlib-no-shims/src/StdlibNoShims.gen.tsx index 8f46ce8d852..1ff3693286a 100644 --- a/tests/gentype_tests/stdlib-no-shims/src/StdlibNoShims.gen.tsx +++ b/tests/gentype_tests/stdlib-no-shims/src/StdlibNoShims.gen.tsx @@ -89,9 +89,27 @@ export const idBigUint64Array: (x:BigUint64Array) => BigUint64Array = StdlibNoSh export const idSymbol: (x:symbol) => symbol = StdlibNoShimsJS.idSymbol as any; -export const idIterator: (x:Iterator) => Iterator = StdlibNoShimsJS.idIterator as any; +export const idIterable: (x:Iterable) => Iterable = StdlibNoShimsJS.idIterable as any; -export const idAsyncIterator: (x:AsyncIterator) => AsyncIterator = StdlibNoShimsJS.idAsyncIterator as any; +export const idBuiltinIterable: (x:Iterable) => Iterable = StdlibNoShimsJS.idBuiltinIterable as any; + +export const idIterator: (x:Iterator) => Iterator = StdlibNoShimsJS.idIterator as any; + +export const idIteratorObject: (x:IteratorObject) => IteratorObject = StdlibNoShimsJS.idIteratorObject as any; + +export const idIterableIterator: (x:IterableIterator) => IterableIterator = StdlibNoShimsJS.idIterableIterator as any; + +export const idGenerator: (x:Generator) => Generator = StdlibNoShimsJS.idGenerator as any; + +export const idAsyncIterable: (x:AsyncIterable) => AsyncIterable = StdlibNoShimsJS.idAsyncIterable as any; + +export const idBuiltinAsyncIterable: (x:AsyncIterable) => AsyncIterable = StdlibNoShimsJS.idBuiltinAsyncIterable as any; + +export const idAsyncIterator: (x:AsyncIterator) => AsyncIterator = StdlibNoShimsJS.idAsyncIterator as any; + +export const idAsyncIterableIterator: (x:AsyncIterableIterator) => AsyncIterableIterator = StdlibNoShimsJS.idAsyncIterableIterator as any; + +export const idAsyncGenerator: (x:AsyncGenerator) => AsyncGenerator = StdlibNoShimsJS.idAsyncGenerator as any; export const idOrdering: (x:number) => number = StdlibNoShimsJS.idOrdering as any; diff --git a/tests/gentype_tests/stdlib-no-shims/src/StdlibNoShims.res b/tests/gentype_tests/stdlib-no-shims/src/StdlibNoShims.res index f37f614d7dc..9d3c5300118 100644 --- a/tests/gentype_tests/stdlib-no-shims/src/StdlibNoShims.res +++ b/tests/gentype_tests/stdlib-no-shims/src/StdlibNoShims.res @@ -91,8 +91,17 @@ let idTuple = (x: (int, string, float)) => x @genType let idSymbol = (x: Symbol.t) => x // More Stdlib exposed types (add more as generator support grows) -@genType let idIterator = (x: Iterator.t) => x -@genType let idAsyncIterator = (x: AsyncIterator.t) => x +@genType let idIterable = (x: Iterable.t) => x +@genType let idBuiltinIterable = (x: iterable) => x +@genType let idIterator = (x: Iterator.t) => x +@genType let idIteratorObject = (x: IteratorObject.t) => x +@genType let idIterableIterator = (x: IterableIterator.t) => x +@genType let idGenerator = (x: Generator.t) => x +@genType let idAsyncIterable = (x: AsyncIterable.t) => x +@genType let idBuiltinAsyncIterable = (x: asyncIterable) => x +@genType let idAsyncIterator = (x: AsyncIterator.t) => x +@genType let idAsyncIterableIterator = (x: AsyncIterableIterator.t) => x +@genType let idAsyncGenerator = (x: AsyncGenerator.t) => x @genType let idOrdering = (x: Ordering.t) => x // Intl* types @@ -111,5 +120,3 @@ let idTuple = (x: (int, string, float)) => x // Dynamic object @genType let idObj = (x: {..}) => x - -// dummy change to trigger rebuild diff --git a/tests/gentype_tests/stdlib-no-shims/src/StdlibNoShims.res.js b/tests/gentype_tests/stdlib-no-shims/src/StdlibNoShims.res.js index 76b6e6b3e29..7afa8d68ddb 100644 --- a/tests/gentype_tests/stdlib-no-shims/src/StdlibNoShims.res.js +++ b/tests/gentype_tests/stdlib-no-shims/src/StdlibNoShims.res.js @@ -153,14 +153,50 @@ function idSymbol(x) { return x; } +function idIterable(x) { + return x; +} + +function idBuiltinIterable(x) { + return x; +} + function idIterator(x) { return x; } +function idIteratorObject(x) { + return x; +} + +function idIterableIterator(x) { + return x; +} + +function idGenerator(x) { + return x; +} + +function idAsyncIterable(x) { + return x; +} + +function idBuiltinAsyncIterable(x) { + return x; +} + function idAsyncIterator(x) { return x; } +function idAsyncIterableIterator(x) { + return x; +} + +function idAsyncGenerator(x) { + return x; +} + function idOrdering(x) { return x; } @@ -248,8 +284,17 @@ export { idBigInt64Array, idBigUint64Array, idSymbol, + idIterable, + idBuiltinIterable, idIterator, + idIteratorObject, + idIterableIterator, + idGenerator, + idAsyncIterable, + idBuiltinAsyncIterable, idAsyncIterator, + idAsyncIterableIterator, + idAsyncGenerator, idOrdering, idIntlCollator, idIntlDateTimeFormat, diff --git a/tests/gentype_tests/stdlib-no-shims/src/index.ts b/tests/gentype_tests/stdlib-no-shims/src/index.ts index 456660117e5..303f07608e5 100644 --- a/tests/gentype_tests/stdlib-no-shims/src/index.ts +++ b/tests/gentype_tests/stdlib-no-shims/src/index.ts @@ -85,12 +85,45 @@ const bu64: BigUint64Array = S.idBigUint64Array(new BigUint64Array(2)); const sym: symbol = S.idSymbol(Symbol("x")); // Iterator / AsyncIterator / Ordering -const it: Iterator = S.idIterator([1, 2, 3].values()); -const ait: AsyncIterator = S.idAsyncIterator({ +const iterable: Iterable = S.idIterable([1, 2, 3]); +const builtinIterable: Iterable = S.idBuiltinIterable([1, 2, 3]); +const it: Iterator = S.idIterator([1, 2, 3].values()); +const ito: IteratorObject = S.idIteratorObject( + [1, 2, 3].values() +); +const iterableIterator: IterableIterator = + S.idIterableIterator([1, 2, 3].values()); +const gen: Generator = S.idGenerator( + (function* () { + yield 1; + })() +); +const asyncIterable: AsyncIterable = S.idAsyncIterable( + (async function* () { + yield 1; + })() +); +const builtinAsyncIterable: AsyncIterable = S.idBuiltinAsyncIterable( + (async function* () { + yield 1; + })() +); +const ait: AsyncIterator = S.idAsyncIterator({ next(): Promise> { return Promise.resolve({ done: true, value: undefined }); }, }); +const asyncIterableIterator: AsyncIterableIterator = + S.idAsyncIterableIterator( + (async function* () { + yield 1; + })() + ); +const asyncGenerator: AsyncGenerator = S.idAsyncGenerator( + (async function* () { + yield 1; + })() +); const ord: number = S.idOrdering(0); // Intl family diff --git a/tests/tests/src/option_wrapping_test.res b/tests/tests/src/option_wrapping_test.res index 57e03476f2c..4d1a83c21a8 100644 --- a/tests/tests/src/option_wrapping_test.res +++ b/tests/tests/src/option_wrapping_test.res @@ -26,7 +26,15 @@ let x29 = Some(JsError.make("")) let x30 = Some(ArrayBuffer.make(0)) let x31 = Some(ArrayBuffer.make(0)->DataView.fromBuffer) let x32 = Some((Map.make(): Map.t)->Map.values) -let x33 = Some(AsyncIterator.make(_ => AsyncIterator.value(true)->Promise.resolve)) +let x33 = Some( + ( + AsyncIterator.make(_ => AsyncIterator.value(true)->Promise.resolve): AsyncIterator.t< + bool, + unit, + unit, + > + ), +) let x34 = Some(Intl.ListFormat.make()) let x35 = Some(Intl.Segmenter.make()) diff --git a/tests/tests/src/reactDOM.res b/tests/tests/src/reactDOM.res index 3cb44aac83f..5a7c7da8678 100644 --- a/tests/tests/src/reactDOM.res +++ b/tests/tests/src/reactDOM.res @@ -67,8 +67,8 @@ module FormData = { @send external set: (string, string) => unit = "set" @send external has: string => bool = "has" - // @send external keys: t => Iterator.t = "keys"; - // @send external values: t => Iterator.t = "values"; + // @send external keys: t => IteratorObject.t = "keys"; + // @send external values: t => IteratorObject.t = "values"; } @module("react-dom") diff --git a/tests/tests/src/stdlib/Stdlib_ArrayTests.mjs b/tests/tests/src/stdlib/Stdlib_ArrayTests.mjs index 38d7cd58193..f78059dd223 100644 --- a/tests/tests/src/stdlib/Stdlib_ArrayTests.mjs +++ b/tests/tests/src/stdlib/Stdlib_ArrayTests.mjs @@ -432,7 +432,99 @@ Test.run([ Test.run([ [ "Stdlib_ArrayTests.res", - 110, + 111, + 13, + 27 + ], + "fromIterable" +], Array.from("abc"), eq, [ + "a", + "b", + "c" +]); + +Test.run([ + [ + "Stdlib_ArrayTests.res", + 118, + 13, + 31 + ], + "Map.fromIterable" +], new Map([ + [ + "one", + 1 + ], + [ + "two", + 2 + ] +]).size, eq, 2); + +Test.run([ + [ + "Stdlib_ArrayTests.res", + 125, + 13, + 31 + ], + "Set.fromIterable" +], new Set([ + 1, + 2, + 2 +]).size, eq, 2); + +Test.run([ + [ + "Stdlib_ArrayTests.res", + 132, + 13, + 29 + ], + "Map.asIterable" +], Array.from(new Map([ + [ + "one", + 1 + ], + [ + "two", + 2 + ] +])), eq, [ + [ + "one", + 1 + ], + [ + "two", + 2 + ] +]); + +Test.run([ + [ + "Stdlib_ArrayTests.res", + 139, + 13, + 29 + ], + "Set.asIterable" +], Array.from(new Set([ + 1, + 2, + 2 +])), eq, [ + 1, + 2 +]); + +Test.run([ + [ + "Stdlib_ArrayTests.res", + 145, 20, 39 ], @@ -446,7 +538,7 @@ Test.run([ Test.run([ [ "Stdlib_ArrayTests.res", - 111, + 146, 20, 34 ], @@ -460,7 +552,7 @@ array.splice(1, 0, "foo"); Test.run([ [ "Stdlib_ArrayTests.res", - 116, + 151, 22, 49 ], @@ -475,7 +567,7 @@ let array$1 = [ Test.run([ [ "Stdlib_ArrayTests.res", - 122, + 157, 15, 43 ], diff --git a/tests/tests/src/stdlib/Stdlib_ArrayTests.res b/tests/tests/src/stdlib/Stdlib_ArrayTests.res index 2ec0031dd0a..cf9d6718853 100644 --- a/tests/tests/src/stdlib/Stdlib_ArrayTests.res +++ b/tests/tests/src/stdlib/Stdlib_ArrayTests.res @@ -102,11 +102,46 @@ Test.run( Test.run( __POS_OF__("fromIterator"), - Array.fromIterator(Map.fromArray([(1, 3), (2, 4)])->Map.values), + Array.fromIterable(Map.fromArray([(1, 3), (2, 4)])->Map.values->IteratorObject.asIterable), eq, [3, 4], ) +Test.run( + __POS_OF__("fromIterable"), + Array.fromIterable("abc"->String.asIterable), + eq, + ["a", "b", "c"], +) + +Test.run( + __POS_OF__("Map.fromIterable"), + Map.fromIterable([("one", 1), ("two", 2)]->Array.asIterable)->Map.size, + eq, + 2, +) + +Test.run( + __POS_OF__("Set.fromIterable"), + Set.fromIterable([1, 2, 2]->Array.asIterable)->Set.size, + eq, + 2, +) + +Test.run( + __POS_OF__("Map.asIterable"), + Map.fromArray([("one", 1), ("two", 2)])->Map.asIterable->Array.fromIterable, + eq, + [("one", 1), ("two", 2)], +) + +Test.run( + __POS_OF__("Set.asIterable"), + Set.fromArray([1, 2, 2])->Set.asIterable->Array.fromIterable, + eq, + [1, 2], +) + Test.run(__POS_OF__("last - with items"), [1, 2, 3]->Array.last, eq, Some(3)) Test.run(__POS_OF__("last - empty"), []->Array.last, eq, None) diff --git a/tests/tests/src/stdlib/Stdlib_DictTests.mjs b/tests/tests/src/stdlib/Stdlib_DictTests.mjs index cc5c91ebb50..717c265756f 100644 --- a/tests/tests/src/stdlib/Stdlib_DictTests.mjs +++ b/tests/tests/src/stdlib/Stdlib_DictTests.mjs @@ -73,6 +73,25 @@ Test.run([ "Stdlib_DictTests.res", 44, 13, + 27 + ], + "fromIterable" +], Object.fromEntries([ + [ + "foo", + "bar" + ], + [ + "baz", + "qux" + ] +]), eq, {foo: "bar", baz: "qux"}); + +Test.run([ + [ + "Stdlib_DictTests.res", + 51, + 13, 35 ], "getUnsafe - existing" @@ -84,7 +103,7 @@ Test.run([ Test.run([ [ "Stdlib_DictTests.res", - 50, + 57, 13, 34 ], @@ -99,7 +118,7 @@ let dict = { Test.run([ [ "Stdlib_DictTests.res", - 62, + 69, 22, 38 ], @@ -109,7 +128,7 @@ Test.run([ Test.run([ [ "Stdlib_DictTests.res", - 63, + 70, 22, 43 ], @@ -119,7 +138,7 @@ Test.run([ Test.run([ [ "Stdlib_DictTests.res", - 64, + 71, 22, 37 ], @@ -129,7 +148,7 @@ Test.run([ Test.run([ [ "Stdlib_DictTests.res", - 65, + 72, 22, 39 ], @@ -139,7 +158,7 @@ Test.run([ Test.run([ [ "Stdlib_DictTests.res", - 67, + 74, 15, 51 ], diff --git a/tests/tests/src/stdlib/Stdlib_DictTests.res b/tests/tests/src/stdlib/Stdlib_DictTests.res index fe637a0c1d6..4e171cb7c00 100644 --- a/tests/tests/src/stdlib/Stdlib_DictTests.res +++ b/tests/tests/src/stdlib/Stdlib_DictTests.res @@ -40,6 +40,13 @@ Test.run(__POS_OF__("make"), Dict.make(), eq, %raw(`{}`)) Test.run(__POS_OF__("fromArray"), Dict.fromArray([("foo", "bar")]), eq, %raw(`{foo: "bar"}`)) +Test.run( + __POS_OF__("fromIterable"), + Dict.fromIterable([("foo", "bar"), ("baz", "qux")]->Array.asIterable), + eq, + %raw(`{foo: "bar", baz: "qux"}`), +) + Test.run( __POS_OF__("getUnsafe - existing"), Dict.fromArray([("foo", "bar")])->Dict.getUnsafe("foo"), diff --git a/tests/tests/src/stdlib/Stdlib_IteratorTests.mjs b/tests/tests/src/stdlib/Stdlib_IteratorTests.mjs index e4073da46ff..31082f5d2f3 100644 --- a/tests/tests/src/stdlib/Stdlib_IteratorTests.mjs +++ b/tests/tests/src/stdlib/Stdlib_IteratorTests.mjs @@ -1,11 +1,179 @@ // Generated by ReScript, PLEASE EDIT WITH CARE import * as Test from "./Test.mjs"; +import * as Belt_Array from "@rescript/runtime/lib/es6/Belt_Array.mjs"; +import * as Stdlib_Iterator from "@rescript/runtime/lib/es6/Stdlib_Iterator.mjs"; import * as Primitive_object from "@rescript/runtime/lib/es6/Primitive_object.mjs"; +import * as Stdlib_Generator from "@rescript/runtime/lib/es6/Stdlib_Generator.mjs"; +import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_exceptions.mjs"; import * as Stdlib_AsyncIterator from "@rescript/runtime/lib/es6/Stdlib_AsyncIterator.mjs"; +import * as Stdlib_AsyncGenerator from "@rescript/runtime/lib/es6/Stdlib_AsyncGenerator.mjs"; +import * as Stdlib_IteratorObject from "@rescript/runtime/lib/es6/Stdlib_IteratorObject.mjs"; +import * as Stdlib_IterableIterator from "@rescript/runtime/lib/es6/Stdlib_IterableIterator.mjs"; +import * as Stdlib_AsyncIterableIterator from "@rescript/runtime/lib/es6/Stdlib_AsyncIterableIterator.mjs"; let eq = Primitive_object.equal; +let supportsIteratorHelpers = (typeof ((function*(){ yield 1; })()).map === "function"); + +function _checkIteratorHelperTypes() { + let iteratorObject = ((function* () { + yield 1 + return "done" + })()); + iteratorObject.map(value => value.toString()); + iteratorObject.filter(value => value > 0); + iteratorObject.drop(1); + iteratorObject.take(1); + iteratorObject.flatMap(value => [ + value, + value + 1 | 0 + ]); +} + +if (supportsIteratorHelpers) { + let makeIteratorObject = () => (((function* () { + yield 1 + yield 2 + yield 3 + })())); + Test.run([ + [ + "Stdlib_IteratorTests.res", + 30, + 15, + 49 + ], + "IteratorObject.toArrayWithMapper" + ], Array.from(makeIteratorObject(), value => value + 10 | 0), eq, [ + 11, + 12, + 13 + ]); + Test.run([ + [ + "Stdlib_IteratorTests.res", + 37, + 15, + 35 + ], + "IteratorObject.map" + ], makeIteratorObject().map(value => value + 1 | 0).toArray(), eq, [ + 2, + 3, + 4 + ]); + Test.run([ + [ + "Stdlib_IteratorTests.res", + 44, + 15, + 38 + ], + "IteratorObject.filter" + ], makeIteratorObject().filter(value => value % 2 === 1).toArray(), eq, [ + 1, + 3 + ]); + Test.run([ + [ + "Stdlib_IteratorTests.res", + 53, + 15, + 36 + ], + "IteratorObject.drop" + ], makeIteratorObject().drop(1).toArray(), eq, [ + 2, + 3 + ]); + Test.run([ + [ + "Stdlib_IteratorTests.res", + 60, + 15, + 36 + ], + "IteratorObject.take" + ], makeIteratorObject().take(2).toArray(), eq, [ + 1, + 2 + ]); + Test.run([ + [ + "Stdlib_IteratorTests.res", + 67, + 15, + 39 + ], + "IteratorObject.flatMap" + ], makeIteratorObject().flatMap(value => [ + value, + value + 10 | 0 + ]).toArray(), eq, [ + 1, + 11, + 2, + 12, + 3, + 13 + ]); + Test.run([ + [ + "Stdlib_IteratorTests.res", + 76, + 15, + 38 + ], + "IteratorObject.reduce" + ], makeIteratorObject().reduce((sum, value) => sum + value | 0, 0), eq, 6); + Test.run([ + [ + "Stdlib_IteratorTests.res", + 83, + 15, + 37 + ], + "IteratorObject.every" + ], makeIteratorObject().every(value => value > 0), eq, true); + Test.run([ + [ + "Stdlib_IteratorTests.res", + 90, + 15, + 36 + ], + "IteratorObject.some" + ], makeIteratorObject().some(value => value === 2), eq, true); + Test.run([ + [ + "Stdlib_IteratorTests.res", + 97, + 15, + 36 + ], + "IteratorObject.find" + ], makeIteratorObject().find(value => value === 3), eq, 3); +} + +Test.run([ + [ + "Stdlib_IteratorTests.res", + 105, + 13, + 73 + ], + "IteratorObject.toArrayWithMapper (built-in array iterator)" +], Array.from([ + 1, + 2, + 3 +].values(), value => value + 20 | 0), eq, [ + 21, + 22, + 23 +]); + let iterator = ((() => { var array1 = ['a', 'b', 'c']; var iterator1 = array1[Symbol.iterator](); @@ -16,39 +184,319 @@ let syncResult = { contents: undefined }; -iterator.forEach(v => { - if (v === "b") { - syncResult.contents = "b"; - return; - } -}); +let match = Stdlib_IterableIterator.next(iterator); + +let match$1 = Stdlib_IterableIterator.next(iterator); + +if (match$1.done === false && match$1.value === "b") { + syncResult.contents = "b"; +} Test.run([ [ "Stdlib_IteratorTests.res", - 19, + 131, 20, 34 ], "Sync forEach" ], syncResult.contents, eq, "b"); -let asyncIterator = ((() => { - var map1 = new Map(); +let iteratorProtocol = ((() => { + var array1 = ['x', 'y']; + var iterator1 = array1[Symbol.iterator](); + return iterator1 + })()); + +let protocolResult = { + contents: undefined +}; + +let match$2 = Stdlib_Iterator.next(iteratorProtocol); + +if (match$2.done === false && match$2.value === "x") { + protocolResult.contents = "x"; +} + +Test.run([ + [ + "Stdlib_IteratorTests.res", + 148, + 20, + 35 + ], + "Iterator next" +], protocolResult.contents, eq, "x"); + +let omittedDoneIterator = (({ + step: 0, + next() { + if (this.step === 0) { + this.step = 1 + return {value: 1} + } + return {done: true, value: "done"} + } +})); + +let omittedDoneResult = { + contents: undefined +}; + +let match$3 = Stdlib_Iterator.next(omittedDoneIterator); + +if (match$3.done === false) { + if (match$3.value !== 1) { + + } else { + omittedDoneResult.contents = "yield"; + } +} + +Test.run([ + [ + "Stdlib_IteratorTests.res", + 169, + 13, + 46 + ], + "Iterator next with omitted done" +], omittedDoneResult.contents, eq, "yield"); + +let current = { + contents: 0 +}; - map1.set('first', '1'); - map1.set('second', '2'); +let createdIterator = Stdlib_Iterator.make(() => { + let value = current.contents; + current.contents = value + 1 | 0; + if (value >= 2) { + return Stdlib_Iterator.doneWithValue("done"); + } else { + return Stdlib_Iterator.value(value); + } +}); + +let createdProtocolResult = { + contents: undefined +}; - var iterator1 = map1[Symbol.iterator](); - return iterator1; +let match$4 = Stdlib_Iterator.next(createdIterator); + +if (match$4.done === false) { + if (match$4.value !== 0) { + + } else { + createdProtocolResult.contents = "protocol"; + } +} + +Test.run([ + [ + "Stdlib_IteratorTests.res", + 197, + 13, + 41 + ], + "Creating your own iterator" +], createdProtocolResult.contents, eq, "protocol"); + +let current$1 = { + contents: 0 +}; + +let createdIterableIterator = Stdlib_IterableIterator.make(() => { + let value = current$1.contents; + current$1.contents = value + 1 | 0; + if (value >= 2) { + return Stdlib_Iterator.doneWithValue("done"); + } else { + return Stdlib_Iterator.value(value); + } +}); + +let createdIterableResult = { + contents: undefined +}; + +let match$5 = Stdlib_IterableIterator.next(createdIterableIterator); + +let match$6 = Stdlib_IterableIterator.next(createdIterableIterator); + +if (match$6.done === false) { + if (match$6.value !== 1) { + + } else { + createdIterableResult.contents = "iterable"; + } +} + +Test.run([ + [ + "Stdlib_IteratorTests.res", + 230, + 13, + 50 + ], + "Creating your own iterable iterator" +], createdIterableResult.contents, eq, "iterable"); + +let generatorViaIterator = ((function* () { + let sent = yield 1 + return String((sent ?? 0) + 1) +})()); + +let iteratorNextValueResult = { + contents: undefined +}; + +let match$7 = Stdlib_Iterator.nextValue(generatorViaIterator, undefined); + +let match$8 = Stdlib_Iterator.nextValue(generatorViaIterator, 4); + +if (match$8.done !== false && match$8.value === "5") { + iteratorNextValueResult.contents = "nextValue"; +} + +Test.run([ + [ + "Stdlib_IteratorTests.res", + 253, + 20, + 40 + ], + "Iterator nextValue" +], iteratorNextValueResult.contents, eq, "nextValue"); + +Test.run([ + [ + "Stdlib_IteratorTests.res", + 256, + 13, + 35 + ], + "Generator.asIterable" +], Array.from(((function* () { + yield 1 + yield 2 + })())), eq, [ + 1, + 2 +]); + +Test.run([ + [ + "Stdlib_IteratorTests.res", + 270, + 13, + 41 + ], + "Generator.asIteratorObject" +], Array.from(((function* () { + yield 1 + yield 2 + })()), value => (value << 1)), eq, [ + 2, + 4 +]); + +let generatorWithNext = ((function* () { + let injected = yield 1 + yield injected + 1 + })()); + +let match$9 = Stdlib_Generator.next(generatorWithNext); + +let tmp; + +if (match$9.done === false && match$9.value === 1) { + let match$10 = Stdlib_IteratorObject.nextValue(generatorWithNext, 41); + tmp = match$10.done === false && match$10.value === 42 ? "nextValue" : undefined; +} else { + tmp = undefined; +} + +Test.run([ + [ + "Stdlib_IteratorTests.res", + 284, + 13, + 51 + ], + "Generator.asIteratorObject nextValue" +], tmp, eq, "nextValue"); + +let generatorReturnValueResult = { + contents: undefined +}; + +let generatorReturnValue = ((function* () { + yield 1 + return "done" +})()); + +let match$11 = Stdlib_Generator.next(generatorReturnValue); + +let match$12 = Stdlib_Generator.returnValue(generatorReturnValue, "stopped"); + +if (match$12.done !== false && match$12.value === "stopped") { + generatorReturnValueResult.contents = "returnValue"; +} + +Test.run([ + [ + "Stdlib_IteratorTests.res", + 321, + 13, + 36 + ], + "Generator.returnValue" +], generatorReturnValueResult.contents, eq, "returnValue"); + +let generatorThrowErrorResult = { + contents: undefined +}; + +let generatorThrowError = ((function* () { + try { + yield 1 + return "done" + } catch (error) { + return error.message + } +})()); + +let match$13 = Stdlib_Generator.next(generatorThrowError); + +let match$14 = Stdlib_Generator.throwError(generatorThrowError, Primitive_exceptions.internalToException(new Error("boom"))); + +if (match$14.done !== false) { + generatorThrowErrorResult.contents = "throwError"; +} + +Test.run([ + [ + "Stdlib_IteratorTests.res", + 348, + 13, + 35 + ], + "Generator.throwError" +], generatorThrowErrorResult.contents, eq, "throwError"); + +let asyncIterableIterator = ((async function* () { + yield ['first', '1'] + yield ['second', '2'] })()); let asyncResult = { contents: undefined }; -await Stdlib_AsyncIterator.forEach(asyncIterator, v => { - if (v !== undefined && v[0] === "second") { +let match$15 = await Stdlib_AsyncIterableIterator.next(asyncIterableIterator); + +await Stdlib_AsyncIterableIterator.forEach(asyncIterableIterator, param => { + if (param[0] === "second") { asyncResult.contents = "second"; return; } @@ -57,7 +505,7 @@ await Stdlib_AsyncIterator.forEach(asyncIterator, v => { Test.run([ [ "Stdlib_IteratorTests.res", - 42, + 374, 20, 35 ], @@ -72,39 +520,252 @@ let count = { contents: 0 }; -let asyncIterator$1 = Stdlib_AsyncIterator.make(async () => { +let asyncIterableIteratorResult = { + contents: undefined +}; + +let asyncIterableIteratorCount = { + contents: 0 +}; + +let asyncIterator = Stdlib_AsyncIterator.make(async () => { let currentCount = count.contents; count.contents = currentCount + 1 | 0; if (currentCount === 3) { - return Stdlib_AsyncIterator.done(currentCount); + return Stdlib_AsyncIterator.doneWithValue(currentCount); } else { return Stdlib_AsyncIterator.value(currentCount); } }); -await Stdlib_AsyncIterator.forEach(asyncIterator$1, v => { - if (v === 3) { +await Stdlib_AsyncIterator.forEach(asyncIterator, value => { + if (value === 2) { asyncResult$1.contents = "done"; - } else { - console.log("next.."); + return; } }); Test.run([ [ "Stdlib_IteratorTests.res", - 67, + 400, 20, 54 ], "Creating your own async iterator" ], asyncResult$1.contents, eq, "done"); +let asyncOmittedDoneValues = { + contents: [] +}; + +let asyncOmittedDoneIterator = (({ + step: 0, + next() { + if (this.step === 0) { + this.step = 1 + return Promise.resolve({value: 1}) + } + return Promise.resolve({done: true, value: "done"}) + } +})); + +await Stdlib_AsyncIterator.forEach(asyncOmittedDoneIterator, value => { + asyncOmittedDoneValues.contents = Belt_Array.concatMany([ + asyncOmittedDoneValues.contents, + [value] + ]); +}); + +Test.run([ + [ + "Stdlib_IteratorTests.res", + 419, + 13, + 54 + ], + "AsyncIterator.forEach with omitted done" +], asyncOmittedDoneValues.contents, eq, [1]); + +let asyncGeneratorNextValue = ((async function* () { + let sent = yield 1 + return String((sent ?? 0) + 1) +})()); + +let asyncGeneratorNextValueResult = { + contents: undefined +}; + +let match$16 = await Stdlib_AsyncIterator.nextValue(asyncGeneratorNextValue, undefined); + +let match$17 = await Stdlib_AsyncGenerator.nextValue(asyncGeneratorNextValue, 4); + +if (match$17.done !== false && match$17.value === "5") { + asyncGeneratorNextValueResult.contents = "nextValue"; +} + +Test.run([ + [ + "Stdlib_IteratorTests.res", + 449, + 13, + 39 + ], + "AsyncGenerator.nextValue" +], asyncGeneratorNextValueResult.contents, eq, "nextValue"); + +let asyncGeneratorIterableValues = { + contents: [] +}; + +let asyncGeneratorIterable = ((async function* () { + yield 2 + yield 3 +})()); + +await Stdlib_AsyncIterableIterator.forEach(asyncGeneratorIterable, value => { + asyncGeneratorIterableValues.contents = Belt_Array.concatMany([ + asyncGeneratorIterableValues.contents, + [value] + ]); +}); + +Test.run([ + [ + "Stdlib_IteratorTests.res", + 468, + 13, + 53 + ], + "AsyncGenerator.asAsyncIterableIterator" +], asyncGeneratorIterableValues.contents, eq, [ + 2, + 3 +]); + +let _asyncIterableView = ((async function* () { + yield 1 + })()); + +let asyncGeneratorReturnValueResult = { + contents: undefined +}; + +let asyncGeneratorReturnValue = ((async function* () { + yield 1 + return "done" +})()); + +let match$18 = await Stdlib_AsyncGenerator.next(asyncGeneratorReturnValue); + +let match$19 = await Stdlib_AsyncGenerator.returnValue(asyncGeneratorReturnValue, "stopped"); + +if (match$19.done !== false && match$19.value === "stopped") { + asyncGeneratorReturnValueResult.contents = "returnValue"; +} + +Test.run([ + [ + "Stdlib_IteratorTests.res", + 497, + 13, + 41 + ], + "AsyncGenerator.returnValue" +], asyncGeneratorReturnValueResult.contents, eq, "returnValue"); + +let asyncGeneratorThrowErrorResult = { + contents: undefined +}; + +let asyncGeneratorThrowError = ((async function* () { + try { + yield 1 + return "done" + } catch (error) { + return error.message + } +})()); + +let match$20 = await Stdlib_AsyncGenerator.next(asyncGeneratorThrowError); + +let match$21 = await Stdlib_AsyncGenerator.throwError(asyncGeneratorThrowError, Primitive_exceptions.internalToException(new Error("boom"))); + +if (match$21.done !== false) { + asyncGeneratorThrowErrorResult.contents = "throwError"; +} + +Test.run([ + [ + "Stdlib_IteratorTests.res", + 526, + 13, + 40 + ], + "AsyncGenerator.throwError" +], asyncGeneratorThrowErrorResult.contents, eq, "throwError"); + +let createdAsyncIterableIterator = Stdlib_AsyncIterableIterator.make(async () => { + let currentCount = asyncIterableIteratorCount.contents; + asyncIterableIteratorCount.contents = currentCount + 1 | 0; + if (currentCount === 2) { + return Stdlib_AsyncIterator.done(); + } else { + return Stdlib_AsyncIterator.value(currentCount); + } +}); + +await Stdlib_AsyncIterableIterator.forEach(createdAsyncIterableIterator, value => { + if (value === 1) { + asyncIterableIteratorResult.contents = "iterable"; + return; + } +}); + +Test.run([ + [ + "Stdlib_IteratorTests.res", + 550, + 13, + 56 + ], + "Creating your own async iterable iterator" +], asyncIterableIteratorResult.contents, eq, "iterable"); + export { eq, + supportsIteratorHelpers, + _checkIteratorHelperTypes, iterator, syncResult, + iteratorProtocol, + protocolResult, + omittedDoneIterator, + omittedDoneResult, + createdIterator, + createdProtocolResult, + createdIterableIterator, + createdIterableResult, + generatorViaIterator, + iteratorNextValueResult, + generatorReturnValueResult, + generatorReturnValue, + generatorThrowErrorResult, + generatorThrowError, + asyncIterableIterator, asyncResult, - asyncIterator$1 as asyncIterator, + asyncIterator, + asyncOmittedDoneValues, + asyncOmittedDoneIterator, + asyncGeneratorNextValue, + asyncGeneratorNextValueResult, + asyncGeneratorIterableValues, + asyncGeneratorIterable, + _asyncIterableView, + asyncGeneratorReturnValueResult, + asyncGeneratorReturnValue, + asyncGeneratorThrowErrorResult, + asyncGeneratorThrowError, + createdAsyncIterableIterator, } -/* iterator Not a pure module */ +/* supportsIteratorHelpers Not a pure module */ diff --git a/tests/tests/src/stdlib/Stdlib_IteratorTests.res b/tests/tests/src/stdlib/Stdlib_IteratorTests.res index 8582a4c44a2..96e7ae08f25 100644 --- a/tests/tests/src/stdlib/Stdlib_IteratorTests.res +++ b/tests/tests/src/stdlib/Stdlib_IteratorTests.res @@ -1,6 +1,114 @@ let eq = (a, b) => a == b -let iterator: Iterator.t = %raw(` +let supportsIteratorHelpers: bool = %raw(`typeof ((function*(){ yield 1; })()).map === "function"`) + +let _checkIteratorHelperTypes = () => { + let iteratorObject: IteratorObject.t = %raw(`(function* () { + yield 1 + return "done" + })()`) + + let _mapped: IteratorObject.t = + iteratorObject->IteratorObject.map(value => value->Int.toString) + let _filtered: IteratorObject.t = + iteratorObject->IteratorObject.filter(value => value > 0) + let _dropped: IteratorObject.t = iteratorObject->IteratorObject.drop(1) + let _taken: IteratorObject.t = iteratorObject->IteratorObject.take(1) + let _flatMapped: IteratorObject.t = + iteratorObject->IteratorObject.flatMap(value => [value, value + 1]->Array.asIterable) +} + +if supportsIteratorHelpers { + let makeIteratorObject = (): IteratorObject.t => + %raw(`(function* () { + yield 1 + yield 2 + yield 3 + })()`) + + Test.run( + __POS_OF__("IteratorObject.toArrayWithMapper"), + makeIteratorObject()->IteratorObject.toArrayWithMapper(value => value + 10), + eq, + [11, 12, 13], + ) + + Test.run( + __POS_OF__("IteratorObject.map"), + makeIteratorObject()->IteratorObject.map(value => value + 1)->IteratorObject.toArray, + eq, + [2, 3, 4], + ) + + Test.run( + __POS_OF__("IteratorObject.filter"), + makeIteratorObject() + ->IteratorObject.filter(value => mod(value, 2) == 1) + ->IteratorObject.toArray, + eq, + [1, 3], + ) + + Test.run( + __POS_OF__("IteratorObject.drop"), + makeIteratorObject()->IteratorObject.drop(1)->IteratorObject.toArray, + eq, + [2, 3], + ) + + Test.run( + __POS_OF__("IteratorObject.take"), + makeIteratorObject()->IteratorObject.take(2)->IteratorObject.toArray, + eq, + [1, 2], + ) + + Test.run( + __POS_OF__("IteratorObject.flatMap"), + makeIteratorObject() + ->IteratorObject.flatMap(value => [value, value + 10]->Array.asIterable) + ->IteratorObject.toArray, + eq, + [1, 11, 2, 12, 3, 13], + ) + + Test.run( + __POS_OF__("IteratorObject.reduce"), + makeIteratorObject()->IteratorObject.reduce((sum, value) => sum + value, ~initialValue=0), + eq, + 6, + ) + + Test.run( + __POS_OF__("IteratorObject.every"), + makeIteratorObject()->IteratorObject.every(value => value > 0), + eq, + true, + ) + + Test.run( + __POS_OF__("IteratorObject.some"), + makeIteratorObject()->IteratorObject.some(value => value == 2), + eq, + true, + ) + + Test.run( + __POS_OF__("IteratorObject.find"), + makeIteratorObject()->IteratorObject.find(value => value == 3), + eq, + Some(3), + ) +} + +Test.run( + __POS_OF__("IteratorObject.toArrayWithMapper (built-in array iterator)"), + [1, 2, 3]->Array.values->IteratorObject.toArrayWithMapper(value => value + 20), + eq, + [21, 22, 23], +) + +let iterator: IterableIterator.t = %raw(` (() => { var array1 = ['a', 'b', 'c']; var iterator1 = array1[Symbol.iterator](); @@ -10,32 +118,256 @@ let iterator: Iterator.t = %raw(` let syncResult = ref(None) -iterator->Iterator.forEach(v => { - if v == "b" { - syncResult.contents = Some("b") - } -}) +switch iterator->IterableIterator.next { +| Yield({value: "a"}) => () +| _ => () +} + +switch iterator->IterableIterator.next { +| Yield({value: "b"}) => syncResult.contents = Some("b") +| _ => () +} Test.run(__POS_OF__("Sync forEach"), syncResult.contents, eq, Some("b")) -let asyncIterator: AsyncIterator.t<(string, string)> = %raw(` +let iteratorProtocol: Iterator.t = %raw(` (() => { - var map1 = new Map(); + var array1 = ['x', 'y']; + var iterator1 = array1[Symbol.iterator](); + return iterator1 + })() +`) + +let protocolResult = ref(None) + +switch iteratorProtocol->Iterator.next { +| Yield({value: "x"}) => protocolResult.contents = Some("x") +| _ => () +} + +Test.run(__POS_OF__("Iterator next"), protocolResult.contents, eq, Some("x")) + +let omittedDoneIterator: Iterator.t = %raw(`({ + step: 0, + next() { + if (this.step === 0) { + this.step = 1 + return {value: 1} + } + return {done: true, value: "done"} + } +})`) + +let omittedDoneResult = ref(None) + +switch omittedDoneIterator->Iterator.next { +| Yield({value: 1}) => omittedDoneResult.contents = Some("yield") +| _ => () +} + +Test.run( + __POS_OF__("Iterator next with omitted done"), + omittedDoneResult.contents, + eq, + Some("yield"), +) + +let createdIterator = { + let current = ref(0) + Iterator.make(() => { + let value = current.contents + current := value + 1 + + if value >= 2 { + Iterator.doneWithValue("done") + } else { + Iterator.value(value) + } + }) +} + +let createdProtocolResult = ref(None) + +switch createdIterator->Iterator.next { +| Yield({value: 0}) => createdProtocolResult.contents = Some("protocol") +| _ => () +} + +Test.run( + __POS_OF__("Creating your own iterator"), + createdProtocolResult.contents, + eq, + Some("protocol"), +) + +let createdIterableIterator = { + let current = ref(0) + IterableIterator.make(() => { + let value = current.contents + current := value + 1 + + if value >= 2 { + Iterator.doneWithValue("done") + } else { + Iterator.value(value) + } + }) +} + +let createdIterableResult = ref(None) + +switch createdIterableIterator->IterableIterator.next { +| Yield({value: 0}) => () +| _ => () +} + +switch createdIterableIterator->IterableIterator.next { +| Yield({value: 1}) => createdIterableResult.contents = Some("iterable") +| _ => () +} + +Test.run( + __POS_OF__("Creating your own iterable iterator"), + createdIterableResult.contents, + eq, + Some("iterable"), +) + +let generatorViaIterator: Generator.t> = %raw(`(function* () { + let sent = yield 1 + return String((sent ?? 0) + 1) +})()`) + +let iteratorNextValueResult = ref(None) + +switch generatorViaIterator->Generator.asIterator->Iterator.nextValue(None) { +| Yield({value: 1}) => () +| _ => () +} + +switch generatorViaIterator->Generator.asIterator->Iterator.nextValue(Some(4)) { +| Return({value: "5"}) => iteratorNextValueResult.contents = Some("nextValue") +| _ => () +} + +Test.run(__POS_OF__("Iterator nextValue"), iteratorNextValueResult.contents, eq, Some("nextValue")) + +Test.run( + __POS_OF__("Generator.asIterable"), + ( + %raw(`(function* () { + yield 1 + yield 2 + })()`): Generator.t + ) + ->Generator.asIterable + ->Array.fromIterable, + eq, + [1, 2], +) + +Test.run( + __POS_OF__("Generator.asIteratorObject"), + ( + %raw(`(function* () { + yield 1 + yield 2 + })()`): Generator.t + ) + ->Generator.asIteratorObject + ->IteratorObject.toArrayWithMapper(value => value * 2), + eq, + [2, 4], +) - map1.set('first', '1'); - map1.set('second', '2'); +Test.run( + __POS_OF__("Generator.asIteratorObject nextValue"), + { + let generatorWithNext: Generator.t = %raw(`(function* () { + let injected = yield 1 + yield injected + 1 + })()`) - var iterator1 = map1[Symbol.iterator](); - return iterator1; + switch generatorWithNext->Generator.next { + | Yield({value: 1}) => + switch generatorWithNext->Generator.asIteratorObject->IteratorObject.nextValue(41) { + | Yield({value: 42}) => Some("nextValue") + | _ => None + } + | _ => None + } + }, + eq, + Some("nextValue"), +) + +let generatorReturnValueResult = ref(None) +let generatorReturnValue: Generator.t = %raw(`(function* () { + yield 1 + return "done" +})()`) + +switch generatorReturnValue->Generator.next { +| Yield({value: 1}) => () +| _ => () +} + +switch generatorReturnValue->Generator.returnValue("stopped") { +| Return({value: "stopped"}) => generatorReturnValueResult.contents = Some("returnValue") +| _ => () +} + +Test.run( + __POS_OF__("Generator.returnValue"), + generatorReturnValueResult.contents, + eq, + Some("returnValue"), +) + +let generatorThrowErrorResult = ref(None) +let generatorThrowError: Generator.t = %raw(`(function* () { + try { + yield 1 + return "done" + } catch (error) { + return error.message + } +})()`) + +switch generatorThrowError->Generator.next { +| Yield({value: 1}) => () +| _ => () +} + +switch generatorThrowError->Generator.throwError(JsExn.anyToExnInternal(JsError.make("boom"))) { +| Return(_) => generatorThrowErrorResult.contents = Some("throwError") +| _ => () +} + +Test.run( + __POS_OF__("Generator.throwError"), + generatorThrowErrorResult.contents, + eq, + Some("throwError"), +) + +let asyncIterableIterator: AsyncIterableIterator.t<(string, string), unit, unit> = %raw(` + (async function* () { + yield ['first', '1'] + yield ['second', '2'] })() `) let asyncResult = ref(None) -await asyncIterator->AsyncIterator.forEach(v => { - switch v { - | Some(("second", _value)) => asyncResult.contents = Some("second") - | _ => () +switch await asyncIterableIterator->AsyncIterableIterator.next { +| Yield({value: ("first", _value)}) => () +| _ => () +} + +await asyncIterableIterator->AsyncIterableIterator.forEach(((key, _value)) => { + if key == "second" { + asyncResult.contents = Some("second") } }) @@ -44,6 +376,8 @@ Test.run(__POS_OF__("Async forEach"), asyncResult.contents, eq, Some("second")) %%private( let asyncResult = ref(None) let count = ref(0) + let asyncIterableIteratorResult = ref(None) + let asyncIterableIteratorCount = ref(0) ) let asyncIterator = AsyncIterator.make(async () => { @@ -51,17 +385,170 @@ let asyncIterator = AsyncIterator.make(async () => { count := currentCount + 1 if currentCount === 3 { - AsyncIterator.done(~finalValue=currentCount) + AsyncIterator.doneWithValue(currentCount) } else { AsyncIterator.value(currentCount) } }) -await asyncIterator->AsyncIterator.forEach(v => { - switch v { - | Some(3) => asyncResult.contents = Some("done") - | _ => Console.log("next..") +await asyncIterator->AsyncIterator.forEach(value => { + if value == 2 { + asyncResult.contents = Some("done") } }) Test.run(__POS_OF__("Creating your own async iterator"), asyncResult.contents, eq, Some("done")) + +let asyncOmittedDoneValues = ref([]) +let asyncOmittedDoneIterator: AsyncIterator.t = %raw(`({ + step: 0, + next() { + if (this.step === 0) { + this.step = 1 + return Promise.resolve({value: 1}) + } + return Promise.resolve({done: true, value: "done"}) + } +})`) + +await asyncOmittedDoneIterator->AsyncIterator.forEach(value => { + asyncOmittedDoneValues := [...asyncOmittedDoneValues.contents, value] +}) + +Test.run( + __POS_OF__("AsyncIterator.forEach with omitted done"), + asyncOmittedDoneValues.contents, + eq, + [1], +) + +let asyncGeneratorNextValue: AsyncGenerator.t< + int, + string, + option, +> = %raw(`(async function* () { + let sent = yield 1 + return String((sent ?? 0) + 1) +})()`) + +let asyncGeneratorNextValueResult = ref(None) + +switch await asyncGeneratorNextValue +->AsyncGenerator.asAsyncIterator +->AsyncIterator.nextValue(None) { +| Yield({value: 1}) => () +| _ => () +} + +switch await asyncGeneratorNextValue->AsyncGenerator.nextValue(Some(4)) { +| Return({value: "5"}) => asyncGeneratorNextValueResult.contents = Some("nextValue") +| _ => () +} + +Test.run( + __POS_OF__("AsyncGenerator.nextValue"), + asyncGeneratorNextValueResult.contents, + eq, + Some("nextValue"), +) + +let asyncGeneratorIterableValues = ref([]) +let asyncGeneratorIterable: AsyncGenerator.t = %raw(`(async function* () { + yield 2 + yield 3 +})()`) + +await asyncGeneratorIterable +->AsyncGenerator.asAsyncIterableIterator +->AsyncIterableIterator.forEach(value => + asyncGeneratorIterableValues := [...asyncGeneratorIterableValues.contents, value] +) + +Test.run( + __POS_OF__("AsyncGenerator.asAsyncIterableIterator"), + asyncGeneratorIterableValues.contents, + eq, + [2, 3], +) + +let _asyncIterableView: AsyncIterable.t = ( + %raw(`(async function* () { + yield 1 + })()`): AsyncGenerator.t +)->AsyncGenerator.asAsyncIterable + +let asyncGeneratorReturnValueResult = ref(None) +let asyncGeneratorReturnValue: AsyncGenerator.t = %raw(`(async function* () { + yield 1 + return "done" +})()`) + +switch await asyncGeneratorReturnValue->AsyncGenerator.next { +| Yield({value: 1}) => () +| _ => () +} + +switch await asyncGeneratorReturnValue->AsyncGenerator.returnValue("stopped") { +| Return({value: "stopped"}) => asyncGeneratorReturnValueResult.contents = Some("returnValue") +| _ => () +} + +Test.run( + __POS_OF__("AsyncGenerator.returnValue"), + asyncGeneratorReturnValueResult.contents, + eq, + Some("returnValue"), +) + +let asyncGeneratorThrowErrorResult = ref(None) +let asyncGeneratorThrowError: AsyncGenerator.t = %raw(`(async function* () { + try { + yield 1 + return "done" + } catch (error) { + return error.message + } +})()`) + +switch await asyncGeneratorThrowError->AsyncGenerator.next { +| Yield({value: 1}) => () +| _ => () +} + +switch await asyncGeneratorThrowError->AsyncGenerator.throwError( + JsExn.anyToExnInternal(JsError.make("boom")), +) { +| Return(_) => asyncGeneratorThrowErrorResult.contents = Some("throwError") +| _ => () +} + +Test.run( + __POS_OF__("AsyncGenerator.throwError"), + asyncGeneratorThrowErrorResult.contents, + eq, + Some("throwError"), +) + +let createdAsyncIterableIterator = AsyncIterableIterator.make(async () => { + let currentCount = asyncIterableIteratorCount.contents + asyncIterableIteratorCount := currentCount + 1 + + if currentCount === 2 { + AsyncIterator.done() + } else { + AsyncIterator.value(currentCount) + } +}) + +await createdAsyncIterableIterator->AsyncIterableIterator.forEach(value => { + if value == 1 { + asyncIterableIteratorResult.contents = Some("iterable") + } +}) + +Test.run( + __POS_OF__("Creating your own async iterable iterator"), + asyncIterableIteratorResult.contents, + eq, + Some("iterable"), +) diff --git a/tests/tests/src/stdlib/Stdlib_StringTests.mjs b/tests/tests/src/stdlib/Stdlib_StringTests.mjs index bdd5fdc03cf..cd25d7f306a 100644 --- a/tests/tests/src/stdlib/Stdlib_StringTests.mjs +++ b/tests/tests/src/stdlib/Stdlib_StringTests.mjs @@ -15,6 +15,20 @@ Test.run([ "String.equal optimization" ], false, eq, false); +Test.run([ + [ + "Stdlib_StringTests.res", + 5, + 13, + 32 + ], + "String.asIterable" +], Array.from("abc"), eq, [ + "a", + "b", + "c" +]); + export { eq, } diff --git a/tests/tests/src/stdlib/Stdlib_StringTests.res b/tests/tests/src/stdlib/Stdlib_StringTests.res index ad1010a3108..f8ca0df1ac3 100644 --- a/tests/tests/src/stdlib/Stdlib_StringTests.res +++ b/tests/tests/src/stdlib/Stdlib_StringTests.res @@ -1,3 +1,9 @@ let eq = (a, b) => a == b Test.run(__POS_OF__("String.equal optimization"), String.equal("one", "three"), eq, false) +Test.run( + __POS_OF__("String.asIterable"), + "abc"->String.asIterable->Array.fromIterable, + eq, + ["a", "b", "c"], +) diff --git a/tests/tests/src/stdlib/Stdlib_TempTests.res b/tests/tests/src/stdlib/Stdlib_TempTests.res index cff0a5aafa6..9f5bbe3738e 100644 --- a/tests/tests/src/stdlib/Stdlib_TempTests.res +++ b/tests/tests/src/stdlib/Stdlib_TempTests.res @@ -160,7 +160,7 @@ Console.info("Symbol") Console.info("---") let x = Symbol.getFor("Foo") Console.log(x) -let array: array = String.getSymbolUnsafe("foo", Symbol.iterator)()->Iterator.toArray +let array: array = String.getSymbolUnsafe("foo", Symbol.iterator)()->IteratorObject.toArray Console.log(array) Console.info("") diff --git a/tests/tests/src/stdlib/Stdlib_TestSuite.mjs b/tests/tests/src/stdlib/Stdlib_TestSuite.mjs index fb60674d6bf..8176f2fe80f 100644 --- a/tests/tests/src/stdlib/Stdlib_TestSuite.mjs +++ b/tests/tests/src/stdlib/Stdlib_TestSuite.mjs @@ -85,14 +85,72 @@ let PatternMatching = Stdlib_DictTests.PatternMatching; let Has = Stdlib_DictTests.Has; +let supportsIteratorHelpers = Stdlib_IteratorTests.supportsIteratorHelpers; + +let _checkIteratorHelperTypes = Stdlib_IteratorTests._checkIteratorHelperTypes; + let iterator = Stdlib_IteratorTests.iterator; let syncResult = Stdlib_IteratorTests.syncResult; +let iteratorProtocol = Stdlib_IteratorTests.iteratorProtocol; + +let protocolResult = Stdlib_IteratorTests.protocolResult; + +let omittedDoneIterator = Stdlib_IteratorTests.omittedDoneIterator; + +let omittedDoneResult = Stdlib_IteratorTests.omittedDoneResult; + +let createdIterator = Stdlib_IteratorTests.createdIterator; + +let createdProtocolResult = Stdlib_IteratorTests.createdProtocolResult; + +let createdIterableIterator = Stdlib_IteratorTests.createdIterableIterator; + +let createdIterableResult = Stdlib_IteratorTests.createdIterableResult; + +let generatorViaIterator = Stdlib_IteratorTests.generatorViaIterator; + +let iteratorNextValueResult = Stdlib_IteratorTests.iteratorNextValueResult; + +let generatorReturnValueResult = Stdlib_IteratorTests.generatorReturnValueResult; + +let generatorReturnValue = Stdlib_IteratorTests.generatorReturnValue; + +let generatorThrowErrorResult = Stdlib_IteratorTests.generatorThrowErrorResult; + +let generatorThrowError = Stdlib_IteratorTests.generatorThrowError; + +let asyncIterableIterator = Stdlib_IteratorTests.asyncIterableIterator; + let asyncResult = Stdlib_IteratorTests.asyncResult; let asyncIterator = Stdlib_IteratorTests.asyncIterator; +let asyncOmittedDoneValues = Stdlib_IteratorTests.asyncOmittedDoneValues; + +let asyncOmittedDoneIterator = Stdlib_IteratorTests.asyncOmittedDoneIterator; + +let asyncGeneratorNextValue = Stdlib_IteratorTests.asyncGeneratorNextValue; + +let asyncGeneratorNextValueResult = Stdlib_IteratorTests.asyncGeneratorNextValueResult; + +let asyncGeneratorIterableValues = Stdlib_IteratorTests.asyncGeneratorIterableValues; + +let asyncGeneratorIterable = Stdlib_IteratorTests.asyncGeneratorIterable; + +let _asyncIterableView = Stdlib_IteratorTests._asyncIterableView; + +let asyncGeneratorReturnValueResult = Stdlib_IteratorTests.asyncGeneratorReturnValueResult; + +let asyncGeneratorReturnValue = Stdlib_IteratorTests.asyncGeneratorReturnValue; + +let asyncGeneratorThrowErrorResult = Stdlib_IteratorTests.asyncGeneratorThrowErrorResult; + +let asyncGeneratorThrowError = Stdlib_IteratorTests.asyncGeneratorThrowError; + +let createdAsyncIterableIterator = Stdlib_IteratorTests.createdAsyncIterableIterator; + let eq = Stdlib_RegExpTest.eq; export { @@ -131,10 +189,39 @@ export { intDict, PatternMatching, Has, + supportsIteratorHelpers, + _checkIteratorHelperTypes, iterator, syncResult, + iteratorProtocol, + protocolResult, + omittedDoneIterator, + omittedDoneResult, + createdIterator, + createdProtocolResult, + createdIterableIterator, + createdIterableResult, + generatorViaIterator, + iteratorNextValueResult, + generatorReturnValueResult, + generatorReturnValue, + generatorThrowErrorResult, + generatorThrowError, + asyncIterableIterator, asyncResult, asyncIterator, + asyncOmittedDoneValues, + asyncOmittedDoneIterator, + asyncGeneratorNextValue, + asyncGeneratorNextValueResult, + asyncGeneratorIterableValues, + asyncGeneratorIterable, + _asyncIterableView, + asyncGeneratorReturnValueResult, + asyncGeneratorReturnValue, + asyncGeneratorThrowErrorResult, + asyncGeneratorThrowError, + createdAsyncIterableIterator, eq, } /* Stdlib_IntTests Not a pure module */