Merge commit '6e92d2345e8231a44556ce7d416451f5f3e6c398' as 'engine262'

This commit is contained in:
2026-03-27 10:07:29 +05:30
433 changed files with 90478 additions and 0 deletions
@@ -0,0 +1,306 @@
import { surroundingAgent } from '../host-defined/engine.mts';
import {
JSStringValue, ReferenceRecord, Value, type PropertyKeyValue,
} from '../value.mts';
import {
IsAnonymousFunctionDefinition,
IsIdentifierRef,
StringValue,
type FunctionDeclaration,
} from '../static-semantics/all.mts';
import {
Evaluate, type PlainEvaluator, type StatementEvaluator,
} from '../evaluator.mts';
import {
Q, X,
Completion,
AbruptCompletion,
NormalCompletion,
EnsureCompletion,
} from '../completion.mts';
import { OutOfRange } from '../helpers.mts';
import type { ParseNode } from '../parser/ParseNode.mts';
import {
Evaluate_PropertyName,
NamedEvaluation,
refineLeftHandSideExpression,
} from './all.mts';
import {
ArrayCreate,
CopyDataProperties,
CreateDataPropertyOrThrow,
GetIterator,
GetV,
GetValue,
IteratorClose,
IteratorStep,
OrdinaryObjectCreate,
PutValue,
ResolveBinding,
RequireObjectCoercible,
ToString,
F,
Assert,
type IteratorRecord,
IteratorStepValue,
} from '#self';
// ObjectAssignmentPattern :
// `{` `}`
// `{` AssignmentPropertyList `}`
// `{` AssignmentPropertyList `,` `}`
// `{` AssignmentPropertyList `,` AssignmentRestProperty? `}`
function* DestructuringAssignmentEvaluation_ObjectAssignmentPattern({ AssignmentPropertyList, AssignmentRestProperty }: ParseNode.ObjectAssignmentPattern, value: Value): PlainEvaluator {
// 1. Perform ? RequireObjectCoercible(value).
Q(RequireObjectCoercible(value));
// 2. Perform ? PropertyDestructuringAssignmentEvaluation for AssignmentPropertyList using value as the argument.
const excludedNames: readonly PropertyKeyValue[] = Q(yield* PropertyDestructuringAssignmentEvaluation(AssignmentPropertyList, value));
if (AssignmentRestProperty) {
Q(yield* RestDestructuringAssignmentEvaluation(AssignmentRestProperty, value, excludedNames));
}
// 3. Return NormalCompletion(empty).
return NormalCompletion(undefined);
}
/** https://tc39.es/ecma262/#sec-runtime-semantics-restdestructuringassignmentevaluation */
// AssignmentRestProperty : `...` DestructuringAssignmentTarget
function* RestDestructuringAssignmentEvaluation({ DestructuringAssignmentTarget }: ParseNode.AssignmentRestProperty, value: Value, excludedNames: readonly PropertyKeyValue[]): StatementEvaluator {
// 1. Let lref be the result of evaluating DestructuringAssignmentTarget.
const lref = Q(yield* Evaluate(DestructuringAssignmentTarget));
Q(lref);
// 3. Let restObj be OrdinaryObjectCreate(%Object.prototype%).
const restObj = OrdinaryObjectCreate(surroundingAgent.intrinsic('%Object.prototype%'));
// 4. Perform ? CopyDataProperties(restObj, value, excludedNames).
Q(yield* CopyDataProperties(restObj, value, excludedNames));
// 5. Return PutValue(lref, restObj).
return yield* PutValue(lref, restObj);
}
function* PropertyDestructuringAssignmentEvaluation(AssignmentPropertyList: ParseNode.ObjectAssignmentPattern['AssignmentPropertyList'], value: Value): PlainEvaluator<PropertyKeyValue[]> {
const propertyNames: PropertyKeyValue[] = [];
for (const AssignmentProperty of AssignmentPropertyList) {
if ('IdentifierReference' in AssignmentProperty) {
// 1. Let P be StringValue of IdentifierReference.
const P = StringValue(AssignmentProperty.IdentifierReference);
// 2. Let lref be ? ResolveBinding(P).
const lref = Q(yield* ResolveBinding(P, undefined, AssignmentProperty.IdentifierReference.strict));
// 3. Let v be ? GetV(value, P).
let v = Q(yield* GetV(value, P));
// 4. If Initializer? is present and v is undefined, then
if (AssignmentProperty.Initializer && v === Value.undefined) {
// a. If IsAnonymousFunctionDefinition(Initializer) is true, then
if (IsAnonymousFunctionDefinition(AssignmentProperty.Initializer)) {
// i. Set v to the result of performing NamedEvaluation for Initializer with argument P.
v = Q(yield* NamedEvaluation(AssignmentProperty.Initializer as FunctionDeclaration, P));
} else { // b. Else,
// i. Let defaultValue be the result of evaluating Initializer.
const defaultValue = Q(yield* Evaluate(AssignmentProperty.Initializer));
// ii. Set v to ? GetValue(defaultValue)
v = Q(yield* GetValue(defaultValue));
}
}
// 5. Perform ? PutValue(lref, v).
Q(yield* PutValue(lref, v));
// 6. Return a new List containing P.
propertyNames.push(P);
} else {
Assert('PropertyName' in AssignmentProperty);
// 1. Let name be the result of evaluating PropertyName.
const name = yield* Evaluate_PropertyName(AssignmentProperty.PropertyName!);
Q(name);
// 3. Perform ? KeyedDestructuringAssignmentEvaluation of AssignmentElement with value and name as the arguments.
Q(yield* KeyedDestructuringAssignmentEvaluation(AssignmentProperty.AssignmentElement, value, name as PropertyKeyValue));
// 4. Return a new List containing name.
propertyNames.push(name as PropertyKeyValue);
}
}
return propertyNames;
}
// AssignmentElement : DestructuringAssignmentTarget Initializer?
function* KeyedDestructuringAssignmentEvaluation({
DestructuringAssignmentTarget,
Initializer,
}: ParseNode.AssignmentElement, value: Value, propertyName: PropertyKeyValue) {
// 1. If DestructuringAssignmentTarget is neither an ObjectLiteral nor an ArrayLiteral, then
let lref;
if (DestructuringAssignmentTarget.type !== 'ObjectLiteral'
&& DestructuringAssignmentTarget.type !== 'ArrayLiteral') {
// a. Let lref be the result of evaluating DestructuringAssignmentTarget.
lref = Q(yield* Evaluate(DestructuringAssignmentTarget));
}
// 2. Let v be ? GetV(value, propertyName).
const v = Q(yield* GetV(value, propertyName));
// 3. If Initializer is present and v is undefined, then
let rhsValue: Value;
if (Initializer && v === Value.undefined) {
// a. If IsAnonymousFunctionDefinition(Initializer) and IsIdentifierRef of DestructuringAssignmentTarget are both true, then
if (IsAnonymousFunctionDefinition(Initializer) && IsIdentifierRef(DestructuringAssignmentTarget)) {
// i. Let rhsValue be NamedEvaluation of Initializer with argument GetReferencedName(lref).
rhsValue = Q(yield* NamedEvaluation(Initializer as FunctionDeclaration, (lref as ReferenceRecord).ReferencedName as JSStringValue));
} else {
// i. Let defaultValue be the result of evaluating Initializer.
const defaultValue = Q(yield* Evaluate(Initializer));
// ii. Let rhsValue be ? GetValue(defaultValue).
rhsValue = Q(yield* GetValue(defaultValue));
}
} else { // 4. Else, let rhsValue be v.
rhsValue = v;
}
// 5. If DestructuringAssignmentTarget is an ObjectLiteral or an ArrayLiteral, then
if (DestructuringAssignmentTarget.type === 'ObjectLiteral'
|| DestructuringAssignmentTarget.type === 'ArrayLiteral') {
// a. Let assignmentPattern be the AssignmentPattern that is covered by DestructuringAssignmentTarget.
const assignmentPattern = refineLeftHandSideExpression(DestructuringAssignmentTarget) as ParseNode.ObjectAssignmentPattern | ParseNode.ArrayAssignmentPattern;
// b. Return the result of performing DestructuringAssignmentEvaluation of assignmentPattern with rhsValue as the argument.
return yield* DestructuringAssignmentEvaluation(assignmentPattern, X(rhsValue));
}
// 6. Return ? PutValue(lref, rhsValue).
return Q(yield* PutValue(X(lref)!, rhsValue));
}
// ArrayAssignmentPattern :
// `[` `]`
// `[` AssignmentElementList `]`
// `[` AssignmentElementList `,` AssignmentRestElement? `]`
function* DestructuringAssignmentEvaluation_ArrayAssignmentPattern({ AssignmentElementList, AssignmentRestElement }: ParseNode.ArrayAssignmentPattern, value: Value) {
// 1. Let iteratorRecord be ? GetIterator(value).
const iteratorRecord = Q(yield* GetIterator(value, 'sync'));
// 2. Let status be IteratorDestructuringAssignmentEvaluation of AssignmentElementList with argument iteratorRecord.
let status = EnsureCompletion(yield* IteratorDestructuringAssignmentEvaluation(AssignmentElementList, iteratorRecord));
// 3. If status is an abrupt completion, then
if (status instanceof AbruptCompletion) {
// a. If iteratorRecord.[[Done]] is false, return ? IteratorClose(iteratorRecord, status).
if (iteratorRecord.Done === Value.false) {
return Q(yield* IteratorClose(iteratorRecord, status));
}
// b. Return Completion(status).
return status;
}
// 4. If Elision is present, then
// ...
// 5. If AssignmentRestElement is present, then
if (AssignmentRestElement) {
// a. Set status to the result of performing IteratorDestructuringAssignmentEvaluation of AssignmentRestElement with iteratorRecord as the argument.
status = EnsureCompletion(yield* IteratorDestructuringAssignmentEvaluation(AssignmentRestElement, iteratorRecord));
}
// 6. If iteratorRecord.[[Done]] is false, return ? IteratorClose(iteratorRecord, status).
if (iteratorRecord.Done === Value.false) {
return Q(yield* IteratorClose(iteratorRecord, status));
}
return Completion(status);
}
function* IteratorDestructuringAssignmentEvaluation(node: ParseNode.AssignmentElisionElement[] | ParseNode.AssignmentElisionElement | ParseNode.AssignmentRestElement, iteratorRecord: IteratorRecord): StatementEvaluator {
if (Array.isArray(node)) {
for (const n of node) {
Q(yield* IteratorDestructuringAssignmentEvaluation(n, iteratorRecord));
}
return NormalCompletion(undefined);
}
switch (node.type) {
case '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);
case 'AssignmentElement': {
const { DestructuringAssignmentTarget, Initializer } = node;
let lref;
// 1. If DestructuringAssignmentTarget is neither an ObjectLiteral nor an ArrayLiteral, then
if (DestructuringAssignmentTarget.type !== 'ObjectLiteral'
&& DestructuringAssignmentTarget.type !== 'ArrayLiteral') {
lref = Q(yield* Evaluate(DestructuringAssignmentTarget));
}
let value: Value = Value.undefined;
// 2. 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, set value to next.
if (next !== 'done') {
value = next;
}
}
let v: Value;
// 4. If Initializer is present and value is undefined, then
if (Initializer && value === Value.undefined) {
// a. If IsAnonymousFunctionDefinition(AssignmentExpression) is true and IsIdentifierRef of LeftHandSideExpression is true, then
if (IsAnonymousFunctionDefinition(Initializer) && IsIdentifierRef(DestructuringAssignmentTarget)) {
// i. Let target be the StringValue of DestructuringAssignmentTarget.
const target = (lref as ReferenceRecord).ReferencedName as JSStringValue;
// i. ii. Let v be ? NamedEvaluation of Initializer with argument target.
v = Q(yield* NamedEvaluation(Initializer as FunctionDeclaration, target));
} else { // b. Else,
// i. Let defaultValue be the result of evaluating Initializer.
const defaultValue = Q(yield* Evaluate(Initializer));
// ii. Let v be ? GetValue(defaultValue).
v = Q(yield* GetValue(defaultValue));
}
} else { // 5. Else, let v be value.
v = Q(value);
}
// 6. If DestructuringAssignmentTarget is an ObjectLiteral or an ArrayLiteral, then
if (DestructuringAssignmentTarget.type === 'ObjectLiteral'
|| DestructuringAssignmentTarget.type === 'ArrayLiteral') {
// a. Let nestedAssignmentPattern be the AssignmentPattern that is covered by DestructuringAssignmentTarget.
const nestedAssignmentPattern = refineLeftHandSideExpression(DestructuringAssignmentTarget) as ParseNode.ObjectAssignmentPattern | ParseNode.ArrayAssignmentPattern;
// b. Return the result of performing DestructuringAssignmentEvaluation of nestedAssignmentPattern with v as the argument.
return yield* DestructuringAssignmentEvaluation(nestedAssignmentPattern, X(v));
}
// 7. Return ? PutValue(lref, v).
return Q(yield* PutValue(Q(lref) as ReferenceRecord, v));
}
case 'AssignmentRestElement': {
const { AssignmentExpression: DestructuringAssignmentTarget } = node;
let lref;
// 1. If DestructuringAssignmentTarget is neither an ObjectLiteral nor an ArrayLiteral, then
if (DestructuringAssignmentTarget.type !== 'ObjectLiteral'
&& DestructuringAssignmentTarget.type !== 'ArrayLiteral') {
lref = yield* Evaluate(DestructuringAssignmentTarget);
Q(lref);
}
// 2. Let A be ! ArrayCreate(0).
const A = X(ArrayCreate(0));
// 3. Let n be 0.
let n = 0;
// 4. Repeat, while iteratorRecord.[[Done]] is false,
while (iteratorRecord.Done === Value.false) {
// a. Let next be IteratorStep(iteratorRecord).
const next = Q(yield* IteratorStepValue(iteratorRecord));
// d. If next is not done, then
if (next !== 'done') {
// i. Perform ! CreateDataPropertyOrThrow(A, ! ToString(𝔽(n)), next).
X(CreateDataPropertyOrThrow(A, X(ToString(F(n))), X(next)));
// v. Set n to n + 1.
n += 1;
}
}
// 5. If DestructuringAssignmentTarget is neither an ObjectLiteral nor an ArrayLiteral, then
if (DestructuringAssignmentTarget.type !== 'ObjectLiteral'
&& DestructuringAssignmentTarget.type !== 'ArrayLiteral') {
return Q(yield* PutValue(Q(lref) as ReferenceRecord, A));
}
// 6. Let nestedAssignmentPattern be the AssignmentPattern that is covered by DestructuringAssignmentTarget.
const nestedAssignmentPattern = refineLeftHandSideExpression(DestructuringAssignmentTarget) as ParseNode.ObjectAssignmentPattern | ParseNode.ArrayAssignmentPattern;
// 7. Return the result of performing DestructuringAssignmentEvaluation of nestedAssignmentPattern with A as the argument.
return yield* DestructuringAssignmentEvaluation(nestedAssignmentPattern, A);
}
default:
throw new OutOfRange('IteratorDestructuringAssignmentEvaluation', node);
}
}
export function DestructuringAssignmentEvaluation(node: ParseNode.ObjectAssignmentPattern | ParseNode.ArrayAssignmentPattern, value: Value): StatementEvaluator {
switch (node.type) {
case 'ObjectAssignmentPattern':
return DestructuringAssignmentEvaluation_ObjectAssignmentPattern(node, value);
case 'ArrayAssignmentPattern':
return DestructuringAssignmentEvaluation_ArrayAssignmentPattern(node, value);
default:
throw new OutOfRange('DestructuringAssignmentEvaluation', node);
}
}