mirror of
https://github.com/bendtherules/ask262.git
synced 2026-08-18 21:31:46 +00:00
Merge commit '6e92d2345e8231a44556ce7d416451f5f3e6c398' as 'engine262'
This commit is contained in:
@@ -0,0 +1,212 @@
|
||||
import { Value } from '../value.mts';
|
||||
import {
|
||||
NormalCompletion,
|
||||
Q, X,
|
||||
} from '../completion.mts';
|
||||
import { Evaluate, type PlainEvaluator } from '../evaluator.mts';
|
||||
import {
|
||||
StringValue,
|
||||
IsAnonymousFunctionDefinition,
|
||||
} from '../static-semantics/all.mts';
|
||||
import type { ParseNode } from '../parser/ParseNode.mts';
|
||||
import { __ts_cast__ } from '../helpers.mts';
|
||||
import { NamedEvaluation, BindingInitialization } from './all.mts';
|
||||
import {
|
||||
Assert,
|
||||
GetValue,
|
||||
InitializeReferencedBinding,
|
||||
IteratorStep,
|
||||
PutValue,
|
||||
ResolveBinding,
|
||||
ArrayCreate,
|
||||
CreateDataPropertyOrThrow,
|
||||
ToString,
|
||||
F,
|
||||
type IteratorRecord,
|
||||
|
||||
IteratorStepValue,
|
||||
UndefinedValue, type EnvironmentRecord, type FunctionDeclaration,
|
||||
} from '#self';
|
||||
|
||||
/** https://tc39.es/ecma262/#sec-function-definitions-runtime-semantics-iteratorbindinginitialization */
|
||||
// FormalParameters :
|
||||
// [empty]
|
||||
// FormalParameterList `,` FunctionRestParameter
|
||||
export function* IteratorBindingInitialization_FormalParameters(FormalParameters: ParseNode.FormalParameters, iteratorRecord: IteratorRecord, environment: EnvironmentRecord | UndefinedValue) {
|
||||
if (FormalParameters.length === 0) {
|
||||
// 1. Return NormalCompletion(empty).
|
||||
return NormalCompletion(undefined);
|
||||
}
|
||||
|
||||
for (const FormalParameter of FormalParameters.slice(0, -1)) {
|
||||
Q(yield* IteratorBindingInitialization_FormalParameter(FormalParameter, iteratorRecord, environment));
|
||||
}
|
||||
|
||||
const last = FormalParameters[FormalParameters.length - 1];
|
||||
if (last.type === 'BindingRestElement') {
|
||||
return yield* IteratorBindingInitialization_FunctionRestParameter(last, iteratorRecord, environment);
|
||||
}
|
||||
return yield* IteratorBindingInitialization_FormalParameter(last, iteratorRecord, environment);
|
||||
}
|
||||
|
||||
// FormalParameter : BindingElement
|
||||
function IteratorBindingInitialization_FormalParameter(BindingElement: ParseNode.FormalParametersElement, iteratorRecord: IteratorRecord, environment: EnvironmentRecord | UndefinedValue) {
|
||||
// TODO
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
return IteratorBindingInitialization_BindingElement(BindingElement as any, iteratorRecord, environment);
|
||||
}
|
||||
|
||||
// FunctionRestParameter : BindingRestElement
|
||||
function IteratorBindingInitialization_FunctionRestParameter(FunctionRestParameter: ParseNode.FunctionRestParameter, iteratorRecord: IteratorRecord, environment: EnvironmentRecord | UndefinedValue) {
|
||||
return IteratorBindingInitialization_BindingRestElement(FunctionRestParameter, iteratorRecord, environment);
|
||||
}
|
||||
|
||||
// BindingElement :
|
||||
// SingleNameBinding
|
||||
// BindingPattern
|
||||
function IteratorBindingInitialization_BindingElement(BindingElement: ParseNode.BindingElement, iteratorRecord: IteratorRecord, environment: EnvironmentRecord | UndefinedValue) {
|
||||
if ('BindingPattern' in BindingElement) {
|
||||
return IteratorBindingInitialization_BindingPattern(BindingElement, iteratorRecord, environment);
|
||||
}
|
||||
return IteratorBindingInitialization_SingleNameBinding(BindingElement, iteratorRecord, environment);
|
||||
}
|
||||
|
||||
// SingleNameBinding : BindingIdentifier Initializer?
|
||||
function* IteratorBindingInitialization_SingleNameBinding({ BindingIdentifier, Initializer }: ParseNode.SingleNameBinding, iteratorRecord: IteratorRecord, environment: EnvironmentRecord | UndefinedValue): PlainEvaluator {
|
||||
// 1. Let bindingId be StringValue of BindingIdentifier.
|
||||
const bindingId = StringValue(BindingIdentifier);
|
||||
// 2. Let lhs be ? ResolveBinding(bindingId, environment).
|
||||
const lhs = Q(yield* ResolveBinding(bindingId, environment, BindingIdentifier.strict));
|
||||
let v: Value = Value.undefined;
|
||||
// 3. If iteratorRecord.[[Done]] is false, then
|
||||
if (iteratorRecord.Done === Value.false) {
|
||||
// a. Let next be ? IteratorStepValue(iteratorRecord).
|
||||
const next = Q(yield* IteratorStepValue(iteratorRecord));
|
||||
// d. If next is not DONE,
|
||||
if (next !== 'done') {
|
||||
v = next;
|
||||
}
|
||||
}
|
||||
// 5. If Initializer is present and v is undefined, then
|
||||
if (Initializer && v === Value.undefined) {
|
||||
if (IsAnonymousFunctionDefinition(Initializer)) {
|
||||
v = Q(yield* NamedEvaluation(Initializer as FunctionDeclaration, bindingId));
|
||||
} else {
|
||||
const defaultValue = Q(yield* Evaluate(Initializer));
|
||||
v = Q(yield* GetValue(defaultValue));
|
||||
}
|
||||
}
|
||||
// 6. If environment is undefined, return ? PutValue(lhs, v).
|
||||
if (environment === Value.undefined) {
|
||||
return Q(yield* PutValue(lhs, v));
|
||||
}
|
||||
// 7. Return InitializeReferencedBinding(lhs, v).
|
||||
return yield* InitializeReferencedBinding(lhs, X(v));
|
||||
}
|
||||
|
||||
// BindingRestElement :
|
||||
// `...` BindingIdentifier
|
||||
// `...` BindingPattern
|
||||
function* IteratorBindingInitialization_BindingRestElement({ BindingIdentifier, BindingPattern }: ParseNode.BindingRestElement, iteratorRecord: IteratorRecord, environment: EnvironmentRecord | UndefinedValue) {
|
||||
if (BindingIdentifier) {
|
||||
// 1. Let lhs be ? ResolveBinding(StringValue of BindingIdentifier, environment).
|
||||
const lhs = Q(yield* ResolveBinding(StringValue(BindingIdentifier), environment, BindingIdentifier.strict));
|
||||
// 2. Let A be ! ArrayCreate(0).
|
||||
const A = X(ArrayCreate(0));
|
||||
// 3. Let n be 0.
|
||||
let n = 0;
|
||||
// 4. Repeat,
|
||||
while (true) {
|
||||
let next: 'done' | Value = 'done';
|
||||
// a. If iteratorRecord.[[Done]] is false, then
|
||||
if (iteratorRecord.Done === Value.false) {
|
||||
// i. Let next be ? IteratorStepValue(iteratorRecord).
|
||||
next = Q(yield* IteratorStepValue(iteratorRecord));
|
||||
}
|
||||
if (next === 'done') {
|
||||
// i. If environment is undefined, return ? PutValue(lhs, A).
|
||||
if (environment === Value.undefined) {
|
||||
return Q(yield* PutValue(lhs, A));
|
||||
}
|
||||
// ii. Return InitializeReferencedBinding(lhs, A).
|
||||
return yield* InitializeReferencedBinding(lhs, A);
|
||||
}
|
||||
// f. Perform ! CreateDataPropertyOrThrow(A, ! ToString(𝔽(n)), next).
|
||||
X(CreateDataPropertyOrThrow(A, X(ToString(F(n))), next));
|
||||
// g. Set n to n + 1.
|
||||
n += 1;
|
||||
}
|
||||
} else {
|
||||
// 1. Let A be ! ArrayCreate(0).
|
||||
const A = X(ArrayCreate(0));
|
||||
// 2. Let n be 0.
|
||||
let n = 0;
|
||||
// 3. Repeat,
|
||||
while (true) {
|
||||
let next: 'done' | Value = 'done';
|
||||
// a. If iteratorRecord.[[Done]] is false, then
|
||||
if (iteratorRecord.Done === Value.false) {
|
||||
// i. Let next be ? IteratorStepValue(iteratorRecord).
|
||||
next = Q(yield* IteratorStepValue(iteratorRecord));
|
||||
}
|
||||
// b. If next is done, then
|
||||
if (next === 'done') {
|
||||
// i. Return the result of performing BindingInitialization of BindingPattern with A and environment as the arguments.
|
||||
return yield* BindingInitialization(BindingPattern!, A, environment);
|
||||
}
|
||||
// f. Perform ! CreateDataPropertyOrThrow(A, ! ToString(𝔽(n)), next).
|
||||
X(CreateDataPropertyOrThrow(A, X(ToString(F(n))), Q(next)));
|
||||
// g. Set n to n + 1.
|
||||
n += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function* IteratorBindingInitialization_BindingPattern({ BindingPattern, Initializer }: ParseNode.BindingElement, iteratorRecord: IteratorRecord, environment: EnvironmentRecord | UndefinedValue) {
|
||||
let v: Value = Value.undefined;
|
||||
// 1. If iteratorRecord.[[Done]] is false, then
|
||||
if (iteratorRecord.Done === Value.false) {
|
||||
// a. Let next be ? IteratorStepValue(iteratorRecord).
|
||||
const next = Q(yield* IteratorStepValue(iteratorRecord));
|
||||
if (next !== 'done') {
|
||||
v = next;
|
||||
}
|
||||
}
|
||||
// 3. If Initializer is present and v is undefined, then
|
||||
if (Initializer && v instanceof UndefinedValue) {
|
||||
// a. Let defaultValue be the result of evaluating Initializer.
|
||||
const defaultValue = Q(yield* Evaluate(Initializer));
|
||||
// b. Set v to ? GetValue(defaultValue).
|
||||
v = Q(yield* GetValue(defaultValue));
|
||||
}
|
||||
// 4. Return the result of performing BindingInitialization of BindingPattern with v and environment as the arguments.
|
||||
return yield* BindingInitialization(BindingPattern, X(v), environment);
|
||||
}
|
||||
|
||||
function* IteratorDestructuringAssignmentEvaluation(node: ParseNode.Elision, iteratorRecord: IteratorRecord): PlainEvaluator {
|
||||
Assert(node.type === 'Elision');
|
||||
// 1. If iteratorRecord.[[Done]] is false, then
|
||||
if (iteratorRecord.Done === Value.false) {
|
||||
// a. Perform ? IteratorStep(iteratorRecord).
|
||||
Q(yield* IteratorStep(iteratorRecord));
|
||||
}
|
||||
// 2. Return NormalCompletion(empty).
|
||||
return NormalCompletion(undefined);
|
||||
}
|
||||
|
||||
export function* IteratorBindingInitialization_ArrayBindingPattern({ BindingElementList, BindingRestElement }: ParseNode.ArrayBindingPattern, iteratorRecord: IteratorRecord, environment: EnvironmentRecord | UndefinedValue): PlainEvaluator {
|
||||
for (const BindingElement of BindingElementList) {
|
||||
if (BindingElement.type === 'Elision') {
|
||||
Q(yield* IteratorDestructuringAssignmentEvaluation(BindingElement, iteratorRecord));
|
||||
} else {
|
||||
// TODO
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
Q(yield* IteratorBindingInitialization_BindingElement(BindingElement as any, iteratorRecord, environment));
|
||||
}
|
||||
}
|
||||
|
||||
if (BindingRestElement) {
|
||||
return Q(yield* IteratorBindingInitialization_BindingRestElement(BindingRestElement, iteratorRecord, environment));
|
||||
}
|
||||
return NormalCompletion(undefined);
|
||||
}
|
||||
Reference in New Issue
Block a user