import { surroundingAgent } from '../host-defined/engine.mts'; import { JSStringValue, NullValue, ObjectValue, Value, type Arguments, type FunctionCallContext, } from '../value.mts'; import { Q, X, type ValueCompletion, type ValueEvaluator, } from '../completion.mts'; import { RegExpExec, AdvanceStringIndex } from './RegExpPrototype.mts'; import { bootstrapPrototype } from './bootstrap.mts'; import { CreateIteratorFromClosure, GeneratorResume, ToString, ToLength, Get, Set, Yield, F, R as MathematicalValue, Realm, type GeneratorObject, } from '#self'; /** https://tc39.es/ecma262/#sec-createregexpstringiterator */ export function CreateRegExpStringIterator(R: ObjectValue, S: JSStringValue, global: boolean, fullUnicode: boolean): ValueCompletion { // 4. Let closure be a new Abstract Closure with no parameters that captures R, S, global, and fullUnicode and performs the following steps when called: const closure = function* closure(): ValueEvaluator { // a. Repeat, while (true) { // i. Let match be ? RegExpExec(R, S). const match = Q(yield* RegExpExec(R, S)); // ii. If match is null, return undefined. if (match instanceof NullValue) { return Value.undefined; } // iii. If global is false, then if (!global) { // 1. Perform ? Yield(match). Q(yield* Yield(match)); // 2. Return undefined. return Value.undefined; } // iv. Let matchStr be ? ToString(? Get(match, "0")). const matchStr = Q(yield* ToString(Q(yield* Get(match, Value('0'))))); // v. If matchStr is the empty String, then if (matchStr.stringValue() === '') { // i. Let thisIndex be ℝ(? ToLength(? Get(R, "lastIndex"))). const thisIndex = MathematicalValue(Q(yield* ToLength(Q(yield* Get(R, Value('lastIndex')))))); // ii. Let nextIndex be ! AdvanceStringIndex(S, thisIndex, fullUnicode). const nextIndex = X(AdvanceStringIndex(S, thisIndex, fullUnicode)); // iii. Perform ? Set(R, "lastIndex", 𝔽(nextIndex), true). Q(yield* Set(R, Value('lastIndex'), F(nextIndex), Value.true)); } // vi. Perform ? Yield(match). Q(yield* Yield(match)); } }; // 4. Return ! CreateIteratorFromClosure(closure, "%RegExpStringIteratorPrototype%", %RegExpStringIteratorPrototype%). return X(CreateIteratorFromClosure(closure, Value('%RegExpStringIteratorPrototype%'), surroundingAgent.intrinsic('%RegExpStringIteratorPrototype%'))); } /** https://tc39.es/ecma262/#sec-%regexpstringiteratorprototype%.next */ function* RegExpStringIteratorPrototype_next(_args: Arguments, { thisValue }: FunctionCallContext): ValueEvaluator { // 1. Return ? GeneratorResume(this value, empty, "%RegExpStringIteratorPrototype%"). return Q(yield* GeneratorResume(thisValue, undefined, Value('%RegExpStringIteratorPrototype%'))); } export function bootstrapRegExpStringIteratorPrototype(realmRec: Realm) { const proto = bootstrapPrototype(realmRec, [ ['next', RegExpStringIteratorPrototype_next, 0], ], realmRec.Intrinsics['%Iterator.prototype%'], 'RegExp String Iterator'); realmRec.Intrinsics['%RegExpStringIteratorPrototype%'] = proto; }