Something went wrong. Try again.
opencode v2 mirror
Something went wrong. Try again.
TypeScript
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349import { Cause, Effect, Exit } from "effect"import { applyCollectionCallback } from "../interpreter/callback.js"import type { Interpreter } from "../interpreter/interpreter.js"import { rangeError, typeError } from "../interpreter/model.js"import { constructor, fn, methods, receiver, requiresNew } from "../interpreter/native.js"import { Arr, coerceToNumber, type Cursor, define, hasPrototype, hidden, IteratorObj, Obj, record, type Step, type Value,} from "../interpreter/objects.js"import { describeValue } from "../interpreter/references.js"
const finished: Step = { done: true, value: undefined }
// Every built-in iterator and helper shares the Iterator prototype; JS gives each collection its own, which is only// observable through getPrototypeOf.export const iteratorGlobals = <R>(ctx: Interpreter<R>) => { const builtins = ctx.builtins const proto = builtins.Iterator const method = (name: string) => `Iterator.prototype.${name}`
// A step that runs program code: when it throws, close the source first, as IteratorClose does. const guarded = <A>(source: Cursor<R>, body: Effect.Effect<A, unknown, R>) => Effect.flatMap(Effect.exit(body), (exit) => { if (Exit.isSuccess(exit)) return Effect.succeed(exit.value) if (Cause.hasInterruptsOnly(exit.cause)) return Effect.failCause(exit.cause) return Effect.andThen(Effect.exit(source.close), Effect.failCause(exit.cause)) })
// A lazy helper: `pull` advances it once. Once it reports done, throws, or is closed, it stays done. A callback // that re-enters its own helper is a TypeError, as for a running generator. const helper = (source: Cursor<R>, pull: Effect.Effect<Step, unknown, R>, close = source.close) => { let done = false let running = false const enter = () => { if (running) throw typeError("Iterator helper is already running.") running = true } return new IteratorObj(builtins.IteratorHelper, { next: Effect.suspend(() => { if (done) return Effect.succeed(finished) enter() return Effect.flatMap(Effect.exit(pull), (exit) => { running = false done = Exit.isSuccess(exit) ? exit.value.done : true return exit }) }), close: Effect.suspend(() => { if (done) return Effect.void enter() done = true return Effect.ensuring( close, Effect.sync(() => { running = false }), ) }), }) }
// GetIteratorFlattenable: an iterable by `[Symbol.iterator]`, otherwise the object itself as an iterator. const flattenable = (value: Value, name: string, strings: boolean) => Effect.gen(function* () { if (typeof value === "string" ? !strings : !(value instanceof Obj)) { throw typeError(`${name} expects an iterable or iterator, received ${describeValue(value)}.`) } return (yield* ctx.iterate(value)) ?? ctx.iterateDirect(value) })
const limit = (value: Value, name: string) => { const count = Math.trunc(coerceToNumber(value)) if (Number.isNaN(count) || count < 0) { throw rangeError(`${method(name)} expects a non-negative count, received ${count}.`) } return count }
methods(builtins, proto, [ [ "next", 0, (thisValue) => Effect.map(receiver(IteratorObj, thisValue, method("next")).cursor.next, (step) => record(builtins.Object, { value: step.value, done: step.done }), ), ], [ "map", 1, (thisValue, args) => { const source = ctx.iterateDirect(thisValue) const apply = applyCollectionCallback(ctx, args[0], method("map")) let counter = 0 return helper( source, Effect.gen(function* () { const step = yield* source.next if (step.done) return finished return { done: false, value: yield* guarded(source, apply([step.value, counter++])) } }), ) }, ], [ "filter", 1, (thisValue, args) => { const source = ctx.iterateDirect(thisValue) const apply = applyCollectionCallback(ctx, args[0], method("filter")) let counter = 0 return helper( source, Effect.gen(function* () { while (true) { const step = yield* source.next if (step.done) return finished if (yield* guarded(source, apply([step.value, counter++]))) return step } }), ) }, ], [ "take", 1, (thisValue, args) => { const source = ctx.iterateDirect(thisValue) let remaining = limit(args[0], "take") return helper( source, Effect.gen(function* () { if (remaining === 0) { yield* source.close return finished } remaining -= 1 return yield* source.next }), ) }, ], [ "drop", 1, (thisValue, args) => { const source = ctx.iterateDirect(thisValue) let remaining = limit(args[0], "drop") return helper( source, Effect.gen(function* () { while (remaining > 0) { remaining -= 1 const step = yield* source.next if (step.done) return finished } return yield* source.next }), ) }, ], [ "flatMap", 1, (thisValue, args) => { const source = ctx.iterateDirect(thisValue) const apply = applyCollectionCallback(ctx, args[0], method("flatMap")) let counter = 0 let inner: Cursor<R> | undefined return helper( source, Effect.gen(function* () { while (true) { if (inner !== undefined) { const step = yield* guarded(source, inner.next) if (!step.done) return step inner = undefined } const step = yield* source.next if (step.done) return finished inner = yield* guarded( source, Effect.flatMap(apply([step.value, counter++]), (mapped) => flattenable(mapped, method("flatMap"), false), ), ) } }), Effect.suspend(() => (inner === undefined ? source.close : Effect.andThen(inner.close, source.close))), ) }, ], [ "reduce", 1, (thisValue, args) => { const source = ctx.iterateDirect(thisValue) const apply = applyCollectionCallback(ctx, args[0], method("reduce")) return Effect.gen(function* () { let counter = 0 let accumulator = args[1] if (args.length < 2) { const first = yield* source.next if (first.done) throw typeError("Iterator.prototype.reduce of an empty iterator with no initial value.") accumulator = first.value counter = 1 } while (true) { const step = yield* source.next if (step.done) return accumulator accumulator = yield* guarded(source, apply([accumulator, step.value, counter++])) } }) }, ], [ "toArray", 0, (thisValue) => { const source = ctx.iterateDirect(thisValue) return Effect.gen(function* () { const items: Array<Value> = [] while (true) { const step = yield* source.next if (step.done) return new Arr(builtins.Array, items) items.push(step.value) } }) }, ], [ "forEach", 1, (thisValue, args) => { const source = ctx.iterateDirect(thisValue) const apply = applyCollectionCallback(ctx, args[0], method("forEach")) return Effect.gen(function* () { let counter = 0 while (true) { const step = yield* source.next if (step.done) return undefined yield* guarded(source, apply([step.value, counter++])) } }) }, ], [ "some", 1, (thisValue, args) => { const source = ctx.iterateDirect(thisValue) const apply = applyCollectionCallback(ctx, args[0], method("some")) return Effect.gen(function* () { let counter = 0 while (true) { const step = yield* source.next if (step.done) return false if (yield* guarded(source, apply([step.value, counter++]))) { yield* source.close return true } } }) }, ], [ "every", 1, (thisValue, args) => { const source = ctx.iterateDirect(thisValue) const apply = applyCollectionCallback(ctx, args[0], method("every")) return Effect.gen(function* () { let counter = 0 while (true) { const step = yield* source.next if (step.done) return true if (!(yield* guarded(source, apply([step.value, counter++])))) { yield* source.close return false } } }) }, ], [ "find", 1, (thisValue, args) => { const source = ctx.iterateDirect(thisValue) const apply = applyCollectionCallback(ctx, args[0], method("find")) return Effect.gen(function* () { let counter = 0 while (true) { const step = yield* source.next if (step.done) return undefined if (yield* guarded(source, apply([step.value, counter++]))) { yield* source.close return step.value } } }) }, ], ])
// Helpers and `Iterator.from` wrappers can be closed; collection iterators, as in JS, cannot. methods(builtins, builtins.IteratorHelper, [ [ "return", 0, (thisValue) => Effect.map(receiver(IteratorObj, thisValue, "Iterator.prototype.return").cursor.close, () => record(builtins.Object, { value: undefined, done: true }), ), ], ])
const iterator = constructor<R>(builtins, proto, { name: "Iterator", length: 0, call: requiresNew("Iterator"), construct: () => Effect.sync(() => { throw typeError("Iterator is abstract; use Iterator.from(...) or a built-in iterator.") }), }) define( iterator, "from", fn(builtins, "from", 1, (_, args) => Effect.gen(function* () { if (args[0] instanceof Obj && hasPrototype(args[0], proto)) return args[0] return new IteratorObj(builtins.IteratorHelper, yield* flattenable(args[0], "Iterator.from", true)) }), ), hidden, ) return iterator}